def cli(**kwargs): """CLI command that calls fetch_release()""" release = kwargs.get("release", None) _file = kwargs.get("_file", False) proxy = kwargs.pop('proxy') if proxy: os.environ.update({'http_proxy': proxy, 'https_proxy': proxy}) if release is not None: if release.lower() == "latest": release = ioc_common.parse_latest_release() kwargs["release"] = release try: float(release.rsplit("-", 1)[0].rsplit("-", 1)[0]) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid entry." }) if not _file: ioc_common.check_release_newer(release, major_only=True) ioc.IOCage().fetch(**kwargs)
def cli(**kwargs): """CLI command that calls fetch_release()""" release = kwargs.get("release", None) _file = kwargs.get("_file", False) proxy = kwargs.pop('proxy') if proxy: os.environ.update({ 'http_proxy': proxy, 'https_proxy': proxy }) if kwargs['plugin_file'] and kwargs['name'] is None: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a --name for plugin-file." }) if release is not None: if release.lower() == "latest": release = ioc_common.parse_latest_release() kwargs["release"] = release try: float(release.rsplit("-", 1)[0].rsplit("-", 1)[0]) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid entry." }) if not _file: ioc_common.check_release_newer(release) ioc.IOCage().fetch(**kwargs)
def cli(command, jail, host_user, jail_user, force): """Runs the command given inside the specified jail as the supplied user.""" # We may be getting ';', '&&' and so forth. Adding the shell for safety. if len(command) == 1: command = ("/bin/sh", "-c") + command if jail.startswith("-"): ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify a jail first!" }) # They haven't set a host_user then, and actually want a jail one, # unsetting the convenience default host_user = "" if jail_user and host_user == "root" else host_user try: ioc.IOCage(jail=jail).exec(command, host_user, jail_user, interactive=True, start_jail=force) except KeyboardInterrupt: pass except Exception as e: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Command failed!\n' f'Exception: "{e.__class__.__name__}:{str(e)}" occured' })
def cli(**kwargs): """CLI command that calls fetch_release()""" release = kwargs.get("release", None) _file = kwargs.get("_file", False) if kwargs['plugin_file'] and kwargs['name'] is None: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a --name for plugin-file." }) if release is not None: if release.lower() == "latest": release = ioc_common.parse_latest_release() kwargs["release"] = release try: float(release.rsplit("-", 1)[0].rsplit("-", 1)[0]) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid entry." }) if not _file: ioc_common.check_release_newer(release) ioc.IOCage().fetch(**kwargs)
def cli(zpool): """Calls ZFS set to change the property org.freebsd.ioc:active to yes.""" ioc.IOCage(activate=True).activate(zpool) ioc_common.logit({ "level" : "INFO", "message": f"ZFS pool '{zpool}' successfully activated." })
def cli(zpool): """Calls ZFS set to change the property org.freebsd.ioc:active to yes.""" ioc.IOCage(activate=True).activate(zpool) ioc_common.logit({ "level": "INFO", "message": f"ZFS pool '{zpool}' successfully activated." })
def cli(force, release, download, jails, recursive): """Destroys the jail's 2 datasets and the snapshot from the RELEASE.""" # Want these here, otherwise they're reinstanced for each jail. zfs = libzfs.ZFS(history=True, history_prefix="<iocage>") iocroot = ioc.PoolAndDataset().get_iocroot() if download and not release: ioc_common.logit({ "level": "EXCEPTION", "message": "--release (-r) must be specified as well!" }) if jails and not release: for jail in jails: if not force: ioc_common.logit({ "level": "WARNING", "message": f"\nThis will destroy jail {jail}" }) if not click.confirm("\nAre you sure?"): continue # no, continue to next jail child_test(zfs, iocroot, jail, "jail", force=force, recursive=recursive) ioc.IOCage(jail=jail, skip_jails=True).destroy_jail(force=force) elif jails and release: for release in jails: if not force: ioc_common.logit({ "level": "WARNING", "message": f"\nThis will destroy RELEASE: {release}" }) if not click.confirm("\nAre you sure?"): continue children = child_test(zfs, iocroot, release, "release", force=force, recursive=recursive) if children: for child in children: ioc.IOCage(jail=child).destroy_jail(force) ioc.IOCage(jail=release, skip_jails=True).destroy_release(download) elif not jails and release: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify one or more RELEASEs!" }) else: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify one or more jails!" })
def cli(force, dataset_type): """Calls the correct destroy function.""" if dataset_type == 'jails': msg = { 'level': 'WARNING', 'message': '\nThis will destroy ALL jails and any ' 'snapshots on a RELEASE,' ' including templates!' } elif dataset_type == 'all': msg = { 'level': 'WARNING', 'message': '\nThis will destroy ALL iocage data!' } elif dataset_type == 'release': msg = { 'level': 'WARNING', 'message': '\nThis will destroy ALL fetched RELEASES and' ' jails/templates created from them!' } elif dataset_type == 'template': msg = { 'level': 'WARNING', 'message': 'This will destroy ALL templates and jails' ' created from them!' } elif dataset_type == 'images': msg = { 'level': 'WARNING', 'message': 'This will destroy ALL exports created!' } elif dataset_type == 'debug': msg = { 'level': 'WARNING', 'message': 'This will destroy ALL debugs created at iocage/debug!' } else: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Please specify a dataset type to clean!' }) if not force: ioc_common.logit(msg) if not click.confirm('\nAre you sure?'): exit() ioc.IOCage(skip_jails=True).clean(dataset_type)
def cli(source, props, count, name, _uuid): # At this point we don't care _uuid = name if name else _uuid err, msg = ioc.IOCage(jail=source).create(source, props, count, _uuid=_uuid, clone=True) if err: ioc_common.logit({"level": "EXCEPTION", "message": msg})
def cli(jail, props, plugin): """Get a list of jails and print the property.""" if not props: # Click doesn't correctly assign the two variables for some reason ioc_common.logit({ "level": "EXCEPTION", "message": "You must specify a jail!" }) for prop in props: ioc.IOCage(jail=jail, skip_jails=True).set(prop, plugin)
def cli(source, props, count, name, _uuid, thickjail): # At this point we don't care _uuid = name if name else _uuid err, msg = ioc.IOCage(jail=source).create( source, props, count, _uuid=_uuid, thickjail=thickjail, clone=True ) if err: ioc_common.logit({ 'level': 'EXCEPTION', 'message': msg })
def cli(jail, name, force): """Get a list of jails and print the property.""" if not force: ioc_common.logit({ "level" : "WARNING", "message": "\nThis will destroy ALL data created including " f"ALL snapshots taken after the snapshot {name}" }) if not click.confirm("\nAre you sure?"): exit() ioc.IOCage(jail=jail).rollback(name)
def cli(header, jail, _long, _sort): """Allows a user to show resource usage of all jails.""" table = texttable.Texttable(max_width=0) snap_list = ioc.IOCage(jail=jail).snap_list(_long, _sort) if header: snap_list.insert(0, ["NAME", "CREATED", "RSIZE", "USED"]) # We get an infinite float otherwise. table.set_cols_dtype(["t", "t", "t", "t"]) table.add_rows(snap_list) ioc_common.logit({"level": "INFO", "message": table.draw()}) else: for snap in snap_list: ioc_common.logit({"level": "INFO", "message": "\t".join(snap)})
def validate_count(ctx, param, value): """Takes a string, removes the commas and returns an int.""" if isinstance(value, str): try: value = value.replace(",", "") return int(value) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": f"({value} is not a valid integer." }) else: return int(value)
def cli(jail, props, plugin): """Get a list of jails and print the property.""" if not props: # Click doesn't correctly assign the two variables for some reason ioc_common.logit( { "level": "EXCEPTION", "message": "You must specify a jail!" }) for prop in props: ioc.IOCage( jail=jail, skip_jails=True).set(prop, plugin)
def validate_count(ctx, param, value): """Takes a string, removes the commas and returns an int.""" if isinstance(value, str): try: value = value.replace(',', '') return int(value) except ValueError: ioc_common.logit({ 'level': 'EXCEPTION', 'message': f'({value} is not a valid integer.' }) else: return int(value)
def validate_count(ctx, param, value): """Takes a string, removes the commas and returns an int.""" if isinstance(value, str): try: value = value.replace(",", "") return int(value) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": f"{value} is not a valid integer." }) else: return int(value)
def cli(rc, jails, ignore): """ Looks for the jail supplied and passes the uuid, path and configuration location to start_jail. """ if not jails and not rc: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Usage: iocage start [OPTIONS] JAILS...\n' '\nError: Missing argument "jails".' }) if rc: ioc.IOCage(rc=rc, silent=True).start(ignore_exception=ignore) else: for jail in jails: ioc.IOCage(jail=jail, rc=rc).start(ignore_exception=ignore)
def cli(rc, force, jails): """ Looks for the jail supplied and passes the uuid, path and configuration location to stop_jail. """ if not jails and not rc: ioc_common.logit({ "level" : "EXCEPTION", "message": 'Usage: iocage stop [OPTIONS] JAILS...\n' '\nError: Missing argument "jails".' }) if rc: ioc.IOCage(rc=rc, silent=True).stop(force=force) else: for jail in jails: ioc.IOCage(jail=jail, rc=rc).stop(force=force)
def cli(header, _long, _sort): """Allows a user to show resource usage of all jails.""" table = texttable.Texttable(max_width=0) jail_list = ioc.IOCage().df() sort = ioc_common.ioc_sort("df", _sort) jail_list.sort(key=sort) if header: jail_list.insert(0, ["NAME", "CRT", "RES", "QTA", "USE", "AVA"]) # We get an infinite float otherwise. table.set_cols_dtype(["t", "t", "t", "t", "t", "t"]) table.add_rows(jail_list) ioc_common.logit({"level": "INFO", "message": table.draw()}) else: for jail in jail_list: ioc_common.logit({"level": "INFO", "message": "\t".join(jail)})
def cli(force, dataset_type): """Calls the correct destroy function.""" if dataset_type == "jails": msg = { "level": "WARNING", "message": "\nThis will destroy ALL jails and any " "snapshots on a RELEASE," "including templates!" } elif dataset_type == "all": msg = { "level": "WARNING", "message": "\nThis will destroy ALL iocage data!" } elif dataset_type == "release": msg = { "level": "WARNING", "message": "\nThis will destroy ALL fetched RELEASES and" " jails/templates created from them!" } elif dataset_type == "template": msg = { "level": "WARNING", "message": "This will destroy ALL templates and jails" " created from them!" } else: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify a dataset type to clean!" }) if not force: ioc_common.logit(msg) if not click.confirm("\nAre you sure?"): exit() ioc.IOCage(skip_jails=True).clean(dataset_type)
def cli(jail, name): """Removes a snapshot from a user supplied jail.""" # TODO: Move to API jails = ioc_list.IOCList("uuid").list_datasets() pool = ioc_json.IOCJson().json_get_value("pool") _jail = { uuid: path for (uuid, path) in jails.items() if uuid.startswith(jail) } if len(_jail) == 1: uuid, path = next(iter(_jail.items())) elif len(_jail) > 1: ioc_common.logit({ "level": "ERROR", "message": f"Multiple jails found for {jail}:" }) for u, p in sorted(_jail.items()): ioc_common.logit({"level": "ERROR", "message": f" {u} ({p})"}) exit(1) else: ioc_common.logit({ "level": "EXCEPTION", "message": f"{jail} not found!" }) # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR conf = ioc_json.IOCJson(path).json_load() if conf["template"] == "yes": target = f"{pool}/iocage/templates/{uuid}@{name}" else: target = f"{pool}/iocage/jails/{uuid}@{name}" try: su.check_call(["zfs", "destroy", "-r", "-f", target]) ioc_common.logit({ "level": "INFO", "message": f"Snapshot: {target} destroyed." }) except su.CalledProcessError as err: ioc_common.logit({"level": "EXCEPTION", "message": f"{err}"}) exit(1)
def cli(rc, force, jails): """ Looks for the jail supplied and passes the uuid, path and configuration location to stop_jail. """ if not jails and not rc: ioc_common.logit({ "level": "EXCEPTION", "message": 'Usage: iocage stop [OPTIONS] JAILS...\n' '\nError: Missing argument "jails".' }) if rc: ioc.IOCage(rc=rc, silent=True).stop(force=force) else: for jail in jails: ioc.IOCage(jail=jail, rc=rc).stop(force=force)
def cli(header, jail, _long, _sort): """Allows a user to show resource usage of all jails.""" table = texttable.Texttable(max_width=0) snap_list = ioc.IOCage(jail=jail).snap_list(_long, _sort) if header: snap_list.insert(0, ["NAME", "CREATED", "RSIZE", "USED"]) # We get an infinite float otherwise. table.set_cols_dtype(["t", "t", "t", "t"]) table.add_rows(snap_list) ioc_common.logit({ "level" : "INFO", "message": table.draw() }) else: for snap in snap_list: ioc_common.logit({ "level" : "INFO", "message": "\t".join(snap) })
def cli(dataset_type, header, _long, remote, http, plugins, _sort, quick, official): """This passes the arg and calls the jail_datasets function.""" freebsd_version = ioc_common.checkoutput(["freebsd-version"]) iocage = ioc.IOCage(skip_jails=True) if dataset_type is None: dataset_type = "all" if remote and not plugins: if "HBSD" in freebsd_version: hardened = True else: hardened = False _list = iocage.fetch(list=True, remote=True, http=http, hardened=hardened) header = False if plugins and remote: _list = iocage.fetch(list=True, remote=True, header=header, _long=_long, plugin_file=True, official=official) elif not remote: _list = iocage.list(dataset_type, header, _long, _sort, plugin=plugins, quick=quick) if not header: if dataset_type == "base": for item in _list: ioc_common.logit({"level": "INFO", "message": item}) else: for item in _list: if remote and not plugins: ioc_common.logit({"level": "INFO", "message": item}) else: ioc_common.logit({ "level": "INFO", "message": "\t".join(item) }) else: ioc_common.logit({"level": "INFO", "message": _list})
def cli(command, jail, host_user, jail_user): """Runs the command given inside the specified jail as the supplied user.""" # We may be getting ';', '&&' and so forth. Adding the shell for safety. if len(command) == 1: command = ("/bin/sh", "-c") + command if jail.startswith("-"): ioc_common.logit( { "level": "EXCEPTION", "message": "Please specify a jail first!" } ) # They haven't set a host_user then, and actually want a jail one, # unsetting the convenience default host_user = "" if jail_user and host_user == "root" else host_user ioc.IOCage(jail=jail).exec(command, host_user, jail_user)
def cli(force, dataset_type): """Calls the correct destroy function.""" if dataset_type == "jails": msg = { "level" : "WARNING", "message": "\nThis will destroy ALL jails and any " "snapshots on a RELEASE," "including templates!" } elif dataset_type == "all": msg = { "level" : "WARNING", "message": "\nThis will destroy ALL iocage data!" } elif dataset_type == "release": msg = { "level" : "WARNING", "message": "\nThis will destroy ALL fetched RELEASES and" " jails/templates created from them!" } elif dataset_type == "template": msg = { "level" : "WARNING", "message": "This will destroy ALL templates and jails" " created from them!" } else: ioc_common.logit({ "level" : "EXCEPTION", "message": "Please specify a dataset type to clean!" }) if not force: ioc_common.logit(msg) if not click.confirm("\nAre you sure?"): exit() ioc.IOCage(skip_jails=True).clean(dataset_type)
def child_test(iocroot, name, _type, force=False, recursive=False): """Tests for dependent children""" path = None children = [] paths = [ f"{iocroot}/jails/{name}/root", f"{iocroot}/releases/{name}", f"{iocroot}/templates/{name}/root" ] for p in paths: if os.path.isdir(p): path = p children = Dataset(path).snapshots_recursive() break if path is None: if not force: ioc_common.logit({ "level": "WARNING", "message": "Partial UUID/NAME supplied, cannot check for " "dependant jails." }) if not click.confirm("\nProceed?"): exit() else: return _children = [] for child in children: _name = child.name _children.append(f" {_name}\n") sort = ioc_common.ioc_sort("", "name", data=_children) _children.sort(key=sort) if len(_children) != 0: if not force and not recursive: ioc_common.logit({ "level": "WARNING", "message": f"\n{name} has dependent jails" " (who may also have dependents)," " use --recursive to destroy: " }) ioc_common.logit({ "level": "WARNING", "message": "".join(_children) }) exit(1) else: return _children
def cli(command, jail, host_user, jail_user, force): """Runs the command given inside the specified jail as the supplied user.""" # We may be getting ';', '&&' and so forth. Adding the shell for safety. if len(command) == 1: command = ("/bin/sh", "-c") + command if jail.startswith("-"): ioc_common.logit( { "level": "EXCEPTION", "message": "Please specify a jail first!" } ) # They haven't set a host_user then, and actually want a jail one, # unsetting the convenience default host_user = "" if jail_user and host_user == "root" else host_user try: ioc.IOCage(jail=jail).exec( command, host_user, jail_user, interactive=True, start_jail=force ) except KeyboardInterrupt: pass except Exception as e: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Command failed!\n' f'Exception: "{e.__class__.__name__}:{str(e)}" occured' })
def cli(dataset_type, header, _long, remote, http, plugins, _sort, quick, official): """This passes the arg and calls the jail_datasets function.""" freebsd_version = ioc_common.checkoutput(["freebsd-version"]) iocage = ioc.IOCage(skip_jails=True) if dataset_type is None: dataset_type = "all" if remote and not plugins: if "HBSD" in freebsd_version: hardened = True else: hardened = False _list = iocage.fetch( list=True, remote=True, http=http, hardened=hardened) header = False if plugins and remote: _list = iocage.fetch( list=True, remote=True, header=header, _long=_long, plugin_file=True, official=official) elif not remote: _list = iocage.list( dataset_type, header, _long, _sort, plugin=plugins, quick=quick) if not header: if dataset_type == "base": for item in _list: ioc_common.logit({"level": "INFO", "message": item}) else: for item in _list: if remote and not plugins: ioc_common.logit({"level": "INFO", "message": item}) else: ioc_common.logit({ "level": "INFO", "message": "\t".join(item) }) else: ioc_common.logit({"level": "INFO", "message": _list})
def child_test(zfs, iocroot, name, _type, force=False, recursive=False): """Tests for dependent children""" path = None children = [] paths = [f"{iocroot}/jails/{name}/root", f"{iocroot}/releases/{name}", f"{iocroot}/templates/{name}/root"] for p in paths: if os.path.isdir(p): path = p children = zfs.get_dataset_by_path(path).snapshots_recursive break if path is None: if not force: ioc_common.logit({ "level": "WARNING", "message": "Partial UUID/NAME supplied, cannot check for " "dependant jails." }) if not click.confirm("\nProceed?"): exit() else: return _children = [] for child in children: _name = child.name.rsplit("@", 1)[-1] _children.append(f" {_name}\n") sort = ioc_common.ioc_sort("", "name", data=_children) _children.sort(key=sort) if len(_children) != 0: if not force and not recursive: ioc_common.logit({ "level": "WARNING", "message": f"\n{name} has dependent jails" " (who may also have dependents)," " use --recursive to destroy: " }) ioc_common.logit({ "level": "WARNING", "message": "".join(_children) }) exit(1) else: return
def cli(prop, _type, _pool, jail, recursive, header, plugin, force): """Get a list of jails and print the property.""" table = texttable.Texttable(max_width=0) if _type: # Confusing I know. jail = prop prop = _type elif _pool: pool = ioc.IOCage(skip_jails=True).get('', pool=True) ioc_common.logit({ 'level': 'INFO', 'message': pool }) exit() else: if not jail and not recursive: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'You must specify a jail!' }) if _type == 'all' and recursive: # TODO: Port this back ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'You cannot use --all (-a) and --recursive (-r) ' 'together. ' }) if not recursive: if prop == 'state' or _type == 'state': state = ioc.IOCage(jail=jail).get(prop) ioc_common.logit({ 'level': 'INFO', 'message': state }) elif prop == 'jid' or _type == 'jid': jid = ioc.IOCage(jail=jail).list('jid', uuid=jail)[1] ioc_common.logit({ 'level': 'INFO', 'message': jid }) elif plugin: _plugin = ioc.IOCage(jail=jail, skip_jails=True).get( prop, plugin=True, start_jail=force ) ioc_common.logit({ 'level': 'INFO', 'message': _plugin }) elif prop == 'all': props = ioc.IOCage(jail=jail, skip_jails=True).get(prop) for p, v in props.items(): ioc_common.logit({ 'level': 'INFO', 'message': f'{p}:{v}' }) else: p = ioc.IOCage(jail=jail, skip_jails=True).get(prop) ioc_common.logit({ 'level': 'INFO', 'message': p }) else: jails = ioc.IOCage().get(prop, recursive=True) table.header(['NAME', f'PROP - {prop}']) for jail_dict in jails: for jail, prop in jail_dict.items(): if header: table.add_row([jail, prop]) else: ioc_common.logit({ 'level': 'INFO', 'message': f'{jail}\t{prop}' }) if header: # Prints the table ioc_common.logit({ 'level': 'INFO', 'message': table.draw() })
def cli(force, release, download, jails, recursive): """Destroys the jail's 2 datasets and the snapshot from the RELEASE.""" # Want these here, otherwise they're reinstanced for each jail. zfs = libzfs.ZFS(history=True, history_prefix="<iocage>") iocroot = ioc.PoolAndDataset().get_iocroot() if download and not release: ioc_common.logit({ "level": "EXCEPTION", "message": "--release (-r) must be specified as well!" }) if jails and not release: for jail in jails: if not force: ioc_common.logit({ "level": "WARNING", "message": f"\nThis will destroy jail {jail}" }) if not click.confirm("\nAre you sure?"): continue # no, continue to next jail child_test(zfs, iocroot, jail, "jail", force=force, recursive=recursive) ioc.IOCage(jail=jail, skip_jails=True).destroy_jail() elif jails and release: for release in jails: if not force: ioc_common.logit({ "level": "WARNING", "message": f"\nThis will destroy RELEASE: {release}" }) if not click.confirm("\nAre you sure?"): continue child_test(zfs, iocroot, release, "release", force=force, recursive=recursive) ioc.IOCage(jail=release, skip_jails=True).destroy_release(download) elif not jails and release: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify one or more RELEASEs!" }) else: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify one or more jails!" })
def cli(prop, _type, _pool, jail, recursive, header, plugin): """Get a list of jails and print the property.""" table = texttable.Texttable(max_width=0) if _type: # Confusing I know. jail = prop prop = _type elif _pool: pool = ioc.IOCage(skip_jails=True).get("", pool=True) ioc_common.logit({ "level" : "INFO", "message": pool }) exit() else: if not jail and not recursive: ioc_common.logit({ "level" : "EXCEPTION", "message": "You must specify a jail!" }) if _type == "all" and recursive: # TODO: Port this back ioc_common.logit({ "level" : "EXCEPTION", "message": "You cannot use --all (-a) and --recursive (-r) " "together. " }) if not recursive: if prop == "state" or _type == "state": state = ioc.IOCage(jail=jail).get(prop) ioc_common.logit({ "level" : "INFO", "message": state }) elif prop == "jid" or _type == "jid": jid = ioc.IOCage(jail=jail).list("jid", uuid=jail)[1] ioc_common.logit({ "level" : "INFO", "message": jid }) elif plugin: _plugin = ioc.IOCage(jail=jail, skip_jails=True).get(prop, plugin=True) ioc_common.logit({ "level" : "INFO", "message": _plugin }) elif prop == "all": props = ioc.IOCage(jail=jail, skip_jails=True).get(prop) for p, v in props.items(): ioc_common.logit({ "level" : "INFO", "message": f"{p}:{v}" }) else: p = ioc.IOCage(jail=jail, skip_jails=True).get(prop) ioc_common.logit({ "level" : "INFO", "message": p }) else: jails = ioc.IOCage().get(prop, recursive=True) table.header(["NAME", f"PROP - {prop}"]) for jail_dict in jails: for jail, prop in jail_dict.items(): if header: table.add_row([jail, prop]) else: ioc_common.logit({ "level" : "INFO", "message": f"{jail}\t{prop}" }) if header: # Prints the table ioc_common.logit({ "level" : "INFO", "message": table.draw() })
def cli(action, fstab_string, jail, header, replace): """ Looks for the jail supplied and passes the uuid, path and configuration location to manipulate the fstab. """ index = None if not replace else replace _index = False add_path = False fstab_string = list(fstab_string) action = action if not replace else "replace" if not fstab_string and action != "edit" and action != "list": ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Please supply an fstab entry or jail!' }) # The user will expect to supply a string, the API would prefer these # separate. If the user supplies a quoted string, we will split it, # otherwise the format is acceptable to be imported directly. if len(fstab_string) == 1: try: source, destination, fstype, options, dump, _pass = fstab_string[ 0].split() except ValueError: # We're going to assume this is an index number. try: index = int(fstab_string[0]) _index = True source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" except TypeError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify either a valid fstab " "entry or an index number." }) except ValueError: # We will assume this is just a source, and will do a readonly # nullfs mount source = fstab_string[0] destination = source fstype = "nullfs" options = "ro" dump = "0" _pass = "******" elif action == "list": # We don't need these source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" else: if action != "edit": try: source, destination, fstype, options, dump, _pass = \ fstab_string except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify a valid fstab entry!\n\n" "Example:\n /the/source /dest FSTYPE " "FSOPTIONS FSDUMP FSPASS" }) else: source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" if not _index: add_path = True fstab = ioc.IOCage(jail=jail).fstab( action, source, destination, fstype, options, dump, _pass, index=index, add_path=add_path, header=header) if action == "list": if header: ioc_common.logit({ "level": "INFO", "message": fstab }) else: for f in fstab: ioc_common.logit({ "level": "INFO", "message": f"{f[0]}\t{f[1]}" })
def cli(release, template, count, props, pkglist, basejail, thickjail, empty, short, name, _uuid, thickconfig): if _uuid: try: uuid.UUID(_uuid, version=4) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please provide a valid UUID" }) else: if count > 1: ioc_common.logit({ "level": "EXCEPTION", "message": "Flag --count cannot be used with --uuid" }) if name: # noinspection Annotator valid = True if re.match(r"^[a-zA-Z0-9\._-]+$", name) else False if not valid: ioc_common.logit({ "level": "EXCEPTION", "message": f"Invalid character in {name}, please remove it." }) # At this point we don't care _uuid = name if release and "=" in release: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid RELEASE!" }) elif release and release.lower() == "latest": release = ioc_common.parse_latest_release() if release: try: ioc_common.check_release_newer(release) except ValueError: # We're assuming they understand the implications of a custom # scheme iocroot = ioc.PoolAndDataset().get_iocroot() path = f'{iocroot}/releases/{release}/root' _release = ioc_common.get_jail_freebsd_version(path, release) try: ioc_common.check_release_newer(_release) except ValueError: # We tried pass # We don't really care it's not a RELEASE at this point. release = template if template else release if pkglist: _pkgformat = """ { "pkgs": [ "foo", "bar" ] }""" if not os.path.isfile(pkglist): ioc_common.logit({ "level": "EXCEPTION", "message": f"{pkglist} does not exist!\n" "Please supply a JSON file with the format:" f" {_pkgformat}" }) else: try: # Just try to open the JSON with the right key. with open(pkglist, "r") as p: json.load(p)["pkgs"] # noqa except json.JSONDecodeError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid" f" JSON file with the format:{_pkgformat}" }) if empty: release = "EMPTY" iocage = ioc.IOCage(skip_jails=True) try: iocage.create(release, props, count, pkglist=pkglist, template=template, short=short, _uuid=_uuid, basejail=basejail, thickjail=thickjail, empty=empty, thickconfig=thickconfig) except RuntimeError as err: if template and "Dataset" in str(err): # We want to list the available templates first ioc_common.logit({ "level": "ERROR", "message": f"Template: {release} not found!" }) templates = ioc.IOCage().list("template") for temp in templates: ioc_common.logit({ "level": "EXCEPTION", "message": f"Created Templates:\n {temp[1]}" }) exit(1) else: # Standard errors ioc_common.logit({ "level": "EXCEPTION", "message": err })
def cli(prop, _type, _pool, jail, recursive, header, plugin): """Get a list of jails and print the property.""" table = texttable.Texttable(max_width=0) if _type: # Confusing I know. jail = prop prop = _type elif _pool: pool = ioc.IOCage(skip_jails=True).get("", pool=True) ioc_common.logit({"level": "INFO", "message": pool}) exit() else: if not jail and not recursive: ioc_common.logit({ "level": "EXCEPTION", "message": "You must specify a jail!" }) if _type == "all" and recursive: # TODO: Port this back ioc_common.logit({ "level": "EXCEPTION", "message": "You cannot use --all (-a) and --recursive (-r) " "together. " }) if not recursive: if prop == "state" or _type == "state": state = ioc.IOCage(jail=jail).get(prop) ioc_common.logit({"level": "INFO", "message": state}) elif prop == "jid" or _type == "jid": jid = ioc.IOCage(jail=jail).list("jid", uuid=jail)[1] ioc_common.logit({"level": "INFO", "message": jid}) elif plugin: _plugin = ioc.IOCage(jail=jail, skip_jails=True).get(prop, plugin=True) ioc_common.logit({"level": "INFO", "message": _plugin}) elif prop == "all": props = ioc.IOCage(jail=jail, skip_jails=True).get(prop) for p, v in props.items(): ioc_common.logit({"level": "INFO", "message": f"{p}:{v}"}) else: p = ioc.IOCage(jail=jail, skip_jails=True).get(prop) ioc_common.logit({"level": "INFO", "message": p}) else: jails = ioc.IOCage().get(prop, recursive=True) table.header(["NAME", f"PROP - {prop}"]) for jail_dict in jails: for jail, prop in jail_dict.items(): if header: table.add_row([jail, prop]) else: ioc_common.logit({ "level": "INFO", "message": f"{jail}\t{prop}" }) if header: # Prints the table ioc_common.logit({"level": "INFO", "message": table.draw()})
def cli(prop, _type, _pool, jail, recursive, header, plugin, force): """Get a list of jails and print the property.""" table = texttable.Texttable(max_width=0) if _type: # Confusing I know. jail = prop prop = _type elif _pool: pool = ioc.IOCage(skip_jails=True).get('', pool=True) ioc_common.logit({'level': 'INFO', 'message': pool}) exit() else: if not jail and not recursive: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'You must specify a jail!' }) if _type == 'all' and recursive: # TODO: Port this back ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'You cannot use --all (-a) and --recursive (-r) ' 'together. ' }) if _type == 'all' and not jail: ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Please specify a jail name when using -a flag.' }) if not recursive: if prop == 'state' or _type == 'state': state = ioc.IOCage(jail=jail).get(prop) ioc_common.logit({'level': 'INFO', 'message': state}) elif prop == 'jid' or _type == 'jid': jid = ioc.IOCage(jail=jail).list('jid', uuid=jail)[1] ioc_common.logit({'level': 'INFO', 'message': jid}) elif plugin: _plugin = ioc.IOCage(jail=jail, skip_jails=True).get(prop, plugin=True, start_jail=force) ioc_common.logit({'level': 'INFO', 'message': _plugin}) elif prop == 'all': props = ioc.IOCage(jail=jail, skip_jails=True).get(prop) for p, v in props.items(): ioc_common.logit({'level': 'INFO', 'message': f'{p}:{v}'}) else: p = ioc.IOCage(jail=jail, skip_jails=True).get(prop) ioc_common.logit({'level': 'INFO', 'message': p}) else: jails = ioc.IOCage().get(prop, recursive=True) table.header(['NAME', f'PROP - {prop}']) for jail_dict in jails: for jail, prop in jail_dict.items(): if header: table.add_row([jail, prop]) else: ioc_common.logit({ 'level': 'INFO', 'message': f'{jail}\t{prop}' }) if header: # Prints the table ioc_common.logit({'level': 'INFO', 'message': table.draw()})
def cli(force, release, download, jails, recursive): """Destroys the jail's 2 datasets and the snapshot from the RELEASE.""" # Want these here, otherwise they're reinstanced for each jail. iocroot = ioc.PoolAndDataset().get_iocroot() if download and not release: ioc_common.logit({ "level": "EXCEPTION", "message": "--release (-r) must be specified as well!" }) if jails and not release: for jail in jails: iocage = ioc.IOCage(jail=jail, skip_jails=True) # If supplied a partial, we want the real match we got. jail, _ = iocage.__check_jail_existence__() if not force: ioc_common.logit({ "level": "WARNING", "message": f"\nThis will destroy jail {jail}" }) if not click.confirm("\nAre you sure?"): continue # no, continue to next jail child_test(iocroot, jail, "jail", force=force, recursive=recursive) iocage.destroy_jail(force=force) elif jails and release: for release in jails: if not force: ioc_common.logit({ "level": "WARNING", "message": f"\nThis will destroy RELEASE: {release}" }) if not click.confirm("\nAre you sure?"): continue children = child_test(iocroot, release, "release", force=force, recursive=recursive) if children: for child in children: ioc.IOCage(jail=child).destroy_jail(force) ioc.IOCage(jail=release, skip_jails=True).destroy_release(download) elif not jails and release: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify one or more RELEASEs!" }) else: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify one or more jails!" })
def cli(release, template, count, props, pkglist, basejail, thickjail, empty, short, name, _uuid, force): if name: # noinspection Annotator valid = True if re.match("^[a-zA-Z0-9\._-]+$", name) else False if not valid: ioc_common.logit({ "level": "EXCEPTION", "message": f"Invalid character in {name}, please remove it." }) # At this point we don't care _uuid = name if release and "=" in release: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid RELEASE!" }) elif release and release.lower() == "latest": release = ioc_common.parse_latest_release() if release: release = release.upper() ioc_common.check_release_newer(release) # We don't really care it's not a RELEASE at this point. release = template if template else release if pkglist: _pkgformat = """ { "pkgs": [ "foo", "bar" ] }""" if not os.path.isfile(pkglist): ioc_common.logit({ "level": "EXCEPTION", "message": f"{pkglist} does not exist!\n" "Please supply a JSON file with the format:" f" {_pkgformat}" }) else: try: # Just try to open the JSON with the right key. with open(pkglist, "r") as p: json.load(p)["pkgs"] # noqa except json.JSONDecodeError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid" f" JSON file with the format:{_pkgformat}" }) if empty: release = "EMPTY" iocage = ioc.IOCage(skip_jails=True) try: iocage.create(release, props, count, pkglist=pkglist, template=template, short=short, _uuid=_uuid, basejail=basejail, thickjail=thickjail, empty=empty) except RuntimeError as err: if template and "Dataset" in str(err): # We want to list the available templates first ioc_common.logit({ "level": "ERROR", "message": f"Template: {release} not found!" }) templates = ioc.IOCage().list("template") for temp in templates: ioc_common.logit({ "level": "EXCEPTION", "message": f"Created Templates:\n {temp[1]}" }) exit(1) else: # Standard errors ioc_common.logit({"level": "EXCEPTION", "message": err})
def cli(release, template, count, props, pkglist, basejail, clone_basejail, thickjail, empty, short, name, _uuid, thickconfig): if _uuid: try: uuid.UUID(_uuid, version=4) except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please provide a valid UUID" }) else: if count > 1: ioc_common.logit({ "level": "EXCEPTION", "message": "Flag --count cannot be used with --uuid" }) if name: # noinspection Annotator valid = True if re.match(r"^[a-zA-Z0-9\._-]+$", name) else False if not valid: ioc_common.logit({ "level": "EXCEPTION", "message": f"Invalid character in {name}, please remove it." }) # At this point we don't care _uuid = name if release and "=" in release: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid RELEASE!" }) elif release and release.lower() == "latest": release = ioc_common.parse_latest_release() if release: try: ioc_common.check_release_newer(release) except ValueError: # We're assuming they understand the implications of a custom # scheme iocroot = ioc.PoolAndDataset().get_iocroot() path = f'{iocroot}/releases/{release}/root' _release = ioc_common.get_jail_freebsd_version(path, release) try: ioc_common.check_release_newer(_release) except ValueError: # We tried pass # We don't really care it's not a RELEASE at this point. release = template if template else release if pkglist: _pkgformat = """ { "pkgs": [ "foo", "bar" ] }""" if not os.path.isfile(pkglist): ioc_common.logit({ "level": "EXCEPTION", "message": f"{pkglist} does not exist!\n" "Please supply a JSON file with the format:" f" {_pkgformat}" }) else: try: # Just try to open the JSON with the right key. with open(pkglist, "r") as p: json.load(p)["pkgs"] # noqa except json.JSONDecodeError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please supply a valid" f" JSON file with the format:{_pkgformat}" }) if empty: release = "EMPTY" if clone_basejail: # We want to still create a basejail basejail = True iocage = ioc.IOCage(skip_jails=True) try: iocage.create(release, props, count, pkglist=pkglist, template=template, short=short, _uuid=_uuid, basejail=basejail, thickjail=thickjail, empty=empty, thickconfig=thickconfig, clone_basejail=clone_basejail) except (RuntimeError, ioc_exceptions.JailMissingConfiguration) as err: if template and "Dataset" in str(err) or str(err).startswith( 'Template'): # We want to list the available templates first ioc_common.logit({ "level": "ERROR", "message": f"Template: {release} not found!" }) templates = ioc.IOCage(silent=True).list('template') template_names = '' for temp in templates: template_names += '\n ' + temp[1] ioc_common.logit({ 'level': 'EXCEPTION', 'message': f'Created Templates:{template_names}' }) exit(1) else: # Standard errors ioc_common.logit({"level": "EXCEPTION", "message": err})
def cli(force, delete): """Migrates all the iocage_legacy develop basejails to clone jails.""" # TODO: Move to API jails = ioc_list.IOCList("uuid").list_datasets() if not force: ioc_common.logit({ "level": "WARNING", "message": "\nThis will migrate ALL iocage-legacy develop" " basejails to clonejails, it can take a long" " time!\nPlease make sure you are not running" " this on iocage-legacy 1.7.6 basejails." }) if not click.confirm("\nAre you sure?"): exit() for uuid, path in jails.items(): pool = ioc_json.IOCJson().json_get_value("pool") iocroot = ioc_json.IOCJson(pool).json_get_value("iocroot") jail = f"{pool}/iocage/jails/{uuid}" jail_old = f"{pool}/iocage/jails_old/{uuid}" conf = ioc_json.IOCJson(path).json_load() try: tag = conf["tag"] except KeyError: # These are actually NEW jails. continue release = conf["cloned_release"] if conf["type"] == "basejail": try: ioc_common.checkoutput(["zfs", "rename", "-p", jail, jail_old], stderr=su.STDOUT) except su.CalledProcessError as err: ioc_common.logit({ "level": "EXCEPTION", "message": f"{err.output.decode('utf-8').strip()}" }) try: os.remove(f"{iocroot}/tags/{tag}") except OSError: pass date_fmt_legacy = "%Y-%m-%d@%H:%M:%S" # We don't want to rename datasets to a bunch of dates. try: datetime.datetime.strptime(tag, date_fmt_legacy) _name = str(uuid.uuid4()) except ValueError: # They already named this jail, making it like our new ones. _name = tag new_uuid = ioc_create.IOCCreate( release, "", 0, None, migrate=True, config=conf, silent=True, uuid=_name, ).create_jail() new_prop = ioc_json.IOCJson(f"{iocroot}/jails/{new_uuid}", silent=True).json_set_value new_prop(f"host_hostname={new_uuid}") new_prop(f"host_hostuuid={new_uuid}") new_prop("type=jail") new_prop(f"jail_zfs_dataset={iocroot}/jails/{new_uuid}/data") ioc_common.logit({ "level": "INFO", "message": f"Copying files for {new_uuid}, please wait..." }) ioc_common.copytree(f"{iocroot}/jails_old/{uuid}/root", f"{iocroot}/jails/{new_uuid}/root", symlinks=True) shutil.copy(f"{iocroot}/jails_old/{uuid}/fstab", f"{iocroot}/jails/{new_uuid}/fstab") for line in fileinput.input( f"{iocroot}/jails/{new_uuid}/root/etc/" "rc.conf", inplace=1): print( line.replace(f'hostname="{uuid}"', f'hostname="{new_uuid}"').rstrip()) if delete: try: ioc_common.checkoutput( ["zfs", "destroy", "-r", "-f", jail_old], stderr=su.STDOUT) except su.CalledProcessError as err: raise RuntimeError( f"{err.output.decode('utf-8').rstrip()}") try: su.check_call([ "zfs", "destroy", "-r", "-f", f"{pool}/iocage/jails_old" ]) except su.CalledProcessError: # We just want the top level dataset gone, no big deal. pass ioc_common.logit({ "level": "INFO", "message": f"{uuid} ({tag}) migrated to {new_uuid}!\n" })
def cli(force, delete): """Migrates all the iocage_legacy develop basejails to clone jails.""" # TODO: Move to API jails = ioc_list.IOCList("uuid").list_datasets() if not force: ioc_common.logit({ "level": "WARNING", "message": "\nThis will migrate ALL iocage-legacy develop" " basejails to clonejails, it can take a long" " time!\nPlease make sure you are not running" " this on iocage-legacy 1.7.6 basejails." }) if not click.confirm("\nAre you sure?"): exit() for uuid, path in jails.items(): pool = ioc_json.IOCJson().json_get_value("pool") iocroot = ioc_json.IOCJson(pool).json_get_value("iocroot") jail = f"{pool}/iocage/jails/{uuid}" jail_old = f"{pool}/iocage/jails_old/{uuid}" conf = ioc_json.IOCJson(path).json_get_value('all') try: tag = conf["tag"] except KeyError: # These are actually NEW jails. continue release = conf["cloned_release"] if conf["type"] == "basejail": try: ioc_common.checkoutput( ["zfs", "rename", "-p", jail, jail_old], stderr=su.STDOUT) except su.CalledProcessError as err: ioc_common.logit( { "level": "EXCEPTION", "message": f"{err.output.decode('utf-8').strip()}" }) try: os.remove(f"{iocroot}/tags/{tag}") except OSError: pass date_fmt_legacy = "%Y-%m-%d@%H:%M:%S" # We don't want to rename datasets to a bunch of dates. try: datetime.datetime.strptime(tag, date_fmt_legacy) _name = str(uuid.uuid4()) except ValueError: # They already named this jail, making it like our new ones. _name = tag new_uuid = ioc_create.IOCCreate( release, "", 0, None, migrate=True, config=conf, silent=True, uuid=_name, ).create_jail() new_prop = ioc_json.IOCJson( f"{iocroot}/jails/{new_uuid}", silent=True).json_set_value new_prop(f"host_hostname={new_uuid}") new_prop(f"host_hostuuid={new_uuid}") new_prop("type=jail") new_prop(f"jail_zfs_dataset={iocroot}/jails/{new_uuid}/data") ioc_common.logit({ "level": "INFO", "message": f"Copying files for {new_uuid}, please wait..." }) ioc_common.copytree( f"{iocroot}/jails_old/{uuid}/root", f"{iocroot}/jails/{new_uuid}/root", symlinks=True) shutil.copy(f"{iocroot}/jails_old/{uuid}/fstab", f"{iocroot}/jails/{new_uuid}/fstab") for line in fileinput.input( f"{iocroot}/jails/{new_uuid}/root/etc/" "rc.conf", inplace=1): print( line.replace(f'hostname="{uuid}"', f'hostname="{new_uuid}"').rstrip()) if delete: try: ioc_common.checkoutput( ["zfs", "destroy", "-r", "-f", jail_old], stderr=su.STDOUT) except su.CalledProcessError as err: raise RuntimeError( f"{err.output.decode('utf-8').rstrip()}") try: su.check_call([ "zfs", "destroy", "-r", "-f", f"{pool}/iocage/jails_old" ]) except su.CalledProcessError: # We just want the top level dataset gone, no big deal. pass ioc_common.logit({ "level": "INFO", "message": f"{uuid} ({tag}) migrated to {new_uuid}!\n" })
def cli(action, fstab_string, jail, header, replace): """ Looks for the jail supplied and passes the uuid, path and configuration location to manipulate the fstab. """ index = None if not replace else replace _index = False add_path = False fstab_string = list(fstab_string) action = action if not replace else "replace" if not fstab_string and action != "edit" and action != "list": ioc_common.logit({ 'level': 'EXCEPTION', 'message': 'Please supply an fstab entry or jail!' }) # The user will expect to supply a string, the API would prefer these # separate. If the user supplies a quoted string, we will split it, # otherwise the format is acceptable to be imported directly. if len(fstab_string) == 1: try: source, destination, fstype, options, dump, _pass = fstab_string[ 0].split() except ValueError: # We're going to assume this is an index number. try: index = int(fstab_string[0]) _index = True source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" except TypeError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify either a valid fstab " "entry or an index number." }) except ValueError: # We will assume this is just a source, and will do a readonly # nullfs mount source = fstab_string[0] destination = source fstype = "nullfs" options = "ro" dump = "0" _pass = "******" elif action == "list": # We don't need these source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" else: if action != "edit": try: source, destination, fstype, options, dump, _pass = \ fstab_string except ValueError: ioc_common.logit({ "level": "EXCEPTION", "message": "Please specify a valid fstab entry!\n\n" "Example:\n /the/source /dest FSTYPE " "FSOPTIONS FSDUMP FSPASS" }) else: source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" if not _index: add_path = True fstab = ioc.IOCage(jail=jail).fstab(action, source, destination, fstype, options, dump, _pass, index=index, add_path=add_path, header=header) if action == "list": if header: ioc_common.logit({"level": "INFO", "message": fstab}) else: for f in fstab: ioc_common.logit({ "level": "INFO", "message": f'{f[0]}\t{f[1]}' })