Esempio n. 1
0
    def create_vlan(self, vlan_tag, parent_name, mtu=None, tags=[]):
        """Create a new VLAN interface on this node.

        :param vlan_tag: The VLAN ID (not MaaS resource id of a VLAN) to create interface for
        :param parent_name: The name of a MaaS interface to build the VLAN interface on top of
        :param mtu: Optional configuration of the interface MTU
        :param tags: Optional list of string tags to apply to the VLAN interface
        """
        self.refresh()

        parent_iface = self.singleton({'name': parent_name})

        if parent_iface is None:
            self.logger.error("Cannot locate parent interface %s" %
                              (parent_name))
            raise errors.DriverError("Cannot locate parent interface %s" %
                                     (parent_name))

        if parent_iface.vlan is None:
            self.logger.error(
                "Cannot create VLAN interface on disconnected parent %s" %
                (parent_iface.resource_id))
            raise errors.DriverError(
                "Cannot create VLAN interface on disconnected parent %s" %
                (parent_iface.resource_id))

        vlans = maas_vlan.Vlans(self.api_client,
                                fabric_id=parent_iface.fabric_id)
        vlans.refresh()

        vlan = vlans.singleton({'vid': vlan_tag})

        if vlan is None:
            msg = ("Cannot locate VLAN %s on fabric %s to attach interface" %
                   (vlan_tag, parent_iface.fabric_id))
            self.logger.warning(msg)
            raise errors.DriverError(msg)

        exists = self.singleton({'vlan': vlan.resource_id})

        if exists is not None:
            self.logger.info(
                "Interface for VLAN %s already exists on node %s, skipping" %
                (vlan_tag, self.system_id))
            return exists

        url = self.interpolate_url()

        options = {
            'tags': ','.join(tags),
            'vlan': vlan.resource_id,
            'parent': parent_iface.resource_id,
        }

        if mtu is not None:
            options['mtu'] = mtu

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

        if resp.status_code == 200:
            resp_json = resp.json()
            vlan_iface = Interface.from_dict(self.api_client, resp_json)
            self.logger.debug(
                "Created VLAN interface %s for parent %s attached to VLAN %s" %
                (vlan_iface.resource_id, parent_iface.resource_id,
                 vlan.resource_id))
            return vlan_iface
        else:
            self.logger.error(
                "Error creating VLAN interface to VLAN %s on system %s - MaaS response %s: %s"
                % (vlan.resource_id, self.system_id, resp.status_code,
                   resp.text))
            raise errors.DriverError(
                "Error creating VLAN interface to VLAN %s on system %s - MaaS response %s"
                % (vlan.resource_id, self.system_id, resp.status_code))

        self.refresh()

        return
Esempio n. 2
0
 def refresh_vlans(self):
     self.vlans = model_vlan.Vlans(
         self.api_client, fabric_id=self.resource_id)
     self.vlans.refresh()
Esempio 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)