Пример #1
0
    def __start_generate_vnet_mac__(self, nic):
        """
        Generates a random MAC address and checks for uniquness.
        If the jail already has a mac address generated, it will return that
        instead.
        """
        mac = self.get("{}_mac".format(nic))

        if mac == "none":
            jails, paths = IOCList("uuid").list_datasets()
            mac_list = []

            for jail in jails:
                path = paths[jail]
                _conf = IOCJson(path).json_load()
                mac = _conf["mac_prefix"]
                mac_list.append(_conf["{}_mac".format(nic)].split(","))

            # We have to flatten our list of lists.
            mac_list = [m for maclist in mac_list for m in maclist]
            for number in range(16**6):
                # SO
                hex_num_a = hex(number)[2:].zfill(6)
                hex_num_b = hex(number + 1)[2:].zfill(6)
                gen_mac_a = "{}{}{}{}{}{}{}".format(mac, *hex_num_a)
                gen_mac_b = "{}{}{}{}{}{}{}".format(mac, *hex_num_b)
                gen_mac_combined = "{},{}".format(gen_mac_a, gen_mac_b)

                if gen_mac_a in mac_list or gen_mac_b in mac_list:
                    continue
                else:
                    self.set("{}_mac={}".format(nic, gen_mac_combined))
                    return gen_mac_a, gen_mac_b
        else:
            mac_a, mac_b = mac.split(",")
            return mac_a, mac_b
Пример #2
0
    def list_all(self, jails):
        """List all jails."""
        table = Texttable(max_width=0)
        jail_list = []

        for jail in jails:
            jail = jail.properties["mountpoint"].value
            conf = IOCJson(jail).json_load()

            uuid = conf["host_hostuuid"]
            full_ip4 = conf["ip4_addr"]
            ip6 = conf["ip6_addr"]
            jail_root = "{}/iocage/jails/{}/root".format(self.pool, uuid)

            try:
                short_ip4 = full_ip4.split("|")[1].split("/")[0]
            except IndexError:
                short_ip4 = "-"

            tag = conf["tag"]
            boot = conf["boot"]
            jail_type = conf["type"]
            full_release = conf["release"]

            if "HBSD" in full_release:
                full_release = "{}-STABLE-HBSD".format(full_release.split(
                    ".")[0])
                short_release = "{}-STABLE".format(full_release.rsplit("-")[0])
            else:
                short_release = "-".join(full_release.rsplit("-")[:2])

            if full_ip4 == "none":
                full_ip4 = "-"

            status, jid = self.list_get_jid(uuid)

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

            if conf["type"] == "template":
                template = "-"
            else:
                try:
                    template = checkoutput(["zfs", "get", "-H", "-o", "value",
                                            "origin",
                                            jail_root]).split("/")[3]
                except IndexError:
                    template = "-"

            if "release" in template.lower() or "stable" in template.lower():
                template = "-"

            # Append the JID and the UUID to the table
            if self.full:
                jail_list.append([jid, uuid, boot, state, tag, jail_type,
                                  full_release, full_ip4, ip6, template])
            else:
                jail_list.append([jid, uuid[:8], state, tag, short_release,
                                  short_ip4])

        list_type = "list_full" if self.full else "list_short"
        sort = ioc_sort(list_type, self.sort, data=jail_list)
        jail_list.sort(key=sort)

        # Prints the table
        if self.header:
            if self.full:
                # We get an infinite float otherwise.
                table.set_cols_dtype(["t", "t", "t", "t", "t", "t", "t", "t",
                                      "t", "t"])
                jail_list.insert(0, ["JID", "UUID", "BOOT", "STATE", "TAG",
                                     "TYPE", "RELEASE", "IP4", "IP6",
                                     "TEMPLATE"])
            else:
                # We get an infinite float otherwise.
                table.set_cols_dtype(["t", "t", "t", "t", "t", "t"])
                jail_list.insert(0, ["JID", "UUID", "STATE", "TAG",
                                     "RELEASE", "IP4"])

            table.add_rows(jail_list)

            return table.draw()
        else:
            flat_jail = [j for j in jail_list]

            return flat_jail
