Example #1
0
def probe_seamicro15k_and_enlist(
    user,
    ip,
    username,
    password,
    power_control=None,
    accept_all=False,
    domain=None,
):
    power_control = power_control or "ipmi"

    maaslog.info("Probing for seamicro15k servers as %s@%s", username, ip)

    servers = find_seamicro15k_servers(ip, username, password, power_control)

    for system_id, macs in servers:
        params = {
            "power_address": ip,
            "power_user": username,
            "power_pass": password,
            "power_control": power_control,
            "system_id": system_id,
        }
        maaslog.info("Creating seamicro15k node with MACs: %s", macs)
        system_id = create_node(macs, "amd64", "sm15k", params,
                                domain=domain).wait(30)

        if accept_all:
            commission_node(system_id, user).wait(30)
Example #2
0
def probe_and_enlist_recs(
    user: str,
    ip: str,
    port: Optional[int],
    username: Optional[str],
    password: Optional[str],
    accept_all: bool = False,
    domain: str = None,
):
    maaslog.info("Probing for RECS servers as %s@%s", username, ip)

    port = 80 if port is None or port == 0 else port
    api = RECSAPI(ip, port, username, password)

    try:
        # if get_nodes works, we have access to the system
        nodes = api.get_nodes()
    except urllib.error.HTTPError as e:
        raise RECSError(
            "Failed to probe nodes for RECS_Master with ip=%s "
            "port=%s, username=%s, password=%s. HTTP error code: %s"
            % (ip, port, username, password, e.code)
        )
    except urllib.error.URLError as e:
        raise RECSError(
            "Failed to probe nodes for RECS_Master with ip=%s "
            "port=%s, username=%s, password=%s. "
            "Server could not be reached: %s"
            % (ip, port, username, password, e.reason)
        )

    for node_id, data in nodes.items():
        params = {
            "power_address": ip,
            "power_port": port,
            "power_user": username,
            "power_pass": password,
            "node_id": node_id,
        }
        arch = "amd64"
        if data["arch"] == "arm":
            arch = "armhf"

        maaslog.info(
            "Creating RECS node %s with MACs: %s", node_id, data["macs"]
        )

        # Set default (persistent) boot to HDD
        api.set_boot_source(node_id, "HDD", True)
        # Set next boot to PXE
        api.set_boot_source(node_id, "PXE", False)

        system_id = create_node(
            data["macs"], arch, "recs_box", params, domain
        ).wait(30)

        if accept_all:
            commission_node(system_id, user).wait(30)
Example #3
0
def _probe_and_enlist_vmware_servers(
    api,
    accept_all,
    host,
    password,
    port,
    prefix_filter,
    protocol,
    servers,
    user,
    username,
    domain,
):
    maaslog.info("Found %d VMware servers", len(servers))
    for system_name in servers:
        if not system_name.startswith(prefix_filter):
            maaslog.info(
                "Skipping node named '%s'; does not match prefix filter '%s'",
                system_name,
                prefix_filter,
            )
            continue
        properties = servers[system_name]
        params = {
            "power_vm_name": system_name,
            "power_uuid": properties["uuid"],
            "power_address": host,
            "power_port": port,
            "power_protocol": protocol,
            "power_user": username,
            "power_pass": password,
        }

        # Note: the system name is URL encoded, so before we go to log
        # and/or create the node, we need to unquote it.
        # Otherwise we might pass in names like "Ubuntu%20(64-bit)"
        system_name = unquote(system_name)
        maaslog.info(
            "Creating VMware node with MACs: %s (%s)",
            properties["macs"],
            system_name,
        )

        system_id = create_node(
            properties["macs"],
            properties["architecture"],
            "vmware",
            params,
            domain,
            system_name,
        ).wait(30)

        if system_id is not None:
            api.set_pxe_boot(properties)

        if accept_all and system_id is not None:
            commission_node(system_id, user).wait(30)
