def install(repos, dev=False): repos = OrderedSet(repos) for repo in repos: StopWatch.start("install " + repo) if dev: banner(f"dev install -> {repo}") Console.info(f"pip install -e .: {repo}") print() os.chdir(repo) os.system("pip install -e .") os.chdir("../") StopWatch.status("install " + repo, True) else: banner(f"install -> {repo}") Console.info(f"pip install: {repo}") print() os.system("pip install {repo}".format(repo=repo)) StopWatch.status("install " + repo, True) StopWatch.stop("install " + repo)
def test_stopwatch_1(self): HEADING() StopWatch.start("stopwatch sleep 1") time.sleep(0.1) StopWatch.stop("stopwatch sleep 1") StopWatch.status("stopwatch sleep 1", True) assert True
def ping(self, processors=1): StopWatch.start(f"total p={processors} c=1") r = Host.ping(hosts, processors=processors, count=1) StopWatch.stop(f"total p={processors} c=1") StopWatch.status(f"total p={processors} c=1", r[0]['success']) return r
def ssh(self, processors=1): StopWatch.start(f"total p={processors} c=1") r = Host.ssh(hosts, command="hostname", processors=processors) StopWatch.stop(f"total p={processors} c=1") StopWatch.status(f"total p={processors} c=1", r[0]["success"]) return r
def test_awstogoogleDir(self): HEADING() sourcecloud = "aws" targetcloud = "google" sourceFile = "uploadtest1.txt" targetFile = "a2/testAwsToGoogle.txt" StopWatch.start("aws_to_google_directory") awsProvider = Provider(service=sourcecloud) try: testResult = awsProvider.copyFiles(source_cloud=sourcecloud, source_file=sourceFile, target_cloud=targetcloud, target_file=targetFile) StopWatch.status("aws_to_google_directory", "Success") finally: StopWatch.stop("aws_to_google_directory")
def test_googletoaws(self): HEADING() sourcecloud = "google" targetcloud = "aws" for fileSize in fileSizes: targetFile = f"{sourcecloud}_to_{targetcloud}_fileSize_{fileSize}.txt" sourceFile = f'local_to_google_fileSize_{fileSize}.txt' StopWatch.start(targetFile) provider = Provider(service=sourcecloud) try: testResult = provider.copyFiles(source_cloud=sourcecloud, source_file=sourceFile, target_cloud=targetcloud, target_file=targetFile) StopWatch.status(targetFile, "Success") finally: StopWatch.stop(targetFile)
def test_googletoawsDir2(self): HEADING() sourcecloud = "google" targetcloud = "aws" sourceFile = "a1/testfolder/" targetFile = "a1/testfolder2/" StopWatch.start("google_to_aws_directory2") awsProvider = Provider(service=sourcecloud) try: testResult = awsProvider.copyFiles(source_cloud=sourcecloud, source_file=sourceFile, target_cloud=targetcloud, target_file=targetFile) StopWatch.status("google_to_aws_directory2", "Success") finally: StopWatch.stop("google_to_aws_directory2")
def test_stopwatch_loop(self): HEADING() cumulate = False dt = 0.1 n = 10 for i in range(0, n): StopWatch.start("stopwatch loop") time.sleep(dt) StopWatch.stop("stopwatch loop") StopWatch.status("stopwatch loop", True) t = StopWatch.get("stopwatch loop") print(t) assert t >= dt t = StopWatch.sum("stopwatch loop", digits=4) print(t) assert t >= n * dt
def test_googletolocal(self): HEADING() local_test = "~/.cloudmesh/storage/test" sourcecloud = "google" targetcloud = "local" for fileSize in fileSizes: targetFileName = f"{sourcecloud}_to_{targetcloud}_fileSize_{fileSize}.txt" targetFile = path_expand(f'{local_test}/{targetFileName}') sourceFile = f'local_to_google_fileSize_{fileSize}.txt' StopWatch.start(targetFileName) provider = Provider(service=sourcecloud) try: testResult = provider.copyFiles(source_cloud=sourcecloud, source_file=sourceFile, target_cloud=targetcloud, target_file=targetFile) StopWatch.status(targetFileName, "Success") finally: StopWatch.stop(targetFileName)
def test_localtoaws(self): HEADING() local_test = "~/.cloudmesh/storage/test" sourcecloud = "local" targetcloud = "aws" for fileSize in fileSizes: sourceFile = path_expand( f'{local_test}/test_file_size_{fileSize}.txt') # targetFile = f'local_to_aws_fileSize_{fileSize}.txt' targetFile = f'{sourcecloud}_to_{targetcloud}_fileSize_{fileSize}.txt' StopWatch.start(targetFile) provider = Provider(service=sourcecloud) try: testResult = provider.copyFiles(source_cloud=sourcecloud, source_file=sourceFile, target_cloud=targetcloud, target_file=targetFile) StopWatch.status(targetFile, "Success") finally: StopWatch.stop(targetFile)
def test_internal_ping(self): HEADING() StopWatch.start("total _ping") for host in hosts: location = { 'ip': host, 'count': 1, } StopWatch.start(f"ping {host}") result = Host._ping(location) StopWatch.stop(f"ping {host}") StopWatch.status(f"ping {host}", result['success']) StopWatch.stop("total _ping") StopWatch.status("total _ping", True) if b'Access denied' in result['stdout'] and sys.platform == "win32": print("ERROR: This test must be run in an administrative " "terminal") assert result['success']
def _install_dnsmasq(cls): """ Uses apt-get to install package dnsmasq :return: """ if cls.dryrun: Console.info('Installing dnsmasq...') else: banner(""" Installing dnsmasq. Please wait for installation to complete. """) StopWatch.start('install dnsmasq') # cls._system(f'sudo apt-get install -y dnsmasq') # Use os.system to display the installation feedback os.system('sudo apt-get install -y dnsmasq') StopWatch.stop('install dnsmasq') StopWatch.status('install dnsmasq', True) Console.ok("Finished installing dnsmasq")
def execute(label, function): StopWatch.start(label) result = function StopWatch.stop(label) StopWatch.status(label, True) return result
def test_stopwatch_2(self): HEADING() StopWatch.start("stopwatch sleep 2") time.sleep(0.1) StopWatch.stop("stopwatch sleep 2") StopWatch.status("stopwatch sleep 2", True)
def _configure_worker_interfaces(cls, worker, user='******'): """ Configures the network interface of the worker to use the master as an internet gateway :param worker: A single string hostname for the worker (ie. --hostname option from cm-pi-burn) :param user: The user we will use to ssh/scp into the worker :return: """ if cls.dryrun: Console.info("Configuring worker info.") Console.info(f"scp /etc/network/interfaces from {cls.master} to {user}@{worker}") Console.info("Configure default gateway and DNS for {cls.priv_interface} on {user}@{worker}") else: # Get gateway and netmask for worker conf = cls._system('ifconfig') conf = conf.split('\n') # Search for priv_interface info = None for i in range(len(conf)): if cls.priv_interface in conf[i]: info = conf[i + 1].split() if info == None: Console.error(f"Interface {cls.priv_interface} not found") sys.exit(1) elif info[0] != 'inet': Console.error(f"Interface {cls.priv_interface} found, but there appears to be no iPv4 connection") sys.exit(1) else: # info ex: ['inet', '192.168.1.34', 'netmask', '255.255.255.0', 'broadcast', '192.168.1.255'] gateway = info[1] netmask = info[3] # Use scp to get /etc/network/interfaces from worker cls._system('mkdir -p ~/.cloudmesh/tmp') tmp = f'~/.cloudmesh/tmp/{worker}-interfaces.tmp' ignore_setting = '-o "StrictHostKeyChecking no"' StopWatch.start(f'Talking to {user}@{worker}') exit_code = cls._system(f'scp {ignore_setting} {user}@{worker}:/etc/network/interfaces {tmp}', exitcode=True) StopWatch.stop(f'Talking to {user}@{worker}') StopWatch.status(f'Talking to {user}@{worker}', exit_code == 0) # Write new interfaces file try: interfaces = readfile(tmp).rstrip().split('\n') except: Console.error(f"Could not open {tmp}") sys.exit(1) try: ind = interfaces.index(f'auto {cls.priv_interface}') except: Console.error(f"Could not find {cls.priv_interface} configuration in interfaces file") interface_config = [line.lstrip() for line in interfaces[ind: ind + 3]] interface_config.append(f'gateway {gateway}') interface_config.append(f'netmask {netmask}') dnss = " ".join(cls.dns) + "\n" interface_config.append(f'dns-nameservers {dnss}') new_config = interfaces[:ind] + interface_config writefile(tmp, '\n'.join(new_config)) # New config file now written on local machine. Move to worker in tmp directory remote_cmd1 = 'mkdir -p ~/.cloudmesh/tmp' remote_path = '~/.cloudmesh/tmp/interface.tmp' cls._system(f'ssh {ignore_setting} {user}@{worker} {remote_cmd1}') cls._system(f'scp {ignore_setting} {tmp} {user}@{worker}:{remote_path}') remote_cmd2 = 'sudo cp ~/.cloudmesh/tmp/interface.tmp /etc/network/interfaces' cls._system(f'ssh {ignore_setting} {user}@{worker} {remote_cmd2}')
def create(cls, masterIP='10.1.1.1', ip_range=['10.1.1.2', '10.1.1.122'], master=None, workers=None, priv_interface='eth0', ext_interface='eth1', purge=False, dryrun=False): """ if worker(s) is missing the master is set up only :param master: expected to be a single string :param workers: :param ext_interface: The external interface through which the master connects to the internet :param priv_interface: The private interface through which the master and workers communicate :param dryrun: :return: """ cls.masterIP = masterIP cls.ip_range = ip_range cls.master = master cls.workers = workers cls.dryrun = dryrun cls.ext_interface = ext_interface cls.priv_interface = priv_interface # Master configuration StopWatch.start('Master Configuration') # Configure dhcpcd.conf of master. No restart StopWatch.start('dhcpcd.conf configuration') cls._dhcpcd_conf() StopWatch.stop('dhcpcd.conf configuration') StopWatch.status('dhcpcd.conf configuration', True) if purge: # Uninstall dnsmasq and all files StopWatch.start('dnsmasq purge') cls._purge_dnsmasq() StopWatch.start('dnsmasq purge') StopWatch.status('dnsmasq purge', True) # Install dnsmasq if it is not already installed if not cls._dnsmasq_exists(): StopWatch.start('dnsmasq installation') cls._install_dnsmasq() StopWatch.stop('dnsmasq installation') StopWatch.status('dnsmasq installation', True) else: Console.info("dnsmasq already installed. Skipping installation") # Configure dnsmasq StopWatch.start('dnsmasq config') cls._config_dnsmasq() StopWatch.stop('dnsmasq config') StopWatch.status('dnsmasq config', True) # iPv4 forwarding StopWatch.start('Enable iPv4 forwarding') cls._set_ipv4() StopWatch.stop('Enable iPv4 forwarding') StopWatch.status('Enable iPv4 forwarding', True) # iptables configuration StopWatch.start('iptables configuration') cls._set_iptables() StopWatch.stop('iptables configuration') StopWatch.status('iptables configuration', True) StopWatch.stop('Master Configuration') StopWatch.status('Master Configuration', True) Console.info("Finished configuration of master") cls._completion_message() Console.ok("Process completed")
def do_bridge(self, args, arguments): """ :: Usage: bridge create [--interface=INTERFACE] [--ip=IPADDRESS] [--range=IPRANGE] [--purge] bridge set HOSTS ADDRESSES bridge restart [--nohup] [--background] bridge status bridge test HOSTS [--rate=RATE] bridge list NAMES bridge check NAMES [--configuration] [--connection] bridge info Arguments: HOSTS Hostnames of connected devices. Ex. red002 Ex. red[002-003] ADDRESSES IP addresses to assign to HOSTS. Addresses should be in the network range configured. Ex. 10.1.1.2 Ex. 10.1.1.[2-3] NAMES A parameterized list of hosts. The first hostname in the list is the master through which the traffic is routed. Example: blue,blue[002-003] Options: --interface=INTERFACE The interface name [default: eth1] You can also specify wlan0 if you wnat to bridge through WIFI on the master eth0 requires a USB to WIFI adapter --ip=IPADDRESS The ip address [default: 10.1.1.1] to assign the master on the interface. Ex. 10.1.1.1 --range=IPRANGE The inclusive range of IPs [default: 10.1.1.2-10.1.1.122] that can be assigned to connecting devices. Value should be a comma separated tuple of the two range bounds. Should not include the ip of the master Ex. 10.1.1.2-10.1.1.20 --workers=WORKERS The parametrized hostnames of workers attatched to the bridge. Ex. red002 Ex. red[002-003] --purge Include option if a full reinstallation of dnsmasq is desired --background Runs the restart command in the background. stdout to bridge_restart.log --nohup Restarts only the dnsmasq portion of the bridge. This is done to surely prevent SIGHUP if using ssh. --rate=RATE The rate in seconds for repeating the test If ommitted its done just once. Description: Command used to set up a bride so that all nodes route the traffic trough the master PI. bridge create [--interface=INTERFACE] [--ip=IPADDRESS] [--range=IPRANGE] creates the bridge on the current device The create command does not restart the network. bridge set HOSTS ADDRESSES the set command assigns the given static ip addresses to the given hostnames. bridge status Returns the status of the bridge and its linked services. bridge restart [--nohup] restarts the bridge on the master without rebooting. bridge test NAMES A test to see if the bridges are configured correctly and one hase internet access on teh specified hosts. bridge list NAMES Lists information about the bridges (may not be needed) bridge check NAMES [--config] [--connection] provides information about the network configuration and netwokrk access. Thisis not a comprehensive speedtest for which we use test. bridge info prints relevant information about the configured bridge Design Changes: We still may need the master to be part of other commands in case for example the check is different for master and worker """ map_parameters(arguments, 'interface', 'ip', 'range', 'workers', 'purge', 'nohup') if arguments.set: StopWatch.start('Static IP assignment') addresses = Parameter.expand(arguments.ADDRESSES) hosts = Parameter.expand(arguments.HOSTS) Bridge.set(workers=hosts, addresses=addresses) banner(f""" You have successfuly set static ip(s) for {arguments.HOSTS} with ips {arguments.ADDRESSES} To see changes on server, run: $ cms bridge restart --nohup If {arguments.HOSTS} is connected already, restart bridge then reboot {arguments.HOSTS}. """, color='CYAN') StopWatch.stop('Static IP assignment') StopWatch.status('Static IP assignment', True) elif arguments.status: StopWatch.start('Status') Bridge.status() StopWatch.stop('Status') elif arguments.create: StopWatch.start('Bridge Creation') Bridge.create(masterIP=arguments.ip, ip_range=arguments.range.split("-"), priv_interface='eth0', ext_interface=arguments.interface, purge=True if arguments.purge else False) StopWatch.stop('Bridge Creation') StopWatch.status('Bridge Creation', True) banner(textwrap.dedent(f""" You have now configured a bridge on your master pi. To see the changes reflected, run the following command: cms bridge restart """), color='CYAN') elif arguments.info: StopWatch.start('info') Bridge.info() StopWatch.stop('info') StopWatch.status('info', True) elif arguments.test: StopWatch.start('test') hosts = Parameter.expand(arguments.HOSTS) banner("Test command", color='CYAN') Bridge.test(hosts) StopWatch.stop('test') StopWatch.status('test', True) elif arguments.restart: background = True if arguments.background else False nohup = True if arguments.nohup else False if background: if nohup: os.system( 'nohup cms bridge restart --nohup > bridge_restart.log 2>&1 &' ) else: os.system( 'nohup cms bridge restart > brige_restart.log 2>&1 &') else: StopWatch.start('Network Service Restart') workers = Parameter.expand(arguments.workers) Bridge.restart(workers=workers, nohup=nohup) StopWatch.stop('Network Service Restart') StopWatch.status('Network Service Restart', True) elif arguments.list: banner("list") elif arguments.check: banner('Check') StopWatch.stop('command') StopWatch.status('command', True) StopWatch.status('load', True) # StopWatch.benchmark(sysinfo=False, csv=False) return ""
def Stop(): """ stops a timer while using the name of the calling method """ StopWatch.stop(Benchmark.name(with_class=True)) StopWatch.status(Benchmark.name(with_class=True), True)
def main(): arguments = docopt(__doc__) bundle = arguments["BUNDLE"] benchmark = arguments["--benchmark"] arguments["DIR"] = \ os.path.expandvars(os.path.expanduser(arguments.get("DIR") or '.')) arguments["LOCATION"] = \ os.path.expandvars(os.path.expanduser( arguments.get("LOCATION") or '~/.ssh/id_rsa.pub')) colorama.init(autoreset=True) if debug: banner("BEGIN ARGUMENTS") pprint(arguments) banner("END ARGUMENTS") WARNING = "WARNING WARNING WARNING WARNING WARNING" # # FIND ALL GIT REPOS IN cwd # global repos repos["all"] = get_all_repos() # # FIND ALL GIT REPOS that start with cloudmesh # bundles = arguments["BUNDLES"] def _get_bundles(): repositories = [] bundles = arguments["BUNDLES"] for bundle in bundles: check_for_bundle(bundle) repositories += repos[bundle] return repositories repos["cloudmesh"] = [] for repo in repos["all"]: if repo.startswith("cloudmesh-"): repos["cloudmesh"].append(repo) if arguments["version"]: print(insatller_version) elif arguments[ "list"] and not arguments["BUNDLE"] and not arguments["--git"]: if not arguments["--short"]: banner("Cloudmesh Bundles") block = "" for bundle in repos: block = block + bundle_elements(bundle) print(block) else: print(bundle_list(repos)) elif arguments["list"] and arguments["--git"]: check_for_bundle(bundle) print(bundle) banner(f" {bundle}") for entry in repos[bundle]: location = Git.url(entry) print(f"{location}.git") elif arguments["list"] and arguments["BUNDLE"]: bundle = arguments["BUNDLE"] if bundle in repos: print(bundle_elements(bundle)) else: print(f"ERROR: could not find bundle {bundle}") print("Available bundles: ") print(" ".join(repos.keys())) return "" elif arguments["info"]: verbose = arguments["--verbose"] native = hasattr(sys, 'real_prefix') executable = sys.executable if native: banner(WARNING, c=Fore.RED) print() RED("You are likely not running in a venv. " "Please remember that for " "development purposes we recommend you run in a venv. " "Please consult with our handbook on how to set one up") print() print("We found python in:") print(executable) print() print(70 * '-') print() # print("info") # packages = ["cloudmesh-common", "cloudmesh-cmd5", "cloudmesh-cloud"] bundle = arguments["BUNDLE"] or "cms" data = [["Package", "Git", "Pypi", "Installed"]] packages = repos[bundle] for package in packages: undefined = Fore.RED + "not found" + Style.RESET_ALL entry = [ package, undefined, # "git": undefined, # "PYPI" undefined, # "installed" ] if verbose: print(f"\nVersion -> {package}") # # GIT # try: v = requests.get( "https://raw.githubusercontent.com/cloudmesh" "/{package}/master/VERSION".format(package=package)).text entry[1] = v except: v = "ERROR: can not find git version" finally: if '404' in v: v = "ERROR: can not find git version" if verbose: print("... Github Version ->", v) # # PYPI # try: v = requests.get("https://pypi.org/project/{package}/".format( package=package)).text pat_str = '(.*)<h1 class="package-header__name">(.+?)</h1>(.*)' pattern = re.compile(pat_str, re.M | re.I | re.S) groups = re.match(pattern, v) # print (groups) v = (groups.group(2)).strip().split(package)[1].strip() entry[2] = v except: v = "ERROR: can not find pypi version" data.append(entry) if verbose: print("... Pypi Version ->", v) # # INSTALLED # try: installed = run(f"pip freeze | grep {package}", verbose=False).strip() entry[3] = installed except: installed = "ERROR: can not find installed version" if verbose: print("... Installed Version ->", installed) if verbose: print(70 * "-") print() print(tabulate(data, headers="firstrow")) print() elif arguments["status"] and arguments["git"]: repositories = _get_bundles() Git.status(repositories) elif arguments["clone"] and arguments["git"]: repositories = _get_bundles() result = Git.clone(repositories) elif arguments["pull"] and arguments["git"]: repositories = _get_bundles() Git.pull(repositories) elif arguments["key"] and arguments["git"]: try: location = arguments["LOCATION"] print("Key location:", location) if not location.endswith(".pub"): ERROR("make sure you specify a public key") sys.exit(1) key_contents = open(location).read() print() print("Make sure you copy the content between the lines to github") print(70 * "-") print(key_contents.strip()) print(70 * "-") print( "Please copy the content now, so you can use it in the browser." ) print() if yn_question( "would you like to open a web page to github to upload the key (yes/n)? " ): webbrowser.open_new("https://github.com/settings/keys") if yn_question("Is the key missing (yes/n)? "): print("Paste the key in the next window and submit.") webbrowser.open_new("https://github.com/settings/ssh/new") except: print(" you must have a key and upload it to github.") print("To generate the key use ssh-keygen") print("To avoid typing in the password all the time, use ssh-add") elif arguments["get"] or arguments["update"]: repositories = _get_bundles() Git.get(repositories) # if benchmark: # StopWatch.benchmark(sysinfo=True) elif arguments["install"]: banner(f"Installing bundles: {bundles}") repositories = OrderedSet(_get_bundles()) print('\n'.join(repositories)) print() if arguments["--venv"]: result = Git.install(repositories) else: result = Git.install(repositories, dev=True) StopWatch.benchmark(sysinfo=True) elif arguments["release"]: testing = "TESTING" in os.environ if testing: del os.environ["TESTING"] os.system("pip install twine") repos = arguments["REPOS"] repositories = [] for repository in repos: repositories.append(f"cloudmesh-{repository}") banner(f"Releasing repositories: {repositories}") print('\n'.join(repositories)) print() result = Git._command(repositories, "make patch") result = Git._command(repositories, "make release") StopWatch.status("make patch", "released") StopWatch.status("make release", "released") StopWatch.benchmark(sysinfo=True) Git.version(repositories) if testing: os.environ["TESTING"] = "1" elif arguments["--venv"] and arguments["clean"]: environment = arguments["--venv"] print() banner(WARNING, c=Fore.RED) RED( textwrap.dedent(""" Please notice that executing this command can do harm to your installation. Make sure that you also check your .bashrc, .bash_profile or .zprofile files as appropriately to remove aliasses or path variables pointing to your venv.""")) print() print(70 * '-') banner(f"Removing {environment}") print(70 * '-') print() commands = [f'rm -rf "~/{environment}"'] print("\n".join(commands)) print() if arguments["--force"] and \ yn_question("Would you like us to execute them (yes/n)? "): print(70 * '-') for command in commands: print("Executing:", command) print() os.system(command) print(70 * '-') print() elif arguments["clean"] and arguments["--dir"]: dryrun = not arguments['--force'] directory = arguments["--dir"] eggs = list(Path(directory).glob("**/cloudmesh*egg*")) if dryrun: banner("Dryrun directory clean") for egg in eggs: print(f" found -> {egg}") else: print() banner(WARNING, c=Fore.RED) RED( textwrap.dedent(""" Please notice that executing this command can do harm to your installation. If you delete files with this command it is on your own risk. The deletion may have bad effects on your python environment. So please only use it if you know what it effects. """)) print() for egg in eggs: print(f" found -> {egg}") print() if not yn_question( Fore.RED + f"WARNING: Removing listed files. Do you really want to continue. yes/n)? " ): sys.exit(1) for egg in eggs: remove(egg) elif arguments["new"]: venv = arguments["VENV"] or os.path.basename( os.environ("VIRTUAL_ENV")) or "~/ENV3" if os.path.basename(venv).startswith("ENV") and yn_question( f"Would you like reinstall the venv {venv} (yes/n)? "): script = textwrap.dedent(f""" rm -rf {venv} python3.8 -m venv {venv} source {venv}/bin/activate pip install pip -U which python which pip python --version pip --version pip install cloudmesh-installer """).strip() script = "; ".join(script.splitlines()) os.system(script) if bundles: print() print("Installing Bundles") print() repositories = _get_bundles() Git.get(repositories) print() print("You can add the following to your .bashrc or .bash_profile" or ".zprofile") print() print(" source ~/ENV3/bin/activate") print()
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 ""
def Status(value=True): """ starts a timer while using the name of the calling method """ StopWatch.status(Benchmark.name(with_class=True), value)
def _create(self, **arguments): arguments = dotdict(arguments) r = [] StopWatch.start(f"create vm {arguments.name}") label = arguments.get("label") or arguments.name cloud = self.cloudname() cm = { 'kind': "vm", 'name': arguments.name, 'label': label, 'group': arguments.group, 'cloud': cloud, 'status': 'booting' } entry = {} entry.update(cm=cm, name=arguments.name) result = CmDatabase.UPDATE(entry, progress=False)[0] data = {} dryrun = False if "dryrun" in arguments: dryrun = arguments.dryrun data = {"dryrun": True} else: arguments.timeout = 360 data = self.p.create(**arguments) # print('entry') # pprint(entry) # print('data') # pprint(data) entry.update(data) cm['status'] = 'available' StopWatch.stop(f"create vm {arguments.name}") t = format(StopWatch.get(f"create vm {arguments.name}"), '.2f') cm['creation'] = t entry.update({'cm': cm}) if arguments.metadata: metadata = arguments.metadata else: metadata = {"cm": str(cm), "image": arguments.image, "size": arguments.size} entry.update({"metadata": str(metadata)}) try: self.p.set_server_metadata(arguments.name, **metadata) StopWatch.status(f"create vm {arguments.name}", True) except Exception as e: Console.error(f"{cloud} reported the following error") Console.error(79 * "-") print(e) Console.error(79 * "-") result = CmDatabase.UPDATE(entry, progress=False)[0] return result