From 974e49e68bb0fc4fb2bf0d771d0bbfbae2c12ec2 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Feb 02 2017 11:51:05 +0000
Subject: Make --can-fail option working for make-image


There are two issues:
1) --can-fail option was ignored when passing to hub
2) when using config, can_fail was ignored as internal variable has
different name

---

diff --git a/builder/kojid b/builder/kojid
index 78c707d..ba9a0fe 100755
--- a/builder/kojid
+++ b/builder/kojid
@@ -2121,6 +2121,7 @@ class BuildBaseImageTask(BuildImageTask):
 
             subtasks = {}
             self.logger.debug("Spawning jobs for image arches: %r" % (arches))
+            canfail = []
             for arch in arches:
                 inst_url = inst_tree.replace('$arch', arch)
                 subtasks[arch] = self.session.host.subtask(
@@ -2128,9 +2129,30 @@ class BuildBaseImageTask(BuildImageTask):
                     arglist=[name, version, release, arch, target_info,
                     build_tag, repo_info, inst_url, opts],
                     label=arch, parent=self.id, arch=arch)
+                if arch in opts.get('optional_arches', []):
+                    canfail.append(subtasks[arch])
             self.logger.debug("Got image subtasks: %r" % (subtasks))
-            self.logger.debug("Waiting on image subtasks...")
-            results = self.wait(subtasks.values(), all=True, failany=True)
+            self.logger.debug("Waiting on image subtasks (%s can fail)..." % canfail)
+            results = self.wait(subtasks.values(), all=True, failany=True, canfail=canfail)
+
+            # if everything failed, fail even if all subtasks are in canfail
+            self.logger.debug('subtask results: %r', results)
+            all_failed = True
+            for result in results.values():
+                if not isinstance(result, dict) or 'faultCode' not in result:
+                    all_failed = False
+                    break
+            if all_failed:
+                raise koji.GenericError("all subtasks failed")
+
+            # determine ignored arch failures
+            ignored_arches = set()
+            for arch in arches:
+                if arch in opts.get('optional_arches', []):
+                    task_id = subtasks[arch]
+                    result = results[task_id]
+                    if isinstance(result, dict) and 'faultCode' in result:
+                        ignored_arches.add(arch)
 
             # wrap in an RPM if asked
             rpm_results = None
@@ -2139,7 +2161,7 @@ class BuildBaseImageTask(BuildImageTask):
                 # get around an xmlrpc limitation, use arches for keys instead
                 results[arch] = results[subtasks[arch]]
                 del results[subtasks[arch]]
-                if spec_url:
+                if spec_url and arch not in ignored_arches:
                     subtask = subtasks[arch]
                     results[arch]['rpmresults'] = self.buildWrapperRPM(
                         spec_url, subtask, target_info, bld_info,
diff --git a/cli/koji b/cli/koji
index 4e39dc1..19fba46 100755
--- a/cli/koji
+++ b/cli/koji
@@ -5778,6 +5778,9 @@ def handle_image_build(options, session, args):
             if config.has_option(section, arg):
                 setattr(task_options, arg, config.get(section, arg).split(','))
                 config.remove_option(section, arg)
+        if config.has_option(section, 'can_fail'):
+            setattr(task_options, 'optional_arches', config.get(section, 'can_fail').split(','))
+            config.remove_option(section, 'can_fail')
         # handle everything else
         for k, v in config.items(section):
             setattr(task_options, k, v)
@@ -5865,7 +5868,7 @@ def _build_image(options, task_opts, session, args, img_type):
     passthru_opts = [
         'format', 'install_tree_url', 'isoname', 'ksurl',
         'ksversion', 'release', 'repo', 'scratch', 'skip_tag',
-        'specfile', 'title', 'vcpu', 'vmem',
+        'specfile', 'title', 'vcpu', 'vmem', 'optional_arches',
         ]
     for opt in passthru_opts:
         val = getattr(task_opts, opt, None)
@@ -5935,7 +5938,8 @@ def _build_image_oz(options, task_opts, session, args):
     hub_opts = {}
     for opt in ('ksurl', 'ksversion', 'kickstart', 'scratch', 'repo',
                 'release', 'skip_tag', 'specfile', 'distro', 'format',
-                'disk_size', 'ova_option', 'factory_parameter'):
+                'disk_size', 'ova_option', 'factory_parameter',
+                'optional_arches'):
         val = getattr(task_opts, opt, None)
         if val is not None:
             hub_opts[opt] = val

