Example #1
0
class CliFetchVserviceVnics(CliAccess):
    def __init__(self):
        super().__init__()
        self.inv = InventoryMgr()
        self.if_header = re.compile('^\d+: ([^:]+): (.+)')
        self.regexps = [{
            'name': 'mac_address',
            're': '^.*\slink/ether\s(\S+)\s'
        }, {
            'name': 'IP Address',
            're': '^\s*inet ([0-9.]+)/'
        }, {
            'name': 'netmask',
            're': '^\s*inet [0-9.]+/([0-9]+)'
        }, {
            'name': 'IPv6 Address',
            're': '^\s*inet6 ([^/]+)/.* global '
        }]

    def get(self, host_id):
        host = self.inv.get_by_id(self.get_env(), host_id)
        if not host:
            self.log.error("host not found: " + host_id)
            return []
        if "host_type" not in host:
            self.log.error("host does not have host_type: " + host_id +
                           ", host: " + str(host))
            return []
        if "Network" not in host["host_type"]:
            return []
        lines = self.run_fetch_lines("ip netns list", host_id)
        ret = []
        for l in [
                l for l in lines
                if l.startswith("qdhcp") or l.startswith("qrouter")
        ]:
            service = l.strip()
            service = service if ' ' not in service \
                else service[:service.index(' ')]
            ret.extend(self.handle_service(host_id, service))
        return ret

    def handle_service(self, host, service, enable_cache=True):
        cmd = "ip netns exec " + service + " ip address show"
        lines = self.run_fetch_lines(cmd, host, enable_cache)
        interfaces = []
        current = None
        for line in lines:
            matches = self.if_header.match(line)
            if matches:
                if current:
                    self.set_interface_data(current)
                name = matches.group(1).strip(":")
                # ignore 'lo' interface
                if name == 'lo':
                    current = None
                else:
                    line_remainder = matches.group(2)
                    master_parent_id = "{}-{}".format(host, service)
                    current = {
                        "id": host + "-" + name,
                        "vnic_type": "vservice_vnic",
                        "host": host,
                        "name": name,
                        "lines": []
                    }
                    self.set_folder_parent(current,
                                           object_type="vnic",
                                           master_parent_type="vservice",
                                           master_parent_id=master_parent_id,
                                           parent_text="vNICs")
                    interfaces.append(current)
                    self.handle_line(current, line_remainder)
            else:
                if current:
                    self.handle_line(current, line)
        if current:
            self.set_interface_data(current)
        return interfaces

    def handle_line(self, interface, line):
        self.find_matching_regexps(interface, line, self.regexps)
        interface["lines"].append(line.strip())

    def set_interface_data(self, interface):
        if not interface or 'IP Address' not in interface or 'netmask' not in interface:
            return

        interface["data"] = "\n".join(interface.pop("lines", None))
        interface["cidr"] = self.get_cidr_for_vnic(interface)
        network = self.inv.get_by_field(self.get_env(),
                                        "network",
                                        "cidrs",
                                        interface["cidr"],
                                        get_single=True)
        if not network:
            return
        interface["network"] = network["id"]
        # set network for the vservice, to check network on clique creation
        vservice = self.inv.get_by_id(self.get_env(),
                                      interface["master_parent_id"])
        network_id = network["id"]
        if "network" not in vservice:
            vservice["network"] = list()
        if network_id not in vservice["network"]:
            vservice["network"].append(network_id)
        self.inv.set(vservice)

    # find CIDR string by IP address and netmask
    def get_cidr_for_vnic(self, vnic):
        if "IP Address" not in vnic:
            vnic["IP Address"] = "No IP Address"
            return "No IP Address"
        ipaddr = vnic["IP Address"].split('.')
        vnic['netmask'] = self.convert_netmask(vnic['netmask'])
        netmask = vnic["netmask"].split('.')

        # calculate network start
        net_start = []
        for pos in range(0, 4):
            net_start.append(str(int(ipaddr[pos]) & int(netmask[pos])))

        cidr_string = '.'.join(net_start) + '/'
        cidr_string = cidr_string + self.get_net_size(netmask)
        return cidr_string

    def get_net_size(self, netmask):
        binary_str = ''
        for octet in netmask:
            binary_str += bin(int(octet))[2:].zfill(8)
        return str(len(binary_str.rstrip('0')))

    @staticmethod
    def convert_netmask(cidr):
        netmask_conversion = {
            '32': '255.255.255.255',
            '31': '255.255.255.254',
            '30': '255.255.255.252',
            '29': '255.255.255.248',
            '28': '255.255.255.240',
            '27': '255.255.255.224',
            '26': '255.255.255.192',
            '25': '255.255.255.128',
            '24': '255.255.255.0',
            '23': '255.255.254.0',
            '22': '255.255.252.0',
            '21': '255.255.248.0',
            '20': '255.255.240.0',
            '19': '255.255.224.0',
            '18': '255.255.192.0',
            '17': '255.255.128.0',
            '16': '255.255.0.0',
            '15': '255.254.0.0',
            '14': '255.252.0.0',
            '13': '255.248.0.0',
            '12': '255.240.0.0',
            '11': '255.224.0.0',
            '10': '255.192.0.0',
            '9': '255.128.0.0',
            '8': '255.0.0.0',
            '7': '254.0.0.0',
            '6': '252.0.0.0',
            '5': '248.0.0.0',
            '4': '240.0.0.0',
            '3': '224.0.0.0',
            '2': '192.0.0.0',
            '1': '128.0.0.0',
            '0': '0.0.0.0'
        }
        if cidr not in netmask_conversion:
            raise ValueError('can' 't convert to netmask: {}'.format(cidr))
        return netmask_conversion.get(cidr)
