Adam Števko
2020-12-14 bf604aba591882992fc26e5992e9eda03e643f3e
Building in zones

* PoC: building in zones

* Building in zones

* Building in zones working version

* Add working makefile targets

* Update environment.mk
1 files deleted
3 files modified
289 ■■■■■ changed files
components/Makefile 7 ●●●●● patch | view | raw | blame | history
make-rules/build-zone.mk 143 ●●●●● patch | view | raw | blame | history
make-rules/environment.mk 65 ●●●●● patch | view | raw | blame | history
tools/userland-zone 74 ●●●● patch | view | raw | blame | history
components/Makefile
@@ -80,9 +80,10 @@
clean:            TARGET = clean
clobber:        TARGET = clobber
test:            TARGET = test
zone-build:        TARGET = component-zone-build
zone-cleanup:        TARGET = component-zone-cleanup
component-hook:        TARGET = component-hook
prep build install pre-publish publish test:    TEMPLATE_ZONE=$(ZONE)
prep build install pre-publish publish test:    LOG = >$(WS_LOGS)/$(subst /,.,$@).$(TARGET).log 2>&1
zone-build zone-cleanup prep build install pre-publish publish test:    LOG = >$(WS_LOGS)/$(subst /,.,$@).$(TARGET).log 2>&1
# turn off pkglint for the individual component builds.
ifeq   ($(strip $(PKGLINT_COMPONENT)),)
@@ -91,7 +92,7 @@
.DEFAULT:    publish
build install pre-publish publish test: $(COMPONENT_DIRS)
zone-build zone-cleanup build install pre-publish publish test: $(COMPONENT_DIRS)
COMPONENT_DIRS.nosetup =    $(COMPONENT_DIRS:%=%.nosetup)
COMPONENT_DIRS.nolog =        $(COMPONENT_DIRS:%=%.nolog)
make-rules/build-zone.mk
File was deleted
make-rules/environment.mk
@@ -21,11 +21,15 @@
#
# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2020, Adam Stevko
#
PFEXEC =               /usr/bin/pfexec
PFEXEC =    /usr/bin/pfexec
ZONE =    $(WS_TOOLS)/userland-zone
define separator-line
       @$(PYTHON) -c 'l="="*(40-len("$1")/2); print("%s%s%s" % (l, "$1", l))'
       @$(PYTHON) -c 'l="="*int(40-len("$1")/2); print("%s%s%s" % (l, "$1", l))'
endef
component-environment-check::
@@ -48,6 +52,63 @@
        { echo "Adding required packages to build environment..."; \
          $(PFEXEC) /usr/bin/pkg install --accept -v $(REQUIRED_PACKAGES:%=/%) || [ $$? -eq 4 ] ; }
ZONENAME_PREFIX = bz
ZONENAME_ID = $(shell echo "$(WS_TOP)" | sha1sum | cut -c0-7)-$(COMPONENT_NAME)
ZONENAME = $(ZONENAME_PREFIX)-$(ZONENAME_ID)
component-zone-template:
    $(call separator-line)
    $(call separator-line,Create template zone)
    USER_ID=$$(id -u) && \
    $(PFEXEC) $(ZONE) --prefix $(ZONENAME_PREFIX) create-template -u $${USER} -i $${USER_ID}
