Example #1
0
def print_cluster(servers: Dict[str, List[OpenStackVMInfo]], vh: ValueHolder = None):
  __run_ico = Symbols.PLAY.color(Colors.GREEN)
  __pause_ico = Symbols.PAUSE.color(Colors.BRIGHT_YELLOW)
  __stop_ico = Symbols.STOP.color(Colors.RED)

  if vh is None:
    vh = ValueHolder(2, [40, 20])

  to = TableOutput(
    TableColumn("Cluster Name", vh.get(WidthConst.max_cluster_name)),
    TableColumn("", 5),
    TableColumn("Nodes state", 20, inv_ch=Colors.GREEN.wrap_len() * 3),
    TableColumn("VmType", vh.get(WidthConst.max_vm_type_len)),
    TableColumn("Lifetime", 10)
  )

  to.print_header()

  for cluster_name, _servers in servers.items():
    server = _servers[0]
    num_running: int = len([s for s in _servers if s.state == ServerPowerState.running])
    num_paused: int = len([s for s in _servers if s.state == ServerPowerState.paused])
    num_stopped: int = len(_servers) - num_running - num_paused

    to.print_row(
      cluster_name,
      f"{len(_servers):>3}{Symbols.PC}:",
      f"{__run_ico}{num_running:<3} {__pause_ico}{num_paused:<3} {__stop_ico}{num_stopped:<3}",
      server.flavor.name,
      get_lifetime(server.created)
    )
Example #2
0
def print_cluster(servers: Dict[str, List[OpenStackVMInfo]], vh: ValueHolder = None, ostack: OpenStack = None):
  __run_ico = Symbols.PLAY.green()
  __pause_ico = Symbols.PAUSE.yellow()
  __stop_ico = Symbols.STOP.red()
  __state = {
    ServerPowerState.running: __run_ico,
    ServerPowerState.paused: __pause_ico
  }

  if vh is None:
    vh = ValueHolder(3, [50, 30, 15])

  to = TableOutput(
    TableColumn("", 1, inv_ch=Colors.GREEN.wrap_len()),
    TableColumn("Host name", vh.get(WidthConst.max_fqdn_len)),
    TableColumn("Host IP", 16),
    TableColumn("SSH Key", vh.get(WidthConst.max_key_len)),
    TableColumn("Network name", length=vh.get(WidthConst.max_net_len))
  )

  to.print_header()
  for cluster_name, servers in servers.items():
    servers = sorted(servers, key=lambda x: x.fqdn)
    for server in servers:
      to.print_row(
        __state[server.state] if server.state in __state else __stop_ico,
        server.fqdn,
        server.ip_address if server.ip_address else "0.0.0.0",
        server.key_name,
        server.net_name
      )
Example #3
0
def host_selector(ostack: OpenStack, name: str, node_index: Optional[int] = None, own: bool = False) -> OpenStackVMInfo:
  if name == "None":
    name = ""

  if name and node_index == -1:
    _name, _, _node_index = name.rpartition("-")

    try:
      node_index = int(_node_index)
      name = _name
    except (ValueError, TypeError):
      pass

  if "." in name:
    name, _ = name.split(".")

  search_result: Dict[str, List[OpenStackVMInfo]] = ostack.get_server_by_cluster(name, sort=True, only_owned=own)
  to = TableOutput(
    TableColumn("Cluster name", 40),
    print_row_number=True
  )
  if len(search_result.keys()) > 1:
    to.print_header()
    for cluster_name in search_result.keys():
      to.print_row(cluster_name)

    selection: int = Console.ask("Choose cluster from the list", int)
    try:
      name = list(search_result.keys())[selection:][0]
    except IndexError:
      raise ValueError("Wrong selection, please select item within an provided range")
  elif search_result:
    name = list(search_result.keys())[0]
  else:
    raise ValueError(f"No matching cluster matching pattern'{name}' found")

  nodes: List[OpenStackVMInfo] = search_result[name]
  if node_index == -1:
    if len(nodes) > 1:
      to = TableOutput(
        TableColumn("IP", 18),
        TableColumn("Host name", 40),

        print_row_number=True
      )
      to.print_header()
      for node in nodes:
        to.print_row(node.ip_address, node.fqdn)
      node_index: int = Console.ask("Choose host from the list", int)
      if node_index > len(nodes):
        raise ValueError("Wrong selection, please select item within an provided range")
    else:
      node_index = 0
  else:
    node_index -= 1    # the node name starts for 1, while list from 0

  try:
    return nodes[node_index]
  except IndexError:
    raise ValueError("Unknown host name, please check the name")
