black: Cover all libnmstate

Signed-off-by: Edward Haas <edwardh@redhat.com>
This commit is contained in:
Edward Haas 2019-06-16 10:21:00 +03:00
parent e5b86c0c0e
commit df3fda59a4
15 changed files with 306 additions and 187 deletions

View File

@ -27,5 +27,12 @@ from .netinfo import show
from .prettystate import PrettyState
__all__ = ['show', 'apply', 'commit', 'rollback', 'error', 'schema',
'PrettyState']
__all__ = [
'show',
'apply',
'commit',
'rollback',
'error',
'schema',
'PrettyState',
]

View File

@ -30,8 +30,7 @@ def set_bridge_ports_metadata(master_state, slave_state):
ports = master_state.get('bridge', {}).get('port', [])
port = next(
six.moves.filter(lambda n: n['name'] == slave_state['name'], ports),
{}
six.moves.filter(lambda n: n['name'] == slave_state['name'], ports), {}
)
slave_state['_brport_options'] = port

View File

@ -19,4 +19,5 @@ import ipaddress
if not hasattr(ipaddress.IPv4Network, 'subnet_of'):
from libnmstate.ipaddress_extender import IPv4Network as _IPv4Network
ipaddress.IPv4Network = _IPv4Network

View File

@ -26,6 +26,7 @@ class NmstateError(Exception):
"""
The base exception of libnmstate.
"""
pass
@ -33,6 +34,7 @@ class NmstateDependencyError(NmstateError):
"""
Nmstate requires external tools installed and/or started for desired state.
"""
pass
@ -44,6 +46,7 @@ class NmstateValueError(NmstateError, ValueError):
* Nmstate schema issue.
* Invalid value of desired property, like bond missing slave.
"""
pass
@ -51,6 +54,7 @@ class NmstatePermissionError(NmstateError, PermissionError):
"""
Permission deny when applying the desired state.
"""
pass
@ -58,6 +62,7 @@ class NmstateConflictError(NmstateError, RuntimeError):
"""
Something else is already editing the network state via Nmstate.
"""
pass
@ -65,6 +70,7 @@ class NmstateLibnmError(NmstateError):
"""
Exception for unexpected libnm failure.
"""
pass
@ -73,6 +79,7 @@ class NmstateVerificationError(NmstateError):
After applied desired state, current state does not match desired state for
unknown reason.
"""
pass
@ -80,6 +87,7 @@ class NmstateNotImplementedError(NmstateError, NotImplementedError):
"""
Desired feature is not supported by Nmstate yet.
"""
pass
@ -88,4 +96,5 @@ class NmstateInternalError(NmstateError):
Unexpected behaviour happened. It is a bug of libnmstate which should be
fixed.
"""
pass

View File

@ -49,7 +49,9 @@ def minimal_ethtool(interface):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockfd = sock.fileno()
ecmd = array.array('B', struct.pack('I39s', ETHTOOL_GSET, b'\x00'*39))
ecmd = array.array(
'B', struct.pack('I39s', ETHTOOL_GSET, b'\x00' * 39)
)
interface = interface.encode('utf-8')
ifreq = struct.pack('16sP', interface, ecmd.buffer_info()[0])

View File

@ -22,7 +22,6 @@ import ipaddress
class IPv4Network(ipaddress.IPv4Network):
def subnet_of(self, other):
"""Return True if this network is a subnet of other."""
return self._is_subnet_of(self, other)
@ -33,9 +32,14 @@ class IPv4Network(ipaddress.IPv4Network):
# Always false if one is v4 and the other is v6.
if a._version != b._version:
raise TypeError(
'{} and {} are not of the same version'.format(a, b))
return (b.network_address <= a.network_address and
b.broadcast_address >= a.broadcast_address)
'{} and {} are not of the same version'.format(a, b)
)
return (
b.network_address <= a.network_address
and b.broadcast_address >= a.broadcast_address
)
except AttributeError:
raise TypeError('Unable to test subnet containment '
'between {} and {}'.format(a, b))
raise TypeError(
'Unable to test subnet containment '
'between {} and {}'.format(a, b)
)

View File

@ -22,9 +22,11 @@ KERNEL_MAIN_ROUTE_TABLE_ID = 254
def is_ipv6_link_local_addr(ip, prefix):
return (ip[:len(_IPV6_LINK_LOCAL_NETWORK_PREFIXES[0])]
in _IPV6_LINK_LOCAL_NETWORK_PREFIXES and
prefix >= _IPV6_LINK_LOCAL_NETWORK_PREFIX_LENGTH)
return (
ip[: len(_IPV6_LINK_LOCAL_NETWORK_PREFIXES[0])]
in _IPV6_LINK_LOCAL_NETWORK_PREFIXES
and prefix >= _IPV6_LINK_LOCAL_NETWORK_PREFIX_LENGTH
)
def is_ipv6_address(addr):

View File

@ -52,21 +52,21 @@ def generate_ifaces_metadata(desired_state, current_state):
current_state.interfaces,
master_type='bond',
get_slaves_func=_get_bond_slaves_from_state,
set_metadata_func=_set_common_slaves_metadata
set_metadata_func=_set_common_slaves_metadata,
)
_generate_link_master_metadata(
desired_state.interfaces,
current_state.interfaces,
master_type='ovs-bridge',
get_slaves_func=_get_ovs_slaves_from_state,
set_metadata_func=_set_ovs_bridge_ports_metadata
set_metadata_func=_set_ovs_bridge_ports_metadata,
)
_generate_link_master_metadata(
desired_state.interfaces,
current_state.interfaces,
master_type='linux-bridge',
get_slaves_func=linux_bridge.get_slaves_from_state,
set_metadata_func=linux_bridge.set_bridge_ports_metadata
set_metadata_func=linux_bridge.set_bridge_ports_metadata,
)
_generate_dns_metadata(desired_state, current_state)
_generate_route_metadata(desired_state, current_state)
@ -92,8 +92,7 @@ def _set_ovs_bridge_ports_metadata(master_state, slave_state):
ports = master_state.get('bridge', {}).get('port', [])
port = next(
six.moves.filter(lambda n: n['name'] == slave_state['name'], ports),
{}
six.moves.filter(lambda n: n['name'] == slave_state['name'], ports), {}
)
slave_state[BRPORT_OPTIONS] = port
@ -110,11 +109,13 @@ def _get_ovs_slaves_from_state(iface_state, default=()):
return [p['name'] for p in ports]
def _generate_link_master_metadata(ifaces_desired_state,
ifaces_current_state,
master_type,
get_slaves_func,
set_metadata_func):
def _generate_link_master_metadata(
ifaces_desired_state,
ifaces_current_state,
master_type,
get_slaves_func,
set_metadata_func,
):
"""
Given master's slaves, add to the slave interface the master information.
@ -136,15 +137,17 @@ def _generate_link_master_metadata(ifaces_desired_state,
if slave in ifaces_desired_state:
set_metadata_func(master_state, ifaces_desired_state[slave])
elif slave in ifaces_current_state:
ifaces_desired_state[slave] = {'name': slave,
'state': master_state['state']}
ifaces_desired_state[slave] = {
'name': slave,
'state': master_state['state'],
}
set_metadata_func(master_state, ifaces_desired_state[slave])
desired_slaves = get_slaves_func(master_state)
current_master_state = ifaces_current_state.get(master_name)
if desired_slaves and current_master_state:
current_slaves = get_slaves_func(current_master_state)
slaves2remove = (set(current_slaves) - set(desired_slaves))
slaves2remove = set(current_slaves) - set(desired_slaves)
for slave in slaves2remove:
if slave not in ifaces_desired_state:
ifaces_desired_state[slave] = {'name': slave}
@ -160,13 +163,18 @@ def _generate_link_master_metadata(ifaces_desired_state,
if slave in ifaces_desired_state:
iface_state = ifaces_desired_state.get(master_name, {})
master_has_no_slaves_specified_in_desired = (
get_slaves_func(iface_state, None) is None)
get_slaves_func(iface_state, None) is None
)
slave_has_no_master_specified_in_desired = (
ifaces_desired_state[slave].get(MASTER) is None)
if (slave_has_no_master_specified_in_desired and
master_has_no_slaves_specified_in_desired):
ifaces_desired_state[slave].get(MASTER) is None
)
if (
slave_has_no_master_specified_in_desired
and master_has_no_slaves_specified_in_desired
):
set_metadata_func(
master_state, ifaces_desired_state[slave])
master_state, ifaces_desired_state[slave]
)
def _generate_route_metadata(desired_state, current_state):
@ -184,20 +192,20 @@ def _generate_route_metadata(desired_state, current_state):
elif current_iface_state:
desired_iface_state = desired_state.interfaces[iface_name] = {
Interface.NAME: iface_name,
Interface.TYPE: current_iface_state[Interface.TYPE]
Interface.TYPE: current_iface_state[Interface.TYPE],
}
_attach_route_metadata(desired_iface_state, routes)
def _attach_route_metadata(iface_state, routes):
_init_iface_route_metadata(iface_state, Interface.IPV4)
_init_iface_route_metadata(iface_state, Interface.IPV6)
_init_iface_route_metadata(iface_state, Interface.IPV4)
_init_iface_route_metadata(iface_state, Interface.IPV6)
for route in routes:
if iplib.is_ipv6_address(route.destination):
iface_state[Interface.IPV6][ROUTES].append(route.to_dict())
else:
iface_state[Interface.IPV4][ROUTES].append(route.to_dict())
for route in routes:
if iplib.is_ipv6_address(route.destination):
iface_state[Interface.IPV6][ROUTES].append(route.to_dict())
else:
iface_state[Interface.IPV4][ROUTES].append(route.to_dict())
def _init_iface_route_metadata(iface_state, ip_key):
@ -219,18 +227,28 @@ def _generate_dns_metadata(desired_state, current_state):
if _dns_config_not_changed(desired_state, current_state):
_preserve_current_dns_metadata(desired_state, current_state)
else:
ifaces_routes = {ifname: [r.to_dict() for r in routes]
for ifname, routes in
six.viewitems(desired_state.config_iface_routes)}
ifaces_routes = {
ifname: [r.to_dict() for r in routes]
for ifname, routes in six.viewitems(
desired_state.config_iface_routes
)
}
ipv4_iface, ipv6_iface = nm.dns.find_interfaces_for_name_servers(
ifaces_routes
)
_save_dns_metadata(desired_state, current_state, ipv4_iface,
ipv6_iface, servers, searches)
_save_dns_metadata(
desired_state,
current_state,
ipv4_iface,
ipv6_iface,
servers,
searches,
)
def _save_dns_metadata(desired_state, current_state, ipv4_iface, ipv6_iface,
servers, searches):
def _save_dns_metadata(
desired_state, current_state, ipv4_iface, ipv6_iface, servers, searches
):
index = 0
searches_saved = False
for server in servers:
@ -244,10 +262,12 @@ def _save_dns_metadata(desired_state, current_state, ipv4_iface, ipv6_iface,
if not iface_name:
raise NmstateValueError(
'Failed to find suitable interface for saving DNS '
'name servers: %s' % server)
'name servers: %s' % server
)
_include_name_only_iface_state(
desired_state, current_state, [iface_name])
desired_state, current_state, [iface_name]
)
iface_state = desired_state.interfaces[iface_name]
if family not in iface_state:
iface_state[family] = {}
@ -256,7 +276,7 @@ def _save_dns_metadata(desired_state, current_state, ipv4_iface, ipv6_iface,
iface_state[family][DNS_METADATA] = {
DNS.SERVER: [server],
DNS.SEARCH: [] if searches_saved else searches,
DNS_METADATA_PRIORITY: nm.dns.DNS_PRIORITY_STATIC_BASE + index
DNS_METADATA_PRIORITY: nm.dns.DNS_PRIORITY_STATIC_BASE + index,
}
else:
iface_state[family][DNS_METADATA][DNS.SERVER].append(server)
@ -265,14 +285,17 @@ def _save_dns_metadata(desired_state, current_state, ipv4_iface, ipv6_iface,
def _include_name_only_iface_state(desired_state, current_state, iface_names):
ifnames = (set(iface_names) & set(current_state.interfaces) -
set(desired_state.interfaces))
ifnames = set(iface_names) & set(current_state.interfaces) - set(
desired_state.interfaces
)
for ifname in ifnames:
desired_state.interfaces[ifname] = {Interface.NAME: ifname}
for iface_name in iface_names:
if iface_name not in desired_state.interfaces and \
iface_name in current_state.interfaces:
if (
iface_name not in desired_state.interfaces
and iface_name in current_state.interfaces
):
desired_state.interfaces[iface_name] = {Interface.NAME: iface_name}
@ -280,10 +303,11 @@ def _clear_current_dns_config(desired_state, current_state):
client = nm.nmclient.client()
current_dns_ifaces = nm.dns.get_dns_config_iface_names(
nm.ipv4.acs_and_ip_profiles(client),
nm.ipv6.acs_and_ip_profiles(client)
nm.ipv6.acs_and_ip_profiles(client),
)
_include_name_only_iface_state(
desired_state, current_state, current_dns_ifaces)
desired_state, current_state, current_dns_ifaces
)
def _dns_config_not_changed(desired_state, current_state):
@ -297,18 +321,21 @@ def _dns_config_not_changed(desired_state, current_state):
client = nm.nmclient.client()
iface_dns_configs = nm.dns.get_indexed_dns_config_by_iface(
nm.ipv4.acs_and_ip_profiles(client),
nm.ipv6.acs_and_ip_profiles(client)
nm.ipv6.acs_and_ip_profiles(client),
)
for iface_name, iface_dns_config in six.viewitems(iface_dns_configs):
if iface_name not in desired_state.interfaces:
continue
iface_state = desired_state.interfaces[iface_name]
if Interface.STATE in iface_state and \
iface_state[Interface.STATE] != InterfaceState.UP:
if (
Interface.STATE in iface_state
and iface_state[Interface.STATE] != InterfaceState.UP
):
return False
for family in six.viewkeys(iface_dns_config):
if family in iface_state and \
not iface_state[family].get('enabled'):
if family in iface_state and not iface_state[family].get(
'enabled'
):
return False
return True
@ -317,7 +344,7 @@ def _preserve_current_dns_metadata(desired_state, current_state):
client = nm.nmclient.client()
iface_dns_configs = nm.dns.get_indexed_dns_config_by_iface(
nm.ipv4.acs_and_ip_profiles(client),
nm.ipv6.acs_and_ip_profiles(client)
nm.ipv6.acs_and_ip_profiles(client),
)
for iface_name, iface_dns_config in six.viewitems(iface_dns_configs):
if iface_name not in desired_state.interfaces:

View File

@ -56,7 +56,8 @@ def apply(desired_state, verify_change=True, commit=True, rollback_timeout=60):
validator.validate_dns(desired_state)
checkpoint = _apply_ifaces_state(
state.State(desired_state), verify_change, commit, rollback_timeout)
state.State(desired_state), verify_change, commit, rollback_timeout
)
if checkpoint:
return str(checkpoint.dbuspath)
@ -105,8 +106,9 @@ def _choose_checkpoint(dbuspath):
return checkpoint
def _apply_ifaces_state(desired_state, verify_change, commit,
rollback_timeout):
def _apply_ifaces_state(
desired_state, verify_change, commit, rollback_timeout
):
current_state = state.State(netinfo.show())
desired_state.sanitize_ethernet(current_state)
@ -121,15 +123,16 @@ def _apply_ifaces_state(desired_state, verify_change, commit,
new_interfaces = _list_new_interfaces(desired_state, current_state)
try:
with nm.checkpoint.CheckPoint(autodestroy=commit,
timeout=rollback_timeout) as checkpoint:
with nm.checkpoint.CheckPoint(
autodestroy=commit, timeout=rollback_timeout
) as checkpoint:
with _setup_providers():
_add_interfaces(new_interfaces, desired_state)
with _setup_providers():
current_state = state.State(netinfo.show())
state2edit = _create_editable_desired_state(desired_state,
current_state,
new_interfaces)
state2edit = _create_editable_desired_state(
desired_state, current_state, new_interfaces
)
_edit_interfaces(state2edit)
if verify_change:
_verify_change(desired_state)
@ -141,9 +144,9 @@ def _apply_ifaces_state(desired_state, verify_change, commit,
raise NmstateConflictError('Error creating a check point')
def _create_editable_desired_state(desired_state,
current_state,
new_intefaces):
def _create_editable_desired_state(
desired_state, current_state, new_intefaces
):
"""
Create a new state object that includes only existing interfaces which need
to be edited/changed.
@ -151,7 +154,8 @@ def _create_editable_desired_state(desired_state,
state2edit = state.create_state(
desired_state.state,
interfaces_to_filter=(
set(current_state.interfaces) - set(new_intefaces))
set(current_state.interfaces) - set(new_intefaces)
),
)
state2edit.merge_interfaces(current_state)
return state2edit
@ -159,11 +163,11 @@ def _create_editable_desired_state(desired_state,
def _list_new_interfaces(desired_state, current_state):
return [
name for name in
six.viewkeys(desired_state.interfaces) -
six.viewkeys(current_state.interfaces)
if desired_state.interfaces[name].get(schema.Interface.STATE) not in (
schema.InterfaceState.ABSENT, schema.InterfaceState.DOWN)
name
for name in six.viewkeys(desired_state.interfaces)
- six.viewkeys(current_state.interfaces)
if desired_state.interfaces[name].get(schema.Interface.STATE)
not in (schema.InterfaceState.ABSENT, schema.InterfaceState.DOWN)
]
@ -182,7 +186,9 @@ def _setup_providers():
if not success:
raise NmstateLibnmError(
'Unexpected failure of libnm when running the mainloop: {}'.format(
mainloop.error))
mainloop.error
)
)
def _add_interfaces(new_interfaces, desired_state):
@ -203,16 +209,20 @@ def _edit_interfaces(state2edit):
ifaces2edit = list(six.viewvalues(state2edit.interfaces))
iface2prepare = list(
filter(lambda state: state.get('state') not in ('absent', 'down'),
ifaces2edit)
filter(
lambda state: state.get('state') not in ('absent', 'down'),
ifaces2edit,
)
)
proxy_ifaces = nm.applier.prepare_proxy_ifaces_desired_state(iface2prepare)
ifaces_configs = nm.applier.prepare_edited_ifaces_configuration(
iface2prepare + proxy_ifaces)
iface2prepare + proxy_ifaces
)
nm.applier.edit_existing_ifaces(ifaces_configs)
nm.applier.set_ifaces_admin_state(ifaces2edit + proxy_ifaces,
con_profiles=ifaces_configs)
nm.applier.set_ifaces_admin_state(
ifaces2edit + proxy_ifaces, con_profiles=ifaces_configs
)
def _index_by_name(ifaces_state):

View File

@ -41,17 +41,21 @@ def show(include_status_data=False):
report['capabilities'] = capabilities()
report[Constants.ROUTES] = {
Route.RUNNING: (nm.ipv4.get_route_running() +
nm.ipv6.get_route_running()),
Route.CONFIG: (nm.ipv4.get_route_config() +
nm.ipv6.get_route_config()),
Route.RUNNING: (
nm.ipv4.get_route_running() + nm.ipv6.get_route_running()
),
Route.CONFIG: (
nm.ipv4.get_route_config() + nm.ipv6.get_route_config()
),
}
client = nm.nmclient.client()
report[Constants.DNS] = {
DNS.RUNNING: nm_dns.get_running(),
DNS.CONFIG: nm_dns.get_config(nm.ipv4.acs_and_ip_profiles(client),
nm.ipv6.acs_and_ip_profiles(client)),
DNS.CONFIG: nm_dns.get_config(
nm.ipv4.acs_and_ip_profiles(client),
nm.ipv6.acs_and_ip_profiles(client),
),
}
validator.validate(report)
@ -72,8 +76,10 @@ def interfaces():
nm.nmclient.client(refresh=True)
devices_info = [(dev, nm.device.get_device_common_info(dev))
for dev in nm.device.list_devices()]
devices_info = [
(dev, nm.device.get_device_common_info(dev))
for dev in nm.device.list_devices()
]
for dev, devinfo in devices_info:
type_id = devinfo['type_id']

View File

@ -31,11 +31,15 @@ def format_desired_current_state_diff(desired_state, current_state):
pretty_desired_state = PrettyState(desired_state).yaml
pretty_current_state = PrettyState(current_state).yaml
diff = ''.join(difflib.unified_diff(
pretty_desired_state.splitlines(True),
pretty_current_state.splitlines(True),
fromfile='desired',
tofile='current', n=3))
diff = ''.join(
difflib.unified_diff(
pretty_desired_state.splitlines(True),
pretty_current_state.splitlines(True),
fromfile='desired',
tofile='current',
n=3,
)
)
return (
'\n'
'desired\n'
@ -46,10 +50,7 @@ def format_desired_current_state_diff(desired_state, current_state):
'{}\n'
'difference\n'
'==========\n'
'{}\n'.format(
pretty_desired_state,
pretty_current_state,
diff)
'{}\n'.format(pretty_desired_state, pretty_current_state, diff)
)
@ -63,8 +64,9 @@ class PrettyState(object):
@property
def yaml(self):
return yaml.dump(self.state, default_flow_style=False,
explicit_start=True)
return yaml.dump(
self.state, default_flow_style=False, explicit_start=True
)
@property
def json(self):
@ -95,9 +97,8 @@ def order_state(state):
if iface_states is not None:
state[Constants.INTERFACES] = [
order_iface_state(iface_state) for iface_state in sorted(
iface_states, key=itemgetter('name')
)
order_iface_state(iface_state)
for iface_state in sorted(iface_states, key=itemgetter('name'))
]
return state
@ -112,8 +113,9 @@ def represent_unicode(_, data):
"""
return yaml.ScalarNode(tag=u'tag:yaml.org,2002:str',
value=data.encode('utf-8'))
return yaml.ScalarNode(
tag=u'tag:yaml.org,2002:str', value=data.encode('utf-8')
)
def order_iface_state(iface_state):

View File

@ -23,7 +23,7 @@ import yaml
def load(schema_name):
return yaml.load(
pkgutil.get_data('libnmstate', 'schemas/' + schema_name + '.yaml'),
Loader=yaml.SafeLoader
Loader=yaml.SafeLoader,
)
@ -99,7 +99,7 @@ class InterfaceType(object):
OVS_BRIDGE,
OVS_PORT,
OVS_INTERFACE,
VLAN
VLAN,
)

View File

@ -68,25 +68,34 @@ class RouteEntry(object):
return hash(self.__keys())
def __keys(self):
return (self.table_id, self.metric, self.destination,
self.next_hop_address, self.next_hop_interface)
return (
self.table_id,
self.metric,
self.destination,
self.next_hop_address,
self.next_hop_interface,
)
def to_dict(self):
return {
key.replace('_', '-'): value
for key, value in six.viewitems(vars(self)) if value is not None
for key, value in six.viewitems(vars(self))
if value is not None
}
def __eq__(self, other):
return self is other or self.__keys() == other.__keys()
def __lt__(self, other):
return ((self.table_id or Route.USE_DEFAULT_ROUTE_TABLE,
self.next_hop_interface or '',
self.destination or '') <
(other.table_id or Route.USE_DEFAULT_ROUTE_TABLE,
other.next_hop_interface or '',
other.destination or ''))
return (
self.table_id or Route.USE_DEFAULT_ROUTE_TABLE,
self.next_hop_interface or '',
self.destination or '',
) < (
other.table_id or Route.USE_DEFAULT_ROUTE_TABLE,
other.next_hop_interface or '',
other.destination or '',
)
def __repr__(self):
return str(self.to_dict())
@ -150,7 +159,7 @@ class State(object):
def state(self):
self._state[Interface.KEY] = sorted(
list(six.viewvalues(self._ifaces_state)),
key=itemgetter(Interface.NAME)
key=itemgetter(Interface.NAME),
)
return self._state
@ -171,7 +180,7 @@ class State(object):
dns_conf = self._state.get(DNS.KEY, {}).get(DNS.CONFIG, {})
return {
DNS.SERVER: dns_conf.get(DNS.SERVER, []),
DNS.SEARCH: dns_conf.get(DNS.SEARCH, [])
DNS.SEARCH: dns_conf.get(DNS.SEARCH, []),
}
def _complement_interface_empty_ip_subtrees(self):
@ -212,12 +221,15 @@ class State(object):
for family in ('ipv4', 'ipv6'):
ip = iface_state[family]
if ip.get('enabled') and (
ip.get('dhcp') or ip.get('autoconf')):
ip.get('dhcp') or ip.get('autoconf')
):
ip['address'] = []
else:
for dhcp_option in ('auto-routes',
'auto-gateway',
'auto-dns'):
for dhcp_option in (
'auto-routes',
'auto-gateway',
'auto-dns',
):
ip.pop(dhcp_option, None)
def verify_interfaces(self, other_state):
@ -244,7 +256,7 @@ class State(object):
raise NmstateVerificationError(
format_desired_current_state_diff(
{Route.KEY: [r.to_dict() for r in routes]},
{Route.KEY: [r.to_dict() for r in other_routes]}
{Route.KEY: [r.to_dict() for r in other_routes]},
)
)
@ -252,12 +264,10 @@ class State(object):
if self.config_dns != other_state.config_dns:
raise NmstateVerificationError(
format_desired_current_state_diff(
{
DNS.KEY: self.config_dns
},
{
DNS.KEY: other_state.config_dns
}))
{DNS.KEY: self.config_dns},
{DNS.KEY: other_state.config_dns},
)
)
def normalize_for_verification(self):
self._clean_sanitize_ethernet()
@ -277,8 +287,9 @@ class State(object):
This is a reverse recursive update operation.
"""
other_state = State(other_state.state)
for name in (six.viewkeys(self.interfaces) &
six.viewkeys(other_state.interfaces)):
for name in six.viewkeys(self.interfaces) & six.viewkeys(
other_state.interfaces
):
dict_update(other_state.interfaces[name], self.interfaces[name])
self._ifaces_state[name] = other_state.interfaces[name]
@ -297,14 +308,17 @@ class State(object):
"""
other_routes = set()
for ifname, routes in six.viewitems(other_state.config_iface_routes):
if (ifname in self.config_iface_routes or
self._is_interface_routable(ifname, routes)):
if (
ifname in self.config_iface_routes
or self._is_interface_routable(ifname, routes)
):
other_routes |= set(routes)
self_routes = {
route
for routes in six.viewvalues(self.config_iface_routes)
for route in routes if not route.absent
for route in routes
if not route.absent
}
absent_routes = set()
@ -334,14 +348,16 @@ class State(object):
if iface_up:
ipv4_state = ifstate.get(Interface.IPV4, {})
ipv4_disabled = ipv4_state.get('enabled') is False
if (ipv4_disabled and
any(not is_ipv6_address(r.destination) for r in routes)):
if ipv4_disabled and any(
not is_ipv6_address(r.destination) for r in routes
):
return False
ipv6_state = ifstate.get(Interface.IPV6, {})
ipv6_disabled = ipv6_state.get('enabled') is False
if (ipv6_disabled and
any(is_ipv6_address(r.destination) for r in routes)):
if ipv6_disabled and any(
is_ipv6_address(r.destination) for r in routes
):
return False
return True
@ -370,16 +386,18 @@ class State(object):
ifaces = {}
for ifname, ifstate in six.viewitems(self.interfaces):
is_virt_down = (
ifstate.get(Interface.STATE) == InterfaceState.DOWN and
ifstate.get(Interface.TYPE) in InterfaceType.VIRT_TYPES
ifstate.get(Interface.STATE) == InterfaceState.DOWN
and ifstate.get(Interface.TYPE) in InterfaceType.VIRT_TYPES
)
if not is_virt_down:
ifaces[ifname] = ifstate
self._ifaces_state = ifaces
def _index_interfaces_state_by_name(self):
return {iface[Interface.NAME]: iface
for iface in self._state.get(Interface.KEY, [])}
return {
iface[Interface.NAME]: iface
for iface in self._state.get(Interface.KEY, [])
}
def _index_routes_by_iface(self):
iface_routes = defaultdict(list)
@ -394,9 +412,11 @@ class State(object):
for ifstate in six.viewvalues(self.interfaces):
ethernet_state = ifstate.get(Ethernet.CONFIG_SUBTREE)
if ethernet_state:
for key in (Ethernet.AUTO_NEGOTIATION,
Ethernet.SPEED,
Ethernet.DUPLEX):
for key in (
Ethernet.AUTO_NEGOTIATION,
Ethernet.SPEED,
Ethernet.DUPLEX,
):
if ethernet_state.get(key, None) is None:
ethernet_state.pop(key, None)
if not ethernet_state:
@ -409,7 +429,8 @@ class State(object):
def _sort_bridge_ports(self):
for ifstate in six.viewvalues(self.interfaces):
ifstate.get('bridge', {}).get('port', []).sort(
key=itemgetter('name'))
key=itemgetter('name')
)
def _canonicalize_ipv6(self):
for ifstate in six.viewvalues(self.interfaces):
@ -420,9 +441,11 @@ class State(object):
def _remove_iface_ipv6_link_local_addr(self):
for ifstate in six.viewvalues(self.interfaces):
ifstate['ipv6']['address'] = list(
addr for addr in ifstate['ipv6']['address']
if not iplib.is_ipv6_link_local_addr(addr['ip'],
addr['prefix-length'])
addr
for addr in ifstate['ipv6']['address']
if not iplib.is_ipv6_link_local_addr(
addr['ip'], addr['prefix-length']
)
)
def _sort_ip_addresses(self):
@ -445,16 +468,17 @@ class State(object):
raise NmstateVerificationError(
format_desired_current_state_diff(
self.interfaces[ifname],
current_state.interfaces[ifname]
current_state.interfaces[ifname],
)
)
def _assert_interfaces_included_in(self, current_state):
if not (set(self.interfaces) <= set(
current_state.interfaces)):
if not (set(self.interfaces) <= set(current_state.interfaces)):
raise NmstateVerificationError(
format_desired_current_state_diff(self.interfaces,
current_state.interfaces))
format_desired_current_state_diff(
self.interfaces, current_state.interfaces
)
)
@property
def _config_routes(self):
@ -479,8 +503,12 @@ def dict_update(origin_data, to_merge_data):
return origin_data
def _validate_routes(iface_route_sets, iface_enable_states,
ipv4_enable_states, ipv6_enable_states):
def _validate_routes(
iface_route_sets,
iface_enable_states,
ipv4_enable_states,
ipv6_enable_states,
):
"""
Check whether user desire routes next hop to:
* down/absent interface
@ -495,7 +523,8 @@ def _validate_routes(iface_route_sets, iface_enable_states,
raise NmstateValueError('Cannot set route to non-exist interface')
if iface_enable_state != InterfaceState.UP:
raise NmstateValueError(
'Cannot set route to {} interface'.format(iface_enable_state))
'Cannot set route to {} interface'.format(iface_enable_state)
)
# Interface is already check, so the ip enable status should be defined
ipv4_enabled = ipv4_enable_states[iface_name]
ipv6_enabled = ipv6_enable_states[iface_name]
@ -503,10 +532,12 @@ def _validate_routes(iface_route_sets, iface_enable_states,
if iplib.is_ipv6_address(route_obj.destination):
if not ipv6_enabled:
raise NmstateValueError(
'Cannot set IPv6 route when IPv6 is disabled')
'Cannot set IPv6 route when IPv6 is disabled'
)
elif not ipv4_enabled:
raise NmstateValueError(
'Cannot set IPv4 route when IPv4 is disabled')
raise NmstateValueError(
'Cannot set IPv4 route when IPv4 is disabled'
)
def _get_iface_enable_states(desire_state, current_state):
@ -524,8 +555,9 @@ def _get_iface_enable_states(desire_state, current_state):
def _get_ip_enable_states(family, desire_state, current_state):
ip_enable_states = {}
for iface_name, iface_state in six.viewitems(current_state.interfaces):
ip_enable_states[iface_name] = iface_state.get(
family, {}).get('enabled', False)
ip_enable_states[iface_name] = iface_state.get(family, {}).get(
'enabled', False
)
for iface_name, iface_state in six.viewitems(desire_state.interfaces):
ip_enable_state = iface_state.get(family, {}).get('enabled')
if ip_enable_state is not None:
@ -536,8 +568,9 @@ def _get_ip_enable_states(family, desire_state, current_state):
return ip_enable_states
def _route_is_valid(route_obj, iface_enable_states, ipv4_enable_states,
ipv6_enable_states):
def _route_is_valid(
route_obj, iface_enable_states, ipv4_enable_states, ipv6_enable_states
):
"""
Return False when route is next hop to any of these interfaces:
* Interface not in InterfaceState.UP state.

