def do_multipass(self, args, arguments): """ :: Usage: multipass deploy [--dryrun] multipass list [--output=OUTPUT] [--dryrun] multipass images [--output=OUTPUT] [--dryrun] multipass create NAMES [--image=IMAGE] [--size=SIZE] [--mem=MEMORY] [--cpus=CPUS] [--cloud-init=FILE] [--dryrun] multipass delete NAMES [--output=OUTPUT][--dryrun] multipass destroy NAMES [--output=OUTPUT][--dryrun] multipass shell NAMES [--dryrun] multipass run COMMAND NAMES [--output=OUTPUT] [--dryrun] multipass info NAMES [--output=OUTPUT] [--dryrun] multipass suspend NAMES [--output=OUTPUT] [--dryrun] multipass resume NAMES [--output=OUTPUT] [--dryrun] multipass start NAMES [--output=OUTPUT] [--dryrun] multipass stop NAMES [--output=OUTPUT] [--dryrun] multipass reboot NAMES [--output=OUTPUT] [--dryrun] multipass mount SOURCE DESTINATION [--dryrun] multipass umount SOURCE [--dryrun] multipass transfer SOURCE DESTINATION [--dryrun] multipass set key=VALUE [--dryrun] multipass get [key] [--dryrun] multipass deploy [--dryrun] multipass rename NAMES [--dryrun] multipass version Interface to multipass Options: --output=OUTPUT the output format [default: table]. Other values are yaml, csv and json. --image=IMAGE the image name to be used to create a VM. --cpus=CPUS Number of CPUs to allocate. Minimum: 1, default: 1. --size=SIZE Disk space to allocate. Positive integers, in bytes, or with K, M, G suffix. Minimum: 512M, default: 5G. --mem=MEMORY Amount of memory to allocate. Positive integers, in bytes, or with K, M, G suffix. Minimum: 128M, default: 1G. --cloud-init=FILE Path to a user-data cloud-init configuration Arguments: NAMES the names of the virtual machine Description: The NAMES can be a parameterized hostname such as red[0-1,5] = red0,red1,red5 Commands: First you can see the supported multipass images with cms multipass images Create and launch a new vm using cms multipass create NAMES Optionally you can provide image name, size, memory, number of cpus to create an instance. Start one or multiple multipass vms with cms multipass start NAMES Stop one or multiple vms with cms multipass stop NAMES Gets all multipass internal key values with cms multipass get Gets a specific internal key. cms multipass get KEY Known keys client.gui.autostart client.primary-name local.driver are there more? Reboot (stop and then start) vms with cms multipass reboot NAMES Delete one of multiple vms without purging with cms multipass delete NAMES Destory multipass vms (delete and purge) with cms multipass destroy NAMES Caution: Once destroyed everything in vm will be deleted and cannot be recovered. WHEN YOU IMPLEMENT A FUNCTION INCLUDE MINIMAL DOCUMENTATION HERE """ name = arguments.NAME map_parameters(arguments, "dryrun", "refresh", "cloud", "image", "size", "mem", "cpus", "cloud-init", "output") # so we can use arguments.cloudinit arguments["cloudinit"] = arguments["--cloud-init"] image = arguments.image variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") names = Parameter.expand(arguments.NAMES) VERBOSE(arguments) if arguments.version: if arguments.dryrun: banner("dryrun list") else: provider = Provider() version = provider.version() del version["name"] print(Printer.attribute(version, header=["Program", "Version"])) return "" elif arguments.list: if arguments.dryrun: banner("dryrun list") else: provider = Provider() list = provider.list() print( provider.Print(list, kind='image', output=arguments.output)) return "" elif arguments.images: if arguments.dryrun: banner("dryrun images") else: provider = Provider() images = provider.images() print( provider.Print(images, kind='image', output=arguments.output)) return "" elif arguments.run: if arguments.dryrun: banner("dryrun run") for name in names: if arguments.dryrun: Console.ok(f"run {name} {arguments.COMMAND}") else: provider = Provider() provider.run(name, arguments.COMMAND) return "" elif arguments.create: result = "" if arguments.dryrun: banner("create") timeout = 360 group = None kwargs = { "cloud_init": arguments.cloud_init, "cpus": arguments.cpus, "memory": arguments.mem } for name in names: if arguments.dryrun: Console.ok(f"dryrun create {name} {image}") else: provider = Provider() result = provider.create(name, image, arguments.size, timeout, group, **kwargs) VERBOSE(result) return result elif arguments.start: result = "" if arguments.dryrun: banner("start") for name in names: if arguments.dryrun: Console.ok(f"dryrun start {name}") else: provider = Provider() result = provider.start(name) VERBOSE(result) return result elif arguments.stop: result = "" if arguments.dryrun: banner("stop") for name in names: if arguments.dryrun: Console.ok(f"dryrun stop {name}") else: provider = Provider(name=name) result = provider.stop(name) VERBOSE(result) return result elif arguments.delete: result = "" if arguments.dryrun: banner("delete") for name in names: if arguments.dryrun: Console.ok(f"dryrun delete {name}") else: provider = Provider() # Default purge is false. Is this ok? result = provider.delete(name) VERBOSE(result) return result elif arguments.info: result = "" if arguments.dryrun: banner(f"info {name}") for name in names: if arguments.dryrun: Console.ok(f"dryrun info {name}") else: provider = Provider() # Default purge is false. Is this ok? result = provider.info(name) VERBOSE(result) return result elif arguments.rename: result = "" if arguments.dryrun: banner(f"Current Name: {names[0]}" f"New Name: {names[1]}") if names.len() > 2: Console.error("You have entered too many names." "Only enter TWO names at a time.") else: old_name = names[0] new_name = names[1] provider = Provider() result = provider.rename(old_name, new_name) VERBOSE(result) return result elif arguments.suspend: result = "" if arguments.dryrun: banner("suspend") for name in names: if arguments.dryrun: Console.ok(f"dryrun suspend {name}") else: provider = Provider() result = provider.suspend(name) VERBOSE(result) return result elif arguments.resume: result = "" if arguments.dryrun: banner("resume") for name in names: if arguments.dryrun: Console.ok(f"dryrun resume {name}") else: provider = Provider() result = provider.resume(name) VERBOSE(result) return result elif arguments.destroy: result = "" if arguments.dryrun: banner("destroy") for name in names: if arguments.dryrun: Console.ok(f"dryrun destroy {name}") else: provider = Provider() result = provider.destroy(name) VERBOSE(result) return result elif arguments.reboot: result = "" if arguments.dryrun: banner("reboot") for name in names: if arguments.dryrun: Console.ok(f"dryrun reboot {name}") else: provider = Provider() result = provider.reboot(name) VERBOSE(result) return result elif arguments.shell: if len(names) > 1: Console.error("shell must only have one host") return "" name = names[0] if arguments.dryrun: banner("dryrun shell {name}") else: provider = Provider() provider.shell() return "" elif arguments.info: if arguments.dryrun: banner("dryrun info") else: provider = Provider() info = provider.info() print( provider.Print(info, kind='info', output=arguments.output)) return "" elif arguments.mount: if arguments.dryrun: banner( f"dryrun mount {arguments.SOURCE} {arguments.DESTINATION}") else: provider = Provider() provider.mount(arguments.SOURCE, arguments.DESTINATION) # list the mounts and display as table return "" elif arguments.deploy: provider = Deploy(dryrun=arguments.dryrun) provider.install() else: Console.error("Not yet implemented") return ""
def do_vm(self, args, arguments): """ :: Usage: vm ping [NAMES] [--cloud=CLOUDS] [--count=N] vm check [NAMES] [--cloud=CLOUDS] [--username=USERNAME] vm status [NAMES] [--cloud=CLOUDS] [--output=OUTPUT] vm console [NAME] [--force] vm log [NAME] [--force] vm stop [NAMES] [--dryrun] vm start [NAMES] [--dryrun] vm terminate [NAMES] [--cloud=CLOUD] [--dryrun] vm delete [NAMES] [--cloud=CLOUD] [--dryrun] vm refresh [--cloud=CLOUDS] vm list [NAMES] [--cloud=CLOUDS] [--output=OUTPUT] [--refresh] vm boot [--n=COUNT] [--name=VMNAMES] [--cloud=CLOUD] [--username=USERNAME] [--image=IMAGE] [--flavor=FLAVOR] [--network=NETWORK] [--public] [--secgroup=SECGROUPs] [--group=GROUPs] [--key=KEY] [--dryrun] [-v] vm meta list [NAME] vm meta set [NAME] KEY=VALUE... vm meta delete [NAME] KEY... vm script [--name=NAMES] [--username=USERNAME] [--key=KEY] [--dryrun] [--dir=DESTINATION] SCRIPT vm ip assign [NAMES] [--cloud=CLOUD] vm ip show [NAMES] [--group=GROUP] [--cloud=CLOUD] [--output=OUTPUT] [--refresh] vm ip inventory [NAMES] vm ssh [NAMES] [--username=USER] [--quiet] [--ip=IP] [--key=KEY] [--command=COMMAND] vm put SOURCE DESTINATION [NAMES] vm get SOURCE DESTINATION [NAMES] vm rename [OLDNAMES] [NEWNAMES] [--force] [--dryrun] vm wait [--cloud=CLOUD] [--interval=INTERVAL] [--timeout=TIMEOUT] vm info [--cloud=CLOUD] [--output=OUTPUT] vm username USERNAME [NAMES] [--cloud=CLOUD] vm resize [NAMES] [--size=SIZE] Arguments: OUTPUT the output format COMMAND positional arguments, the commands you want to execute on the server(e.g. ls -a) separated by ';', you will get a return of executing result instead of login to the server, note that type in -- is suggested before you input the commands NAME server name. By default it is set to the name of last vm from database. NAMES server name. By default it is set to the name of last vm from database. KEYPAIR_NAME Name of the vm keypair to be used to create VM. Note this is not a path to key. NEWNAMES New names of the VM while renaming. OLDNAMES Old names of the VM while renaming. Options: -v verbose, prints the dict at the end --output=OUTPUT the output format -H --modify-knownhosts Do not modify ~/.ssh/known_hosts file when ssh'ing into a machine --username=USERNAME the username to login into the vm. If not specified it will be guessed from the image name and the cloud --ip=IP give the public ip of the server --cloud=CLOUD give a cloud to work on, if not given, selected or default cloud will be used --count=COUNT give the number of servers to start --detail for table, a brief version is used as default, use this flag to print detailed table --flavor=FLAVOR give the name or id of the flavor --group=GROUP give the group name of server --secgroup=SECGROUP security group name for the server --image=IMAGE give the name or id of the image --key=KEY specify a key to use, input a string which is the full path to the private key file --keypair_name=KEYPAIR_NAME Name of the vm keypair to be used to create VM. Note this is not a path to key. --user=USER give the user name of the server that you want to use to login --name=NAME give the name of the virtual machine --force rename/ delete vms without user's confirmation --command=COMMAND specify the commands to be executed Description: commands used to boot, start or delete servers of a cloud vm default [options...] Displays default parameters that are set for vm boot either on the default cloud or the specified cloud. vm boot [options...] Boots servers on a cloud, user may specify flavor, image .etc, otherwise default values will be used, see how to set default values of a cloud: cloud help vm start [options...] Starts a suspended or stopped vm instance. vm stop [options...] Stops a vm instance . vm delete [options...] Delete servers of a cloud, user may delete a server by its name or id, delete servers of a group or servers of a cloud, give prefix and/or range to find servers by their names. Or user may specify more options to narrow the search vm floating_ip_assign [options...] assign a public ip to a VM of a cloud vm ip show [options...] show the ips of VMs vm ssh [options...] login to a server or execute commands on it vm list [options...] same as command "list vm", please refer to it vm status [options...] Retrieves status of last VM booted on cloud and displays it. vm refresh [--cloud=CLOUDS] this command refreshes the data for virtual machines, images and flavors for the specified clouds. vm ping [NAMES] [--cloud=CLOUDS] [--count=N] [--processors=PROCESSORS] pings the specified virtual machines, while using at most N pings. The ping is executed in parallel. If names are specifies the ping is restricted to the given names in parameter format. If clouds are specified, names that are not in these clouds are ignored. If the name is set in the variables this name is used. cms vm ssh --command=\"uname -a\" executes the uname command on the last booted vm vm script [--name=NAMES] [--username=USERNAME] [--key=KEY] [--dryrun] [--dir=DESTINATION] [--shell=SHELL] SCRIPT The script command copies a shell script to the specified vms into the DESTINATION directory and than execute it. With SHELL you can set the shell for executing the command, this coudl even be a python interpreter. Examples for SHELL are /bin/sh, /usr/bin/env python vm put SOURCE DESTINATION [NAMES] puts the file defined by SOURCE into the DESINATION folder on the specified machines. If the file exists it is overwritten, so be careful. vm get SOURCE DESTINATION [NAMES] gets the file defined by SOURCE into the DESINATION folder on the specified machines. The SOURCE is on the remote machine. If one machine is specified, the SOURCE is the same name as on the remote machine. If multiple machines are specified, the name of the machine will be a prefix to the filename. If the filenames exists, they will be overwritten, so be careful. Tip: give the VM name, but in a hostlist style, which is very convenient when you need a range of VMs e.g. sample[1-3] => ['sample1', 'sample2', 'sample3'] sample[1-3,18] => ['sample1', 'sample2', 'sample3', 'sample18'] Quoting commands: cm vm login gregor-004 --command=\"uname -a\" Limitations: Azure: rename is not supported """ map_parameters(arguments, 'active', 'cloud', 'command', 'dryrun', 'flavor', 'force', 'group' 'output', 'group', 'image', 'interval', 'timeout', 'ip', 'key', 'modify-knownhosts', 'n', 'name', 'public', 'quiet', 'secgroup', 'size', 'username', 'output', 'count', 'network', 'refresh') variables = Variables() database = CmDatabase() arguments.output = Parameter.find("output", arguments, variables, "table") arguments.refresh = Parameter.find_bool("refresh", arguments, variables) if (arguments.meta and arguments.list): name = arguments.NAME if arguments.NAME is None: name = variables['vm'] if name is None: Console.error("No vm specified") cloud = "chameleon" # cloud = Parameter.find(arguments, variables) print(f"vm metadata for {name} on {cloud}") provider = Provider(name=cloud) r = provider.get_server_metadata(name) print(r) elif arguments.meta and arguments.set: metadata = {} pairs = arguments['KEY=VALUE'] for pair in pairs: key, value = pair.split("=", 1) metadata[key] = value name = arguments.NAME if arguments.NAME is None: name = variables['vm'] if name is None: Console.error("No vm specified") cloud = "chameleon" # cloud = Parameter.find(arguments, variables) print(f"cloud {cloud} {name}") provider = Provider(name=cloud) provider.set_server_metadata(name, **metadata) r = provider.get_server_metadata(name) pprint(r) elif arguments.meta and arguments.delete: metadata = {} keys = arguments['KEY'] name = arguments.NAME if arguments.NAME is None: name = variables['vm'] if name is None: Console.error("No vm specified") cloud = "chameleon" # cloud = Parameter.find(arguments, variables) print(f"cloud {cloud} {name}") provider = Provider(name=cloud) for key in keys: provider.delete_server_metadata(name, key) r = provider.get_server_metadata(name) pprint(r) elif arguments.list and arguments.refresh: names = [] clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) for cloud in clouds: print(f"cloud {cloud}") provider = Provider(name=cloud) vms = provider.list() provider.Print(vms, output=arguments.output, kind="vm") return "" elif arguments.list: names = [] clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) try: for cloud in clouds: print(f"List {cloud}") p = Provider(cloud) kind = p.kind collection = "{cloud}-vm".format(cloud=cloud, kind=p.kind) db = CmDatabase() vms = db.find(collection=collection) p.Print(vms, output=arguments.output, kind="vm") except Exception as e: Console.error("Error in listing ", traceflag=True) VERBOSE(e) return "" elif arguments.ping: """ vm ping [NAMES] [--cloud=CLOUDS] [--count=N] """ if arguments.NAMES: variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names( "status", arguments, variables) count = arguments.count if arguments.count: count = int(count) else: count = 1 def get_ips(): ips = [] for cloud in clouds: params = {} # gets public ips from database cursor = database.db[f'{cloud}-vm'] for name in names: for node in cursor.find({'name': name}): ips.append(node['ip_public']) ips = list(set(ips)) pprint(ips) return ips ips = get_ips() if len(ips) == 0: Console.warning("no public ip found.") for cloud in clouds: print(f"refresh for cloud {cloud}") provider = Provider(name=cloud) vms = provider.list() ips = get_ips() if len(ips) == 0: Console.error("No vms with public IPS found.") Console.error(" Make sure to use cms vm list --refresh") for ip in ips: result = Shell.ping(host=ip, count=count) banner(ip) print(result) print() elif arguments.check: raise NotImplementedError """ vm check [NAMES] [--cloud=CLOUDS] [--username=USERNAME] """ """ THIS IS ALL WRONG AS PROVIDER DEPENDENT !!! if arguments.NAMES: variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names("status", arguments, variables) for cloud in clouds: provider = Provider(cloud) params = {} params['key'] = \ provider.p.spec["credentials"]['EC2_PRIVATE_KEY_FILE_PATH'] + \ provider.p.spec["credentials"]['EC2_PRIVATE_KEY_FILE_NAME'] params['username'] = arguments['--username'] # or get from db processors = arguments['--processors'] if processors: params['processors'] = int(processors[0]) # gets public ips from database public_ips = [] cursor = database.db['{cloud}-vm'] for name in names: for node in cursor.find({'name': name}): public_ips.append(node['public_ips']) public_ips = [y for x in public_ips for y in x] Host.check(hosts=public_ips, **params) """ elif arguments.status: if arguments.NAMES: variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names( "status", arguments, variables) # gets status from database for cloud in clouds: provider = Provider(cloud) status = [] cursor = database.db[f'{cloud}-vm'] print(cloud) for name in names: for node in cursor.find({'name': name}): status.append(node) provider.Print(status, output=arguments.output, kind="status") return "" elif arguments.start: # TODO: not tested if arguments.NAMES: names = variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names( "stop", arguments, variables) cloud = clouds[0] print(cloud) print(names) for name in names: provider = Provider(cloud) if arguments['--dryrun']: print(f"start node {name}") else: vms = provider.start(name=name, cloud=cloud) provider.Print(vms, output=arguments.output, kind="vm") return "" elif arguments.stop: # TODO: not tested if arguments.NAMES: variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names( "stop", arguments, variables) for cloud in clouds: params = {} provider = Provider(cloud) if arguments['--dryrun']: Console.ok(f"Dryrun stop: " f" {cloud}\n" f" {names}" f" {provider}") else: for name in names: vms = provider.stop(name) provider.Print(vms, output=arguments.output, kind="vm") elif arguments.terminate: # TODO: not tested if arguments.NAMES: variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names( "stop", arguments, variables) for cloud in clouds: params = {} provider = Provider(cloud) if arguments['--dryrun']: Console.ok(f"Dryrun terminate: " f" {cloud}\n" f" {names}" f" {provider}") else: for name in names: vms = provider.destroy(name) provider.Print(vms, output=arguments.output, kind="vm") elif arguments.delete: if arguments.NAMES: variables['vm'] = arguments.NAMES if arguments['--cloud']: variables['cloud'] = arguments['--cloud'] clouds, names = Arguments.get_cloud_and_names( "stop", arguments, variables) if names is not None: pass elif clouds is not None: for cloud in clouds: provider = Provider(cloud) vms = provider.list() for vm in vms: r = provider.destroy(name=vm) return "" else: return "" for cloud in clouds: provider = Provider(cloud) vms = provider.list() for vm in vms: name = vm["cm"]["name"] if name in names: r = provider.destroy(name=name) # TODO: username, secgroup elif arguments.boot: # not everything works """ vm boot [--name=VMNAMES] [--cloud=CLOUD] [--username=USERNAME] [--image=IMAGE] [--flavor=FLAVOR] [--network=NETWORK] [--public] [--secgroup=SECGROUP] [--key=KEY] [--group=GROUP] [--dryrun] """ # for name in names: # node = p.create(name=name, size=flavor, image=image) # VERBOSE(arguments) parameters = dotdict() names = Parameter.expand(arguments.name) cloud = Parameter.find("cloud", arguments, variables.dict()) defaults = Config()[f"cloudmesh.cloud.{cloud}.default"] groups = Parameter.find("group", arguments, variables.dict(), {"group": "default"}) parameters = dotdict() # parameters.names = arguments.name parameters.group = groups for attribute in [ "image", "username", "flavor", "key", "network", "secgroup" ]: parameters[attribute] = Parameter.find(attribute, arguments, variables.dict(), defaults) if arguments.username is None: parameters.user = Image.guess_username(parameters.image) provider = Provider(name=cloud) parameters.secgroup = arguments.secgroup or "default" # # determine names # if names and arguments.n and len(names) > 1: Console.error( f"When using --n={arguments.n}, you can only specify one name" ) return "" # cases # # only name --name = "a[1,2]" # name and count # --name="a" --n=3, names must be of length 1 # only count --n=2 names are read form var # nothing, just use one vm # determin names _names = [] if not names: if not arguments.n: count = 1 else: count = int(arguments.n) for i in range(0, count): if names is None: n = Name() n.incr() name = str(n) else: n = names[i] name = str(n) _names.append(name) names = _names elif len(names) == 1 and arguments.n: name = names[0] for i in range(0, int(arguments.n)): _names.append(f"{name}-{i}") names = _names # pprint(parameters) for name in names: parameters.name = name if arguments['--dryrun']: banner("boot") pprint(parameters) Console.ok(f"Dryrun boot {name}: \n" f" cloud={cloud}\n" f" names={names}\n" f" provider={provider}") print() for attribute in parameters: value = parameters[attribute] Console.ok(f" {attribute}={value}") else: # parameters.progress = len(parameters.names) < 2 try: vms = provider.create(**parameters) except TimeoutError: Console.error( f"Timeout during vm creation. There may be a problem with the cloud {cloud}" ) except Exception as e: Console.error("create problem", traceflag=True) print(e) return "" variables['vm'] = str(n) if arguments["-v"]: banner("Details") pprint(vms) # provider.Print(arguments.output, "vm", vms) elif arguments.info: """ vm info [--cloud=CLOUD] [--output=OUTPUT] """ print("info for the vm") cloud, names = Arguments.get_cloud_and_names( "info", arguments, variables) raise NotImplementedError elif arguments.rename: raise NotImplementedError # Not tested print("rename the vm") v = Variables() cloud = v["cloud"] p = Provider(cloud) try: oldnames = Parameter.expand(arguments["OLDNAMES"]) newnames = Parameter.expand(arguments["NEWNAMES"]) force = arguments["--force"] if oldnames is None or newnames is None: Console.error("Wrong VMs specified for rename", traceflag=False) elif len(oldnames) != len(newnames): Console.error("The number of VMs to be renamed is wrong", traceflag=False) else: print(oldnames) print(newnames) for i in range(0, len(oldnames)): oldname = oldnames[i] newname = newnames[i] if arguments["--dryrun"]: Console.ok("Rename {} to {}".format( oldname, newname)) else: print(f"rename {oldname} -> {newname}") p.rename(source=oldname, destination=newname) msg = "info. OK." Console.ok(msg) except Exception as e: Error.traceback(e) Console.error("Problem renaming instances", traceflag=True) elif arguments["ip"] and arguments["show"]: raise NotImplementedError print("show the ips") """ vm ip show [NAMES] [--group=GROUP] [--cloud=CLOUD] [--output=OUTPUT] [--refresh] """ elif arguments["ip"] and arguments["assign"]: raise NotImplementedError """ vm ip assign [NAMES] [--cloud=CLOUD] """ print("assign the public ip") elif arguments["ip"] and arguments["inventory"]: raise NotImplementedError """ vm ip inventory [NAMES] """ print("list ips that could be assigned") elif arguments.default: raise NotImplementedError print("sets defaults for the vm") elif arguments.script: raise NotImplementedError clouds, names = Arguments.get_cloud_and_names( "run", arguments, variables) username = arguments['--username'] script = arguments.SCRIPT for cloud in clouds: provider = Provider(cloud) name_ips = {} cursor = database.db['{}-node'.format(cloud)] for name in names: for node in cursor.find({'name': name}): name_ips[name] = node['public_ips'] if arguments['--dryrun']: print("run script {} on vms: {}".format(script, names)) else: provider.ssh(name_ips, username=username, script=script) elif arguments.username: raise NotImplementedError """ vm username USERNAME [NAMES] [--cloud=CLOUD] """ print("sets the username for the vm") elif arguments.resize: raise NotImplementedError """ vm resize [NAMES] [--size=SIZE] """ pass elif arguments.ssh: """ vm ssh [NAMES] [--username=USER] [--quiet] [--ip=IP] [--key=KEY] [--command=COMMAND] """ # VERBOSE(arguments) clouds, names, command = Arguments.get_commands( "ssh", arguments, variables) # print (clouds) # print(names) # print (command) if arguments.command is None and len(names) > 1: Console.error("Interactive shell can only be done on one vm") return "" elif arguments.command is None and len(names) == 1: name = names[0] cloud = clouds[0] cm = CmDatabase() try: vm = cm.find_name(name, "vm")[0] except IndexError: Console.error(f"could not find vm {name}") return "" # VERBOSE(vm) cloud = vm["cm"]["cloud"] provider = Provider(name=cloud) try: provider.ssh(vm=vm) except KeyError: vms = provider.list() provider.Print(vms, output=arguments.output, kind="vm") provider.ssh(vm=vm) return "" else: # command on all vms if clouds is None or names is None or command is None: return "" else: for cloud in clouds: p = Provider(cloud) for name in names: cm = CmDatabase() try: vm = cm.find_name(name, "vm")[0] except IndexError: Console.error(f"could not find vm {name}") continue r = p.ssh(vm=vm, command=command) print(r) return "" elif arguments.console: # why is this not vm clouds, names, command = Arguments.get_commands( "ssh", arguments, variables) print(clouds) print(names) print(command) for cloud in clouds: p = Provider(cloud) for name in names: cm = CmDatabase() try: vm = cm.find_name(name, "vm")[0] except IndexError: Console.error(f"could not find vm {name}") continue r = p.console(vm=vm) print(r) return "" elif arguments.log: # why is this not vm clouds, names, command = Arguments.get_commands( "ssh", arguments, variables) print(clouds) print(names) print(command) for cloud in clouds: p = Provider(cloud) for name in names: cm = CmDatabase() try: vm = cm.find_name(name, "vm")[0] except IndexError: Console.error(f"could not find vm {name}") continue r = p.log(vm=vm) print(r) return "" elif arguments.wait: """ vm wait [--cloud=CLOUD] [--interval=INTERVAL] [--timeout=TIMEOUT] """ # why is this not vm clouds, names, command = Arguments.get_commands( "ssh", arguments, variables) # print (clouds) # print (names) # print (command) for cloud in clouds: p = Provider(cloud) for name in names: cm = CmDatabase() try: vm = cm.find_name(name, "vm")[0] except IndexError: Console.error(f"could not find vm {name}") continue r = p.wait(vm=vm, interval=arguments.interval, timeout=arguments.timeout) if r: Console.ok("Instance available for SSH") else: Console.error( f"Instance unavailable after timeout of {arguments.timeout}" ) # print(r) return "" elif arguments.put: """ vm put SOURCE DESTINATION """ clouds, names, command = Arguments.get_commands( "ssh", arguments, variables) key = variables['key'] source = arguments['SOURCE'] destination = arguments['DESTINATION'] for cloud in clouds: p = Provider(name=cloud) cm = CmDatabase() for name in names: try: vms = cm.find_name(name, "vm") except IndexError: Console.error(f"could not find vm {name}") return "" # VERBOSE(vm) for vm in vms: try: ip = vm['public_ips'] except: try: ip = p.get_public_ip(name=name) except: Console.error( f"could not find a public ip for vm {name}", traceflag=True) return Console.error( f"could not find a public ip for vm {name}", traceflag=True) return # get the username try: # username not in vm...guessing imagename = list( cm.collection(cloud + '-image').find( {'ImageId': vm['ImageId']}))[0]['name'] print(imagename) user = Image.guess_username(image=imagename, cloud=cloud) except: try: user = vm['os_profile']['admin_username'] except: Console.error( f"could not find a valid username for " f"{name}, try refreshing the image list", traceflag=True) return Console.error( f"could not find a valid username for {name}, try refreshing the image list" ) return cmd = f'scp -i {key} {source} {user}@{ip}:{destination}' print(cmd) os.system(cmd) return ""
def do_volume(self, args, arguments): """ :: Usage: volume list [NAMES] [--vm=VM] [--region=REGION] [--cloud=CLOUD] [--refresh] [--dryrun] [--output=FORMAT] volume create [NAME] [--size=SIZE] [--volume_type=TYPE] [--description=DESCRIPTION] [--dryrun] [--region=REGION] [--path=PATH] volume attach [NAMES] [--vm=VM] volume detach [NAMES] volume delete [NAMES] volume add_tag [NAME] [--key=KEY] [--value=VALUE] volume status [NAME] volume migrate [NAME] [--vm=VM] [--cloud=CLOUD] volume sync [NAMES] [--cloud=CLOUD] volume purge [--cloud=CLOUD] This command manages volumes across different clouds Arguments: NAME the name of the volume NAMES the names of multiple volumes Options: --vm=VM The name of the virtual machine --region=REGION The name of the region --cloud=CLOUD The name of the cloud --refresh If refresh the info is taken from the cloud --volume_type=TYPE The type of the volume --output=FORMAT Output format [default: table] --key=KEY The tag key --value=VALUE The value of tag key --snapshot The snapshot of volume --path=PATH The path of local volume Description: volume list [NAMES] [--vm=VM] [--region=REGION] [--cloud=CLOUD] [--refresh] [--dryrun] [--output=FORMAT] List all the volumes for certain vm, region, or cloud. volume create [NAME] [--size=SIZE] [--volume_type=TYPE] [--description=DESCRIPTION] [--dryrun] [--snapshot=SNAPSHOT] [--region=REGION] Creates a volume volume status [NAMES] [--cloud=CLOUD] Get the status (e.g. 'available', 'READY', 'in-use') of a volume volume attach [NAMES] [--vm=VM] Attach volume to a vm volume detach [NAMES] Detach volume from a vm volume delete [NAMES] Delete the named volumes volume migrate [NAME] [--vm=VM] [--cloud=CLOUD] Migrate volume from one vm to another vm in the same provider. volume sync [NAMES] [--cloud=CLOUD] Volume sync allows for data to be shared between two volumes. volume purge [--cloud=CLOUD] Volume purge delete all the "deleted" volumes in MongoDB database """ VERBOSE(arguments) variables = Variables() def get_last_volume(): """ get the last volume name :return: string """ config = Config() n = VolumeName(user=config["cloudmesh.profile.user"], kind="volume", path=f"{config.location}/volume.yaml", schema="{user}-volume-{counter}") last_volume_name = n return str(last_volume_name) def create_name(): """ Create volume name if name is not specified :return: string """ config = Config() n = VolumeName(user=config["cloudmesh.profile.user"], kind="volume", path=f"{config.location}/volume.yaml", schema="{user}-volume-{counter}") n.incr() return n map_parameters(arguments, "cloud", "vm", "region", "refresh", "dryrun", "output", "size", "volume_type", "description", "key", "value", "snapshot", "path") arguments.output = Parameter.find( "output", arguments, variables, ) cloud = variables['cloud'] if arguments.list: if arguments.NAMES: names = Parameter.expand(arguments["NAMES"]) if arguments.cloud: # "cms volume list NAMES --cloud=aws1" provider = Provider(name=arguments.cloud) result = provider.list(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) else: # if "cms volume list NAMES" config = Config() clouds = list(config["cloudmesh.volume"].keys()) for cloud in clouds: if len(names) != 0: banner(f"listing volume info from {cloud}") else: banner("End of listing Volumes") break active = config[f"cloudmesh.volume.{cloud}.cm.active"] if active: provider = Provider(name=cloud) listed = [] for name in names: volume = provider.search(name=name) if volume: arguments.NAME = name result = provider.list(**arguments) print( provider.Print( result, kind='volume', output=arguments.output)) listed.append(name) if len(listed) > 0: # delete all listed volumes in names for name in listed: names.remove(name) else: if arguments.cloud: # "cms volume list --cloud=aws1" provider = Provider(name=arguments.cloud) result = provider.list(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) else: # "cms volume list" arguments['cloud'] = cloud provider = Provider(name=arguments.cloud) result = provider.list(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) return "" elif arguments.create: if arguments.cloud is None: arguments['cloud'] = cloud if arguments.NAME is None: arguments.NAME = str(create_name()) provider = Provider(name=arguments.cloud) result = provider.create(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) elif arguments.delete: names = arguments.NAMES or variables["volume"] names = Parameter.expand(names) if names is None: Console.error("No volume specified or found") return "" config = Config() clouds = list(config["cloudmesh.volume"].keys()) for cloud in clouds: # if len(names) != 0: # banner(f"Deleting volumes from {cloud}") # else: # banner("End of Deleting Volumes") active = config[f"cloudmesh.volume.{cloud}.cm.active"] if active: provider = Provider(name=cloud) deleted = [] for name in names: volume = provider.search(name=name) if volume: result = provider.delete(name=name) deleted.append(name) if len(deleted) > 0: # delete all deleted volumes in names for name in deleted: names.remove(name) elif arguments.attach: arguments.cloud = arguments.cloud or cloud names = arguments.NAMES or variables["volume"] vm = arguments.vm or variables["vm"] if names is None: Console.error("No Volume specified or found") return "" if vm is None: Console.error("No vm specified or found") return "" names = Parameter.expand(names) # banner(f"Attaching {names} to {arguments.vm}") provider = Provider(name=arguments.cloud) result = provider.attach(names, vm) print( provider.Print(result, kind='volume', output=arguments.output)) elif arguments.detach: config = Config() clouds = list(config["cloudmesh.volume"].keys()) volumes = arguments.NAMES or variables["volume"] if volumes is None: Console.error("No volume specified or found") return "" volumes = Parameter.expand(volumes) for cloud in clouds: # if len(volumes) != 0: # banner(f"Detaching volumes from {cloud}") # else: # banner("End of Detaching Volumes") # break active = config[f"cloudmesh.volume.{cloud}.cm.active"] if active: detached = [] provider = Provider(name=cloud) for name in volumes: # returns volume name if found in the cloud, # None if it is not in the cloud volume = provider.search(name=name) if volume: # banner(f"Detaching {name} from {cloud}") result = provider.detach(name=name) detached.append(name) print( provider.Print(result, kind='volume', output=arguments.output)) if len(detached) > 0: # delete all detached volumes in volumes for name in detached: volumes.remove(name) elif arguments.add_tag: arguments.cloud = arguments.cloud or cloud name = arguments.NAME or variables["volume"] or get_last_volume() arguments.NAME = name provider = Provider(name=arguments.cloud) result = provider.add_tag(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) elif arguments.status: arguments.cloud = arguments.cloud or cloud name = arguments.NAME or variables["volume"] or get_last_volume() arguments.NAME = name provider = Provider(name=arguments.cloud) result = provider.status(name=name) print( provider.Print(result, kind='volume', output=arguments.output)) elif arguments.migrate: if arguments.cloud: # "cms volume migrate NAME --vm=VM --cloud=aws1" # if no given volume, get the current volume # or get the last volume, name = arguments.NAME or variables[ "volume"] or get_last_volume() arguments.NAME = name provider = Provider(name=arguments.cloud) result = provider.migrate(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) else: raise NotImplementedError elif arguments.sync: # "cms volume sync NAMES --cloud=CLOUD" # when len(NAMES)==2, sync volume (NAMES[0]) with volume (NAMES[1]) # when len(NAMES)==1, sync current volume with volume(NAMES[0]) # what it actually does is copy second volume and overwrite # the other (current volume or first volume in NAMES) if len([arguments.NAMES]) == 1: volumes = [ variables["volume"] or get_last_volume(), arguments.NAMES ] arguments.NAMES = volumes elif len([arguments.NAMES]) == 2: volumes = arguments.NAMES else: Console.error("Two volumes should be specified") # if arguments.cloud: arguments.cloud = cloud provider = Provider(name=arguments.cloud) result = provider.sync(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) # else: # raise NotImplementedError elif arguments.purge: arguments.cloud = arguments.cloud or cloud provider = Provider(name=arguments.cloud) provider.purge(**arguments) result = provider.list() print( provider.Print(result, kind='volume', output=arguments.output))
def do_check(self, args, arguments): """ :: Usage: check [KEYWORDS...] [--output=OUTPUT] Options: --output=OUTPUT the output format [default: table] Description: checks if some programs are available to cms in the system. This includes mongodb ssh These can also be passed as optional keywords """ map_parameters(arguments, "output") variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") keywords = arguments.KEYWORDS or ['mongo', "mongod", "mongoimport"] def check_ssh(): cmd = "ssh " \ "-o StrictHostKeyChecking=no " \ "-o UserKnownHostsFile=/dev/null " \ f"-v localhost date" r = Shell.run(cmd) return "Connection refused" not in r def get_info(shell_command): v = "unkown" path = Shell.which(shell_command) if shell_command == "ssh": v = Shell.run(f"{shell_command} -V") elif path and len(path) > 0: try: v = Shell.run(f"{shell_command} --version") if shell_command.endswith("mongo"): v = v.splitlines()[0].replace("MongoDB shell version ", "") elif shell_command.endswith("mongod"): v = v.splitlines()[0].replace("db version ", "") elif shell_command.endswith("mongoimport"): v = v.splitlines()[0].replace("mongoimport version: ", "") except: v = "unkown" return path, v config = Config() try: machine = sys.platform mongo_path = config[ f"cloudmesh.data.mongo.MONGO_DOWNLOAD.{machine}.MONGO_HOME"] except: mongo_path = None data = {} for keyword in keywords: # # probe system mongo # path, version_string = get_info(keyword) entry = { 'system': { 'name': keyword, 'path': path, 'version': version_string } } data[keyword] = entry # # probe cloudmesh mongo # if "mongo" in ['mongo', 'mongod', 'mongoimport']: if mongo_path: path = str(Path(path_expand(mongo_path)) / "bin" / keyword) p, v = get_info(path) try: entry = { 'cloudmesh': { 'name': keyword, 'path': path, 'version': v } } except: Console.error(f"{keyword}") data[keyword].update(entry) path, v = get_info('ssh') data['ssh'] = { 'system': { 'name': 'ssh', 'path': path, 'version': v.strip(), 'enabled': check_ssh() } } # # probe ssh commands # for c in ["ssh-keygen", "ssh-add", "ssh-agent"]: data[c] = { 'system': { 'name': c, 'path': Shell.which(c), } } if len(data) > 0: banner("ssh, mongo, mongod, mongoimport") print(json.dumps(data, indent=2)) banner("os.environ") for attribute in os.environ: print(attribute, os.environ[attribute]) banner("Shell.run") for c in ["echo $0", "echo $SHELL"]: try: r = Shell.run(c).strip() except: r = 'error' print(f"Shell.run('{c}')", r) return ""
def do_flavor(self, args, arguments): """ :: Usage: flavor list [NAMES] [--cloud=CLOUD] [--refresh] [--output=OUTPUT] Options: --output=OUTPUT the output format [default: table] --cloud=CLOUD the ycloud name --refresh refreshes the data before displaying it Description: This lists out the flavors present for a cloud Examples: cm flavor list --refresh cm flavor list cm flavor list --output=csv cm flavor list 58c9552c-8d93-42c0-9dea-5f48d90a3188 --refresh please remember that a uuid or the flavor name can be used to identify a flavor. """ map_parameters(arguments, "refresh", "cloud", "output") variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") arguments.refresh = Parameter.find_bool("refresh", arguments, variables) if arguments.list and arguments.refresh: names = [] clouds, names = Arguments.get_cloud_and_names("list", arguments, variables) for cloud in clouds: print(f"cloud {cloud}") provider = Provider(name=cloud) flavors = provider.flavors() provider.Print(flavors, output=arguments.output, kind="flavor") return "" elif arguments.list: names = [] clouds, names = Arguments.get_cloud_and_names("list", arguments, variables) print(clouds, names) try: for cloud in clouds: print(f"List {cloud}") provider = Provider(cloud) db = CmDatabase() flavors = db.find(collection=f"{cloud}-flavor") provider.Print(flavors, output=arguments.output, kind="flavor") except Exception as e: VERBOSE(e) return ""
def do_ssh(self, args, arguments): """ :: Usage: ssh config list [--output=OUTPUT] ssh config add NAME IP [USER] [KEY] ssh config delete NAME Arguments: NAME Name or ip of the machine to log in list Lists the machines that are registered and the commands to login to them PARAMETERS Register te resource and add the given parameters to the ssh config file. if the resource exists, it will be overwritten. The information will be written in /.ssh/config USER The username for the ssh resource KEY The location of the public keye used for authentication to the host Options: --output=OUTPUT the format in which this list is given formats includes cat, table, json, yaml, dict. If cat is used, it is just printed as is. [default: table] Description: ssh config list lists the hostsnames that are present in the ~/.ssh/config file ssh config add NAME IP [USER] [KEY] registers a host i ~/.ssh/config file Parameters are attribute=value pairs ssh config delete NAME deletes the named host from the ssh config file Examples: ssh config add blue 192.168.1.245 gregor Adds the following to the !/.ssh/config file Host blue HostName 192.168.1.245 User gergor IdentityFile ~/.ssh/id_rsa.pub """ map_parameters(arguments, "output") if arguments.config and arguments.list: # ssh config list [--output=OUTPUT]" hosts = dict(ssh_config().hosts) # Make keywords uniform for host in hosts: if "HostName" in hosts[host]: hosts[host]["Hostname"] = hosts[host]["HostName"] del hosts[host]["HostName"] if "Identityfile" in hosts[host]: hosts[host]["IdentityFile"] = hosts[host]["Identityfile"] del hosts[host]["Identityfile"] print(Printer.write(hosts, order=['host', 'Hostname', 'User', 'IdentityFile'])) elif arguments.config and arguments.add: # ssh config add NAME IP [USER] [KEY] variables = Variables() user = Parameter.find("user", arguments, variables.dict()) key = Parameter.find("key", arguments, variables.dict(), {"key": "~/.ssh/id_rsa.pub"}) name = arguments.NAME or variables['vm'] ip = arguments.IP hosts = ssh_config() if name in hosts.hosts: Console.error("Host already in ~/.ssh/config") return "" hosts.generate(host=name, hostname=ip, identity=key, user=user) elif arguments.config and arguments.add: # ssh host add NAME location = path_expand("~/.ssh/known_hosts") name = arguments.NAME os.system("ssh-keygen -R {name}") os.system(f"ssh-keyscan -H {name} >> {location}") elif arguments.config and arguments.delete: # ssh host delete NAME name = arguments.NAME try: os.system("ssh-keygen -R {name}") except: pass ssh_config.delete(name)
def do_flavor(self, args, arguments): """ :: Usage: flavor list [NAMES] [--cloud=CLOUD] [--refresh] [--output=OUTPUT] [--query=QUERY] Options: --output=OUTPUT the output format [default: table] --cloud=CLOUD the ycloud name --refresh refreshes the data before displaying it Description: This lists out the flavors present for a cloud Examples: cm flavor list --refresh cm flavor list cm flavor list --output=csv cm flavor list 58c9552c-8d93-42c0-9dea-5f48d90a3188 --refresh please remember that a uuid or the flavor name can be used to identify a flavor. cms flavor list --refresh --query=\'{\"a\": \"b\"}\' OpenStack Query Example: cms flavor list --refresh --query=\'{\"minDisk\": \"80\"}\' cms flavor list --refresh --query=\'{\"name\": \"m1.large\"}\' supported query parameters for OpenStack: min_disk min_ram name """ map_parameters(arguments, "query", "refresh", "cloud", "output") variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") arguments.refresh = Parameter.find_bool("refresh", arguments, variables) if arguments.list and arguments.refresh: names = [] clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) for cloud in clouds: print(f"cloud {cloud} query={arguments.query}") provider = Provider(name=cloud) if arguments.query is not None: query = eval(arguments.query) flavors = provider.flavors(**query) else: flavors = provider.flavors() provider.Print(flavors, output=arguments.output, kind="flavor") return "" elif arguments.list: names = [] clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) try: for cloud in clouds: if arguments.output in ["table"]: print(f"List {cloud}") provider = Provider(name=cloud) db = CmDatabase() flavors = db.find(collection=f"{cloud}-flavor") provider.Print(flavors, output=arguments.output, kind="flavor") except Exception as e: VERBOSE(e) return ""
def do_volume(self, args, arguments): """ :: Usage: volume register which volume register [NAME] [--cloud=CLOUD] [ARGUMENTS...] volume list [NAMES] [--vm=VM] [--region=REGION] [--cloud=CLOUD] [--refresh] [--dryrun] [--output=FORMAT] volume create [NAME] [--size=SIZE] [--volume_type=TYPE] [--description=DESCRIPTION] [--dryrun] [ARGUMENTS...] volume status [NAMES] [--cloud=CLOUD] volume attach [NAMES] [--vm=VM] volume detach [NAMES] volume delete NAMES volume migrate NAME FROM_VM TO_VM volume sync FROM_VOLUME TO_VOLUME This command manages volumes accross different clouds Arguments: NAME the name of the volume vm the name of the vm Options: --vm=VMNAME The name of the virtual machine --region=REGION The name of the region --cloud=CLOUD The name of the cloud --refresh If refresh the information is taken from the cloud --volume_type=TYPE The type of the volume --output=FORMAT Output format [default: table] Description: TBD """ VERBOSE(arguments) variables = Variables() def get_last_volume(): cm = CmDatabase() cloud = arguments['--cloud'] or variables["cloud"] #how to get updated cloud names? or only search the last volume in --cloud? last_entry = cm.find(cloud=cloud, kind='volume')[-1] cm.close_client() for tag in last_entry['Tags']: if tag['key'] == 'Name': name = tag['Value'] else: raise ("Please name the volume!") return name def create_name(): """ Gregor suggests to use from cloudmesh.management.configuration.Name import Name as VolumeName config = Config() n = VolumeName( user=config["cloudmesh.profile.username"], kind="volume", path=f"{config.location}/volume.yaml", schema="{user}-volume-{counter}" counter=1) n.incr() counter = n.get() :return: """ # please edit ~ /.cloudmesh / volume.yaml as following: # counter: 1 # kind: volume config = Config() directory = f"{config.location}" volume_yaml = path_expand(f"{directory}/volume.yaml") try: with open(volume_yaml) as file: dic = yaml.load(file, Loader=yaml.FullLoader) counter = dic["counter"] user = dic["user"] created_name = f"{user}-{cloud}-{counter}" dic["counter"] += 1 with open(volume_yaml, 'w') as file: documents = yaml.dump(dic, file) except: Console.error("the volume.yaml file does not exist." "You need to implement " "the case so it gets autogenerated") raise NotImplementedError return created_name map_parameters( arguments, "cloud", "vm", "region", "refresh", "dryrun", "output", "size", "volume_type", "description", ) arguments.output = Parameter.find( "output", arguments, variables, ) arguments.NAME = arguments.NAME or variables[ "volume"] #or get_last_volume() #path = arguments.PATH cloud = variables['cloud'] if arguments.list: if arguments.NAMES: raise NotImplementedError names = Parameter.expand(arguments.NAMES) for name in names: # kind = cm.kind provider = Provider(name=name) # result = provider.list(???) result = provider.list() elif arguments.cloud: # banner(f'get in arguments.cloud {arguments.cloud}') #print (arguments.cloud) provider = Provider(name=arguments.cloud) result = provider.list(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) #from pprint import pprint #pprint (result) return "" elif arguments.create: #parameters = Parameter.arguments_to_dict(arguments.ARGUMENTS) #print("parameters",parameters) if arguments.cloud == None: arguments['cloud'] = cloud #cloud from variable['volume'] if arguments.NAME == None: arguments.NAME = str(create_name()) provider = Provider(name=arguments.cloud) result = provider.create(**arguments) print( provider.Print(result, kind='volume', output=arguments.output)) elif arguments.delete: names = Parameter.expand(arguments["NAMES"]) config = Config() clouds = list(config["cloudmesh.volume"].keys()) for cloud in clouds: active = config[f"cloudmesh.volume.{cloud}.cm.active"] if active: p = Provider(name=cloud) deleted = [] for name in names: result = p.delete( name) # returns None if it is not in the cloud if result: deleted.append(name) if len(deleted) > 0: for name in deleted: del names[name] """ 2 spaces not fout ! cloudmesh: volume: aws1: cm: active: cloudmesh.cloud.aws.cm.active names = Parametrs.expnad(arguments.NAMES) config = Config() clouds = list(config["cloudmesh.volume"].keys()) for cloud in clouds : active = config[f"cloudmesh.volume.{cloud}.cm.active"] if active: found = [] # from cloudmesh.volume.Provider import Provider p = Provider(name=cloud) for name in names: volume = p.list(name=name) found = found.append(name) p.destroy(','.join(found) # delete all found volumes in the cloud """ elif arguments.attach: # cloud from variable['volume'] arguments.cloud = arguments.cloud or cloud names = arguments.NAMES or variables["volume"] vm = arguments.vm or variables["vm"] if names is None: Console.error("No Volume specified or found") return "" if vm is None: Console.error("No vm specified or found") return "" names = Parameter.expand(names) banner(f"Attach {arguments.NAMES} to {arguments.vm}") provider = Provider(name=arguments.cloud) for name in names: result = provider.attach(name, vm) print( provider.Print(result, kind='volume', output=arguments.output)) elif arguments.detach: # # this has a bug as the general provider needs a serach that finds # the vm given a volume name to find the vm it is attached to # this way you can write just a loop such as # # for volume in volumes: # v = provider.serach(volume) # if v['vm'] and v['cm.cloud'] == v['cm.cloud']: # result = provider.detach(name) # # or something similar dependent on how you defined the datastructure # cm. for a volume # volumes = arguments.NAMES or variables["volume"] if volumes is None: Console.error("No volumes specified or found") return "" volumes = Parameter.expand(volumes) banner(f"Detach {volumes}") for name in volumes: volume = Provider.search(name=name) cloud = volume["cm"]["cloud"] provider = Provider(name=cloud) result = provider.detach(name=name) print( provider.Print(result, kind='volume', output=arguments.output))
def do_image(self, args, arguments): """ :: Usage: image list [NAMES] [--cloud=CLOUD] [--refresh] [--output=OUTPUT] [--query=QUERY] Options: --output=OUTPUT the output format [default: table] --cloud=CLOUD the cloud name --refresh live data taken from the cloud Description: image list image list --cloud=aws --refresh image list --output=csv image list 58c9552c-8d93-42c0-9dea-5f48d90a3188 --refresh """ map_parameters(arguments, "query", "refresh", "cloud", "output") variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") arguments.refresh = Parameter.find_bool("refresh", arguments, variables) if arguments.list and arguments["--query"]: names = [] clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) for cloud in clouds: print(f"cloud {cloud} query={arguments.query}") provider = Provider(name=cloud) if arguments.query is not None: query = eval(arguments.query) images = provider.images(**query) else: images = provider.images() provider.Print(images, output=arguments.output, kind="image") return "" if arguments.list and arguments.refresh: names = [] clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) for cloud in clouds: print(f"cloud {cloud}") provider = Provider(name=cloud) images = provider.images() provider.Print(images, output=arguments.output, kind="image") return "" elif arguments.list: clouds, names = Arguments.get_cloud_and_names( "list", arguments, variables) print(clouds) print("find images") try: for cloud in clouds: print(f"List {cloud} images") provider = Provider(name=cloud) db = CmDatabase() images = db.find(collection=f"{cloud}-image") provider.Print(images, output=arguments.output, kind="image") except Exception as e: VERBOSE(e) return ""
def do_multipass(self, args, arguments): """ :: Usage: multipass list [--output=OUTPUT] [--dryrun] multipass images [--output=OUTPUT] [--dryrun] multipass start NAMES [--output=OUTPUT] [--dryrun] multipass stop NAMES [--output=OUTPUT] [--dryrun] multipass reboot NAMES [--output=OUTPUT] [--dryrun] multipass delete NAMES [--output=OUTPUT][--dryrun] multipass destroy NAMES [--output=OUTPUT][--dryrun] multipass shell NAMES [--dryrun] multipass run COMMAND NAMES [--output=OUTPUT] [--dryrun] multipass info NAMES [--output=OUTPUT] [--dryrun] multipass suspend NAMES [--output=OUTPUT] [--dryrun] multipass resume NAMES [--output=OUTPUT] [--dryrun] multipass destroy NAMES [--dryrun] multipass create NAMES [--image=IMAGE] [--size=SIZE] [--mem=MEMORY] [--cpus=CPUS] [--cloud-init=CLOUDINIT] [--dryrun] multipass reboot NAMES [--dryrun] multipass mount SOURCE DESTINATION [--dryrun] multipass umount SOURCE [--dryrun] multipass transfer SOURCE DESTINATION [--dryrun] multipass set key=VALUE [--dryrun] multipass get [key] [--dryrun] Interface to multipass Options: --output=OUTPUT the output format [default: table]. Other values are yaml, csv and json. --image=IMAGE the image name to be used to create a VM. Arguments: NAMES the names of the virtual machine Description: The NAMES can be a parameterized hostname such as red[0-1,5] = red0,red1,red5 Commands: First you can see the supported multipass images with cms multipass images Create and launch a new vm using cms multipass create NAMES Optionally you can provide image name, size, memory, # of cpus to create an instance. Start one or multiple multipass vms with cms multipass start NAMES Stop one or multiple vms with cms multipass stop NAMES Gets all multipass internal key values with cms multipass get Gets a specific internal key. cms multipass get KEY Known keys client.gui.autostart client.primary-name local.driver are there more? Reboot (stop and then start) vms with cms multipass reboot NAMES Delete one of multiple vms without purging with cms multipass delete NAMES Destory multipass vms (delete and purge) with cms multipass destroy NAMES Caution: Once destroyed everything in vm will be deleted and cannot be recovered. WHEN YOU IMPLEMENT A FUNCTION INCLUDE MINIMAL DOCUMENTATION HERE """ name = arguments.NAME map_parameters(arguments, "dryrun", "refresh", "cloud", "image", "size", "mem", "cpus", "output") # so we can use arguments.cloudinit arguments["cloudinit"] = arguments["--cloud-init"] image = arguments.image variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") names = Parameter.expand(arguments.NAMES) VERBOSE(arguments) if arguments.list: if arguments.dryrun: banner("dryrun list") else: provider = Provider() provider.list() return "" elif arguments.images: if arguments.dryrun: banner("dryrun images") else: provider = Provider() images = provider.images() print( provider.Print(images, kind='image', output=arguments.output)) return "" elif arguments.run: if arguments.dryrun: banner("dryrun run") for name in names: if arguments.dryrun: Console.ok(f"run {name} {arguments.COMMAND}") else: provider = Provider() provider.run(name, arguments.COMMAND) return "" elif arguments.create: result = "" if arguments.dryrun: banner("create") for name in names: if arguments.dryrun: Console.ok(f"dryrun create {name} {image}") else: provider = Provider() result = provider.create(name, image) VERBOSE(result) return result elif arguments.start: result = "" if arguments.dryrun: banner("start") for name in names: if arguments.dryrun: Console.ok(f"dryrun start {name}") else: provider = Provider() result = provider.start(name) VERBOSE(result) return result elif arguments.stop: result = "" if arguments.dryrun: banner("stop") for name in names: if arguments.dryrun: Console.ok(f"dryrun stop {name}") else: provider = Provider(name=name) result = provider.stop(name) VERBOSE(result) return result elif arguments.delete: result = "" if arguments.dryrun: banner("delete") for name in names: if arguments.dryrun: Console.ok(f"dryrun delete {name}") else: provider = Provider() # Default purge is false. Is this ok? result = provider.delete(name) VERBOSE(result) return result elif arguments.info: result = "" if arguments.dryrun: banner(f"info {name}") for name in names: if arguments.dryrun: Console.ok(f"dryrun info {name}") else: provider = Provider() # Default purge is false. Is this ok? result = provider.info(name) VERBOSE(result) return result elif arguments.suspend: result = "" if arguments.dryrun: banner("suspend") for name in names: if arguments.dryrun: Console.ok(f"dryrun suspend {name}") else: provider = Provider() result = provider.suspend(name) VERBOSE(result) return result elif arguments.resume: result = "" if arguments.dryrun: banner("resume") for name in names: if arguments.dryrun: Console.ok(f"dryrun resume {name}") else: provider = Provider() result = provider.resume(name) VERBOSE(result) return result elif arguments.destroy: result = "" if arguments.dryrun: banner("destroy") for name in names: if arguments.dryrun: Console.ok(f"dryrun destroy {name}") else: provider = Provider() result = provider.destroy(name) VERBOSE(result) return result elif arguments.reboot: result = "" if arguments.dryrun: banner("reboot") for name in names: if arguments.dryrun: Console.ok(f"dryrun reboot {name}") else: provider = Provider() result = provider.reboot(name) VERBOSE(result) return result elif arguments.shell: if len(names) > 1: Console.error("shell must only have one host") return "" name = names[0] if arguments.dryrun: banner("dryrun shell {name}") else: provider = Provider() provider.shell() return "" elif arguments.info: if arguments.dryrun: banner("dryrun info") else: provider = Provider() info = provider.info() print( provider.Print(info, kind='info', output=arguments.output)) return "" elif arguments.mount: if arguments.dryrun: banner( f"dryrun mount {arguments.SOURCE} {arguments.DESTINATION}") else: provider = Provider() provider.mount(arguments.SOURCE, arguments.DESTINATION) # list the mounts and display as table return "" else: Console.error("Not yet implemented") return ""
def do_iu(self, args, arguments): """ :: Usage: iu [--user=USERNAME] [--host=HOST] [--node=NUMBER] [--gpu=GPUS] [--res=RESERVATION] iu status iu res iu setup --user=USERNAME This command allows you to inteactively log into roeo or volta Arguments: FILE a file name HOST the host is either rome or volta [default: romeo] NUMBER is a number that specifies where to login GPUS the number of GPU's to be used Options: --res=RESERVATION [default: lijguo_11] Example: cms iu logs in on the first available node, and uses 1 GPU BUG: some reservation are not detected cms iu --node=random logs in on the first available node and uses 1 GPU cms iu status lists the status of rome and volta. The output will look like: +-------------+-----------+ | romeo | Used GPUs | +-------------+-----------+ | r-001 | | | r-002 | 7 | | r-003 | 7 | | r-004 | 7 | +-------------+-----------+ +-------+-----------+ | volta | Used GPUs | +-------+-----------+ | r-005 | 5 | | r-006 | 7 | +-------+-----------+ Users on romeo user1 Users on volta user2 """ VERBOSE(arguments) map_parameters(arguments, "user", "host", "node", "gpu") variables = Variables() #arguments["user"] = Parameter.find("user", arguments, variables) # if arguments.user is None: # config = Config() # arguments.user = config["cloudmesh.iu.user"] iu = Manager(user=arguments.user) if arguments.setup: iu.setup(user=arguments.user) return "" if arguments.status: iu.status(user=arguments.user) return "" elif arguments.res: iu.reservations(user=arguments.user) return "" else: arguments["host"] = Parameter.find("host", arguments, variables, {"host": "romeo"}) arguments["node"] = Parameter.find("node", arguments, variables) arguments["gpu"] = int(Parameter.find("gpu", arguments, variables, {"gpu": "1"})) # VERBOSE(arguments) banner(f"Login {arguments.host}") #iu.login(user=arguments.user, # host=arguments.host, # node=arguments.node, # gpus=arguments.gpu) iu.smart_login(user=arguments.user, host=arguments.host, node=arguments.node, gpus=arguments.gpu) return ""
def do_ip(self, args, arguments): """ :: Usage: ip list [--cloud=CLOUD] [--output=OUTPUT] ip create [N] [--cloud=CLOUD] ip delete [IP] [--cloud=CLOUD] ip attach [NAME] [IP] ip detach [NAME] [IP] Options: -h help message --cloud=CLOUD Name of the cloud --output=OUTPUT The output format [default: table] Arguments: N Number of IPS to create IP IP Address NAME Name of the service Description: ip list floating [--cloud=CLOUD] [--output=OUTPUT] returns a list of all the floating IPS in the cloud ip add floating [--cloud=CLOUD] adds a floating ip to the pool of available floating ips ip delete floating [IP] [--cloud=CLOUD] deletes a floating ip to the pool of available floating ips ip add NAME [IP] add the ip to the named vm ip delete NAME [IP] deletes the ip from the vm """ def get_ip(ip): if ip is None: # find a free one try: ip = provider.find_available_public_ip() return ip except Exception as e: Console.error("No free floating ip found") return "" map_parameters(arguments, "cloud", "output") arguments.vm = arguments.NAME variables = Variables() if arguments.list: cloud = Parameter.find("cloud", arguments, variables) print(f"cloud {cloud}") provider = Provider(name=cloud) ips = provider.list_public_ips() provider.Print(ips, output=arguments.output, kind="ip") elif arguments.create: cloud = Parameter.find("cloud", arguments, variables) n = arguments.N or 1 print(f"cloud {cloud}") provider = Provider(name=cloud) for i in range(0, int(n)): ips = provider.create_public_ip() ips = provider.list_public_ips() provider.Print(ips, output=arguments.output, kind="ip") elif arguments.delete: cloud = Parameter.find("cloud", arguments, variables) print(f"cloud {cloud}") provider = Provider(name=cloud) ip = arguments.IP ip = get_ip(arguments.IP) ips = provider.delete_public_ip(ip) ips = provider.list_public_ips() provider.Print(ips, output=arguments.output, kind="ip") elif arguments.attach: name = Parameter.find("vm", arguments, variables) cm = CmDatabase() vm = cm.find_name(name, kind="vm")[0] cloud = vm["cm"]["cloud"] print(f"cloud {cloud}") provider = Provider(name=cloud) ip = get_ip(arguments.IP) try: ips = provider.attach_public_ip(name=name, ip=ip) except Exception as e: print(e) Console.error("Could not assign public ip.") elif arguments.detach: name = Parameter.find("vm", arguments, variables) cm = CmDatabase() vm = cm.find_name(name, kind="vm")[0] cloud = vm["cm"]["cloud"] print(f"cloud {cloud}") provider = Provider(name=cloud) ip = provider.get_public_ip(name=name) print(name, ip) try: ips = provider.detach_public_ip(name=name, ip=ip) except Exception as e: print(e) Console.error("can not detach ip")
def do_ssh(self, args, arguments): """ :: Usage: ssh ssh config list [--output=OUTPUT] ssh config add NAME IP [USER] [KEY] ssh config delete NAME ssh host delete NAME ssh host add NAME ssh [--name=VMs] [--user=USERs] [COMMAND] Arguments: NAME Name or ip of the machine to log in list Lists the machines that are registered and the commands to login to them PARAMETERS Register te resource and add the given parameters to the ssh config file. if the resource exists, it will be overwritten. The information will be written in /.ssh/config Options: -v verbose mode --output=OUTPUT the format in which this list is given formats includes cat, table, json, yaml, dict. If cat is used, it is just printed as is. [default: table] --user=USERs overwrites the username that is specified in ~/.ssh/config --name=CMs the names of the VMS to execute the command on Description: ssh config list lists the hostsnames that are present in the ~/.ssh/config file ssh config add NAME IP [USER] [KEY] registers a host i ~/.ssh/config file Parameters are attribute=value pairs Note: Note yet implemented ssh [--name=VMs] [--user=USERs] [COMMAND] executes the command on the named hosts. If user is specified and is greater than 1, it must be specified for each vm. If only one username is specified it is used for all vms. However, as the user is typically specified in the cloudmesh database, you probably do not have to specify it as it is automatically found. Examples: ssh config add blue 192.168.1.245 blue Adds the following to the !/.ssh/config file Host blue HostName 192.168.1.245 User blue IdentityFile ~/.ssh/id_rsa.pub """ map_parameters(arguments, "name", "user", "output") if arguments.config and arguments.list: # ssh config list [--output=OUTPUT]" hosts = dict(ssh_config().hosts) print( Printer.dict_table( hosts, order=['host', 'HostName', 'User', 'IdentityFile'])) elif arguments.config and arguments.add: # ssh config add NAME IP [USER] [KEY] variables = Variables() user = Parameter.find("user", arguments, variables.dict()) key = Parameter.find("key", arguments, variables.dict(), {"key": "~/.ssh/id_rsa.pub"}) name = arguments.NAME or variables['vm'] ip = arguments.IP hosts = ssh_config() if name in hosts.hosts: Console.error("Host already in ~/.ssh/config") return "" hosts.generate(host=name, hostname=ip, identity=key, user=user) elif arguments.config and arguments.delete: # ssh config delete NAME raise NotImplementedError elif arguments.config and arguments.add: # ssh host add NAME location = path_expand("~/.ssh/known_hosts") name = arguments.NAME os.system("ssh-keygen -R {name}") os.system(f"ssh-keyscan -H {name} >> {location}") elif arguments.config and arguments.delete: # ssh host delete NAME name = arguments.NAME os.system("ssh-keygen -R {name}") elif (arguments.name and arguments.COMMAND) or arguments.COMMAND: # ssh [--name=VMs] [--user=USERs] [COMMAND]" variables = Variables() if arguments.name is None: name = arguments.NAME or variables['vm'] names = [name] else: names = Parameter.expand(arguments.name) users = Parameter.expand(arguments.users) command = arguments.COMMAND if command is None and len(names) > 1: raise ValueError("For interactive shells the number of vms " "must be 1") elif command is None and len(names) == 1: # find the cloud cm = CmDatabase() vm = cm.find_name(names[0], kind="vm")[0] cloud = vm['cm']['cloud'] # update the cloud provider = Provider(name=cloud) # update the vm provider.list() vm = cm.find_name(names[0], kind="vm")[0] # run ssh result = provider.ssh(vm=vm, command=command) print(result) return "" if len(names) > 1 and len(users) == 1: users = [users] * len(names) if len(names) > 1 and len(users) > 1 and len(names) != len(users): raise ValueError("vms and users have different length") for name in names: cm = CmDatabase() try: vm = cm.find_name(name, kind="vm")[0] except IndexError: Console.error( "VM not found, make sure the vm exists in the list below: " ) os.system('cms vm list') return cloud = vm['cm']['cloud'] provider = Provider(name=cloud) result = provider.ssh(vm=vm, command=command) print(result) else: # ssh with no argument last_vm = Variables()['vm'] cm = CmDatabase() vm = cm.find_name(last_vm, kind="vm")[0] cloud = vm['cm']['cloud'] provider = Provider(name=cloud) provider.ssh(vm=vm)
def do_iu(self, args, arguments): """ :: Usage: iu lab [--port=PORT] iu connect [--port=PORT] iu config iu allocate iu ps iu info iu kill iu status iu jupyter [--port=PORT] iu port [--port=PORT] iu view iu [--user=USERNAME] [--host=HOST] [--node=NUMBER] [--gpu=GPUS] [--res=RESERVATION] iu res iu setup --user=USERNAME iu romeo [--user=USERNAME] This command allows you to inteactively log into roeo or volta Arguments: FILE a file name HOST the host is either rome or volta [default: romeo] NUMBER is a number that specifies where to login GPUS the number of GPU's to be used Options: --res=RESERVATION [default: lijguo_11] Example: cms iu logs in on the first available node, and uses 1 GPU BUG: some reservation are not detected cms iu --node=random logs in on the first available node and uses 1 GPU cms iu status lists the status of rome and volta. The output will look like: +-------------+-----------+ | romeo | Used GPUs | +-------------+-----------+ | r-001 | | | r-002 | 7 | | r-003 | 7 | | r-004 | 7 | +-------------+-----------+ +-------+-----------+ | volta | Used GPUs | +-------+-----------+ | r-005 | 5 | | r-006 | 7 | +-------+-----------+ Users on romeo user1 Users on volta user2 """ # VERBOSE(arguments) config = Config()["cloudmesh.iu"] config["port"] = arguments["--port"] or config["port"] # pprint (config) map_parameters(arguments, "user", "host", "node", "gpu") variables = Variables() # arguments["user"] = Parameter.find("user", arguments, variables) # if arguments.user is None: # config = Config() # arguments.user = config["cloudmesh.iu.user"] iu = Manager(config=config) if arguments.setup: iu.setup() return "" elif arguments.config: iu.config(config) return "" if arguments.status: iu.status(user=arguments.user) return "" elif arguments.res: iu.reservations(user=arguments.user) return "" elif arguments.allocate: iu.allocate(config) return "" elif arguments.ps: found = iu.ps(config) print("\n".join(found)) return "" elif arguments.info: r = iu.info(config) print(Printer.attribute(r)) return "" elif arguments.jupyter: found = iu.jupyter(config) # print ("\n".join(found)) return "" elif arguments.connect: found = iu.connect(config) return "" elif arguments.port: found = iu.set_port(config) return "" elif arguments.view: found = iu.view(config) return "" elif arguments.lab: found = iu.lab(config) return "" elif arguments.kill: found = iu.ps(config) for line in found: line = line.replace(" ", " ") line = line.replace(" ", " ") line = line.replace(" ", " ") line = line.replace(" ", " ") parameter = line.split(" ", 3) if "python" in line: id = parameter[1] r = iu.kill(config, id) print(r) return "" # elif arguments.romeo(user=arguments.user): # iu.reservations(user=arguments.user) # return "" else: arguments["host"] = Parameter.find("host", arguments, variables, {"host": "romeo"}) arguments["node"] = Parameter.find("node", arguments, variables) arguments["gpu"] = int(Parameter.find("gpu", arguments, variables, {"gpu": "1"})) # VERBOSE(arguments) banner(f"Login {arguments.host}") # iu.login(user=arguments.user, # host=arguments.host, # node=arguments.node, # gpus=arguments.gpu) iu.smart_login(user=arguments.user, host=arguments.host, node=arguments.node, gpus=arguments.gpu) return ""
def do_multipass(self, args, arguments): """ :: Usage: multipass list [--output=OUTPUT] [--dryrun] multipass images [--output=OUTPUT] [--dryrun] multipass start NAMES [--output=OUTPUT] [--dryrun] multipass stop NAMES [--output=OUTPUT] [--dryrun] multipass delete NAMES [--output=OUTPUT][--dryrun] multipass shell NAMES [--dryrun] multipass run COMMAND NAMES [--output=OUTPUT] [--dryrun] Interface to multipass Options: --output=OUTPUT the output format [default: table] Arguments: NAMES the names of the virtual machine Description: cms multipass start host[01-03] start multiple vms The NAMES can be a parameterized hostname """ name = arguments.NAME map_parameters(arguments, "dryrun", "refresh", "cloud", "output") variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") names = Parameter.expand(arguments.NAMES) VERBOSE(arguments) if arguments.list: if arguments.dryrun: banner("dryrun list") else: provider = Provider() provider.list() return "" elif arguments.images: if arguments.dryrun: banner("dryrun images") else: provider = Provider() images = provider.images() print(provider.Print(images, kind='image', output=arguments.output)) return "" elif arguments.run: if arguments.dryrun: banner("dryrun run") for name in names: if arguments.dryrun: Console.ok(f"run {name} {arguments.COMMAND}") else: provider = Provider(name=name) provider.run(arguments.COMMAND) return "" elif arguments.start: if arguments.dryrun: banner("start") for name in names: if arguments.dryrun: Console.ok(f"dryrun start {name}") else: provider = Provider(name=name) provider.start() return "" elif arguments.stop: if arguments.dryrun: banner("stop") for name in names: if arguments.dryrun: Console.ok(f"dryrun stop {name}") else: provider = Provider(name=name) provider.stop() return "" elif arguments.delete: if arguments.dryrun: banner("delete") for name in names: if arguments.dryrun: Console.ok(f"dryrun delete {name}") else: provider = Provider(name=name) provider.delete() return "" elif arguments.shell: if len(names) > 1: Console.error("shell must only have one host") return "" name = names[0] if arguments.dryrun: banner("dryrun shell {name}") else: provider = Provider(name=name) provider.shell() return "" else: Console.error("Not yet implemented") return ""
def do_multipass(self, args, arguments): """ :: Usage: multipass list [--output=OUTPUT] [--dryrun] multipass images [--output=OUTPUT] [--dryrun] multipass start NAMES [--output=OUTPUT] [--dryrun] multipass stop NAMES [--output=OUTPUT] [--dryrun] multipass delete NAMES [--output=OUTPUT][--dryrun] multipass shell NAMES [--dryrun] multipass run COMMAND NAMES [--output=OUTPUT] [--dryrun] multipass info NAMES [--output=OUTPUT] [--dryrun] multipass suspend NAMES [--output=OUTPUT] [--dryrun] multipass resume NAMES [--output=OUTPUT] [--dryrun] multipass destroy NAMES [--dryrun] multipass create NAMES [--image=IMAGE] [--size=SIZE] [--mem=MEMORY] [--cpus=CPUS] [--cloud-init=CLOUDINIT] [--dryrun] multipass reboot NAMES [--dryrun] Interface to multipass Options: --output=OUTPUT the output format [default: table] Arguments: NAMES the names of the virtual machine Description: The NAMES can be a parameterized hostname such as red[0-1,5] = red0,red1,red5 cms multipass start vm1,vm2 start multiple vms WHEN YOU IMPLEMENT A FUNCTION INCLUDE MINIMAL DOCUMENTATION HERE """ name = arguments.NAME map_parameters(arguments, "dryrun", "refresh", "cloud", "image", "size", "mem", "cpus", "output") # so we can use arguments.cloudinit arguments["cloudinit"] = arguments["--cloud-init"] image = arguments.image variables = Variables() arguments.output = Parameter.find("output", arguments, variables, "table") names = Parameter.expand(arguments.NAMES) VERBOSE(arguments) if arguments.list: if arguments.dryrun: banner("dryrun list") else: provider = Provider() provider.list() return "" elif arguments.images: if arguments.dryrun: banner("dryrun images") else: provider = Provider() images = provider.images() print(provider.Print(images, kind='image', output=arguments.output)) return "" elif arguments.run: if arguments.dryrun: banner("dryrun run") for name in names: if arguments.dryrun: Console.ok(f"run {name} {arguments.COMMAND}") else: provider = Provider() provider.run(name, arguments.COMMAND) return "" elif arguments.create: result = "" if arguments.dryrun: banner("create") for name in names: if arguments.dryrun: Console.ok(f"dryrun create {name} {image}") else: provider = Provider() result = provider.create(name, image) VERBOSE(result) return result elif arguments.start: result = "" if arguments.dryrun: banner("start") for name in names: if arguments.dryrun: Console.ok(f"dryrun start {name}") else: provider = Provider() result = provider.start(name) VERBOSE(result) return result elif arguments.stop: result = "" if arguments.dryrun: banner("stop") for name in names: if arguments.dryrun: Console.ok(f"dryrun stop {name}") else: provider = Provider(name=name) result = provider.stop(name) VERBOSE(result) return result elif arguments.delete: result = "" if arguments.dryrun: banner("delete") for name in names: if arguments.dryrun: Console.ok(f"dryrun delete {name}") else: provider = Provider() # Default purge is false. Is this ok? result = provider.delete(name) VERBOSE(result) return result elif arguments.info: result = "" if arguments.dryrun: banner(f"info {name}") for name in names: if arguments.dryrun: Console.ok(f"dryrun info {name}") else: provider = Provider() # Default purge is false. Is this ok? result = provider.info(name) VERBOSE(result) return result elif arguments.suspend: result = "" if arguments.dryrun: banner("suspend") for name in names: if arguments.dryrun: Console.ok(f"dryrun suspend {name}") else: provider = Provider() result = provider.suspend(name) VERBOSE(result) return result elif arguments.resume: result = "" if arguments.dryrun: banner("resume") for name in names: if arguments.dryrun: Console.ok(f"dryrun resume {name}") else: provider = Provider() result = provider.resume(name) VERBOSE(result) return result elif arguments.destroy: result = "" if arguments.dryrun: banner("destroy") for name in names: if arguments.dryrun: Console.ok(f"dryrun destroy {name}") else: provider = Provider() result = provider.destroy(name) VERBOSE(result) return result elif arguments.reboot: result = "" if arguments.dryrun: banner("reboot") for name in names: if arguments.dryrun: Console.ok(f"dryrun reboot {name}") else: provider = Provider() result = provider.reboot(name) VERBOSE(result) return result elif arguments.shell: if len(names) > 1: Console.error("shell must only have one host") return "" name = names[0] if arguments.dryrun: banner("dryrun shell {name}") else: provider = Provider() provider.shell() return "" elif arguments.info: if arguments.dryrun: banner("dryrun info") else: provider = Provider() info = provider.info() print( provider.Print(info, kind='info', output=arguments.output)) return "" else: Console.error("Not yet implemented") return ""