Beispiel #1
0
def cli(prop, jail, plugin):
    """Get a list of jails and print the property."""
    jails, paths = ioc_list.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 = ioc_json.IOCJson(path, cli=True)
    elif len(_jail) > 1:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })
        for t, u in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({t})"})
        exit(1)
    else:
        ioc_common.logit({"level": "ERROR", "message": f"{jail} not found!"})
        exit(1)

    if "template" in prop.split("=")[0]:
        if "template" in path and prop != "template=no":
            ioc_common.logit({
                "level":
                "ERROR",
                "message":
                f"{uuid} ({tag}) is already a template!"
            })
            exit(1)
        elif "template" not in path and prop != "template=yes":
            ioc_common.logit({
                "level": "ERROR",
                "message": f"{uuid} ({tag}) is already a jail!"
            })
            exit(1)
    if plugin:
        _prop = prop.split(".")
        err = ioc_json.IOCJson(path, cli=True).json_plugin_set_value(_prop)
        if err:
            exit(1)
    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]
            ioc_common.logit({
                "level": "ERROR",
                "message": f"{_prop} is not a valid property!"
            })
            exit(1)
Beispiel #2
0
 def __init__(self, jail=None, rc=False, callback=None, silent=False):
     self.pool = ioc_json.IOCJson().json_get_value("pool")
     self.iocroot = ioc_json.IOCJson(self.pool).json_get_value("iocroot")
     self.zfs = libzfs.ZFS(history=True, history_prefix="<iocage>")
     self.jails, self._paths = ioc_list.IOCList("uuid").list_datasets()
     self.jail = jail
     self.rc = rc
     self._all = True if self.jail and 'ALL' in self.jail else False
     self.callback = ioc_common.callback if not callback else callback
     self.silent = silent
Beispiel #3
0
def cli(jail, name):
    """Get a list of jails and print the property."""
    jails, paths = ioc_list.IOCList("uuid").list_datasets()
    pool = ioc_json.IOCJson().json_get_value("pool")
    date = datetime.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:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })
        for t, u in sorted(_jail.items()):
            ioc_common.logit({
                "level"  : "ERROR",
                "message": f"  {u} ({t})"
            })
        exit(1)
    else:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": f"{jail} not found!"
        })
        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 = ioc_json.IOCJson(path).json_load()

    if conf["template"] == "yes":
        target = f"{pool}/iocage/templates/{tag}@{name}"
    else:
        target = f"{pool}/iocage/jails/{uuid}@{name}"

    try:
        su.check_call(["zfs", "snapshot", "-r", target], stderr=su.PIPE)
        ioc_common.logit({
            "level"  : "INFO",
            "message": f"Snapshot: {target} created."
        })
    except su.CalledProcessError:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": "Snapshot already exists!"
        })
        exit(1)
Beispiel #4
0
def cli(jail, name):
    """Removes a snapshot from a user supplied jail."""
    # TODO: Move to API
    jails = ioc_list.IOCList("uuid").list_datasets()
    pool = ioc_json.IOCJson().json_get_value("pool")
    _jail = {
        uuid: path
        for (uuid, path) in jails.items() if uuid.startswith(jail)
    }

    if len(_jail) == 1:
        uuid, path = next(iter(_jail.items()))
    elif len(_jail) > 1:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })
        for u, p in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({p})"})
        exit(1)
    else:
        ioc_common.logit(
            {
                "level": "EXCEPTION",
                "message": f"{jail} not found!"
            },
            exit_on_error=True)

    # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR
    conf = ioc_json.IOCJson(path).json_load()

    if conf["template"] == "yes":
        target = f"{pool}/iocage/templates/{uuid}@{name}"
    else:
        target = f"{pool}/iocage/jails/{uuid}@{name}"

    try:
        su.check_call(["zfs", "destroy", "-r", "-f", target])
        ioc_common.logit({
            "level": "INFO",
            "message": f"Snapshot: {target} destroyed."
        })
    except su.CalledProcessError as err:
        ioc_common.logit({
            "level": "EXCEPTION",
            "message": f"{err}"
        },
                         exit_on_error=True)
        exit(1)
Beispiel #5
0
    def df(self, long=False):
        """Returns a list containing the resource usage of all jails"""
        jail_list = []

        for jail, path in self.jails.items():
            conf = ioc_json.IOCJson(path).json_load()
            mountpoint = f"{self.pool}/iocage/jails/{jail}"

            template = conf["type"]

            if template == "template":
                mountpoint = f"{self.pool}/iocage/templates/{jail}"

            ds = self.zfs.get_dataset(mountpoint)
            zconf = ds.properties

            compressratio = zconf["compressratio"].value
            reservation = zconf["reservation"].value
            quota = zconf["quota"].value
            used = zconf["used"].value
            available = zconf["available"].value

            jail_list.append(
                [jail, compressratio, reservation, quota, used, available])

        return jail_list
Beispiel #6
0
    def start(self, jail=None):
        """Checks jails type and existence, then starts the jail"""
        if self.rc or self._all:
            if not jail:
                self.__jail_order__("start")
        else:
            uuid, path = self.__check_jail_existence__()
            conf = ioc_json.IOCJson(path, silent=self.silent).json_load()
            err, msg = self.__check_jail_type__(conf["type"], uuid)
            depends = conf["depends"].split()

            if not err:
                for depend in depends:
                    if depend != "none":
                        self.jail = depend
                        self.start()

                ioc_start.IOCStart(uuid,
                                   path,
                                   conf,
                                   silent=self.silent,
                                   callback=self.callback)

                return False, None
            else:
                if jail:
                    return err, msg
                else:
                    self.callback({"level": "ERROR", "message": msg})
                    exit(1)