Пример #3
0
    def list_datasets(self, set=False):
        """Lists the datasets of given type."""

        if self.list_type == "all" or self.list_type == "uuid":
            # List the datasets underneath self.POOL/iocroot/jails
            cmd = [
                "zfs", "list", "-rHd", "1", "{}/iocage/jails".format(self.pool)
            ]

            # UUIDS are 12345678-1234-1234-1234-123456789012
            regex = re.compile("{}/jails/".format(self.iocroot) + "\\w{8}")
        elif self.list_type == "base":
            # List the datasets underneath self.POOL/iocroot/releases
            cmd = [
                "zfs", "list", "-rHd", "1",
                "{}/iocage/releases".format(self.pool)
            ]

            # Format is Major.Minor-{RELEASE,STABLE,CURRENT,BETA,ALPHA,RC}
            regex = re.compile("{}/releases/".format(self.iocroot) +
                               "\\w*.\\w")
        elif self.list_type == "template":
            # List the datasets underneath self.POOL/iocroot/releases
            cmd = [
                "zfs", "list", "-rHd", "1",
                "{}/iocage/templates".format(self.pool)
            ]

            regex = re.compile("{}/templates/".format(self.iocroot))

        zfs_list = Popen(cmd,
                         stdout=PIPE).communicate()[0].decode("utf-8").split()
        datasets = [d for d in zfs_list if re.match(regex, d)]

        if self.list_type == "all":
            self.list_all(datasets)
        elif self.list_type == "uuid":
            jails = {}
            paths = {}
            dups = {}

            for jail in datasets:
                conf = IOCJson(jail).json_load()

                if not set and conf["tag"] in jails:
                    # Add the original in
                    dups[paths[conf["tag"]]] = conf["tag"]
                    dups[jail] = conf["tag"]
                    tag = conf["tag"]

                jails[conf["tag"]] = conf["host_hostuuid"]
                paths[conf["tag"]] = jail

            template_cmd = [
                "zfs", "list", "-rHd", "1",
                "{}/iocage/templates".format(self.pool)
            ]
            template_regex = re.compile("{}/templates/".format(self.iocroot))
            template_zfs_list = Popen(
                template_cmd,
                stdout=PIPE).communicate()[0].decode("utf-8").split()
            template_datasets = [
                t for t in template_zfs_list if re.match(template_regex, t)
            ]

            for template in template_datasets:
                conf = IOCJson(template).json_load()

                jails[conf["tag"]] = conf["host_hostuuid"]
                paths[conf["tag"]] = template

            if len(dups):
                self.lgr.error(
                    "ERROR: Duplicate tag ({}) detected!".format(tag))
                for d, t in sorted(dups.items()):
                    u = [
                        m for m in d.split("/") if len(m) == 36 or len(m) == 8
                    ][0]
                    self.lgr.error("  {} ({})".format(u, t))
                self.lgr.error("\nPlease run \"iocage set tag=NEWTAG "
                               "UUID\" for one of the UUID's.")
                raise RuntimeError()

            return jails, paths
        elif self.list_type == "base":
            bases = self.list_bases(datasets)

            if self.return_object:
                return bases
        elif self.list_type == "template":
            templates = self.list_all(datasets)
            if self.return_object:
                return templates
Пример #4
0
def start_cmd(rc, jails):
    """
    Looks for the jail supplied and passes the uuid, path and configuration
    location to start_jail.
    """
    lgr = logging.getLogger('ioc_cli_start')

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

    if rc:
        boot_order = {}
        for j in _jails:
            path = paths[j]
            conf = IOCJson(path).json_load()
            boot = conf["boot"]
            priority = conf["priority"]

            if boot == "on":
                boot_order[j] = int(priority)

        boot_order = OrderedDict(sorted(boot_order.items(),
                                        key=itemgetter(1)))
        for j in boot_order.keys():
            uuid = _jails[j]
            path = paths[j]
            conf = IOCJson(path).json_load()
            status, _ = IOCList().list_get_jid(uuid)

            if not status:
                lgr.info("  Starting {} ({})".format(uuid, j))
                IOCStart(uuid, j, path, conf, silent=True)
            else:
                lgr.info("{} ({}) is already running!".format(uuid, j))
        exit()

    if len(jails) >= 1 and jails[0] == "ALL":
        if len(_jails) < 1:
            raise RuntimeError("No jails exist to start!")

        for j in _jails:
            uuid = _jails[j]
            path = paths[j]

            conf = IOCJson(path).json_load()
            IOCStart(uuid, j, path, conf)
    else:
        if len(jails) < 1:
            raise RuntimeError("Please specify either one or more jails or "
                               "ALL!")

        for jail in jails:
            _jail = {tag: uuid for (tag, uuid) in _jails.items() if
                     uuid.startswith(jail) or tag == jail}

            if len(_jail) == 1:
                tag, uuid = next(iter(_jail.items()))
                path = paths[tag]
            elif len(_jail) > 1:
                lgr.error("Multiple jails found for"
                          " {}:".format(jail))
                for t, u in sorted(_jail.items()):
                    lgr.error("  {} ({})".format(u, t))
                raise RuntimeError()
            else:
                raise RuntimeError("{} not found!".format(jail))

            conf = IOCJson(path).json_load()

            if conf["type"] in ("jail", "plugin"):
                IOCStart(uuid, tag, path, conf)
            elif conf["type"] == "basejail":
                raise RuntimeError(
                    "Please run \"iocage migrate\" before trying"
                    " to start {} ({})".format(uuid, tag))
            elif conf["type"] == "template":
                raise RuntimeError(
                    "Please convert back to a jail before trying"
                    " to start {} ({})".format(uuid, tag))
            else:
                raise RuntimeError("{} is not a supported jail type.".format(
                    conf["type"]
                ))
