Ejemplo n.º 1
0
 def __init__(self,
              filesystem,
              user_namespace=None,
              private_net=None,
              hostname=None,
              links=None):
     self.filesystem = filesystem
     if user_namespace is None:
         self.user_namespace = UserNamespace(None, None)
     else:
         self.user_namespace = user_namespace
     self.private_net = private_net
     self.hostname = hostname
     self.links = links
Ejemplo n.º 2
0
def run(obj, container_id, command, bridge, entrypoint, env, force, from_image,
        ip, link, rm, target_uid, target_gid, user, workdir):
    shoebox_dir = obj['shoebox_dir']
    repo = obj['repo']

    if bridge != 'None' and ip is not None:
        private_net = PrivateNetwork(bridge, ip)
    else:
        private_net = None

    links = []
    if link is not None:
        if private_net and ip:
            for l in link:
                source, alias = l.split(':', 1)
                link_ct = Container(shoebox_dir, source)
                links.append(ContainerLink(link_ct, alias))
        else:
            logging.warning(
                'Ignoring container links when running without private networking'
            )

    userns = UserNamespace(target_uid, target_gid)

    if from_image is None:
        container = load_container(container_id, shoebox_dir)
    else:
        container = clone_image(force, from_image, repo, shoebox_dir, userns)

    run_container(container, userns, shoebox_dir, command, entrypoint, user,
                  workdir, rm, private_net, links, env)
Ejemplo n.º 3
0
 def __init__(self, filesystem, user_namespace=None, private_net=None, hostname=None, links=None):
     self.filesystem = filesystem
     if user_namespace is None:
         self.user_namespace = UserNamespace(None, None)
     else:
         self.user_namespace = user_namespace
     self.private_net = private_net
     self.hostname = hostname
     self.links = links
Ejemplo n.º 4
0
def build(obj, base_dir, force, target_uid, target_gid):
    repo = obj['repo']
    shoebox_dir = obj['shoebox_dir']

    os.chdir(base_dir)
    dockerfile = parse_dockerfile(open('Dockerfile').read(), repo=repo)
    userns = UserNamespace(target_uid, target_gid)
    container = build_container(os.getcwd(), force, dockerfile, repo,
                                shoebox_dir, userns)

    print container.container_id
Ejemplo n.º 5
0
class ContainerNamespace(object):
    def __init__(self, filesystem, user_namespace=None, private_net=None, hostname=None, links=None):
        self.filesystem = filesystem
        if user_namespace is None:
            self.user_namespace = UserNamespace(None, None)
        else:
            self.user_namespace = user_namespace
        self.private_net = private_net
        self.hostname = hostname
        self.links = links

    def __repr__(self):
        return 'FS: {0!r}, USER: {1!r}, NET: {2!r}'.format(self.filesystem, self.user_namespace, self.private_net)

    def linked_hostnames(self):
        if not self.links:
            return

        ip_names = defaultdict(set)
        ip_aliases = defaultdict(set)
        aliases = set()
        for link in self.links:
            ip_names[link.target_ip].add(link.source_container.container_id)
            ip_aliases[link.target_ip].add(link.alias)
            aliases.add(link.alias)

        for ip, names in ip_names.items():
            yield ip, list(ip_aliases[ip]) + [n for n in names if n not in aliases]

    def etc_hosts(self):
        base_hosts = """
127.0.0.1	localhost

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
"""
        hosts = []
        if self.private_net and self.private_net.ip_address and self.hostname:
            hosts.append('{0} {1}'.format(self.private_net.ip_address, self.hostname))

            for ip, names in self.linked_hostnames():
                hosts.append('{0} {1}'.format(ip, ' '.join(names)))

        return '\n'.join(hosts) + base_hosts

    def etc_resolv_conf(self):
        resolvconf = []
        for line in open('/etc/resolv.conf'):
            line = line.strip()
            if line.startswith('nameserver'):
                _, ns = line.split()
                if ns.startswith('127.') and self.private_net and self.private_net.ip_address:
                    resolvconf.append('nameserver {0}'.format(self.private_net.gateway))
                    continue
            resolvconf.append(line)
        return '\n'.join(resolvconf)

    def build(self):
        self.filesystem.check_root_dir()
        resolvconf = self.etc_resolv_conf()

        with self.user_namespace.setup_userns():
            namespaces = CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWPID
            if self.private_net:
                namespaces |= CLONE_NEWNET
                with self.private_net.setup_netns():
                    unshare(namespaces)
            else:
                unshare(namespaces)

        if self.hostname:
            sethostname(self.hostname)

        self.filesystem.build()
        if self.filesystem.special_fs:
            with open('/etc/hosts', 'w') as hosts:
                print >> hosts, self.etc_hosts()

            with open('/etc/resolv.conf', 'w') as resolv:
                print >> resolv, resolvconf

        drop_caps()
        os.setgroups([os.getgid()])

    def execns(self, ns_func, *args, **kwargs):
        exitcode = 1
        # noinspection PyBroadException
        try:
            self.build()
            ns_func(*args, **kwargs)
            exitcode = 0
        except:
            logger.exception('Exception inside namespace {0!r}'.format(self))
        finally:
            # noinspection PyProtectedMember
            os._exit(exitcode)

    def run(self, ns_func, *args, **kwargs):
        pid = os.fork()
        if pid:
            _, ret = os.waitpid(pid, 0)
            exitcode = ret >> 8
            exitsig = ret & 0x7f
            if exitsig:
                raise RuntimeError('Subprocess caught signal {0}'.format(exitsig))
            elif exitcode:
                raise RuntimeError('Subprocess exited with status {0}'.format(exitcode))
        else:
            self.execns(ns_func, *args, **kwargs)