component-zone-build:
    $(call separator-line)
    $(call separator-line,Create $(ZONENAME))
    $(PFEXEC) $(ZONE) --prefix $(ZONENAME_PREFIX) spawn-zone --id $(ZONENAME_ID)
    $(call separator-line,Boot $(ZONENAME))
    @while $$(true); do \
        echo "Waiting for zone $(ZONENAME) to boot..."; \
        $(PFEXEC) /usr/sbin/zlogin -l $${USER} $(ZONENAME) \
                /bin/true >/dev/null 2>&1 && break; \
        sleep 10; \
    done
    # FIXME:
    # - remove once we figure out a better way how to enable zoneproxy-client inside the nlipkg brand
    @while $$(true); do \
          echo "Waiting for $(ZONENAME) config repository.."; \
          $(PFEXEC) /usr/bin/svcs -z $(ZONENAME) -a >/dev/null 2>&1 && break; \
          sleep 10; \
      done
    # We need to create door inside  after zone-proxy-client is running
    $(call separator-line,Configure IPS for $(ZONENAME))
    $(PFEXEC) /usr/lib/zones/zoneproxy-adm $(ZONENAME)
    @while $$(true); do \
          echo "Waiting for zoneproxyd to be ready.."; \
          PROXY_PID=$$(/usr/bin/svcs -p svc:/application/pkg/zones-proxyd:default | \
              nawk '$$0 ~ /zoneproxyd/ {print $$2}') && \
              $(PFEXEC) /usr/bin/pfiles $${PROXY_PID} | \
              $(GNU_GREP) $(ZONENAME) >/dev/null 2>&1 && break; \
          sleep 10; \
      done
    $(PFEXEC) /usr/sbin/svcadm -z $(ZONENAME) \
        enable svc:/application/pkg/zones-proxy-client:default
    ZONEROOT="$$(/usr/sbin/zoneadm -z $(ZONENAME) list -p | cut -d: -f4)/root" && \
        $(PFEXEC) /usr/bin/pkg -R $${ZONEROOT} set-property use-system-repo True && \
    while $$(true); do \
        echo "Waiting for sysrepo to be ready..." && \
        $(PFEXEC) /usr/bin/pkg -R $${ZONEROOT} publisher | \
        $(GNU_GREP) syspub >/dev/null 2>&1 && break; \
        sleep 10; \
    done
    $(call separator-line,Build in $(ZONENAME))
    $(PFEXEC) /usr/sbin/zlogin -l $${USER} $(ZONENAME) \
        "cd $(COMPONENT_DIR); gmake install"
    $(call separator-line)
component-zone-cleanup:
    $(PFEXEC) $(ZONE) destroy-zone --id $(ZONENAME_ID)
# Short aliases for user convenience
env-check:: component-environment-check
env-prep:: component-environment-prep
tools/userland-zone
@@ -23,25 +23,28 @@
import errno
import logging
import os
import pwd
import subprocess
logger = logging.getLogger("userland-zone")
BUILD_ZONE_NAME = "prbuilder"
BUILD_ZONE_NAME = "bz"
TEMPLATE_ZONE_NAME = "-".join([BUILD_ZONE_NAME, "template"])
ZONES_ROOT = "/zones"
ARCHIVES_DIR = "/ws/archives"
CODE_DIR = "/ws/code"
DEVELOPER_PACKAGES = ["build-essential"]
ETC_SYSDING_CONF = ["#!/usr/bin/ksh", "setup_timezone UTC", "setup_locale en_US.UTF-8"]
class Zone:
    def __init__(self, name, path=None, brand="nlipkg"):
    def __init__(
        self, name, path=None, brand="nlipkg", user="oi", user_id=1000,
    ):
        self._name = name
        self._path = path or self._get_zone_path()
        self._brand = brand
        self._user = user
        self._user_id = user_id
    @property
    def name(self):
@@ -115,10 +118,31 @@
        zone_root_path = os.path.join(self._path, "root")
        return self._pkg(["-R", zone_root_path, "update"])
    def configure(self, sysding_lines=ETC_SYSDING_CONF):
    def configure(self, sysding_lines=None):
        sysding_config = [
            "#!/usr/bin/ksh",
            "setup_timezone UTC",
            "setup_locale en_US.UTF-8",
            'setup_user_account {user} {uid} {gid} "{gecos}" {home} {shell}'.format(
                user=self._user,
                uid=self._user_id,
                gid="10",
                gecos="Build user",
                home="/export/home/{}".format(self._user),
                shell="/usr/bin/bash",
            ),
            "/usr/sbin/usermod -P'Primary Administrator' {user}".format(
                user=self._user
            ),
        ]
        if sysding_lines:
            sysding_config.extend(sysding_lines)
        sysding_config.append("\n")
        sysding_conf = os.path.join(self._path, "root", "etc", "sysding.conf")
        with open(sysding_conf, "w") as f:
            f.write("\n".join(sysding_lines))
            f.write("\n".join(sysding_config))