Example #4
0
def probe_virsh_and_enlist(user: str,
                           poweraddr: str,
                           password: str = None,
                           prefix_filter: str = None,
                           accept_all: bool = False,
                           domain: str = None):
    """Extracts all of the VMs from virsh and enlists them
    into MAAS.

    :param user: user for the nodes.
    :param poweraddr: virsh connection string.
    :param password: password connection string.
    :param prefix_filter: only enlist nodes that have the prefix.
    :param accept_all: if True, commission enlisted nodes.
    :param domain: The domain for the node to join.
    """
    conn = VirshSSH(dom_prefix=prefix_filter)
    logged_in = conn.login(poweraddr, password)
    if not logged_in:
        raise VirshError('Failed to login to virsh console.')

    conn_list = conn.list_machines()
    for machine in conn_list:
        arch = conn.get_machine_arch(machine)
        state = conn.get_machine_state(machine)
        macs = conn.list_machine_mac_addresses(machine)

        params = {
            'power_address': poweraddr,
            'power_id': machine,
        }
        if password is not None:
            params['power_pass'] = password
        system_id = create_node(macs,
                                arch,
                                'virsh',
                                params,
                                domain,
                                hostname=machine).wait(30)

        # If the system_id is None an error occured when creating the machine.
        # Most likely the error is the node already exists.
        if system_id is None:
            continue

        # Force the machine off, as MAAS will control the machine
        # and it needs to be in a known state of off.
        if state == VirshVMState.ON:
            conn.poweroff(machine)

        conn.configure_pxe_boot(machine)

        if accept_all:
            commission_node(system_id, user).wait(30)

    conn.logout()
Example #5
0
def probe_and_enlist_ucsm(
    user: str,
    url: str,
    username: Optional[str],
    password: Optional[str],
    accept_all: bool = False,
    domain: str = None,
):
    """Probe a UCS Manager and enlist all its servers.

    Here's what happens here: 1. Get a list of servers from the UCS
    Manager, along with their MAC addresses.

    2. Configure each server to boot from LAN first.

    3. Add each server to MAAS as a new node, with a power control
    method of 'ucsm'. The URL and credentials supplied are persisted
    with each node so MAAS knows how to access UCSM to manage the node
    in the future.

    This code expects each server in the system to have already been
    associated with a service profile. The servers must have networking
    configured, and their boot profiles must include a boot from LAN
    option. During enlistment, the boot profile for each service profile
    used by a server will be modified to move LAN boot to the highest
    priority boot option.

    Also, if any node fails to enlist, this enlistment process will
    stop and won't attempt to enlist any additional nodes. If a node is
    already known to MAAS, it will fail to enlist, so all nodes must be
    added at once.

    There is also room for optimization during enlistment. While our
    client deals with a single server at a time, the API is capable
    of reading/writing the settings of multiple servers in the same
    request.
    """
    with logged_in(url, username, password) as api:
        servers = probe_servers(api)
        for server, _ in servers:
            set_lan_boot_default(api, server)

    for server, macs in servers:
        params = {
            "power_address": url,
            "power_user": username,
            "power_pass": password,
            "uuid": server.get("uuid"),
        }
        system_id = create_node(macs, "amd64", "ucsm", params, domain).wait(30)

        if accept_all:
            commission_node(system_id, user).wait(30)
Example #6
0
def probe_and_enlist_msftocs(
    user: str,
    ip: str,
    port: Optional[int],
    username: Optional[str],
    password: Optional[str],
    accept_all: bool = False,
    domain: str = None,
):
    """Extracts all of nodes from msftocs, sets all of them to boot via
    HDD by, default, sets them to bootonce via PXE, and then enlists them
    into MAAS.
    """
    # The default port for a MicrosoftOCS chassis is 8000. We expect an
    # integer from the AddChassis RPC call.
    port = 8000 if port is None or port == 0 else port

    msftocs_driver = MicrosoftOCSPowerDriver()
    context = {
        "power_address": ip,
        "power_port": str(port),
        "power_user": username,
        "power_pass": password,
    }
    try:
        # if get_blades works, we have access to the system
        blades = msftocs_driver.get_blades(context)
    except urllib.error.HTTPError as e:
        raise PowerFatalError(
            "Failed to probe nodes for Microsoft OCS with ip=%s "
            "port=%s, username=%s, password=%s. HTTP error code: %s" %
            (ip, port, username, password, e.code))
    except urllib.error.URLError as e:
        raise PowerFatalError(
            "Failed to probe nodes for Microsoft OCS with ip=%s "
            "port=%s, username=%s, password=%s. "
            "Server could not be reached: %s" %
            (ip, port, username, password, e.reason))
    else:
        for blade_id, macs in blades.items():
            context["blade_id"] = blade_id
            # Set default (persistent) boot to HDD
            msftocs_driver.set_next_boot_device(context, persistent=True)
            # Set next boot to PXE
            msftocs_driver.set_next_boot_device(context, pxe=True)
            system_id = create_node(macs, "amd64", "msftocs", context,
                                    domain).wait(30)

            if accept_all:
                commission_node(system_id, user).wait(30)
