Ejemplo n.º 1
0
    def test_maas_subnet(self):
        client_config = config.DrydockConfig.node_driver['maasdriver']

        maas_client = client.MaasRequestFactory(client_config['api_url'], client_config['api_key'])

        subnet_list = maas_subnet.Subnets(maas_client)
        subnet_list.refresh()

        for s in subnet_list:
            print(s.to_dict())
        assert False
Ejemplo n.º 2
0
    def link_subnet(self,
                    subnet_id=None,
                    subnet_cidr=None,
                    ip_address=None,
                    primary=False):
        """Link this interface to a MaaS subnet.

        One of subnet_id or subnet_cidr should be specified. If both are, subnet_id rules.

        :param subnet_id: The MaaS resource ID of a network subnet to connect to
        :param subnet_cidr: The CIDR of a MaaS subnet to connect to
        :param ip_address: The IP address to assign this interface. Should be a string with
                           a static IP or None. If None, DHCP will be used.
        :param primary: Boolean of whether this interface is the primary interface of the node. This
                        sets the node default gateway to the gateway of the subnet
        """
        subnet = None

        subnets = maas_subnet.Subnets(self.api_client)
        subnets.refresh()

        if subnet_id is not None:
            subnet = subnets.select(subnet_id)
        elif subnet_cidr is not None:
            subnet = subnets.singleton({'cidr': subnet_cidr})
        else:
            self.logger.warning("Must specify subnet_id or subnet_cidr")
            raise ValueError("Must specify subnet_id or subnet_cidr")

        if subnet is None:
            self.logger.warning(
                "Subnet not found in MaaS for subnet_id %s, subnet_cidr %s" %
                (subnet_id, subnet_cidr))
            raise errors.DriverError(
                "Subnet not found in MaaS for subnet_id %s, subnet_cidr %s" %
                (subnet_id, subnet_cidr))

        url = self.interpolate_url()

        if self.is_linked(subnet.resource_id):
            self.logger.info(
                "Interface %s already linked to subnet %s, unlinking." %
                (self.resource_id, subnet.resource_id))
            self.unlink_subnet(subnet.resource_id)

        # TODO(sh8121att) Probably need to enumerate link mode
        options = {
            'subnet': subnet.resource_id,
            'default_gateway': primary,
        }

        if ip_address == 'dhcp':
            options['mode'] = 'dhcp'
        elif ip_address is not None:
            options['ip_address'] = ip_address
            options['mode'] = 'static'
        else:
            options['mode'] = 'link_up'

        self.logger.debug(
            "Linking interface %s to subnet: subnet=%s, mode=%s, address=%s, primary=%s"
            % (self.resource_id, subnet.resource_id, options['mode'],
               ip_address, primary))

        resp = self.api_client.post(url, op='link_subnet', files=options)

        if not resp.ok:
            self.logger.error(
                "Error linking interface %s to subnet %s - MaaS response %s: %s"
                % (self.resouce_id, subnet.resource_id, resp.status_code,
                   resp.text))
            raise errors.DriverError(
                "Error linking interface %s to subnet %s - MaaS response %s" %
                (self.resouce_id, subnet.resource_id, resp.status_code))

        self.refresh()

        return
