nmstate: Centralize 'interfaces' constant

Signed-off-by: Edward Haas <edwardh@redhat.com>
This commit is contained in:
Edward Haas 2018-10-23 19:16:24 +03:00 committed by Till Maas
parent 234fb15967
commit 2b6b0526da
11 changed files with 73 additions and 51 deletions

View File

@ -27,6 +27,7 @@ from libnmstate import nm
from libnmstate import validator
from libnmstate.nm import nmclient
from libnmstate.prettystate import format_desired_current_state_diff
from libnmstate.schema import Constants
class ApplyError(Exception):
@ -41,7 +42,7 @@ def apply(desired_state, verify_change=True):
validator.verify(desired_state)
validator.verify_capabilities(desired_state, netinfo.capabilities())
_apply_ifaces_state(desired_state['interfaces'], verify_change)
_apply_ifaces_state(desired_state[Constants.INTERFACES], verify_change)
def _apply_ifaces_state(interfaces_desired_state, verify_change):

View File

@ -18,6 +18,7 @@ from __future__ import absolute_import
from libnmstate import nm
from libnmstate import validator
from libnmstate.schema import Constants
def show(include_status_data=False):
@ -30,7 +31,7 @@ def show(include_status_data=False):
When include_status_data is set, both are reported, otherwise only the
configuration data is reported.
"""
report = {'interfaces': interfaces()}
report = {Constants.INTERFACES: interfaces()}
if include_status_data:
report['capabilities'] = capabilities()

View File

@ -24,6 +24,8 @@ from operator import itemgetter
import yaml
from libnmstate.schema import Constants
def format_desired_current_state_diff(desired_state, current_state):
pretty_desired_state = PrettyState(desired_state).yaml
@ -83,12 +85,12 @@ def represent_ordereddict(dumper, data):
def order_state(state):
iface_states = state.pop('interfaces', None)
iface_states = state.pop(Constants.INTERFACES, None)
state = order_iface_state(state)
if iface_states is not None:
state['interfaces'] = [
state[Constants.INTERFACES] = [
order_iface_state(iface_state) for iface_state in sorted(
iface_states, key=itemgetter('name')
)

View File

@ -26,3 +26,7 @@ def load(schema_name):
ifaces_schema = load('operational-state')
class Constants(object):
INTERFACES = 'interfaces'

View File

@ -20,6 +20,7 @@ import jsonschema as js
from . import nm
from . import schema
from .schema import Constants
class LinkAggregationSlavesMissingError(Exception):
@ -39,7 +40,7 @@ def verify(data, validation_schema=schema.ifaces_schema):
def verify_capabilities(state, capabilities):
verify_interface_capabilities(state['interfaces'], capabilities)
verify_interface_capabilities(state[Constants.INTERFACES], capabilities)
def verify_interface_capabilities(ifaces_state, capabilities):

View File

@ -31,6 +31,7 @@ import yaml
from libnmstate import netapplier
from libnmstate import netinfo
from libnmstate.prettystate import PrettyState
from libnmstate.schema import Constants
def main():
@ -56,7 +57,7 @@ def setup_subcommand_edit(subparsers):
parser_edit.add_argument('--json', help='Edit as JSON', default=True,
action='store_false', dest='yaml')
parser_edit.add_argument(
'only', default='*', nargs='?', metavar='interfaces',
'only', default='*', nargs='?', metavar=Constants.INTERFACES,
help='Edit only specified interfaces (comma-separated)'
)
parser_edit.add_argument(
@ -71,7 +72,7 @@ def setup_subcommand_show(subparsers):
parser_show.add_argument('--yaml', help='Output as yaml', default=False,
action='store_true')
parser_show.add_argument(
'only', default='*', nargs='?', metavar='interfaces',
'only', default='*', nargs='?', metavar=Constants.INTERFACES,
help='Show only specified interfaces (comma-separated)'
)
@ -92,7 +93,7 @@ def setup_subcommand_set(subparsers):
def edit(args):
state = _filter_state(netinfo.show(), args.only)
if not state['interfaces']:
if not state[Constants.INTERFACES]:
sys.stderr.write('ERROR: No such interface\n')
return os.EX_USAGE
@ -146,7 +147,7 @@ def apply(args):
def _filter_state(state, whitelist):
if whitelist != '*':
patterns = [p for p in whitelist.split(',')]
state['interfaces'] = _filter_interfaces(state, patterns)
state[Constants.INTERFACES] = _filter_interfaces(state, patterns)
return state
@ -157,7 +158,7 @@ def _filter_interfaces(state, patterns):
"""
showinterfaces = []
for interface in state['interfaces']:
for interface in state[Constants.INTERFACES]:
for pattern in patterns:
if fnmatch.fnmatch(interface['name'], pattern):
showinterfaces.append(interface)
@ -214,7 +215,7 @@ def _parse_state(txtstate, parse_yaml):
except ValueError as e:
error = 'Invalid JSON syntax: %s\n' % e
if not error and 'interfaces' not in state:
if not error and Constants.INTERFACES not in state:
error = 'Invalid state: should contain "interfaces" entry.\n'
return state, error

