From 0aeb1c42af231c22ebe89d47ceeeb7fa318549cf Mon Sep 17 00:00:00 2001 From: Disassembler Date: Fri, 7 Feb 2020 17:27:19 +0100 Subject: [PATCH] Add ability to set UID/GID by username --- usr/lib/python3.8/spoc/container.py | 15 ++++++++++++--- usr/lib/python3.8/spoc/imagebuilder.py | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/usr/lib/python3.8/spoc/container.py b/usr/lib/python3.8/spoc/container.py index 1fc5f3c..023141c 100644 --- a/usr/lib/python3.8/spoc/container.py +++ b/usr/lib/python3.8/spoc/container.py @@ -170,7 +170,7 @@ class Container: subprocess.Popen(['lxc-stop', '-P', CONTAINERS_DIR, self.name]) self.await_state(STATE_STOPPED) - def execute(self, cmd, check=False): + def execute(self, cmd, **kwargs): # TODO: Allow to pass UID/GID # If the container is starting or stopping, wait until the operation is finished state = self.get_state() @@ -182,8 +182,17 @@ class Container: state = self.get_state() # If the container is stopped, use lxc-execute, otherwise use lxc-attach if state == STATE_STOPPED: - return subprocess.run(['lxc-execute', '-P', CONTAINERS_DIR, self.name, '--']+cmd, check=check) + return subprocess.run(['lxc-execute', '-P', CONTAINERS_DIR, self.name, '--']+cmd, **kwargs) elif state == STATE_RUNNING: - return subprocess.run(['lxc-attach', '-P', CONTAINERS_DIR, '--clear-env', self.name, '--']+cmd, check=check) + return subprocess.run(['lxc-attach', '-P', CONTAINERS_DIR, '--clear-env', self.name, '--']+cmd, **kwargs) else: raise InvalidContainerStateError(self.name, state) + + def get_uidgid(self, user, group=None): + # Helper function to get UID/GID of an user/group from the container + uid_entry = self.execute(['/usr/bin/getent', 'passwd', user], capture_output=True, check=True).stdout.decode().split(':') + if group: + gid_entry = self.execute(['/usr/bin/getent', 'group', group], capture_output=True, check=True).stdout.decode().split(':') + return (uid_entry[2], gid_entry[2]) + else: + return (uid_entry[2], uid_entry[3]) diff --git a/usr/lib/python3.8/spoc/imagebuilder.py b/usr/lib/python3.8/spoc/imagebuilder.py index 411e9d0..16e19df 100644 --- a/usr/lib/python3.8/spoc/imagebuilder.py +++ b/usr/lib/python3.8/spoc/imagebuilder.py @@ -52,7 +52,7 @@ class ImageBuilder: self.set_env(*args.split(None, 1)) elif 'USER' == directive: # Sets init UID / GID - self.image.uid,self.image.gid = args.split() #TODO: Get UID/GID by name + get GID automatically as primary UID group if only UID is given + self.set_uidgid(*args.split()) elif 'CMD' == directive: # Sets init command self.image.cmd = args @@ -82,11 +82,12 @@ class ImageBuilder: container.set_definition(self.image.get_definition()) container.build = True container.create() - container.execute(['/bin/sh', '-lc', os.path.join('/', script_name)], True) + container.execute(['/bin/sh', '-lc', os.path.join('/', script_name)], check=True) container.destroy() os.unlink(script_path) def set_env(self, key, value=None): + # Set or unset environement variable if value: self.image.env[key] = value else: @@ -95,6 +96,18 @@ class ImageBuilder: except KeyError: pass + def set_uidgid(self, uid, gid=''): + # Set UID/GID for init + if not uid.isdigit() or not gid.isdigit(): + # Resolve the UID/GID from container if either of them is entered as string + container = Container(self.image.name, False) + container.set_definition(self.image.get_definition()) + container.create() + uid,gid = container.get_uidgid(uid, gid) + container.destroy() + self.image.uid = uid + self.image.gid = gid + def copy_files(self, src, dst): # Copy files from the host or download them from a http(s) URL dst = os.path.join(self.image.layer_path, dst.lstrip('/'))