def _setup_bridge(bridge, ip=None, prefix=None, ifc=None):
    """ Sets up a bridge. If the bridge does not exist, it is created.
    If an ip address and prefix are given it will be added to the bridge.
    If an interface name is specified it will be attached to the bridge
    Args:
        bridge (str) bridge name
        ip (str) ipv4 address (ie '1.2.3.4')
        prefix (int or str) Network mask length (ie 24)
        ifc (str) An interface name
    """
    LOG.debug('Setting up bridge {} with ifc {} and address {}'
              .format(bridge, ifc, ip))
    if not IPR.link_lookup(ifname=bridge):
        IPR.link("add", ifname=bridge, kind="bridge")
    IPR.link("set", ifname=bridge, state="up")
    if ip and prefix:
        if not _is_addr_on_link(ip, bridge):
            IPR.addr(
                'add', index=IPR.link_lookup(ifname=bridge)[0],
                address=ip,
                mask=int(prefix))
    if ifc:
        IPR.link(
            'set',
            index=IPR.link_lookup(ifname=ifc)[0],
            master=IPR.link_lookup(ifname=bridge)[0])
    if not _wait_for_ifc_up(ifc):
        LOG.error('Failed to bring up interface {}'.format(ifc))
        raise UserCriticalException('Failed to bring up interface {}'.format(ifc))
    if not _wait_for_ifc_up(bridge):
        LOG.error('Failed to bring up bridge {}'.format(bridge))
        raise UserCriticalException('Failed to bring up bridge {}'.format(bridge))
    def validate_config_schema(self):
        """Config schema validation

        Exception:
            If schema validation fails
        """

        schema = SchemaDefinition.get_schema(ordered=True)
        try:
            validate(self.config,
                     schema,
                     format_checker=jsonschema.FormatChecker())
        except jsonschema.exceptions.ValidationError as error:
            if error.cause is None:
                path = None
                for index, element in enumerate(error.path):
                    if isinstance(element, int):
                        path += '[{}]'.format(element)
                    else:
                        if index == 0:
                            path = '{}'.format(element)
                        else:
                            path += '.{}'.format(element)
                exc = 'Schema validation failed - {} - {}'.format(
                    path, error.message)
            else:
                exc = 'Schema validation failed - {} - {}'.format(
                    error.cause, error.message)
            if 'Additional properties are not allowed' in error.message:
                raise UserException(exc)
            else:
                raise UserCriticalException(exc)
