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 test_stop(): jails, paths = IOCList("uuid").list_datasets() uuid = jails["test"] uuid_short = jails["test_short"] path = paths["test"] path_short = paths["test_short"] conf = IOCJson(path).json_load() conf_short = IOCJson(path_short).json_load() IOCStop(uuid, "test", path, conf) IOCStop(uuid_short, "test_short", path_short, conf_short) assert True == True
def destroy(self, jail): """Takes a jail and destroys it.""" from iocage.lib.ioc_destroy import IOCDestroy tag, uuid, path = self.check_jail_existence(jail) conf = IOCJson(path).json_load() status, _ = IOCList().list_get_jid(uuid) if status: from iocage.lib.ioc_stop import IOCStop IOCStop(uuid, tag, path, conf, silent=True) IOCDestroy(uuid, tag, path).destroy_jail() return True
def destroy_jail(self, path, clean=False): """ A convenience wrapper to call __stop_jails__ and __destroy_datasets__ """ dataset_type, uuid = path.rsplit("/")[-2:] if clean: self.__stop_jails__(path) else: from iocage.lib.ioc_stop import IOCStop conf = IOCJson(path).json_load() IOCStop(uuid, "", path, conf, silent=True) self.__destroy_datasets__(f"{self.pool}/iocage/{dataset_type}/{uuid}")
def stop(self, jail): """Takes a jail and stops it.""" from iocage.lib.ioc_stop import IOCStop tag, uuid, path = self.check_jail_existence(jail) conf = IOCJson(path).json_load() status, _ = IOCList().list_get_jid(uuid) if status: if conf["type"] in ("jail", "plugin"): IOCStop(uuid, tag, path, conf) return True else: raise RuntimeError(f"{jail} must be type jail or plugin to" " be stopped") else: raise RuntimeError(f"{jail} already stopped")
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 create_install_packages(self, jail_uuid, location, _tag, config): """ Takes a list of pkg's to install into the target jail. The resolver property is required for pkg to have network access. """ status, jid = IOCList().list_get_jid(jail_uuid) err = False if not status: IOCStart(jail_uuid, _tag, location, config, silent=True) resolver = config["resolver"] if resolver != "/etc/resolv.conf" and resolver != "none": with open("{}/etc/resolv.conf".format(location), "w") as resolv_conf: for line in resolver.split(";"): resolv_conf.write(line + "\n") else: copy(resolver, "{}/root/etc/resolv.conf".format(location)) status, jid = IOCList().list_get_jid(jail_uuid) if not self.plugin: with open(self.pkglist, "r") as j: self.pkglist = json.load(j)["pkgs"] self.lgr.info("\nInstalling pkg... ") # To avoid a user being prompted about pkg. Popen(["pkg-static", "-j", jid, "install", "-q", "-y", "pkg"], stderr=PIPE).communicate() # We will have mismatched ABI errors from earlier, this is to be safe. os.environ["ASSUME_ALWAYS_YES"] = "yes" cmd = ("pkg-static", "upgrade", "-f", "-q", "-y") pkg_upgrade = IOCExec(cmd, jail_uuid, _tag, location, plugin=self.plugin).exec_jail() if pkg_upgrade: self.lgr.error("ERROR: {}".format(pkg_upgrade.decode("utf-8"))) err = True self.lgr.info("Installing supplied packages:") for pkg in self.pkglist: self.lgr.info(" - {}... ".format(pkg)) cmd = ("pkg", "install", "-q", "-y", pkg) pkg_install = IOCExec(cmd, jail_uuid, _tag, location, plugin=self.plugin).exec_jail() if pkg_install: self.lgr.error("ERROR: {}".format(pkg_install)) err = True os.remove("{}/root/etc/resolv.conf".format(location)) if status: IOCStop(jail_uuid, _tag, location, config, silent=True) if self.plugin and err: return err
def json_load(self): """Load the JSON at the location given. Returns a JSON object.""" version = self.json_get_version() skip = False try: with open(self.location + "/config.json", "r") as conf: conf = json.load(conf) except FileNotFoundError: if path.isfile(self.location + "/config"): self.json_convert_from_ucl() with open(self.location + "/config.json", "r") as conf: conf = json.load(conf) else: try: dataset = self.location.split("/") for d in dataset: if len(d) == 36: uuid = d elif len(d) == 8: # Hack88 migration to a perm short UUID. pool, iocroot = _get_pool_and_iocroot() from iocage.lib.ioc_list import IOCList full_uuid = checkoutput([ "zfs", "get", "-H", "-o", "value", "org.freebsd.iocage:host_hostuuid", self.location ]).rstrip() jail_hostname = checkoutput([ "zfs", "get", "-H", "-o", "value", "org.freebsd.iocage:host_hostname", self.location ]).rstrip() short_uuid = full_uuid[:8] full_dataset = "{}/iocage/jails/{}".format( pool, full_uuid) short_dataset = "{}/iocage/jails/{}".format( pool, short_uuid) self.json_convert_from_zfs(full_uuid) with open(self.location + "/config.json", "r") as conf: conf = json.load(conf) self.lgr.info("hack88 is no longer supported." "\n{} is being converted to {} " "permanently.".format( full_dataset, short_dataset)) status, _ = IOCList().list_get_jid(full_uuid) if status: self.lgr.info( "Stopping jail to migrate UUIDs.") from iocage.lib.ioc_stop import IOCStop IOCStop(full_uuid, conf["tag"], self.location, conf, silent=True) jail_zfs_prop = \ "org.freebsd.iocage:jail_zfs_dataset" uuid_prop = "org.freebsd.iocage:host_hostuuid" host_prop = "org.freebsd.iocage:host_hostname" # Set jailed=off and move the jailed dataset. checkoutput([ "zfs", "set", "jailed=off", "{}/data".format(full_dataset) ]) # We don't want to change a real hostname. if jail_hostname == full_uuid: checkoutput([ "zfs", "set", "{}={}".format(host_prop, short_uuid), full_dataset ]) checkoutput([ "zfs", "set", "{}={}".format(uuid_prop, short_uuid), full_dataset ]) checkoutput([ "zfs", "set", "{}=iocage/jails/{}/data".format( jail_zfs_prop, short_uuid), "{}/data".format(full_dataset) ]) checkoutput([ "zfs", "rename", "-f", full_dataset, short_dataset ]) checkoutput([ "zfs", "set", "jailed=on", "{}/data".format(short_dataset) ]) uuid = short_uuid self.location = "{}/jails/{}".format( iocroot, short_uuid) skip = True self.json_convert_from_zfs(uuid, skip=skip) with open(self.location + "/config.json", "r") as conf: conf = json.load(conf) except CalledProcessError: # At this point it should be a real misconfigured jail raise RuntimeError("Configuration is missing!" f" Please destroy {uuid} and recreate" " it.") try: conf_version = conf["CONFIG_VERSION"] if version != conf_version: conf = self.json_check_config(conf, version) except KeyError: conf = self.json_check_config(conf, version) return conf
def create_install_packages(self, jail_uuid, location, _tag, config): """ Takes a list of pkg's to install into the target jail. The resolver property is required for pkg to have network access. """ status, jid = IOCList().list_get_jid(jail_uuid) err = False if not status: IOCStart(jail_uuid, _tag, location, config, silent=True) resolver = config["resolver"] if resolver != "/etc/resolv.conf" and resolver != "none": with open("{}/etc/resolv.conf".format(location), "w") as resolv_conf: for line in resolver.split(";"): resolv_conf.write(line + "\n") else: copy(resolver, "{}/root/etc/resolv.conf".format(location)) status, jid = IOCList().list_get_jid(jail_uuid) # Connectivity test courtesy David Cottlehuber off Google Group srv_connect_cmd = ["drill", "_http._tcp.pkg.freebsd.org", "SRV"] dnssec_connect_cmd = ["drill", "-D", "pkg.freebsd.org"] self.lgr.info("Testing SRV response to FreeBSD") srv_connection = IOCExec(srv_connect_cmd, jail_uuid, _tag, location, plugin=self.plugin).exec_jail() if srv_connection: raise RuntimeError(f"{srv_connection}\n" f"Command run: {' '.join(srv_connect_cmd)}") self.lgr.info("Testing DNSSEC response to FreeBSD") dnssec_connection = IOCExec(dnssec_connect_cmd, jail_uuid, _tag, location, plugin=self.plugin).exec_jail() if dnssec_connection: raise RuntimeError(f"{dnssec_connection}\n" f"Command run: {' '.join(dnssec_connect_cmd)}") if not self.plugin: with open(self.pkglist, "r") as j: self.pkglist = json.load(j)["pkgs"] self.lgr.info("\nInstalling pkg... ") # To avoid a user being prompted about pkg. Popen(["pkg-static", "-j", jid, "install", "-q", "-y", "pkg"], stderr=PIPE).communicate() # We will have mismatched ABI errors from earlier, this is to be safe. os.environ["ASSUME_ALWAYS_YES"] = "yes" cmd = ("pkg-static", "upgrade", "-f", "-q", "-y") pkg_upgrade = IOCExec(cmd, jail_uuid, _tag, location, plugin=self.plugin).exec_jail() if pkg_upgrade: self.lgr.error(f"{pkg_upgrade}") err = True self.lgr.info("Installing supplied packages:") for pkg in self.pkglist: self.lgr.info(" - {}... ".format(pkg)) cmd = ("pkg", "install", "-q", "-y", pkg) pkg_install = IOCExec(cmd, jail_uuid, _tag, location, plugin=self.plugin).exec_jail() if pkg_install: self.lgr.error("{}".format(pkg_install)) err = True os.remove("{}/root/etc/resolv.conf".format(location)) if status: IOCStop(jail_uuid, _tag, location, config, silent=True) if self.plugin and err: return err
def __hard_restart__(uuid, jail, path, conf): """Stops and then starts the jail.""" IOCStop(uuid, jail, path, conf) IOCStart(uuid, jail, path, conf)
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))