Пример #5
0
    def create_config(self, jail_uuid, release):
        """
        This sets up the default configuration for a jail. It also does some
        mild sanity checking on the properties users are supplying.
        """
        version = IOCJson().json_get_version()

        with open("/etc/hostid", "r") as _file:
            hostid = _file.read().strip()

        default_props = {
            "CONFIG_VERSION": version,
            # Network properties
            "interfaces": "vnet0:bridge0,vnet1:bridge1",
            "host_domainname": "none",
            "host_hostname": jail_uuid,
            "exec_fib": "0",
            "ip4_addr": "none",
            "ip4_saddrsel": "1",
            "ip4": "new",
            "ip6_addr": "none",
            "ip6_saddrsel": "1",
            "ip6": "new",
            "defaultrouter": "none",
            "defaultrouter6": "none",
            "resolver": "/etc/resolv.conf",
            "mac_prefix": "02ff60",
            "vnet0_mac": "none",
            "vnet1_mac": "none",
            "vnet2_mac": "none",
            "vnet3_mac": "none",
            # Jail Properties
            "devfs_ruleset": "4",
            "exec_start": "/bin/sh /etc/rc",
            "exec_stop": "/bin/sh /etc/rc.shutdown",
            "exec_prestart": "/usr/bin/true",
            "exec_poststart": "/usr/bin/true",
            "exec_prestop": "/usr/bin/true",
            "exec_poststop": "/usr/bin/true",
            "exec_clean": "1",
            "exec_timeout": "60",
            "stop_timeout": "30",
            "exec_jail_user": "******",
            "exec_system_jail_user": "******",
            "exec_system_user": "******",
            "mount_devfs": "1",
            "mount_fdescfs": "1",
            "enforce_statfs": "2",
            "children_max": "0",
            "login_flags": "-f root",
            "securelevel": "2",
            "sysvmsg": "new",
            "sysvsem": "new",
            "sysvshm": "new",
            "host_hostuuid": jail_uuid,
            "allow_set_hostname": "1",
            "allow_sysvipc": "0",
            "allow_raw_sockets": "0",
            "allow_chflags": "0",
            "allow_mount": "0",
            "allow_mount_devfs": "0",
            "allow_mount_nullfs": "0",
            "allow_mount_procfs": "0",
            "allow_mount_tmpfs": "0",
            "allow_mount_zfs": "0",
            "allow_quotas": "0",
            "allow_socket_af": "0",
            # RCTL limits
            "cpuset": "off",
            "rlimits": "off",
            "memoryuse": "8G:log",
            "memorylocked": "off",
            "vmemoryuse": "off",
            "maxproc": "off",
            "cputime": "off",
            "pcpu": "off",
            "datasize": "off",
            "stacksize": "off",
            "coredumpsize": "off",
            "openfiles": "off",
            "pseudoterminals": "off",
            "swapuse": "off",
            "nthr": "off",
            "msgqqueued": "off",
            "msgqsize": "off",
            "nmsgq": "off",
            "nsemop": "off",
            "nshm": "off",
            "shmsize": "off",
            "wallclock": "off",
            # Custom properties
            "type": "jail",
            "tag": datetime.utcnow().strftime("%F@%T:%f"),
            "bpf": "off",
            "dhcp": "off",
            "boot": "off",
            "notes": "none",
            "owner": "root",
            "priority": "99",
            "last_started": "none",
            "release": release,
            "cloned_release": self.release,
            "template": "no",
            "hostid": hostid,
            "jail_zfs": "off",
            "jail_zfs_dataset": "iocage/jails/{}/data".format(jail_uuid),
            "jail_zfs_mountpoint": "none",
            "mount_procfs": "0",
            "mount_linprocfs": "0",
            "count": "1",
            "vnet": "off",
            "basejail": "no",
            # Sync properties
            "sync_state": "none",
            "sync_target": "none",
            "sync_tgt_zpool": "none",
            # Native ZFS properties
            "compression": "lz4",
            "origin": "readonly",
            "quota": "none",
            "mountpoint": "readonly",
            "compressratio": "readonly",
            "available": "readonly",
            "used": "readonly",
            "dedup": "off",
            "reservation": "none",
        }

        return default_props
Пример #6
0
    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")
