Implement 'error-pkg' parameter
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Mon, 2 Jun 2014 15:42:32 +0000 (18:42 +0300)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 3 Jun 2014 13:08:21 +0000 (16:08 +0300)
Instead of causing a service error generate a special "error package"
that shows the service error log but fails to build. The parameter value
is a comma-separated list of integers, representing the exit codes for
which the special error package is created.

This is a special hack to prevent the +creation of broken packages in
case of service failures.

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

index a8f75d7..1372c65 100644 (file)
@@ -41,6 +41,37 @@ EXIT_ERR_SERVICE = 1
 EXIT_ERR_GBS_EXPORT = 2
 EXIT_ERR_GBS_CRASH = 3
 
+# Template spec file for the "error package"
+ERROR_PKG_SPEC = """
+Name:           service-error
+Version:        1
+Release:        0
+License:        GPL-2.0+
+Summary:        Package indicating an export error in gbs source service
+Source0:        service-error
+
+%description
+This is a dummy package created by obs-service-gbs that indicates that
+exporting the packaging files failed. This is a special hack to prevent the
+creation of broken packages in case of service failures. This behaviour was
+implicitly enabled with the 'error-pkg' parameter of the service.
+
+%build
+cat << EOF
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!
+!!!
+!!! OBS-SERVICE-GBS FAILED
+!!!
+!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+--- SERVICE ERROR LOG --------------------------------------------------------
+`sed s'/^/  /' %{SOURCE0}`
+--- END OF SERVICE ERROR LOG -------------------------------------------------
+EOF
+exit 1
+"""
+
 # Setup logging
 LOGGER = gbplog.getLogger('source_service')
 LOGGER.setLevel(gbplog.INFO)
@@ -143,6 +174,10 @@ def gbs_export(repo, args, config):
     finally:
         shutil.rmtree(tmpdir)
 
+def integer_list(string):
+    """Convert a string of comma-separated integers into a list of ints"""
+    return [int(val.strip()) for val in string.split(',') if val]
+
 def parse_args(argv):
     """Argument parser"""
     default_configs = ['/etc/obs/services/gbs',
@@ -161,6 +196,11 @@ def parse_args(argv):
     parser.add_argument('--git-meta', metavar='FILENAME',
                         help='Create a json-formatted file FILENAME containing'
                              'metadata about the exported revision')
+    parser.add_argument('--error-pkg', metavar='EXIT_CODES', type=integer_list,
+                        default=[],
+                        help='Comma-separated list of exit codes that cause '
+                             'an "error package" to be created instead of '
+                             'causing a service error.')
     args = parser.parse_args(argv)
     if not args.config:
         args.config = default_configs
@@ -182,22 +222,30 @@ def main(argv=None):
     else:
         gbplog.setup(color='auto', verbose=False)
         gbs_log.setup(verbose=False)
+    # Add a new handler writing to a tempfile into the root logger
+    file_log = tempfile.NamedTemporaryFile(prefix='gbs-service_')
+    file_handler = gbplog.GbpStreamHandler(file_log)
+    gbplog.getLogger().addHandler(file_handler)
 
     LOGGER.info('Starting GBS source service')
 
+    # Create outdir
+    try:
+        os.makedirs(args.outdir)
+    except OSError as err:
+        if err.errno != os.errno.EEXIST:
+            LOGGER.error('Failed to create outdir: %s', err)
+            return EXIT_ERR_SERVICE
+
     try:
         config = read_config(args.config)
         # Create / update cached repository
-        repo = CachedRepo(config['repo-cache-dir'], args.url)
-        args.revision = repo.update_working_copy(args.revision,
-                                                 submodules=False)
-        # Create outdir
         try:
-            os.makedirs(args.outdir)
-        except OSError as err:
-            if err.errno != os.errno.EEXIST:
-                raise ServiceError('Failed to create outdir: %s' % err,
-                                   EXIT_ERR_SERVICE)
+            repo = CachedRepo(config['repo-cache-dir'], args.url)
+            args.revision = repo.update_working_copy(args.revision,
+                                                     submodules=False)
+        except CachedRepoError as err:
+            raise ServiceError('RepoCache: %s' % err, EXIT_ERR_SERVICE)
 
         # Export sources with GBS
         gbs_export(repo, args, config)
@@ -211,9 +259,14 @@ def main(argv=None):
                 raise ServiceError(str(err), EXIT_ERR_SERVICE)
     except ServiceError as err:
         LOGGER.error(err[0])
-        ret = err[1]
-    except CachedRepoError as err:
-        LOGGER.error('RepoCache: %s', err)
-        ret = EXIT_ERR_SERVICE
+        if err[1] in args.error_pkg:
+            file_handler.flush()
+            error_fn = os.path.join(args.outdir, 'service-error')
+            shutil.copy2(file_log.name, error_fn)
+            with open(error_fn + '.spec', 'w') as error_spec:
+                error_spec.write(ERROR_PKG_SPEC)
+            ret = EXIT_OK
+        else:
+            ret = err[1]
 
     return ret
index fdaeb06..c1e2846 100644 (file)
@@ -1,6 +1,9 @@
 <service name="gbs">
     <summary>Build with GBS (Git Build System)</summary>
     <description>Export packaging files from a git repository managed with GBS (Git Build System).</description>
+    <parameter name="error-pkg">
+        <description>Instead of service error create an "error package". Comma-separated list of exit codes.</description>
+    </parameter>
     <parameter name="git-meta">
         <description>Export meta data about the revision into a file in JSON format.</description>
     </parameter>
index cbc20ea..93659bc 100644 (file)
@@ -234,6 +234,19 @@ class TestGbsService(UnitTestsBase):
         eq_(service(['--url', self.orig_repo.path,
                      '--git-meta=test-package.spec']), 1)
 
+    def test_options_error_pkg(self):
+        """Test the --error-pkg option"""
+        # Do not create err-pkg if exit code not listed
+        eq_(service(['--url', self.orig_repo.path, '--error-pkg=2,3',
+                     '--revision=foobar']), 1)
+        self.check_files([])
+
+        # Catch error and create err-pkg
+        eq_(service(['--url', self.orig_repo.path, '--error-pkg=1,2,3',
+                     '--revision=foobar', '--outdir=foo']), 0)
+        self.check_files(['service-error.spec', 'service-error'],
+                         directory='foo')
+
     def test_user_group_config(self):
         """Test the user/group settings"""
         # Changing to current user/group should succeed