Example #4
0
def __init__(conf: Configuration, search_pattern: str, own: bool):
    ostack = OpenStack(conf)
    image_id_ref: Dict[str,
                       DiskImageInfo] = {img.id: img
                                         for img in ostack.images}
    images: List[tuple[DiskImageInfo, str, DiskImageInfo]] = [
    ]  #  Snap Image, Base Image Name, Base Image
    user_id = conf.user_id

    _search_pattern = search_pattern.lower() if search_pattern else None

    max_name_len: TableMaxValue[int] = TableMaxValue(0)
    max_base_name: TableMaxValue[int] = TableMaxValue(0)

    for image in ostack.images:
        if own and image.user_id != user_id:
            continue
        if not image.image_type:
            continue
        if search_pattern and _search_pattern not in image.name.lower():
            continue

        base_image: DiskImageInfo = image_id_ref[
            image.
            base_image_ref] if image.base_image_ref in image_id_ref else None
        base_os_image: OSImageInfo = ostack.get_os_image(
            base_image) if base_image else None

        base_image_name: str = base_os_image.name if base_os_image else\
                             base_image.name if base_image else "unknown"
        max_name_len.process(len(image.name))
        max_base_name.process(len(base_image_name))

        images.append((
            image,
            base_image_name,
            base_image,
        ))

    table = TableOutput(TableColumn("Name", max_name_len.value),
                        TableColumn("Status", 10),
                        TableColumn("Base Image Name", max_base_name.value),
                        TableColumn("Snap Size | Base Sise | Total Size", 36),
                        TableColumn("Visibility", 10))

    table.print_header()

    for image, base_name, base_image in images:
        snap_size = TableSizeColumn(image.size)
        base_image_size = TableSizeColumn(
            base_image.size) if base_image else snap_size

        table.print_row(
            image.name, image.status, base_name,
            f"{(snap_size-base_image_size).value:>10} | {base_image_size.value:>10} | {snap_size.value:>10}",
            image.visibility)
Example #5
0
def __init__(conf: Configuration, details: bool, show_clusters: bool,
             graph: bool):
    stack = OpenStack(conf)
    limits = stack.quotas

    to = TableOutput(
        TableColumn("Metric",
                    length=limits.max_metric_len,
                    pos=TableColumnPosition.right,
                    sep=":",
                    inv_ch=Colors.RED.wrap_len()),
        TableColumn("Used",
                    length=7,
                    pos=TableColumnPosition.right,
                    sep="|",
                    inv_ch=Colors.RED.wrap_len()),
        TableColumn(
            "Avl.",
            length=7,
            pos=TableColumnPosition.right,
            sep="|",
        ), TableColumn("Total", length=7, pos=TableColumnPosition.right),
        TableColumn("", length=30))

    print(f"Region {conf.region} stats\n")

    to.print_header(solid=True)

    for metric in limits:
        prc = get_percents(metric.used, metric.max_count)
        c_end = Colors.RESET if prc > 80 else ""
        c_start = Colors.RED if prc > 90 else Colors.YELLOW if prc > 80 else ""

        if metric.max_count < 0:
            c_start = ""
            c_end = ""

        to.print_row(
            f"{c_start}{metric.name}{c_end}", f"{c_start}{metric.used}{c_end}",
            "-" if metric.available < 0 else metric.available,
            "-" if metric.max_count < 0 else metric.max_count,
            f"{get_progressbar(prc, c_start)} {c_start}{prc:.1f}%{c_end}")

    print()
    print("* Used/Avl.    - raw metric")
    print()

    if graph:
        _show_graph(stack, limits)
    elif details:
        print("Calculating per-user statistic....")
        _show_details(conf, stack, limits, show_clusters)