View File

@ -17,6 +17,7 @@
import json
from libnmstate.schema import Constants
from .testlib import cmd as libcmd
@ -66,7 +67,7 @@ def test_show_command_with_no_flags():
assert LOOPBACK_JSON_CONFIG in out
state = json.loads(out)
assert len(state['interfaces']) > 1
assert len(state[Constants.INTERFACES]) > 1
def test_show_command_with_yaml_format():
@ -84,8 +85,8 @@ def test_show_command_only_lo():
assert_rc(rc, RC_SUCCESS, ret)
state = json.loads(out)
assert len(state['interfaces']) == 1
assert state['interfaces'][0]['name'] == 'lo'
assert len(state[Constants.INTERFACES]) == 1
assert state[Constants.INTERFACES][0]['name'] == 'lo'
def test_show_command_only_non_existing():
@ -95,7 +96,7 @@ def test_show_command_only_non_existing():
assert_rc(rc, RC_SUCCESS, ret)
state = json.loads(out)
assert len(state['interfaces']) == 0
assert len(state[Constants.INTERFACES]) == 0
def assert_rc(actual, expected, return_tuple):

View File

@ -16,9 +16,10 @@
#
from libnmstate import netinfo
from libnmstate.schema import Constants
INTERFACES = 'interfaces'
INTERFACES = Constants.INTERFACES
def show_only(ifnames):

View File

