Exemple #1
0
def configure_management():
    interface_list = list()
    lldp_interface_list = list()

    print("Enabling interfaces... ", end=' ')
    ip_link_output = subprocess.check_output(['ip', '-o', 'link'])

    for line in ip_link_output.splitlines():
        interface = line.split()[1].rstrip(':')
        if interface != 'lo':
            interface_list.append(interface)
        subprocess.call(['ip', 'link', 'set', interface, 'up'])
    print('DONE')

    wait_seconds = 120
    delay_seconds = 5
    print("Waiting %d seconds for LLDP neighbor discovery" % wait_seconds,
          end=' ')
    while wait_seconds > 0:
        sys.stdout.write('.')
        sys.stdout.flush()
        time.sleep(delay_seconds)
        wait_seconds -= delay_seconds
    print(' DONE')

    print("Retrieving neighbor details... ", end=' ')
    lldpcli_show_output = subprocess.check_output(
        ['sudo', 'lldpcli', 'show', 'neighbors', 'summary', '-f', 'json'])
    try:
        lldp_interfaces = json.loads(
            lldpcli_show_output)['lldp'][0]['interface']
    except Exception as e:
        lldp_interfaces = {}
    print("DONE")

    print("\nAvailable interfaces:")
    print("%-20s %s" % ("local interface", "remote port"))
    print("%-20s %s" % ("---------------", "-----------"))
    for interface in lldp_interfaces:
        print("%-20s %s" %
              (interface['name'], interface['port'][0]['id'][0]['value']))
        lldp_interface_list.append(interface['name'])
    for interface in interface_list:
        if interface not in lldp_interface_list:
            print("%-20s %s" % (interface, 'unknown'))

    print('')
    while True:
        user_input = input("Enter management interface name: ")
        if user_input in interface_list:
            management_interface = user_input
            break
        else:
            print("Invalid interface name")
            continue

    while True:
        user_input = input("Enter management IP address in CIDR "
                           "notation, ie. ip/prefix_length: ")
        try:
            management_cidr = netaddr.IPNetwork(user_input)
            management_ip = management_cidr.ip
            management_network = netaddr.IPNetwork(
                "%s/%s" %
                (str(management_cidr.network), str(management_cidr.prefixlen)))
            if not is_valid_management_address(management_ip,
                                               management_network):
                continue
            break
        except (netaddr.AddrFormatError, ValueError):
            print("Invalid CIDR - "
                  "please enter a valid management IP address in "
                  "CIDR notation.")

    while True:
        user_input = input("Enter management gateway IP address [" +
                           str(management_network[1]) + "]: ")
        if user_input == "":
            user_input = management_network[1]

        try:
            ip_input = netaddr.IPAddress(user_input)
            if not is_valid_management_address(ip_input, management_network):
                continue
            management_gateway_address = ip_input
            break
        except (netaddr.AddrFormatError, ValueError):
            print("Invalid address - "
                  "please enter a valid management gateway IP address")

    min_addresses = 8
    while True:
        user_input = input("Enter System Controller subnet in "
                           "CIDR notation: ")
        try:
            system_controller_subnet = cutils.validate_network_str(
                user_input, min_addresses)
            break
        except cexeptions.ValidateFail as e:
            print("{}".format(e))

    print("Disabling non-management interfaces... ", end=' ')
    for interface in interface_list:
        if interface != management_interface:
            subprocess.call(['ip', 'link', 'set', interface, 'down'])
    print('DONE')

    print("Configuring management interface... ", end=' ')
    subprocess.call([
        'ip', 'addr', 'add',
        str(management_cidr), 'dev', management_interface
    ])
    print("DONE")

    print("Adding route to System Controller... ", end=' ')
    subprocess.call([
        'ip', 'route', 'add',
        str(system_controller_subnet), 'dev', management_interface, 'via',
        str(management_gateway_address)
    ])
    print("DONE")
    def _validate_subcloud_config(self, context, name, management_subnet_str,
                                  management_start_ip_str,
                                  management_end_ip_str,
                                  management_gateway_ip_str,
                                  systemcontroller_gateway_ip_str):
        """Check whether subcloud config is valid."""

        # Validate the name
        if name.isdigit():
            pecan.abort(400, _("name must contain alphabetic characters"))

        if name in [consts.DEFAULT_REGION_NAME, consts.SYSTEM_CONTROLLER_NAME]:
            pecan.abort(
                400,
                _("name cannot be %(bad_name1)s or %(bad_name2)s") % {
                    'bad_name1': consts.DEFAULT_REGION_NAME,
                    'bad_name2': consts.SYSTEM_CONTROLLER_NAME
                })

        # Parse/validate the management subnet
        subcloud_subnets = []
        subclouds = db_api.subcloud_get_all(context)
        for subcloud in subclouds:
            subcloud_subnets.append(IPNetwork(subcloud.management_subnet))

        MIN_MANAGEMENT_ADDRESSES = 8

        management_subnet = None
        try:
            management_subnet = validate_network_str(
                management_subnet_str,
                minimum_size=MIN_MANAGEMENT_ADDRESSES,
                existing_networks=subcloud_subnets)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-subnet invalid: %s") % e)

        # Parse/validate the start/end addresses
        management_start_ip = None
        try:
            management_start_ip = validate_address_str(management_start_ip_str,
                                                       management_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-start-ip invalid: %s") % e)

        management_end_ip = None
        try:
            management_end_ip = validate_address_str(management_end_ip_str,
                                                     management_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-end-ip invalid: %s") % e)

        if not management_start_ip < management_end_ip:
            pecan.abort(
                400, _("management-start-ip  not less than management-end-ip"))

        if not len(IPRange(management_start_ip, management_end_ip)) >= \
                MIN_MANAGEMENT_ADDRESSES:
            pecan.abort(
                400,
                _("management address range must contain at least %d "
                  "addresses") % MIN_MANAGEMENT_ADDRESSES)

        # Parse/validate the gateway
        try:
            validate_address_str(management_gateway_ip_str, management_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-gateway-ip invalid: %s") % e)

        # Ensure systemcontroller gateway is in the management subnet
        # for the systemcontroller region.
        management_address_pool = self._get_management_address_pool(context)
        systemcontroller_subnet_str = "%s/%d" % (
            management_address_pool.network, management_address_pool.prefix)
        systemcontroller_subnet = IPNetwork(systemcontroller_subnet_str)
        try:
            validate_address_str(systemcontroller_gateway_ip_str,
                                 systemcontroller_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("systemcontroller-gateway-ip invalid: %s") % e)
Exemple #3
0
    def _validate_subcloud_config(self, context, name, management_subnet_str,
                                  management_start_ip_str,
                                  management_end_ip_str,
                                  management_gateway_ip_str,
                                  systemcontroller_gateway_ip_str):
        """Check whether subcloud config is valid."""

        # Validate the name
        if name.isdigit():
            pecan.abort(400, _("name must contain alphabetic characters"))

        if name in [consts.DEFAULT_REGION_NAME, consts.SYSTEM_CONTROLLER_NAME]:
            pecan.abort(
                400,
                _("name cannot be %(bad_name1)s or %(bad_name2)s") % {
                    'bad_name1': consts.DEFAULT_REGION_NAME,
                    'bad_name2': consts.SYSTEM_CONTROLLER_NAME
                })

        # Parse/validate the management subnet
        subcloud_subnets = []
        subclouds = db_api.subcloud_get_all(context)
        for subcloud in subclouds:
            subcloud_subnets.append(IPNetwork(subcloud.management_subnet))

        MIN_MANAGEMENT_SUBNET_SIZE = 8
        # subtract 3 for network, gateway and broadcast addresses.
        MIN_MANAGEMENT_ADDRESSES = MIN_MANAGEMENT_SUBNET_SIZE - 3

        management_subnet = None
        try:
            management_subnet = validate_network_str(
                management_subnet_str,
                minimum_size=MIN_MANAGEMENT_SUBNET_SIZE,
                existing_networks=subcloud_subnets)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-subnet invalid: %s") % e)

        # Parse/validate the start/end addresses
        management_start_ip = None
        try:
            management_start_ip = validate_address_str(management_start_ip_str,
                                                       management_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-start-ip invalid: %s") % e)

        management_end_ip = None
        try:
            management_end_ip = validate_address_str(management_end_ip_str,
                                                     management_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-end-ip invalid: %s") % e)

        if not management_start_ip < management_end_ip:
            pecan.abort(
                400, _("management-start-ip  not less than management-end-ip"))

        if not len(IPRange(management_start_ip, management_end_ip)) >= \
                MIN_MANAGEMENT_ADDRESSES:
            pecan.abort(
                400,
                _("management address range must contain at least %d "
                  "addresses") % MIN_MANAGEMENT_ADDRESSES)

        # Parse/validate the gateway
        try:
            validate_address_str(management_gateway_ip_str, management_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("management-gateway-ip invalid: %s") % e)

        # Ensure subcloud management gateway is not within the actual subcloud
        # management subnet address pool for consistency with the
        # systemcontroller gateway restriction below. Address collision
        # is not a concern as the address is added to sysinv.
        subcloud_mgmt_address_start = IPAddress(management_start_ip_str)
        subcloud_mgmt_address_end = IPAddress(management_end_ip_str)
        subcloud_mgmt_gw_ip = IPAddress(management_gateway_ip_str)
        if ((subcloud_mgmt_gw_ip >= subcloud_mgmt_address_start)
                and (subcloud_mgmt_gw_ip <= subcloud_mgmt_address_end)):
            pecan.abort(
                400,
                _("management-gateway-ip invalid, "
                  "is within management pool: %(start)s - "
                  "%(end)s") % {
                      'start': subcloud_mgmt_address_start,
                      'end': subcloud_mgmt_address_end
                  })

        # Ensure systemcontroller gateway is in the management subnet
        # for the systemcontroller region.
        management_address_pool = self._get_management_address_pool(context)
        systemcontroller_subnet_str = "%s/%d" % (
            management_address_pool.network, management_address_pool.prefix)
        systemcontroller_subnet = IPNetwork(systemcontroller_subnet_str)
        try:
            validate_address_str(systemcontroller_gateway_ip_str,
                                 systemcontroller_subnet)
        except ValidateFail as e:
            LOG.exception(e)
            pecan.abort(400, _("systemcontroller-gateway-ip invalid: %s") % e)
        # Ensure systemcontroller gateway is not within the actual
        # management subnet address pool to prevent address collision.
        mgmt_address_start = IPAddress(management_address_pool.ranges[0][0])
        mgmt_address_end = IPAddress(management_address_pool.ranges[0][1])
        systemcontroller_gw_ip = IPAddress(systemcontroller_gateway_ip_str)
        if ((systemcontroller_gw_ip >= mgmt_address_start)
                and (systemcontroller_gw_ip <= mgmt_address_end)):
            pecan.abort(
                400,
                _("systemcontroller-gateway-ip invalid, "
                  "is within management pool: %(start)s - "
                  "%(end)s") % {
                      'start': mgmt_address_start,
                      'end': mgmt_address_end
                  })
    def _create_subcloud_config_file(self, context, subcloud, payload):
        """Creates the subcloud config file for a subcloud."""
        DEFAULT_STR = '<EDIT>'

        pxe_cidr = payload.get('pxe-subnet', DEFAULT_STR)
        management_vlan = payload.get('management-vlan', DEFAULT_STR)
        management_interface_mtu = payload.get('management-interface-mtu',
                                               DEFAULT_STR)
        management_interface_ports = payload.get('management-interface-port',
                                                 DEFAULT_STR)
        oam_cidr = payload.get('oam-subnet', DEFAULT_STR)
        oam_gateway = payload.get('oam-gateway-ip', DEFAULT_STR)
        oam_ip_floating_address = payload.get('oam-floating-ip', DEFAULT_STR)
        oam_ip_unit_0_address = payload.get('oam-unit-0-ip', DEFAULT_STR)
        oam_ip_unit_1_address = payload.get('oam-unit-1-ip', DEFAULT_STR)
        oam_interface_mtu = payload.get('oam-interface-mtu', DEFAULT_STR)
        oam_interface_ports = payload.get('oam-interface-port', DEFAULT_STR)
        system_mode = payload.get('system-mode', DEFAULT_STR)

        management_address_pool = self._get_management_address_pool(context)
        systemcontroller_subnet = "%s/%d" % (management_address_pool.network,
                                             management_address_pool.prefix)
        sc_mgmt_floating_ip = management_address_pool.floating_address

        subcloud_config = ""
        if system_mode in [
                SYSTEM_MODE_SIMPLEX, SYSTEM_MODE_DUPLEX,
                SYSTEM_MODE_DUPLEX_DIRECT
        ]:
            subcloud_config += ("[SYSTEM]\n"
                                "SYSTEM_MODE={}\n".format(system_mode))

        if system_mode == SYSTEM_MODE_SIMPLEX:
            subcloud_oamip_config = (
                "IP_ADDRESS = {oam_ip_floating_address}\n").format(
                    oam_ip_floating_address=oam_ip_floating_address, )
        else:
            subcloud_oamip_config = (
                "IP_FLOATING_ADDRESS = {oam_ip_floating_address}\n"
                "IP_UNIT_0_ADDRESS = {oam_ip_unit_0_address}\n"
                "IP_UNIT_1_ADDRESS = {oam_ip_unit_1_address}\n").format(
                    oam_ip_floating_address=oam_ip_floating_address,
                    oam_ip_unit_0_address=oam_ip_unit_0_address,
                    oam_ip_unit_1_address=oam_ip_unit_1_address,
                )

        MIN_MANAGEMENT_ADDRESSES = 8
        tmp_management_subnet = validate_network_str(
            subcloud.management_subnet, minimum_size=MIN_MANAGEMENT_ADDRESSES)

        is_ipv6_mgmt = (tmp_management_subnet.version == 6)

        # If ipv6 then we need pxe subnet and management_vlan.
        # If user specified pxe boot subnet, then management vlan is required
        # and vice versa
        if is_ipv6_mgmt or (pxe_cidr != DEFAULT_STR) or \
                (management_vlan != DEFAULT_STR):
            subcloud_config += ("[REGION2_PXEBOOT_NETWORK]\n"
                                "PXEBOOT_CIDR = {pxe_cidr}\n"
                                "[MGMT_NETWORK]\n"
                                "VLAN = {management_vlan}\n").format(
                                    pxe_cidr=pxe_cidr,
                                    management_vlan=management_vlan,
                                )
        else:
            subcloud_config += "[MGMT_NETWORK]\n"

        subcloud_config += (
            "CIDR = {management_cidr}\n"
            "GATEWAY = {management_gateway}\n"
            "IP_START_ADDRESS = {management_ip_start_address}\n"
            "IP_END_ADDRESS = {management_ip_end_address}\n"
            "DYNAMIC_ALLOCATION = Y\n"
            "LOGICAL_INTERFACE = LOGICAL_INTERFACE_1\n"
            "[LOGICAL_INTERFACE_1]\n"
            "LAG_INTERFACE = N\n"
            "INTERFACE_MTU = {management_interface_mtu}\n"
            "INTERFACE_PORTS = {management_interface_ports}\n"
            "[OAM_NETWORK]\n"
            "CIDR = {oam_cidr}\n"
            "GATEWAY = {oam_gateway}\n" + subcloud_oamip_config +
            "LOGICAL_INTERFACE = LOGICAL_INTERFACE_2\n"
            "[LOGICAL_INTERFACE_2]\n"
            "LAG_INTERFACE = N\n"
            "INTERFACE_MTU = {oam_interface_mtu}\n"
            "INTERFACE_PORTS = {oam_interface_ports}\n"
            "[SHARED_SERVICES]\n"
            "SYSTEM_CONTROLLER_SUBNET = {systemcontroller_subnet}\n"
            "SYSTEM_CONTROLLER_FLOATING_ADDRESS = {sc_mgmt_floating_ip}\n"
            "REGION_NAME = SystemController\n"
            "ADMIN_PROJECT_NAME = admin\n"
            "ADMIN_USER_NAME = admin\n"
            "ADMIN_PASSWORD = {admin_password}\n"
            "KEYSTONE_ADMINURL = {keystone_adminurl}\n"
            "KEYSTONE_SERVICE_NAME = keystone\n"
            "KEYSTONE_SERVICE_TYPE = identity\n"
            "GLANCE_SERVICE_NAME = glance\n"
            "GLANCE_SERVICE_TYPE = image\n"
            "GLANCE_CACHED = True\n"
            "[REGION_2_SERVICES]\n"
            "REGION_NAME = {region_2_name}\n"
            "[VERSION]\n"
            "RELEASE = {release}\n").format(
                management_cidr=subcloud.management_subnet,
                management_gateway=subcloud.management_gateway_ip,
                management_ip_start_address=subcloud.management_start_ip,
                management_ip_end_address=subcloud.management_end_ip,
                management_interface_mtu=management_interface_mtu,
                management_interface_ports=management_interface_ports,
                oam_cidr=oam_cidr,
                oam_gateway=oam_gateway,
                oam_interface_mtu=oam_interface_mtu,
                oam_interface_ports=oam_interface_ports,
                systemcontroller_subnet=systemcontroller_subnet,
                sc_mgmt_floating_ip=sc_mgmt_floating_ip,
                admin_password=cfg.CONF.cache.admin_password,
                keystone_adminurl=cfg.CONF.cache.auth_uri,
                region_2_name=subcloud.name,
                release=subcloud.software_version,
            )
        return subcloud_config
Exemple #5
0
    def parse_config(self,
                     system_config,
                     config_type,
                     network_type,
                     min_addresses=0,
                     multicast_addresses=0,
                     optional=False,
                     naming_type=DEFAULT_NAMES,
                     logical_interface_required=True):
        network_prefix = NETWORK_PREFIX_NAMES[naming_type][network_type]
        network_name = network_prefix + '_NETWORK'

        if naming_type == HP_NAMES:
            attr_prefix = network_prefix + '_'
        else:
            attr_prefix = ''

        # Ensure network config is present
        if not system_config.has_section(network_name):
            if not optional:
                raise ConfigFail("Missing config for network %s." %
                                 network_name)
            else:
                # Optional interface - just return
                return

        # Parse/validate the VLAN
        if system_config.has_option(network_name, attr_prefix + 'VLAN'):
            self.vlan = system_config.getint(network_name,
                                             attr_prefix + 'VLAN')
        if self.vlan:
            if not is_valid_vlan(self.vlan):
                raise ConfigFail(
                    "Invalid %s value of %d for %s. Valid values: 1-4094" %
                    (attr_prefix + 'VLAN', self.vlan, network_name))

        # Parse/validate the cidr
        cidr_str = system_config.get(network_name, attr_prefix + 'CIDR')
        try:
            self.cidr = validate_network_str(cidr_str, min_addresses)
        except ValidateFail as e:
            raise ConfigFail("Invalid %s value of %s for %s.\nReason: %s" %
                             (attr_prefix + 'CIDR', cidr_str, network_name, e))

        # Parse/validate the multicast subnet
        if 0 < multicast_addresses and \
                system_config.has_option(network_name,
                                         attr_prefix + 'MULTICAST_CIDR'):
            multicast_cidr_str = system_config.get(
                network_name, attr_prefix + 'MULTICAST_CIDR')
            try:
                self.multicast_cidr = validate_network_str(multicast_cidr_str,
                                                           multicast_addresses,
                                                           multicast=True)
            except ValidateFail as e:
                raise ConfigFail("Invalid %s value of %s for %s.\nReason: %s" %
                                 (attr_prefix + 'MULTICAST_CIDR',
                                  multicast_cidr_str, network_name, e))

            if self.cidr.version != self.multicast_cidr.version:
                raise ConfigFail(
                    "Invalid %s value of %s for %s.  Multicast "
                    "subnet and network IP families must be the same." %
                    (attr_prefix + 'MULTICAST_CIDR', multicast_cidr_str,
                     network_name))

        # Parse/validate the hardwired controller addresses
        floating_address_str = None
        address_0_str = None
        address_1_str = None

        if min_addresses == 1:
            if (system_config.has_option(network_name,
                                         attr_prefix + 'IP_FLOATING_ADDRESS')
                    or system_config.has_option(
                        network_name, attr_prefix + 'IP_UNIT_0_ADDRESS')
                    or system_config.has_option(
                        network_name, attr_prefix + 'IP_UNIT_1_ADDRESS')
                    or system_config.has_option(
                        network_name, attr_prefix + 'IP_START_ADDRESS')
                    or system_config.has_option(
                        network_name, attr_prefix + 'IP_END_ADDRESS')):
                raise ConfigFail(
                    "Only one IP address is required for OAM "
                    "network, use 'IP_ADDRESS' to specify the OAM IP "
                    "address")
            floating_address_str = system_config.get(
                network_name, attr_prefix + 'IP_ADDRESS')
            try:
                self.floating_address = validate_address_str(
                    floating_address_str, self.cidr)
            except ValidateFail as e:
                raise ConfigFail("Invalid %s value of %s for %s.\nReason: %s" %
                                 (attr_prefix + 'IP_ADDRESS',
                                  floating_address_str, network_name, e))
            self.address_0 = self.floating_address
            self.address_1 = self.floating_address
        else:
            if system_config.has_option(network_name,
                                        attr_prefix + 'IP_FLOATING_ADDRESS'):
                floating_address_str = system_config.get(
                    network_name, attr_prefix + 'IP_FLOATING_ADDRESS')
                try:
                    self.floating_address = validate_address_str(
                        floating_address_str, self.cidr)
                except ValidateFail as e:
                    raise ConfigFail(
                        "Invalid %s value of %s for %s.\nReason: %s" %
                        (attr_prefix + 'IP_FLOATING_ADDRESS',
                         floating_address_str, network_name, e))

            if system_config.has_option(network_name,
                                        attr_prefix + 'IP_UNIT_0_ADDRESS'):
                address_0_str = system_config.get(
                    network_name, attr_prefix + 'IP_UNIT_0_ADDRESS')
                try:
                    self.address_0 = validate_address_str(
                        address_0_str, self.cidr)
                except ValidateFail as e:
                    raise ConfigFail(
                        "Invalid %s value of %s for %s.\nReason: %s" %
                        (attr_prefix + 'IP_UNIT_0_ADDRESS', address_0_str,
                         network_name, e))

            if system_config.has_option(network_name,
                                        attr_prefix + 'IP_UNIT_1_ADDRESS'):
                address_1_str = system_config.get(
                    network_name, attr_prefix + 'IP_UNIT_1_ADDRESS')
                try:
                    self.address_1 = validate_address_str(
                        address_1_str, self.cidr)
                except ValidateFail as e:
                    raise ConfigFail(
                        "Invalid %s value of %s for %s.\nReason: %s" %
                        (attr_prefix + 'IP_UNIT_1_ADDRESS', address_1_str,
                         network_name, e))

            # Parse/validate the start/end addresses
            start_address_str = None
            end_address_str = None
            if system_config.has_option(network_name,
                                        attr_prefix + 'IP_START_ADDRESS'):
                start_address_str = system_config.get(
                    network_name, attr_prefix + 'IP_START_ADDRESS')
                try:
                    self.start_address = validate_address_str(
                        start_address_str, self.cidr)
                except ValidateFail as e:
                    raise ConfigFail(
                        "Invalid %s value of %s for %s.\nReason: %s" %
                        (attr_prefix + 'IP_START_ADDRESS', start_address_str,
                         network_name, e))

            if system_config.has_option(network_name,
                                        attr_prefix + 'IP_END_ADDRESS'):
                end_address_str = system_config.get(
                    network_name, attr_prefix + 'IP_END_ADDRESS')
                try:
                    self.end_address = validate_address_str(
                        end_address_str, self.cidr)
                except ValidateFail as e:
                    raise ConfigFail(
                        "Invalid %s value of %s for %s.\nReason: %s " %
                        (attr_prefix + 'IP_END_ADDRESS', end_address_str,
                         network_name, e))

            if start_address_str or end_address_str:
                if not end_address_str:
                    raise ConfigFail(
                        "Missing attribute %s for %s_NETWORK" %
                        (attr_prefix + 'IP_END_ADDRESS', network_name))
                if not start_address_str:
                    raise ConfigFail(
                        "Missing attribute %s for %s_NETWORK" %
                        (attr_prefix + 'IP_START_ADDRESS', network_name))
                if not self.start_address < self.end_address:
                    raise ConfigFail(
                        "Start address %s not less than end address %s for %s."
                        % (str(self.start_address), str(
                            self.end_address), network_name))
                if not IPRange(start_address_str, end_address_str).size >= \
                        min_addresses:
                    raise ConfigFail("Address range for %s must contain at "
                                     "least %d addresses." %
                                     (network_name, min_addresses))
                self.start_end_in_config = True

            if floating_address_str or address_0_str or address_1_str:
                if not floating_address_str:
                    raise ConfigFail(
                        "Missing attribute %s for %s_NETWORK" %
                        (attr_prefix + 'IP_FLOATING_ADDRESS', network_name))
                if not address_0_str:
                    raise ConfigFail(
                        "Missing attribute %s for %s_NETWORK" %
                        (attr_prefix + 'IP_UNIT_0_ADDRESS', network_name))
                if not address_1_str:
                    raise ConfigFail(
                        "Missing attribute %s for %s_NETWORK" %
                        (attr_prefix + 'IP_UNIT_1_ADDRESS', network_name))

            if start_address_str and floating_address_str:
                raise ConfigFail(
                    "Overspecified network: Can only set %s "
                    "and %s OR %s, %s, and %s for "
                    "%s_NETWORK" %
                    (attr_prefix + 'IP_START_ADDRESS', attr_prefix +
                     'IP_END_ADDRESS', attr_prefix + 'IP_FLOATING_ADDRESS',
                     attr_prefix + 'IP_UNIT_0_ADDRESS',
                     attr_prefix + 'IP_UNIT_1_ADDRESS', network_name))

        if config_type == DEFAULT_CONFIG:
            if not self.start_address:
                self.start_address = self.cidr[2]
            if not self.end_address:
                self.end_address = self.cidr[-2]

        # Parse/validate the dynamic IP address allocation
        if system_config.has_option(network_name, 'DYNAMIC_ALLOCATION'):
            dynamic_allocation = system_config.get(network_name,
                                                   'DYNAMIC_ALLOCATION')
            if dynamic_allocation.lower() == 'y':
                self.dynamic_allocation = True
            elif dynamic_allocation.lower() == 'n':
                self.dynamic_allocation = False
            else:
                raise ConfigFail(
                    "Invalid DYNAMIC_ALLOCATION value of %s for %s. "
                    "Valid values: Y or N" %
                    (dynamic_allocation, network_name))

        # Parse/validate the gateway (optional)
        if system_config.has_option(network_name, attr_prefix + 'GATEWAY'):
            gateway_address_str = system_config.get(network_name,
                                                    attr_prefix + 'GATEWAY')
            try:
                self.gateway_address = validate_address_str(
                    gateway_address_str, self.cidr)
            except ValidateFail as e:
                raise ConfigFail("Invalid %s value of %s for %s.\nReason: %s" %
                                 (attr_prefix + 'GATEWAY', gateway_address_str,
                                  network_name, e))

        # Parse/validate the logical interface
        if logical_interface_required or system_config.has_option(
                network_name, attr_prefix + 'LOGICAL_INTERFACE'):
            logical_interface_name = system_config.get(
                network_name, attr_prefix + 'LOGICAL_INTERFACE')
            self.logical_interface = LogicalInterface()
            self.logical_interface.parse_config(system_config,
                                                logical_interface_name)