Beispiel #3
0
 def _config_file(self):
     from lib.inv_items import InventoryNodes
     print(COL.scroll_ten, COL.up_ten)
     print('{}Validating cluster configuration file{}\n'.format(
         COL.header1, COL.endc))
     dbase = DatabaseConfig(self.config_file_path)
     inv_path = gen.GEN_LOGS_PATH + gen.INV_FILE_NAME
     nodes = InventoryNodes(inv_path, self.config_file_path)
     try:
         dbase.validate_config()
         nodes.create_nodes()
         rc, stdout = _run_playbook("validate_bootstrap_vars.yml",
                                    self.config_file_path,
                                    extra_vars=self.args.extra_vars,
                                    display=False,
                                    load_config_vars=True)
         if rc != 0:
             raise UserCriticalException(stdout)
     except UserCriticalException as exc:
         message = 'Failure: Config file validation.\n' + str(exc)
         print('{}{}{}'.format(COL.red, message, COL.endc))
         sys.exit(1)
     except UserException as exc:
         message = 'Warning: Config file validation.\n' + str(exc)
         print('{}{}{}'.format(COL.yellow, message, COL.endc))
     else:
         print('Successfully completed config file validation.\n')
    def validate_config_logic(self):
        """Config logic validation"""

        self._validate_version()
        self._validate_physical_interfaces()
        self._validate_deployer_networks()
        self._validate_dhcp_lease_time()

        if self.exc:
            raise UserCriticalException(self.exc)
    def validate_config_logic(self):
        """Config logic validation"""

        self._validate_version()
        self._validate_physical_interfaces()
        self._validate_deployer_networks()
        self._validate_dhcp_lease_time()
        self._validate_labels()
        self._validate_software_bootstrap()
        self._validate_os_profiles()

        if self.exc:
            raise UserCriticalException(self.exc)
    def validate_pxe(self, bootdev='default', persist=True):
        # if self.inv.check_all_nodes_pxe_macs():
        #     self.log.info("Inventory exists with PXE MACs populated.")
        #     if not self.ran_ipmi:
        #         return
        #     print("\nPress Enter to continue cluster deployment without "
        #           "running PXE hardware validation.")
        #     print("Type 'C' to validate cluster nodes defined in current "
        #           "'config.yml'")
        #     resp = input("Type 'T' to terminate Power-Up ")
        #     if resp == 'T':
        #         resp = input("Type 'y' to confirm ")
        #         if resp == 'y':
        #             self.log.info("'{}' entered. Terminating Power-Up at user "
        #                           "request".format(resp))
        #             sys.exit(1)
        #     elif resp == 'C':
        #         self.log.info("'{}' entered. Continuing with hardware "
        #                       "validation".format(resp))
        #     else:
        #         print()
        #         return
        # if not self.ran_ipmi:
        #     return
        if not self.node_table_ipmi:
            raise UserCriticalException('No BMCs discovered')
        self.log.debug("Checking PXE networks and client PXE"
                       " ports ________\n")
        self.log.debug('Boot device: {}'.format(bootdev))
        ipmi_cnt, pxe_cnt = self._get_port_cnts()
        pxe_addr, bridge_addr, pxe_prefix, pxe_vlan = self._get_network('pxe')
        pxe_network = pxe_addr + '/' + str(pxe_prefix)
        addr = IPNetwork(bridge_addr + '/' + str(pxe_prefix))
        netmask = str(addr.netmask)
        addr.value += NAME_SPACE_OFFSET_ADDR
        addr = str(addr)
        foundall = False
        dhcp_st = get_dhcp_pool_start()
        pxe_ns = NetNameSpace('pxe-ns-', 'br-pxe-' + str(pxe_vlan), addr)

        # setup DHCP. save start and end addr raw numeric values
        self.log.debug('Installing DHCP server in network namespace')
        addr_st = self._add_offset_to_address(pxe_network, dhcp_st)
        addr_end = self._add_offset_to_address(pxe_network,
                                               dhcp_st + pxe_cnt + 2)

        dns_list, stderr, rc = sub_proc_exec('pgrep dnsmasq')
        dns_list = dns_list.splitlines()

        if os.path.exists(self.dhcp_pxe_leases_file):
            os.remove(self.dhcp_pxe_leases_file)

        # delete any remnant dnsmasq processes
        for pid in dns_list:
            ns_name, stderr, rc = sub_proc_exec(
                'ip netns identify {}'.format(pid))
            if pxe_ns._get_name_sp_name() in ns_name:
                self.log.debug('Killing dnsmasq. pid {}'.format(pid))
                stdout, stderr, rc = sub_proc_exec('kill -15 ' + pid)

        cmd = (f'dnsmasq --dhcp-leasefile={self.dhcp_pxe_leases_file} '
               f'--interface={pxe_ns._get_name_sp_ifc_name()} '
               f'--dhcp-range={addr_st},{addr_end},{netmask},3600')
        stdout, stderr, rc = pxe_ns._exec_cmd(cmd)
        if rc != 0:
            self.log.warning(f'Error configuring dnsmasq. rc: {rc}')

        if os.path.exists(self.tcp_dump_file):
            os.remove(self.tcp_dump_file)

        tcpdump_list, stderr, rc = sub_proc_exec('pgrep tcpdump')
        tcpdump_list = tcpdump_list.splitlines()

        # delete any remnant tcpdump processes
        for pid in tcpdump_list:
            ns_name, stderr, rc = sub_proc_exec('ip netns identify ' + pid)
            if pxe_ns._get_name_sp_name() in ns_name:
                self.log.debug('Killing tcpdump. pid {}'.format(pid))
                stdout, stderr, rc = sub_proc_exec('kill -15 ' + pid)

        cmd = (f'sudo tcpdump -X -U -i {pxe_ns._get_name_sp_ifc_name()} '
               f'-w {self.tcp_dump_file} --immediate-mode  port 67')
        proc = pxe_ns._launch_cmd(cmd)
        if not isinstance(proc, object):
            self.log.error(
                f'Failure to launch process of tcpdump monitor {proc}')

        # Scan up to 25 times. Delay 10 seconds between scans
        # Allow infinite number of retries
        self.log.info('Scanning pxe network on 10 s intervals.')
        cnt = 0
        cnt_prev = 0
        cnt_down = 25
        mac_list = []
        dump = ''
        while cnt < pxe_cnt:
            print()
            cmd = 'sudo tcpdump -r {} -xx'.format(self.tcp_dump_file)
            for i in range(cnt_down):
                print('\r{} of {} nodes requesting PXE boot. Scan cnt: {} '.
                      format(cnt, pxe_cnt, cnt_down - i),
                      end="")
                sys.stdout.flush()
                time.sleep(10)
                # read the tcpdump file if size is not 0
                if os.path.exists(self.tcp_dump_file) and os.path.getsize(
                        self.tcp_dump_file):
                    dump, stderr, rc = sub_proc_exec(cmd)
                    if rc != 0:
                        self.log.warning(
                            f'Error reading tcpdump file. rc: {rc}')
                    if 'reading' not in stderr:
                        self.log.warning(
                            f'Failure reading tcpdump file - {stderr}')
                mac_list = self._get_macs(mac_list, dump)
                cnt = len(mac_list)
                if cnt > cnt_prev:
                    cnt_prev = cnt
                    # Pause briefly for in flight DHCP to complete and lease file to update
                    time.sleep(5)
                    self._build_port_table_pxe(mac_list)
                if cnt >= pxe_cnt:
                    foundall = True
                    print(
                        '\r{} of {} nodes requesting PXE boot. Scan count: {} '
                        .format(cnt, pxe_cnt, cnt_down - i),
                        end="")
                    break
            self.log.debug('Table of found PXE ports: {}'.format(
                self.node_table_pxe))
            for switch in self.node_table_pxe:
                print('\n\nSwitch: {}'.format(switch))
                print(
                    tabulate(self.node_table_pxe[switch],
                             headers=('port', 'MAC address', 'IP address')))
                print()

            if cnt >= pxe_cnt:
                break
            print('\n\nPress Enter to continue scanning for cluster nodes.')
            print(
                "Or enter 'C' to continue cluster deployment with a subset of nodes"
            )
            print("Or enter 'R' to cycle power to missing nodes")
            resp = input("Or enter 'T' to terminate Power-Up ")
            if resp == 'T':
                resp = input("Enter 'y' to confirm ")
                if resp == 'y':
                    self.log.info("'{}' entered. Terminating Power-Up at user"
                                  " request".format(resp))
                    self._teardown_ns(self.ipmi_ns)
                    self._teardown_ns(pxe_ns)
                    sys.exit(1)
            elif resp == 'R':
                self._reset_unfound_nodes()
            elif resp == 'C':
                print('\nNot all nodes have been discovered')
                resp = input("Enter 'y' to confirm continuation of"
                             " deployment without all nodes ")
                if resp == 'y':
                    self.log.info(
                        "'{}' entered. Continuing Power-Up".format(resp))
                    break
        if cnt < pxe_cnt:
            self.log.warning('Failed to validate expected number of nodes')

        self._teardown_ns(pxe_ns)

        # Cycle power on all discovered nodes if bootdev set to 'network'
        if bootdev == 'network':
            self.log.debug('\nCycling power to discovered nodes.\n')
            set_power_clients('off', clients=self.bmc_ai)

            set_power_clients('on', clients=self.bmc_ai)

            set_bootdev_clients('network', clients=self.bmc_ai)

        self._teardown_ns(self.ipmi_ns)

        # Reset BMCs to insure they acquire a new address from container
        # during inv_add_ports. Avoids conflicting addresses during redeploy
        self._reset_existing_bmcs(self.node_list, self._get_cred_list())

        self.log.info('Cluster nodes validation complete')
        if not foundall:
            raise UserException('Not all node PXE ports validated')
    def validate_mgmt_switches(self):
        self.log.info('Verifying management switches')

        sw_cnt = self.cfg.get_sw_mgmt_cnt()
        self.log.debug(
            'Number of management switches defined in config file: {}'.format(
                sw_cnt))

        for index, switch_label in enumerate(self.cfg.yield_sw_mgmt_label()):
            print('.', end="")
            sys.stdout.flush()
            label = self.cfg.get_sw_mgmt_label(index)
            self.log.debug('switch_label: {}'.format(switch_label))

            switch_class = self.cfg.get_sw_mgmt_class(index)
            if not switch_class:
                self.log.error('No switch class found')
                return False
            userid = None
            password = None
            rc = True

            try:
                userid = self.cfg.get_sw_mgmt_userid(index)
            except AttributeError:
                self.log.debug('Passive switch mode specified')
                return rc

            try:
                password = self.cfg.get_sw_mgmt_password(index)
            except AttributeError:
                try:
                    self.cfg.get_sw_mgmt_ssh_key(index)
                except AttributeError:
                    return rc
                else:
                    self.log.error(
                        'Switch authentication via ssh keys not yet supported')
                    rc = False
            # Verify communication on each defined interface
            for ip in self.cfg.yield_sw_mgmt_interfaces_ip(index):
                self.log.debug('Verifying switch communication on ip address:'
                               ' {}'.format(ip))
                sw = SwitchFactory.factory(switch_class, ip, userid, password,
                                           'active')
                if sw.is_pingable():
                    self.log.debug(
                        'Successfully pinged management switch \"%s\" at %s' %
                        (label, ip))
                else:
                    self.log.warning(
                        'Failed to ping management switch \"%s\" at %s' %
                        (label, ip))
                    rc = False
                try:
                    vlans = sw.show_vlans()
                except (SwitchException, SSH_Exception):
                    self.log.error(
                        'Failed communicating with management switch'
                        ' at address {}'.format(ip))
                    rc = False

                if vlans and len(vlans) > 1:
                    self.log.debug(
                        'Successfully communicated with management switch \"%s\"'
                        ' at %s' % (label, ip))
                else:
                    self.log.warning(
                        'Failed to communicate with data switch \"%s\"'
                        'at %s' % (label, ip))
                    rc = False
        print()
        if rc:
            self.log.debug(' OK - All management switches verified')
        else:
            raise UserCriticalException(
                'Failed verification of management switches')