Beispiel #7
0
    def start(self, jail=None):
        """Checks jails type and existence, then starts the jail"""
        if self.rc or self._all:
            if not jail:
                self.__jail_order__("start")
        else:
            tag, uuid, path = self.__check_jail_existence__()
            conf = ioc_json.IOCJson(path).json_load()
            err, msg = self.__check_jail_type__(conf["type"], uuid, tag)

            if not err:
                ioc_start.IOCStart(uuid,
                                   tag,
                                   path,
                                   conf,
                                   callback=self.callback,
                                   silent=self.silent)

                return False, None
            else:
                if jail:
                    return err, msg
                else:
                    self.callback({"level": "ERROR", "message": msg})
                    exit(1)
Beispiel #8
0
    def snap_list(self, long=True):
        """Gathers a list of snapshots and returns it"""
        uuid, path = self.__check_jail_existence__()
        conf = ioc_json.IOCJson(path, silent=self.silent).json_load()
        snap_list = []

        if conf["template"] == "yes":
            full_path = f"{self.pool}/iocage/templates/{uuid}"
        else:
            full_path = f"{self.pool}/iocage/jails/{uuid}"

        snapshots = self.zfs.get_dataset(full_path)

        for snap in snapshots.snapshots_recursive:
            snap_name = snap.name.rsplit("@")[1] if not long else snap.name
            root_snap_name = snap.name.rsplit("@")[0].split("/")[-1]

            if root_snap_name == "root":
                snap_name += "/root"
            elif root_snap_name != uuid:
                # basejail datasets.
                continue

            creation = snap.properties["creation"].value
            used = snap.properties["used"].value
            referenced = snap.properties["referenced"].value

            snap_list.append([snap_name, creation, referenced, used])

        return snap_list
Beispiel #9
0
def __soft_restart__(uuid, jail, path, conf):
    """
    Will tear down the jail by running exec_stop and then exec_start, leaving
    the network stack intact, ideal for VIMAGE.
    """
    getjid = ioc_list.IOCList().list_get_jid(uuid)
    status, jid = getjid

    # These needs to be a list.
    exec_start = conf["exec_start"].split()
    exec_stop = conf["exec_stop"].split()
    exec_fib = conf["exec_fib"]

    if status:
        ioc_common.logit({
            "level"  : "INFO",
            "message": f"Soft restarting {uuid} ({jail})"
        })
        stop_cmd = ["setfib", exec_fib, "jexec", f"ioc-{uuid}"] + exec_stop
        su.Popen(stop_cmd, stdout=su.PIPE, stderr=su.PIPE).communicate()

        su.Popen(["pkill", "-j", jid]).communicate()
        start_cmd = ["setfib", exec_fib, "jexec", f"ioc-{uuid}"] + exec_start
        su.Popen(start_cmd, stdout=su.PIPE, stderr=su.PIPE).communicate()
        ioc_json.IOCJson(path, silent=True).json_set_value(
            f"last_started={datetime.datetime.utcnow().strftime('%F %T')}")
    else:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": f"{jail} is not running!"
        })
        exit(1)
Beispiel #10
0
    def __jail_order__(self, action):
        """Helper to gather lists of all the jails by order and boot order."""
        jail_order = {}
        boot_order = {}

        _reverse = True if action == 'stop' else False

        for jail in self.jails:
            self.jail = jail
            tag, uuid, path = self.__check_jail_existence__()
            conf = ioc_json.IOCJson(path).json_load()
            boot = conf['boot']
            priority = conf['priority']
            jail_order[jail] = int(priority)

            # This removes having to grab all the JSON again later.
            if boot == 'on':
                boot_order[jail] = int(priority)

            jail_order = collections.OrderedDict(
                sorted(jail_order.items(),
                       key=operator.itemgetter(1),
                       reverse=_reverse))
            boot_order = collections.OrderedDict(
                sorted(boot_order.items(),
                       key=operator.itemgetter(1),
                       reverse=_reverse))

        if self.rc:
            self.__rc__(boot_order, action)
        elif self._all:
            self.__all__(jail_order, action)
Beispiel #11
0
    def get_iocroot(self):
        """
        Helper to get the iocroot.

        Return:
                string: with the iocroot name.
        """
        return ioc_json.IOCJson(self.pool).json_get_value("iocroot")
Beispiel #12
0
 def stop(self, jail=None):
     """Stops the jail."""
     if self.rc or self._all:
         if not jail:
             self.__jail_order__("stop")
     else:
         tag, uuid, path = self.__check_jail_existence__()
         conf = ioc_json.IOCJson(path).json_load()
         ioc_stop.IOCStop(uuid, tag, path, conf, silent=self.silent)