Ejemplo n.º 6
0
def rm(obj, container_id, target_uid, target_gid, volumes):
    shoebox_dir = obj['shoebox_repo']
    userns = UserNamespace(target_uid, target_gid)
    for container in container_id:
        remove_container(shoebox_dir, container, userns, volumes)
Ejemplo n.º 7
0
class ContainerNamespace(object):
    def __init__(self,
                 filesystem,
                 user_namespace=None,
                 private_net=None,
                 hostname=None,
                 links=None):
        self.filesystem = filesystem
        if user_namespace is None:
            self.user_namespace = UserNamespace(None, None)
        else:
            self.user_namespace = user_namespace
        self.private_net = private_net
        self.hostname = hostname
        self.links = links

    def __repr__(self):
        return 'FS: {0!r}, USER: {1!r}, NET: {2!r}'.format(
            self.filesystem, self.user_namespace, self.private_net)

    def linked_hostnames(self):
        if not self.links:
            return

        ip_names = defaultdict(set)
        ip_aliases = defaultdict(set)
        aliases = set()
        for link in self.links:
            ip_names[link.target_ip].add(link.source_container.container_id)
            ip_aliases[link.target_ip].add(link.alias)
            aliases.add(link.alias)

        for ip, names in ip_names.items():
            yield ip, list(
                ip_aliases[ip]) + [n for n in names if n not in aliases]

    def etc_hosts(self):
        base_hosts = """
127.0.0.1	localhost

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
"""
        hosts = []
        if self.private_net and self.private_net.ip_address and self.hostname:
            hosts.append('{0} {1}'.format(self.private_net.ip_address,
                                          self.hostname))

            for ip, names in self.linked_hostnames():
                hosts.append('{0} {1}'.format(ip, ' '.join(names)))

        return '\n'.join(hosts) + base_hosts

    def etc_resolv_conf(self):
        resolvconf = []
        for line in open('/etc/resolv.conf'):
            line = line.strip()
            if line.startswith('nameserver'):
                _, ns = line.split()
                if ns.startswith(
                        '127.'
                ) and self.private_net and self.private_net.ip_address:
                    resolvconf.append('nameserver {0}'.format(
                        self.private_net.gateway))
                    continue
            resolvconf.append(line)
        return '\n'.join(resolvconf)

    def build(self):
        self.filesystem.check_root_dir()
        resolvconf = self.etc_resolv_conf()

        with self.user_namespace.setup_userns():
            namespaces = CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_NEWPID
            if self.private_net:
                namespaces |= CLONE_NEWNET
                with self.private_net.setup_netns():
                    unshare(namespaces)
            else:
                unshare(namespaces)

        if self.hostname:
            sethostname(self.hostname)

        self.filesystem.build()
        if self.filesystem.special_fs:
            with open('/etc/hosts', 'w') as hosts:
                print >> hosts, self.etc_hosts()

            with open('/etc/resolv.conf', 'w') as resolv:
                print >> resolv, resolvconf

        drop_caps()
        os.setgroups([os.getgid()])

    def execns(self, ns_func, *args, **kwargs):
        exitcode = 1
        # noinspection PyBroadException
        try:
            self.build()
            ns_func(*args, **kwargs)
            exitcode = 0
        except:
            logger.exception('Exception inside namespace {0!r}'.format(self))
        finally:
            # noinspection PyProtectedMember
            os._exit(exitcode)

    def run(self, ns_func, *args, **kwargs):
        pid = os.fork()
        if pid:
            _, ret = os.waitpid(pid, 0)
            exitcode = ret >> 8
            exitsig = ret & 0x7f
            if exitsig:
                raise RuntimeError(
                    'Subprocess caught signal {0}'.format(exitsig))
            elif exitcode:
                raise RuntimeError(
                    'Subprocess exited with status {0}'.format(exitcode))
        else:
            self.execns(ns_func, *args, **kwargs)