Exemplo n.º 1
0
def _keys_list(conf: Configuration,
               ostack: OpenStack,
               show_row_nums: bool = False) -> List[VMKeypairItemValue]:
    server_keypairs: Dict[int, VMKeypairItemValue] = {
        hash(key): key
        for key in ostack.get_keypairs()
    }
    conf_keys = conf.get_keys()
    if not conf_keys:
        Console.print_warning("No keys found, add new ones")
        return []

    max_key_len = len(max(conf.key_names))
    to = TableOutput(TableColumn("Key Name",
                                 max_key_len + len(KEY_ICON),
                                 inv_ch=len(KEY_ICON) - 2,
                                 pos=TableColumnPosition.left),
                     TableColumn("Priv.Key",
                                 3,
                                 inv_ch=len(CHECK_ICON) - 2,
                                 pos=TableColumnPosition.center),
                     TableColumn("Pub.Key",
                                 3,
                                 inv_ch=len(CHECK_ICON) - 2,
                                 pos=TableColumnPosition.center),
                     TableColumn("Rem.Sync",
                                 3,
                                 inv_ch=len(CHECK_ICON),
                                 pos=TableColumnPosition.center),
                     TableColumn("Fingerprint",
                                 48,
                                 pos=TableColumnPosition.left),
                     print_row_number=show_row_nums)

    to.print_header()

    for kp in conf_keys:
        to.print_row(
            f"{KEY_ICON}{kp.name}",
            CHECK_ICON if kp.private_key else UNCHECK_ICON,
            CHECK_ICON if kp.public_key else UNCHECK_ICON,
            CHECK_ICON if hash(kp) in server_keypairs else UNCHECK_ICON,
            server_keypairs[hash(kp)].fingerprint
            if hash(kp) in server_keypairs else
            "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00")

    return conf_keys
    def __call__(self, *args, **kwargs):
        assert isinstance(self._conf, Configuration)
        conf: Configuration = self._conf

        if not conf.os_address:
            conf.os_address = self.ask_text_question(
                "OpenStack identity api address: ")

        if not conf.os_login:
            conf.os_login = self.ask_text_question("OpenStack username: "******"OpenStack password: "******"""
    Login sequence:
    ------------------
    - unscoped loing
    - set project id
    - scoped login
    - fetch region
    - relogin to fetch API endpoints
    """

        if not conf.project.id:
            print("Fetching available projects....")
            if not osvm.login(_type=AuthRequestType.UNSCOPED):
                if osvm.has_errors:
                    so.check_issues()
                    self.reset()
                raise RuntimeError("Unable to continue")

            projects = osvm.projects
            to = TableOutput(TableColumn("Id", 33),
                             TableColumn("Name", 20),
                             TableColumn("Enabled", 6),
                             print_row_number=True)

            to.print_header()
            for prj in projects:
                to.print_row(prj.id, prj.name, prj.enabled)

            n: int = Console.ask("Select the project number to be used",
                                 _type=int)
            conf.project = VMProject(id=projects[n].id,
                                     name=projects[n].name,
                                     domain=projects[n].domain_id)
            osvm.logout()

        print(f"Checking login for the project '{conf.project.name}'...")
        if not osvm.login():
            if osvm.has_errors:
                so.check_issues()
                self.reset()
            raise RuntimeError("Unable to continue")

        if not conf.region:
            print(
                f"Fetching available regions for the project '{conf.project.name}'..."
            )
            to = TableOutput(TableColumn("Id", 33),
                             TableColumn("Descriuption"),
                             print_row_number=True)
            to.print_header()
            regions = osvm.regions
            for region in regions:
                to.print_row(region.id, region.description)

            n: int = Console.ask("Select the region number to be used",
                                 _type=int)
            conf.region = regions[n].id
            osvm.logout()

            if not osvm.login():
                conf.reset()
                raise RuntimeError("Unable to continue")

        if not conf.default_network:
            print(
                "Please select default network for the VM (could be changed via 'conf network' command):"
            )
            _net = print_networks(ostack=osvm, select=True)
            if not _net:
                raise RuntimeError("Network is not selected")
            conf.default_network = _net

        if not conf.default_vm_password:
            _p = self.ask_text_question("Default VM password: "******"qwerty"
            conf.default_vm_password = _p

        _default_keypair_name = "default"
        keys = conf.get_keys()
        srv_keys = osvm.get_keypairs(no_cache=True)
        _is_srv_key = False
        _is_cfg_key = False
        for srv_key in srv_keys:
            if srv_key.name == _default_keypair_name:
                _is_srv_key = True
                break

        for cfg_key in keys:
            if cfg_key.name == _default_keypair_name:
                _is_cfg_key = True
                break

        if _is_cfg_key and not _is_srv_key:
            print(f"Purging  '{_default_keypair_name}' key from configuration")
            conf.delete_key(_default_keypair_name)
            _is_cfg_key = False

        if not _is_cfg_key and not _is_srv_key:
            print(f"Creating new '{_default_keypair_name}' keypair..")
            _create_key(
                conf, osvm,
                VMNewKeyPairItemBuilder().set_name(_default_keypair_name))
            print(
                f"Key '{_default_keypair_name}' could be exported using command 'conf keys export {_default_keypair_name}'"
            )

        if not _is_cfg_key and _is_srv_key:
            print(
                f"Public key '{_default_keypair_name}' would be re-synced locally, please add private key or re-generate new default key"
            )
Exemplo n.º 3
0
def __init__(conf: Configuration, name: str, count: int, flavor: str,
             image: str, key: str, password: str):
    def __work_unit(x: OpenStackVMInfo) -> bool:
        while True:
            if x.status == ServerState.active:
                return True

            if x.status not in [
                    ServerState.building, ServerState.build, ServerState.active
            ]:
                return False

            sleep(2)
            #  ToDo: short term cache data by reservation_id
            x = ostack.get_server_by_id(x)

    # ======================================================================
    ostack = OpenStack(conf)
    vh = ValueHolder(2)

    def __filter(vm: OpenStackVMInfo) -> bool:
        r = not str(vm.name).startswith(name)
        if not r:
            vh.set_if_bigger(0, len(vm.cluster_name))
            vh.set_if_bigger(1, len(vm.flavor.name))
        return r

    servers = ostack.get_server_by_cluster(name, True, filter_func=__filter)
    if len(servers) > 1:
        Console.print_warning(
            f"Cluster with name '{Colors.BRIGHT_WHITE.wrap(name)}' already exists, instance would be not be created"
        )
        print_cluster(servers, vh)
        return
    elif len(servers) == 1:
        Console.print_info(
            f"The cluster already exists, will add requested amount of hosts to the cluster"
        )
        with Console.status_context(
                f"Obtaining cluster information from existing {name}..."):
            cluster_name, hosts = next(iter(servers.items()))
            cluster_name: str = cluster_name
            hosts: List[OpenStackVMInfo] = hosts
            host: OpenStackVMInfo = hosts[0]

            # re-calculate host names
            last_host_name = hosts[-1:][0].name
            _, _, num = last_host_name.rpartition("-")

            _start_num: int = 1
            if num and num.isnumeric():
                _start_num: int = int(num) + 1

            name: List[str] = [
                f"{cluster_name}-{num}"
                for num in range(_start_num, _start_num + count)
            ]

            image: OSImageInfo = ostack.get_os_image(host.image)
            img_flavor: OSFlavor = host.flavor
            _default_key = ostack.get_keypairs()[0] if ostack.get_keypairs(
            ) else None
            _key = ostack.get_keypair(host.key_name, _default_key)
            _pass = conf.default_vm_password if not password else password

            print(f"   |Image flavor to use: {img_flavor.name}")
            print(f"   |Image to use       : {image.alias}")
            print(f"   |Key to use         : {_key.name}")
            print(f"   |Hosts to add       : {', '.join(name)}")
    else:
        with Console.status_context("Resolving cluster configuration"):
            image: List[OSImageInfo] = list(ostack.get_image_by_alias(image))
            if not image:
                raise RuntimeError("Cannot resolve image name for the request")

            image: OSImageInfo = image[0]
            img_flavor = ostack.get_flavor(image, flavor)
            _default_key = ostack.get_keypairs()[0] if ostack.get_keypairs(
            ) else None
            _key = _default_key if not key else ostack.get_keypair(
                key, _default_key)
            _pass = conf.default_vm_password if not password else password

    # == create nodes

    so = StatusOutput(__work_unit,
                      pool_size=2,
                      additional_errors=ostack.last_errors)

    with Console.status_context("Asking for node creation"):
        servers = ostack.create_instances(cluster_names=name,
                                          image=image,
                                          flavor=img_flavor,
                                          password=_pass,
                                          count=count,
                                          ssh_key=_key)
        if not servers:
            so.check_issues()
            return

    so.start("Creating nodes ", objects=servers)

    # == Configure nodes
    def __work_unit_waiter(x: OpenStackVMInfo) -> bool:
        tries: int = 0
        while tries < 200:
            log = ostack.get_server_console_log(x.id)
            for l in log:
                if "finished" in l or "login:"******"Configure nodes", servers)

    console = ostack.get_server_console_log(servers[0], grep_by="cloud-init")

    to = TableOutput(TableColumn("Name", 15), TableColumn("Value", 30))

    to.print_header(custom_header="SUMMARY")

    for line in console:
        if "@users@" in line:
            users = line.split("@users@:")[1].strip().split(" ")
            to.print_row("Accounts", ",".join(users))

    to.print_row("Key", _key.name if _key else "Not used")
    to.print_row("Password", _pass)