def json_plugin_set_value(self, prop): from iocage.lib.ioc_exec import IOCExec from iocage.lib.ioc_list import IOCList pool, iocroot = _get_pool_and_iocroot() conf = self.json_load() uuid = conf["host_hostuuid"] tag = conf["tag"] _path = checkoutput([ "zfs", "get", "-H", "-o", "value", "mountpoint", "{}/iocage/jails/{}".format(pool, uuid) ]).rstrip() status, _ = IOCList().list_get_jid(uuid) # Plugin variables settings = self.json_plugin_load() serviceset = settings["serviceset"] servicerestart = settings["servicerestart"].split() keys, _, value = ".".join(prop).partition("=") prop = keys.split(".") restart = False if "options" in prop: prop = keys.split(".")[1:] prop_cmd = "{},{},{}".format(serviceset, ",".join(prop), value).split(",") setting = settings["options"] try: while prop: current = prop[0] key = current prop.remove(current) if not prop: if setting[current]: try: restart = setting[current]["requirerestart"] except KeyError: pass else: setting = setting[current] if status: # IOCExec will not show this if it doesn't start the jail. self.lgr.info("Command output:") IOCExec(prop_cmd, uuid, tag, _path).exec_jail() if restart: self.lgr.info("\n-- Restarting service --") self.lgr.info("Command output:") IOCExec(servicerestart, uuid, tag, _path).exec_jail() self.lgr.info("\nKey: {} has been updated to {}".format( keys, value)) except KeyError: raise RuntimeError("Key: \"{}\" does not exist!".format(key))
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 json_plugin_get_value(self, prop): from iocage.lib.ioc_exec import IOCExec pool, iocroot = _get_pool_and_iocroot() conf = self.json_load() uuid = conf["host_hostuuid"] tag = conf["tag"] _path = checkoutput([ "zfs", "get", "-H", "-o", "value", "mountpoint", "{}/iocage/jails/{}".format(pool, uuid) ]).rstrip() # Plugin variables settings = self.json_plugin_load() serviceget = settings["serviceget"] prop_error = ".".join(prop) if "options" in prop: _prop = prop[1:] else: _prop = prop prop_cmd = "{},{}".format(serviceget, ",".join(_prop)).split(",") try: if prop[0] != "all": if len(_prop) > 1: return get_nested_key(settings, prop) else: return IOCExec(prop_cmd, uuid, tag, _path).exec_jail() else: return settings except KeyError: raise RuntimeError( "Key: \"{}\" does not exist!".format(prop_error))
def exec(self, jail, command, options): """Issues a command inside a jail.""" from iocage.lib.ioc_exec import IOCExec tag, uuid, path = self.check_jail_existence(jail) host_user = options["host_user"] jail_user = options["jail_user"] # We may be getting ';', '&&' and so forth. Adding the shell for # safety. if len(command) == 1: command = ["/bin/sh", "-c"] + command msg, _ = IOCExec(command, uuid, tag, path, host_user, jail_user).exec_jail() return msg.decode("utf-8")
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 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 fetch_plugin(self, _json, props, num): """Expects an JSON object.""" with open(_json, "r") as j: conf = json.load(j) self.release = conf["release"] pkg_repos = conf["fingerprints"] freebsd_version = f"{self.iocroot}/releases/{conf['release']}" \ "/root/bin/freebsd-version" if num <= 1: self.lgr.info("Plugin: {}".format(conf["name"])) self.lgr.info(" Using RELEASE: {}".format(self.release)) self.lgr.info( " Post-install Artifact: {}".format(conf["artifact"])) self.lgr.info(" These pkgs will be installed:") for pkg in conf["pkgs"]: self.lgr.info(" - {}".format(pkg)) if not os.path.isdir("{}/releases/{}".format(self.iocroot, self.release)): self.fetch_release() if conf["release"][:4].endswith("-"): # 9.3-RELEASE and under don't actually have this binary. release = conf["release"] else: with open(freebsd_version, "r") as r: for line in r: if line.startswith("USERLAND_VERSION"): release = line.rstrip().partition("=")[2].strip( '"') # We set our properties that we need, and then iterate over the user # supplied properties replacing ours. Finally we add _1, _2 etc to # the tag with the final iteration if the user supplied count. create_props = [f"cloned_release={self.release}", f"release={release}", "type=plugin"] # If the user supplied a tag, we shouldn't add ours. if "tag" not in [p.split("=")[0] for p in props]: _tag = f"tag={conf['name']}" create_props += [_tag] else: for p in props: _p = p.split("=")[0] _tag = p if _p == "tag" else "" create_props = [f"{k}={v}" for k, v in (p.split("=") for p in props)] + create_props create_props = [f"{k}_{num}" if k == f"{_tag}" and num != 0 else k for k in create_props] uuid = IOCCreate(self.release, create_props, 0).create_jail() jaildir = "{}/jails/{}".format(self.iocroot, uuid) repo_dir = "{}/root/usr/local/etc/pkg/repos".format(jaildir) _conf = IOCJson(jaildir).json_load() tag = _conf["tag"] # We do this test again as the user could supply a malformed IP to # fetch that bypasses the more naive check in cli/fetch if _conf["ip4_addr"] == "none" and _conf["ip6_addr"] == "none": self.lgr.error("\nERROR: An IP address is needed to fetch a " "plugin!\n") self.lgr.error("Destroying partial plugin.") IOCDestroy(uuid, tag, jaildir).destroy_jail() raise RuntimeError() IOCStart(uuid, tag, jaildir, _conf, silent=True) try: os.makedirs(repo_dir, 0o755) except OSError: # It exists, that's fine. pass for repo in pkg_repos: repo_name = repo repo = pkg_repos[repo] f_dir = "{}/root/usr/local/etc/pkg/fingerprints/{}/trusted".format( jaildir, repo_name) repo_conf = """\ {reponame}: {{ url: "{packagesite}", signature_type: "fingerprints", fingerprints: "/usr/local/etc/pkg/fingerprints/{reponame}", enabled: true }} """ try: os.makedirs(f_dir, 0o755) except OSError: self.lgr.error("Repo: {} already exists, skipping!".format( repo_name)) r_file = "{}/{}.conf".format(repo_dir, repo_name) with open(r_file, "w") as r_conf: r_conf.write(repo_conf.format(reponame=repo_name, packagesite=conf["packagesite"])) f_file = "{}/{}".format(f_dir, repo_name) for r in repo: finger_conf = """\ function: {function} fingerprint: {fingerprint} """ with open(f_file, "w") as f_conf: f_conf.write(finger_conf.format(function=r["function"], fingerprint=r[ "fingerprint"])) err = IOCCreate(self.release, create_props, 0, plugin=True, pkglist=conf["pkgs"]).create_install_packages(uuid, jaildir, tag, _conf) if not err: # We need to pipe from tar to the root of the jail. if conf["artifact"]: # TODO: Fancier. self.lgr.info("Fetching artifact... ") Popen(["git", "clone", conf["artifact"], "{}/plugin".format(jaildir)], stdout=PIPE, stderr=PIPE).communicate() tar_in = Popen(["tar", "cvf", "-", "-C", "{}/plugin/overlay/".format(jaildir), "."], stdout=PIPE, stderr=PIPE).communicate() Popen(["tar", "xf", "-", "-C", "{}/root".format(jaildir)], stdin=PIPE).communicate(input=tar_in[0]) try: copy("{}/plugin/post_install.sh".format(jaildir), "{}/root/root".format(jaildir)) self.lgr.info("Running post_install.sh") command = ["sh", "/root/post_install.sh"] IOCExec(command, uuid, conf["name"], jaildir, skip=True).exec_jail() except (IOError, OSError): pass else: self.lgr.error("ERROR: pkg error, refusing to fetch artifact and " "run post_install.sh!\n")
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