def configure_mgmt_switches(config_file=None):

    LOG = logger.getlogger()
    cfg = Config(config_file)
    LOG.debug(
        '------------------- configure_mgmt_switches -------------------')

    for index, switch_label in enumerate(cfg.yield_sw_mgmt_label()):
        mode = ACTIVE

        label = cfg.get_sw_mgmt_label(index)
        LOG.info('Configuring switch: {}'.format(switch_label))

        switch_class = cfg.get_sw_mgmt_class(index)
        if not switch_class:
            LOG.error('Unrecognized switch class')
            raise UserCriticalException('Unrecognized switch class')
        userid = None
        password = None
        switch_ip = None

        if cfg.is_passive_mgmt_switches():
            mode = PASSIVE

        try:
            userid = cfg.get_sw_mgmt_userid(index)
        except AttributeError:
            pass

        try:
            password = cfg.get_sw_mgmt_password(index)
        except AttributeError:
            try:
                cfg.get_sw_mgmt_ssh_key(index)
            except AttributeError:
                pass
            else:
                LOG.error(
                    'Switch authentication via ssh keys not yet supported')
                raise UserCriticalException(
                    'Switch authentication via ssh keys not yet supported')

        if mode == PASSIVE:
            sw = SwitchFactory.factory(switch_class, mode)

        elif mode == ACTIVE:
            # Try all ipaddrs in switches.interfaces
            for ip in cfg.yield_sw_mgmt_interfaces_ip(index):
                sw = SwitchFactory.factory(switch_class, ip, userid, password)
                # Get the enumerations needed to call set_switchport_mode() and
                # allowed_vlans_port()
                port_mode, allow_op = sw.get_enums()

                if sw.is_pingable():
                    LOG.debug(
                        'Sucessfully pinged management switch \"%s\" at %s' %
                        (label, ip))
                    switch_ip = ip
                    break

                LOG.debug('Failed to ping management switch \"%s\" at %s' %
                          (label, ip))

            else:
                LOG.error('Management switch is not responding to pings')
                raise UserCriticalException(
                    'Management switch at address {} is not responding to '
                    'pings'.format(ip))

        LOG.debug('%d: \"%s\" (%s) %s %s/%s' %
                  (index, switch_label, mode, switch_ip, userid, password))

        ports_cfg = sw.show_ports(format='std')

        sw_vlans = []
        for port in ports_cfg:
            if int(ports_cfg[str(port)]['nvlan']) not in sw_vlans:
                sw_vlans.append(int(port))
            avlans = ports_cfg[str(port)]['avlans'].split(', ')
            for avlan in avlans:
                if avlan and int(avlan) not in sw_vlans:
                    sw_vlans.append(int(avlan))

        vlan_mgmt = cfg.get_depl_netw_mgmt_vlan()
        vlan_mgmt = [x for x in vlan_mgmt if x is not None]
        LOG.debug('Management vlans: {}'.format(vlan_mgmt))

        vlan_client = cfg.get_depl_netw_client_vlan()
        LOG.debug('vlan_mgmt: {} , vlan_client: {}'.format(
            vlan_mgmt, vlan_client))
        for vlan in vlan_mgmt + vlan_client:
            if vlan and vlan not in sw_vlans:
                print('.', end="")
                sys.stdout.flush()
                sw.create_vlan(vlan)

        for intf_i, ip in enumerate(cfg.yield_sw_mgmt_interfaces_ip(index)):
            if ip != switch_ip:
                vlan = cfg.get_sw_mgmt_interfaces_vlan(index, intf_i)
                if vlan is None:
                    vlan = vlan_mgmt[0]
                netmask = cfg.get_sw_mgmt_interfaces_netmask(index, intf_i)

                try:
                    LOG.debug(
                        "Configuring mgmt switch \"%s\" inband interface. "
                        "(ip=%s netmask=%s vlan=%s)" %
                        (label, ip, netmask, vlan))
                    # sw.configure_interface(ip, netmask, vlan, port)
                    sw.configure_interface(ip, netmask, vlan)
                except SwitchException as exc:
                    LOG.warning(exc)

        for target_i, target in (enumerate(
                cfg.yield_sw_mgmt_links_target(index))):
            port = cfg.get_sw_mgmt_links_port(index, target_i)
            if target.lower() == 'deployer':
                vlans = vlan_mgmt + vlan_client
                if ports_cfg[str(port)]['mode'] != 'trunk':
                    try:
                        print('.', end="")
                        sys.stdout.flush()
                        LOG.debug('Adding vlans {} to port {}'.format(
                            vlans, port))
                        sw.set_switchport_mode(port, port_mode.TRUNK)
                    except SwitchException as exc:
                        LOG.error(exc)
                else:
                    LOG.debug('Port {} already in trunk mode'.format(port))
                port_vlans = ports_cfg[str(port)]['avlans'].split(', ')
                add_vlans = False
                for vlan in vlan_client:
                    if str(vlan) not in port_vlans:
                        add_vlans = True
                if (vlan_mgmt
                        and str(vlan_mgmt) not in port_vlans) or add_vlans:
                    try:
                        sw.allowed_vlans_port(port, allow_op.ADD, vlans)
                    except SwitchException as exc:
                        LOG.error(exc)
            else:
                vlan = cfg.get_sw_mgmt_links_vlan(index, target_i)
                if vlan is None:
                    if not vlan_mgmt:
                        vlan = 1
                    else:
                        vlan = vlan_mgmt[0]
                if ports_cfg[str(port)]['mode'] != 'trunk' or \
                        str(vlan) not in ports_cfg[str(port)]['avlans'].split(', '):
                    try:
                        sw.set_switchport_mode(port, port_mode.TRUNK)
                        sw.allowed_vlans_port(port, allow_op.NONE)
                        sw.allowed_vlans_port(port, allow_op.ADD, vlan)
                        sw.set_switchport_mode(port, port_mode.TRUNK, vlan)
                    except SwitchException as exc:
                        LOG.error(exc)

        for if_type in ['ipmi', 'pxe']:
            vlan = cfg.get_depl_netw_client_vlan(if_type=if_type)[0]

            for port in cfg.yield_client_switch_ports(switch_label, if_type):
                if mode == 'passive':
                    LOG.debug(
                        'Set switchport mode - switch is in passive mode.')
                else:
                    print('.', end="")
                    sys.stdout.flush()
                    if vlan != int(ports_cfg[str(port)]['nvlan']):
                        try:
                            LOG.debug(
                                'Setting port {} into {} mode with access '
                                'vlan {}'.format(port, port_mode.ACCESS, vlan))
                            sw.set_switchport_mode(port, port_mode.ACCESS,
                                                   vlan)
                        except SwitchException as exc:
                            LOG.error(exc)
                    else:
                        LOG.debug(
                            '\n{} port {} access vlan already configured.'.
                            format(if_type, port))
            # Remove (optionally) access vlan from ports in pxe or ipmi vlan that
            # are not listed in the config file.
            ports = cfg.get_client_switch_ports(switch_label, if_type)
            resp = 'y'
            for port in ports_cfg:
                if int(port) not in ports and ports_cfg[port]['nvlan'] == str(
                        vlan):
                    msg = (
                        'Port {} on switch {} configured with vlan {} but is '
                        'not specified in the {} network in your cluster config '
                        'file '.format(port, switch_label, vlan, if_type))
                    print()
                    LOG.warning(msg)
                    if resp not in ('yta', 'nta'):
                        resp = rlinput(
                            '\nOK to remove port {} from {} vlan '
                            '(y/yta/n/nta)? '.format(port, if_type), 'y')
                    if resp in ('y', 'yta'):
                        sw.set_switchport_mode(port, port_mode.ACCESS, 1)