Пример #7
0
def snaplist_cmd(header, jail):
    """Allows a user to show resource usage of all jails."""
    lgr = ioc_logger.Logger('ioc_cli_snaplist').getLogger()

    jails, paths = IOCList("uuid").list_datasets()
    pool = IOCJson().json_get_value("pool")
    snap_list = []
    table = 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:
        lgr.error("Multiple jails found for" " {}:".format(jail))
        for t, u in sorted(_jail.items()):
            lgr.critical("  {} ({})".format(u, t))
        exit(1)
    else:
        lgr.critical("{} not found!".format(jail))
        exit(1)

    conf = IOCJson(path).json_load()

    if conf["template"] == "yes":
        full_path = "{}/iocage/templates/{}".format(pool, tag)
    else:
        full_path = "{}/iocage/jails/{}".format(pool, uuid)

    zconf = ["zfs", "get", "-H", "-o", "value"]
    snapshots = Popen(["zfs", "list", "-r", "-H", "-t", "snapshot", full_path],
                      stdout=PIPE,
                      stderr=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 = Popen(
                zconf + ["creation", snap[0]],
                stdout=PIPE).communicate()[0].decode("utf-8").strip()
            used = snap[1]
            referenced = Popen(
                zconf + ["referenced", snap[0]],
                stdout=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)
        lgr.info(table.draw())
    else:
        for snap in snap_list:
            lgr.info("\t".join(snap))
Пример #8
0
 def __init__(self, callback=None):
     self.callback = callback
     self.pool = IOCJson().json_get_value("pool")
     self.iocroot = IOCJson(self.pool).json_get_value("iocroot")
     self.date = datetime.utcnow().strftime("%F")
Пример #9
0
def fstab_cmd(action, fstab_string, jail):
    """
    Looks for the jail supplied and passes the uuid, path and configuration
    location to manipulate the fstab.
    """
    lgr = ioc_logger.Logger('ioc_cli_fstab').getLogger()
    pool = IOCJson().json_get_value("pool")
    iocroot = IOCJson(pool).json_get_value("iocroot")
    index = None
    _index = False
    fstab_string = list(fstab_string)

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

    if not fstab_string and action != "edit":
        lgr.critical("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:
        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)

    # 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])
            except TypeError:
                lgr.critical("Please specify either a valid fstab "
                             "entry or an index number.")
                exit(1)
            _index = True
            source, destination, fstype, options, dump, _pass = "", "", "", \
                                                                "", "", ""
    else:
        if action != "edit":
            try:
                source, destination, fstype, options, dump, _pass = \
                    fstab_string
            except ValueError:
                lgr.critical("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 = "{}/jails/{}/root".format(iocroot, uuid) + destination

    IOCFstab(uuid,
             tag,
             action,
             source,
             destination,
             fstype,
             options,
             dump,
             _pass,
             index=index)
Пример #10
0
    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
Пример #11
0
def export_cmd(jail):
    """Make a recursive snapshot of the jail and export to a file."""
    lgr = logging.getLogger('ioc_cli_export')

    pool = IOCJson().json_get_value("pool")
    iocroot = IOCJson(pool).json_get_value("iocroot")
    date = datetime.utcnow().strftime("%F")
    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))

    status, _ = IOCList().list_get_jid(uuid)
    if status:
        raise RuntimeError("{} ({}) is runnning, stop the jail before "
                           "exporting!".format(uuid, tag))

    images = "{}/images".format(iocroot)
    name = "{}_{}".format(uuid, date)
    image = "{}/{}_{}".format(images, name, tag)
    image_path = "{}{}".format(pool, path)
    jail_list = []

    # Looks like foo/iocage/jails/df0ef69a-57b6-4480-b1f8-88f7b6febbdf@BAR
    target = "{}@ioc-export-{}".format(image_path, date)

    try:
        checkoutput(["zfs", "snapshot", "-r", target], stderr=STDOUT)
    except CalledProcessError as err:
        raise RuntimeError("ERROR: {}".format(
            err.output.decode("utf-8").rstrip()))

    datasets = Popen(
        ["zfs", "list", "-H", "-r", "-o", "name", "{}{}".format(pool, path)],
        stdout=PIPE,
        stderr=PIPE).communicate()[0].decode("utf-8").split()

    for dataset in datasets:
        if len(dataset) == 54:
            _image = image
            jail_list.append(_image)
        elif len(dataset) > 54:
            image_name = dataset.partition("{}{}".format(pool, path))[2]
            name = image_name.replace("/", "_")
            _image = image + name
            jail_list.append(_image)
            target = "{}@ioc-export-{}".format(dataset, date)

        # Sending each individually as sending them recursively to a file does
        # not work how one expects.
        try:
            with open(_image, "wb") as export:
                lgr.info("Exporting dataset: {}".format(dataset))
                check_call(["zfs", "send", target], stdout=export)
        except CalledProcessError as err:
            raise RuntimeError("ERROR: {}".format(err))

    lgr.info("\nPreparing zip file: {}.zip.".format(image))
    with zipfile.ZipFile("{}.zip".format(image),
                         "w",
                         compression=zipfile.ZIP_DEFLATED,
                         allowZip64=True) as final:
        os.chdir(images)

        for jail in jail_list:
            final.write(jail)

    # Cleanup our mess.
    try:
        checkoutput(["zfs", "destroy", "-r", target], stderr=STDOUT)

        for jail in jail_list:
            os.remove(jail)

    except CalledProcessError as err:
        raise RuntimeError("ERROR: {}".format(
            err.output.decode("utf-8").rstrip()))

    lgr.info("\nExported: {}.zip".format(image))