Beispiel #13
0
    def __soft_restart__(self):
        """
        Executes a soft reboot by keeping the jail network stack intact,
        but executing the rc scripts.
        """
        uuid, path = self.__check_jail_existence__()
        status, jid = self.list("jid", uuid=uuid)
        conf = ioc_json.IOCJson(path, silent=self.silent).json_load()

        # These need to be a list.
        exec_start = conf["exec_start"].split()
        exec_stop = conf["exec_stop"].split()
        exec_fib = conf["exec_fib"]

        if status:
            ioc_common.logit(
                {
                    "level": "INFO",
                    "message": f"Soft restarting {uuid} ({self.jail})"
                },
                _callback=self.callback,
                silent=self.silent)

            stop_cmd = [
                "setfib", exec_fib, "jexec", f"ioc-{uuid.replace('.', '_')}"
            ] + exec_stop
            su.Popen(stop_cmd, stdout=su.PIPE, stderr=su.PIPE).communicate()

            su.Popen(["pkill", "-j", jid]).communicate()
            start_cmd = [
                "setfib", exec_fib, "jexec", f"ioc-{uuid.replace('.', '_')}"
            ] + exec_start
            su.Popen(start_cmd, stdout=su.PIPE, stderr=su.PIPE).communicate()
            ioc_json.IOCJson(path, silent=True).json_set_value(
                f"last_started={datetime.datetime.utcnow().strftime('%F %T')}")
        else:
            ioc_common.logit(
                {
                    "level": "ERROR",
                    "message": f"{self.jail} is not running!"
                },
                _callback=self.callback,
                silent=self.silent)
Beispiel #14
0
    def __jail_start__(self, jail, silent=False):
        """Checks jails type and existence, then starts the jail"""
        tag, uuid, path = self.__check_jail_existence__(jail)
        conf = ioc_json.IOCJson(path).json_load()
        err, msg = self.__check_jail_type__(conf, uuid, tag)

        if not err:
            ioc_start.IOCStart(uuid, tag, path, conf, silent)

            return False, None
        else:
            return err, msg
Beispiel #15
0
    def rollback(self, name):
        """Rolls back a jail and all datasets to the supplied snapshot"""
        uuid, path = self.__check_jail_existence__()
        conf = ioc_json.IOCJson(path, silent=self.silent).json_load()
        status, _ = self.list("jid", uuid=uuid)

        if status:
            ioc_common.logit(
                {
                    "level": "EXCEPTION",
                    "message": f"Please stop {uuid} before trying to"
                    " rollback!"
                },
                _callback=self.callback,
                silent=self.silent)

        if conf["template"] == "yes":
            target = f"{self.pool}/iocage/templates/{uuid}"
        else:
            target = f"{self.pool}/iocage/jails/{uuid}"

        try:
            datasets = self.zfs.get_dataset(target)
            self.zfs.get_snapshot(f"{datasets.name}@{name}")
        except libzfs.ZFSException as err:
            ioc_common.logit({
                "level": "EXCEPTION",
                "message": err
            },
                             _callback=self.callback,
                             silent=self.silent)

        for dataset in datasets.dependents:
            if dataset.type == libzfs.DatasetType.FILESYSTEM:
                self.zfs.get_snapshot(f"{dataset.name}@{name}").rollback()

        # datasets is actually the parent.
        self.zfs.get_snapshot(f"{datasets.name}@{name}").rollback()

        ioc_common.logit(
            {
                "level": "INFO",
                "message": f"Rolled back to: {target}"
            },
            _callback=self.callback,
            silent=self.silent)
Beispiel #16
0
def check_type(uuid, tag, path, _all, soft):
    """
    Checks the jail type and spits out an error or does the specified 
    restart method.
    """
    conf = ioc_json.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":
        ioc_common.logit({
            "level"  : "ERROR",
            "message": "Please run \"iocage migrate\" before trying"
                       f" to restart {uuid} ({tag})"
        })
        if not _all:
            exit(1)
    elif conf["type"] == "template":
        ioc_common.logit({
            "level"  : "ERROR",
            "message": "Please convert back to a jail before trying"
                       f" to restart {uuid} ({tag})"
        })
        if not _all:
            exit(1)
    else:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": f"{conf['type']} is not a supported jail type."
        })

        if not _all:
            exit(1)