def configure_mgmt_switches(config_file=None):

    LOG = logger.getlogger()
    cfg = Config(config_file)
    LOG.debug(
        '------------------- configure_mgmt_switches -------------------')

    for index, switch_label in enumerate(cfg.yield_sw_mgmt_label()):
        mode = ACTIVE

        label = cfg.get_sw_mgmt_label(index)
        LOG.info('Configuring switch: {}'.format(switch_label))

        switch_class = cfg.get_sw_mgmt_class(index)
        if not switch_class:
            LOG.error('Unrecognized switch class')
            raise UserCriticalException('Unrecognized switch class')
        userid = None
        password = None
        switch_ip = None

        if cfg.is_passive_mgmt_switches():
            mode = PASSIVE

        try:
            userid = cfg.get_sw_mgmt_userid(index)
        except AttributeError:
            pass

        try:
            password = cfg.get_sw_mgmt_password(index)
        except AttributeError:
            try:
                cfg.get_sw_mgmt_ssh_key(index)
            except AttributeError:
                pass
            else:
                LOG.error(
                    'Switch authentication via ssh keys not yet supported')
                raise UserCriticalException(
                    'Switch authentication via ssh keys not yet supported')

        if mode == PASSIVE:
            sw = SwitchFactory.factory(switch_class, mode)

        elif mode == ACTIVE:
            # Try all ipaddrs in switches.interfaces
            for ip in cfg.yield_sw_mgmt_interfaces_ip(index):
                sw = SwitchFactory.factory(switch_class, ip, userid, password)
                # Get the enumerations needed to call set_switchport_mode() and
                # allowed_vlans_port()
                port_mode, allow_op = sw.get_enums()

                if sw.is_pingable():
                    LOG.debug(
                        'Sucessfully pinged management switch \"%s\" at %s' %
                        (label, ip))
                    switch_ip = ip
                    break

                LOG.debug('Failed to ping management switch \"%s\" at %s' %
                          (label, ip))

            else:
                LOG.error('Management switch is not responding to pings')
                raise UserCriticalException(
                    'Management switch at address {} is not responding to '
                    'pings'.format(ip))

        LOG.debug('%d: \"%s\" (%s) %s %s/%s' %
                  (index, switch_label, mode, switch_ip, userid, password))

        vlan_mgmt = cfg.get_depl_netw_mgmt_vlan()
        vlan_mgmt = [x for x in vlan_mgmt if x is not None]
        LOG.debug('Management vlans: {}'.format(vlan_mgmt))

        vlan_client = cfg.get_depl_netw_client_vlan()
        LOG.debug('vlan_mgmt: {} , vlan_client: {}'.format(
            vlan_mgmt, vlan_client))
        for vlan in vlan_mgmt + vlan_client:
            if vlan:
                print('.', end="")
                sys.stdout.flush()
                sw.create_vlan(vlan)

        for intf_i, ip in enumerate(cfg.yield_sw_mgmt_interfaces_ip(index)):
            if ip != switch_ip:
                vlan = cfg.get_sw_mgmt_interfaces_vlan(index, intf_i)
                if vlan is None:
                    vlan = vlan_mgmt[0]
                netmask = cfg.get_sw_mgmt_interfaces_netmask(index, intf_i)

                try:
                    LOG.debug(
                        "Configuring mgmt switch \"%s\" inband interface. "
                        "(ip=%s netmask=%s vlan=%s)" %
                        (label, ip, netmask, vlan))
                    # sw.configure_interface(ip, netmask, vlan, port)
                    sw.configure_interface(ip, netmask, vlan)
                except SwitchException as exc:
                    LOG.warning(exc)

        for target_i, target in (enumerate(
                cfg.yield_sw_mgmt_links_target(index))):
            port = cfg.get_sw_mgmt_links_port(index, target_i)
            if target.lower() == 'deployer':
                try:
                    print('.', end="")
                    sys.stdout.flush()
                    vlans = vlan_mgmt + vlan_client
                    LOG.debug('Adding vlans {} to port {}'.format(vlans, port))
                    sw.set_switchport_mode(port, port_mode.TRUNK)
                except SwitchException as exc:
                    LOG.error(exc)
                try:
                    sw.allowed_vlans_port(port, allow_op.ADD, vlans)
                except SwitchException as exc:
                    LOG.error(exc)
            else:
                vlan = cfg.get_sw_mgmt_links_vlan(index, target_i)
                if vlan is None:
                    if not vlan_mgmt:
                        vlan = 1
                    else:
                        vlan = vlan_mgmt[0]
                try:
                    sw.set_switchport_mode(port, port_mode.TRUNK)
                    sw.allowed_vlans_port(port, allow_op.NONE)
                    sw.allowed_vlans_port(port, allow_op.ADD, vlan)
                    sw.set_switchport_mode(port, port_mode.TRUNK, vlan)
                except SwitchException as exc:
                    LOG.error(exc)
        for if_type in ['ipmi', 'pxe']:
            vlan = cfg.get_depl_netw_client_vlan(if_type=if_type)[0]

            for port in cfg.yield_client_switch_ports(switch_label, if_type):
                if mode == 'passive':
                    LOG.debug(
                        'Set switchport mode - switch is in passive mode.')
                else:
                    print('.', end="")
                    sys.stdout.flush()
                    try:
                        LOG.debug('Setting port {} into {} mode with access '
                                  'vlan {}'.format(port, port_mode.ACCESS,
                                                   vlan))
                        sw.set_switchport_mode(port, port_mode.ACCESS, vlan)
                    except SwitchException as exc:
                        LOG.error(exc)