Example #7
0
def probe_hmcz_and_enlist(
    user: str,
    hostname: str,
    username: str,
    password: str,
    accept_all: bool = False,
    domain: str = None,
    prefix_filter: str = None,
):
    """Extracts all of the VMs from an HMC for Z and enlists them into MAAS.

    :param user: user for the nodes.
    :param hostname: Hostname for Proxmox
    :param username: The username to connect to Proxmox to
    :param password: The password to connect to Proxmox with.
    :param accept_all: If True, commission enlisted nodes.
    :param domain: What domain discovered machines to be apart of.
    :param prefix_filter: only enlist nodes that have the prefix.
    """
    session = Session(hostname, username, password)
    client = Client(session)
    # Each HMC manages one or more CPCs(Central Processor Complex). Iterate
    # over all CPCs to find all partitions to add.
    for cpc in client.cpcs.list():
        if not cpc.dpm_enabled:
            maaslog.warning(
                f"DPM is not enabled on '{cpc.get_property('name')}', "
                "skipping")
            continue
        for partition in cpc.partitions.list():
            if prefix_filter and not partition.name.startswith(prefix_filter):
                continue

            system_id = yield create_node(
                [
                    nic.get_property("mac-address")
                    for nic in partition.nics.list()
                ],
                "s390x",
                "hmcz",
                {
                    "power_address": hostname,
                    "power_user": username,
                    "power_pass": password,
                    "power_partition_name": partition.name,
                },
                domain,
                partition.name,
            )

            # If the system_id is None an error occured when creating the machine.
            # Most likely the error is the node already exists.
            if system_id is None:
                continue

            if accept_all:
                yield commission_node(system_id, user)
Example #8
0
    def test_calls_commission_node_rpc(self):
        protocol, connecting = self.prepare_region_rpc()
        self.addCleanup((yield connecting))
        protocol.CommissionNode.return_value = defer.succeed({})
        system_id = factory.make_name('system_id')
        user = factory.make_name('user')

        yield commission_node(system_id, user)
        self.assertThat(
            protocol.CommissionNode, MockCalledOnceWith(
                protocol, system_id=system_id, user=user))
Example #9
0
    def process_vms(data):
        extra_headers, response_data = data
        vms = json.loads(response_data)["data"]
        if not vms:
            raise PowerActionError(
                "No VMs returned! Are permissions set correctly?"
            )
        for vm in vms:
            if prefix_filter and not vm["name"].startswith(prefix_filter):
                continue
            # Proxmox doesn't have an easy way to get the MAC address, it
            # includes it with a bunch of other data in the config.
            vm_config_data = yield proxmox._webhook_request(
                b"GET",
                proxmox._get_url(
                    context,
                    f"nodes/{vm['node']}/{vm['type']}/{vm['vmid']}/config",
                ),
                proxmox._make_auth_headers("", {}, extra_headers),
                verify_ssl,
            )
            macs = [
                mac[0] for mac in mac_regex.findall(vm_config_data.decode())
            ]

            system_id = yield create_node(
                macs,
                "amd64",
                "proxmox",
                {"power_vm_name": vm["vmid"], **context},
                domain,
                hostname=vm["name"].replace(" ", "-"),
            )

            # If the system_id is None an error occured when creating the machine.
            # Most likely the error is the node already exists.
            if system_id is None:
                continue

            if vm["status"] != "stopped":
                yield proxmox._webhook_request(
                    b"POST",
                    proxmox._get_url(
                        context,
                        f"nodes/{vm['node']}/{vm['type']}/{vm['vmid']}/"
                        "status/stop",
                    ),
                    proxmox._make_auth_headers(system_id, {}, extra_headers),
                    context.get("power_verify_ssl") == SSL_INSECURE_YES,
                )

            if accept_all:
                yield commission_node(system_id, user)