Beispiel #17
0
def cli(force, delete):
    """Migrates all the iocage_legacy develop basejails to clone jails."""
    # TODO: Move to API
    jails = ioc_list.IOCList("uuid").list_datasets()

    if not force:
        ioc_common.logit({
            "level":
            "WARNING",
            "message":
            "\nThis will migrate ALL iocage-legacy develop"
            " basejails to clonejails, it can take a long"
            " time!\nPlease make sure you are not running"
            " this on iocage-legacy 1.7.6 basejails."
        })

        if not click.confirm("\nAre you sure?"):
            exit()

    for uuid, path in jails.items():
        pool = ioc_json.IOCJson().json_get_value("pool")
        iocroot = ioc_json.IOCJson(pool).json_get_value("iocroot")
        jail = f"{pool}/iocage/jails/{uuid}"
        jail_old = f"{pool}/iocage/jails_old/{uuid}"
        conf = ioc_json.IOCJson(path).json_load()

        try:
            tag = conf["tag"]
        except KeyError:
            # These are actually NEW jails.

            continue

        release = conf["cloned_release"]

        if conf["type"] == "basejail":
            try:
                ioc_common.checkoutput(["zfs", "rename", "-p", jail, jail_old],
                                       stderr=su.STDOUT)
            except su.CalledProcessError as err:
                ioc_common.logit(
                    {
                        "level": "EXCEPTION",
                        "message": f"{err.output.decode('utf-8').strip()}"
                    },
                    exit_on_error=True)

            try:
                os.remove(f"{iocroot}/tags/{tag}")
            except OSError:
                pass

            date_fmt_legacy = "%Y-%m-%d@%H:%M:%S"

            # We don't want to rename datasets to a bunch of dates.
            try:
                datetime.datetime.strptime(tag, date_fmt_legacy)
                _name = str(uuid.uuid4())
            except ValueError:
                # They already named this jail, making it like our new ones.
                _name = tag

            new_uuid = ioc_create.IOCCreate(release,
                                            "",
                                            0,
                                            None,
                                            migrate=True,
                                            config=conf,
                                            silent=True,
                                            uuid=_name,
                                            exit_on_error=True).create_jail()
            new_prop = ioc_json.IOCJson(f"{iocroot}/jails/{new_uuid}",
                                        silent=True).json_set_value
            new_prop(f"host_hostname={new_uuid}")
            new_prop(f"host_hostuuid={new_uuid}")
            new_prop("type=jail")
            new_prop(f"jail_zfs_dataset={iocroot}/jails/{new_uuid}/data")

            ioc_common.logit({
                "level":
                "INFO",
                "message":
                f"Copying files for {new_uuid}, please wait..."
            })

            ioc_common.copytree(f"{iocroot}/jails_old/{uuid}/root",
                                f"{iocroot}/jails/{new_uuid}/root",
                                symlinks=True)

            shutil.copy(f"{iocroot}/jails_old/{uuid}/fstab",
                        f"{iocroot}/jails/{new_uuid}/fstab")

            for line in fileinput.input(
                    f"{iocroot}/jails/{new_uuid}/root/etc/"
                    "rc.conf", inplace=1):
                print(
                    line.replace(f'hostname="{uuid}"',
                                 f'hostname="{new_uuid}"').rstrip())

            if delete:
                try:
                    ioc_common.checkoutput(
                        ["zfs", "destroy", "-r", "-f", jail_old],
                        stderr=su.STDOUT)
                except su.CalledProcessError as err:
                    raise RuntimeError(
                        f"{err.output.decode('utf-8').rstrip()}")

                try:
                    su.check_call([
                        "zfs", "destroy", "-r", "-f",
                        f"{pool}/iocage/jails_old"
                    ])
                except su.CalledProcessError:
                    # We just want the top level dataset gone, no big deal.
                    pass

            ioc_common.logit({
                "level":
                "INFO",
                "message":
                f"{uuid} ({tag}) migrated to {new_uuid}!\n"
            })
Beispiel #18
0
def cli(jail, release):
    """Runs upgrade with the command given inside the specified jail."""
    # TODO: Move to API
    release = release.rsplit("-", 1)[0].rsplit("-", 1)[0]
    host_release = os.uname()[2].rsplit("-", 1)[0].rsplit("-", 1)[0]

    if release is not None:
        if host_release < release:
            ioc_common.logit({
                "level":
                "EXCEPTION",
                "message":
                f"\nHost: {host_release} is not greater than"
                f" target: {release}\nThis is unsupported."
            })

    jails = ioc_list.IOCList("uuid").list_datasets()
    _jail = {
        uuid: path
        for (uuid, path) in jails.items() if uuid.startswith(jail)
    }

    if len(_jail) == 1:
        uuid, path = next(iter(_jail.items()))
        root_path = f"{path}/root"
    elif len(_jail) > 1:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })

        for u, p in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({p})"})
        exit(1)
    else:
        ioc_common.logit(
            {
                "level": "EXCEPTION",
                "message": f"{jail} not found!"
            },
            exit_on_error=True)

    status, jid = ioc_list.IOCList.list_get_jid(uuid)
    conf = ioc_json.IOCJson(path).json_load()
    jail_release = conf["release"]

    if release in jail_release:
        ioc_common.logit(
            {
                "level": "EXCEPTION",
                "message": f"Jail: {uuid} is already at version {release}!"
            },
            exit_on_error=True)

    started = False

    if conf["release"] == "EMPTY":
        ioc_common.logit(
            {
                "level": "EXCEPTION",
                "message": "Upgrading is not supported for empty jails."
            },
            exit_on_error=True)

    if conf["type"] == "jail":
        if not status:
            ioc_start.IOCStart(uuid, path, conf, silent=True)
            started = True

        new_release = ioc_upgrade.IOCUpgrade(conf, release,
                                             root_path).upgrade_jail()
    elif conf["type"] == "basejail":
        ioc_common.logit(
            {
                "level":
                "EXCEPTION",
                "message":
                "Please run \"iocage migrate\" before trying"
                f" to upgrade {uuid}"
            },
            exit_on_error=True)
    elif conf["type"] == "template":
        ioc_common.logit(
            {
                "level":
                "EXCEPTION",
                "message":
                "Please convert back to a jail before trying"
                f" to upgrade {uuid}"
            },
            exit_on_error=True)
    else:
        ioc_common.logit(
            {
                "level": "EXCEPTION",
                "message": f"{conf['type']} is not a supported jail type."
            },
            exit_on_error=True)

    if started:
        ioc_stop.IOCStop(uuid, path, conf, silent=True)

        ioc_common.logit({
            "level":
            "INFO",
            "message":
            f"\n{uuid} successfully upgraded from"
            f" {jail_release} to {new_release}!"
        })