def _create_network(
        dev_label,
        interface_ipaddr,
        netprefix,
        container_ipaddr=None,
        bridge_ipaddr=None,
        vlan=None,
        _type='mgmt'):
    """ Creates a network between the container interface and a physical interface.
    If no bridge ip address is specified, the connection is via the default lxc
    bridge. If a bridge ip address and vlan are specified, a bridge is created.
    Inputs:
        dev_label (str): Name of the physical device providing external connectivity
            for the network.
        interface_ipaddr (str): ipv4 address of the phsical device specified by
            dev_label. If the address does not already exist on the interface it is
            added.
        netprefix (int): Size in bits of the network address.
        container_ipaddr (str): ip address of the management interface in the
        PowerUp container.
        bridge_ipaddr (str): ip address of the bridge connecting the container and
        the physical device.
        vlan (int):
        type (str): Type of interface being served by the network (mgmt, pxe, ipmi)
        to be created.
    """

    ifc_addresses = _get_ifc_addresses()

    if not IPR.link_lookup(ifname=dev_label):
        LOG.error('External interface {} not found'.format(dev_label))
        raise UserCriticalException('External interface {} not found.'
                                    .format(dev_label))

    # if no bridge_ipaddr is specied (ie None), then a bridge will not be created.
    if not bridge_ipaddr:
        # if address not already on device, then add it.
        if not interface_ipaddr + '/' + str(netprefix) in ifc_addresses[dev_label]:
            LOG.debug('Adding address {} to link {}'.
                      format(interface_ipaddr, dev_label))
            index = IPR.link_lookup(ifname=dev_label)
            IPR.addr('add', index=index, address=interface_ipaddr, mask=netprefix)
        else:
            LOG.debug('Address {} already exists on link {}'.
                      format(interface_ipaddr, dev_label))

        # Check to see if the device and address is configured in any interface
        # definition file. If not, then write a definition file.
        ifc_file_list = _get_ifcs_file_list()

        for filename in ifc_file_list:
            ifc_cfgd, addr_cfgd = _is_ifc_configured(filename, dev_label, interface_ipaddr)
            if ifc_cfgd:
                break

        broadcast = None
        netmask = str(IPNetwork('255.255.255.255/' + str(netprefix)).netmask)
        if not addr_cfgd:
            _write_ifc_cfg_file(
                dev_label,
                ip=interface_ipaddr,
                mask=netmask,
                broadcast=broadcast,
                ifc_cfgd=ifc_cfgd)
    # bridge
    else:
        # Check for existing addresses on the external interface and
        # remove any that lie within the mgmt subnet. You only need to remove
        # the first address found in the subnet since any additional ones are
        # secondary and removed when the first (primary) is removed. Note that
        # this does not remove addresses from network config files.
        cidr = IPNetwork(bridge_ipaddr + '/' + str(netprefix))
        network = IPNetwork(cidr)
        network_addr = str(network.network)

        for addr in IPR.get_addr(label=dev_label):
            pfx = int(addr['prefixlen'])
            adr = addr.get_attr('IFA_ADDRESS')
            existing_network = IPNetwork(
                addr.get_attr('IFA_ADDRESS') + '/' + str(addr['prefixlen']))
            existing_network_addr = str(existing_network.network)
            if existing_network_addr == network_addr:
                LOG.debug(
                    'Removing address {}/{} from interface {}'
                    .format(adr, pfx, dev_label))
                IPR.addr(
                    'delete',
                    index=IPR.link_lookup(ifname=dev_label),
                    address=adr,
                    mask=pfx)

        # Prepare to setup the bridge
        br_label = 'br-' + _type
        if vlan and vlan != 4095:
            br_label = br_label + '-' + str(vlan)
        link = dev_label
        # if a vlan other than 1 or 4095 is specified, create the vlan link
        if vlan and vlan != 4095:
            link = dev_label + '.{}'.format(vlan)
        # if the vlan link already exists on another bridge then display warning
        if _is_ifc_attached_elsewhere(link, br_label):
            LOG.warning('Link {} already in use on another bridge.'.format(link))
            print('Warning: Link {} already in use on another bridge.'.format(link))

        if not IPR.link_lookup(ifname=link):
            LOG.debug('creating vlan interface: {}'.format(link))
            IPR.link(
                "add",
                ifname=link,
                kind="vlan",
                link=IPR.link_lookup(ifname=dev_label)[0],
                vlan_id=vlan)
        IPR.link("set", index=IPR.link_lookup(ifname=link)[0], state="up")
        if not _wait_for_ifc_up(link):
            raise UserCriticalException('Failed to bring up interface {} '.
                                        format(link))

        # set bridge file write mode to 'w' (write) or 'a' (append)
        mode = 'a' if _type == 'mgmt' else 'w'

        if IPR.link_lookup(ifname=br_label):
            LOG.info('{}NOTE: bridge {} is already configured.{}'.format(Color.bold,
                     br_label, Color.endc))
            print("Enter to continue, or 'T' to terminate deployment")
            resp = input("\nEnter or 'T': ")
            if resp == 'T':
                sys.exit('POWER-Up stopped at user request')

        _write_br_cfg_file(
            br_label,
            ip=bridge_ipaddr,
            prefix=netprefix,
            ifc=link,
            mode=mode)
        _setup_bridge(br_label, bridge_ipaddr, netprefix, link)
        _update_firewall(br_label)
