def test_inventory(self): HEADING() for output in ['dict', 'yaml', 'csv', 'table']: banner(output) print(self.i.list(format=output)) banner("changing values") self.i.add(host="i1", cluster="india", label="india") self.i.add(host="i2", cluster="india", label="gregor") self.i.add(host="d[1-4]", cluster="delta", label="delta") banner("saving") self.i.save() for output in ['dict', 'yaml', 'csv', 'table']: banner(output) print(self.i.list(format=output)) banner("reading") n = Inventory() n.read() t = n.list('table') print(t) assert "gregor" in str(t) assert "+" in str(t)
def __init__(self, inventory=None, cluster=None, debug=False, download_images=False): self.debug = debug self.manager_public_key = None # Populated by self.generate_ssh_key if inventory: self.inventory = Inventory(inventory) else: self.inventory = Inventory() if cluster is not None: self.nodes = self.inventory.find(cluster=cluster) else: self.nodes = self.inventory.find( service='manager') + self.inventory.find(service='worker') self.manager_public_key = None managers = self.inventory.find(service='manager') workers = self.inventory.find(service='worker') configs = managers + workers # Create dict for them for easy lookup self.configs = dict((config['host'], config) for config in configs) if download_images: self.get_images()
def __init__(self, inventory=None, names=None, ssid=None, wifipassword=None, force_inv=False, country=None): # Get inventory self.ssid = ssid self.wifipasswd = wifipassword if inventory is None: names = Parameter.expand(names) manager, workers = Host.get_hostnames(names) if workers: worker_base_name = ''.join( [i for i in workers[0] if not i.isdigit()]) cluster_name = manager or worker_base_name inventory = path_expand( f'~/.cloudmesh/inventory-{cluster_name}.yaml') if not os.path.exists(inventory) or force_inv: if not manager: Console.error("No inventory found. Can not create an " "inventory without a " "manager.") return "" Inventory.build_default_inventory(filename=inventory, manager=manager, workers=workers) inv = Inventory(filename=inventory) else: inv = Inventory(filename=inventory) self.inventory = inv # Find managers and workers managers = inv.find(service='manager') if len(managers) > 0: if not self.ssid: self.ssid = get_ssid() if self.ssid == "": Console.info('Could not determine SSID, skipping wifi ' 'config') self.ssid = None if not self.wifipasswd and self.ssid: self.wifipasswd = getpass(f"Using --SSID={self.ssid}, please " f"enter wifi password:") workers = inv.find(service='worker') # No inherenet need to distinguish the configs by service configs = managers + workers # Create dict for them for easy lookup self.configs = dict((config['host'], config) for config in configs) self.get_images() self.country = country if country else Shell.locale().upper()
def test_key_gen(self): HEADING() inv_file = '~/.cloudmesh/config_test.yaml' inv = Inventory(inv_file) inv.add_directory(host='test_host1', keyfile='~/.ssh/id_rsa.pub', service='manager') inv.save() c = Configure(inventory=inv_file) priv_key, pub_key = c.generate_ssh_key(hostname='test_host1') u = c.build_user_data(name='test_host1') keys = readfile(filename='~/.ssh/id_rsa.pub').strip().split('\n') t1 = Userdata()\ .with_authorized_keys(keys=keys)\ .with_ssh_password_login(ssh_pwauth=False)\ .with_locale()\ .with_net_tools()\ .with_hostname(hostname='test_host1')\ .with_hosts(hosts=['127.0.0.1:test_host1'])\ .with_packages(packages='avahi-daemon')\ .with_runcmd(cmd=f'cat /boot/firmware/id_rsa.pub > /home/ubuntu/.ssh/id_rsa.pub')\ .with_runcmd(cmd=f'cat /boot/firmware/id_rsa > /home/ubuntu/.ssh/id_rsa')\ .with_fix_user_dir_owner(user='******')\ .with_runcmd(cmd=f'chmod 600 /home/ubuntu/.ssh/id_rsa')\ .with_runcmd(cmd=f'sudo rm /boot/firmware/id_rsa.pub')\ .with_runcmd(cmd=f'sudo rm /boot/firmware/id_rsa') assert (t1.content == u.content) os.system("rm -f " + path_expand(inv_file))
def test_build_networkdata(self): HEADING() inv_file = '~/.cloudmesh/config_test.yaml' inv = Inventory(inv_file) inv.add_directory(host='test_host1', keyfile='~/.ssh/id_rsa.pub', service='manager', ip='10.1.1.11', router='10.1.1.1', dns=['8.8.8.8', '8.8.4.4']) inv.add_directory(host='test_host2', service='worker', ip='10.1.1.10', router='10.1.1.1', dns=['8.8.8.8', '8.8.4.4']) inv.save() c = Configure(inventory=inv_file) b1 = c.build_network_data(name='test_host1') b2 = c.build_network_data(name='test_host2') keys = readfile(filename='~/.ssh/id_rsa.pub').strip().split('\n') t1 = Networkdata()\ .with_defaults()\ .with_ip(ip='10.1.1.11')\ .with_nameservers(nameservers=['8.8.8.8', '8.8.4.4'])\ .with_gateway(gateway='10.1.1.1') t2 = Networkdata()\ .with_defaults()\ .with_ip(ip='10.1.1.10')\ .with_nameservers(nameservers=['8.8.8.8', '8.8.4.4'])\ .with_gateway(gateway='10.1.1.1') assert (t1.content == b1.content) assert (t2.content == b2.content) os.system("rm -f " + path_expand(inv_file))
def test_build_user_data(self): HEADING() inv_file = '~/.cloudmesh/config_test.yaml' inv = Inventory(inv_file) inv.add_directory(host='test_host1', keyfile='~/.ssh/id_rsa.pub', service='manager') inv.add_directory(host='test_host2', service='worker') inv.save() c = Configure(inventory=inv_file) b1 = c.build_user_data(name='test_host1') b2 = c.build_user_data(name='test_host2') keys = readfile(filename='~/.ssh/id_rsa.pub').strip().split('\n') t1 = Userdata()\ .with_authorized_keys(keys=keys)\ .with_ssh_password_login(ssh_pwauth=False)\ .with_locale()\ .with_net_tools()\ .with_hostname(hostname='test_host1')\ .with_hosts(hosts=['127.0.0.1:test_host1'])\ .with_packages(packages='avahi-daemon') t2 = Userdata()\ .with_default_user()\ .with_ssh_password_login()\ .with_locale()\ .with_net_tools()\ .with_hostname(hostname='test_host2')\ .with_hosts(hosts=['127.0.0.1:test_host2'])\ .with_packages(packages='avahi-daemon') assert (t1.content == b1.content) assert (t2.content == b2.content) os.system("rm -f " + path_expand(inv_file))
class Configure: """ This class serves to build cloud-init config files for entries in a cloudmesh inventory file. This accepts two params for init: inventory = INVENTORY_FILE cluster = CLUSTER_NAME If inventory arg is None, then default ~/.cloudmesh/inventory.yaml is used if cluster arg is not None, then nodes are found by searching via the "cluster" column in inventory if cluster arg is None, then nodes are found by searching for "worker" and "manager" in the "service" column in inventory Usage: config_generator = Configure() Configure.build_user_data(name=NAME) returns a Userdata builder object where NAME is the hostname of an entry in inventory.yaml with corresponding config options """ KEY_DIR = path_expand('~/.cloudmesh/cmburn') def __init__(self, inventory=None, cluster=None, debug=False, download_images=False): self.debug = debug self.manager_public_key = None # Populated by self.generate_ssh_key if inventory: self.inventory = Inventory(inventory) else: self.inventory = Inventory() if cluster is not None: self.nodes = self.inventory.find(cluster=cluster) else: self.nodes = self.inventory.find( service='manager') + self.inventory.find(service='worker') self.manager_public_key = None managers = self.inventory.find(service='manager') workers = self.inventory.find(service='worker') configs = managers + workers # Create dict for them for easy lookup self.configs = dict((config['host'], config) for config in configs) if download_images: self.get_images() def get_images(self): """ Downloads all tags found in self.configs """ tags = set() for config in self.configs.values(): try: tags.add(config['tag']) except KeyError as e: Console.warning( f'Could not find tag for {config["host"]}. Skipping') banner("Downloading Images", figlet=True) image = Image() for tag in tags: Console.info(f'Attempting to download {tag}') res = image.fetch(tag=[tag]) if not res: Console.error('Failed Image Fetch.') raise Exception('Failed Image Fetch') def build_user_data(self, name=None, with_defaults=True, country=None, add_manager_key=False, upgrade=False, with_bridge=False): """ Given a name, get its config from self.inventory and create a Userdata object """ if name is None: raise Exception('name arg supplied is None') elif not self.inventory.has_host(name): raise Exception( f'Could not find {name} in {self.inventory.filename}') if country is not None and len(country) != 2: raise Exception('Country code is not 2 characters.') # Get the current configurations from inventory hostname = self.inventory.get(name=name, attribute='host') keyfile = self.inventory.get(name=name, attribute='keyfile') if keyfile: keys = readfile(keyfile).strip().split('\n') else: keys = None if keys is None and add_manager_key: keys = [self.manager_public_key] elif add_manager_key: keys.append(self.manager_public_key) service = self.inventory.get(name=name, attribute='service') # Build Userdata user_data = Userdata() if with_defaults: user_data.with_locale().with_net_tools().with_packages( packages=['avahi-daemon', 'libraspberrypi-bin']) if upgrade: user_data.with_package_update().with_package_upgrade() if hostname: user_data.with_hostname(hostname=hostname) if keys: # Disable password auth in favor of key auth user_data.with_ssh_password_login(ssh_pwauth=False) user_data.with_authorized_keys(keys=keys) else: user_data.with_default_user().with_ssh_password_login() # Add known hosts user_data.with_hosts(hosts=self.get_hosts_for(name=name)) if country: user_data.with_set_wifi_country(country=country) if service == 'manager' and self.manager_public_key: # If public key is set, then we expect /boot/firmware/id_rsa and /boot/firmware/id_rsa.pub on burned card user_data.with_runcmd(cmd='cat /boot/firmware/id_rsa.pub > /home/ubuntu/.ssh/id_rsa.pub')\ .with_runcmd(cmd='cat /boot/firmware/id_rsa > /home/ubuntu/.ssh/id_rsa')\ .with_fix_user_dir_owner(user='******')\ .with_runcmd(cmd='chmod 600 /home/ubuntu/.ssh/id_rsa')\ .with_runcmd(cmd='sudo rm /boot/firmware/id_rsa.pub')\ .with_runcmd(cmd='sudo rm /boot/firmware/id_rsa') if with_bridge: user_data.with_access_point_bridge_nftables() if with_defaults: # disable cloud-init on subsequent boots user_data.with_runcmd( cmd='sudo touch /etc/cloud/cloud-init.disabled') if self.debug: Console.info(f'User data for {name}:\n' + str(user_data)) return user_data def build_network_data(self, name=None, ssid=None, password=None, with_defaults=True): """ Given a name, get its config from self.inventory and create a Networkdata object """ if name is None: raise Exception('name arg supplied is None') elif not self.inventory.has_host(name): raise Exception( f'Could not find {name} in {self.inventory.filename}') if ssid or password: if not ssid or not password: raise Exception( "ssid or password supplied with no corresponding ssid or password" ) # Get the current configurations from inventory eth0_ip = self.inventory.get(name=name, attribute='ip') eth0_nameservers = self.inventory.get(name=name, attribute='dns') eth0_gateway = self.inventory.get(name=name, attribute='router') network_data = Networkdata() if with_defaults: network_data.with_defaults() if eth0_ip: network_data.with_ip(ip=eth0_ip) if eth0_nameservers: network_data.with_nameservers(nameservers=eth0_nameservers) if eth0_gateway: network_data.with_gateway(gateway=eth0_gateway) if ssid and password: Console.info(f'Providing WiFi access to {name}') network_data.with_access_points(ssid=ssid, password=password)\ .with_dhcp4(interfaces='wifis', interface='wlan0', dhcp4=True)\ .with_optional(interfaces='wifis', interface='wlan0', optional=True) if self.debug: Console.info(f'Network data for {name}:\n' + str(network_data)) return network_data def get_hosts_for(self, name=None): """ Given a hostname, return a list of ':' separated strings of the form: ip:hostname for all hosts with ips in the inventory. Also includes mapping for own hostname in the form of 127.0.0.1:{name} For example, if inventory has worker001 with ip 10.1.1.1, worker002 with ip 10.1.1.2, worker003 with ip 10.1.1.3, then: self.get_hosts_for(name='worker001') returns ['127.0.0.1:worker001', '10.1.1.2:worker002', '10.1.1.3:worker003'] Do not rely on the order of the result here """ if name is None: raise Exception('name arg supplied is None') if not self.inventory.has_host(name): raise Exception( f'{name} could not be found in {self.inventory.filename}') result = [f'127.0.0.1:{name}'] for node in self.nodes: if node['ip'] and name != node['host']: host = node['host'] ip = node['ip'] result += [f'{ip}:{host}'] return result def generate_ssh_key(self, hostname): Shell.execute('mkdir', f'-p {Configure.KEY_DIR}') Shell.run(f'ssh-keygen -q -N "" -C "ubuntu@{hostname}" -f ' f'{Configure.KEY_DIR}/id_rsa') priv_key = readfile(f'{Configure.KEY_DIR}/id_rsa').strip() pub_key = readfile(f'{Configure.KEY_DIR}/id_rsa.pub').strip() self.manager_public_key = pub_key Shell.execute('rm', path_expand(f'{Configure.KEY_DIR}/id_rsa')) Shell.execute('rm', path_expand(f'{Configure.KEY_DIR}/id_rsa.pub')) return priv_key, pub_key
def do_inventory(self, args, arguments): """ :: Usage: inventory add cluster NAMES inventory add NAMES [--label=LABEL] [--services=SERVICES] [--project=PROJECT] [--owners=OWNERS] [--comment=COMMENT] [--inventory=INVENTORY] [--cluster=CLUSTER] [--ip=IP] [--service=SERVICE] [--tag=TAG] [--keyfile=KEYFILE] [--router=ROUTER] [--locale=LOCALE] [--timezone=TIMEZONE] inventory create TAG [--hostnames=NAMES] [--ip=IP] [--inventory=INVENTORY] [--keyfile=KEYFILE] inventory set NAMES ATTRIBUTE to VALUES [--inventory=INVENTORY] [--listvalue] inventory delete NAMES [--inventory=INVENTORY] inventory clone NAMES from SOURCE [--inventory=INVENTORY] inventory list [NAMES] [--format=FORMAT] [--columns=COLUMNS] [--inventory=INVENTORY] inventory info [--inventory=INVENTORY] inventory remove --inventory=INVENTORY Arguments: NAMES Name of the resources (example i[10-20]) FORMAT The format of the output is either txt, yaml, dict, table [default: table]. OWNERS a comma separated list of owners for this resource LABEL a unique label for this resource SERVICE a string that identifies the service PROJECT a string that identifies the project SOURCE a single host name to clone from COMMENT a comment Options: -v verbose mode --keyfile=KEYFILE Keyfile to assign [default: ~/.ssh/id_rsa.pub] Description: add -- adds a resource to the resource inventory list -- lists the resources in the given format delete -- deletes objects from the table clone -- copies the content of an existing object and creates new once with it set -- sets for the specified objects the attribute to the given value or values. If multiple values are used the values are assigned to the and objects in order. See examples map -- allows to set attributes on a set of objects with a set of values Examples: cms inventory add x[0-3] --service=openstack adds hosts x0, x1, x2, x3 and puts the string openstack into the service column cms inventory list lists the repository cms inventory set x[3-4] temperature to 32 sets for the resources x3, x4 the value of the temperature to 32 cms inventory set x[7-8] ip to 128.0.0.[0-1] sets the value of x7 to 128.0.0.0 sets the value of x8 to 128.0.0.1 cms inventory set x1 services to bridge,kubernetes --listvalue sets the value of x1 to [bridge, kubernetes] The --listvalue option indicates the value set is a list cms inventory clone x[5-6] from x3 clones the values for x5, x6 from x3 """ map_parameters(arguments, "columns", 'ip', 'hostnames', 'inventory', 'keyfile', 'listvalue') if arguments.info: if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() i.info() elif arguments.remove and arguments.inventory: os.system("rm -f " + path_expand(f'~/.cloudmesh/{arguments.inventory}')) elif arguments.NAMES is not None and arguments.list: hosts = Parameter.expand(arguments.NAMES) if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() d = dict(i.data) r = {} for key in d: if key in hosts: r[key] = d[key] pprint(r) i.data = r if arguments["--columns"]: order = arguments["--columns"].split(",") else: order = i.order print(i.list(format="table", order=order)) # elif arguments["set"]: # hosts = hostlist.expand_hostlist(arguments.NAMES) # i = inventory() # i.read() # element = {} # for attribute in i.order: # try: # attribute = arguments["ATTRIBUTE"] # value = arguments["VALUE"] # if value is not None: # element[attribute] = value # except: # pass # element['host'] = arguments.NAMES # i.add(**element) # print (i.list(format="table")) elif arguments.create: tag = arguments.TAG hostnames = Parameter.expand(arguments.hostnames) manager, workers = Host.get_hostnames(hostnames) ips = Parameter.expand(arguments.ip) if len(ips) != len(hostnames): Console.error( "The number of hosts does not match the number of ips") return keyfile = arguments.keyfile or '~/.ssh/id_rsa.pub' if arguments.inventory is None: arguments.inventory = "inventory.yaml" if manager is None: manager_ip = None worker_ips = ips else: manager_ip = ips[0] worker_ips = ips[1:] worker_hostnames = workers if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() inventory_name = arguments.inventory.split('.')[0] i.add(host=manager, name=manager, tag=tag, cluster=inventory_name, service='manager', ip=manager_ip, keyfile=keyfile, status="inactive") for worker, ip in zip(worker_hostnames, worker_ips): i.add(host=worker, name=worker, tag=tag, cluster=inventory_name, service='worker', ip=ip, keyfile=keyfile, status="inactive") # noqa: E124 i.save() Console.ok( f"Successfuly saved to ~/.cloudmesh/{arguments.inventory}") elif arguments.list: if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() if arguments["--columns"]: order = arguments["--columns"].split(",") else: order = i.order print(i.list(format="table", order=order)) elif arguments.set: hosts = Parameter.expand(arguments.NAMES) values = Parameter.expand(arguments.VALUES) if len(values) == 1: values = values * len(hosts) attribute = arguments.ATTRIBUTE if not arguments.listvalue and len(hosts) != len(values): Console.error( "Number of names {:} != number of values{:}".format( len(hosts), len(values))) if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() for index in range(0, len(hosts)): host = hosts[index] value = values if arguments.listvalue else values[index] if not i.has_host(host): i.add(host=host) i.set(host, attribute, value) # object = {'host': host, # attribute: value} # i.add(**object) i.save() print(i.list(format="table")) elif arguments.add and arguments.cluster: names = Parameter.expand(arguments.NAMES) manager, workers = Host.get_hostnames(names) if manager is None: Console.error( "A manager node is required. Numbers are not allowed in a manger name, " "i.e. red is an acceptable manager name, red00 is not.") return if workers: worker_base_name = ''.join( [i for i in workers[0] if not i.isdigit()]) cluster_name = manager or worker_base_name inventory = path_expand( f'~/.cloudmesh/inventory-{cluster_name}.yaml') Inventory.build_default_inventory(filename=inventory, manager=manager, workers=workers) elif arguments.add: hosts = Parameter.expand(arguments.NAMES) if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() element = {} for attribute in i.order: try: value = arguments["--" + attribute] if value is not None: element[attribute] = value except Exception as e: # noqa: F841 pass element['host'] = arguments.NAMES element['status'] = 'inactive' i.add(**element) i.save() print(i.list(format="table")) elif arguments.delete: hosts = Parameter.expand(arguments.NAMES) if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() for host in hosts: i.delete(host) i.save() elif arguments.clone: hosts = Parameter.expand(arguments.NAMES) source = arguments.SOURCE if arguments.inventory is None: i = Inventory() else: i = Inventory(f'~/.cloudmesh/{arguments.inventory}') i.read() if source in i.data: for host in hosts: i.data[host] = dict(i.data[source]) i.save() else: Console.error("The source {:} does not exist".format(source)) return ""
def run(self): Sudo.password() host = None ips = None hostnames = None key = None event = None tags = None kind = None device = None while True: event, values = self.window.read() if event in ("Cancel", 'cancel', None): if not self.no_diagram: rack_file = f"~/.cloudmesh/gui/{self.manager}-rack.png" net_file = f"~/.cloudmesh/gui/{self.manager}-net.png" os.remove(path_expand(rack_file)) os.remove(path_expand(net_file)) break # # UPDATE OS SELECTION # if event.startswith("os"): for image in values: if image.startswith("os") and values[image]: break self.logger(f"Switch OS to: {image}") image_manager = image_tags[image]["manager"] image_worker = image_tags[image]["worker"] self.window[f'tags-{self.manager}'].update(image_manager) for worker in self.workers: self.window[f'tags-{worker}'].update(image_worker) self.window.Refresh() if event.startswith("button"): # # set imaged string # imaged = values['imaged'] if not imaged: self.imaged_str = "--imaged" else: self.imaged_str = "" # # handle device, hostnames and ips # ips = [] hostnames = [] tags = [] for entry in values: if str(entry).startswith("name"): hostnames.append(values[entry]) if str(entry).startswith("ip"): ips.append(values[entry]) if str(entry).startswith("device-") and values[entry]: device = "/dev/" + entry.replace("device-", "") if str(entry).startswith("tag") and values[entry]: tags.append(values[entry]) key = values['key'] self.hostnames_str = ','.join(hostnames) self.ips_str = ','.join(ips) # # get the ssid # self.ssid = values['ssid'] self.wifipassword = values['wifi'] host = event.replace("button-", "") self.set_button_color(host, 'grey') if host == self.manager: kind = "manager" else: kind = "worker" print() print("Host: ", host) print("IPs: ", ips) print("Hostnames", hostnames) print("Ssid: ", self.ssid) print("Key: ", key) print("Event: ", event) print("Tags: ", tags) print("Kind: ", kind) print("Device: ", device) print("Format ", imaged) print() # Call burn function for manager and workers self.logger(f"Burning {kind} {host}") # tags = values[f'tags-{host}'] self.window[f'status-{host}'].update(' Burning ') if not self.no_diagram: self.update_diagram_colors(self.manager, host, "blue") self.hostnames_str = ','.join(hostnames) self.ips_str = ','.join(ips) # command = f"cms burn cluster --device={device}" \ # f" --hostname={self.hostnames_str}" \ # f" --ssid={self.ssid}" \ # f" --wifipassword={self.wifipassword}" \ # f" --ip={self.ips_str}" \ # f" --burning={host}" \ # " -y" \ # f" {self.imaged_str}" manager, workers = Host.get_hostnames(hostnames) filename = path_expand(f"~/.cloudmesh/inventory-{manager}.yaml") Inventory.build_default_inventory(filename=filename, manager=manager, workers=workers, ips=ips, gui_images=tags) if "ubuntu" in tags[0]: os_cmd = 'ubuntu' else: os_cmd = 'raspberry' if host == manager: command = f"cms burn {os_cmd} {host}" \ f" --device={device}" \ f" --ssid={self.ssid}" \ f" --wifipassword={self.wifipassword}" \ f" --country={Shell.locale().upper()}" else: command = f"cms burn {os_cmd} {host}" \ f" --device={device}" print(command) try: self.logger(f"Executing: {command}") if self.dryrun: time.sleep(0.5) else: os.system(command) self.window[f'status-{host}'].update(' Completed ') if not self.no_diagram: self.update_diagram_colors(self.manager, host, "green") self.set_button_color(host, 'green') except Exception as e: print(e) self.logger("Command failed") if not self.no_diagram: self.update_diagram_colors(self.manager, host, "orange") self.set_button_color(host, 'red') self.window.FindElement(f'button-{host}').Update(button_color=('white', 'green')) self.window.Refresh() print('exit') self.window.close()
# # fab queue.start:1 # python t.py # from cloudmesh.provisioner.queue.celery import celery from cloudmesh.provisioner.queue.tasks import info, provision from cloudmesh.inventory.inventory import FabricImage, FabricServer, \ FabricService, Inventory inventory = Inventory("nosetest") import hostlist import time from pprint import pprint """ t = info.delay() print t.status for i in range(10): time.sleep(1) print t.status if t.status == 'SUCCESS': break print t.get() """ inventory.print_cluster("bravo") hosts = hostlist.expand_hostlist("b-[001-008]")
class Test_inventory: def setup(self): self.i = Inventory('~/.cloudmesh/test.yaml') self.i.info() def test_add(self): HEADING(txt="cms inventory add") cluster = "test_cluster" label = "test{j}" host = "red00{j}" ip = "10.1.1.{j}" dns = "8.8.8.8" # Adding one by one for j in range(1, 4): self.i.add( host=host.format(j=j), cluster=cluster, dns=dns, label=label.format(j=j), ip=ip.format(j=j), ) for j in range(1, 4): host_name = host.format(j=j) assert self.i.has_host(host_name) entry = self.i.data[host_name] assert entry['cluster'] == cluster assert entry['ip'] == ip.format(j=j) assert entry['label'] == label.format(j=j) assert entry['dns'] == dns # Multi add self.i.add(host=host.format(j='[4-7]'), cluster=cluster, ip=ip.format(j='[4-7]')) for j in range(4, 8): host_name = host.format(j=j) assert self.i.has_host(host_name) entry = self.i.data[host_name] assert entry['cluster'] == cluster assert entry['ip'] == ip.format(j=j) self.i.save() def test_list(self): HEADING(txt="cms inventory list") # for output in ['dict', 'yaml', 'csv', 'table']: # bug in 'csv' print in cloudmesh-common for output in ['dict', 'yaml', 'table']: banner(output) print(self.i.list(format=output)) t = str(self.i.list('table')) for order in self.i.order: assert order in t def test_set(self): HEADING() self.i.set("red002", "service", "worker") assert self.i.get("red002", "service") == "worker" self.i.save() def test_find(self): HEADING() assert len(self.i.find(host="red002")) > 0
def setup(self): self.i = Inventory() banner("Info") self.i.info()
def do_inventory(self, args, arguments): """ :: Usage: inventory add NAMES [--label=LABEL] [--service=SERVICES] [--project=PROJECT] [--owners=OWNERS] [--comment=COMMENT] [--cluster=CLUSTER] [--ip=IP] inventory set NAMES ATTRIBUTE to VALUES inventory delete NAMES inventory clone NAMES from SOURCE inventory list [NAMES] [--format=FORMAT] [--columns=COLUMNS] inventory info Arguments: NAMES Name of the resources (example i[10-20]) FORMAT The format of the output is either txt, yaml, dict, table [default: table]. OWNERS a comma separated list of owners for this resource LABEL a unique label for this resource SERVICE a string that identifies the service PROJECT a string that identifies the project SOURCE a single host name to clone from COMMENT a comment Options: -v verbose mode Description: add -- adds a resource to the resource inventory list -- lists the resources in the given format delete -- deletes objects from the table clone -- copies the content of an existing object and creates new once with it set -- sets for the specified objects the attribute to the given value or values. If multiple values are used the values are assigned to the and objects in order. See examples map -- allows to set attributes on a set of objects with a set of values Examples: cms inventory add x[0-3] --service=openstack adds hosts x0, x1, x2, x3 and puts the string openstack into the service column cms inventory lists lists the repository cms inventory x[3-4] set temperature to 32 sets for the resources x3, x4 the value of the temperature to 32 cms inventory x[7-8] set ip 128.0.0.[0-1] sets the value of x7 to 128.0.0.0 sets the value of x8 to 128.0.0.1 cms inventory clone x[5-6] from x3 clones the values for x5, x6 from x3 """ map_parameters(arguments, "columns") # # TODO: fix config reader, use cmd4 # filename = Config(config_path="/cloudmesh_inventory.yaml") sorted_keys = True if arguments.info: i = Inventory() i.read() i.info() elif arguments.NAMES is not None and arguments.list: hosts = Parameter.expand(arguments.NAMES) print(hosts) i = Inventory() i.read() d = dict(i.data) r = {} for key in d: if key in hosts: r[key] = d[key] pprint(r) i.data = r if arguments["--columns"]: order = arguments["--columns"].split(",") else: order = i.order print(i.list(format="table", order=order)) # elif arguments["set"]: # hosts = hostlist.expand_hostlist(arguments.NAMES) # i = inventory() # i.read() # element = {} # for attribute in i.order: # try: # attribute = arguments["ATTRIBUTE"] # value = arguments["VALUE"] # if value is not None: # element[attribute] = value # except: # pass # element['host'] = arguments.NAMES # i.add(**element) # print (i.list(format="table")) elif arguments.list: i = Inventory() i.read() if arguments["--columns"]: order = arguments["--columns"].split(",") else: order = i.order print(i.list(format="table", order=order)) elif arguments.set: hosts = Parameter.expand(arguments.NAMES) values = Parameter.expand(arguments.VALUES) if len(values) == 1: values = values * len(hosts) print(hosts) print(values) attribute = arguments.ATTRIBUTE if len(hosts) != len(values): Console.error( "Number of names {:} != number of values{:}".format( len(hosts), len(values))) i = Inventory() i.read() for index in range(0, len(hosts)): host = hosts[index] value = values[index] object = {'host': host, attribute: value} i.add(**object) print(i.list(format="table")) elif arguments.add: hosts = Parameter.expand(arguments.NAMES) i = Inventory() i.read() element = {} for attribute in i.order: try: value = arguments["--" + attribute] if value is not None: element[attribute] = value except: pass element['host'] = arguments.NAMES i.add(**element) print(i.list(format="table")) elif arguments.delete: hosts = Parameter.expand(arguments.NAMES) i = Inventory() i.read() for host in hosts: del i.data[host] i.save() elif arguments.clone: hosts = Parameter.expand(arguments.NAMES) source = arguments.SOURCE i = Inventory() i.read() if source in i.data: for host in hosts: i.data[host] = dict(i.data[source]) i.save() else: Console.error("The source {:} does not exist".format(source)) return ""
def do_pi(self, args, arguments): """ :: Usage: pi ssh HOSTS pi setup1 HOSTS pi setup2 HOSTS pi setupmaster HOSTS pi cmd HOSTS pi label MASTER HOSTS Arguments: HOSTS hostlist Description: This command configures Pis for Kubernetes clusters. pi ssh HOSTS: Launch an interactive SSH session on each host. When you logout from one host, it will automatically SSH to the next host in the list. pi setup1 HOSTS: Run part 1 of Kubernetes setup on the hosts. pi setup2 HOSTS: Run part 2 of Kubernetes setup on the hosts. pi setupmaster HOSTS: Configure the HOSTS as Kubernetes masters. HOSTS will probably just be one hostname here. pi cmd HOSTS: Run CMD on every host via SSH. CMD is specified on stdin. For example: $ echo "uname -a" | cms pi cmd pi[1-5] pi label MASTER HOSTS: SSH to master node and label all worker nodes (HOSTS) as workers. """ hosts = Parameter.expand(arguments.HOSTS) inv = Inventory() inv.read() inv = inv.list() ips = self.get_host_ips(hosts, inv) if ips == None: # error return "" if arguments.ssh: self.run_many_commands(ips, ['']) elif arguments.setup1: self.setup_1(ips) elif arguments.setup2: self.setup_2(ips) elif arguments.setupmaster: self.setup_master(ips) elif arguments.cmd: # [:-1] to ignore the \n at the end of stdin self.run_many_commands(ips, [sys.stdin.read()[:-1]]) elif arguments.label: master_ip = self.get_host_ips([arguments.MASTER], inv)[0] self.label_nodes(master_ip, hosts)
def setup(self): self.i = Inventory('~/.cloudmesh/test.yaml') self.i.info()
def do_burn(self, args, arguments): """ :: Usage: burn gui [--hostname=HOSTNAME] [--ip=IP] [--ssid=SSID] [--wifipassword=PSK] [--bs=BLOCKSIZE] [--dryrun] [--no_diagram] burn ubuntu NAMES [--inventory=INVENTORY] [--ssid=SSID] [-f] [--wifipassword=PSK] [-v] --device=DEVICE [--country=COUNTRY] [--upgrade] burn raspberry NAMES --device=DEVICE [--inventory=INVENTORY] [--ssid=SSID] [--wifipassword=PSK] [--country=COUNTRY] [--password=PASSWORD] [-v] [-f] burn firmware check burn firmware update burn install burn load --device=DEVICE burn format --device=DEVICE burn imager [TAG...] burn mount [--device=DEVICE] [--os=OS] burn unmount [--device=DEVICE] [--os=OS] burn network list [--ip=IP] [--used] burn network burn info [--device=DEVICE] burn image versions [--details] [--refresh] [--yaml] burn image ls burn image delete [--image=IMAGE] burn image get [--url=URL] [TAG...] burn backup [--device=DEVICE] [--to=DESTINATION] burn copy [--device=DEVICE] [--from=DESTINATION] burn shrink [--image=IMAGE] burn cluster --device=DEVICE --hostname=HOSTNAME [--burning=BURNING] [--ip=IP] [--ssid=SSID] [--wifipassword=PSK] [--bs=BLOCKSIZE] [--os=OS] [-y] [--imaged] [--set_passwd] burn create [--image=IMAGE] [--device=DEVICE] [--burning=BURNING] [--hostname=HOSTNAME] [--ip=IP] [--sshkey=KEY] [--blocksize=BLOCKSIZE] [--passwd=PASSWD] [--ssid=SSID] [--wifipassword=PSK] [--format] [--tag=TAG] [--inventory=INVENTORY] [--name=NAME] [-y] burn sdcard [TAG...] [--device=DEVICE] [-y] burn set [--hostname=HOSTNAME] [--ip=IP] [--key=KEY] [--keyboard=COUNTRY] [--cmdline=CMDLINE] burn enable ssh burn wifi --ssid=SSID [--passwd=PASSWD] [--country=COUNTRY] burn check [--device=DEVICE] burn mac --hostname=HOSTNAME Options: -h --help Show this screen. --version Show version. --image=IMAGE The image filename, e.g. 2019-09-26-raspbian-buster.img --device=DEVICE The device, e.g. /dev/sdX --hostname=HOSTNAME The hostnames of the cluster --ip=IP The IP addresses of the cluster --key=KEY The name of the SSH key file --blocksize=BLOCKSIZE The blocksise to burn [default: 4M] --burning=BURNING The hosts to be burned Arguments: TAG Keyword tags to identify an image Files: This is not fully thought through and needs to be documented ~/.cloudmesh/images Location where the images will be stored for reuse Description: cms burn create --inventory=INVENTORY --device=DEVICE --name=NAME Will refer to a specified cloudmesh inventory file (see cms help inventory). Will search the configurations for NAME inside of INVENTORY and will burn to DEVICE. Supports parameter expansion. cms burn create --passwd=PASSWD if the passwd flag is added the default password is queried from the commandline and added to all SDCards if the flag is omitted login via the password is disabled and only login via the sshkey is allowed Network cms burn network list Lists the ip addresses that are on the same network +------------+---------------+----------+-----------+ | Name | IP | Status | Latency | |------------+---------------+----------+-----------| | Router | 192.168.1.1 | up | 0.0092s | | iPhone | 192.168.1.4 | up | 0.061s | | red01 | 192.168.1.46 | up | 0.0077s | | laptop | 192.168.1.78 | up | 0.058s | | unkown | 192.168.1.126 | up | 0.14s | | red03 | 192.168.1.158 | up | 0.0037s | | red02 | 192.168.1.199 | up | 0.0046s | | red | 192.168.1.249 | up | 0.00021s | +------------+----------------+----------+-----------+ cms burn network list [--used] Lists the used ip addresses as a comma separated parameter list 192.168.50.1,192.168.50.4,... cms burn network address Lists the own network address +---------+----------------+----------------+ | Label | Local | Broadcast | |---------+----------------+----------------| | wlan0 | 192.168.1.12 | 192.168.1.255 | +---------+----------------+----------------+ cms burn firmware check Checks if the firmware on the Pi is up to date cms burn firmware update Checks and updates the firmware on the Pi cms burn install Installs a program to shrink img files. THis is useful, after you created a backup to make the backup smaller and allow faster burning in case of recovery This command is not supported on MacOS cms burn load --device=DEVICE Loads the sdcard into the USB drive. Thi sis similar to loading a cdrom drive. It s the opposite to eject cms burn format --device=DEVICE Formats the SDCard in the specified device. Be careful it is the correct device. cms burn info will help you to identifying it cms burn mount [--device=DEVICE] [--os=OS] Mounts the file systems available on the SDCard cms burn unmount [--device=DEVICE] [--os=OS] Unmounts the mounted file systems from the SDCard cms burn info [--device=DEVICE] Provides useful information about the SDCard cms burn image versions [--refresh] [--yaml] The images that you like to burn onto your SDCard can be cached locally with the image command. The available images for the PI can be found when using the --refresh option. If you do not specify it it reads a copy of the image list from our cache cms burn image ls Lists all downloaded images in our cache. You can download them with the cms burn image get command cms burn image delete [--image=IMAGE] Deletes the specified image. The name can be found with the image ls command cms burn image get [--url=URL] [TAG...] Downloads a specific image or the latest image. The tag are a number of words separated by a space that must occur in the tag that you find in the versions command cms burn backup [--device=DEVICE] [--to=DESTINATION] This command requires you to install pishrink previously with cms burn install Backs up a SDCard to the given location. cms burn copy [--device=DEVICE] [--from=DESTINATION] Copies the file form the destination on the SDCard this is the same as the SDCard command. we will in future remove one cms burn shrink [--image=IMAGE] Shrinks the size of a backup or image file that is on your local file system. It can only be used for .img files This command is not supported on MacOS. cms burn create [--image=IMAGE] [--device=DEVICE] [--hostname=HOSTNAME] [--ip=IP] [--sshkey=KEY] [--blocksize=BLOCKSIZE] [--passwd=PASSWD] [--ssid=SSID] [--wifipassword=PSK] [--format] This command not only can format the SDCard, but also initializes it with specific values cms burn sdcard [TAG...] [--device=DEVICE] this burns the sd card, see also copy and create cms burn set [--hostname=HOSTNAME] [--ip=IP] [--key=KEY] [--mount=MOUNTPOINT] [--keyboard=COUNTRY] [--cmdline=CMDLINE] Sets specific values on the sdcard after it has ben created with the create, copy or sdcard command a --ssh is missing from this command cms burn enable ssh [--mount=MOUNTPOINT] Enables the ssh server once it is booted cms burn wifi --ssid=SSID [--passwd=PASSWD] [--country=COUNTRY] Sets the wifi ssid and password after the card is created, copied, or the sdcard is used. The option country option expects an ISO 3166-1 two digit country code. The default is "US" and the option not required if suitable. See https://en.wikipedia.org/wiki/ISO_3166-1 for other countries. cms burn check [--device=DEVICE] Lists the parameters that were set with the set or create command Examples: ( \\ is not shown) > cms burn create --image=2019-09-26-raspbian-buster-lite > --device=/dev/mmcblk0 > --hostname=red[5-7] > --ip=192.168.1.[5-7] > --sshkey=id_rsa > cms burn image get latest > cms burn image get https://downloads.raspberrypi.org/ > raspbian_lite/images/ > raspbian_lite-2018-10-11/2018-10-09-raspbian-stretch-lite.zip > cms burn image delete 2019-09-26-raspbian-buster-lite """ map_parameters(arguments, "details", "refresh", "device", "dryrun", "burning", "hostname", "ip", "sshkey", "blocksize", "ssid", "url", "imaged", "key", "keyboard", "passwd", "wifipassword", "version", "to", "os", "country", "inventory", "name", "bs", "set_passwd", "cmdline", "upgrade", "no_diagram") # arguments.MOUNTPOINT = arguments["--mount"] arguments.FORMAT = arguments["--format"] arguments.FROM = arguments["--from"] arguments.IMAGE = arguments["--image"] arguments.output = "table" # hard code for now arguments.bs = arguments.bs or "4M" arguments.yes = arguments["-y"] if len(arguments.TAG) == 0: arguments.TAG = "latest" # VERBOSE(arguments) def execute(label, function): StopWatch.start(label) result = function StopWatch.stop(label) StopWatch.status(label, True) return result burner = Burner() sdcard = SDCard() if arguments.imager: arguments.TAG = arguments.TAG or ["latest-lite"] Console.msg(f"Tags: {arguments.TAG}") try: file = Imager.fetch(tag=arguments.TAG) except: # noqa: E722 pass try: Imager.launch(file=file) except Exception as e: Console.error( f"could not find image with the tag {arguments.TAG}\n\n{e}\n" ) return "" elif arguments.gui: from cloudmesh.burn.gui import Gui VERBOSE(arguments) g = Gui(hostname=arguments.hostname, ip=arguments.ip, dryrun=arguments.dryrun, no_diagram=arguments.no_diagram) g.run() return "" elif arguments.raspberry: banner(txt="RaspberryOS Burn", figlet=True) if arguments.inventory: inv_path = path_expand(f'~/.cloudmesh/{arguments.inventory}') try: burner = RaspberryBurner( inventory=inv_path, ssid=arguments['--ssid'], wifipassword=arguments['--wifipassword'], country=arguments['--country']) except: Console.error('Burner Error') return "" else: try: burner = RaspberryBurner( names=arguments.NAMES, ssid=arguments['--ssid'], wifipassword=arguments['--wifipassword'], force_inv=arguments['-f'], country=arguments['--country']) except Exception as e: Console.error('Burner Error') raise e return "" execute( "burn raspberry", burner.multi_burn( names=arguments.NAMES, devices=arguments.device, verbose=arguments['-v'], password=arguments['--password'], )) return "" elif arguments.ubuntu: banner(txt="Ubuntu Burn with cloud-init", figlet=True) names = Parameter.expand(arguments.NAMES) if len(Parameter.expand(arguments.device)) > 1: Console.error( "Too many devices specified. Please only specify one") return "" if arguments.inventory: c = Configure(inventory=arguments.inventory, debug=arguments['-v']) inv = Inventory(filename=arguments.inventory) else: names = Parameter.expand(arguments.NAMES) manager, workers = Host.get_hostnames(names) if workers: worker_base_name = ''.join( [i for i in workers[0] if not i.isdigit()]) cluster_name = manager or worker_base_name inventory = path_expand( f'~/.cloudmesh/inventory-{cluster_name}.yaml') if not os.path.exists(inventory) or arguments['-f']: if not manager: Console.error("No inventory found. Can not create an " "inventory without a " "manager.") return "" Inventory.build_default_inventory( filename=inventory, manager=manager, workers=workers, manager_image='ubuntu-20.10-64-bit', worker_image='ubuntu-20.10-64-bit') c = Configure(inventory=inventory, debug=arguments['-v'], download_images=True) inv = Inventory(filename=inventory) names = Parameter.expand(arguments.NAMES) manager, workers = Host.get_hostnames(names) if manager: if not arguments.ssid and 'wifi' in c.configs[manager][ 'services']: arguments.ssid = get_ssid() if arguments.ssid == "": Console.info('Could not determine SSID, skipping wifi ' 'config') arguments.ssid = None if not arguments.wifipassword and arguments.ssid is not None: arguments.country = Shell.locale().upper() arguments.wifipassword = getpass( f"Using --SSID=" f"{arguments.ssid} and " f" --COUNTRY=" f"{arguments.country}, please " f"enter wifi password:"******"" if 'ubuntu' not in tag: Console.error( "This command only supports burning ubuntu cards") return "" sdcard = SDCard(card_os="ubuntu") # Code below taken from arguments.sdcard try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" # determine if we are burning a manager, as this needs to be done # first to get the ssh public key # manager = False # for name in names: # if not inv.has_host(name): # Console.error(f'Could not find {name} in inventory {inv.filename}') # return "" # service = inv.get(name=name, attribute='service') # if service == 'manager' and not manager: # manager = name # # make manager first in names # names.remove(name) # names.insert(0, name) # elif service == 'manager' and manager: # raise Exception('More than one manager detected in NAMES') for name in names: if not yn_choice( f'Is the card to be burned for {name} inserted?'): if not yn_choice( f"Please insert the card to be burned for {name}. " "Type 'y' when done or 'n' to terminante"): Console.error("Terminating: User Break") return "" service = inv.get(name=name, attribute='service') # Make sure bridge is only enabled if WiFi enabled if service == 'manager': services = inv.get(name=name, attribute='services') if 'bridge' in services and not arguments.ssid: Console.error( 'Service bridge can only be configured if WiFi' ' is enabled with --ssid and --wifipassword') return "" else: enable_bridge = 'bridge' in services Console.info(f'Burning {name}') sdcard.format_device(device=arguments.device, yes=True) sdcard.unmount(device=arguments.device) sdcard.burn_sdcard(tag=tag, device=arguments.device, yes=True) sdcard.mount(device=arguments.device, card_os="ubuntu") if service == 'manager': # Generate a private public key pair for the manager that will be persistently used # priv_key, pub_key = c.generate_ssh_key(name) # Write priv_key and pub_key to /boot/id_rsa and /boot/id_rsa.pub # SDCard.writefile(filename=f'{sdcard.boot_volume}/id_rsa', content=priv_key) # SDCard.writefile(filename=f'{sdcard.boot_volume}/id_rsa.pub', content=pub_key) c.build_user_data( name=name, country=arguments.country, upgrade=arguments.upgrade, with_bridge=enable_bridge).write( filename=sdcard.boot_volume + '/user-data') c.build_network_data(name=name, ssid=arguments.ssid, password=arguments.wifipassword)\ .write(filename=sdcard.boot_volume + '/network-config') else: c.build_user_data( name=name, add_manager_key=manager, upgrade=arguments.upgrade).write( filename=sdcard.boot_volume + '/user-data') c.build_network_data(name=name).write( filename=sdcard.boot_volume + '/network-config') time.sleep( 1 ) # Sleep for 1 seconds to give ample time for writing to finish sdcard.unmount(device=arguments.device, card_os="ubuntu") Console.info("Remove card") Console.ok(f"Burned {len(names)} card(s)") return "" elif arguments.firmware and arguments.check: execute("firmware check", burner.firmware(action="check")) return "" elif arguments.firmware and arguments.update: execute("firmware update", burner.firmware(action="update")) return "" if arguments.check: execute("check", burner.check(device=arguments.device)) return "" elif arguments.versions and arguments['image']: StopWatch.start("image versions") result = Image.create_version_cache(refresh=arguments["--refresh"]) output = "table" if arguments["--yaml"]: output = "yaml" order = ["tag", 'date', "os", "type", 'version'] header = ["Tag", 'Date', "OS", "Type", 'Version'] if arguments.details: order = ["tag", 'date', "os", "type", 'version', "url"] header = ["Tag", 'Date', "OS", "Type", 'Version', "Url"] print( Printer.write(result, order=order, header=header, output=output)) StopWatch.stop("image versions") StopWatch.status("image versions", True) return "" elif arguments.load: execute("load", sdcard.load_device(device=arguments.device)) return "" elif arguments[ "format"]: # as format is a python word, we need to use an index execute( "format", sdcard.format_device(device=arguments.device, unmount=True)) return "" elif arguments.network and arguments["list"]: if os_is_mac(): Console.error("Not yet implemented on MacOS") return "" ip = arguments.ip or Network.address()[0]['local'] details = Network.nmap(ip=ip) if arguments.used: print(','.join([x['ip'] for x in details])) else: print( Printer.write(details, order=[ 'name', "ip", "status", "latency", ], header=[ 'Name', "IP", "Status", "Latency", ])) return "" elif arguments.network: if os_is_mac(): Console.error("Not yet implemented on MacOS") return "" # print (Network.nmap()) details = Network.address() print( Printer.write(details, order=['label', "local", "broadcast"], header=["Label", "Local", "Broadcast"])) return "" elif arguments.wifi: password = arguments.passwd ssid = arguments.ssid or get_ssid() country = arguments.country if password is None: password = getpass("Please enter the Wifi password or enter " "for no password: "******"macos" elif os_is_linux(): host = "linux" elif os_is_pi(): host = "raspberry" else: Console.error( "This command is not yet implemented for your OS") return "" burner.configure_wifi(ssid, psk=password, country=country, host=host) return "" elif arguments.info: output = arguments.output or "table" card = SDCard() execute("info", card.info(output=output)) try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" return "" elif arguments.install: if os_is_mac(): Console.error("Not yet implemented on MacOS") return "" execute("install", burner.install()) return "" elif arguments.shrink: if os_is_mac(): Console.error("Not yet implemented on MacOS") return "" execute("shrink", burner.shrink(image=arguments.IMAGE)) return "" elif arguments.backup: try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" execute( "backup", sdcard.backup(device=arguments.device, to_file=arguments.to)) return "" elif arguments[ "copy"]: # as copy is a reserved word we need to use the index USB.check_for_readers() execute( "copy", sdcard.copy(device=arguments.device, from_file=arguments.FROM)) return "" elif arguments.sdcard: try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" if arguments.device is None: card = SDCard() card.info() Console.error("Please specify a device") return "" arguments.TAG = arguments.TAG or ["latest-lite"] if any("ubuntu" in tag for tag in arguments.TAG): sdcard = SDCard(card_os="ubuntu") execute( "format", sdcard.format_device(device=arguments.device, unmount=True)) execute("unmount", sdcard.unmount(device=arguments.device)) execute( "sdcard", sdcard.burn_sdcard(tag=arguments.TAG, device=arguments.device, yes=arguments.yes)) return "" elif arguments.mount: if arguments.device is None: card = SDCard card.info() Console.error("Please specify a device") return "" execute( "mount", sdcard.mount(device=arguments.device, card_os=arguments.os)) return "" elif arguments.unmount: card = SDCard(card_os=arguments.os) execute( "unmount", card.unmount(device=arguments.device, card_os=arguments.os)) return "" elif arguments.mac: hostnames = Parameter.expand(arguments.hostname) execute("mac", burner.mac(hostnames=hostnames)) return "" elif arguments.set: try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" if arguments.hostname: execute("set hostname", burner.set_hostname(arguments.hostname)) if arguments.ip: execute("set ip", burner.set_static_ip(arguments.ip)) if arguments.key: execute("set key", burner.set_key(arguments.key)) if arguments.keyboard: execute("set keyboard", burner.keyboard(country=arguments.keyboard)) if arguments.cmdline: execute("set cmdline", burner.set_cmdline(arguments.cmdline)) return "" elif arguments.enable and arguments.ssh: try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" execute("enable ssh", burner.enable_ssh()) return "" # elif arguments.versions and arguments.image: # image = Image() elif arguments.ls and arguments['image']: execute("image ls", Image().ls()) return "" elif arguments.delete and arguments.IMAGE: execute("image rm", Image().rm(arguments.IMAGE)) return "" elif arguments["get"] and arguments['image'] and arguments["--url"]: image = Image() execute("image fetch", image.fetch(url=arguments.url)) return "" elif arguments["get"] and arguments['image'] and arguments["TAG"]: tag = arguments["TAG"] if "latest" in tag and ("full" in tag or "lite" in tag): result = Image.create_version_cache( refresh=arguments["--refresh"]) image = Image() execute("image fetch", image.fetch(tag=arguments["TAG"])) return "" elif arguments["get"] and arguments['image']: image = Image() execute("image fetch", image.fetch(tag="latest")) return "" elif arguments.cluster: # is true when # # cms burn cluster --hostname=red,red00[1-2] # --device=/dev/sdb # --ip=10.1.1.[1-3] # --ssid=myssid # --wifipassword=mypass # try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" execute("cluster", burner.cluster(arguments=arguments)) return "" elif arguments.create and arguments.inventory: try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" if not os_is_pi(): print() Console.error( "This command has only been written for a Raspberry Pis. " "Terminating for caution") print() if yn_choice("Continue anyways?"): pass else: return if not arguments.name: Console.error( "Missing --name parameter. See cms help burn for usage") return "" if not arguments.device: Console.error( "Missing --device parameter. See cms help burn for usage") return "" StopWatch.start("burn inventory") multi_burner = MultiBurner() # Perhaps we want to change the path at some point inventory = f"~/.cloudmesh/{arguments.inventory}" multi_burner.burn_inventory(inventory=inventory, name=arguments.name, device=arguments.device, yes=arguments.yes, passwd=arguments.passwd) StopWatch.stop("burn inventory") StopWatch.status("burn inventory", True) StopWatch.benchmark(sysinfo=False, csv=False) return "" elif arguments.create: try: USB.check_for_readers() except Exception as e: print() Console.error(e) print() return "" if arguments["--passwd"]: passwd = arguments["--passwd"] elif "PASSWD" in os.environ: passwd = os.environ["PASSWD"] else: passwd = generate_strong_pass() psk = None if arguments["--ssid"]: ssid = arguments["--ssid"] if arguments["--wifipassword"]: psk = arguments["--wifipassword"] else: psk = None else: if arguments["--wifipassword"]: print("Can't have wifi password with no ssid") return else: ssid = None image = 'latest' or arguments.IMAGE dev = os.environ['DEV'] if 'DEV' in os.environ else None devices = arguments["--device"] or dev or None if devices is not None: devices = Parameter.expand_string(devices) hostnames = Parameter.expand(arguments.hostname) if arguments.burnimg is None: burning = hostnames else: burning = arguments.burning VERBOSE(arguments) ips = None if not arguments.ip else Parameter.expand(arguments.ip) key = arguments.sshkey tag = arguments['--tag'] if os_is_pi() or os_is_linux(): blocksize = arguments.blocksize StopWatch.start("total") multi = MultiBurner() multi.burn_all( burning=burning, image=image, device=devices, blocksize=blocksize, progress=True, hostnames=hostnames, # not difference between names and name, maybe we should align ips=ips, key=key, password=passwd, ssid=ssid, psk=psk, tag=tag, yes=arguments.yes) StopWatch.stop("total") StopWatch.status("total", True) StopWatch.benchmark(sysinfo=False, csv=False) else: Console.error( "This command is only supported ona Pi and Linux") return "" Console.error("see manual page: cms help burn") return ""