Пример #1
0
def _assert_bond_config_is_legal(iface_state, original_iface_state):
    """
    When MAC address defined in original_iface_state and bond is MAC
    address restricted mode(cannot define MAC), raise NmstateValueError.
    When both miimon > 0 and arp_interval > 0 defined in merged state,
    raise NmstateValueError
    """
    mac = original_iface_state.get(Interface.MAC)
    bond_options = iface_state[Bond.CONFIG_SUBTREE].get(
        Bond.OPTIONS_SUBTREE, {}
    )
    bond_options[Bond.MODE] = iface_state[Bond.CONFIG_SUBTREE].get(Bond.MODE)

    if mac and is_in_mac_restricted_mode(bond_options):
        raise NmstateValueError(
            "MAC address cannot be specified in bond interface along with "
            "specified bond options"
        )

    if "miimon" in bond_options and "arp_interval" in bond_options:
        try:
            miimon = int(bond_options["miimon"])
            arp_interval = int(bond_options["arp_interval"])
        except ValueError as e:
            raise NmstateValueError(f"Invalid bond option: {e}")
        if miimon > 0 and arp_interval > 0:
            raise NmstateValueError(
                "Bond option arp_interval is conflicting with miimon, "
                "please disable one of them by setting to 0"
            )
Пример #2
0
def validate_link_aggregation_state(desired_state, current_state):
    available_ifaces = {
        ifname
        for ifname, ifstate in desired_state.interfaces.items()
        if ifstate.get("state") != "absent"
    }
    available_ifaces |= set(current_state.interfaces)

    specified_slaves = set()
    for iface_state in desired_state.interfaces.values():
        if iface_state.get("state") != "absent":
            link_aggregation = iface_state.get("link-aggregation")
            if link_aggregation:
                slaves = set(link_aggregation.get("slaves", []))
                if not (slaves <= available_ifaces):
                    raise NmstateValueError(
                        "Link aggregation has missing slave: {}".format(
                            iface_state
                        )
                    )
                if slaves & specified_slaves:
                    raise NmstateValueError(
                        "Link aggregation has reused slave: {}".format(
                            iface_state
                        )
                    )
                specified_slaves |= slaves