def _write_br_cfg_file(bridge, ip=None, prefix=None, ifc=None, mode='w'):
    """ Writes the config file for the specified bridge.  If the specified
    interface is not configured, a config file is created for it also.  If
    mode is set to 'a' (append) and the bridge config file exists, the
    specified interface is added to the bridge config file.  If mode is
    unspecified or set to 'w' (write), the config file is created or
    overwritten. The interface specified by 'ifc' is attached to the bridge.
    Args:
        bridge (str) bridge name
        ip (str) ipv4 address to be added to the bridge
        prefix (int or str) network prefix length.  ie the length of the
            network portion of the ip address
        ifc (str) name of the interface to be added to the bridge.
    """
    LOG.debug('OS: ' + OPSYS)
    if OPSYS not in ('debian', 'Ubuntu', 'redhat'):
        LOG.error('Unsupported Operating System')
        raise UserCriticalException('Unsupported Operating System')
    network = IPNetwork(ip + '/' + str(prefix))
    network_addr = str(network.network)
    broadcast = str(network.broadcast)
    netmask = str(network.netmask)
    if OPSYS in ('debian', 'Ubuntu'):
        if mode == 'a' and os.path.exists('/etc/network/interfaces.d/' + bridge):
            LOG.debug('Appending to bridge config file {} IP addr {}'.
                      format(bridge, ip))
            os.system(
                'cp /etc/network/interfaces.d/{} {}{} '
                .format(bridge, GEN_PATH, bridge))
            f = open(GEN_PATH + bridge, 'r')
            data = f.read()
            f.close()
            data = data.split('auto')
            f = open(GEN_PATH + bridge, 'w')
            # Write the specified interface if it is a vlan interface
            # If the interface already exists in the file it will be replaced
            f.write(data[0])
            if '.' in ifc:
                f.write('auto {}\n'.format(ifc))
                f.write('iface {} inet manual\n'.format(ifc))
                f.write('    vlan-raw-device {}\n\n'.format(ifc[:ifc.find('.')]))
            for item in data[1:len(data) - 1]:
                if not ('iface ' + ifc + ' ') in item:
                    f.write('auto' + item)
            # rewrite the bridge config
            data = ('auto' + data[len(data) - 1]).splitlines()
            for item in data:
                item = item + ' '
                if 'bridge_ports' in item and not ifc + ' ' in item:
                    item = item + ifc
                f.write(item.rstrip(' ') + '\n')
            f.close()
            os.system(
                'sudo cp {}{} /etc/network/interfaces.d/{}'
                .format(GEN_PATH, bridge, bridge))
            os.system('rm ' + GEN_PATH + bridge)

        else:
            LOG.debug('Wrting bridge configuration file: {} IP addr: {}'.
                      format(bridge, ip))
            f = open(GEN_PATH + bridge, 'w')
            f.write("# This file should not be edited manually\n")
            f.write('auto {}\n'.format(ifc))
            f.write('iface {} inet manual\n'.format(ifc))
            f.write('    vlan-raw-device {}\n\n'.format(ifc[:ifc.find('.')]))
            f.write('auto {}\n'.format(bridge))
            f.write('iface {} inet static\n'.format(bridge))
            f.write('    address {}\n'.format(ip))
            f.write('    netmask {}\n'.format(netmask))
            f.write('    broadcast {}\n'.format(broadcast))
            f.write('    network {}\n'.format(network_addr))
            f.write('    bridge_ports {}\n'.format(ifc))
            f.write('    bridge fd 0\n')
            f.close()
            os.system(
                'sudo cp {}{} /etc/network/interfaces.d/{}'
                .format(GEN_PATH, bridge, bridge))
            os.system('rm ' + GEN_PATH + bridge)
        return
    elif OPSYS == 'redhat':
        # Create the ifc config file
        # non vlan ifc
        if '.' not in ifc:
            _write_ifc_cfg_file(ifc, bridge=bridge)
        # vlan ifc
        else:
            file_path = IFCFG_PATH + f'ifcfg-{ifc}'
            with open(file_path, 'w') as f:
                LOG.debug(f'Writing vlan config file:\n{file_path}')
                f.write(f'DEVICE={ifc}\n')
                f.write('ONBOOT=yes\n')
                f.write('BOOTPROTO=none\n')
                f.write('NM_CONTROLLED=no\n')
                f.write('VLAN=yes\n')
                f.write(f'BRIDGE={bridge}')

        # Create the bridge config file
        file_path = f'{IFCFG_PATH}ifcfg-{bridge}'
        if mode == 'a' and os.path.isfile(file_path):
            LOG.debug(f'Appending to bridge config file {bridge} IP addr {ip}')
            ifc_cfgd, addr_cfgd = _is_ifc_configured(file_path, ifc, ip)
            if not addr_cfgd:
                ipaddr_num = _get_ip_addr_num(file_path)
                with open(file_path, 'a') as f:
                    f.write(f'IPADDR{ipaddr_num}={ip}\n')
                    f.write(f'PREFIX{ipaddr_num}={prefix}')
        else:
            with open(file_path, 'w') as f:
                f.write(f'DEVICE={bridge}\n')
                f.write('ONBOOT=yes\n')
                f.write('TYPE=Bridge\n')
                f.write(f'IPADDR={ip}\n')
                f.write(f'PREFIX={prefix}\n')
                f.write('BOOTPROTO=none\n')
                f.write('NM_CONTROLLED=no\n')
                f.write('DELAY=0')