Пример #12
0
def upgrade_cmd(jail, release):
    """Runs upgrade with the command given inside the specified jail."""
    lgr = logging.getLogger('ioc_cli_upgrade')

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

    if len(_jail) == 1:
        tag, uuid = next(iter(_jail.items()))
        path = paths[tag]
        root_path = "{}/root".format(path)
    elif len(_jail) > 1:
        lgr.error("Multiple jails found for" " {}:".format(jail))
        for t, u in sorted(_jail.items()):
            lgr.error("  {} ({})".format(u, t))
        raise RuntimeError()
    else:
        raise RuntimeError("{} not found!".format(jail))

    pool = IOCJson().json_get_value("pool")
    iocroot = IOCJson(pool).json_get_value("iocroot")
    freebsd_version = checkoutput(["freebsd-version"])
    status, jid = IOCList.list_get_jid(uuid)
    conf = IOCJson(path).json_load()
    host_release = os.uname()[2]
    jail_release = conf["release"]
    started = False

    if conf["release"] == "EMPTY":
        raise RuntimeError("Upgrading is not supported for empty jails.")

    if conf["type"] == "jail":
        if not status:
            IOCStart(uuid, tag, path, conf, silent=True)
            status, jid = IOCList.list_get_jid(uuid)
            started = True
    elif conf["type"] == "basejail":
        raise RuntimeError("Please run \"iocage migrate\" before trying"
                           " to upgrade {} ({})".format(uuid, tag))
    elif conf["type"] == "template":
        raise RuntimeError("Please convert back to a jail before trying"
                           " to upgrade {} ({})".format(uuid, tag))
    else:
        raise RuntimeError("{} is not a supported jail type.".format(
            conf["type"]))

    _freebsd_version = "{}/releases/{}/root/bin/freebsd-version".format(
        iocroot, release)

    if "HBSD" in freebsd_version:
        Popen(["hbsd-upgrade", "-j", jid]).communicate()
    else:
        if os.path.isfile("{}/etc/freebsd-update.conf".format(root_path)):
            # 10.3-RELEASE and under lack this flag
            if float(host_release.partition("-")[0][:5]) <= 10.3:
                raise RuntimeError(
                    "Host: {} is too old, please upgrade to "
                    "10.3-RELEASE or above".format(host_release))

            os.environ["PAGER"] = "/bin/cat"
            fetch = Popen([
                "freebsd-update", "-b", root_path, "-d",
                "{}/var/db/freebsd-update/".format(root_path), "-f",
                "{}/etc/freebsd-update.conf".format(root_path),
                "--currently-running {}".format(jail_release), "-r", release,
                "upgrade"
            ],
                          stdin=PIPE)
            fetch.communicate(b"y")

            while not __upgrade_install__(root_path, release):
                pass

            if release[:4].endswith("-"):
                # 9.3-RELEASE and under don't actually have this binary.
                new_release = release
            else:
                with open(_freebsd_version, "r") as r:
                    for line in r:
                        if line.startswith("USERLAND_VERSION"):
                            new_release = line.rstrip().partition(
                                "=")[2].strip('"')

            IOCJson(path, silent=True).json_set_value(
                "release={}".format(new_release))

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

            lgr.info("\n{} ({}) successfully upgraded from {} to {}!".format(
                uuid, tag, jail_release, new_release))
Пример #13
0
 def __init__(self):
     self.pool = IOCJson().json_get_value("pool")
     self.iocroot = IOCJson(self.pool).json_get_value("iocroot")
     self.lgr = logging.getLogger('ioc_destroy')
     self.zfs = libzfs.ZFS()
     self.ds = self.zfs.get_dataset
Пример #14
0
 def __init__(self):
     self.pool = IOCJson().json_get_value("pool")
     self.iocroot = IOCJson(self.pool).json_get_value("iocroot")
     self.lgr = logging.getLogger('ioc_clean')