Пример #3
0
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
        * Non-exit interface
        * IPv4/IPv6 disabled
    """
    for iface_name, route_set in iface_route_sets.items():
        if not route_set:
            continue
        iface_enable_state = iface_enable_states.get(iface_name)
        if iface_enable_state is None:
            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)
            )
        # 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]
        for route_obj in route_set:
            if iplib.is_ipv6_address(route_obj.destination):
                if not ipv6_enabled:
                    raise NmstateValueError(
                        "Cannot set IPv6 route when IPv6 is disabled"
                    )
            elif not ipv4_enabled:
                raise NmstateValueError(
                    "Cannot set IPv4 route when IPv4 is disabled"
                )
Пример #4
0
def validate_link_aggregation_state(desired_state, current_state):
    available_ifaces = {
        ifname
        for ifname, ifstate in six.viewitems(desired_state.interfaces)
        if ifstate.get('state') != 'absent'
    }
    available_ifaces |= set(current_state.interfaces)

    specified_slaves = set()
    for iface_state in six.viewvalues(desired_state.interfaces):
        if iface_state.get('state') != 'absent':
            link_aggregation = iface_state.get('link-aggregation')
            if link_aggregation:
                slaves = set(link_aggregation.get('slaves', []))
                if not (slaves <= available_ifaces):
                    raise NmstateValueError(
                        "Link aggregation has missing slave: {}".format(
                            iface_state
                        )
                    )
                if slaves & specified_slaves:
                    raise NmstateValueError(
                        "Link aggregation has reused slave: {}".format(
                            iface_state
                        )
                    )
                specified_slaves |= slaves
Пример #5
0
 def _validate_miimon_conflict_with_arp_interval(self):
     bond_options = self._bond_options
     if bond_options.get("miimon") and bond_options.get("arp_interval"):
         raise NmstateValueError(
             "Bond option arp_interval is conflicting with miimon, "
             "please disable one of them by setting to 0"
         )
Пример #6
0
def ip_address_full_to_tuple(addr):
    try:
        net = ipaddress.ip_network(addr)
    except (ipaddress.AddressValueError, ipaddress.NetmaskValueError) as err:
        raise NmstateValueError(f"Invalid IP address, error: {err}")

    return f"{net.network_address}", net.prefixlen
Пример #7
0
 def _validate_mandatory_properties(self):
     if self.is_up:
         for prop in (VXLAN.ID, VXLAN.BASE_IFACE, VXLAN.REMOTE):
             if prop not in self._vxlan_config:
                 raise NmstateValueError(
                     f"Vxlan tunnel {self.name} has missing mandatory "
                     f"property: {prop}")
Пример #8
0
def _rule_info_to_nm_rule(rule, family):
    nm_rule = nmclient.NM.IPRoutingRule.new(family)
    ip_from = rule.get(RouteRule.IP_FROM)
    ip_to = rule.get(RouteRule.IP_TO)
    if not ip_from and not ip_to:
        raise NmstateValueError(
            f"Neither {RouteRule.IP_FROM} or {RouteRule.IP_TO} is defined"
        )

    if ip_from:
        nm_rule.set_from(*iplib.ip_address_full_to_tuple(ip_from))
    if ip_to:
        nm_rule.set_to(*iplib.ip_address_full_to_tuple(ip_to))

    priority = rule.get(RouteRule.PRIORITY)
    if priority and priority != RouteRule.USE_DEFAULT_PRIORITY:
        nm_rule.set_priority(priority)
    else:
        nm_rule.set_priority(ROUTE_RULE_DEFAULT_PRIORIRY)
    table = rule.get(RouteRule.ROUTE_TABLE)
    if table and table != RouteRule.USE_DEFAULT_ROUTE_TABLE:
        nm_rule.set_table(table)
    else:
        nm_rule.set_table(iplib.KERNEL_MAIN_ROUTE_TABLE_ID)
    return nm_rule
Пример #9
0
def _validate_linux_bond(original_desired_state, current_state):
    """
    Raise NmstateValueError on these scenarios:
        * Bond mode not defined.
        * Original desire state contains illegal bond config.
        * After merge, user's intention will cause illegal bong config.
          For example: mac specified in desired_state without any bond options
                       defined. While current state is fail_over_mac=1 with
                       active-backup mode.
    """
    merged_desired_state = copy.deepcopy(original_desired_state)
    merged_desired_state.merge_interfaces(current_state)

    original_iface_states = {}
    for iface_name, iface_state in original_desired_state.interfaces.items():
        original_iface_states[iface_name] = iface_state

    for iface_state in merged_desired_state.interfaces.values():
        if iface_state[Interface.STATE] != InterfaceState.UP:
            continue
        if iface_state[Interface.TYPE] == InterfaceType.BOND:
            if not iface_state.get(Bond.CONFIG_SUBTREE, {}).get(Bond.MODE):
                raise NmstateValueError("Bond mode is not defined")

            original_iface_state = original_iface_states.get(
                iface_state[Interface.NAME], {}
            )
            _assert_bond_config_is_legal(iface_state, original_iface_state)
Пример #10
0
def _save_dns_metadata(desired_state, current_state, ipv4_iface, ipv6_iface,
                       servers, searches):
    index = 0
    searches_saved = False
    for server in servers:
        iface_name = None
        if iplib.is_ipv6_address(server):
            iface_name = ipv6_iface
            family = Interface.IPV6
        else:
            iface_name = ipv4_iface
            family = Interface.IPV4
        if not iface_name:
            raise NmstateValueError(
                "Failed to find suitable interface for saving DNS "
                "name servers: %s" % server)

        _include_name_only_iface_state(desired_state, current_state,
                                       [iface_name])
        iface_state = desired_state.interfaces[iface_name]
        if family not in iface_state:
            iface_state[family] = {}

        if DNS_METADATA not in iface_state[family]:
            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,
            }
        else:
            iface_state[family][DNS_METADATA][DNS.SERVER].append(server)
        searches_saved = True
        index += 1
Пример #11
0
def _assert_vlan_filtering_trunk_tags(ports_state):
    for port_state in ports_state:
        port_vlan_state = port_state.get(LB.Port.VLAN_SUBTREE, {})
        vlan_mode = port_vlan_state.get(LB.Port.Vlan.MODE)
        trunk_tags = port_vlan_state.get(LB.Port.Vlan.TRUNK_TAGS, [])

        if vlan_mode == LB.Port.Vlan.Mode.ACCESS:
            if trunk_tags:
                raise NmstateValueError("Access port cannot have trunk tags")
        elif port_vlan_state:
            if not trunk_tags:
                raise NmstateValueError(
                    "A trunk port needs to specify trunk tags"
                )
        for trunk_tag in trunk_tags:
            _assert_vlan_filtering_trunk_tag(trunk_tag)
Пример #12
0
def _assert_vlan_filtering_trunk_tag(trunk_tag_state):
    vlan_id = trunk_tag_state.get(LinuxBridge.Port.Vlan.TrunkTags.ID)
    vlan_id_range = trunk_tag_state.get(
        LinuxBridge.Port.Vlan.TrunkTags.ID_RANGE)

    if vlan_id and vlan_id_range:
        raise NmstateValueError(
            "Trunk port cannot be configured by both id and range: {}".format(
                trunk_tag_state))
    elif vlan_id_range:
        if not ({
                LinuxBridge.Port.Vlan.TrunkTags.MIN_RANGE,
                LinuxBridge.Port.Vlan.TrunkTags.MAX_RANGE,
        } <= set(vlan_id_range)):
            raise NmstateValueError(
                "Trunk port range requires min / max keys: {}".format(
                    vlan_id_range))
Пример #13
0
 def _validate_ovs_patch_peers(self):
     """
     When OVS patch peer does not exist or is down, raise an error.
     """
     for iface in self._ifaces.values():
         if iface.type == InterfaceType.OVS_INTERFACE and iface.is_up:
             if iface.peer:
                 peer_iface = self._ifaces.get(iface.peer)
                 if not peer_iface or not peer_iface.is_up:
                     raise NmstateValueError(
                         f"OVS patch port peer {iface.peer} must exist and "
                         "be up")
                 elif (not peer_iface.type == InterfaceType.OVS_INTERFACE
                       or not peer_iface.is_patch_port):
                     raise NmstateValueError(
                         f"OVS patch port peer {iface.peer} must be an OVS"
                         " patch port")
Пример #14
0
 def _iface_for_route_table(self, route_state, route_table):
     for routes in route_state.config_iface_routes.values():
         for route in routes:
             if route.table_id == route_table:
                 return route.next_hop_interface
     raise NmstateValueError(
         "Failed to find interface to with route table ID "
         f"{route_table} to store route rules")
Пример #15
0
 def _validate_ovs_lag_slave_count(self):
     for port in self.port_configs:
         slaves_subtree = OVSBridge.Port.LinkAggregation.SLAVES_SUBTREE
         lag = port.get(OVSBridge.Port.LINK_AGGREGATION_SUBTREE)
         if lag and len(lag.get(slaves_subtree, ())) < 2:
             raise NmstateValueError(
                 f"OVS {self.name} LAG port {lag} has less than 2 slaves."
             )
Пример #16
0
    def __init__(self, des_iface_infos, cur_iface_infos, save_to_disk=True):
        self._save_to_disk = save_to_disk
        self._des_iface_infos = des_iface_infos
        self._cur_ifaces = {}
        self._ifaces = {}
        if cur_iface_infos:
            for iface_info in cur_iface_infos:
                cur_iface = _to_specific_iface_obj(iface_info, save_to_disk)
                self._ifaces[cur_iface.name] = cur_iface
                self._cur_ifaces[cur_iface.name] = cur_iface

        if des_iface_infos:
            for iface_info in des_iface_infos:
                iface = BaseIface(iface_info, save_to_disk)
                cur_iface = self._ifaces.get(iface.name)
                if cur_iface and cur_iface.is_desired:
                    raise NmstateValueError(
                        f"Duplicate interfaces names detected: {iface.name}")

                if iface_info.get(Interface.TYPE) is None:
                    if cur_iface:
                        iface_info[Interface.TYPE] = cur_iface.type
                    elif iface.is_up:
                        raise NmstateValueError(
                            f"Interface {iface.name} has no type defined "
                            "neither in desire state nor current state")
                iface = _to_specific_iface_obj(iface_info, save_to_disk)
                if (iface.type == InterfaceType.UNKNOWN
                        # Allowing deletion of down profiles
                        and not iface.is_absent):
                    # Ignore interface with unknown type
                    continue
                if cur_iface:
                    iface.merge(cur_iface)
                iface.mark_as_desired()
                self._ifaces[iface.name] = iface

            self._create_virtual_slaves()
            self._validate_unknown_slaves()
            self._validate_unknown_parent()
            self._gen_metadata()
            for iface in self._ifaces.values():
                iface.pre_edit_validation_and_cleanup()

            self._pre_edit_validation_and_cleanup()
Пример #17
0
def create_setting(options):
    bond_setting = nmclient.NM.SettingBond.new()
    for option_name, option_value in six.viewitems(options):
        success = bond_setting.add_option(option_name, option_value)
        if not success:
            raise NmstateValueError('Invalid bond option: \{}\=\'{}\''.format(
                option_name, option_value))

    return bond_setting
Пример #18
0
 def _validate_unknown_parent(self):
     """
     Check the existance of parent interface
     """
     for iface in self._ifaces.values():
         if iface.parent and not self._ifaces.get(iface.parent):
             raise NmstateValueError(
                 f"Interface {iface.name} has unknown parent: "
                 f"{iface.parent}")
Пример #19
0
 def _validate_slave_ip(self):
     for family in (Interface.IPV4, Interface.IPV6):
         ip_state = IPState(family, self._origin_info.get(family, {}))
         if (ip_state.is_enabled and self.master
                 and not self.can_have_ip_when_enslaved):
             raise NmstateValueError(
                 f"Interface {self.name} is enslaved by {self.master_type} "
                 f"interface {self.master} which does not allow "
                 f"slaves to have {family} enabled")
Пример #20
0
def create_setting(options):
    bond_setting = nmclient.NM.SettingBond.new()
    for option_name, option_value in options.items():
        success = bond_setting.add_option(option_name, option_value)
        if not success:
            raise NmstateValueError("Invalid bond option: '{}'='{}'".format(
                option_name, option_value))

    return bond_setting
Пример #21
0
 def _fix_mac_restriced_mode(self):
     if self.is_in_mac_restricted_mode:
         if self.original_dict.get(Interface.MAC):
             raise NmstateValueError(
                 "MAC address cannot be specified in bond interface along "
                 "with fail_over_mac active on active backup mode"
             )
         else:
             self.raw.pop(Interface.MAC, None)
Пример #22
0
def _generate_route_rule_per_stack_metadata(family, indexed_rules, routes,
                                            desired_state):
    for route_table, rules in indexed_rules.items():
        iface_name = _find_iface_for_route_table(routes, route_table)
        if not iface_name:
            raise NmstateValueError(
                "Failed to find suitable interface for saving route rule: "
                "{}".format(rules[0]))
        iface_state = desired_state.interfaces[iface_name]
        _attach_route_rule_metadata(iface_state, rules, family)
Пример #23
0
 def _validate_unknown_slaves(self):
     """
     Check the existance of slave interface
     """
     for iface in self._ifaces.values():
         for slave_name in iface.slaves:
             if not self._ifaces.get(slave_name):
                 raise NmstateValueError(
                     f"Interface {iface.name} has unknown slave: "
                     f"{slave_name}")
Пример #24
0
 def _validate_vlan_filtering_enable_native(self):
     for port_config in self.original_dict.get(LinuxBridge.CONFIG_SUBTREE,
                                               {}).get(
                                                   LinuxBridge.PORT_SUBTREE,
                                                   []):
         vlan_config = _get_port_vlan_config(port_config)
         if _vlan_is_access_mode(vlan_config) and _vlan_is_enable_native(
                 vlan_config):
             raise NmstateValueError(
                 "enable-native cannot be set in access mode")
Пример #25
0
def _choose_checkpoint(dbuspath):
    if not dbuspath:
        candidates = nm.checkpoint.get_checkpoints()
        if candidates:
            dbuspath = candidates[0]

    if not dbuspath:
        raise NmstateValueError("No checkpoint specified or found")
    checkpoint = nm.checkpoint.CheckPoint(dbuspath=dbuspath)
    return checkpoint
Пример #26
0
    def _activation_progress_check(self, action):
        if self._ctx.is_cancelled():
            self._activation_clean_up()
            return
        devname = self._nm_dev.get_iface()
        cur_nm_dev = self._ctx.get_nm_dev(devname)
        if cur_nm_dev and cur_nm_dev != self._nm_dev:
            logging.debug(f"The NM.Device of profile {devname} changed")
            self._remove_dev_handlers()
            self._nm_dev = cur_nm_dev
            self.wait_dev_activation(action)

        cur_nm_ac = get_device_active_connection(self.nmdevice)
        if cur_nm_ac and cur_nm_ac != self._nm_ac:
            logging.debug(
                "Active connection of device {} has been replaced".format(
                    self.devname
                )
            )
            self._remove_ac_handlers()
            self._nm_ac = cur_nm_ac
            self._wait_ac_activation(action)
        if is_activated(self._nm_ac, self._nm_dev):
            logging.debug(
                "Connection activation succeeded: dev=%s, con-state=%s, "
                "dev-state=%s, state-flags=%s",
                devname,
                self._nm_ac.get_state(),
                self._nm_dev.get_state(),
                self._nm_ac.get_state_flags(),
            )
            self._activation_clean_up()
            self._ctx.finish_async(action)
        elif (
            not self._is_activating()
            and self._is_sriov_parameter_not_supported_by_driver()
        ):
            reason = (
                f"The device={self.devname} does not support one or "
                "more of the SR-IOV parameters set."
            )
            self._activation_clean_up()
            self._ctx.fail(
                NmstateValueError(f"{action} failed: reason={reason}")
            )
        elif not self._is_activating():
            reason = f"{self._nm_ac.get_state_reason()}"
            if self.nmdevice:
                reason += f" {self.nmdevice.get_state_reason()}"
            self._activation_clean_up()
            self._ctx.fail(
                NmstateLibnmError(f"{action} failed: reason={reason}")
            )
Пример #27
0
def _parse_checkpoints(checkpoints):
    """
    Return a dict mapping plugin name to checkpoint
    """
    if not checkpoints:
        return None
    parsed = checkpoints.split("|")
    if len(parsed) % 2:
        raise NmstateValueError("Invalid format of checkpoint")
    checkpoint_index = {}
    for plugin_name, checkpoint in zip(parsed[0::2], parsed[1::2]):
        checkpoint_index[plugin_name] = checkpoint
Пример #28
0
    def _validate_vlan_filtering_trunk_tags(self):
        for port_config in self.original_dict.get(LinuxBridge.CONFIG_SUBTREE,
                                                  {}).get(
                                                      LinuxBridge.PORT_SUBTREE,
                                                      []):
            port_vlan_state = port_config.get(LinuxBridge.Port.VLAN_SUBTREE,
                                              {})
            vlan_mode = port_vlan_state.get(LinuxBridge.Port.Vlan.MODE)
            trunk_tags = port_vlan_state.get(LinuxBridge.Port.Vlan.TRUNK_TAGS,
                                             [])

            if vlan_mode == LinuxBridge.Port.Vlan.Mode.ACCESS:
                if trunk_tags:
                    raise NmstateValueError(
                        "Access port cannot have trunk tags")
            elif port_vlan_state:
                if not trunk_tags:
                    raise NmstateValueError(
                        "A trunk port needs to specify trunk tags")
            for trunk_tag in trunk_tags:
                _assert_vlan_filtering_trunk_tag(trunk_tag)
Пример #29
0
 def _load_checkpoint(self, checkpoint_path):
     if checkpoint_path:
         if self._checkpoint:
             # Old checkpoint might timeout, hence it's legal to load
             # another one.
             self._checkpoint.clean_up()
         candidates = get_checkpoints(self._ctx.client)
         if checkpoint_path in candidates:
             self._checkpoint = CheckPoint(nm_context=self._ctx,
                                           dbuspath=checkpoint_path)
         else:
             raise NmstateValueError("No checkpoint specified or found")
     else:
         if not self._checkpoint:
             # Get latest one
             candidates = get_checkpoints(self._ctx.client)
             if candidates:
                 self._checkpoint = CheckPoint(nm_context=self._ctx,
                                               dbuspath=candidates[0])
             else:
                 raise NmstateValueError("No checkpoint specified or found")
Пример #30
0
def _assert_vxlan_has_missing_attribute(state, *attributes):
    vxlan_config = state.get(VXLAN.CONFIG_SUBTREE, {})
    if not vxlan_config:
        return
    attributes_set = set(attributes)
    vxlan_config_set = set(vxlan_config)
    if not (attributes_set <= vxlan_config_set):
        raise NmstateValueError(
            "Vxlan tunnel {} has missing {}: {}".format(
                state[schema.Interface.NAME],
                attributes_set.difference(vxlan_config_set),
                state,
            )
        )