Beispiel #12
0
def _create_network(
        dev_label,
        interface_ipaddr,
        netprefix,
        container_ipaddr=None,
        bridge_ipaddr=None,
        vlan=None,
        type_='mgmt'):

    ifc_addresses = _get_ifc_addresses()

    if not IPR.link_lookup(ifname=dev_label):
        LOG.error('External interface {} not found'.format(dev_label))
        raise UserCriticalException('External interface {} not found.'
                                    .format(dev_label))

    # if a bridge_ipaddr is not specied, then a bridge will not be created.
    if not bridge_ipaddr:
        # if address not already on device, then add it.
        if not interface_ipaddr + '/' + str(netprefix) in ifc_addresses[dev_label]:
            LOG.debug('Adding address {} to link {}'.
                      format(interface_ipaddr, dev_label))
            index = IPR.link_lookup(ifname=dev_label)
            IPR.addr('add', index=index, address=interface_ipaddr, mask=netprefix)
        else:
            LOG.debug('Address {} already exists on link {}'.
                      format(interface_ipaddr, dev_label))

        # Check to see if the device and address is configured in any interface
        # definition file. If not, then write a definition file.
        ifc_file_list = _get_ifcs_file_list()

        ifc_cfgd = False
        addr_cfgd = False
        for filename in ifc_file_list:
            f = open(filename, 'r')
            interfaces = f.read()
            f.close()
            if re.findall(r'^ *auto\s+' + dev_label + '\s', interfaces, re.MULTILINE):
                ifc_cfgd = True
                LOG.debug('Device {} already configured in network configuration file {}'.
                          format(dev_label, filename))
            interfaces = interfaces.split('iface')
            for line in interfaces:
                if dev_label in line:
                    if re.findall(r'^ *address\s+' + interface_ipaddr, line, re.MULTILINE):
                        addr_cfgd = True
                        LOG.debug('Address {} configured in {}'.
                                  format(interface_ipaddr, filename))

        broadcast = None
        netmask = str(IPNetwork('255.255.255.255/' + str(netprefix)).netmask)
        if not addr_cfgd:
            _write_ifc_cfg_file(
                dev_label,
                ip=interface_ipaddr,
                mask=netmask,
                broadcast=broadcast,
                ifc_cfgd=ifc_cfgd)
    # bridge
    else:
        # Check for existing addresses on the external interface and
        # remove any that lie within the mgmt subnet. You only need to remove
        # the first address found in the subnet since any additional ones are
        # secondary and removed when the first (primary) is removed.

        cidr = IPNetwork(bridge_ipaddr + '/' + str(netprefix))
        network = IPNetwork(cidr)
        network_addr = str(network.network)

        for addr in IPR.get_addr(label=dev_label):
            pfx = int(addr['prefixlen'])
            adr = addr.get_attr('IFA_ADDRESS')
            existing_network = IPNetwork(
                addr.get_attr('IFA_ADDRESS') + '/' + str(addr['prefixlen']))
            existing_network_addr = str(existing_network.network)
            if existing_network_addr == network_addr:
                LOG.debug(
                    'Removing address {}/{} from interface {}'
                    .format(adr, pfx, dev_label))
                IPR.addr(
                    'delete',
                    index=IPR.link_lookup(ifname=dev_label),
                    address=adr,
                    mask=pfx)

        # Prepare to setup the bridge
        br_label = 'br-' + type_
        if vlan and vlan != 4095:
            br_label = br_label + '-' + str(vlan)
        link = dev_label
        # if a vlan other than 1 or 4095 is specified, create the vlan link
        if vlan and vlan != 4095:
            link = dev_label + '.{}'.format(vlan)
        # if the vlan link already exists on another bridge then display warning
        if _is_ifc_attached_elsewhere(link, br_label):
            LOG.warning('Link {} already in use on another bridge.'.format(link))
            print('Warning: Link {} already in use on another bridge.'.format(link))

        if not IPR.link_lookup(ifname=link):
            LOG.debug('creating vlan interface: {}'.format(link))
            IPR.link(
                "add",
                ifname=link,
                kind="vlan",
                link=IPR.link_lookup(ifname=dev_label)[0],
                vlan_id=vlan)
        IPR.link("set", index=IPR.link_lookup(ifname=link)[0], state="up")
        if not _wait_for_ifc_up(link):
            raise UserCriticalException('Failed to bring up interface {} '.
                                        format(link))

        # set bridge file write mode to 'w' (write) or 'a' (add)
        if type_ == 'mgmt':
            mode = 'a'
        else:
            mode = 'w'

        if IPR.link_lookup(ifname=br_label):
            LOG.info('{}NOTE: bridge {} is already configured.{}'.format(Color.bold,
                     br_label, Color.endc))
            print("Enter to continue, or 'T' to terminate deployment")
            resp = raw_input("\nEnter or 'T': ")
            if resp == 'T':
                sys.exit('POWER-Up stopped at user request')

        _write_br_cfg_file(
            br_label,
            ip=bridge_ipaddr,
            prefix=netprefix,
            ifc=link,
            mode=mode)
        _setup_bridge(br_label, bridge_ipaddr, netprefix, link)