Пример #15
0
def get_cmd(prop, _all, _pool, jail, recursive, header, plugin):
    """Get a list of jails and print the property."""
    lgr = logging.getLogger('ioc_cli_get')

    get_jid = IOCList.list_get_jid
    jails, paths = IOCList("uuid").list_datasets()
    jail_list = []
    table = Texttable(max_width=0)

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

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

        lgr.info(pool)
        exit()

    if recursive is None:
        if jail == "":
            lgr.info("Usage: iocage get [OPTIONS] PROP JAIL\n")
            raise RuntimeError("Error: Missing argument \"jail\".")

        _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))

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

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

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

            if isinstance(props, dict):
                lgr.info(json.dumps(props, indent=4))
            else:
                pass
        elif prop == "all":
            props = IOCJson(path).json_get_value(prop)

            for p, v in props.items():
                lgr.info("{}:{}".format(p, v))
        elif prop == "fstab":
            pool = IOCJson().json_get_value("pool")
            iocroot = IOCJson(pool).json_get_value("iocroot")
            index = 0

            with open("{}/jails/{}/fstab".format(iocroot, uuid), "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)
                lgr.info(table.draw())
            else:
                for fstab in jail_list:
                    lgr.info("{}\t{}".format(fstab[0], fstab[1]))
        else:
            try:
                lgr.info(IOCJson(path).json_get_value(prop))
            except:
                raise RuntimeError("{} is not a valid property!".format(prop))
    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 = IOCJson(path).json_get_value(prop)

                    for p, v in props.items():
                        jail_list.append([uuid, j, "{}:{}".format(p, v)])
                else:
                    jail_list.append(
                        [uuid, j, IOCJson(path).json_get_value(prop)])
            except:
                raise RuntimeError("{} is not a valid property!".format(prop))

        # Prints the table
        if header:
            jail_list.insert(0, ["UUID", "TAG", "PROP - {}".format(prop)])
            # We get an infinite float otherwise.
            table.set_cols_dtype(["t", "t", "t"])
            table.add_rows(jail_list)
            lgr.info(table.draw())
        else:
            for jail in jail_list:
                lgr.info("\t".join(jail))
Пример #16
0
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))
Пример #17
0
 def __init__(self):
     self.pool = IOCJson().json_get_value("pool")
     self.lgr = logging.getLogger('ioc_clean')
     self.zfs = libzfs.ZFS()
     self.ds = self.zfs.get_dataset
Пример #18
0
    def import_jail(self, jail):
        """Import from an iocage export."""
        image_dir = f"{self.iocroot}/images"
        exports = os.listdir(image_dir)
        uuid_matches = fnmatch.filter(exports, f"{jail}*.zip")
        tag_matches = fnmatch.filter(exports, f"*{jail}.zip")
        cmd = ["zfs", "recv", "-F", "-d", self.pool]

        # We want to allow the user some flexibility.
        if uuid_matches:
            matches = uuid_matches
        else:
            matches = tag_matches

        if len(matches) == 1:
            image_target = f"{image_dir}/{matches[0]}"
            uuid = matches[0].rsplit("_")[0]
            date = matches[0].rsplit("_")[1]
            tag = matches[0].rsplit("_")[2].rsplit(".")[0]
        elif len(matches) > 1:
            msg = f"Multiple exports found for {jail}:"

            for j in sorted(matches):
                msg += f"\n  {j}"

            raise RuntimeError(msg)
        else:
            raise RuntimeError(f"{jail} not found!")

        with zipfile.ZipFile(image_target, "r") as _import:
            for z in _import.namelist():
                z_split = z.split("_")

                # We don't want the date and tag
                del z_split[1]
                del z_split[1]

                z_split_str = "/".join(z_split)
                _z = z_split_str.replace("iocage/images/", "")

                if callable(self.callback):
                    self.callback("Importing dataset: {}".format(_z))

                dataset = _import.read(z)
                recv = Popen(cmd, stdin=PIPE)
                recv.stdin.write(dataset)
                recv.communicate()
                recv.stdin.close()

        # Cleanup our mess.
        try:
            target = f"{self.pool}{self.iocroot}/jails/{uuid}@ioc-export-" \
                     f"{date}"

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

        tag = IOCJson(f"{self.iocroot}/jails/{uuid}",
                      silent=True).json_set_value(f"tag={tag}")

        if callable(self.callback):
            self.callback(f"\nImported: {uuid} ({tag})")
Пример #19
0
 def __init__(self):
     self.pool = IOCJson().json_get_value("pool")
     self.lgr = logging.getLogger('ioc_clean')
     self.zfs = libzfs.ZFS(history=True, history_prefix="<iocage>")
     self.ds = self.zfs.get_dataset