Example #2
0
class ApiFetchNetworks(ApiAccess):
    def __init__(self):
        super(ApiFetchNetworks, self).__init__()
        self.inv = InventoryMgr()

    def get(self, project_id=None):
        # use project admin credentials, to be able to fetch all networks
        token = self.v2_auth_pwd(self.admin_project)
        if not token:
            return []
        ret = []
        for region in self.regions:
            ret.extend(self.get_networks(region, token))
        return ret

    def get_networks(self, region, token):
        endpoint = self.get_region_url_nover(region, "neutron")
        req_url = endpoint + "/v2.0/networks"
        headers = {
            "X-Auth-Project-Id": self.admin_project,
            "X-Auth-Token": token["id"]
        }
        response = self.get_url(req_url, headers)
        if "networks" not in response:
            return []
        networks = response["networks"]
        req_url = endpoint + "/v2.0/subnets"
        response = self.get_url(req_url, headers)
        subnets_hash = {}
        if "subnets" in response:
            # create a hash subnets, to allow easy locating of subnets
            subnets = response["subnets"]
            for s in subnets:
                subnets_hash[s["id"]] = s
        for doc in networks:
            project_id = doc["tenant_id"]
            if not project_id:
                # find project ID of admin project
                project = self.inv.get_by_field(self.get_env(),
                                                "project",
                                                "name",
                                                self.admin_project,
                                                get_single=True)
                if not project:
                    self.log.error("failed to find admin project in DB")
                project_id = project["id"]
            self.set_folder_parent(doc,
                                   object_type='network',
                                   master_parent_id=project_id,
                                   master_parent_type='project')
            # set the 'network' attribute for network objects to the name of
            # network, to allow setting constraint on network when creating
            # network clique
            doc['network'] = doc["id"]
            # get the project name
            project = self.inv.get_by_id(self.get_env(), project_id)
            if project:
                doc["project"] = project["name"]
            subnets_details = {}
            cidrs = []
            subnet_ids = []
            for s in doc["subnets"]:
                try:
                    subnet = subnets_hash[s]
                    cidrs.append(subnet["cidr"])
                    subnet_ids.append(subnet["id"])
                    subnets_details[subnet["name"]] = subnet
                except KeyError:
                    pass

            doc["subnets"] = subnets_details
            doc["cidrs"] = cidrs
            doc["subnet_ids"] = subnet_ids
        return networks