def __soft_restart__(uuid, jail, path, conf): """ Will tear down the jail by running exec_stop and then exec_start, leaving the network stack intact, ideal for VIMAGE. """ getjid = IOCList().list_get_jid(uuid) status, jid = getjid lgr = ioc_logger.Logger('ioc_cli_restart').getLogger() # These needs to be a list. exec_start = conf["exec_start"].split() exec_stop = conf["exec_stop"].split() if status: lgr.info("Soft restarting {} ({})".format(uuid, jail)) stop_cmd = ["jexec", "ioc-{}".format(uuid)] + exec_stop Popen(stop_cmd, stdout=PIPE, stderr=PIPE).communicate() Popen(["pkill", "-j", jid]).communicate() start_cmd = ["jexec", "ioc-{}".format(uuid)] + exec_start Popen(start_cmd, stdout=PIPE, stderr=PIPE).communicate() IOCJson(path, silent=True).json_set_value("last_started={}".format( datetime.utcnow().strftime("%F %T"))) else: lgr.critical("{} is not running!".format(jail)) exit(1)
def pkg_cmd(command, jail): """Runs pkg with the command given inside the specified jail.""" lgr = ioc_logger.Logger('ioc_cli_pkg').getLogger() jails, paths = IOCList("uuid").list_datasets() _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) cmd = ("pkg", ) + command IOCExec(cmd, uuid, tag, path).exec_jail()
def list_cmd(dataset_type, header, _long, remote, http, plugins): """This passes the arg and calls the jail_datasets function.""" lgr = ioc_logger.Logger('ioc_cli_list').getLogger() freebsd_version = checkoutput(["freebsd-version"]) if dataset_type is None: dataset_type = "all" if remote: if "HBSD" in freebsd_version: hardened = True else: hardened = False IOCFetch("", http=http, hardened=hardened).fetch_release(_list=True) elif plugins: IOCFetch("").fetch_plugin_index("", _list=True) else: _list = IOCList(dataset_type, header, _long).list_datasets() if not header: if dataset_type == "base": for item in _list: lgr.info(item) else: for item in _list: print("\t".join(item)) else: lgr.info(_list)
def snapremove_cmd(jail, name): """Removes a snapshot from a user supplied jail.""" lgr = ioc_logger.Logger('ioc_cli_snapremove').getLogger() jails, paths = IOCList("uuid").list_datasets() pool = IOCJson().json_get_value("pool") _jail = {tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail} if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.critical(" {} ({})".format(u, t)) exit(1) else: lgr.critical("{} not found!".format(jail)) exit(1) # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR conf = IOCJson(path).json_load() if conf["template"] == "yes": target = "{}/iocage/templates/{}@{}".format(pool, tag, name) else: target = "{}/iocage/jails/{}@{}".format(pool, uuid, name) try: check_call(["zfs", "destroy", "-r", "-f", target]) lgr.info("Snapshot: {} destroyed.".format(target)) except CalledProcessError as err: lgr.error("{}".format(err))
def console_cmd(jail, force): """ Runs jexec to login into the specified jail. Accepts a force flag that will attempt to start the jail if it is not already running. """ lgr = ioc_logger.Logger('ioc_cli_console').getLogger() jails, paths = IOCList("uuid").list_datasets() _jail = {tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail} if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] iocjson = IOCJson(path) conf = iocjson.json_load() login_flags = conf["login_flags"].split() exec_fib = conf["exec_fib"] status, _ = IOCList().list_get_jid(uuid) elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.critical(" {} ({})".format(u, t)) exit(1) else: lgr.critical("{} not found!".format(jail)) exit(1) if not status and not force: lgr.critical("{} ({}) is not running!".format(uuid, tag)) exit(1) if not status and force: lgr.info("{} ({}) is not running".format(uuid, tag) + ", starting jail.") if conf["type"] == "jail": IOCStart(uuid, jail, path, conf, silent=True) status = True elif conf["type"] == "basejail": lgr.critical("Please run \"iocage migrate\" before trying" " to start {} ({})".format(uuid, tag)) exit(1) elif conf["type"] == "template": lgr.critical("Please convert back to a jail before trying" " to start {} ({})".format(uuid, tag)) exit(1) else: lgr.critical("{} is not a supported jail type.".format( conf["type"] )) exit(1) if status: Popen(["setfib", exec_fib, "jexec", f"ioc-{uuid}", "login"] + login_flags).communicate()
def rollback_cmd(jail, name, force): """Get a list of jails and print the property.""" lgr = ioc_logger.Logger('ioc_cli_rollback').getLogger() jails, paths = IOCList("uuid").list_datasets() pool = IOCJson().json_get_value("pool") _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" f" {jail}:") for t, u in sorted(_jail.items()): lgr.error(f" {u} ({t})") raise RuntimeError() else: lgr.critical(f"{jail} not found!") exit(1) # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR conf = IOCJson(path).json_load() if conf["template"] == "yes": target = f"{pool}/iocage/templates/{tag}" else: target = f"{pool}/iocage/jails/{uuid}" try: checkoutput(["zfs", "get", "-H", "creation", target], stderr=PIPE) except CalledProcessError: lgr.critical(f"Snapshot {target} does not exist!") exit(1) if not force: lgr.warning("\nThis will destroy ALL data created since" f" {name} was taken.\nIncluding ALL snapshots taken after" f" {name} for {uuid} ({tag})") if not click.confirm("\nAre you sure?"): exit() try: datasets = Popen(["zfs", "list", "-H", "-r", "-o", "name", target], stdout=PIPE, stderr=PIPE).communicate()[0].decode("utf-8").split() for dataset in datasets: check_call(["zfs", "rollback", "-r", f"{dataset}@{name}"]) lgr.info(f"Rolled back to: {target}") except CalledProcessError as err: lgr.error(f"{err}") exit(1)
def df_cmd(header, _long, _sort): """Allows a user to show resource usage of all jails.""" lgr = ioc_logger.Logger('ioc_cli_df').getLogger() jails, paths = IOCList("uuid").list_datasets() pool = IOCJson().json_get_value("pool") jail_list = [] table = Texttable(max_width=0) for jail in jails: full_uuid = jails[jail] if not _long: uuid = full_uuid[:8] else: uuid = full_uuid path = paths[jail] conf = IOCJson(path).json_load() zconf = ["zfs", "get", "-H", "-o", "value"] mountpoint = f"{pool}/iocage/jails/{full_uuid}" tag = conf["tag"] template = conf["type"] if template == "template": mountpoint = f"{pool}/iocage/templates/{tag}" compressratio = Popen( zconf + ["compressratio", mountpoint], stdout=PIPE).communicate()[0].decode("utf-8").strip() reservation = Popen( zconf + ["reservation", mountpoint], stdout=PIPE).communicate()[0].decode("utf-8").strip() quota = Popen(zconf + ["quota", mountpoint], stdout=PIPE).communicate()[0].decode("utf-8").strip() used = Popen(zconf + ["used", mountpoint], stdout=PIPE).communicate()[0].decode("utf-8").strip() available = Popen( zconf + ["available", mountpoint], stdout=PIPE).communicate()[0].decode("utf-8").strip() jail_list.append( [uuid, compressratio, reservation, quota, used, available, tag]) sort = ioc_common.ioc_sort("df", _sort) jail_list.sort(key=sort) if header: jail_list.insert(0, ["UUID", "CRT", "RES", "QTA", "USE", "AVA", "TAG"]) # We get an infinite float otherwise. table.set_cols_dtype(["t", "t", "t", "t", "t", "t", "t"]) table.add_rows(jail_list) lgr.info(table.draw()) else: for jail in jail_list: print("\t".join(jail))
def update_cmd(jail): """Runs update with the command given inside the specified jail.""" lgr = ioc_logger.Logger('ioc_cli_update').getLogger() jails, paths = IOCList("uuid").list_datasets() _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.critical(" {} ({})".format(u, t)) exit(1) else: lgr.critical("{} not found!".format(jail)) exit(1) freebsd_version = checkoutput(["freebsd-version"]) status, jid = IOCList.list_get_jid(uuid) conf = IOCJson(path).json_load() started = False if conf["type"] == "jail": if not status: IOCStart(uuid, tag, path, conf, silent=True) status, jid = IOCList.list_get_jid(uuid) started = True elif conf["type"] == "basejail": lgr.critical("Please run \"iocage migrate\" before trying" " to update {} ({})".format(uuid, tag)) exit(1) elif conf["type"] == "template": lgr.critical("Please convert back to a jail before trying" " to update {} ({})".format(uuid, tag)) exit(1) else: lgr.critical("{} is not a supported jail type.".format(conf["type"])) exit(1) if "HBSD" in freebsd_version: Popen(["hbsd-update", "-j", jid]).communicate() if started: IOCStop(uuid, tag, path, conf, silent=True) else: IOCFetch(conf["cloned_release"]).fetch_update(True, uuid, tag) if started: IOCStop(uuid, tag, path, conf, silent=True)
def rollback_cmd(jail, name, force): """Get a list of jails and print the property.""" lgr = ioc_logger.Logger('ioc_cli_rollback').getLogger() jails, paths = IOCList("uuid").list_datasets() pool = IOCJson().json_get_value("pool") _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR target = "{}{}@{}".format(pool, path, name) try: checkoutput(["zfs", "get", "-H", "creation", target], stderr=PIPE) except CalledProcessError: lgr.critical("Snapshot {} does not exist!".format(target)) exit(1) if not force: lgr.warning("\nThis will destroy ALL data created since" " {} was taken.".format(name) + "\nIncluding ALL snapshots taken after" " {} for {} ({}).".format(name, uuid, tag)) if not click.confirm("\nAre you sure?"): exit() try: datasets = Popen([ "zfs", "list", "-H", "-r", "-o", "name", "{}{}".format(pool, path) ], stdout=PIPE, stderr=PIPE).communicate()[0].decode("utf-8").split() for dataset in datasets: check_call( ["zfs", "rollback", "-r", "{}@{}".format(dataset, name)]) lgr.info("Rolled back to: {}.".format(target)) except CalledProcessError as err: lgr.error("{}".format(err)) exit(1)
def __callback__(self, log): """Helper to call the appropriate logging level""" lgr = ioc_logger.Logger('mng_jail').getLogger() if log['level'] == 'CRITICAL': lgr.critical(log['message']) elif log['level'] == 'ERROR': lgr.error(log['message']) elif log['level'] == 'WARNING': lgr.warning(log['message']) elif log['level'] == 'INFO': lgr.info(log['message']) elif log['level'] == 'DEBUG': lgr.debug(log['message'])
def set_cmd(prop, jail, plugin): """Get a list of jails and print the property.""" lgr = ioc_logger.Logger('ioc_cli_set').getLogger() jails, paths = IOCList("uuid").list_datasets(set=True) _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] iocjson = IOCJson(path, cli=True) elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) if "template" in prop.split("=")[0]: if "template" in path and prop != "template=no": lgr.critical("{} ({}) is already a template!".format(uuid, tag)) exit(1) elif "template" not in path and prop != "template=yes": lgr.critical("{} ({}) is already a jail!".format(uuid, tag)) exit(1) if plugin: _prop = prop.split(".") IOCJson(path, cli=True).json_plugin_set_value(_prop) else: try: # We use this to test if it's a valid property at all. _prop = prop.partition("=")[0] iocjson.json_get_value(_prop) # The actual setting of the property. iocjson.json_set_value(prop) except KeyError: _prop = prop.partition("=")[0] lgr.critical("{} is not a valid property!".format(_prop)) exit(1)
def exec_cmd(command, jail, host_user, jail_user): """Runs the command given inside the specified jail as the supplied user.""" lgr = ioc_logger.Logger('ioc_cli_exec').getLogger() # We may be getting ';', '&&' and so forth. Adding the shell for safety. if len(command) == 1: command = ("/bin/sh", "-c") + command if jail.startswith("-"): lgr.critical("Please specify a jail first!") exit(1) if host_user and jail_user: lgr.critical("Please only specify either host_user or" " jail_user, not both!") exit(1) jails, paths = IOCList("uuid").list_datasets() _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) msg, err = IOCExec(command, uuid, tag, path, host_user, jail_user).exec_jail() if err: err = indent_lines(msg) lgr.error("{}".format(err)) else: lgr.info(msg.decode("utf-8"))
def snapshot_cmd(jail, name): """Get a list of jails and print the property.""" lgr = ioc_logger.Logger('ioc_cli_snapshot').getLogger() jails, paths = IOCList("uuid").list_datasets() pool = IOCJson().json_get_value("pool") date = datetime.utcnow().strftime("%F_%T") _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) # If they don't supply a snapshot name, we will use the date. if not name: name = date # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR conf = IOCJson(path).json_load() if conf["template"] == "yes": target = "{}/iocage/templates/{}@{}".format(pool, tag, name) else: target = "{}/iocage/jails/{}@{}".format(pool, uuid, name) try: check_call(["zfs", "snapshot", "-r", target], stderr=PIPE) lgr.info("Snapshot: {} created.".format(target)) except CalledProcessError: lgr.critical("Snapshot already exists!") exit(1)
def activate_cmd(zpool): """Calls ZFS set to change the property org.freebsd.ioc:active to yes.""" lgr = ioc_logger.Logger('ioc_cli_activate').getLogger() zfs = libzfs.ZFS(history=True, history_prefix="<iocage>") pools = zfs.pools prop = "org.freebsd.ioc:active" for _pool in pools: if _pool.name == zpool: ds = zfs.get_dataset(_pool.name) ds.properties[prop] = libzfs.ZFSUserProperty("yes") else: ds = zfs.get_dataset(_pool.name) ds.properties[prop] = libzfs.ZFSUserProperty("no") # Check and clean if necessary iocage_legacy way # to mark a ZFS pool as usable (now replaced by ZFS property) comment = zfs.get(_pool.name).properties["comment"] if comment.value == "iocage": comment.value = "-" lgr.info(f"ZFS pool '{zpool}' successfully activated.")
def clean_cmd(force, dataset_type): """Calls the correct destroy function.""" lgr = ioc_logger.Logger('ioc_cli_clean').getLogger() if dataset_type == "jails": if not force: lgr.warning("\nThis will destroy ALL jails" " and any snapshots on a RELEASE, including " "templates!") if not click.confirm("\nAre you sure?"): exit() IOCClean().clean_jails() lgr.info("All iocage jail datasets have been destroyed.") elif dataset_type == "all": if not force: lgr.warning("\nThis will destroy ALL iocage data!") if not click.confirm("\nAre you sure?"): exit() IOCClean().clean_all() lgr.info("All iocage datasets have been destroyed.") elif dataset_type == "release": pass elif dataset_type == "template": if not force: lgr.warning("This will destroy ALL templates" " and jails created from them!") if not click.confirm("\nAre you sure?"): exit() IOCClean().clean_templates() lgr.info("All iocage template datasets have been destroyed.") else: lgr.critical("Please specify a dataset type to clean!") exit(1)
def migrate_cmd(force, delete): """Migrates all the iocage_legacy develop basejails to clone jails.""" lgr = ioc_logger.Logger('ioc_cli_migrate').getLogger() jails, paths = IOCList("uuid").list_datasets() if not force: lgr.warning("\nThis will migrate ALL basejails to " "clonejails, it can take a long time!") if not click.confirm("\nAre you sure?"): exit() for tag, uuid in jails.items(): pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") jail = "{}/iocage/jails/{}".format(pool, uuid) jail_old = "{}/iocage/jails_old/{}".format(pool, uuid) path = paths[tag] conf = IOCJson(path).json_load() release = conf["release"] if conf["type"] == "basejail": try: checkoutput(["zfs", "rename", "-p", jail, jail_old], stderr=STDOUT) except CalledProcessError as err: lgr.critical("{}".format(err.output.decode("utf-8").strip())) exit(1) try: os.remove("{}/tags/{}".format(iocroot, tag)) except OSError: pass new_uuid = IOCCreate(release, "", 0, None, migrate=True, config=conf, silent=True).create_jail() new_prop = IOCJson("{}/jails/{}".format(iocroot, new_uuid), silent=True).json_set_value new_prop("host_hostname={}".format(new_uuid)) new_prop("host_hostuuid={}".format(new_uuid)) new_prop("type=jail") new_prop( "jail_zfs_dataset={}/jails/{}/data".format(iocroot, new_uuid)) lgr.info("Copying files for {} ({}), please wait...".format( uuid, tag )) copytree("{}/jails_old/{}/root".format(iocroot, uuid), "{}/jails/{}/root".format(iocroot, new_uuid), symlinks=True) copy("{}/jails_old/{}/fstab".format(iocroot, uuid), "{}/jails/{}/fstab".format(iocroot, new_uuid)) for line in fileinput.input("{}/jails/{}/root/etc/rc.conf".format( iocroot, new_uuid), inplace=1): lgr.info(line.replace(f'hostname="{uuid}"', f'hostname="{new_uuid}"').rstrip()) if delete: try: checkoutput(["zfs", "destroy", "-r", "-f", jail_old], stderr=STDOUT) except CalledProcessError as err: raise RuntimeError("{}".format( err.output.decode("utf-8").rstrip())) try: check_call(["zfs", "destroy", "-r", "-f", "{}/iocage/jails_old".format(pool)]) except CalledProcessError: # We just want the top level dataset gone, no big deal. pass lgr.info("{} ({}) migrated to {} ({})!\n".format(uuid, tag, new_uuid, tag))
def fetch_cmd(http, _file, server, user, password, auth, verify, release, plugins, plugin_file, root_dir, props, count, update, eol, files): """CLI command that calls fetch_release()""" freebsd_version = checkoutput(["freebsd-version"]) arch = os.uname()[4] lgr = ioc_logger.Logger("ioc_cli_fetch").getLogger() if not files: if arch == "arm64": files = ("MANIFEST", "base.txz", "doc.txz") else: files = ("MANIFEST", "base.txz", "lib32.txz", "doc.txz") if "HBSD" in freebsd_version: if server == "ftp.freebsd.org": hardened = True else: hardened = False else: hardened = False if plugins or plugin_file: if plugin_file: try: with open(plugin_file) as f: return json.load(f) except FileNotFoundError: lgr.critical("Please supply a file before any properties.") exit(1) except json.decoder.JSONDecodeError: lgr.critical("Invalid JSON file supplied, please supply a " "correctly formatted JSON file.") exit(1) ip = [ x for x in props if x.startswith("ip4_addr") or x.startswith("ip6_addr") ] if not ip: lgr.critical("An IP address is needed to fetch a " "plugin!\nPlease specify " "ip(4|6)_addr=\"INTERFACE|IPADDRESS\"!") exit(1) if plugins: IOCFetch(release=None).fetch_plugin_index(props) exit() if count == 1: IOCFetch("", server, user, password, auth, root_dir, http=http, _file=_file, verify=verify, hardened=hardened, update=update, eol=eol, files=files).fetch_plugin(plugin_file, props, 0) else: for j in range(1, count + 1): IOCFetch("", server, user, password, auth, root_dir, http=http, _file=_file, verify=verify, hardened=hardened, update=update, eol=eol, files=files).fetch_plugin(plugin_file, props, j) else: IOCFetch(release, server, user, password, auth, root_dir, http=http, _file=_file, verify=verify, hardened=hardened, update=update, eol=eol, files=files).fetch_release()
def create_cmd(release, template, count, props, pkglist, basejail, empty, short, uuid): lgr = ioc_logger.Logger('ioc_cli_create').getLogger() if short and uuid: lgr.critical( "Can't use --short (-s) and --uuid (-u) at the same time!") exit(1) if not template and not release and not empty: lgr.critical("Must supply either --template (-t) or --release (-r)!") exit(1) if release and "=" in release: lgr.critical("Please supply a valid RELEASE!") exit(1) if template: # We don't really care it's not a RELEASE at this point. release = template if pkglist: _pkgformat = """ { "pkgs": [ "foo", "bar" ] }""" if not os.path.isfile(pkglist): lgr.critical("{} does not exist!\nPlease supply a JSON file " "with the format:{}".format(pkglist, _pkgformat)) exit(1) else: try: # Just try to open the JSON with the right key. with open(pkglist, "r") as p: json.load(p)["pkgs"] # noqa except JSONDecodeError: lgr.critical("Please supply a valid JSON file with the" f" format:\n{_pkgformat}") exit(1) pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") if not os.path.isdir( f"{iocroot}/releases/{release}") and not template and not empty: freebsd_version = checkoutput(["freebsd-version"]) if "HBSD" in freebsd_version: hardened = True else: hardened = False IOCFetch(release, hardened=hardened).fetch_release() if empty: release = "EMPTY" if count == 1: try: IOCCreate(release, props, 0, pkglist, template=template, short=short, uuid=uuid, basejail=basejail, empty=empty).create_jail() except RuntimeError as err: lgr.error(err) if template: lgr.info("Created Templates:") templates = IOCList("template", hdr=False).list_datasets() for temp in templates: lgr.info(" {}".format(temp[3])) else: for j in range(1, count + 1): try: IOCCreate(release, props, j, pkglist, template=template, short=short, basejail=basejail, empty=empty).create_jail() except RuntimeError as err: lgr.error(err) if template: lgr.info("Created Templates:") templates = IOCList("template", hdr=False).list_datasets() for temp in templates: lgr.info(" {}".format(temp[3])) exit(1)
def destroy_cmd(force, release, download, jails): """Destroys the jail's 2 datasets and the snapshot from the RELEASE.""" lgr = ioc_logger.Logger('ioc_cli_destroy').getLogger() if download and not release: exit("--release (-r) must be specified as well!") if jails and not release: get_jid = IOCList().list_get_jid try: jail_list, paths = IOCList("uuid").list_datasets() except RuntimeError as err: err = str(err) if "Configuration is missing" in err: uuid = err.split()[5] pool = IOCJson().json_get_value("pool") path = f"{pool}/iocage/jails/{uuid}" IOCDestroy().__stop_jails__(path.replace(pool, "")) IOCDestroy().__destroy_parse_datasets__(path) exit() else: lgr.critical(err) exit(1) for jail in jails: _jail = { tag: uuid for (tag, uuid) in jail_list.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.critical(" {} ({})".format(u, t)) exit(1) else: lgr.critical("{} not found!".format(jail)) exit(1) if not force: lgr.warning("\nThis will destroy" " jail {} ({})".format(uuid, tag)) if not click.confirm("\nAre you sure?"): continue # no, continue to next jail status, _ = get_jid(uuid) # If the jail is not running, let's do this thing. if status and not force: lgr.critical(f"{uuid} ({tag}) is running.\nPlease stop " "it first!") exit(1) elif status and force: lgr.info("Stopping {} ({}).".format(uuid, tag)) IOCDestroy().destroy_jail(path) elif jails and release: pool = IOCJson().json_get_value("pool") for release in jails: path = f"{pool}/iocage/releases/{release}" if not force: lgr.warning(f"\nThis will destroy RELEASE: {release}") lgr.warning(" and any jail that was created with it.") if not click.confirm("\nAre you sure?"): continue IOCDestroy().__destroy_parse_datasets__(path) if download: path = f"{pool}/iocage/download/{release}" IOCDestroy().__destroy_parse_datasets__(path) elif not jails and release: lgr.critical("Please specify one or more RELEASEs!") exit(1) else: lgr.critical("Please specify one or more jails!") exit(1)
def callback(message): lgr = ioc_logger.Logger('ioc_cli_import').getLogger() lgr.info(message)
"""export module for the cli.""" import click import iocage.lib.ioc_logger as ioc_logger from iocage.lib.ioc_image import IOCImage from iocage.lib.ioc_list import IOCList __cmdname__ = "export_cmd" __rootcmd__ = True lgr = ioc_logger.Logger("ioc_cli_export").getLogger() def callback(message): lgr.info(message) @click.command(name="export", help="Exports a specified jail.") @click.argument("jail", required=True) def export_cmd(jail): """Make a recursive snapshot of the jail and export to a file.""" jails, paths = IOCList("uuid").list_datasets() _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag]
def fstab_cmd(action, fstab_string, jail): """ Looks for the jail supplied and passes the uuid, path and configuration location to manipulate the fstab. """ lgr = ioc_logger.Logger('ioc_cli_fstab').getLogger() pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") index = None _index = False fstab_string = list(fstab_string) _jails, paths = IOCList("uuid").list_datasets() if not fstab_string and action != "edit": lgr.critical("Please supply a fstab entry!") exit(1) _jail = { tag: uuid for (tag, uuid) in _jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) # 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]) except TypeError: lgr.critical("Please specify either a valid fstab " "entry or an index number.") exit(1) _index = True source, destination, fstype, options, dump, _pass = "", "", "", \ "", "", "" else: if action != "edit": try: source, destination, fstype, options, dump, _pass = \ fstab_string except ValueError: lgr.critical("Please specify a valid fstab entry!\n\n" "Example:\n /the/source /dest FSTYPE " "FSOPTIONS FSDUMP FSPASS") exit(1) else: source, destination, fstype, options, dump, _pass = "", "", \ "", "", \ "", "" if not _index and action == "add": destination = "{}/jails/{}/root".format(iocroot, uuid) + destination IOCFstab(uuid, tag, action, source, destination, fstype, options, dump, _pass, index=index)
"""restart module for the cli.""" from datetime import datetime from subprocess import PIPE, Popen import click import iocage.lib.ioc_logger as ioc_logger from iocage.lib.ioc_json import IOCJson from iocage.lib.ioc_list import IOCList from iocage.lib.ioc_start import IOCStart from iocage.lib.ioc_stop import IOCStop __cmdname__ = "restart_cmd" __rootcmd__ = True lgr = ioc_logger.Logger('ioc_cli_restart').getLogger() def check_type(uuid, tag, path, _all, soft): """ Checks the jail type and spits out an error or does the specified restart method. """ conf = IOCJson(path).json_load() if conf["type"] in ("jail", "plugin"): if not soft: __hard_restart__(uuid, tag, path, conf) else: __soft_restart__(uuid, tag, path, conf) elif conf["type"] == "basejail":
def snaplist_cmd(header, jail): """Allows a user to show resource usage of all jails.""" lgr = ioc_logger.Logger('ioc_cli_snaplist').getLogger() jails, paths = IOCList("uuid").list_datasets() pool = IOCJson().json_get_value("pool") snap_list = [] table = Texttable(max_width=0) _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.critical(" {} ({})".format(u, t)) exit(1) else: lgr.critical("{} not found!".format(jail)) exit(1) conf = IOCJson(path).json_load() if conf["template"] == "yes": full_path = "{}/iocage/templates/{}".format(pool, tag) else: full_path = "{}/iocage/jails/{}".format(pool, uuid) zconf = ["zfs", "get", "-H", "-o", "value"] snapshots = Popen(["zfs", "list", "-r", "-H", "-t", "snapshot", full_path], stdout=PIPE, stderr=PIPE).communicate()[0].decode("utf-8").split("\n") for snap in snapshots: # We get an empty list at the end. if snap: snap = snap.split() snapname = snap[0].rsplit("@")[1] root_snapname = snap[0].rsplit("@")[0].split("/")[-1] if root_snapname == "root": snapname += "/root" elif root_snapname != uuid and root_snapname != tag: # basejail datasets. continue creation = Popen( zconf + ["creation", snap[0]], stdout=PIPE).communicate()[0].decode("utf-8").strip() used = snap[1] referenced = Popen( zconf + ["referenced", snap[0]], stdout=PIPE).communicate()[0].decode("utf-8").strip() snap_list.append([snapname, creation, referenced, used]) 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) lgr.info(table.draw()) else: for snap in snap_list: lgr.info("\t".join(snap))
def chroot_cmd(jail, command): """Will chroot into a jail regardless if it's running.""" lgr = ioc_logger.Logger('ioc_cli_chroot').getLogger() jails, paths = IOCList("uuid").list_datasets() command = list(command) # We may be getting ';', '&&' and so forth. Adding the shell for safety. if len(command) == 1: command = ["/bin/sh", "-c"] + command if jail.startswith("-"): raise RuntimeError("Please specify a jail first!") _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.critical(" {} ({})".format(u, t)) exit(1) else: lgr.critical("{} not found!".format(jail)) exit(1) devfs_stderr = mount(f"{path}/root/dev", "devfs") if devfs_stderr: lgr.critical("Mounting devfs failed!") exit(1) fstab_stderr = mount(f"{path}/fstab", "fstab") if fstab_stderr: lgr.critical("Mounting devfs failed!") exit(1) chroot = Popen(["chroot", f"{path}/root"] + command) chroot.communicate() udevfs_stderr = umount(f"{path}/root/dev", "devfs") if udevfs_stderr: lgr.critical("Unmounting devfs failed!") exit(1) ufstab_stderr = umount(f"{path}/fstab", "fstab") if ufstab_stderr: if b"fstab reading failure\n" in ufstab_stderr: # By default our fstab is empty and will throw this error. pass else: lgr.critical("Unmounting fstab failed!") exit(1) if chroot.returncode: lgr.warning("Chroot had a non-zero exit code!")
def get_cmd(prop, _all, _pool, jail, recursive, header, plugin): """Get a list of jails and print the property.""" lgr = ioc_logger.Logger('ioc_cli_get').getLogger() get_jid = IOCList.list_get_jid jails, paths = IOCList("uuid").list_datasets() jail_list = [] table = Texttable(max_width=0) if _all: # Confusing I know. jail = prop prop = "all" if _pool: pool = IOCJson().json_get_value("pool") lgr.info(pool) exit() if recursive is None: if jail == "": lgr.info("Usage: iocage get [OPTIONS] PROP JAIL\n") lgr.critical("Missing argument \"jail\".") exit(1) _jail = { tag: uuid for (tag, uuid) in jails.items() if uuid.startswith(jail) or tag == jail } if len(_jail) == 1: tag, uuid = next(iter(_jail.items())) path = paths[tag] elif len(_jail) > 1: lgr.error("Multiple jails found for" " {}:".format(jail)) for t, u in sorted(_jail.items()): lgr.error(" {} ({})".format(u, t)) raise RuntimeError() else: lgr.critical("{} not found!".format(jail)) exit(1) if prop == "state": status, _ = get_jid(path.split("/")[3]) if status: state = "up" else: state = "down" lgr.info(state) elif plugin: _prop = prop.split(".") props = IOCJson(path).json_plugin_get_value(_prop) if isinstance(props, dict): lgr.info(json.dumps(props, indent=4)) else: pass elif prop == "all": props = IOCJson(path).json_get_value(prop) for p, v in props.items(): lgr.info("{}:{}".format(p, v)) elif prop == "fstab": pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") index = 0 with open("{}/jails/{}/fstab".format(iocroot, uuid), "r") as \ fstab: for line in fstab.readlines(): line = line.rsplit("#")[0].rstrip() jail_list.append([index, line.replace("\t", " ")]) index += 1 if header: jail_list.insert(0, ["INDEX", "FSTAB ENTRY"]) # We get an infinite float otherwise. table.set_cols_dtype(["t", "t"]) table.add_rows(jail_list) lgr.info(table.draw()) else: for fstab in jail_list: lgr.info("{}\t{}".format(fstab[0], fstab[1])) else: try: lgr.info(IOCJson(path).json_get_value(prop)) except: lgr.critical("{} is not a valid property!".format(prop)) exit(1) else: for j in jails: uuid = jails[j] path = paths[j] try: if prop == "state": status, _ = get_jid(path.split("/")[3]) if status: state = "up" else: state = "down" jail_list.append([uuid, j, state]) elif prop == "all": props = IOCJson(path).json_get_value(prop) for p, v in props.items(): jail_list.append([uuid, j, "{}:{}".format(p, v)]) else: jail_list.append( [uuid, j, IOCJson(path).json_get_value(prop)]) except: lgr.critical("{} is not a valid property!".format(prop)) exit(1) # Prints the table if header: jail_list.insert(0, ["UUID", "TAG", "PROP - {}".format(prop)]) # We get an infinite float otherwise. table.set_cols_dtype(["t", "t", "t"]) table.add_rows(jail_list) lgr.info(table.draw()) else: for jail in jail_list: lgr.info("\t".join(jail))