def test_create(release, hardened): prop = ("tag=test", ) prop_short = ("tag=test_short", ) if hardened: release = "{}-STABLE".format(release) IOCCreate(release, prop, 0).create_jail() IOCCreate(release, prop_short, 0, short=True).create_jail() assert True == True
def create(self, job, options): """Creates a jail.""" from iocage.lib.ioc_create import IOCCreate self.check_dataset_existence() release = options["release"] template = options["template"] pkglist = options["pkglist"] uuid = options["uuid"] basejail = options["basejail"] empty = options["empty"] short = options["short"] props = options["props"] pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") if template: release = template if not os.path.isdir(f"{iocroot}/releases/{release}") and not \ template and not empty: self.middleware.call('jail.fetch', {"release": release}).wait() IOCCreate(release, props, 0, pkglist, template=template, short=short, uuid=uuid, basejail=basejail, empty=empty).create_jail() return True
def create(self, options): """Creates a jail.""" from iocage.lib.ioc_create import IOCCreate self.check_dataset_existence() release = options.get("release", None) template = options.get("template", None) pkglist = options.get("pkglist", None) # uuid = options.get("uuid", None) Not in 0.9.7 basejail = options.get("basejail", False) empty = options.get("empty", False) short = options.get("short", False) props = options.get("props", []) pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") if template: release = template if not os.path.isdir(f"{iocroot}/releases/{release}") and not \ template and not empty: # FIXME: List index out of range # self.fetch(options={"release": release}) pass IOCCreate(release, props, 0, pkglist, template=template, short=short, basejail=basejail, empty=empty).create_jail() return True
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 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 json_set_value(self, prop, create_func=False): """Set a property for the specified jail.""" # Circular dep! Meh. from iocage.lib.ioc_list import IOCList from iocage.lib.ioc_create import IOCCreate key, _, value = prop.partition("=") conf = self.json_load() old_tag = conf["tag"] uuid = conf["host_hostuuid"] status, jid = IOCList.list_get_jid(uuid) conf[key] = value sysctls_cmd = ["sysctl", "-d", "security.jail.param"] jail_param_regex = re.compile("security.jail.param.") sysctls_list = Popen( sysctls_cmd, stdout=PIPE).communicate()[0].decode("utf-8").split() jail_params = [ p.replace("security.jail.param.", "").replace(":", "") for p in sysctls_list if re.match(jail_param_regex, p) ] single_period = [ "allow_raw_sockets", "allow_socket_af", "allow_set_hostname" ] if not create_func: if key == "tag": conf["tag"] = IOCCreate("", prop, 0).create_link(conf["host_hostuuid"], value, old_tag=old_tag) tag = conf["tag"] if key == "template": pool, iocroot = _get_pool_and_iocroot() old_location = "{}/iocage/jails/{}".format(pool, uuid) new_location = "{}/iocage/templates/{}".format(pool, old_tag) if status: raise RuntimeError(f"{uuid} ({old_tag}) is running.\nPlease" "stop it first!") jails, paths = IOCList("uuid").list_datasets() for j in jails: _uuid = jails[j] _path = f"{paths[j]}/root" t_old_path = f"{old_location}/root@{_uuid}" t_path = f"{new_location}/root@{_uuid}" if _uuid == uuid: continue origin = checkoutput( ["zfs", "get", "-H", "-o", "value", "origin", _path]).rstrip() if origin == t_old_path or origin == t_path: _status, _ = IOCList.list_get_jid(_uuid) if _status: raise RuntimeError(f"CHILD: {_uuid} ({j}) is" f" running.\nPlease stop it first!") if value == "yes": try: checkoutput( ["zfs", "rename", "-p", old_location, new_location], stderr=STDOUT) conf["type"] = "template" self.location = new_location.lstrip(pool).replace( "/iocage", iocroot) except CalledProcessError as err: raise RuntimeError("{}".format( err.output.decode("utf-8").rstrip())) self.lgr.info("{} ({}) converted to a template.".format( uuid, old_tag)) self.lgr.disabled = True elif value == "no": try: checkoutput( ["zfs", "rename", "-p", new_location, old_location], stderr=STDOUT) conf["type"] = "jail" self.location = old_location.lstrip(pool).replace( "/iocage", iocroot) except CalledProcessError as err: raise RuntimeError("{}".format( err.output.decode("utf-8").rstrip())) self.lgr.info("{} ({}) converted to a jail.".format( uuid, old_tag)) self.lgr.disabled = True self.json_check_prop(key, value, conf) self.json_write(conf) self.lgr.info("Property: {} has been updated to {}".format(key, value)) # Used for import if not create_func: if key == "tag": return tag # We can attempt to set a property in realtime to jail. if status: if key in single_period: key = key.replace("_", ".", 1) else: key = key.replace("_", ".") if key in jail_params: try: checkoutput([ "jail", "-m", "jid={}".format(jid), "{}={}".format( key, value) ], stderr=STDOUT) except CalledProcessError as err: raise RuntimeError("{}".format( err.output.decode("utf-8").rstrip()))
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 create_cmd(release, template, count, props, pkglist, basejail, short): lgr = logging.getLogger('ioc_cli_create') if not template and not release: raise RuntimeError( "Must supply either --template (-t) or --release (-r)!") if release and "=" in release: raise RuntimeError("Please supply a valid RELEASE!") if template: # We don't really care it's not a RELEASE at this point. release = template if pkglist: if not os.path.isfile(pkglist): _pkgformat = """ { "pkgs": [ "foo", "bar", ] }""" raise RuntimeError("{} does not exist!\nPlease supply a JSON file " "with the format:{}".format( pkglist, _pkgformat)) pool = IOCJson().json_get_value("pool") iocroot = IOCJson(pool).json_get_value("iocroot") if not os.path.isdir("{}/releases/{}".format(iocroot, release)) and not template: IOCFetch(release).fetch_release() if count == 1: try: IOCCreate(release, props, 0, pkglist, template=template, short=short, basejail=basejail).create_jail() except RuntimeError as err: lgr.error(err) if template: lgr.info("Created Templates:") templates = IOCList("template", hdr=False, rtrn_object=True).list_datasets() for temp in templates: lgr.info(" {}".format(temp)) else: for j in range(1, count + 1): try: IOCCreate(release, props, j, pkglist, template=template, short=short, basejail=basejail).create_jail() except RuntimeError as err: lgr.error(err) if template: lgr.info("Created Templates:") templates = IOCList("template", hdr=False, rtrn_object=True).list_datasets() for temp in templates: lgr.info(" {}".format(temp)) exit(1)