Beispiel #19
0
def cli(action, fstab_string, jail):
    """
    Looks for the jail supplied and passes the uuid, path and configuration
    location to manipulate the fstab.
    """
    pool = ioc_json.IOCJson().json_get_value("pool")
    iocroot = ioc_json.IOCJson(pool).json_get_value("iocroot")
    index = None
    _index = False
    fstab_string = list(fstab_string)

    _jails, paths = ioc_list.IOCList("uuid").list_datasets()

    if not fstab_string and action != "edit":
        ioc_common.logit({
            "level": "ERROR",
            "message": "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:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })
        for t, u in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({t})"})
        exit(1)
    else:
        ioc_common.logit({"level": "ERROR", "message": f"{jail} not found!"})
        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])

                _index = True
                source, destination, fstype, options, dump, _pass = "", "", \
                                                                    "", "", \
                                                                    "", ""
            except TypeError:
                ioc_common.logit({
                    "level":
                    "ERROR",
                    "message":
                    "Please specify either a valid fstab "
                    "entry or an index number."
                })
                exit(1)
            except ValueError:
                # We will assume this is just a source, and will do a readonly
                # nullfs mount
                source = fstab_string[0]
                destination = source
                fstype = "nullfs"
                options = "ro"
                dump = "0"
                _pass = "******"
    else:
        if action != "edit":
            try:
                source, destination, fstype, options, dump, _pass = \
                    fstab_string
            except ValueError:
                ioc_common.logit({
                    "level":
                    "ERROR",
                    "message":
                    "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 = f"{iocroot}/jails/{uuid}/root{destination}"

    ioc_fstab.IOCFstab(uuid,
                       tag,
                       action,
                       source,
                       destination,
                       fstype,
                       options,
                       dump,
                       _pass,
                       index=index)
Beispiel #20
0
def cli(jail, name, force):
    """Get a list of jails and print the property."""
    jails, paths = ioc_list.IOCList("uuid").list_datasets()
    pool = ioc_json.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:
        ioc_common.logit({
            "level": "ERROR",
            "message": "Multiple jails found for"
            f" {jail}:"
        })
        for t, u in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({t})"})
        exit(1)
    else:
        ioc_common.logit({"level": "ERROR", "message": f"{jail} not found!"})
        exit(1)

    # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR
    conf = ioc_json.IOCJson(path).json_load()

    if conf["template"] == "yes":
        target = f"{pool}/iocage/templates/{tag}"
    else:
        target = f"{pool}/iocage/jails/{uuid}"

    try:
        ioc_common.checkoutput(["zfs", "get", "-H", "creation", target],
                               stderr=su.PIPE)
    except su.CalledProcessError:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Snapshot {target} does not exist!"
        })
        exit(1)

    if not force:
        ioc_common.logit({
            "level":
            "WARNING",
            "message":
            "\nThis will destroy ALL data created since"
            f" {name} was taken.\nIncluding ALL snapshots taken"
            f" after {name} for {uuid} ({tag})"
        })
        if not click.confirm("\nAre you sure?"):
            exit()
    try:
        datasets = su.Popen(
            ["zfs", "list", "-H", "-r", "-o", "name", target],
            stdout=su.PIPE,
            stderr=su.PIPE).communicate()[0].decode("utf-8").split()

        for dataset in datasets:
            su.check_call(["zfs", "rollback", "-r", f"{dataset}@{name}"])

        ioc_common.logit({
            "level": "INFO",
            "message": f"Rolled back to: {target}"
        })
    except su.CalledProcessError as err:
        ioc_common.logit({"level": "ERROR", "message": f"{err}"})
        exit(1)
Beispiel #21
0
    def mng_jail(self, rc, jails, action):
        """Starts and stops jails."""
        if action.lower() not in ('start', 'stop'):
            raise ValueError('You must specify [start|stop] as an action.')

        jail_order = {}
        boot_order = {}

        _reverse = True if action == 'stop' else False
        _all = True if 'ALL' in jails else False
        jails = self.jails if rc or _all else jails

        if len(jails) < 1:
            if self.callback:
                message = "Please specify either one or more jails or ALL!"
                self.__callback__({'level': 'CRITICAL', 'message': message})

                exit(1)
        else:
            for jail in jails:
                tag, uuid, path = self.__check_jail_existence__(jail)
                conf = ioc_json.IOCJson(path).json_load()
                boot = conf['boot']
                priority = conf['priority']
                jail_order[jail] = int(priority)

                # This removes having to grab all the JSON again later.
                if boot == 'on':
                    boot_order[jail] = int(priority)

                jail_order = OrderedDict(
                    sorted(jail_order.items(),
                           key=itemgetter(1),
                           reverse=_reverse))
                boot_order = OrderedDict(
                    sorted(boot_order.items(),
                           key=itemgetter(1),
                           reverse=_reverse))

            if rc:
                for j in boot_order.keys():
                    tag, uuid, path = self.__check_jail_existence__(j)
                    status, _ = ioc_list.IOCList().list_get_jid(uuid)

                    if action == 'stop':
                        if status:
                            message = f"  Stopping {uuid} ({j})"
                            self.__callback__({
                                'level': 'INFO',
                                'message': message
                            })
                            self.__jail_stop__(j, True)
                        else:
                            message = f"{uuid} ({j}) is not running!"
                            self.__callback__({
                                'level': 'INFO',
                                'message': message
                            })
                    elif action == 'start':
                        if not status:
                            err, msg = self.__jail_start__(j)

                            if err:
                                self.__callback__({
                                    'level': 'ERROR',
                                    'message': msg
                                })
                        else:
                            message = f"{uuid} ({j}) is already running!"
                            self.__callback__({
                                'level': 'WARNING',
                                'message': message
                            })
                exit()

            else:
                if _all:
                    for j in jail_order:
                        if action == 'stop':
                            self.__jail_stop__(j)
                        elif action == 'start':
                            err, msg = self.__jail_start__(j)

                            if err:
                                self.__callback__({
                                    'level': 'WARNING',
                                    'message': msg
                                })
                else:
                    if action == 'start':
                        err, msg = self.__jail_start__(jail)

                        if err and msg:
                            self.__callback__({
                                'level': 'CRITICAL',
                                'message': msg
                            })
                            exit(1)
                    elif action == 'stop':
                        self.__jail_stop__(jail)