Example #6
0
def show_normal(conf: Configuration, ostack: OpenStack, search_pattern: str,
                own: bool):
    images = ostack.os_images

    table = TableOutput(TableColumn("Name", 20), TableColumn("Alias", 20),
                        TableColumn("Size", 9), TableColumn("Description", 60))
    table.print_header()

    for image in images:
        if search_pattern and search_pattern.lower() not in image.name.lower():
            continue

        table.print_row(image.name, image.alias,
                        TableSizeColumn(image.size).value, image.description)
Example #7
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
Example #8
0
def print_networks(ostack: OpenStack,
                   select: bool = False) -> OSNetworkItem or None:
    tbl = TableOutput(TableColumn("N.", 3),
                      TableColumn("Zone", 10),
                      TableColumn("Name", 20),
                      TableColumn("CIDR", 15),
                      TableColumn("Domain name", 30),
                      TableColumn("DNS", 15),
                      TableColumn("Active", 6),
                      style=TableStyle.line_highlight)
    nets: List[OSNetworkItem] = sorted(ostack.networks, key=lambda x: x.name)

    tbl.print_header()
    counter: int = 0
    for net in nets:
        if len(net.dns_nameservers) > 1:
            dns_servers = net.dns_nameservers[:-1]
            for dns_ip in dns_servers:
                tbl.print_row("", "", "", "", "", "", dns_ip, "")

        tbl.print_row(
            str(counter), ",".join(net.orig_network.availability_zones),
            net.name, net.cidr, net.domain_name,
            ",".join(net.dns_nameservers[-1:]) if len(net.dns_nameservers) > 1
            else ",".join(net.dns_nameservers), net.orig_network.status)
        counter += 1

    if select:
        a = input("Please select item:")
        try:
            return nets[int(a)]
        except ValueError:
            pass

    return None
Example #9
0
def show_all(conf: Configuration, ostack: OpenStack, search_pattern: str,
             own: bool):
    images = ostack.images

    table = TableOutput(TableColumn("Id", 36), TableColumn("Name", 60),
                        TableColumn("Size", 9), TableColumn("Status", 10),
                        TableColumn("Description", 20))

    table.print_header()

    for image in images:
        if image.image_type:
            continue

        if search_pattern and search_pattern.lower() not in image.name.lower():
            continue

        table.print_row(image.id, image.name,
                        TableSizeColumn(image.size).value, image.status,
                        image.description if image.description else "-")
Example #10
0
def __init__(conf: Configuration, image_name: str, sort_by_name: bool,
             all: bool):
    sort_keys = {
        True: lambda x: x.name,
        False: lambda x: (x.vcpus, x.ram, x.disk, x.ephemeral_disk)
    }
    ostack = OpenStack(conf)
    if image_name:
        images = list(ostack.get_image_by_alias(image_name))
        if images and len(images) > 1:
            Console.print_error(
                f"Image '{image_name}' matches more than one image")
            return
        elif not images:
            Console.print_error(f"No image with name '{image_name}' found")
            return
        flavors = sorted(ostack.get_flavors(images[0]),
                         key=sort_keys[sort_by_name])
    else:
        flavors = sorted(ostack.flavors, key=sort_keys[sort_by_name])

    table = TableOutput(TableColumn("Name", 20), TableColumn("vCPU", 5),
                        TableColumn("RAM", 9), TableColumn("D+E Size", 15),
                        TableColumn("Disk", 15),
                        TableColumn("Ephemeral Disk", 15),
                        TableColumn("Id", 36))

    table.print_header()

    for flavor in flavors:
        if not all and flavor.ephemeral_disk == 0:
            continue
        table.print_row(flavor.name, flavor.vcpus,
                        TableSizeColumn(flavor.ram).value,
                        TableSizeColumn(flavor.sum_disk_size).value,
                        TableSizeColumn(flavor.disk).value,
                        TableSizeColumn(flavor.ephemeral_disk).value,
                        flavor.id)