View File

@ -57,12 +57,13 @@ def validate_interface_capabilities(ifaces_state, capabilities):
is_ovs_type = iface_type in (
nm.ovs.BRIDGE_TYPE,
nm.ovs.PORT_TYPE,
nm.ovs.INTERNAL_INTERFACE_TYPE
nm.ovs.INTERNAL_INTERFACE_TYPE,
)
if is_ovs_type and not has_ovs_capability:
raise NmstateDependencyError(
"Open vSwitch NetworkManager support not installed "
"and started")
"and started"
)
def validate_interfaces_state(desired_state, current_state):
@ -71,7 +72,8 @@ def validate_interfaces_state(desired_state, current_state):
def validate_link_aggregation_state(desired_state, current_state):
available_ifaces = {
ifname for ifname, ifstate in six.viewitems(desired_state.interfaces)
ifname
for ifname, ifstate in six.viewitems(desired_state.interfaces)
if ifstate.get('state') != 'absent'
}
available_ifaces |= set(current_state.interfaces)
@ -85,11 +87,15 @@ def validate_link_aggregation_state(desired_state, current_state):
if not (slaves <= available_ifaces):
raise NmstateValueError(
"Link aggregation has missing slave: {}".format(
iface_state))
iface_state
)
)
if slaves & specified_slaves:
raise NmstateValueError(
"Link aggregation has reused slave: {}".format(
iface_state))
iface_state
)
)
specified_slaves |= slaves
@ -97,10 +103,15 @@ def validate_dhcp(state):
for iface_state in state[Constants.INTERFACES]:
for family in ('ipv4', 'ipv6'):
ip = iface_state.get(family, {})
if ip.get('enabled') and ip.get('address') and \
(ip.get('dhcp') or ip.get('autoconf')):
logging.warning('%s addresses are ignored when '
'dynamic IP is enabled', family)
if (
ip.get('enabled')
and ip.get('address')
and (ip.get('dhcp') or ip.get('autoconf'))
):
logging.warning(
'%s addresses are ignored when ' 'dynamic IP is enabled',
family,
)
def validate_dns(state):
@ -108,11 +119,13 @@ def validate_dns(state):
Only support at most 2 name servers now:
https://nmstate.atlassian.net/browse/NMSTATE-220
"""
dns_servers = state.get(
DNS.KEY, {}).get(DNS.CONFIG, {}).get(DNS.SERVER, [])
dns_servers = (
state.get(DNS.KEY, {}).get(DNS.CONFIG, {}).get(DNS.SERVER, [])
)
if len(dns_servers) > 2:
raise NmstateNotImplementedError(
'Nmstate only support at most 2 DNS name servers')
'Nmstate only support at most 2 DNS name servers'
)
def validate_routes(desired_state, current_state):
@ -132,11 +145,13 @@ def validate_routes(desired_state, current_state):
if desired_iface_state or current_iface_state:
_assert_iface_is_up(desired_iface_state, current_iface_state)
if any(is_ipv6_address(route.destination) for route in routes):
_assert_iface_ipv6_enabled(desired_iface_state,
current_iface_state)
_assert_iface_ipv6_enabled(
desired_iface_state, current_iface_state
)
if any(not is_ipv6_address(route.destination) for route in routes):
_assert_iface_ipv4_enabled(desired_iface_state,
current_iface_state)
_assert_iface_ipv4_enabled(
desired_iface_state, current_iface_state
)
else:
raise NmstateRouteWithNoInterfaceError(str(routes))
@ -160,12 +175,14 @@ def _assert_iface_is_up(desired_iface_state, current_iface_state):
def _assert_iface_ipv4_enabled(desired_iface_state, current_iface_state):
_assert_iface_ip_enabled(
desired_iface_state, current_iface_state, schema.Interface.IPV4)
desired_iface_state, current_iface_state, schema.Interface.IPV4
)
def _assert_iface_ipv6_enabled(desired_iface_state, current_iface_state):
_assert_iface_ip_enabled(
desired_iface_state, current_iface_state, schema.Interface.IPV6)
desired_iface_state, current_iface_state, schema.Interface.IPV6
)
def _assert_iface_ip_enabled(desired_iface_state, current_iface_state, ipkey):

View File

@ -88,7 +88,7 @@ commands =
-S \
--check \
{posargs} \
libnmstate/nm \
libnmstate \
tests
[testenv:pylint]