Beispiel #22
0
    def get(self, prop, recursive=False, plugin=False, pool=False):
        """Get a jail property"""
        if pool:
            return self.pool

        if not recursive:
            if self.jail == "default":
                try:
                    return ioc_json.IOCJson().json_get_value(prop,
                                                             default=True)
                except KeyError:
                    ioc_common.logit(
                        {
                            "level": "EXCEPTION",
                            "message": f"{prop} is not a valid property!"
                        },
                        _callback=self.callback,
                        silent=self.silent)

            uuid, path = self.__check_jail_existence__()
            status, jid = self.list("jid", uuid=uuid)

            if prop == "state":
                if status:
                    state = "up"
                else:
                    state = "down"

                return state
            elif plugin:
                _prop = prop.split(".")
                props = ioc_json.IOCJson(path).json_plugin_get_value(_prop)

                if isinstance(props, dict):
                    return json.dumps(props, indent=4)
                else:
                    return props[0].decode("utf-8")
            elif prop == "all":
                props = ioc_json.IOCJson(path).json_get_value(prop)

                return props
            else:
                try:
                    return ioc_json.IOCJson(path).json_get_value(prop)
                except KeyError:
                    ioc_common.logit(
                        {
                            "level": "EXCEPTION",
                            "message": f"{prop} is not a valid property!"
                        },
                        _callback=self.callback,
                        silent=self.silent)
        else:
            jail_list = []

            for uuid, path in self.jails.items():
                try:
                    if prop == "state":
                        status, _ = self.list("jid", uuid=uuid)

                        if status:
                            state = "up"
                        else:
                            state = "down"

                        jail_list.append({uuid: state})
                    elif prop == "all":
                        props = ioc_json.IOCJson(path).json_get_value(prop)

                        jail_list.append({uuid: props})
                    else:
                        jail_list.append({
                            uuid:
                            ioc_json.IOCJson(path).json_get_value(prop)
                        })
                except KeyError:
                    ioc_common.logit(
                        {
                            "level": "EXCEPTION",
                            "message": f"{prop} is not a valid property!"
                        },
                        _callback=self.callback,
                        silent=self.silent)

            return jail_list
Beispiel #23
0
 def __init__(self):
     self.pool = ioc_json.IOCJson().json_get_value("pool")
     self.zfs = libzfs.ZFS(history=True, history_prefix="<iocage>")