Example #11
0
def __init__(conf: Configuration, name: str, node_number: int, user_name: str, use_password: bool, use_key: str,
             own: bool, port: int, internal: bool):
  ostack = OpenStack(conf)
  if name == "None":
    name = ""

  if use_key == "None":
    use_key = None

  if name and node_number == -1:
    _name, _, _node_number = name.rpartition("-")

    try:
      node_number = int(_node_number)
      name = _name
    except (ValueError, TypeError):
      pass

  if "." in name:
    name, _ = name.split(".")

  search_result: Dict[str, List[OpenStackVMInfo]] = ostack.get_server_by_cluster(name, sort=True, only_owned=own)
  to = TableOutput(
    TableColumn("Cluster name", 40),
    print_row_number=True
  )
  if len(search_result.keys()) > 1:
    to.print_header()
    for cluster_name in search_result.keys():
      to.print_row(cluster_name)

    selection: int = Console.ask("Choose cluster from the list", int)
    try:
      name = list(search_result.keys())[selection:][0]
    except IndexError:
      raise ValueError("Wrong selection, please select item within an provided range")
  elif search_result:
    name = list(search_result.keys())[0]
  else:
    raise ValueError(f"No matching cluster matching pattern'{name}' found")

  nodes: List[OpenStackVMInfo] = search_result[name]
  if node_number == -1:
    if len(nodes) > 1:
      to = TableOutput(
        TableColumn("IP", 18),
        TableColumn("Host name", 40),

        print_row_number=True
      )
      to.print_header()
      for node in nodes:
        to.print_row(node.ip_address, node.fqdn)
      node_number: int = Console.ask("Choose host from the list", int)
      if node_number > len(nodes):
        raise ValueError("Wrong selection, please select item within an provided range")
    else:
      node_number = 0
  else:
    node_number -= 1    # the node name starts for 1, while list from 0

  try:
    node: OpenStackVMInfo = nodes[node_number]
  except IndexError:
    raise ValueError("Unknown host name, please check the name")

  print(f"Establishing connection to {node.fqdn}({node.ip_address}) as '{user_name}' user...")
  if use_password:
    _open_console(internal, node.ip_address, port=port, user_name=user_name, password=True)
  else:
    if not os.path.exists(conf.local_key_dir):
      os.makedirs(conf.local_key_dir, exist_ok=True)

    if not use_key and node.key_name and node.key_name in conf.key_names and conf.get_key(node.key_name).private_key:
      #PKCS8 format -> openssl
      pkcs8_frmt_B = "-----BEGIN PRIVATE KEY-----"
      pkcs8_frmt_E ="-----END PRIVATE KEY-----"
      openssl_frmt_B = "-----BEGIN RSA PRIVATE KEY-----"
      openssl_frmt_E = "-----END RSA PRIVATE KEY-----"

      key = conf.get_key(node.key_name).private_key
      if pkcs8_frmt_B in key:
        key = key.replace(pkcs8_frmt_B, openssl_frmt_B)

      if pkcs8_frmt_E in key:
        key = key.replace(pkcs8_frmt_E, openssl_frmt_E)

      use_key = os.path.join(conf.local_key_dir, node.key_name) + ".key"
      with open(use_key, "w+", encoding="UTF-8") as f:
        f.write(key)
      try:
        os.chmod(use_key, 0o600)
      except OSError:
        pass
    else:
      raise ValueError("No custom key provided nor private key found in the key storage. Please add private key to"
                       " storage or use custom one with 'use-key' argument")

    _open_console(internal, node.ip_address, user_name=user_name, port=port, key_file=use_key)
    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"
            )
Example #13
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)