Ability to run gbs under different user/group
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Thu, 5 Dec 2013 08:55:11 +0000 (10:55 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 10 Dec 2013 10:14:58 +0000 (12:14 +0200)
This change adds new configuration file options to set the user/group
under which gbs is run in the service. The service itself is run under
whatever user/group the source service server itself is configured to
use. The service now spawns a separate thread for gbs and sets the
uid/gid there before calling gbs - this is accomplished by utilizing
functionality from the obs-service-git-buildpackage-utils module.

Change-Id: I0c8a9c4d2349cd0ca629f816cb9011f26a42b3bb
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
config/gbs
obs_service_gbs/command.py
packaging/obs-service-gbs.spec
tests/test_obs_service_gbs.py

index 098d52b..3d68906 100644 (file)
 ## You probably need to define if the service is run on the client side as
 ## the default directory is likely not accessible by regular users.
 #repo-cache-dir = /var/cache/obs/git-buildpackage-repos/
+
+## User and group
+## The user and group under which gbs is run. The service itself is run under
+## whatever user/group the source service server is configured to use - this
+## user must have the privileges to set uid/gid if you configure these settings.
+## You can give the user and group as name or uid/gid number directly.
+#gbs-user = gbsservice
+#gbs-group = gbsservice
index fabeaa3..07f16f9 100644 (file)
@@ -32,6 +32,7 @@ import gbp.log as gbplog
 
 import gbp_repocache
 from gbp_repocache import CachedRepo, CachedRepoError
+from obs_service_gbp_utils import GbpServiceError, fork_call, sanitize_uid_gid
 
 
 # Setup logging
@@ -64,7 +65,9 @@ def construct_gbs_args(args, outdir, gitdir):
 
 def read_config(filenames):
     '''Read configuration file(s)'''
-    defaults = {'repo-cache-dir': '/var/cache/obs/gbs-repos/'}
+    defaults = {'repo-cache-dir': '/var/cache/obs/gbs-repos/',
+                'gbs-user': None,
+                'gbs-group': None}
 
     filenames = [os.path.expanduser(fname) for fname in filenames]
     LOGGER.debug('Trying %s config files: %s' % (len(filenames), filenames))
@@ -85,7 +88,7 @@ def read_config(filenames):
     # We only use keys from one section, for now
     return dict(parser.items('general'))
 
-def gbs_export(repo, args):
+def gbs_export(repo, args, config):
     '''Export packaging files with GBS'''
     # Create temporary directory
     try:
@@ -93,13 +96,25 @@ def gbs_export(repo, args):
     except OSError as err:
         raise ServiceError('Failed to create tmpdir: %s' % err, 1)
 
+    # Determine UID/GID and grant permissions to tmpdir
+    try:
+        uid, gid = sanitize_uid_gid(config['gbs-user'], config['gbs-group'])
+    except GbpServiceError as err:
+        raise ServiceError(err, 1)
+    os.chown(tmpdir, uid, gid)
+
     # Do export
     try:
         gbs_args = construct_gbs_args(args, tmpdir, repo.repodir)
         LOGGER.info('Exporting packaging files with GBS')
         LOGGER.debug('gbs args: %s' % gbs_args)
         try:
-            cmd_export(gbs_args)
+            fork_call(uid, gid, cmd_export, gbs_args)
+        except GbpServiceError as err:
+            LOGGER.error('Internal service error when trying to run GBS: '
+                         '%s' % err)
+            LOGGER.error('Most likely a configuration error (or a BUG)!')
+            raise ServiceError('Failed to run GBS thread: %s' % err, 1)
         except CmdError as err:
             raise ServiceError('GBS export failed: %s' % err, 2)
         except Exception as err:
@@ -168,7 +183,7 @@ def main(argv=None):
                 raise ServiceError('Failed to create outdir: %s' % err, 1)
 
         # Export sources with GBS
-        gbs_export(repo, args)
+        gbs_export(repo, args, config)
 
     except ServiceError as err:
         LOGGER.error(err[0])
index 088420d..7350cb3 100644 (file)
@@ -16,6 +16,7 @@ Source:         %{name}-%{version}.tar.bz2
 Requires:       gbs-export
 Requires:       git-buildpackage-common
 Requires:       gbp-repocache
+Requires:       obs-service-git-buildpackage-utils
 BuildRequires:  python
 BuildRequires:  python-setuptools
 %if 0%{?do_unittests}
@@ -24,6 +25,7 @@ BuildRequires:  python-nose
 BuildRequires:  gbs-export
 BuildRequires:  git-buildpackage-common
 BuildRequires:  gbp-repocache
+BuildRequires:  obs-service-git-buildpackage-utils
 %endif
 BuildArch:      noarch
 
index 4fc0d6c..26a31d5 100644 (file)
@@ -18,6 +18,7 @@
 # MA 02110-1301, USA.
 """Tests for the GBS source service"""
 
+import grp
 import os
 import shutil
 import stat
@@ -190,4 +191,18 @@ class TestGbsService(UnitTestsBase):
         ok_(not os.path.exists(default_cache), os.listdir('.'))
         ok_(os.path.exists('my-repo-cache'), os.listdir('.'))
 
+    def test_user_group_config(self):
+        """Test the user/group settings"""
+        # Changing to current user/group should succeed
+        os.environ['OBS_GBS_GBS_USER'] = str(os.getuid())
+        os.environ['OBS_GBS_GBS_GROUP'] = grp.getgrgid(os.getgid()).gr_name
+        eq_(service(['--url', self.orig_repo.path]), 0)
+
+        # Changing to non-existent user should fail
+        os.environ['OBS_GBS_GBS_USER'] = '_non_existent_user'
+        del os.environ['OBS_GBS_GBS_GROUP']
+        eq_(service(['--url', self.orig_repo.path]), 1)
+
+        # Return env
+        del os.environ['OBS_GBS_GBS_USER']