@ -21,8 +21,10 @@ import pytest
from .compat import mock
from libnmstate import netapplier
from libnmstate.schema import Constants
INTERFACES = Constants.INTERFACES
BOND_TYPE = 'bond'
OVS_BR_TYPE = 'ovs-bridge'
BOND_NAME = 'bond99'
@ -52,7 +54,7 @@ def netinfo_nm_mock():
def test_iface_admin_state_change(netinfo_nm_mock, netapplier_nm_mock):
current_config = {
'interfaces': [
INTERFACES: [
{
'name': 'foo',
'type': 'unknown',
@ -70,22 +72,22 @@ def test_iface_admin_state_change(netinfo_nm_mock, netapplier_nm_mock):
netinfo_nm_mock.device.list_devices.return_value = ['one-item']
netinfo_nm_mock.translator.Nm2Api.get_common_device_info.return_value = (
current_config['interfaces'][0])
current_config[INTERFACES][0])
netinfo_nm_mock.bond.is_bond_type_id.return_value = False
netinfo_nm_mock.ovs.is_ovs_bridge_type_id.return_value = False
netinfo_nm_mock.ovs.is_ovs_port_type_id.return_value = False
netinfo_nm_mock.ipv4.get_info.return_value = (
current_config['interfaces'][0]['ipv4'])
current_config[INTERFACES][0]['ipv4'])
netinfo_nm_mock.ipv6.get_info.return_value = (
current_config['interfaces'][0]['ipv6'])
current_config[INTERFACES][0]['ipv6'])
desired_config['interfaces'][0]['state'] = 'down'
desired_config[INTERFACES][0]['state'] = 'down'
netapplier.apply(desired_config, verify_change=False)
netapplier_nm_mock.applier.set_ifaces_admin_state.assert_has_calls(
[
mock.call([]),
mock.call(desired_config['interfaces'])
mock.call(desired_config[INTERFACES])
]
)
@ -94,7 +96,7 @@ def test_add_new_bond(netinfo_nm_mock, netapplier_nm_mock):
netinfo_nm_mock.device.list_devices.return_value = []
desired_config = {
'interfaces': [
INTERFACES: [
{
'name': 'bond99',
'type': BOND_TYPE,
@ -116,12 +118,12 @@ def test_add_new_bond(netinfo_nm_mock, netapplier_nm_mock):
m_prepare.assert_called_once_with([])
m_prepare = netapplier_nm_mock.applier.prepare_new_ifaces_configuration
m_prepare.assert_called_once_with(desired_config['interfaces'])
m_prepare.assert_called_once_with(desired_config[INTERFACES])
def test_edit_existing_bond(netinfo_nm_mock, netapplier_nm_mock):
current_config = {
'interfaces': [
INTERFACES: [
{
'name': 'bond99',
'type': BOND_TYPE,
@ -145,27 +147,27 @@ def test_edit_existing_bond(netinfo_nm_mock, netapplier_nm_mock):
netinfo_nm_mock.device.list_devices.return_value = ['one-item']
netinfo_nm_mock.translator.Nm2Api.get_common_device_info.return_value = {
'name': current_config['interfaces'][0]['name'],
'type': current_config['interfaces'][0]['type'],
'state': current_config['interfaces'][0]['state'],
'name': current_config[INTERFACES][0]['name'],
'type': current_config[INTERFACES][0]['type'],
'state': current_config[INTERFACES][0]['state'],
}
netinfo_nm_mock.bond.is_bond_type_id.return_value = True
netinfo_nm_mock.translator.Nm2Api.get_bond_info.return_value = {
'link-aggregation': current_config['interfaces'][0]['link-aggregation']
'link-aggregation': current_config[INTERFACES][0]['link-aggregation']
}
netinfo_nm_mock.ipv4.get_info.return_value = (
current_config['interfaces'][0]['ipv4'])
current_config[INTERFACES][0]['ipv4'])
netinfo_nm_mock.ipv6.get_info.return_value = (
current_config['interfaces'][0]['ipv6'])
current_config[INTERFACES][0]['ipv6'])
desired_config = copy.deepcopy(current_config)
options = desired_config['interfaces'][0]['link-aggregation']['options']
options = desired_config[INTERFACES][0]['link-aggregation']['options']
options['miimon'] = 200
netapplier.apply(desired_config, verify_change=False)
m_prepare = netapplier_nm_mock.applier.prepare_edited_ifaces_configuration
m_prepare.assert_called_once_with(desired_config['interfaces'])
m_prepare.assert_called_once_with(desired_config[INTERFACES])
m_prepare = netapplier_nm_mock.applier.prepare_new_ifaces_configuration
m_prepare.assert_called_once_with([])

View File

@ -19,6 +19,10 @@ import pytest
from .compat import mock
from libnmstate import netinfo
from libnmstate.schema import Constants
INTERFACES = Constants.INTERFACES
@pytest.fixture
@ -29,7 +33,7 @@ def nm_mock():
def test_netinfo_show_generic_iface(nm_mock):
current_config = {
'interfaces': [
INTERFACES: [
{
'name': 'foo',
'type': 'unknown',
@ -46,12 +50,12 @@ def test_netinfo_show_generic_iface(nm_mock):
nm_mock.device.list_devices.return_value = ['one-item']
nm_mock.translator.Nm2Api.get_common_device_info.return_value = (
current_config['interfaces'][0])
current_config[INTERFACES][0])
nm_mock.bond.is_bond_type_id.return_value = False
nm_mock.ipv4.get_info.return_value = (
current_config['interfaces'][0]['ipv4'])
current_config[INTERFACES][0]['ipv4'])
nm_mock.ipv6.get_info.return_value = (
current_config['interfaces'][0]['ipv6'])
current_config[INTERFACES][0]['ipv6'])
report = netinfo.show()
@ -60,7 +64,7 @@ def test_netinfo_show_generic_iface(nm_mock):
def test_netinfo_show_bond_iface(nm_mock):
current_config = {
'interfaces': [
INTERFACES: [
{
'name': 'bond99',
'type': 'bond',
@ -84,18 +88,18 @@ def test_netinfo_show_bond_iface(nm_mock):
nm_mock.device.list_devices.return_value = ['one-item']
nm_mock.translator.Nm2Api.get_common_device_info.return_value = {
'name': current_config['interfaces'][0]['name'],
'type': current_config['interfaces'][0]['type'],
'state': current_config['interfaces'][0]['state'],
'name': current_config[INTERFACES][0]['name'],
'type': current_config[INTERFACES][0]['type'],
'state': current_config[INTERFACES][0]['state'],
}
nm_mock.bond.is_bond_type_id.return_value = True
nm_mock.translator.Nm2Api.get_bond_info.return_value = {
'link-aggregation': current_config['interfaces'][0]['link-aggregation']
'link-aggregation': current_config[INTERFACES][0]['link-aggregation']
}
nm_mock.ipv4.get_info.return_value = (
current_config['interfaces'][0]['ipv4'])
current_config[INTERFACES][0]['ipv4'])
nm_mock.ipv6.get_info.return_value = (
current_config['interfaces'][0]['ipv6'])
current_config[INTERFACES][0]['ipv6'])
report = netinfo.show()

View File

@ -23,10 +23,14 @@ import pytest
import jsonschema as js
import libnmstate
from libnmstate.schema import Constants
INTERFACES = Constants.INTERFACES
COMMON_IFACE_DATA = {
'interfaces': [
INTERFACES: [
{
'name': 'lo',
'description': 'Loopback Interface',
@ -73,14 +77,14 @@ class TestIfaceCommon(object):
libnmstate.validator.verify(default_data)
def test_invalid_instance(self, default_data):
default_data['interfaces'][0]['state'] = 'bad-state'
default_data[INTERFACES][0]['state'] = 'bad-state'
with pytest.raises(js.ValidationError) as err:
libnmstate.validator.verify(default_data)
assert 'bad-state' in err.value.args[0]
def test_invalid_type(self, default_data):
default_data['interfaces'][0]['type'] = 'bad-type'
default_data[INTERFACES][0]['type'] = 'bad-type'
with pytest.raises(js.ValidationError) as err:
libnmstate.validator.verify(default_data)
@ -90,14 +94,14 @@ class TestIfaceCommon(object):
class TestIfaceTypeEthernet(object):
def test_valid_ethernet_with_auto_neg(self, default_data):
default_data['interfaces'][0].update({
default_data[INTERFACES][0].update({
'type': 'ethernet',
'auto-negotiation': True,
})
libnmstate.validator.verify(default_data)
def test_valid_ethernet_without_auto_neg(self, default_data):
default_data['interfaces'][0].update({
default_data[INTERFACES][0].update({
'auto-negotiation': False,
'link-speed': 1000,
'duplex': 'full',
@ -110,10 +114,10 @@ class TestIfaceTypeEthernet(object):
not a valid configuration, however, this is not handled by the schema
at the moment, deferring the handling to the application code.
"""
default_data['interfaces'][0].update({
default_data[INTERFACES][0].update({
'type': 'ethernet',
'auto-negotiation': False,
})
del default_data['interfaces'][0]['link-speed']
del default_data[INTERFACES][0]['link-speed']
libnmstate.validator.verify(default_data)