Source code for cloudmesh_client.shell.plugins.CometCommand

from cloudmesh_client.shell.console import Console
from cloudmesh_client.shell.command import command, PluginCommand, CometPluginCommand
from cloudmesh_client.comet.comet import Comet
from cloudmesh_client.comet.cluster import Cluster
from cloudmesh_client.common.hostlist import Parameter
from cloudmesh_client.common.ConfigDict import ConfigDict
import hostlist
import os
import sys
from builtins import input
from pprint import pprint

from cloudmesh_client.common.Printer import Printer
import requests

# noinspection PyUnusedLocal,PyBroadException
[docs]class CometCommand(PluginCommand, CometPluginCommand): topics = {"comet": "comet"} def __init__(self, context): self.context = context self.context.comet_token = None if self.context.debug: Console.ok("init comet command") @command def do_comet(self, args, arguments): """ :: Usage: comet init comet active [ENDPOINT] comet ll [CLUSTERID] [--format=FORMAT] [--endpoint=ENDPOINT] comet cluster [--concise|--status] [CLUSTERID] [--format=FORMAT] [--sort=SORTKEY] [--endpoint=ENDPOINT] comet computeset [COMPUTESETID] [--allocation=ALLOCATION] [--cluster=CLUSTERID] [--state=COMPUTESESTATE] [--endpoint=ENDPOINT] comet start CLUSTERID [--count=NUMNODES] [COMPUTENODEIDS] [--allocation=ALLOCATION] [--reservation=RESERVATION] [--walltime=WALLTIME] [--endpoint=ENDPOINT] comet terminate COMPUTESETID [--endpoint=ENDPOINT] comet power (on|off|reboot|reset|shutdown) CLUSTERID [NODESPARAM] [--endpoint=ENDPOINT] comet console [--link] CLUSTERID [COMPUTENODEID] [--endpoint=ENDPOINT] comet node info CLUSTERID [COMPUTENODEID] [--format=FORMAT] [--endpoint=ENDPOINT] comet node rename CLUSTERID OLDNAMES NEWNAMES [--endpoint=ENDPOINT] comet iso list [--endpoint=ENDPOINT] comet iso upload [--isoname=ISONAME] PATHISOFILE [--endpoint=ENDPOINT] comet iso attach ISOIDNAME CLUSTERID [COMPUTENODEIDS] [--endpoint=ENDPOINT] comet iso detach CLUSTERID [COMPUTENODEIDS] [--endpoint=ENDPOINT] comet reservation (list|create|update|delete) Options: --endpoint=ENDPOINT Specify the comet nucleus service endpoint to work with, e.g., dev or production --format=FORMAT Format is either table, json, yaml, csv, rest [default: table] --sort=SORTKEY Sorting key for the table view --count=NUMNODES Number of nodes to be powered on. When this option is used, the comet system will find a NUMNODES number of arbitrary nodes that are available to boot as a computeset --allocation=ALLOCATION Allocation to charge when power on node(s) --reservation=RESERVATION Submit the request to an existing reservation --walltime=WALLTIME Walltime requested for the node(s). Walltime could be an integer value followed by a unit (m, h, d, w, for minute, hour, day, and week, respectively). E.g., 3h, 2d --isoname=ISONAME Name of the iso image after being stored remotely. If not specified, use the original filename --state=COMPUTESESTATE List only computeset with the specified state. The state could be submitted, running, completed --link Whether to open the console url or just show the link --concise Concise table view for cluster info --status Cluster table view displays only those columns showing state of nodes Arguments: ENDPOINT Service endpoint based on the yaml config file. By default it's either dev or production. CLUSTERID The assigned name of a cluster, e.g. vc1 COMPUTESETID An integer identifier assigned to a computeset COMPUTENODEID A compute node name, e.g., vm-vc1-0 If not provided, the requested action will be taken on the frontend node of the specified cluster COMPUTENODEIDS A set of compute node names in hostlist format, e.g., vm-vc1-[0-3] One single node is also acceptable: vm-vc1-0 If not provided, the requested action will be taken on the frontend node of the specified cluster NODESPARAM Specifying the node/nodes/computeset to act on. In case of integer, will be intepreted as a computesetid; in case of a hostlist format, e.g., vm-vc1-[0-3], a group of nodes; or a single host is also acceptable, e.g., vm-vc1-0 ISONAME Name of an iso image at remote server ISOIDNAME Index or name of an iso image at the remote server. The index is based on the list from 'comet iso list'. PATHISOFILE The full path to the iso image file to be uploaded OLDNAMES The list of current node names to be renamed, in hostlist format. A single host is also acceptable. NEWNAMES The list of new names to rename to, in hostlist format. A single host is also acceptable. """ # back up of all the proposed commands/options """ comet status comet tunnel start comet tunnel stop comet tunnel status comet logon comet logoff comet ll [CLUSTERID] [--format=FORMAT] comet docs comet info [--user=USER] [--project=PROJECT] [--format=FORMAT] comet cluster [CLUSTERID][--name=NAMES] [--user=USER] [--project=PROJECT] [--hosts=HOSTS] [--start=TIME_START] [--end=TIME_END] [--hosts=HOSTS] [--format=FORMAT] comet computeset [COMPUTESETID] comet start ID comet stop ID comet power on CLUSTERID [NODESPARAM] [--allocation=ALLOCATION] [--walltime=WALLTIME] comet power (off|reboot|reset|shutdown) CLUSTERID [NODESPARAM] comet console CLUSTERID [COMPUTENODEID] comet delete [all] [--user=USER] [--project=PROJECT] [--name=NAMES] [--hosts=HOSTS] [--start=TIME_START] [--end=TIME_END] [--host=HOST] comet delete --file=FILE comet update [--name=NAMES] [--hosts=HOSTS] [--start=TIME_START] [--end=TIME_END] comet add [--user=USER] [--project=PROJECT] [--host=HOST] [--description=DESCRIPTION] [--start=TIME_START] [--end=TIME_END] NAME comet add --file=FILENAME Options: --user=USER user name --name=NAMES Names of the vcluster --start=TIME_START Start time of the vcluster, in YYYY/MM/DD HH:MM:SS format. [default: 1901-01-01] --end=TIME_END End time of the vcluster, in YYYY/MM/DD HH:MM:SS format. In addition a duratio can be specified if the + sign is the first sig The duration will than be added to the start time. [default: 2100-12-31] --project=PROJECT project id --host=HOST host name --description=DESCRIPTION description summary of the vcluster --file=FILE Adding multiple vclusters from one file --format=FORMAT Format is either table, json, yaml, csv, rest [default: table] --allocation=ALLOCATION Allocation to charge when power on node(s) --walltime=WALLTIME Walltime requested for the node(s) Arguments: FILENAME the file to open in the cwd if . is specified. If file in in cwd you must specify it with ./FILENAME Opens the given URL in a browser window. """ """ if not arguments["tunnel"] and Comet.tunnelled and not Comet.is_tunnel(): Console.error("Please establish a tunnel first with:") print print (" comet tunnel start") print return "" try: if not arguments["tunnel"]: logon = Comet.logon() if logon is False: Console.error("Could not logon") return "" except: Console.error("Could not logon") # pprint (arguments) output_format = arguments["--format"] or "table" if arguments["status"]: Comet.state() elif arguments["tunnel"] and arguments["start"]: Comet.tunnel(True) elif arguments["tunnel"] and arguments["stop"]: Comet.tunnel(False) elif arguments["tunnel"] and arguments["status"]: Comet.state() elif arguments["logon"]: if self.context.comet_token is None: if Comet.logon(): Console.ok("logging on") self.context.comet_token = Comet.token else: Console.error("could not logon") else: Console.error("already logged on") elif arguments["logoff"]: if self.context.comet_token is None: Console.error("not logged in") else: if Comet.logoff(): Console.ok("Logging off") self.context.comet_token = None else: Console.error( "some issue while logging off. Maybe comet not reachable") elif arguments["docs"]: Comet.docs() elif arguments["info"]: Console.error("not yet implemented") elif arguments["add"]: print ("add the cluster") elif arguments["start"]: cluster_id = arguments["ID"] print("start", cluster_id) Cluster.start(cluster_id) elif arguments["stop"]: cluster_id = arguments["ID"] print("stop", cluster_id) Cluster.stop(cluster_id) elif arguments["ll"]: """ if arguments["init"]: print ("Initializing the comet configuration file...") config = ConfigDict("cloudmesh.yaml") # for unit testing only. cometConf = config["cloudmesh.comet"] endpoints = [] # print (cometConf.keys()) if "endpoints" in cometConf.keys(): endpoints = cometConf["endpoints"].keys() if len(endpoints) < 1: Console.error("No service endpoints available. " "Please check the config template", traceflag=False) return "" if "username" in cometConf.keys(): default_username = cometConf['username'] # print (default_username) if 'TBD' == default_username: set_default_user = \ input("Set a default username (RETURN to skip): ") if set_default_user: config.data["cloudmesh"]["comet"]["username"] = \ set_default_user config.save() Console.ok("Comet default username set!") if "active" in cometConf.keys(): active_endpoint = cometConf['active'] set_active_endpoint = \ input("Set the active service endpoint to use. " "The availalbe endpoints are - %s [%s]: " % ("/".join(endpoints), active_endpoint) ) if set_active_endpoint: if set_active_endpoint in endpoints: config.data["cloudmesh"]["comet"]["active"] = \ set_active_endpoint config.save() Console.ok("Comet active service endpoint set!") else: Console.error("The provided endpoint does not match " "any available service endpoints. Try %s" % "/".join(endpoints), traceflag=False) if cometConf['active'] in endpoints: endpoint_url = cometConf["endpoints"] \ [cometConf['active']]["nucleus_base_url"] api_version = cometConf["endpoints"] \ [cometConf['active']]["api_version"] set_endpoint_url = \ input("Set the base url for the nucleus %s service [%s]: " \ % (cometConf['active'], endpoint_url) ) if set_endpoint_url: if set_endpoint_url != endpoint_url: config.data["cloudmesh"]["comet"]["endpoints"] \ [cometConf['active']]["nucleus_base_url"] \ = set_endpoint_url config.save() Console.ok("Service base url set!") set_api_version = \ input("Set the api version for the nucleus %s service [%s]: " \ % (cometConf['active'], api_version) ) if set_api_version: if set_api_version != api_version: config.data["cloudmesh"]["comet"]["endpoints"] \ [cometConf['active']]["api_version"] \ = set_api_version config.save() Console.ok("Service api version set!") print("Authenticating to the nucleus %s " \ "service and obtaining the apikey..." \ % cometConf['active']) Comet.get_apikey(cometConf['active']) return '' # Comet.get_apikey() if arguments["active"]: config = ConfigDict("cloudmesh.yaml") cometConf = config["cloudmesh.comet"] endpoint = arguments["ENDPOINT"] or None # parameter specified, intended to change if endpoint: if "endpoints" in cometConf.keys(): endpoints = cometConf["endpoints"].keys() if endpoint in endpoints: config.data["cloudmesh"] \ ["comet"] \ ["active"] = endpoint config.save() Console.ok("Comet active service endpoint set" " to: %s" % endpoint) else: Console.error("The provided endpoint does not match " "any available service endpoints. Try %s." % "/".join(endpoints), traceflag = False) else: Console.error("No available endpoint to set. " "Check config file!", traceflag=False) else: if "active" in cometConf.keys(): active_endpoint = cometConf['active'] Console.ok("Current active service endpoint is: %s" % active_endpoint) else: Console.error("Cannot set active endpoint. " "Check config file!", traceflag = False) try: endpoint = None config = ConfigDict("cloudmesh.yaml") cometConf = config["cloudmesh.comet"] if arguments["--endpoint"]: endpoint = arguments["--endpoint"] if "endpoints" in cometConf.keys(): endpoints = cometConf["endpoints"].keys() if endpoint not in endpoints: Console.error("The provided endpoint does not match " "any available service endpoints. Try %s." % "/".join(endpoints), traceflag = False) return '' logon = Comet.logon(endpoint=endpoint) if logon is False: Console.error("Could not logon. Please try first:\n" "cm comet init", traceflag = False) return "" except: Console.error("Could not logon", traceflag = False) output_format = arguments["--format"] or "table" if arguments["ll"]: cluster_id = arguments["CLUSTERID"] or None print(Cluster.simple_list(cluster_id, format=output_format)) elif arguments["cluster"]: view = "FULL" if arguments["--concise"]: view = "CONCISE" if arguments["--status"]: view = "STATE" cluster_id = arguments["CLUSTERID"] sortkey = arguments["--sort"] print(Cluster.list(cluster_id, format=output_format, sort=sortkey, view=view)) elif arguments["computeset"]: computeset_id = arguments["COMPUTESETID"] or None cluster = arguments["--cluster"] or None state = arguments["--state"] or None allocation = arguments["--allocation"] or None cluster = arguments["--cluster"] or None print (Cluster.computeset(computeset_id, cluster, state, allocation)) elif arguments["start"]: clusterid = arguments["CLUSTERID"] numnodes = arguments["--count"] or None computenodeids = arguments["COMPUTENODEIDS"] or None # check allocation information for the cluster cluster = Cluster.list(clusterid, format='rest') try: allocations = cluster[0]['allocations'] except: # print (cluster) Console.error("No allocation available for the specified cluster."\ "Please check with the comet help team", traceflag=False) return "" # checking whether the computesetids is in valid hostlist format if computenodeids: try: hosts_param = hostlist.expand_hostlist(computenodeids) except hostlist.BadHostlist: Console.error("Invalid hosts list specified!", traceflag=False) return "" elif numnodes: try: param = int(numnodes) except ValueError: Console.error("Invalid count value specified!", traceflag=False) return "" if param <= 0: Console.error("count value has to be greather than zero", traceflag=False) return "" numnodes = param else: Console.error("You have to specify either the count of nodes, " \ "or the names of nodes in hostlist format", traceflag=False) return "" walltime = arguments["--walltime"] or None allocation = arguments["--allocation"] or None reservation = arguments["--reservation"] or None # validating walltime and allocation parameters walltime = Cluster.convert_to_mins(walltime) if not walltime: print("No valid walltime specified. " \ "Using system default (2 days)") if not allocation: if len(allocations) == 1: allocation = allocations[0] else: allocation = Cluster.display_get_allocation(allocations) # issuing call to start a computeset with specified parameters print(Cluster.computeset_start(clusterid, computenodeids, numnodes, allocation, reservation, walltime) ) elif arguments["terminate"]: computesetid = arguments["COMPUTESETID"] print(Cluster.computeset_terminate(computesetid)) elif arguments["power"]: clusterid = arguments["CLUSTERID"] or None fuzzyparam = arguments["NODESPARAM"] or None # parsing nodesparam for proper action if fuzzyparam: try: param = int(fuzzyparam) subject = 'COMPUTESET' except ValueError: param = fuzzyparam try: hosts_param = hostlist.expand_hostlist(fuzzyparam) subject = 'HOSTS' except hostlist.BadHostlist: Console.error("Invalid hosts list specified!", traceflag=False) return "" else: subject = 'FE' param = None if arguments["on"]: action = "on" elif arguments["off"]: action = "off" elif arguments["reboot"]: action = "reboot" elif arguments["reset"]: action = "reset" elif arguments["shutdown"]: action = "shutdown" else: action = None print (Cluster.power(clusterid, subject, param, action) ) elif arguments["console"]: clusterid = arguments["CLUSTERID"] linkonly = False if arguments["--link"]: linkonly = True nodeid = None if 'COMPUTENODEID' in arguments: nodeid = arguments["COMPUTENODEID"] Comet.console(clusterid, nodeid, linkonly) elif arguments["iso"]: if arguments["list"]: isos = (Comet.list_iso()) idx = 0 for iso in isos: if iso.startswith("public/"): iso = iso.split("/")[1] idx += 1 print ("{}: {}".format(idx, iso)) if arguments["upload"]: isofile = arguments["PATHISOFILE"] isofile = os.path.abspath(isofile) if os.path.isfile(isofile): if arguments["--isoname"]: filename = arguments["--isoname"] else: filename = os.path.basename(isofile) else: print ("File does not exist - {}" \ .format(arguments["PATHISOFILE"])) return "" print(Comet.upload_iso(filename, isofile)) elif arguments["attach"]: isoidname = arguments["ISOIDNAME"] clusterid = arguments["CLUSTERID"] computenodeids = arguments["COMPUTENODEIDS"] or None print(Cluster.attach_iso(isoidname, clusterid, computenodeids)) elif arguments["detach"]: clusterid = arguments["CLUSTERID"] computenodeids = arguments["COMPUTENODEIDS"] or None print(Cluster.detach_iso(clusterid, computenodeids)) elif arguments["node"]: if arguments["info"]: clusterid = arguments["CLUSTERID"] nodeid = arguments["COMPUTENODEID"] print (Cluster.node_info(clusterid, nodeid=nodeid, format=output_format)) elif arguments["rename"]: clusterid = arguments["CLUSTERID"] oldnames = Parameter.expand(arguments["OLDNAMES"]) newnames = Parameter.expand(arguments["NEWNAMES"]) if len(oldnames) != len(newnames): Console.error("Length of OLDNAMES and NEWNAMES have to be the same", traceflag=False) return "" else: for newname in newnames: if newname.strip() == "": Console.error("Newname cannot be empty string", traceflag=False) return "" cluster_data = Cluster.list(clusterid, format="rest") if len(cluster_data) > 0: computes = cluster_data[0]["computes"] nodenames = [x["name"] for x in computes] else: Console.error("Error obtaining the cluster information", traceflag=False) return "" # check if new names ar not already taken # to be implemented # print (oldnames) # print (newnames) # print (nodenames) oldset = set(oldnames) newset = set(newnames) currentset = set(nodenames) # at least one OLDNAME does not exist if not oldset <= currentset: Console.error("Not all OLDNAMES are valid", traceflag=False) return "" else: # those unchanged nodes keptset = currentset - oldset # duplication between name of unchanged nodes and # the requested NEWNAMES if keptset & newset != set(): Console.error("Not proceeding as otherwise introducing "\ "duplicated names", traceflag=False) else: for i in range(0,len(oldnames)): oldname = oldnames[i] newname = newnames[i] print ("%s -> %s" % (oldname, newname)) confirm = input("Confirm batch renaming (Y/y to confirm, "\ "any other key to abort):") if confirm.lower() == 'y': print ("Conducting batch renaming") for i in range(0,len(oldnames)): oldname = oldnames[i] newname = newnames[i] print (Cluster.rename_node(clusterid, oldname, newname)) else: print ("Action aborted!") elif arguments["reservation"]: if arguments["create"] or \ arguments["update"] or \ arguments["delete"]: Console.info("Operation not supported. Please contact XSEDE helpdesk for help!") if arguments["list"]: if "hpcinfo" in cometConf: hpcinfourl = cometConf["hpcinfo"]["endpoint"] else: Console.error("Admin feature not configured for this client", traceflag = False) return "" ret = requests.get("%s/reservations/%s" % (hpcinfourl, cometConf['active']) ) jobs = ret.json() result = Printer.write(jobs) print (result) return ""