From 01a00b4815eb4e1f7f23147aff4e2cf7602b9f4f Mon Sep 17 00:00:00 2001 From: Steven Noble Date: Sun, 22 Nov 2015 17:13:05 -0800 Subject: [PATCH] fixes for buildroot config, added onlbuilder and docker_shell --- docker_shell | 159 ++++++++++++++++++ onlbuilder | 145 ++++++++++++++++ .../buildroot/builds/buildroot.config-powerpc | 2 +- 3 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 docker_shell create mode 100755 onlbuilder diff --git a/docker_shell b/docker_shell new file mode 100644 index 00000000..a1242a02 --- /dev/null +++ b/docker_shell @@ -0,0 +1,159 @@ +#!/usr/bin/python + +import os +import sys +import argparse +import datetime +import subprocess +import pwd +import logging +import re + +logging.basicConfig() +logger = logging.getLogger('docker_shell') +logger.setLevel(logging.INFO) + +g_dry = False + +def fatal(msg, rc=1): + logger.critical(msg) + sys.exit(rc) + +def execute(cmd, msg=None): + logger.debug('+ %s ...' % cmd) + rc = 0 + if not g_dry: + rc = os.system(cmd) + if rc == 0: + logger.debug('+ %s [OK]' % cmd) + else: + logger.debug('+ %s [FAILED (%d)]' % (cmd, rc)) + if msg: + fatal(msg) + else: + logger.debug('+ %s [DRY]' % cmd) + return rc + +class User(object): + + default_shell="/bin/bash" + default_user="root:0" + + def __init__(self, uspec): + + (self.name, c, rest) = uspec.partition(':') + self.validate_name() + + (self.uid, c, rest) = rest.partition(':') + self.validate_uid() + + (self.shell, c, rest) = rest.partition(':') + if self.shell == '': + self.shell = User.default_shell + if not os.path.exists(self.shell): + fatal("Requested shell '%s' does not exist." % self.shell) + + (self.home, c, rest) = rest.partition(':') + + logger.debug("User(%s) initialized." % self) + + def __str__(self): + return "%s:%s:%s" % (self.name, self.uid, self.shell) + + def validate_name(self): + NAME_REGEX=r"[a-z][-a-z0-9]*" + if re.match(NAME_REGEX, self.name) is None: + fatal("'%s' is not a valid username." % self.name) + logger.debug("username %s is validated." % self.name) + + def validate_uid(self): + try: + self.uid = int(self.uid) + logger.debug("uid %d is validated." % self.uid) + except: + if self.uid == '': + if self.name == 'root': + self.uid = 0 + else: + fatal("A user id is required for user '%s'" % self.name) + else: + fatal("'%s' is not a valid user id." % self.uid) + + + def add(self): + logger.debug("Process user %s ..." % self) + existing_user = None + try: + existing_user = pwd.getpwnam(self.name) + if existing_user and existing_user.pw_uid != self.uid: + fatal("User %s already exists with a different uid (%d).\n" % (self.name, existing_user.pw_uid)) + except KeyError: + logger.debug("User %s does not exist." % self.name) + + try: + existing_uid = pwd.getpwuid(self.uid) + if existing_uid and existing_uid.pw_name != self.name: + fatal("UID %d already exists with a different user (%s).\n" % (self.uid, existing_uid.pw_name)) + except KeyError: + logger.debug("UID %d does not exist." % self.uid) + + if existing_user: + logger.debug("User %s already exists." % self) + else: + logger.debug("Creating user %s ..." % (self)) + cmd = "useradd %s --uid %s --shell %s" % (self.name, self.uid, self.shell) + if self.home not in [ None, '' ]: + cmd += " -d %s" % (self.home) + execute(cmd, "User creation failed for user %s" % self) + + if not g_dry and self.name != 'root': + with open("/etc/sudoers.d/%s" % self.name, "w") as f: + f.write("%s ALL=(ALL:ALL) NOPASSWD:ALL\n" % self.name) + + +############################################################ + +ap = argparse.ArgumentParser("ONL Docker Shell Build and Development Container Init Script.") + +ap.add_argument("--user", "-u", + help="Run as the given user:uid. The user is created if necessary. The default is %s" % User.default_user, + default=User.default_user, + metavar="USERNAME:UID[:SHELL]") +ap.add_argument("--addusers", "-a", + help="Add additional users.", + nargs='+', + metavar="USERNAME:UID[:SHELL]", + default=[]) +ap.add_argument("--verbose", "-v", + help="Set verbose logging.", + action='store_true') +ap.add_argument("--start-cacher", + help="Start apt-cacher-ng in the container. It does not run by default.", + action='store_true') +ap.add_argument("--dry", + help="Dry run.", + action='store_true') +ap.add_argument('--command', '-c', + help="The command to run. All arguments after this option are considered part of the command.", + nargs='+', + default=["/bin/bash"]) + +ops = ap.parse_args() +opsdict = vars(ops) +g_dry = ops.dry + +if ops.verbose or ops.dry: + logger.setLevel(logging.DEBUG) + +g_user = User(ops.user) +g_user.add() + +for u in ops.addusers: + User(u).add() + +if ops.start_cacher: + execute("/etc/init.d/apt-cacher-ng start", "The apt-cacher-ng service could not be started.") + +# Fixme: change this to os.execvp() +c = "/usr/bin/sudo -E -u %s %s" % (g_user.name, " ".join(ops.command)) +execute(c) diff --git a/onlbuilder b/onlbuilder new file mode 100755 index 00000000..e8d98c1c --- /dev/null +++ b/onlbuilder @@ -0,0 +1,145 @@ +#!/usr/bin/python + +import os +import sys +import argparse +import datetime +import getpass +import subprocess +import logging +import pwd + +logging.basicConfig() +logger = logging.getLogger('onlbuilder') +logger.setLevel(logging.INFO) + +g_current_user = getpass.getuser() +g_current_uid = os.getuid() +g_timestamp = datetime.datetime.now().strftime("%Y-%m-%d.%H%M%S") + +g_default_image_name="opennetworklinux/builder7:1.0" +g_default_container_name = "%s_%s" % (g_current_user, g_timestamp) +g_default_user="%s:%s" % (g_current_user, g_current_uid) + +ap = argparse.ArgumentParser("ONL Docker Build") + +ap.add_argument("--dry", + help="Dry run.", + action='store_true') + +ap.add_argument("--verbose", "-v", + help="Verbose logging.", + action='store_true') + +ap.add_argument("--image", "-i", + help="The docker image to use. The default is %s." % g_default_image_name, + default=g_default_image_name) + +ap.add_argument("--exec", "-e", + help="Execute in running container instead of starting a new one.", + metavar='CONTAINER|NAME', + dest='exec_') + +ap.add_argument("--user", "-u", + help="Run as the given user:uid. Create if necessary. The default is you (%s)" % g_default_user, + default=g_default_user, + metavar='USERNAME:UID') + +ap.add_argument("--adduser", "-a", + help="Add additional user(s). These users will only be added to the container.", + nargs="+", + metavar='USENAME:UID') + +ap.add_argument("--name", "-n", + help="Set the container name. The default will be your username concatenated with the current timestamp (%s)." % g_default_container_name, + default=g_default_container_name) + +ap.add_argument("--workdir", "-w", + help="Set the working directory. The default will be the current working directory.", + default=os.getcwd()) + +ap.add_argument("--no-ssh", + help="Do not include current SSH Agent credentials. The default is to include them if present.", + action='store_true') + +ap.add_argument("--use-running", "-r", + help="Use an existing, matching, running container instead of starting a new one (if available).", + action='store_true'), + +ap.add_argument("--isolate", + help="Build isolation mode. Only the isolate directories are mounted, and a new network namespace is used. The --hostname becomes active in this mode.", + nargs='*') + +ap.add_argument("--hostname", + help="Change hostname in isolation mode.") +ap.add_argument("--non-interactive", + help="Non-interactive mode.", + action='store_true') + +ap.add_argument("--command", "-c", + help="Explicit command to run. All arguments after -c are considered to be part of the command.", + nargs='+', + default=['bash']) + +ops = ap.parse_args() + +if ops.verbose or ops.dry: + logger.setLevel(logging.DEBUG) + +logger.debug('arguments: %s\n' % vars(ops)) + +if ops.use_running: + sys.stderr.write("The --r option is not yet implemented.") + # Todo -- query running containers that match and set ops.exec_cid + sys.exit(1) + +g_ssh_options = '' +g_ssh_auth_sock = os.getenv('SSH_AUTH_SOCK') +if g_ssh_auth_sock and not ops.no_ssh: + g_ssh_dir = os.path.dirname(g_ssh_auth_sock) + g_ssh_options = '-v %s:%s -e SSH_AUTH_SOCK=%s' % (g_ssh_dir, g_ssh_dir, g_ssh_auth_sock) + +g_arg_d=vars(ops) + +g_arg_d['username'] = g_arg_d['user'].split(':')[0] +g_arg_d['ssh_options'] = g_ssh_options +g_arg_d['interactive'] = " " if ops.non_interactive else " -i " +g_arg_d['commands'] = " ".join(ops.command) + +# Get the home directory of the requested user. +try: + passwd = pwd.getpwnam(g_arg_d['username']) + g_arg_d['home'] = passwd.pw_dir +except KeyError: + # Not a local user. Just skip setting $HOME + pass + +if ops.exec_: + g_docker_arguments = "docker exec %(interactive)s -t %(exec_)s ~/OpenNetworkLinux/docker_shell --user %(user)s" % g_arg_d +else: + g_docker_arguments = "docker run --privileged %(interactive)s -t -e DOCKER_IMAGE=%(image)s --name %(name)s %(ssh_options)s -v /lib/modules:/lib/modules " % g_arg_d + + if ops.isolate is not None: + if len(ops.isolate) is 0: + ops.isolate.append(os.getcwd()) + + isolates = [ os.path.abspath(i) for i in ops.isolate ] + g_docker_arguments += " -e HOME=%s -w %s " % (isolates[0], isolates[0]) + for d in isolates: + g_docker_arguments += " -v %s:%s " % (d,d) + + if ops.hostname: + g_docker_arguments += " -h %s" % ops.hostname + + else: + # Development host mode + g_docker_arguments += "-e USER=%(username)s --net host -w %(workdir)s " % g_arg_d + if 'home' in g_arg_d: + g_docker_arguments += " -e HOME=%(home)s -v %(home)s:%(home)s" % g_arg_d + +g_docker_arguments += " %(image)s /bin/docker_shell --user %(user)s -c %(commands)s" % g_arg_d + +g_docker_arguments = " ".join(g_docker_arguments.split()) +logger.debug("running: %s" % g_docker_arguments) +if not ops.dry: + sys.exit(os.system(g_docker_arguments)) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc b/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc index f136ebbe..ec76348d 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc @@ -85,7 +85,7 @@ BR2_HOST_DIR="$(BASE_DIR)/host" # Mirrors and Download locations # BR2_PRIMARY_SITE="http://switch-nfs/export/buildroot-download-cache/dl" -BR2_PRIMARY_SITE_ONLY=y +BR2_PRIMARY_SITE_ONLY=n BR2_BACKUP_SITE="http://sources.buildroot.net/" BR2_KERNEL_MIRROR="http://www.kernel.org/pub/" BR2_GNU_MIRROR="http://ftp.gnu.org/pub/gnu"