def print_ssh_table(output): content = read(filename="~/.ssh/config").split("\n") entries = [ ] def empty(): return { "host": None, "hostname": None, "user": None, "proxycommand": None, "serveraliveinterval": None, "localforward": None, "forwardx11": None } entry = empty() for line in content: line = line.strip() if line.startswith("#"): pass elif line.strip() == "": pass elif "Host " in line: hostname = line.strip().split("Host")[1] entry["host"] = hostname.strip() if entry is not None: entries.append(entry) entry = empty() else: attribute, value = line.strip().split(" ", 1) entry[attribute.lower()] = value.strip() # pprint(entries) order = ["host", "hostname", "user", "proxycommand", "serveraliveinterval", "localforward", "forwardx11"] print(Printer.list(entries, order=order))
def print_ssh_table(output): content = read(filename="~/.ssh/config").split("\n") entries = [] def empty(): return { "host": None, "hostname": None, "user": None, "proxycommand": None, "serveraliveinterval": None, "localforward": None, "forwardx11": None } entry = empty() for line in content: line = line.strip() if line.startswith("#"): pass elif line.strip() == "": pass elif "Host " in line: hostname = line.strip().split("Host")[1] entry["host"] = hostname.strip() if entry is not None: entries.append(entry) entry = empty() else: attribute, value = line.strip().split(" ", 1) entry[attribute.lower()] = value.strip() # pprint(entries) order = [ "host", "hostname", "user", "proxycommand", "serveraliveinterval", "localforward", "forwardx11" ] print(Printer.list(entries, order=order))
def do_cluster(self, args, arguments): """ :: Usage: cluster list [--format=FORMAT] cluster list NAME [--format=FORMAT] [--column=COLUMN] [--short] cluster create NAME [--count=COUNT] [--login=USERNAME] [--cloud=CLOUD] [--image=IMAGE] [--flavor=FLAVOR] [--add] cluster delete NAME cluster setup NAME [--username] cluster inventory NAME Description: with the help of the cluster command you can create a number of virtual machines that are integrated in a named virtual cluster. You will be able to login between the nodes of the virtual cluster while using public keys. cluster setup NAME sets up the keys between the cluster node as well as the machine that executes the cm command cluster inventory NAME creates an inventory.txt file to be used by ansible in the current directory cluster create NAME creates the virtual machines used for the cluster cluster list NAME lists selected details of the vms for the cluster cluster delete NAME remove the cluster and its VMs Examples: cluster list list the clusters cluster create NAME --count=COUNT --login=USERNAME [options...] Start a cluster of VMs, and each of them can log into each other. CAUTION: you should specify defaults before using this command: 1. select cloud to work on, e.g. cloud select kilo default cloud=kilo 2. test if you can create a single VM on the cloud to see if everything is set up 3. set the default key to start VMs, e.g. key default [USERNAME-key] 5. set image of VMs, e.g. default image 6. set flavor of VMs, e.g. default flavor 7. Make sure to use a new unused group name Arguments: NAME cluster name or group name Options: --count=COUNT give the number of VMs to add into the cluster --login=USERNAME give a login name for the VMs, e.g. ubuntu --cloud=CLOUD give a cloud to work on --flavor=FLAVOR give the name of the flavor or flavor id --image=IMAGE give the name of the image or image id --add if a group exists and there are VMs in it additional vms will be added to this cluster and the keys will be added to each other so one can login between them FORMAT output format: table, json, csv COLUMN customize what information to display, for example: --column=status,addresses prints the columns status and addresses --detail for table print format, a brief version is used as default, use this flag to print detailed table """ def get_vms(group_name): groups = Vm.get_vms_by_group(group_name) vms = [] for group in groups: name = group["member"] print(name) vm = Vm.get_vm(name) vm['cluster'] = group_name vms.append(vm) return vms def _print(f): print (f) def write(filename, msg): with open(path_expand(filename), 'w') as f: output = f.write(msg) arg = dotdict(arguments) arg.format = arguments["--format"] or "table" arg.count = int(arguments["--count"] or 1) arg.username = arguments["--login"] arg.cloud = arguments["--cloud"] or Default.cloud arg.image = arguments["--image"] or Default.get(name="image", category=arg.cloud) arg.flavor = arguments["--flavor"] or Default.get(name="flavor", category=arg.cloud) arg.add = arguments["--add"] arg.group = arg.NAME arg.name = None arg.key = Default.key arg.secgroup = Default.secgroup arg.group = arg.NAME arg.short = arguments["--short"] if arg.create: boot_from_args(arg) elif arg.inventory: group = Vm.get_vms_by_group(arg.group) result = "" if arg.format is "table": result = "[servers]\n" for element in group: name = element["member"] vm = Vm.get_vm(name)[0] vm['cluster'] = arg.group result += "{floating_ip}\n".format(**vm) Console.ok("Writing ips to inventory.txt") print(result) write("inventory.txt", result) Console.ok(".ok") return "" elif arg.list and arg.NAME is not None: if arg.short: vms = Vm.get_vms_by_group(arg.group) if vms is None: Console.error("no vms found for {}".format(arg.group)) else: print(Printer.list(vms, header=['Group', 'Vm'], order=['name', 'member'], output=arg.format)) else: groups = Vm.get_vms_by_group(arg.group) pprint(groups) vms = [] for group in groups: name = group["member"] vm = Vm.get_vm(name)[0] vm['cluster'] = arg.group if vm is not None: vms.append(vm) pprint(vms) if vms is None: Console.error("no vms found for {}".format(arg.group)) else: print(Printer.list(vms, order=['name', 'cluster', 'flavor', 'image', 'status', 'user_id', 'floating_ip'], output=arg.format)) return "" elif arg.setup: def push(from_path, vm): vm.ip = vm.floating_ip if vm.ip is not None: if arg.verbose: Console.info("Connecting to Instance at IP:" + format(vm.ip)) sshcommand = "scp" sshcommand += " -o StrictHostKeyChecking=no" sshcommand += " {:}".format(from_path) sshcommand += " {username}@{ip}:.ssh/authorized_keys".format(**vm) print(sshcommand) os.system(sshcommand) else: Console.error("No Public IPs found for the instance", traceflag=False) groups = Vm.get_vms_by_group(arg.group) pprint (groups) vms = [] for group in groups: name = group["member"] vm = Vm.get_vm(name)[0] vm['cluster'] = arg.group if vm is not None: vms.append(vm) pprint(vms) if vms is None: Console.error("no vms found for {}".format(arg.group)) else: print(Printer.list(vms, order=['name', 'cluster', 'flavor', 'image', 'status', 'user_id', 'floating_ip'], output=arg.format)) keys = "" for vm in vms: vm = dotdict(vm) cloud = vm.category if vm.username is None: vm.username = arguments["--username"] or Image.guess_username(arg.image) chameleon = "chameleon" in ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["clouds"][cloud][ "cm_host"] print ("C", chameleon) if chameleon: vm.username = "******" elif vm.category == "azure": vm.username = ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["clouds"]["azure"]["default"][ "username"] else: if vm.username is None: Console.error("Could not guess the username of the vm", traceflag=False) return Vm.set_login_user(name=vm.name, cloud=vm.category, username=vm.username) vm.ip = vm.floating_ip def execute(commands): if vm.ip is not None: if arg.verbose: Console.info("Connecting to Instance at IP:" + format(vm.ip)) sshcommand = "ssh" if arg.key is not None: sshcommand += " -i {:}".format(arg.key) sshcommand += " -o StrictHostKeyChecking=no" sshcommand += " {username}@{ip}".format(**vm) sshcommand += " \'{:}\'".format(commands) print(sshcommand) os.system(sshcommand) else: Console.error("No Public IPs found for the instance", traceflag=False) def copy(commands): if vm.ip is not None: if arg.verbose: Console.info("Connecting to Instance at IP:" + format(vm.ip)) sshcommand = "scp" sshcommand += " -o StrictHostKeyChecking=no" sshcommand += " {username}@{ip}".format(**vm) sshcommand += ":{:}".format(commands) print(sshcommand) os.system(sshcommand) else: Console.error("No Public IPs found for the instance", traceflag=False) def cat(filename): with open(path_expand(filename), 'r') as f: output = f.read() return output execute('cat /dev/zero | ssh-keygen -q -N ""') copy(".ssh/id_rsa.pub ~/.ssh/id_rsa_{name}.pub".format(**vm)) output = "~/.ssh/id_rsa_{name}.pub".format(**vm) keys = keys + cat(output) print ("WRITE KEYS") keys = keys + cat("~/.ssh/id_rsa.pub") output = "~/.ssh/id_rsa_{group}.pub".format(**arg) write(output, keys) print("PUSH KEYS") for vm in vms: vm = dotdict(vm) push("~/.ssh/id_rsa_{group}.pub".format(**arg), vm) return ""
def do_register(self, args, arguments): """ :: Usage: register info register backup register new [--force] [--dryrun] register clean [--force] register list ssh [--format=FORMAT] register list [--yaml=FILENAME][--info][--format=FORMAT] register cat [--yaml=FILENAME] register edit [--yaml=FILENAME] register user [USERNAME] register cloud [CLOUD] [--force] register remote [CLOUD] [--force] register export HOST [--password] [--format=FORMAT] register source HOST register merge FILEPATH register form [--yaml=FILENAME] register check [--yaml=FILENAME] register test [--yaml=FILENAME] register json HOST register env [--provider=PROVIDER] register ec2 CLOUD EC2ZIP register ENTRY managing the registered clouds in the cloudmesh.yaml file. It looks for it in the current directory, and than in ~/.cloudmesh. If the file with the cloudmesh.yaml name is there it will use it. If neither location has one a new file will be created in ~/.cloudmesh/cloudmesh.yaml. Some defaults will be provided. However you will still need to fill it out with valid entries. Arguments: HOST the host name USER the user name FILEPATH the path of the file CLOUD the cloud name PROVIDER the provider or type of cloud [Default: openstack] USERNAME Username that would be registered in yaml. Defaults to OS username. Options: --provider=PROVIDER Provider to be used for cloud. Values are: openstack, azure, ec2. --version=VERSION Version of the openstack cloud. --openrc=OPENRC The location of the openrc file --password Prints the password --force ignore interactive questions and execute the action Description: register info lists the clouds specified in the cloudmesh.yaml file in the current directory, and then in ~/.cloudmesh register list [--yaml=FILENAME] [--name] [--info] lists the clouds specified in the cloudmesh.yaml file. If info is specified it also prints the location of the yaml file. register list ssh lists hosts from ~/.ssh/config register cat [--yaml=FILENAME] outputs the cloudmesh.yaml file register edit [--yaml=FILENAME] edits the cloudmesh.yaml file register export HOST [--format=FORMAT] prints the contents of an openrc.sh file based on the information found in the cloudmesh.yaml file. register remote CLOUD [--force] reads the Openstack OPENRC file from a remote host that is described in cloudmesh.yaml file. We assume that the file has already a template for this host. If not it can be created from other examples before you run this command. It uses the OS_OPENRC variable to locate the file and copy it onto your computer. register merge FILENAME Replaces the TBD in cloudmesh.yaml with the contents present in the named file register form [--yaml=FILENAME] interactively fills out the form wherever we find TBD. register check [--yaml=FILENAME] checks the yaml file for completness register test [--yaml=FILENAME] checks the yaml file and executes tests to check if we can use the cloud. TODO: maybe this should be in a test command register json host displays the host details in json format register remote CLOUD registers a remote cloud and copies the openrc file specified in the credentials of the cloudmesh.yaml register CLOUD --dir Copies the entire directory from the cloud and puts it in ~/.cloudmesh/clouds/host For kilo, The directory would be copied to ~/.cloudmesh/clouds/kilo register env [--provider=PROVIDER] [HOSTNAME] Reads env OS_* variables and registers a new cloud in yaml, interactively. Default PROVIDER is openstack and HOSTNAME is localhost. register user [USERNAME] Sets the user in yaml with the value provided. """ # from pprint import pprint # pprint(arguments) def _get_config_yaml_file(arguments): filename = arguments["--yaml"] or "cloudmesh.yaml" filename = Config.find_file(filename) return filename def exists(filename): return os.path.isfile(filename) def export(host, output): config = ConfigDict("cloudmesh.yaml") credentials = dict( config["cloudmesh"]["clouds"][host]["credentials"]) if not arguments["--password"]: credentials["OS_PASSWORD"] = "******" if output is None: for attribute, value in credentials.items(): print("export {}={}".format(attribute, value)) elif output == "table": print(Printer.attribute(credentials)) else: print(Printer.write(credentials, output=output)) # TODO: bug csv does not work if arguments["info"]: filename = _get_config_yaml_file(arguments) if os.path.isfile(filename): Console.ok("File '{}' exists. ok.".format(filename)) Console.ok("The yaml file contains the following templates:") d = CloudRegister.list(filename, Default.cloud, info=False, output="table") print(d) else: Console.error("File {} does not exist".format(filename)) return "" elif arguments["backup"]: name = backup_name("~/.cloudmesh/cloudmesh.yaml") configfile = path_expand("~/.cloudmesh/cloudmesh.yaml") print (name) try: copy(configfile, name) Console.ok("Bakup copy created: {}. ok.".format(name)) except: Console.error("Could not create a backup copy from {}".format(configfile)) return "" elif arguments["new"]: import shutil import cloudmesh_client.etc config = ConfigDict("cloudmesh.yaml") data = dotdict({ 'dir': cloudmesh_client.etc.__file__, 'filename': os.path.join( os.path.dirname(cloudmesh_client.etc.__file__), "cloudmesh.yaml"), 'yamlfile': path_expand("~/.cloudmesh/cloudmesh.yaml"), 'dryrun': arguments['--dryrun'] }) Console.ok(data.filename) force = arguments["--force"] if not force: force = yn_choice("Would you like create a new configuration file at {}".format(data.yamlfile)) if force: if not data.dryrun: config.make_a_copy(location=data.yamlfile) shutil.copyfile(data.filename, data.yamlfile) print("copy ") print("From: ", data.filename) print("To: ", data.yamlfile) # filename = _get_config_yaml_file(arguments) # if _exists(filename): # Console.ok("File '{}' exists. ok.".format(filename)) # else: # Console.error("File {} does not exist".format(filename)) return "" elif arguments["clean"]: filename = _get_config_yaml_file(arguments) force = arguments["--force"] or False if filename is not None: print(filename, force) if exists(filename): print("Delete cloudmesh.yaml file:", filename) if not force: force = yn_choice("Would you like to delete the " "cloudmesh.yaml file") print(force) if force: os.remove(filename) Console.ok("Deleted the file " + filename + ". ok.") else: Console.ok("Please use Y to delete the file.") pass else: Console.error("File {} does not exist".format(filename)) else: Console.error("No cloudmesh.yaml file found.") return "" elif arguments["cat"]: filename = _get_config_yaml_file(arguments) if exists(filename): with open(filename, 'r') as f: lines = f.read().split("\n") print('\n'.join(lines)) else: Console.error("File {} does not exist".format(filename)) return "" elif arguments["edit"]: filename = _get_config_yaml_file(arguments) if exists(filename): try: data = {"editor": os.environ["EDITOR"], "filename": filename} Console.ok("editing file " + filename) os.system("{editor} {filename}".format(**data)) except: Console.error("No operating system environment variable EDITOR set.", traceflag=False) else: Console.error("File {} does not exist".format(filename), traceflag=False) return "" elif arguments['list'] and arguments['ssh']: output = arguments['--format'] or 'table' hosts = CloudRegister.list_ssh() print(Printer.list(hosts, output=output)) return "" elif arguments['list']: filename = _get_config_yaml_file(arguments) info = arguments["--info"] or False output = arguments["--format"] or "table" if not filename: Console.error("File {} doesn't exist".format(filename)) else: d = CloudRegister.list(filename, Default.cloud, info=info, output=output) print(d) return "" elif arguments['check']: filename = _get_config_yaml_file(arguments) if not filename: Console.error("File {} doesn't exist".format( arguments["--yaml"] or 'cloudmesh.yaml')) else: CloudRegister.check_yaml_for_completeness(filename) return "" elif arguments['merge']: filename = arguments['FILENAME'] CloudRegister.from_file(filename) return "" elif arguments['test']: filename = _get_config_yaml_file(arguments) CloudRegister.test(filename) return "" elif arguments['form']: filename = _get_config_yaml_file(arguments) if not filename: Console.error("File {} doesn't exist".format( arguments["--yaml"] or 'cloudmesh.yaml')) else: CloudRegister.fill_out_form(filename) return "" elif arguments['source']: host = arguments['HOST'] config = ConfigDict("cloudmesh.yaml") credentials = dict( config["cloudmesh"]["clouds"][host]["credentials"]) # unset variables = list(os.environ) for attribute in variables: if attribute.startswith("OS_"): print("x ", attribute) del os.environ[attribute] # set for attribute, value in credentials.items(): os.putenv(attribute, value) print("+ ", attribute) export(host, "table") return "" elif arguments['export']: output = arguments['--format'] host = arguments['HOST'] try: variables = list(os.environ) for attribute in variables: if attribute.startswith("OS_"): print("unset ", attribute) del os.environ[attribute] export(host, output) except: Console.error ("The export may not include all values", traceflag=False) return "" elif arguments['json']: host = arguments['HOST'] result = CloudRegister.get(host) if result: print(json.dumps(result, indent=4)) else: print("Cloud {:} is not described in cloudmesh.yaml".format( host)) return "" elif arguments['remote']: force = arguments['--force'] cloud = arguments['CLOUD'] if cloud is None: # clouds = [ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["active"][0]] clouds = ["kilo"] # hardcode to kilo for now else: clouds = [cloud] for cloud in clouds: CloudRegister.remote(cloud, force) export(cloud, "table") config = ConfigDict("cloudmesh.yaml") if config["cloudmesh.profile.user"] == "TBD": name = config["cloudmesh.clouds.kilo.credentials.OS_USERNAME"] config["cloudmesh"]["profile"]["user"] = name config.save() return "" elif arguments['ec2']: cloud = arguments['CLOUD'] zipfile = arguments['EC2ZIP'] if cloud is None: clouds = [ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["active"][0]] else: clouds = [cloud] for cloud in clouds: CloudRegister.ec2(cloud, zipfile) export(cloud, "table") return "" elif arguments['env']: try: CloudRegister.from_environ(arguments['--provider']) except Exception as e: Error.traceback(e) return "" elif arguments['cloud']: """ if arguments['--dir']: cloud = arguments['--name'] directory = arguments['--dir'] Console.ok(directory) CloudRegister.directory(cloud, directory) else: """ values_to_replace = ['tbd', 'null', 'tbd_not_used'] cloud = arguments['CLOUD'] if cloud is None: clouds = [ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["active"][0]] else: clouds = [cloud] for cloud in clouds: config = ConfigDict("cloudmesh.yaml") cloud_config = config["cloudmesh.clouds"][cloud] # Checking credentials print("Checking cloud credentials...") for prop in cloud_config["credentials"]: if cloud_config["credentials"][prop].lower() in values_to_replace: value = input(prop + "(" + cloud_config["credentials"][prop] + "): ") cloud_config["credentials"][prop] = value # Checking defaults print("Checking cloud defaults...") for prop in cloud_config["default"]: if cloud_config["default"][prop].lower() in values_to_replace: value = input(prop + "(" + cloud_config["default"][prop] + "): ") cloud_config["default"][prop] = value config.save() export(cloud, "table") return "" elif arguments['user']: username = arguments["USERNAME"] or getpass.getuser() CloudRegister.set_username(username) Console.ok("Setting profile user to {} in the yaml file.".format(username)) hosts = ssh_config() hosts.generate(key="india", username=username, verbose=True) return "" elif arguments['ENTRY'].lower() in ['chameleon']: config = ConfigDict("cloudmesh.yaml") credentials = dotdict(config["cloudmesh.clouds.chameleon.credentials"]) default = credentials.OS_USERNAME username = input("Please enter the username for {:} [{}]: ".format("chameleon", default)) username = username or default while True: default = credentials.OS_PROJECT_NAME project = input("Please enter the project id for {:} [{}]: ".format("chameleon", default)) project = project or default if project.isdigit(): project = "CH-{}".format(project) break else: try: prefix, number = project.split("-") if not (prefix in ["CH"] and number.isdigit()): Console.error("This is not a valid Chameleon.org cloud project", traceflag=False) else: break except: Console.error("This is not a valid Chameleon.org cloud project", traceflag=False) password = getpass.getpass("Please enter the password for {:}: ".format("chameleon", credentials.OS_PASSWORD)) credentials.OS_TENENT_ID = credentials.OS_PROJECT_NAME credentials.OS_TENENT_NAME = credentials.OS_PROJECT_NAME credentials.OS_USERNAME = username credentials.OS_PASSWORD = password config.save() return "" elif arguments['ENTRY'] is not None: name = arguments['ENTRY'] Register.entry(name) return "" # if all fails do a simple list filename = _get_config_yaml_file(arguments) CloudRegister.list(filename) pass
def do_cluster(self, args, arguments): """ :: Usage: cluster list [--format=FORMAT] cluster list NAME [--format=FORMAT] [--column=COLUMN] [--short] cluster create NAME [--count=COUNT] [--login=USERNAME] [--cloud=CLOUD] [--image=IMAGE] [--flavor=FLAVOR] [--add] cluster delete NAME cluster setup NAME [--username] cluster inventory NAME Description: with the help of the cluster command you can create a number of virtual machines that are integrated in a named virtual cluster. You will be able to login between the nodes of the virtual cluster while using public keys. cluster setup NAME sets up the keys between the cluster node as well as the machine that executes the cm command cluster inventory NAME creates an inventory.txt file to be used by ansible in the current directory cluster create NAME creates the virtual machines used for the cluster cluster list NAME lists selected details of the vms for the cluster cluster delete NAME remove the cluster and its VMs Examples: cluster list list the clusters cluster create NAME --count=COUNT --login=USERNAME [options...] Start a cluster of VMs, and each of them can log into each other. CAUTION: you should specify defaults before using this command: 1. select cloud to work on, e.g. cloud select kilo default cloud=kilo 2. test if you can create a single VM on the cloud to see if everything is set up 3. set the default key to start VMs, e.g. key default [USERNAME-key] 5. set image of VMs, e.g. default image 6. set flavor of VMs, e.g. default flavor 7. Make sure to use a new unused group name Arguments: NAME cluster name or group name Options: --count=COUNT give the number of VMs to add into the cluster --login=USERNAME give a login name for the VMs, e.g. ubuntu --cloud=CLOUD give a cloud to work on --flavor=FLAVOR give the name of the flavor or flavor id --image=IMAGE give the name of the image or image id --add if a group exists and there are VMs in it additional vms will be added to this cluster and the keys will be added to each other so one can login between them FORMAT output format: table, json, csv COLUMN customize what information to display, for example: --column=status,addresses prints the columns status and addresses --detail for table print format, a brief version is used as default, use this flag to print detailed table """ def get_vms(group_name): groups = Vm.get_vms_by_group(group_name) vms = [] for group in groups: name = group["member"] print(name) vm = Vm.get_vm(name) vm['cluster'] = group_name vms.append(vm) return vms def _print(f): print(f) def write(filename, msg): with open(path_expand(filename), 'w') as f: output = f.write(msg) arg = dotdict(arguments) arg.format = arguments["--format"] or "table" arg.count = int(arguments["--count"] or 1) arg.username = arguments["--login"] arg.cloud = arguments["--cloud"] or Default.cloud arg.image = arguments["--image"] or Default.get(name="image", category=arg.cloud) arg.flavor = arguments["--flavor"] or Default.get(name="flavor", category=arg.cloud) arg.add = arguments["--add"] arg.group = arg.NAME arg.name = None arg.key = Default.key arg.secgroup = Default.secgroup arg.group = arg.NAME arg.short = arguments["--short"] if arg.create: boot_from_args(arg) elif arg.inventory: group = Vm.get_vms_by_group(arg.group) result = "" if arg.format is "table": result = "[servers]\n" for element in group: name = element["member"] vm = Vm.get_vm(name)[0] vm['cluster'] = arg.group result += "{floating_ip}\n".format(**vm) Console.ok("Writing ips to inventory.txt") print(result) write("inventory.txt", result) Console.ok(".ok") return "" elif arg.list and arg.NAME is not None: if arg.short: vms = Vm.get_vms_by_group(arg.group) if vms is None: Console.error("no vms found for {}".format(arg.group)) else: print( Printer.list(vms, header=['Group', 'Vm'], order=['name', 'member'], output=arg.format)) else: groups = Vm.get_vms_by_group(arg.group) pprint(groups) vms = [] for group in groups: name = group["member"] vm = Vm.get_vm(name)[0] vm['cluster'] = arg.group if vm is not None: vms.append(vm) pprint(vms) if vms is None: Console.error("no vms found for {}".format(arg.group)) else: print( Printer.list(vms, order=[ 'name', 'cluster', 'flavor', 'image', 'status', 'user_id', 'floating_ip' ], output=arg.format)) return "" elif arg.setup: def push(from_path, vm): vm.ip = vm.floating_ip if vm.ip is not None: if arg.verbose: Console.info("Connecting to Instance at IP:" + format(vm.ip)) sshcommand = "scp" sshcommand += " -o StrictHostKeyChecking=no" sshcommand += " {:}".format(from_path) sshcommand += " {username}@{ip}:.ssh/authorized_keys".format( **vm) print(sshcommand) os.system(sshcommand) else: Console.error("No Public IPs found for the instance", traceflag=False) groups = Vm.get_vms_by_group(arg.group) pprint(groups) vms = [] for group in groups: name = group["member"] vm = Vm.get_vm(name)[0] vm['cluster'] = arg.group if vm is not None: vms.append(vm) pprint(vms) if vms is None: Console.error("no vms found for {}".format(arg.group)) else: print( Printer.list(vms, order=[ 'name', 'cluster', 'flavor', 'image', 'status', 'user_id', 'floating_ip' ], output=arg.format)) keys = "" for vm in vms: vm = dotdict(vm) cloud = vm.category if vm.username is None: vm.username = arguments[ "--username"] or Image.guess_username(arg.image) chameleon = "chameleon" in ConfigDict( filename="cloudmesh.yaml" )["cloudmesh"]["clouds"][cloud]["cm_host"] print("C", chameleon) if chameleon: vm.username = "******" elif vm.category == "azure": vm.username = ConfigDict( filename="cloudmesh.yaml")["cloudmesh"]["clouds"][ "azure"]["default"]["username"] else: if vm.username is None: Console.error( "Could not guess the username of the vm", traceflag=False) return Vm.set_login_user(name=vm.name, cloud=vm.category, username=vm.username) vm.ip = vm.floating_ip def execute(commands): if vm.ip is not None: if arg.verbose: Console.info("Connecting to Instance at IP:" + format(vm.ip)) sshcommand = "ssh" if arg.key is not None: sshcommand += " -i {:}".format(arg.key) sshcommand += " -o StrictHostKeyChecking=no" sshcommand += " {username}@{ip}".format(**vm) sshcommand += " \'{:}\'".format(commands) print(sshcommand) os.system(sshcommand) else: Console.error( "No Public IPs found for the instance", traceflag=False) def copy(commands): if vm.ip is not None: if arg.verbose: Console.info("Connecting to Instance at IP:" + format(vm.ip)) sshcommand = "scp" sshcommand += " -o StrictHostKeyChecking=no" sshcommand += " {username}@{ip}".format(**vm) sshcommand += ":{:}".format(commands) print(sshcommand) os.system(sshcommand) else: Console.error( "No Public IPs found for the instance", traceflag=False) def cat(filename): with open(path_expand(filename), 'r') as f: output = f.read() return output execute('cat /dev/zero | ssh-keygen -q -N ""') copy(".ssh/id_rsa.pub ~/.ssh/id_rsa_{name}.pub".format( **vm)) output = "~/.ssh/id_rsa_{name}.pub".format(**vm) keys = keys + cat(output) print("WRITE KEYS") keys = keys + cat("~/.ssh/id_rsa.pub") output = "~/.ssh/id_rsa_{group}.pub".format(**arg) write(output, keys) print("PUSH KEYS") for vm in vms: vm = dotdict(vm) push("~/.ssh/id_rsa_{group}.pub".format(**arg), vm) return ""
def do_ssh(self, args, arguments): """ :: Usage: ssh table ssh list [--format=FORMAT] ssh cat ssh register NAME PARAMETERS ssh ARGUMENTS conducts a ssh login on a machine while using a set of registered machines specified in ~/.ssh/config 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 resoource exists, it will be overwritten. The information will be written in /.ssh/config Options: -v verbose mode --format=FORMAT the format in which this list is given formats incluse table, json, yaml, dict [default: table] --user=USER overwrites the username that is specified in ~/.ssh/config --key=KEY The keyname as defined in the key list or a location that contains a pblic key Description: ssh list lists the hostsnames that are present in the ~/.ssh/config file ssh cat prints the ~/.ssh/config file ssh table prints contents of the ~/.ssh/config file in table format ssh register NAME PARAMETERS registers a host i ~/.ssh/config file Parameters are attribute=value pairs Note: Note yet implemented ssh ARGUMENTS executes the ssh command with the given arguments Example: ssh myhost conducts an ssh login to myhost if it is defined in ~/.ssh/config file """ # pprint(arguments) def read(filename=None): if filename is None: filename = "~/.ssh/config" with open(path_expand("~/.ssh/config"), "r") as f: content = f.readlines() return "".join(content) if arguments["list"]: output_format = arguments["--format"] banner('List SSH config hosts') hosts = ssh_config() for host in hosts.list(): print(host) elif arguments["table"]: content = read(filename="~/.ssh/config").split("\n") entries = [ ] def empty(): return { "host": None, "hostname": None, "user": None, "proxycommand": None, "serveraliveinterval": None, "localforward": None, "forwardx11": None } entry = empty() for line in content: line = line.strip() if line.startswith("#"): pass elif line.strip() == "": pass elif "Host " in line: hostname = line.strip().split("Host")[1] entry["host"] = hostname.strip() if entry is not None: entries.append(entry) entry = empty() else: attribute, value = line.strip().split(" ", 1) entry[attribute.lower()] = value.strip() pprint(entries) order = ["host", "hostname", "user", "proxycommand", "serveraliveinterval", "localforward", "forwardx11"] print(Printer.list(entries, order=order)) elif arguments["cat"]: print(read(filename="~/.ssh/config")) elif arguments["register"]: name = arguments["NAME"] parameters = arguments["PARAMETERS"] Console.ok('register {} {}'.format(name, parameters)) TODO.implement("Not implemented") else: # ssh ARGUMENTS... args = arguments["ARGUMENTS"] os.system("ssh {}".format(args)) return "" return ""
def do_register(self, args, arguments): """ :: Usage: register info register backup register new [--force] [--dryrun] register clean [--force] register list ssh [--format=FORMAT] register list [--yaml=FILENAME][--info][--format=FORMAT] register cat [--yaml=FILENAME] register edit [--yaml=FILENAME] register user [USERNAME] register cloud [CLOUD] [--force] register remote [CLOUD] [--force] register export HOST [--password] [--format=FORMAT] register source HOST register merge FILEPATH register form [--yaml=FILENAME] register check [--yaml=FILENAME] register test [--yaml=FILENAME] register json HOST register env [--provider=PROVIDER] register ec2 CLOUD EC2ZIP register ENTRY managing the registered clouds in the cloudmesh.yaml file. It looks for it in the current directory, and than in ~/.cloudmesh. If the file with the cloudmesh.yaml name is there it will use it. If neither location has one a new file will be created in ~/.cloudmesh/cloudmesh.yaml. Some defaults will be provided. However you will still need to fill it out with valid entries. Arguments: HOST the host name USER the user name FILEPATH the path of the file CLOUD the cloud name PROVIDER the provider or type of cloud [Default: openstack] USERNAME Username that would be registered in yaml. Defaults to OS username. Options: --provider=PROVIDER Provider to be used for cloud. Values are: openstack, azure, ec2. --version=VERSION Version of the openstack cloud. --openrc=OPENRC The location of the openrc file --password Prints the password --force ignore interactive questions and execute the action Description: register info lists the clouds specified in the cloudmesh.yaml file in the current directory, and then in ~/.cloudmesh register list [--yaml=FILENAME] [--name] [--info] lists the clouds specified in the cloudmesh.yaml file. If info is specified it also prints the location of the yaml file. register list ssh lists hosts from ~/.ssh/config register cat [--yaml=FILENAME] outputs the cloudmesh.yaml file register edit [--yaml=FILENAME] edits the cloudmesh.yaml file register export HOST [--format=FORMAT] prints the contents of an openrc.sh file based on the information found in the cloudmesh.yaml file. register remote CLOUD [--force] reads the Openstack OPENRC file from a remote host that is described in cloudmesh.yaml file. We assume that the file has already a template for this host. If not it can be created from other examples before you run this command. It uses the OS_OPENRC variable to locate the file and copy it onto your computer. register merge FILENAME Replaces the TBD in cloudmesh.yaml with the contents present in the named file register form [--yaml=FILENAME] interactively fills out the form wherever we find TBD. register check [--yaml=FILENAME] checks the yaml file for completness register test [--yaml=FILENAME] checks the yaml file and executes tests to check if we can use the cloud. TODO: maybe this should be in a test command register json host displays the host details in json format register remote CLOUD registers a remote cloud and copies the openrc file specified in the credentials of the cloudmesh.yaml register CLOUD --dir Copies the entire directory from the cloud and puts it in ~/.cloudmesh/clouds/host For kilo, The directory would be copied to ~/.cloudmesh/clouds/kilo register env [--provider=PROVIDER] [HOSTNAME] Reads env OS_* variables and registers a new cloud in yaml, interactively. Default PROVIDER is openstack and HOSTNAME is localhost. register user [USERNAME] Sets the user in yaml with the value provided. """ # from pprint import pprint # pprint(arguments) def _get_config_yaml_file(arguments): filename = arguments["--yaml"] or "cloudmesh.yaml" filename = Config.find_file(filename) return filename def exists(filename): return os.path.isfile(filename) def export(host, output): config = ConfigDict("cloudmesh.yaml") credentials = dict( config["cloudmesh"]["clouds"][host]["credentials"]) if not arguments["--password"]: credentials["OS_PASSWORD"] = "******" if output is None: for attribute, value in credentials.items(): print("export {}={}".format(attribute, value)) elif output == "table": print(Printer.attribute(credentials)) else: print(Printer.write(credentials, output=output)) # TODO: bug csv does not work if arguments["info"]: filename = _get_config_yaml_file(arguments) if os.path.isfile(filename): Console.ok("File '{}' exists. ok.".format(filename)) Console.ok("The yaml file contains the following templates:") d = CloudRegister.list(filename, Default.cloud, info=False, output="table") print(d) else: Console.error("File {} does not exist".format(filename)) return "" elif arguments["backup"]: name = backup_name("~/.cloudmesh/cloudmesh.yaml") configfile = path_expand("~/.cloudmesh/cloudmesh.yaml") print(name) try: copy(configfile, name) Console.ok("Bakup copy created: {}. ok.".format(name)) except: Console.error("Could not create a backup copy from {}".format( configfile)) return "" elif arguments["new"]: import shutil import cloudmesh_client.etc config = ConfigDict("cloudmesh.yaml") data = dotdict({ 'dir': cloudmesh_client.etc.__file__, 'filename': os.path.join(os.path.dirname(cloudmesh_client.etc.__file__), "cloudmesh.yaml"), 'yamlfile': path_expand("~/.cloudmesh/cloudmesh.yaml"), 'dryrun': arguments['--dryrun'] }) Console.ok(data.filename) force = arguments["--force"] if not force: force = yn_choice( "Would you like create a new configuration file at {}". format(data.yamlfile)) if force: if not data.dryrun: config.make_a_copy(location=data.yamlfile) shutil.copyfile(data.filename, data.yamlfile) print("copy ") print("From: ", data.filename) print("To: ", data.yamlfile) # filename = _get_config_yaml_file(arguments) # if _exists(filename): # Console.ok("File '{}' exists. ok.".format(filename)) # else: # Console.error("File {} does not exist".format(filename)) return "" elif arguments["clean"]: filename = _get_config_yaml_file(arguments) force = arguments["--force"] or False if filename is not None: print(filename, force) if exists(filename): print("Delete cloudmesh.yaml file:", filename) if not force: force = yn_choice("Would you like to delete the " "cloudmesh.yaml file") print(force) if force: os.remove(filename) Console.ok("Deleted the file " + filename + ". ok.") else: Console.ok("Please use Y to delete the file.") pass else: Console.error("File {} does not exist".format(filename)) else: Console.error("No cloudmesh.yaml file found.") return "" elif arguments["cat"]: filename = _get_config_yaml_file(arguments) if exists(filename): with open(filename, 'r') as f: lines = f.read().split("\n") print('\n'.join(lines)) else: Console.error("File {} does not exist".format(filename)) return "" elif arguments["edit"]: filename = _get_config_yaml_file(arguments) if exists(filename): try: data = { "editor": os.environ["EDITOR"], "filename": filename } Console.ok("editing file " + filename) os.system("{editor} {filename}".format(**data)) except: Console.error( "No operating system environment variable EDITOR set.", traceflag=False) else: Console.error("File {} does not exist".format(filename), traceflag=False) return "" elif arguments['list'] and arguments['ssh']: output = arguments['--format'] or 'table' hosts = CloudRegister.list_ssh() print(Printer.list(hosts, output=output)) return "" elif arguments['list']: filename = _get_config_yaml_file(arguments) info = arguments["--info"] or False output = arguments["--format"] or "table" if not filename: Console.error("File {} doesn't exist".format(filename)) else: d = CloudRegister.list(filename, Default.cloud, info=info, output=output) print(d) return "" elif arguments['check']: filename = _get_config_yaml_file(arguments) if not filename: Console.error("File {} doesn't exist".format( arguments["--yaml"] or 'cloudmesh.yaml')) else: CloudRegister.check_yaml_for_completeness(filename) return "" elif arguments['merge']: filename = arguments['FILENAME'] CloudRegister.from_file(filename) return "" elif arguments['test']: filename = _get_config_yaml_file(arguments) CloudRegister.test(filename) return "" elif arguments['form']: filename = _get_config_yaml_file(arguments) if not filename: Console.error("File {} doesn't exist".format( arguments["--yaml"] or 'cloudmesh.yaml')) else: CloudRegister.fill_out_form(filename) return "" elif arguments['source']: host = arguments['HOST'] config = ConfigDict("cloudmesh.yaml") credentials = dict( config["cloudmesh"]["clouds"][host]["credentials"]) # unset variables = list(os.environ) for attribute in variables: if attribute.startswith("OS_"): print("x ", attribute) del os.environ[attribute] # set for attribute, value in credentials.items(): os.putenv(attribute, value) print("+ ", attribute) export(host, "table") return "" elif arguments['export']: output = arguments['--format'] host = arguments['HOST'] try: variables = list(os.environ) for attribute in variables: if attribute.startswith("OS_"): print("unset ", attribute) del os.environ[attribute] export(host, output) except: Console.error("The export may not include all values", traceflag=False) return "" elif arguments['json']: host = arguments['HOST'] result = CloudRegister.get(host) if result: print(json.dumps(result, indent=4)) else: print("Cloud {:} is not described in cloudmesh.yaml".format( host)) return "" elif arguments['remote']: force = arguments['--force'] cloud = arguments['CLOUD'] if cloud is None: # clouds = [ConfigDict(filename="cloudmesh.yaml")["cloudmesh"]["active"][0]] clouds = ["kilo"] # hardcode to kilo for now else: clouds = [cloud] for cloud in clouds: CloudRegister.remote(cloud, force) export(cloud, "table") config = ConfigDict("cloudmesh.yaml") if config["cloudmesh.profile.user"] == "TBD": name = config["cloudmesh.clouds.kilo.credentials.OS_USERNAME"] config["cloudmesh"]["profile"]["user"] = name config.save() return "" elif arguments['ec2']: cloud = arguments['CLOUD'] zipfile = arguments['EC2ZIP'] if cloud is None: clouds = [ ConfigDict( filename="cloudmesh.yaml")["cloudmesh"]["active"][0] ] else: clouds = [cloud] for cloud in clouds: CloudRegister.ec2(cloud, zipfile) export(cloud, "table") return "" elif arguments['env']: try: CloudRegister.from_environ(arguments['--provider']) except Exception as e: Error.traceback(e) return "" elif arguments['cloud']: """ if arguments['--dir']: cloud = arguments['--name'] directory = arguments['--dir'] Console.ok(directory) CloudRegister.directory(cloud, directory) else: """ values_to_replace = ['tbd', 'null', 'tbd_not_used'] cloud = arguments['CLOUD'] if cloud is None: clouds = [ ConfigDict( filename="cloudmesh.yaml")["cloudmesh"]["active"][0] ] else: clouds = [cloud] for cloud in clouds: config = ConfigDict("cloudmesh.yaml") cloud_config = config["cloudmesh.clouds"][cloud] # Checking credentials print("Checking cloud credentials...") for prop in cloud_config["credentials"]: if cloud_config["credentials"][prop].lower( ) in values_to_replace: value = input(prop + "(" + cloud_config["credentials"][prop] + "): ") cloud_config["credentials"][prop] = value # Checking defaults print("Checking cloud defaults...") for prop in cloud_config["default"]: if cloud_config["default"][prop].lower( ) in values_to_replace: value = input(prop + "(" + cloud_config["default"][prop] + "): ") cloud_config["default"][prop] = value config.save() export(cloud, "table") return "" elif arguments['user']: username = arguments["USERNAME"] or getpass.getuser() CloudRegister.set_username(username) Console.ok("Setting profile user to {} in the yaml file.".format( username)) hosts = ssh_config() hosts.generate(key="india", username=username, verbose=True) return "" elif arguments['ENTRY'] is not None: name = arguments['ENTRY'] Register.entry(name) return "" # if all fails do a simple list filename = _get_config_yaml_file(arguments) CloudRegister.list(filename) pass