def execute(cmd, args, **kwargs):
@@ -152,6 +176,7 @@
        raise argparse.ArgumentTypeError("{} is not a valid path".format(path))
    parser = argparse.ArgumentParser()
    parser.add_argument("--prefix", default=BUILD_ZONE_NAME, help="Zone name prefix")
    subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
    # create-template
@@ -163,6 +188,18 @@
        help="Zone path",
        default=os.path.join(ZONES_ROOT, TEMPLATE_ZONE_NAME),
        dest="zone_path",
    )
    ct_parser.add_argument(
        "-u",
        help="User ID to use for build user",
        default=os.getuid(),
        dest="uid",
    )
    ct_parser.add_argument(
        "-l",
        help="User name to use for build user",
        default=pwd.getpwuid(os.getuid()).pw_name,
        dest="user",
    )
    # update-template
@@ -210,8 +247,8 @@
    return args
def create_template(zone_path, zone_name=TEMPLATE_ZONE_NAME):
    zone = Zone(path=zone_path, name=zone_name)
def create_template(zone_path, zone_name=TEMPLATE_ZONE_NAME, user='oi', user_id=1000):
    zone = Zone(path=zone_path, name=zone_name, user=user, user_id=user_id)
    zone.create()
    zone.install()
    zone.configure()
@@ -226,8 +263,8 @@
    zone.delete()
def spawn_zone(id, archive_dir=ARCHIVES_DIR, code_dir=CODE_DIR):
    name = "{}-{}".format(BUILD_ZONE_NAME, id)
def spawn_zone(id, prefix=BUILD_ZONE_NAME, archive_dir=ARCHIVES_DIR, code_dir=CODE_DIR):
    name = "{}-{}".format(prefix, id)
    zone = Zone(name=name, path=os.path.join(ZONES_ROOT, name))
    template_zone = Zone(name=TEMPLATE_ZONE_NAME)
@@ -262,8 +299,8 @@
    zone.boot()
def update_template():
    zone = Zone(name=TEMPLATE_ZONE_NAME)
def update_template(zone_name=TEMPLATE_ZONE_NAME):
    zone = Zone(name=zone_name)
    zone.update()
@@ -271,15 +308,18 @@
    args = parse_arguments()
    if args.subcommand == "create-template":
        create_template(zone_path=args.zone_path)
        zone_name = '{}-{}'.format(args.prefix, 'template')
        create_template(zone_path=args.zone_path, zone_name=zone_name, user=args.user, user_id=args.uid)
    elif args.subcommand == "destroy-template":
        destroy_zone(zone_name=TEMPLATE_ZONE_NAME)
        zone_name = '{}-{}'.format(args.prefix, 'template')
        destroy_zone(zone_name=zone_name)
    elif args.subcommand == "update-template":
        update_template()
        zone_name = '{}-{}'.format(args.prefix, 'template')
        update_template(zone_name=zone_name)
    elif args.subcommand == "spawn-zone":
        spawn_zone(id=args.id, archive_dir=args.archive_dir, code_dir=args.code_dir)
        spawn_zone(id=args.id, prefix=args.prefix, archive_dir=args.archive_dir, code_dir=args.code_dir)
    elif args.subcommand == "destroy-zone":
        zone_name = "{}-{}".format(BUILD_ZONE_NAME, args.id)
        zone_name = "{}-{}".format(args.prefix, args.id)
        destroy_zone(zone_name=zone_name)