def pkg_cmd(command, jail): """Runs pkg with the command given inside the specified jail.""" lgr = logging.getLogger('ioc_cli_pkg') 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: raise RuntimeError("{} not found!".format(jail)) cmd = ("pkg", ) + command IOCExec(cmd, uuid, tag, path).exec_jail()
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] 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) status, _ = IOCList().list_get_jid(uuid) if status: lgr.critical("{} ({}) is runnning, stop the jail before " "exporting!".format(uuid, tag)) exit(1) IOCImage(callback=callback).export_jail(uuid, tag, path)
def destroy_cmd(force, jails): """Destroys the jail's 2 datasets and the snapshot from the RELEASE.""" lgr = logging.getLogger('ioc_cli_destroy') if jails: 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()[6] pool = IOCJson().json_get_value("pool") path = f"{pool}/iocage/jails/{uuid}" IOCDestroy().__stop_jails__(path.replace(pool, "")) IOCDestroy().__destroy_datasets__(path) exit() else: raise RuntimeError(err) 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.error(" {} ({})".format(u, t)) raise RuntimeError() else: raise RuntimeError("{} not found!".format(jail)) if not force: lgr.warning("\nWARNING: This 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: raise RuntimeError(f"{uuid} ({tag}) is running.\nPlease stop " "it first!") elif status and force: lgr.info("Stopping {} ({}).".format(uuid, tag)) IOCDestroy().destroy_jail(path) else: raise RuntimeError("Please specify one or more jails!")
def restart_cmd(jail, soft): """ Looks for the jail supplied and passes the uuid, path and configuration location to stop_jail and start_jail. """ jails, paths = IOCList("uuid").list_datasets() if jail == "ALL": for j in jails: uuid = jails[j] path = paths[j] check_type(uuid, j, path, True, soft) else: _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] check_type(uuid, tag, path, False, soft) 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)
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 chroot_cmd(jail, command): """Will chroot into a jail regardless if it's running.""" lgr = logging.getLogger('ioc_cli_chroot') 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.error(" {} ({})".format(u, t)) raise RuntimeError() else: raise RuntimeError("{} not found!".format(jail)) devfs_stderr = mount(f"{path}/root/dev", "devfs") if devfs_stderr: raise RuntimeError("ERROR: Mounting devfs failed!") fstab_stderr = mount(f"{path}/fstab", "fstab") if fstab_stderr: raise RuntimeError("ERROR: Mounting devfs failed!") chroot = Popen(["chroot", f"{path}/root"] + command) chroot.communicate() udevfs_stderr = umount(f"{path}/root/dev", "devfs") if udevfs_stderr: raise RuntimeError("ERROR: Unmounting devfs failed!") 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: raise RuntimeError("ERROR: Unmounting fstab failed!") if chroot.returncode: lgr.warning("WARNING: Chroot had a non-zero exit code!")
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 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" " {}:".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 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 check_jail_existence(self, jail): self.check_dataset_existence() 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] return tag, uuid, path elif len(_jail) > 1: raise RuntimeError("Multiple jails found for {}:".format(jail)) else: raise RuntimeError("{} not found!".format(jail))
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 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 upgrade_cmd(jail, release): """Runs upgrade with the command given inside the specified jail.""" lgr = logging.getLogger('ioc_cli_upgrade') 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] root_path = "{}/root".format(path) 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: raise RuntimeError("{} not found!".format(jail)) pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") freebsd_version = checkoutput(["freebsd-version"]) status, jid = IOCList.list_get_jid(uuid) conf = IOCJson(path).json_load() host_release = os.uname()[2] jail_release = conf["release"] started = False if conf["release"] == "EMPTY": raise RuntimeError("Upgrading is not supported for empty jails.") 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": raise RuntimeError("Please run \"iocage migrate\" before trying" " to upgrade {} ({})".format(uuid, tag)) elif conf["type"] == "template": raise RuntimeError("Please convert back to a jail before trying" " to upgrade {} ({})".format(uuid, tag)) else: raise RuntimeError("{} is not a supported jail type.".format( conf["type"])) _freebsd_version = "{}/releases/{}/root/bin/freebsd-version".format( iocroot, release) if "HBSD" in freebsd_version: Popen(["hbsd-upgrade", "-j", jid]).communicate() else: if os.path.isfile("{}/etc/freebsd-update.conf".format(root_path)): # 10.3-RELEASE and under lack this flag if float(host_release.partition("-")[0][:5]) <= 10.3: raise RuntimeError( "Host: {} is too old, please upgrade to " "10.3-RELEASE or above".format(host_release)) os.environ["PAGER"] = "/bin/cat" fetch = Popen([ "freebsd-update", "-b", root_path, "-d", "{}/var/db/freebsd-update/".format(root_path), "-f", "{}/etc/freebsd-update.conf".format(root_path), "--currently-running {}".format(jail_release), "-r", release, "upgrade" ], stdin=PIPE) fetch.communicate(b"y") while not __upgrade_install__(root_path, release): pass if release[:4].endswith("-"): # 9.3-RELEASE and under don't actually have this binary. new_release = release else: with open(_freebsd_version, "r") as r: for line in r: if line.startswith("USERLAND_VERSION"): new_release = line.rstrip().partition( "=")[2].strip('"') IOCJson(path, silent=True).json_set_value( "release={}".format(new_release)) if started: IOCStop(uuid, tag, path, conf, silent=True) lgr.info("\n{} ({}) successfully upgraded from {} to {}!".format( uuid, tag, jail_release, new_release))
def export_cmd(jail): """Make a recursive snapshot of the jail and export to a file.""" lgr = logging.getLogger('ioc_cli_export') pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") date = datetime.utcnow().strftime("%F") 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: raise RuntimeError("{} not found!".format(jail)) status, _ = IOCList().list_get_jid(uuid) if status: raise RuntimeError("{} ({}) is runnning, stop the jail before " "exporting!".format(uuid, tag)) images = "{}/images".format(iocroot) name = "{}_{}".format(uuid, date) image = "{}/{}_{}".format(images, name, tag) image_path = "{}{}".format(pool, path) jail_list = [] # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR target = "{}@ioc-export-{}".format(image_path, date) try: checkoutput(["zfs", "snapshot", "-r", target], stderr=STDOUT) except CalledProcessError as err: raise RuntimeError("ERROR: {}".format( err.output.decode("utf-8").rstrip())) 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: if len(dataset) == 54: _image = image jail_list.append(_image) elif len(dataset) > 54: image_name = dataset.partition("{}{}".format(pool, path))[2] name = image_name.replace("/", "_") _image = image + name jail_list.append(_image) target = "{}@ioc-export-{}".format(dataset, date) # Sending each individually as sending them recursively to a file does # not work how one expects. try: with open(_image, "wb") as export: lgr.info("Exporting dataset: {}".format(dataset)) check_call(["zfs", "send", target], stdout=export) except CalledProcessError as err: raise RuntimeError("ERROR: {}".format(err)) lgr.info("\nPreparing zip file: {}.zip.".format(image)) with zipfile.ZipFile("{}.zip".format(image), "w", compression=zipfile.ZIP_DEFLATED, allowZip64=True) as final: os.chdir(images) for jail in jail_list: final.write(jail) # Cleanup our mess. try: checkoutput(["zfs", "destroy", "-r", target], stderr=STDOUT) for jail in jail_list: os.remove(jail) except CalledProcessError as err: raise RuntimeError("ERROR: {}".format( err.output.decode("utf-8").rstrip())) lgr.info("\nExported: {}.zip".format(image))
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 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 start_cmd(rc, jails): """ Looks for the jail supplied and passes the uuid, path and configuration location to start_jail. """ lgr = logging.getLogger('ioc_cli_start') _jails, paths = IOCList("uuid").list_datasets() if rc: boot_order = {} for j in _jails: path = paths[j] conf = IOCJson(path).json_load() boot = conf["boot"] priority = conf["priority"] if boot == "on": boot_order[j] = int(priority) boot_order = OrderedDict(sorted(boot_order.items(), key=itemgetter(1))) for j in boot_order.keys(): uuid = _jails[j] path = paths[j] conf = IOCJson(path).json_load() status, _ = IOCList().list_get_jid(uuid) if not status: lgr.info(" Starting {} ({})".format(uuid, j)) IOCStart(uuid, j, path, conf, silent=True) else: lgr.info("{} ({}) is already running!".format(uuid, j)) exit() if len(jails) >= 1 and jails[0] == "ALL": if len(_jails) < 1: raise RuntimeError("No jails exist to start!") for j in _jails: uuid = _jails[j] path = paths[j] conf = IOCJson(path).json_load() IOCStart(uuid, j, path, conf) else: if len(jails) < 1: raise RuntimeError("Please specify either one or more jails or " "ALL!") for jail in jails: _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: raise RuntimeError("{} not found!".format(jail)) conf = IOCJson(path).json_load() if conf["type"] in ("jail", "plugin"): IOCStart(uuid, tag, path, conf) elif conf["type"] == "basejail": raise RuntimeError( "Please run \"iocage migrate\" before trying" " to start {} ({})".format(uuid, tag)) elif conf["type"] == "template": raise RuntimeError( "Please convert back to a jail before trying" " to start {} ({})".format(uuid, tag)) else: raise RuntimeError("{} is not a supported jail type.".format( conf["type"] ))
def get_cmd(prop, _all, _pool, jail, recursive, header, plugin): """Get a list of jails and print the property.""" lgr = logging.getLogger('ioc_cli_get') 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") raise RuntimeError("Error: Missing argument \"jail\".") _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: raise RuntimeError("{} not found!".format(jail)) 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: raise RuntimeError("{} is not a valid property!".format(prop)) 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: raise RuntimeError("{} is not a valid property!".format(prop)) # 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))
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)
def stop_cmd(rc, jails): """ Looks for the jail supplied and passes the uuid, path and configuration location to stop_jail. """ lgr = logging.getLogger('ioc_cli_stop') _jails, paths = IOCList("uuid").list_datasets() jail_order = {} boot_order = {} for j in _jails: path = paths[j] conf = IOCJson(path).json_load() boot = conf["boot"] priority = conf["priority"] jail_order[j] = int(priority) # This removes having to grab all the JSON again later. if boot == "on": boot_order[j] = int(priority) jail_order = OrderedDict( sorted(jail_order.items(), key=itemgetter(1), reverse=True)) boot_order = OrderedDict( sorted(boot_order.items(), key=itemgetter(1), reverse=True)) if rc: for j in boot_order.keys(): uuid = _jails[j] path = paths[j] conf = IOCJson(path).json_load() status, _ = IOCList().list_get_jid(uuid) if status: lgr.info(" Stopping {} ({})".format(uuid, j)) IOCStop(uuid, j, path, conf, silent=True) else: lgr.info("{} ({}) is not running!".format(uuid, j)) exit() if len(jails) >= 1 and jails[0] == "ALL": if len(_jails) < 1: raise RuntimeError("No jails exist to stop!") for j in jail_order: uuid = _jails[j] path = paths[j] conf = IOCJson(path).json_load() IOCStop(uuid, j, path, conf) else: if len(jails) < 1: raise RuntimeError("Please specify either one or more jails or " "ALL!") for jail in jails: _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: raise RuntimeError("{} not found!".format(jail)) conf = IOCJson(path).json_load() IOCStop(uuid, tag, path, conf)
def restart_cmd(jail, soft): """ Looks for the jail supplied and passes the uuid, path and configuration location to stop_jail and start_jail. """ lgr = logging.getLogger('ioc_cli_restart') jails, paths = IOCList("uuid").list_datasets() if jail == "ALL": for j in jails: uuid = jails[j] path = paths[j] conf = IOCJson(path).json_load() if conf["type"] in ("jail", "plugin"): try: if not soft: __hard_restart__(uuid, j, path, conf) else: __soft_restart__(uuid, j, path, conf) except RuntimeError as err: lgr.error(err) elif conf["type"] == "basejail": lgr.error("Please run \"iocage migrate\" before trying" " to restart {} ({})".format(uuid, j)) elif conf["type"] == "template": raise RuntimeError( "Please convert back to a jail before trying" " to restart {} ({})".format(uuid, j)) else: lgr.error("{} is not a supported jail type.".format( conf["type"])) else: _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: raise RuntimeError("{} not found!".format(jail)) 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": raise RuntimeError("Please run \"iocage migrate\" before trying" " to restart {} ({})".format(uuid, tag)) elif conf["type"] == "template": raise RuntimeError("Please convert back to a jail before trying" " to restart {} ({})".format(uuid, tag)) else: raise RuntimeError("{} is not a supported jail type.".format( conf["type"]))