def create_jail(self): """ Create a snapshot of the user specified RELEASE dataset and clone a jail from that. The user can also specify properties to override the defaults. """ jail_uuid = str(uuid.uuid4()) if self.short: jail_uuid = jail_uuid[:8] location = "{}/jails/{}".format(self.iocroot, jail_uuid) if self.migrate: config = self.config else: if self.template: _type = "templates" else: _type = "releases" freebsd_version = "{}/{}/{}/root/bin/freebsd-version".format( self.iocroot, _type, self.release) try: if self.release[:4].endswith("-"): # 9.3-RELEASE and under don't actually have this binary. cloned_release = self.release else: with open(freebsd_version, "r") as r: for line in r: if line.startswith("USERLAND_VERSION"): cloned_release = line.rstrip().partition( "=")[2].strip('"') config = self.create_config(jail_uuid, cloned_release) except (IOError, OSError): if self.template: raise RuntimeError("Template: {} not found!".format( self.release)) else: raise RuntimeError("RELEASE: {} not found!".format( self.release)) jail = "{}/iocage/jails/{}/root".format(self.pool, jail_uuid) if self.template: try: check_call([ "zfs", "snapshot", "{}/iocage/templates/{}/root@{}".format( self.pool, self.release, jail_uuid) ], stderr=PIPE) except CalledProcessError: raise RuntimeError("Template: {} not found!".format( self.release)) Popen([ "zfs", "clone", "-p", "{}/iocage/templates/{}/root@{}".format( self.pool, self.release, jail_uuid), jail ], stdout=PIPE).communicate() # self.release is actually the templates name config["release"] = IOCJson("{}/templates/{}".format( self.iocroot, self.release)).json_get_value("release") config["cloned_release"] = IOCJson("{}/templates/{}".format( self.iocroot, self.release)).json_get_value("cloned_release") else: try: check_call([ "zfs", "snapshot", "{}/iocage/releases/{}/root@{}".format( self.pool, self.release, jail_uuid) ], stderr=PIPE) except CalledProcessError: raise RuntimeError("RELEASE: {} not found!".format( self.release)) Popen([ "zfs", "clone", "-p", "{}/iocage/releases/{}/root@{}".format( self.pool, self.release, jail_uuid), jail ], stdout=PIPE).communicate() iocjson = IOCJson(location) # This test is to avoid the same warnings during install_packages. if not self.plugin: for prop in self.props: key, _, value = prop.partition("=") if self.num != 0: if key == "tag": value = f"{value}_{self.num}" try: iocjson.json_check_prop(key, value, config) config[key] = value except RuntimeError as err: # Instead this will stay as default. self.lgr.warning(f"***\n{err}\n***\n") iocjson.json_write(config) # Just "touch" the fstab file, since it won't exist. open("{}/jails/{}/fstab".format(self.iocroot, jail_uuid), "wb").close() _tag = self.create_link(jail_uuid, config["tag"]) config["tag"] = _tag self.create_rc(location, config["host_hostname"]) if self.basejail: from iocage.lib.ioc_fstab import IOCFstab basedirs = [ "bin", "boot", "lib", "libexec", "rescue", "sbin", "usr/bin", "usr/include", "usr/lib", "usr/libexec", "usr/sbin", "usr/share", "usr/libdata", "usr/lib32" ] for bdir in basedirs: source = f"{self.iocroot}/releases/{self.release}/root/{bdir}" destination = f"{self.iocroot}/jails/{jail_uuid}/root/{bdir}" IOCFstab(jail_uuid, _tag, "add", source, destination, "nullfs", "ro", "0", "0", silent=True) config["basejail"] = "yes" iocjson.json_write(config) if not self.plugin: self.lgr.info("{} ({}) successfully created!".format( jail_uuid, _tag)) if self.pkglist: if config["ip4_addr"] == "none" and config["ip6_addr"] == "none": self.lgr.error(" ERROR: You need an IP address for the jail" " to install packages!\n") else: self.create_install_packages(jail_uuid, location, _tag, config) return jail_uuid
def create_jail(self): """ Create a snapshot of the user specified RELEASE dataset and clone a jail from that. The user can also specify properties to override the defaults. """ start = False if self.uuid: jail_uuid = self.uuid else: jail_uuid = str(uuid.uuid4()) if self.short: jail_uuid = jail_uuid[:8] location = "{}/jails/{}".format(self.iocroot, jail_uuid) if os.path.isdir(location): raise RuntimeError("The UUID is already in use by another jail.") if self.migrate: config = self.config else: try: if self.template: _type = "templates" temp_path = f"{self.iocroot}/{_type}/{self.release}" template_config = IOCJson(f"{temp_path}").json_get_value cloned_release = template_config("cloned_release") else: _type = "releases" rel_path = f"{self.iocroot}/{_type}/{self.release}" freebsd_version = f"{rel_path}/root/bin/freebsd-version" if not self.empty: if self.release[:4].endswith("-"): # 9.3-RELEASE and under don't actually have this # binary. cloned_release = self.release else: with open(freebsd_version, "r") as r: for line in r: if line.startswith("USERLAND_VERSION"): # Long lines ftw? cl = line.rstrip().partition("=")[2] cloned_release = cl.strip('"') else: cloned_release = "EMPTY" except (IOError, OSError, FileNotFoundError, UnboundLocalError): # Unintuitevly a missing template will throw a # UnboundLocalError as the missing file will kick the # migration routine for zfs props. We don't need that :) if self.template: raise RuntimeError("Template: {} not found!".format( self.release)) else: raise RuntimeError("RELEASE: {} not found!".format( self.release)) config = self.create_config(jail_uuid, cloned_release) jail = "{}/iocage/jails/{}/root".format(self.pool, jail_uuid) if self.template: try: check_call([ "zfs", "snapshot", "{}/iocage/templates/{}/root@{}".format( self.pool, self.release, jail_uuid) ], stderr=PIPE) except CalledProcessError: raise RuntimeError("Template: {} not found!".format( self.release)) Popen([ "zfs", "clone", "-p", "{}/iocage/templates/{}/root@{}".format( self.pool, self.release, jail_uuid), jail ], stdout=PIPE).communicate() # self.release is actually the templates name config["release"] = IOCJson("{}/templates/{}".format( self.iocroot, self.release)).json_get_value("release") config["cloned_release"] = IOCJson("{}/templates/{}".format( self.iocroot, self.release)).json_get_value("cloned_release") else: if not self.empty: try: check_call([ "zfs", "snapshot", "{}/iocage/releases/{}/root@{}".format( self.pool, self.release, jail_uuid) ], stderr=PIPE) except CalledProcessError: raise RuntimeError("RELEASE: {} not found!".format( self.release)) Popen([ "zfs", "clone", "-p", "{}/iocage/releases/{}/root@{}".format( self.pool, self.release, jail_uuid), jail ], stdout=PIPE).communicate() else: try: checkoutput(["zfs", "create", "-p", jail], stderr=PIPE) except CalledProcessError as err: raise RuntimeError(err.output.decode("utf-8").rstrip()) iocjson = IOCJson(location) # This test is to avoid the same warnings during install_packages. if not self.plugin: for prop in self.props: key, _, value = prop.partition("=") if self.num != 0: if key == "tag": value = f"{value}_{self.num}" elif key == "boot" and value == "on": start = True try: iocjson.json_check_prop(key, value, config) config[key] = value except RuntimeError as err: from iocage.lib.ioc_destroy import IOCDestroy iocjson.json_write(config) # Destroy counts on this. IOCDestroy().destroy_jail(location) raise RuntimeError(f"***\n{err}\n***\n") iocjson.json_write(config) # Just "touch" the fstab file, since it won't exist. open("{}/jails/{}/fstab".format(self.iocroot, jail_uuid), "wb").close() _tag = self.create_link(jail_uuid, config["tag"]) config["tag"] = _tag if not self.empty: self.create_rc(location, config["host_hostname"]) if self.basejail: from iocage.lib.ioc_fstab import IOCFstab basedirs = [ "bin", "boot", "lib", "libexec", "rescue", "sbin", "usr/bin", "usr/include", "usr/lib", "usr/libexec", "usr/sbin", "usr/share", "usr/libdata", "usr/lib32" ] for bdir in basedirs: if "-RELEASE" not in self.release: _type = "templates" else: _type = "releases" source = f"{self.iocroot}/{_type}/{self.release}/root/{bdir}" destination = f"{self.iocroot}/jails/{jail_uuid}/root/{bdir}" IOCFstab(jail_uuid, _tag, "add", source, destination, "nullfs", "ro", "0", "0", silent=True) config["basejail"] = "yes" iocjson.json_write(config) if self.empty: config["release"] = "EMPTY" config["cloned_release"] = "EMPTY" iocjson.json_write(config) if not self.plugin: self.lgr.info("{} ({}) successfully created!".format( jail_uuid, _tag)) if self.pkglist: if config["ip4_addr"] == "none" and config["ip6_addr"] == "none": self.lgr.warning(" You need an IP address for the" " jail to install packages!\n") else: self.create_install_packages(jail_uuid, location, _tag, config) if start: from iocage.lib.ioc_start import IOCStart IOCStart(jail_uuid, _tag, location, config) return jail_uuid