Beispiel #13
0
def _write_br_cfg_file(bridge, ip=None, prefix=None, ifc=None, mode='w'):
    """ Writes the config file for the specified bridge.  If the specified
    interface is not configured, a config file is created for it also.  If
    mode is set to 'a' (append) and the bridge config file exists, the
    specified interface is added to the bridge config file.  If mode is
    unspecified or set to 'w' (write), the config file is created or
    overwritten.
    Args:
        bridge (str) bridge name
        ip (str) ipv4 address to be added to the bridge
        prefix (int or str) network prefix length.  ie the length of the
            network portion of the ip address
        ifc (str) name of the interface to be added to the bridge.
    """
    opsys = platform.dist()[0]
    LOG.debug('OS: ' + opsys)
    if opsys not in ('Ubuntu', 'redhat'):
        LOG.error('Unsupported Operating System')
        raise UserCriticalException('Unsupported Operating System')
    network = IPNetwork(ip + '/' + str(prefix))
    network_addr = str(network.network)
    broadcast = str(network.broadcast)
    netmask = str(network.netmask)
    if opsys == 'Ubuntu':
        if mode == 'a' and os.path.exists('/etc/network/interfaces.d/' + bridge):
            LOG.debug('Appending to bridge config file {} IP addr {}'.
                      format(bridge, ip))
            os.system(
                'cp /etc/network/interfaces.d/{} {}{} '
                .format(bridge, GEN_PATH, bridge))
            f = open(GEN_PATH + bridge, 'r')
            data = f.read()
            f.close()
            data = data.split('auto')
            f = open(GEN_PATH + bridge, 'w')
            # Write the specified interface if it is a vlan interface
            # If the interface already exists in the file it will be replaced
            f.write(data[0])
            if '.' in ifc:
                f.write('auto {}\n'.format(ifc))
                f.write('iface {} inet manual\n'.format(ifc))
                f.write('    vlan-raw-device {}\n\n'.format(ifc[:ifc.find('.')]))
            for item in data[1:len(data) - 1]:
                if not ('iface ' + ifc + ' ') in item:
                    f.write('auto' + item)
            # rewrite the bridge config
            data = ('auto' + data[len(data) - 1]).splitlines()
            for item in data:
                item = item + ' '
                if 'bridge_ports' in item and not ifc + ' ' in item:
                    item = item + ifc
                f.write(item.rstrip(' ') + '\n')
            f.close()
            os.system(
                'sudo cp {}{} /etc/network/interfaces.d/{}'
                .format(GEN_PATH, bridge, bridge))
            os.system('rm ' + GEN_PATH + bridge)

        else:
            LOG.debug('Wrting bridge configuration file: {} IP addr: {}'.
                      format(bridge, ip))
            f = open(GEN_PATH + bridge, 'w')
            f.write("# This file should not be edited manually\n")
            f.write('auto {}\n'.format(ifc))
            f.write('iface {} inet manual\n'.format(ifc))
            f.write('    vlan-raw-device {}\n\n'.format(ifc[:ifc.find('.')]))
            f.write('auto {}\n'.format(bridge))
            f.write('iface {} inet static\n'.format(bridge))
            f.write('    address {}\n'.format(ip))
            f.write('    netmask {}\n'.format(netmask))
            f.write('    broadcast {}\n'.format(broadcast))
            f.write('    network {}\n'.format(network_addr))
            f.write('    bridge_ports {}\n'.format(ifc))
            f.write('    bridge fd 0\n')
            f.close()
            os.system(
                'sudo cp {}{} /etc/network/interfaces.d/{}'
                .format(GEN_PATH, bridge, bridge))
            os.system('rm ' + GEN_PATH + bridge)

        os.system('cp /etc/lxc/lxc-usernet ' + GEN_PATH)
        f = open(GEN_PATH + 'lxc-usernet', 'r')
        data = f.read()
        f.close()
        username = os.getlogin()
        perm = re.findall(username + r'\s+veth\s+' + bridge, data, re.MULTILINE)
        permlxcbr0 = re.findall(username + r'\s+veth\s+lxcbr0', data, re.MULTILINE)
        if not perm or not permlxcbr0:
            LOG.debug('Updating lxc user network permissions')
            f = open(GEN_PATH + 'lxc-usernet', 'a')
            if not permlxcbr0:
                f.write(username + ' veth lxcbr0 10\n')
            if not perm:
                f.write(username + ' veth ' + bridge + ' 10\n')
            f.close()

            os.system('sudo cp ' + GEN_PATH + 'lxc-usernet /etc/lxc/lxc-usernet')
        return
    LOG.error('Support for Red Hat not yet implemented')
    raise UserCriticalException('Support for Red Hat not yet implemented')