Пример #20
0
def destroy_cmd(force, release, download, jails):
    """Destroys the jail's 2 datasets and the snapshot from the RELEASE."""
    lgr = ioc_logger.Logger('ioc_cli_destroy').getLogger()

    if download and not release:
        exit("--release (-r) must be specified as well!")

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

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

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

                IOCDestroy().__stop_jails__(path.replace(pool, ""))
                IOCDestroy().__destroy_parse_datasets__(path)
                exit()
            else:
                lgr.critical(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:
                lgr.error("Multiple jails found for" " {}:".format(jail))
                for t, u in sorted(_jail.items()):
                    lgr.critical("  {} ({})".format(u, t))
                exit(1)
            else:
                lgr.critical("{} not found!".format(jail))
                exit(1)

            if not force:
                lgr.warning("\nThis will destroy"
                            " jail {} ({})".format(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:
                lgr.critical(f"{uuid} ({tag}) is running.\nPlease stop "
                             "it first!")
                exit(1)
            elif status and force:
                lgr.info("Stopping {} ({}).".format(uuid, tag))

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

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

            if not force:
                lgr.warning(f"\nThis will destroy RELEASE: {release}")
                lgr.warning("       and any jail that was created with it.")

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

            IOCDestroy().__destroy_parse_datasets__(path)

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

    elif not jails and release:
        lgr.critical("Please specify one or more RELEASEs!")
        exit(1)
    else:
        lgr.critical("Please specify one or more jails!")
        exit(1)
Пример #21
0
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)
Пример #22
0
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)
Пример #23
0
def import_cmd(jail):
    """Import from an iocage export."""
    lgr = logging.getLogger('ioc_cli_import')

    pool = IOCJson().json_get_value("pool")
    iocroot = IOCJson(pool).json_get_value("iocroot")
    image_dir = "{}/images".format(iocroot)
    exports = os.listdir(image_dir)
    uuid_matches = fnmatch.filter(exports, "{}*.zip".format(jail))
    tag_matches = fnmatch.filter(exports, "*{}.zip".format(jail))
    cmd = ["zfs", "recv", "-F", "-d", pool]

    # We want to allow the user some flexibility.
    if uuid_matches:
        matches = uuid_matches
    else:
        matches = tag_matches

    if len(matches) == 1:
        image_target = "{}/{}".format(image_dir, matches[0])
        uuid = matches[0].rsplit("_")[0]
        date = matches[0].rsplit("_")[1]
        tag = matches[0].rsplit("_")[2].rsplit(".")[0]
    elif len(matches) > 1:
        lgr.error("Multiple exports found for"
                  " {}:".format(jail))
        for j in sorted(matches):
            lgr.error("  {}".format(j))
        raise RuntimeError()
    else:
        raise RuntimeError("{} not found!".format(jail))

    with zipfile.ZipFile(image_target, "r") as _import:
        for z in _import.namelist():
            z_split = z.split("_")

            # We don't want the date and tag
            del z_split[1]
            del z_split[1]

            z_split_str = "/".join(z_split)
            _z = z_split_str.replace("iocage/images/", "")

            lgr.info("Importing dataset: {}".format(_z))
            dataset = _import.read(z)
            recv = Popen(cmd, stdin=PIPE)
            recv.stdin.write(dataset)
            recv.communicate()
            recv.stdin.close()

    # Cleanup our mess.
    try:
        target = "{}{}/jails/{}@ioc-export-{}".format(pool, iocroot, uuid,
                                                      date)
        checkoutput(["zfs", "destroy", "-r", target], stderr=STDOUT)
    except CalledProcessError as err:
        raise RuntimeError(
            "ERROR: {}".format(err.output.decode("utf-8").rstrip()))

    tag = IOCJson("{}/jails/{}".format(iocroot, uuid),
                  silent=True).json_set_value("tag={}".format(tag))
    lgr.info("\nImported: {} ({})".format(uuid, tag))
Пример #24
0
    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
Пример #25
0
    def list_datasets(self, set=False):
        """Lists the datasets of given type."""

        if self.list_type == "all" or self.list_type == "uuid":
            ds = self.zfs.get_dataset(f"{self.pool}/iocage/jails").children
        elif self.list_type == "base":
            ds = self.zfs.get_dataset(f"{self.pool}/iocage/releases").children
        elif self.list_type == "template":
            ds = self.zfs.get_dataset(
                f"{self.pool}/iocage/templates").children

        if self.list_type == "all":
            _all = self.list_all(ds)

            return _all
        elif self.list_type == "uuid":
            jails = {}
            paths = {}
            dups = {}

            for jail in ds:
                jail = jail.properties["mountpoint"].value
                conf = IOCJson(jail).json_load()

                if not set and conf["tag"] in jails:
                    # Add the original in
                    dups[paths[conf["tag"]]] = conf["tag"]
                    dups[jail] = conf["tag"]
                    tag = conf["tag"]

                jails[conf["tag"]] = conf["host_hostuuid"]
                paths[conf["tag"]] = jail

            template_datasets = self.zfs.get_dataset(
                f"{self.pool}/iocage/templates")
            template_datasets = template_datasets.children

            for template in template_datasets:
                template = template.properties["mountpoint"].value
                conf = IOCJson(template).json_load()

                jails[conf["tag"]] = conf["host_hostuuid"]
                paths[conf["tag"]] = template

            if len(dups):
                self.lgr.error(f"Duplicate tag ({tag}) detected!")
                for d, t in sorted(dups.items()):
                    u = [m for m in d.split("/") if len(m) == 36 or len(m)
                         == 8][0]
                    self.lgr.error("  {} ({})".format(u, t))
                self.lgr.error("\nPlease run \"iocage set tag=NEWTAG "
                               "UUID\" for one of the UUID's.")
                raise RuntimeError()

            return jails, paths
        elif self.list_type == "base":
            bases = self.list_bases(ds)

            return bases
        elif self.list_type == "template":
            templates = self.list_all(ds)

            return templates
Пример #26
0
def stop_cmd(rc, jails):
    """
    Looks for the jail supplied and passes the uuid, path and configuration
    location to stop_jail.
    """
    lgr = logging.getLogger('ioc_cli_stop')

    _jails, paths = IOCList("uuid").list_datasets()
    jail_order = {}
    boot_order = {}

    for j in _jails:
        path = paths[j]
        conf = IOCJson(path).json_load()
        boot = conf["boot"]
        priority = conf["priority"]

        jail_order[j] = int(priority)

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

    jail_order = OrderedDict(
        sorted(jail_order.items(), key=itemgetter(1), reverse=True))
    boot_order = OrderedDict(
        sorted(boot_order.items(), key=itemgetter(1), reverse=True))
    if rc:
        for j in boot_order.keys():
            uuid = _jails[j]
            path = paths[j]
            conf = IOCJson(path).json_load()
            status, _ = IOCList().list_get_jid(uuid)

            if status:
                lgr.info("  Stopping {} ({})".format(uuid, j))
                IOCStop(uuid, j, path, conf, silent=True)
            else:
                lgr.info("{} ({}) is not running!".format(uuid, j))
        exit()

    if len(jails) >= 1 and jails[0] == "ALL":
        if len(_jails) < 1:
            raise RuntimeError("No jails exist to stop!")

        for j in jail_order:
            uuid = _jails[j]
            path = paths[j]

            conf = IOCJson(path).json_load()
            IOCStop(uuid, j, path, conf)
    else:
        if len(jails) < 1:
            raise RuntimeError("Please specify either one or more jails or "
                               "ALL!")

        for jail in jails:
            _jail = {
                tag: uuid
                for (tag, uuid) in _jails.items()
                if uuid.startswith(jail) or tag == jail
            }

            if len(_jail) == 1:
                tag, uuid = next(iter(_jail.items()))
                path = paths[tag]
            elif len(_jail) > 1:
                lgr.error("Multiple jails found for" " {}:".format(jail))
                for t, u in sorted(_jail.items()):
                    lgr.error("  {} ({})".format(u, t))
                raise RuntimeError()
            else:
                raise RuntimeError("{} not found!".format(jail))

            conf = IOCJson(path).json_load()
            IOCStop(uuid, tag, path, conf)
Пример #27
0
def restart_cmd(jail, soft):
    """
    Looks for the jail supplied and passes the uuid, path and configuration
    location to stop_jail and start_jail.
    """
    lgr = logging.getLogger('ioc_cli_restart')

    jails, paths = IOCList("uuid").list_datasets()
    if jail == "ALL":
        for j in jails:
            uuid = jails[j]
            path = paths[j]

            conf = IOCJson(path).json_load()

            if conf["type"] in ("jail", "plugin"):
                try:
                    if not soft:
                        __hard_restart__(uuid, j, path, conf)
                    else:
                        __soft_restart__(uuid, j, path, conf)
                except RuntimeError as err:
                    lgr.error(err)
            elif conf["type"] == "basejail":
                lgr.error("Please run \"iocage migrate\" before trying"
                          " to restart {} ({})".format(uuid, j))
            elif conf["type"] == "template":
                raise RuntimeError(
                    "Please convert back to a jail before trying"
                    " to restart {} ({})".format(uuid, j))
            else:
                lgr.error("{} is not a supported jail type.".format(
                    conf["type"]))
    else:
        _jail = {
            tag: uuid
            for (tag, uuid) in jails.items()
            if uuid.startswith(jail) or tag == jail
        }

        if len(_jail) == 1:
            tag, uuid = next(iter(_jail.items()))
            path = paths[tag]
        elif len(_jail) > 1:
            lgr.error("Multiple jails found for" " {}:".format(jail))
            for t, u in sorted(_jail.items()):
                lgr.error("  {} ({})".format(u, t))
            raise RuntimeError()
        else:
            raise RuntimeError("{} not found!".format(jail))

        conf = IOCJson(path).json_load()

        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":
            raise RuntimeError("Please run \"iocage migrate\" before trying"
                               " to restart {} ({})".format(uuid, tag))
        elif conf["type"] == "template":
            raise RuntimeError("Please convert back to a jail before trying"
                               " to restart {} ({})".format(uuid, tag))
        else:
            raise RuntimeError("{} is not a supported jail type.".format(
                conf["type"]))