Beispiel #24
0
def cli(header, jail):
    """Allows a user to show resource usage of all jails."""
    jails, paths = ioc_list.IOCList("uuid").list_datasets()
    pool = ioc_json.IOCJson().json_get_value("pool")
    snap_list = []
    table = texttable.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:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })
        for t, u in sorted(_jail.items()):
            ioc_common.logit({
                "level"  : "ERROR",
                "message": f"  {u} ({t})"
            })
        exit(1)
    else:
        ioc_common.logit({
            "level"  : "ERROR",
            "message": f"{jail} not found!"
        })
        exit(1)

    conf = ioc_json.IOCJson(path).json_load()

    if conf["template"] == "yes":
        full_path = f"{pool}/iocage/templates/{tag}"
    else:
        full_path = f"{pool}/iocage/jails/{uuid}"

    zconf = ["zfs", "get", "-H", "-o", "value"]
    snapshots = su.Popen(["zfs", "list", "-r", "-H", "-t", "snapshot",
                          full_path], stdout=su.PIPE,
                         stderr=su.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 = su.Popen(zconf + ["creation", snap[0]],
                                stdout=su.PIPE).communicate()[0].decode(
                "utf-8").strip()
            used = snap[1]
            referenced = su.Popen(zconf + ["referenced", snap[0]],
                                  stdout=su.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)
        ioc_common.logit({
            "level"  : "INFO",
            "message": table.draw()
        })
    else:
        for snap in snap_list:
            ioc_common.logit({
                "level"  : "INFO",
                "message": "\t".join(snap)
            })
Beispiel #25
0
def cli(force, release, download, jails):
    """Destroys the jail's 2 datasets and the snapshot from the RELEASE."""
    if download and not release:
        exit("--release (-r) must be specified as well!")

    if jails and not release:
        get_jid = ioc_list.IOCList().list_get_jid

        try:
            jail_list, paths = ioc_list.IOCList("uuid").list_datasets()
        except RuntimeError as err:
            err = str(err)

            if "Configuration is missing" in err:
                uuid = err.split()[5]
                pool = ioc_json.IOCJson().json_get_value("pool")
                path = f"{pool}/iocage/jails/{uuid}"

                ioc_destroy.IOCDestroy().__stop_jails__(path.replace(pool, ""))
                ioc_destroy.IOCDestroy().__destroy_parse_datasets__(path)
                exit()
            else:
                ioc_common.logit({"level": "ERROR", "message": 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:
                ioc_common.logit({
                    "level": "ERROR",
                    "message": f"Multiple jails found for {jail}:"
                })
                for t, u in sorted(_jail.items()):
                    ioc_common.logit({
                        "level": "ERROR",
                        "message": f"  {u} ({t})"
                    })
                exit(1)
            else:
                ioc_common.logit({
                    "level": "ERROR",
                    "message": f"{jail} not found!"
                })
                exit(1)

            if not force:
                ioc_common.logit({
                    "level":
                    "WARNING",
                    "message":
                    f"\nThis will destroy jail {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:
                ioc_common.logit({
                    "level":
                    "ERROR",
                    "message":
                    f"{uuid} ({tag}) is running.\nPlease stop"
                    " it first!"
                })
                exit(1)
            elif status and force:
                ioc_common.logit({
                    "level": "INFO",
                    "message": f"Stopping {uuid} ({tag})."
                })

            ioc_destroy.IOCDestroy().destroy_jail(path)
    elif jails and release:
        pool = ioc_json.IOCJson().json_get_value("pool")

        for release in jails:
            path = f"{pool}/iocage/releases/{release}"

            if not force:
                ioc_common.logit({
                    "level":
                    "WARNING",
                    "message":
                    f"\nThis will destroy RELEASE: {release} and "
                    "any jail that was created with it."
                })

                if not click.confirm("\nAre you sure?"):
                    continue

            ioc_destroy.IOCDestroy().__destroy_parse_datasets__(path)

            if download:
                path = f"{pool}/iocage/download/{release}"
                ioc_destroy.IOCDestroy().__destroy_parse_datasets__(path)

    elif not jails and release:
        ioc_common.logit({
            "level": "ERROR",
            "message": "Please specify one or more RELEASEs!"
        })
        exit(1)
    else:
        ioc_common.logit({
            "level": "ERROR",
            "message": "Please specify one or more jails!"
        })
        exit(1)
Beispiel #26
0
    def set(self, prop, plugin=False):
        """Sets a property for a jail or plugin"""
        try:
            key, value = prop.split("=", 1)
        except ValueError:
            ioc_common.logit(
                {
                    "level": "EXCEPTION",
                    "message": f"{prop} is is missing a value!"
                },
                _callback=self.callback,
                silent=self.silent)

        if self.jail == "default":
            ioc_json.IOCJson().json_check_default_config()
            default = True
        else:
            default = False

        if not default:
            uuid, path = self.__check_jail_existence__()
            iocjson = ioc_json.IOCJson(path, cli=True)

            if "template" in key:
                if "templates/" in path and prop != "template=no":
                    ioc_common.logit(
                        {
                            "level": "EXCEPTION",
                            "message": f"{uuid} is already a template!"
                        },
                        _callback=self.callback,
                        silent=self.silent)
                elif "template" not in path and prop != "template=yes":
                    ioc_common.logit(
                        {
                            "level": "EXCEPTION",
                            "message": f"{uuid} is already a jail!"
                        },
                        _callback=self.callback,
                        silent=self.silent)

            if plugin:
                _prop = prop.split(".")
                ioc_json.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]
                    self.get(_prop)

                    # The actual setting of the property.
                    iocjson.json_set_value(prop)
                except KeyError:
                    _prop = prop.partition("=")[0]
                    ioc_common.logit(
                        {
                            "level": "EXCEPTION",
                            "message": f"{_prop} is not a valid property!"
                        },
                        _callback=self.callback,
                        silent=self.silent)

            if key == "ip6_addr":
                rtsold_enable = "YES" if "accept_rtadv" in value else "NO"
                ioc_common.set_rcconf(path, "rtsold_enable", rtsold_enable)

        else:
            ioc_json.IOCJson(self.iocroot).json_set_value(prop, default=True)
Beispiel #27
0
def cli(prop, _all, _pool, jail, recursive, header, plugin):
    """Get a list of jails and print the property."""
    get_jid = ioc_list.IOCList.list_get_jid
    jails, paths = ioc_list.IOCList("uuid").list_datasets()
    jail_list = []
    table = texttable.Texttable(max_width=0)

    if _all:
        # Confusing I know.
        jail = prop
        prop = "all"

    if _pool:
        pool = ioc_json.IOCJson().json_get_value("pool")

        ioc_common.logit({"level": "INFO", "message": pool})
        exit()

    if recursive is None:
        if jail == "":
            ioc_common.logit({
                "level":
                "ERROR",
                "message":
                'Usage: iocage get [OPTIONS] PROP JAIL\n'
                'Missing argument "jail".'
            })
            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()))
            path = paths[tag]
        elif len(_jail) > 1:
            ioc_common.logit({
                "level": "ERROR",
                "message": f"Multiple jails found for {jail}:"
            })
            for t, u in sorted(_jail.items()):
                ioc_common.logit({"level": "ERROR", "message": f"  {u} ({t})"})
            exit(1)
        else:
            ioc_common.logit({
                "level": "ERROR",
                "message": f"{jail} not found!"
            })
            exit(1)

        if prop == "state":
            status, _ = get_jid(path.split("/")[3])

            if status:
                state = "up"
            else:
                state = "down"

            ioc_common.logit({"level": "INFO", "message": state})
        elif plugin:
            _prop = prop.split(".")
            props = ioc_json.IOCJson(path).json_plugin_get_value(_prop)

            if isinstance(props, dict):
                ioc_common.logit({
                    "level": "INFO",
                    "message": json.dumps(props, indent=4)
                })
            else:
                ioc_common.logit({
                    "level": "INFO",
                    "message": props[0].decode("utf-8")
                })
        elif prop == "all":
            props = ioc_json.IOCJson(path).json_get_value(prop)

            for p, v in props.items():
                ioc_common.logit({"level": "INFO", "message": f"{p}:{v}"})
        elif prop == "fstab":
            pool = ioc_json.IOCJson().json_get_value("pool")
            iocroot = ioc_json.IOCJson(pool).json_get_value("iocroot")
            index = 0

            with open(f"{iocroot}/jails/{uuid}/fstab", "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)
                ioc_common.logit({"level": "INFO", "message": table.draw()})
            else:
                for fstab in jail_list:
                    ioc_common.logit({
                        "level": "INFO",
                        "message": f"{fstab[0]}\t{fstab[1]}"
                    })
        else:
            try:
                ioc_common.logit({
                    "level":
                    "INFO",
                    "message":
                    ioc_json.IOCJson(path).json_get_value(prop)
                })
            except:
                ioc_common.logit({
                    "level": "ERROR",
                    "message": f"{prop} is not a valid property!"
                })
                exit(1)
    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 = ioc_json.IOCJson(path).json_get_value(prop)

                    for p, v in props.items():
                        jail_list.append([uuid, j, f"{p}:{v}"])
                else:
                    jail_list.append(
                        [uuid, j,
                         ioc_json.IOCJson(path).json_get_value(prop)])
            except:
                ioc_common.logit({
                    "level": "ERROR",
                    "message": f"{prop} is not a valid property!"
                })
                exit(1)

        # Prints the table
        if header:
            jail_list.insert(0, ["UUID", "TAG", f"PROP - {prop}"])
            # We get an infinite float otherwise.
            table.set_cols_dtype(["t", "t", "t"])
            table.add_rows(jail_list)
            ioc_common.logit({"level": "INFO", "message": table.draw()})
        else:
            for jail in jail_list:
                ioc_common.logit({"level": "INFO", "message": "\t".join(jail)})
Beispiel #28
0
 def __jail_stop__(self, jail, silent=False):
     """Stops the jail."""
     tag, uuid, path = self.__check_jail_existence__(jail)
     conf = ioc_json.IOCJson(path).json_load()
     ioc_stop.IOCStop(uuid, tag, path, conf, silent)
Beispiel #29
0
def cli(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.
    """
    jails, paths = ioc_list.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 = ioc_json.IOCJson(path)
        conf = iocjson.json_load()
        login_flags = conf["login_flags"].split()
        exec_fib = conf["exec_fib"]
        status, _ = ioc_list.IOCList().list_get_jid(uuid)
    elif len(_jail) > 1:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Multiple jails found for {jail}"
        })
        for t, u in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({t})"})
        exit(1)
    else:
        ioc_common.logit({"level": "ERROR", "message": f"{jail} not found!"})
        exit(1)

    if not status and not force:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"{uuid} ({tag}) is not running!"
        })
        exit(1)

    if not status and force:
        ioc_common.logit({
            "level":
            "INFO",
            "message":
            f"{uuid} ({tag}) is not running, starting jail."
        })
        if conf["type"] == "jail":
            ioc_start.IOCStart(uuid, jail, path, conf, silent=True)
            status = True
        elif conf["type"] == "basejail":
            ioc_common.logit({
                "level":
                "ERROR",
                "message":
                "Please run \"iocage migrate\" before trying to"
                f" start {uuid} ({tag})"
            })
            exit(1)
        elif conf["type"] == "template":
            ioc_common.logit({
                "level":
                "ERROR",
                "message":
                "Please convert back to a jail before trying to"
                f" start {uuid} ({tag})"
            })
            exit(1)
        else:
            ioc_common.logit({
                "level":
                "ERROR",
                "message":
                f"{conf['type']} is not a supported jail type."
            })
            exit(1)

    if status:
        su.Popen(["setfib", exec_fib, "jexec", f"ioc-{uuid}", "login"] +
                 login_flags).communicate()
Beispiel #30
0
def cli(jail):
    """Runs update with the command given inside the specified jail."""
    # TODO: Move to API
    jails = ioc_list.IOCList("uuid").list_datasets()
    _jail = {
        uuid: path
        for (uuid, path) in jails.items() if uuid.startswith(jail)
    }

    if len(_jail) == 1:
        uuid, path = next(iter(_jail.items()))
    elif len(_jail) > 1:
        ioc_common.logit({
            "level": "ERROR",
            "message": f"Multiple jails found for {jail}:"
        })
        for u, p in sorted(_jail.items()):
            ioc_common.logit({"level": "ERROR", "message": f"  {u} ({p})"})
        exit(1)
    else:
        ioc_common.logit({"level": "ERROR", "message": f"{jail} not found!"})
        exit(1)

    freebsd_version = ioc_common.checkoutput(["freebsd-version"])
    status, jid = ioc_list.IOCList.list_get_jid(uuid)
    conf = ioc_json.IOCJson(path).json_load()
    started = False

    if conf["type"] == "jail":
        if not status:
            ioc_start.IOCStart(uuid, path, conf, silent=True)
            status, jid = ioc_list.IOCList.list_get_jid(uuid)
            started = True
    elif conf["type"] == "basejail":
        ioc_common.logit({
            "level":
            "ERROR",
            "message":
            "Please run \"iocage migrate\" before trying"
            f" to update {uuid}"
        })
        exit(1)
    elif conf["type"] == "template":
        ioc_common.logit({
            "level":
            "ERROR",
            "message":
            "Please convert back to a jail before trying"
            f" to update {uuid}"
        })
        exit(1)
    else:
        ioc_common.logit({
            "level":
            "ERROR",
            "message":
            f"{conf['type']} is not a supported jail type."
        })
        exit(1)

    if "HBSD" in freebsd_version:
        su.Popen(["hbsd-update", "-j", jid]).communicate()

        if started:
            ioc_stop.IOCStop(uuid, path, conf, silent=True)
    else:
        ioc_fetch.IOCFetch(conf["cloned_release"]).fetch_update(True, uuid)

        if started:
            ioc_stop.IOCStop(uuid, path, conf, silent=True)