Ejemplo n.º 3
0
    def execute_task(self):
        task_action = self.task.action

        self.orchestrator.task_field_update(
            self.task.get_id(),
            status=hd_fields.TaskStatus.Running,
            result=hd_fields.ActionResult.Incomplete)

        self.maas_client = MaasRequestFactory(self.driver_config['api_url'],
                                              self.driver_config['api_key'])

        site_design = self.orchestrator.get_effective_site(self.task.design_id)

        if task_action == hd_fields.OrchestratorAction.CreateNetworkTemplate:
            # Try to true up MaaS definitions of fabrics/vlans/subnets
            # with the networks defined in Drydock
            design_networks = site_design.networks

            subnets = maas_subnet.Subnets(self.maas_client)
            subnets.refresh()

            result_detail = {'detail': []}

            for n in design_networks:
                try:
                    subnet = subnets.singleton({'cidr': n.cidr})

                    if subnet is not None:
                        subnet.name = n.name
                        subnet.dns_servers = n.dns_servers

                        vlan_list = maas_vlan.Vlans(self.maas_client,
                                                    fabric_id=subnet.fabric)
                        vlan_list.refresh()

                        vlan = vlan_list.select(subnet.vlan)

                        if vlan is not None:
                            if ((n.vlan_id is None and vlan.vid != 0)
                                    or (n.vlan_id is not None
                                        and vlan.vid != n.vlan_id)):

                                # if the VLAN name matches, assume this is the correct resource
                                # and it needs to be updated
                                if vlan.name == n.name:
                                    vlan.set_vid(n.vlan_id)
                                    vlan.mtu = n.mtu
                                    vlan.update()
                                    result_detail['detail'].append(
                                        "VLAN %s found for network %s, updated attributes"
                                        % (vlan.resource_id, n.name))
                                else:
                                    # Found a VLAN with the correct VLAN tag, update subnet to use it
                                    target_vlan = vlan_list.singleton({
                                        'vid':
                                        n.vlan_id
                                        if n.vlan_id is not None else 0
                                    })
                                    if target_vlan is not None:
                                        subnet.vlan = target_vlan.resource_id
                                    else:
                                        # This is a flag that after creating a fabric and
                                        # VLAN below, update the subnet
                                        subnet.vlan = None
                        else:
                            subnet.vlan = None

                        # Check if the routes have a default route
                        subnet.gateway_ip = n.get_default_gateway()

                        result_detail['detail'].append(
                            "Subnet %s found for network %s, updated attributes"
                            % (subnet.resource_id, n.name))

                    # Need to find or create a Fabric/Vlan for this subnet
                    if (subnet is None
                            or (subnet is not None and subnet.vlan is None)):
                        fabric_list = maas_fabric.Fabrics(self.maas_client)
                        fabric_list.refresh()
                        fabric = fabric_list.singleton({'name': n.name})

                        vlan = None

                        if fabric is not None:
                            vlan_list = maas_vlan.Vlans(
                                self.maas_client, fabric_id=fabric.resource_id)
                            vlan_list.refresh()

                            vlan = vlan_list.singleton({
                                'vid':
                                n.vlan_id if n.vlan_id is not None else 0
                            })

                            if vlan is not None:
                                vlan = matching_vlans[0]

                                vlan.name = n.name
                                if getattr(n, 'mtu', None) is not None:
                                    vlan.mtu = n.mtu

                                if subnet is not None:
                                    subnet.vlan = vlan.resource_id
                                    subnet.update()

                                vlan.update()
                                result_detail['detail'].append(
                                    "VLAN %s found for network %s, updated attributes"
                                    % (vlan.resource_id, n.name))
                            else:
                                # Create a new VLAN in this fabric and assign subnet to it
                                vlan = maas_vlan.Vlan(
                                    self.maas_client,
                                    name=n.name,
                                    vid=vlan_id,
                                    mtu=getattr(n, 'mtu', None),
                                    fabric_id=fabric.resource_id)
                                vlan = vlan_list.add(vlan)

                                result_detail['detail'].append(
                                    "VLAN %s created for network %s" %
                                    (vlan.resource_id, n.name))
                                if subnet is not None:
                                    subnet.vlan = vlan.resource_id
                                    subnet.update()

                        else:
                            # Create new fabric and VLAN
                            fabric = maas_fabric.Fabric(self.maas_client,
                                                        name=n.name)
                            fabric = fabric_list.add(fabric)
                            fabric_list.refresh()

                            result_detail['detail'].append(
                                "Fabric %s created for network %s" %
                                (fabric.resource_id, n.name))

                            vlan_list = maas_vlan.Vlans(
                                self.maas_client,
                                fabric_id=new_fabric.resource_id)
                            vlan_list.refresh()

                            # A new fabric comes with a single default VLAN. Retrieve it and update attributes
                            vlan = vlan_list.single()

                            vlan.name = n.name
                            vlan.vid = n.vlan_id if n.vlan_id is not None else 0
                            if getattr(n, 'mtu', None) is not None:
                                vlan.mtu = n.mtu

                            vlan.update()
                            result_detail['detail'].append(
                                "VLAN %s updated for network %s" %
                                (vlan.resource_id, n.name))
                        if subnet is not None:
                            # If subnet was found above, but needed attached to a new fabric/vlan then
                            # attach it
                            subnet.vlan = vlan.resource_id
                            subnet.update()

                    if subnet is None:
                        # If subnet did not exist, create it here and attach it to the fabric/VLAN
                        subnet = maas_subnet.Subnet(
                            self.maas_client,
                            name=n.name,
                            cidr=n.cidr,
                            fabric=fabric.resource_id,
                            vlan=vlan.resource_id,
                            gateway_ip=n.get_default_gateway())

                        subnet_list = maas_subnet.Subnets(self.maas_client)
                        subnet = subnet_list.add(subnet)
                except ValueError as vex:
                    raise errors.DriverError("Inconsistent data from MaaS")

            subnet_list = maas_subnet.Subnets(self.maas_client)
            subnet_list.refresh()

            action_result = hd_fields.ActionResult.Incomplete

            success_rate = 0

            for n in design_networks:
                exists = subnet_list.query({'cidr': n.cidr})
                if len(exists) > 0:
                    subnet = exists[0]
                    if subnet.name == n.name:
                        success_rate = success_rate + 1
                    else:
                        success_rate = success_rate + 1
                else:
                    success_rate = success_rate + 1

            if success_rate == len(design_networks):
                action_result = hd_fields.ActionResult.Success
            elif success_rate == -(len(design_networks)):
                action_result = hd_fields.ActionResult.Failure
            else:
                action_result = hd_fields.ActionResult.PartialSuccess

            self.orchestrator.task_field_update(
                self.task.get_id(),
                status=hd_fields.TaskStatus.Complete,
                result=action_result,
                result_detail=result_detail)
        elif task_action == hd_fields.OrchestratorAction.IdentifyNode:
            try:
                machine_list = maas_machine.Machines(self.maas_client)
                machine_list.refresh()
            except:
                self.orchestrator.task_field_update(
                    self.task.get_id(),
                    status=hd_fields.TaskStatus.Complete,
                    result=hd_fields.ActionResult.Failure,
                    result_detail={
                        'detail': 'Error accessing MaaS Machines API',
                        'retry': True
                    })
                return

            nodes = self.task.node_list

            result_detail = {'detail': []}

            worked = failed = False

            for n in nodes:
                try:
                    node = site_design.get_baremetal_node(n)
                    machine = machine_list.identify_baremetal_node(node)
                    if machine is not None:
                        worked = True
                        result_detail['detail'].append(
                            "Node %s identified in MaaS" % n)
                    else:
                        failed = True
                        result_detail['detail'].append(
                            "Node %s not found in MaaS" % n)
                except Exception as ex:
                    failed = True
                    result_detail['detail'].append(
                        "Error identifying node %s: %s" % (n, str(ex)))

            result = None
            if worked and failed:
                result = hd_fields.ActionResult.PartialSuccess
            elif worked:
                result = hd_fields.ActionResult.Success
            elif failed:
                result = hd_fields.ActionResult.Failure

            self.orchestrator.task_field_update(
                self.task.get_id(),
                status=hd_fields.TaskStatus.Complete,
                result=result,
                result_detail=result_detail)