def __init__(conf: Configuration, name: str, hard: bool, own: bool): ostack = OpenStack(conf) def __work_unit(value: OpenStackVMInfo) -> bool: return ostack.start_instance(value) so = StatusOutput(__work_unit, pool_size=5, additional_errors=ostack.last_errors) servers = ostack.get_server_by_cluster( name, sort=True, filter_func=lambda x: x.state in ServerPowerState.stop_states(), only_owned=own) if not servers: print("No matches or already started") return if Console.confirm_operation("reboot", servers): flatten_servers = [ server for server_pair in servers.values() for server in server_pair ] so.start("Rebooting nodes", objects=flatten_servers) else: print("Aborted....")
def _keys_del(conf: Configuration, ostack: OpenStack, name: str, force: bool = False): if not name: _keys = _keys_list(conf, ostack, True) item = Console.ask("Select key to remove", _type=int) if item is None or item > len(_keys) - 1: Console.print_warning("Invalid selection, aborting") return name = _keys[item].name if Console.ask_confirmation(f"Confirm removing key '{name}'", force=force): ostack.delete_keypair(name) if ostack.has_errors: so = StatusOutput(additional_errors=ostack.last_errors) so.check_issues() else: Console.print("Removed from the server") if not conf.delete_key(name): Console.print_error( f"Failed to remove key '{name}' from the configuration") else: Console.print("Removed from the configuration")
def _create_key(conf: Configuration, ostack: OpenStack, keyBuilder: VMKeyPairItemBuilder): key = keyBuilder.build() try: conf.add_key(key) ostack.create_key(key) Console.print(f"Key with name '{key.name}' successfully added") except ValueError as e: if ostack.has_errors: so = StatusOutput(None, pool_size=0, additional_errors=ostack.last_errors) so.check_issues() else: Console.print_error( f"Configuration already have the key with name {key.name}, please remove it first" )
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" )
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)