Example #10
0
def probe_seamicro15k_and_enlist(
        user, ip, username, password, power_control=None, accept_all=False,
        domain=None):
    power_control = power_control or 'ipmi'

    maaslog.info("Probing for seamicro15k servers as %s@%s", username, ip)

    servers = find_seamicro15k_servers(ip, username, password, power_control)

    for system_id, macs in servers:
        params = {
            'power_address': ip,
            'power_user': username,
            'power_pass': password,
            'power_control': power_control,
            'system_id': system_id
        }
        maaslog.info("Creating seamicro15k node with MACs: %s", macs)
        system_id = create_node(
            macs, 'amd64', 'sm15k', params, domain=domain).wait(30)

        if accept_all:
            commission_node(system_id, user).wait(30)
Example #11
0
    def test_logs_error_when_not_able_to_commission(self):
        protocol, connecting = self.prepare_region_rpc()
        self.addCleanup((yield connecting))
        maaslog = self.patch(provisioningserver.rpc.utils, 'maaslog')
        system_id = factory.make_name('system_id')
        user = factory.make_name('user')
        error = CommissionNodeFailed('error')

        protocol.CommissionNode.return_value = defer.fail(error)

        yield commission_node(system_id, user)
        self.assertThat(
            maaslog.error, MockCalledOnceWith(
                "Could not commission with system_id %s because %s.",
                system_id, error.args[0]))
Example #12
0
def probe_and_enlist_mscm(
    user: str,
    host: str,
    username: Optional[str],
    password: Optional[str],
    accept_all: bool = False,
    domain: str = None,
):
    """ Extracts all of nodes from the MSCM, sets all of them to boot via M.2
    by, default, sets them to bootonce via PXE, and then enlists them into
    MAAS.  If accept_all is True, it will also commission them.
    """
    mscm_driver = MSCMPowerDriver()
    # Discover all available nodes
    #
    # Example of output from running "show node list":
    # "show node list\r\r\nSlot ID    Proc Manufacturer
    # Architecture         Memory Power Health\r\n----
    # ----- ---------------------- --------------------
    # ------ ----- ------\r\n 01  c1n1  Intel Corporation
    # x86 Architecture     32 GB  On    OK \r\n 02  c2n1
    # N/A                    No Asset Information \r\n\r\n'"
    node_list = mscm_driver.run_mscm_command(
        "show node list",
        power_address=host,
        power_user=username,
        power_pass=password,
    )
    nodes = re.findall(r"c\d+n\d", node_list)
    for node_id in nodes:
        params = {
            "power_address": host,
            "power_user": username,
            "power_pass": password,
            "node_id": node_id,
        }
        # Set default boot to M.2
        mscm_driver.run_mscm_command("set node boot M.2 %s" % node_id,
                                     **params)
        # Retrieve node architecture
        #
        # Example of output from running "show node info <node_id>":
        # "show node info c1n1\r\r\n\r\nCartridge #1 \r\n
        # Type: Compute\r\n Manufacturer: HP\r\n
        # Product Name: ProLiant m500 Server Cartridge\r\n"
        node_info = mscm_driver.run_mscm_command("show node info %s" % node_id,
                                                 **params)
        match = re.search(r"Product Name:\s*([A-Za-z0-9 ]+)", node_info)
        if match is None:
            raise PowerFatalError(
                "MSCM Power Driver unable to extract node architecture"
                " from: %s" % node_info)
        else:
            cartridge = match.group(1)
        if cartridge in cartridge_mapping:
            arch = cartridge_mapping[cartridge]
        else:
            arch = cartridge_mapping["Default"]
        # Retrieve node MACs
        #
        # Example of output from running "show node macaddr <node_id>":
        # "show node macaddr c1n1\r\r\nSlot ID    NIC 1 (Switch A)
        # NIC 2 (Switch B)  NIC 3 (Switch A)  NIC 4 (Switch B)\r\n
        # ---- ----- ----------------- ----------------- -----------------
        # -----------------\r\n  1  c1n1  a0:1d:48:b5:04:34 a0:1d:48:b5:04:35
        # a0:1d:48:b5:04:36 a0:1d:48:b5:04:37\r\n\r\n\r\n"
        node_macaddr = mscm_driver.run_mscm_command(
            "show node macaddr %s" % node_id, **params)
        macs = re.findall(r":".join(["[0-9a-f]{2}"] * 6), node_macaddr)
        # Create node
        system_id = create_node(macs, arch, "mscm", params, domain).wait(30)

        if accept_all:
            commission_node(system_id, user).wait(30)