Esempio n. 1
0
def test_is_isolated_build(build_json, isolated):
    flexmock(util).should_receive('get_build_json').and_return(build_json)
    if isolated is None:
        with pytest.raises(KeyError):
            is_isolated_build()
    else:
        assert is_isolated_build() == isolated
Esempio n. 2
0
    def should_run(self):
        """
        Check if the plugin should run or skip execution.

        :return: bool, False if plugin should skip execution
        """
        if not self.is_in_orchestrator():
            self.log.warning("%s plugin set to run on worker. Skipping",
                             self.key)
            return False

        if not get_omps_config(self.workflow, None):
            self.log.info("Integration with OMPS is not configured. Skipping")
            return False

        if not has_operator_manifest(self.workflow):
            self.log.info("Not an operator build. Skipping")
            return False

        if is_scratch_build():
            self.log.info('Scratch build. Skipping')
            return False

        if is_rebuild(self.workflow):
            self.log.info('Autorebuild. Skipping')
            return False

        if is_isolated_build():
            self.log.info('Isolated build. Skipping')
            return False

        return True
Esempio n. 3
0
 def isolated_from_scratch_build(self):
     """Isolated builds for FROM scratch builds are prohibited
      except operator bundle images"""
     if (self.workflow.data.dockerfile_images.base_from_scratch
             and is_isolated_build(self.workflow)
             and not has_operator_bundle_manifest(self.workflow)):
         raise RuntimeError('"FROM scratch" image build cannot be isolated '
                            '(except operator bundle images)')
Esempio n. 4
0
    def run(self):
        """
        run the plugin
        """
        if self.koji_target:
            koji_session = get_koji_session(self.workflow, NO_FALLBACK)
            self.log.info("Checking koji target for platforms")
            event_id = koji_session.getLastEvent()['id']
            target_info = koji_session.getBuildTarget(self.koji_target,
                                                      event=event_id)
            build_tag = target_info['build_tag']
            koji_build_conf = koji_session.getBuildConfig(build_tag,
                                                          event=event_id)
            koji_platforms = koji_build_conf['arches']
            if not koji_platforms:
                self.log.info("No platforms found in koji target")
                return None
            platforms = koji_platforms.split()
            self.log.info("Koji platforms are %s", sorted(platforms))

            if is_scratch_build() or is_isolated_build():
                override_platforms = get_orchestrator_platforms(self.workflow)
                if override_platforms and set(override_platforms) != set(
                        platforms):
                    sort_platforms = sorted(override_platforms)
                    self.log.info("Received user specified platforms %s",
                                  sort_platforms)
                    self.log.info("Using them instead of koji platforms")
                    # platforms from user params do not match platforms from koji target
                    # that almost certainly means they were overridden and should be used
                    return set(override_platforms)
        else:
            platforms = get_orchestrator_platforms(self.workflow)
            self.log.info("No koji platforms. User specified platforms are %s",
                          sorted(platforms))

        if not platforms:
            raise RuntimeError(
                "Cannot determine platforms; no koji target or platform list")

        # Filter platforms based on clusters
        enabled_platforms = []
        for p in platforms:
            if self.reactor_config.get_enabled_clusters_for_platform(p):
                enabled_platforms.append(p)
            else:
                self.log.warning(
                    "No cluster found for platform '%s' in reactor config map, skipping",
                    p)

        final_platforms = get_platforms_in_limits(self.workflow,
                                                  enabled_platforms)

        self.log.info("platforms in limits : %s", final_platforms)
        return final_platforms
    def allow_inheritance(self):
        """Returns boolean if composes can be inherited"""
        if not self.workflow.source.config.inherit:
            return False
        self.log.info("Inheritance requested in config file")

        if is_scratch_build() or is_isolated_build():
            self.log.warning(
                "Inheritance is not allowed for scratch or isolated builds. "
                "Skipping inheritance.")
            return False

        return True
Esempio n. 6
0
    def allow_inheritance(self):
        """Returns boolean if composes can be inherited"""
        if not self.workflow.source.config.inherit:
            return False
        self.log.info("Inheritance requested in container.yaml file")

        if is_scratch_build(self.workflow) or is_isolated_build(self.workflow):
            msg = ("'inherit: true' in the compose section of container.yaml "
                   "is not allowed for scratch or isolated builds. "
                   "Skipping inheritance.")
            self.log.warning(msg)
            self.log.user_warning(message=msg)
            return False

        return True
    def run(self):
        """
        run the plugin
        """
        if self.koji_target:
            koji_session = get_koji_session(self.workflow, NO_FALLBACK)
            self.log.info("Checking koji target for platforms")
            event_id = koji_session.getLastEvent()['id']
            target_info = koji_session.getBuildTarget(self.koji_target, event=event_id)
            build_tag = target_info['build_tag']
            koji_build_conf = koji_session.getBuildConfig(build_tag, event=event_id)
            koji_platforms = koji_build_conf['arches']
            if not koji_platforms:
                self.log.info("No platforms found in koji target")
                return None
            platforms = koji_platforms.split()
            self.log.info("Koji platforms are %s", sorted(platforms))

            if is_scratch_build() or is_isolated_build():
                override_platforms = get_orchestrator_platforms(self.workflow)
                if override_platforms and set(override_platforms) != set(platforms):
                    sort_platforms = sorted(override_platforms)
                    self.log.info("Received user specified platforms %s", sort_platforms)
                    self.log.info("Using them instead of koji platforms")
                    # platforms from user params do not match platforms from koji target
                    # that almost certainly means they were overridden and should be used
                    return set(override_platforms)
        else:
            platforms = get_orchestrator_platforms(self.workflow)
            self.log.info("No koji platforms. User specified platforms are %s", sorted(platforms))

        if not platforms:
            raise RuntimeError("Cannot determine platforms; no koji target or platform list")

        # Filter platforms based on clusters
        enabled_platforms = []
        for p in platforms:
            if self.reactor_config.get_enabled_clusters_for_platform(p):
                enabled_platforms.append(p)
            else:
                self.log.warning(
                    "No cluster found for platform '%s' in reactor config map, skipping", p)

        final_platforms = get_platforms_in_limits(self.workflow, enabled_platforms)

        self.log.info("platforms in limits : %s", final_platforms)
        return final_platforms
Esempio n. 8
0
    def run(self):
        """
        run the plugin
        """
        if is_scratch_build(self.workflow):
            self.log.info('scratch build, skipping plugin')
            return False
        if is_isolated_build(self.workflow):
            self.log.info('isolated build, skipping plugin')
            return False

        if self.workflow.builder.dockerfile_images.base_from_scratch:
            self.log.info(
                "Skipping check and set rebuild: unsupported for FROM-scratch images"
            )
            return False
        if self.workflow.builder.dockerfile_images.custom_base_image:
            self.log.info(
                "Skipping check and set rebuild: unsupported for custom base images"
            )
            return False

        metadata = get_build_json().get("metadata", {})
        self.build_labels = metadata.get("labels", {})
        buildconfig = self.build_labels["buildconfig"]
        is_rebuild = self.build_labels.get(self.label_key) == self.label_value
        self.log.info("This is a rebuild? %s", is_rebuild)

        if not is_rebuild:
            # Update the BuildConfig metadata so the next Build
            # instantiated from it is detected as being an automated
            # rebuild
            osbs = get_openshift_session(self.workflow,
                                         self.openshift_fallback)
            new_labels = {self.label_key: self.label_value}
            osbs.update_labels_on_build_config(buildconfig, new_labels)
        else:
            self.pull_latest_commit_if_configured()

        return is_rebuild
    def run(self):
        """
        run the plugin
        """
        koji_session = get_koji_session(self.workflow, NO_FALLBACK)
        self.log.info("Checking koji target for platforms")
        event_id = koji_session.getLastEvent()['id']
        target_info = koji_session.getBuildTarget(self.koji_target, event=event_id)
        build_tag = target_info['build_tag']
        koji_build_conf = koji_session.getBuildConfig(build_tag, event=event_id)
        koji_platforms = koji_build_conf['arches']
        if not koji_platforms:
            self.log.info("No platforms found in koji target")
            return None
        platforms = koji_platforms.split()

        if is_scratch_build() or is_isolated_build():
            override_platforms = get_orchestrator_platforms(self.workflow)
            if override_platforms and set(override_platforms) != koji_platforms:
                # platforms from user params do not match platforms from koji target
                # that almost certainly means they were overridden and should be used
                return set(override_platforms)

        return get_platforms_in_limits(self.workflow, platforms)
Esempio n. 10
0
    def __init__(
        self,
        tasker,
        workflow,
        odcs_url=None,
        odcs_insecure=False,
        odcs_openidc_secret_path=None,
        odcs_ssl_secret_path=None,
        koji_target=None,
        koji_hub=None,
        koji_ssl_certs_dir=None,
        signing_intent=None,
        compose_ids=tuple(),
        repourls=None,
        minimum_time_to_expire=MINIMUM_TIME_TO_EXPIRE,
    ):
        """
        :param tasker: ContainerTasker instance
        :param workflow: DockerBuildWorkflow instance
        :param odcs_url: URL of ODCS (On Demand Compose Service)
        :param odcs_insecure: If True, don't check SSL certificates for `odcs_url`
        :param odcs_openidc_secret_path: directory to look in for a `token` file
        :param odcs_ssl_secret_path: directory to look in for `cert` file - a PEM file
                                     containing both cert and key
        :param koji_target: str, contains build tag to be used when requesting compose from "tag"
        :param koji_hub: str, koji hub (xmlrpc), required if koji_target is used
        :param koji_ssl_certs_dir: str, path to "cert", and "serverca"
                                   used when Koji's identity certificate is not trusted
        :param signing_intent: override the signing intent from git repo configuration
        :param compose_ids: use the given compose_ids instead of requesting a new one
        :param repourls: list of str, URLs to the repo files
        :param minimum_time_to_expire: int, used in deciding when to extend compose's time
                                       to expire in seconds
        """
        super(ResolveComposesPlugin, self).__init__(tasker, workflow)

        if signing_intent and compose_ids:
            raise ValueError(
                'signing_intent and compose_ids cannot be used at the same time'
            )

        self.signing_intent = signing_intent
        self.compose_ids = compose_ids
        self.odcs_fallback = {
            'api_url': odcs_url,
            'insecure': odcs_insecure,
            'auth': {
                'ssl_certs_dir': odcs_ssl_secret_path,
                'openidc_dir': odcs_openidc_secret_path
            }
        }

        self.koji_target = koji_target
        self.koji_fallback = {
            'hub_url': koji_hub,
            'auth': {
                'ssl_certs_dir': koji_ssl_certs_dir
            }
        }
        if koji_target:
            if not get_koji(self.workflow, self.koji_fallback)['hub_url']:
                raise ValueError(
                    'koji_hub is required when koji_target is used')

        self.minimum_time_to_expire = minimum_time_to_expire

        self._koji_session = None
        self._odcs_client = None
        self.odcs_config = None
        self.compose_config = None
        self.composes_info = None
        self._parent_signing_intent = None
        self.repourls = repourls or []
        self.inherit = self.workflow.source.config.inherit
        self.plugin_result = self.workflow.prebuild_results.get(
            PLUGIN_KOJI_PARENT_KEY)
        self.allow_inheritance = self.inherit and not (is_scratch_build()
                                                       or is_isolated_build())
        self.all_compose_ids = list(self.compose_ids)
    def run(self) -> Optional[List[str]]:
        """
        run the plugin
        """
        if self.koji_target:
            koji_session = get_koji_session(self.workflow.conf)
            self.log.info("Checking koji target for platforms")
            event_id = koji_session.getLastEvent()['id']
            target_info = koji_session.getBuildTarget(self.koji_target, event=event_id)
            build_tag = target_info['build_tag']
            koji_build_conf = koji_session.getBuildConfig(build_tag, event=event_id)
            koji_platforms = koji_build_conf['arches']
            if not koji_platforms:
                self.log.info("No platforms found in koji target")
                return None
            platforms = koji_platforms.split()
            self.log.info("Koji platforms are %s", sorted(platforms))

            if is_scratch_build(self.workflow) or is_isolated_build(self.workflow):
                override_platforms = set(get_orchestrator_platforms(self.workflow) or [])
                if override_platforms and override_platforms != set(platforms):
                    sorted_platforms = sorted(override_platforms)
                    self.log.info("Received user specified platforms %s", sorted_platforms)
                    self.log.info("Using them instead of koji platforms")
                    # platforms from user params do not match platforms from koji target
                    # that almost certainly means they were overridden and should be used
                    return sorted_platforms
        else:
            platforms = get_orchestrator_platforms(self.workflow)
            user_platforms = sorted(platforms) if platforms else None
            self.log.info("No koji platforms. User specified platforms are %s", user_platforms)

        if not platforms:
            raise RuntimeError("Cannot determine platforms; no koji target or platform list")

        # Filter platforms based on configured remote hosts
        remote_host_pools = self.workflow.conf.remote_hosts.get("pools", {})
        enabled_platforms = []
        defined_but_disabled = []

        def has_enabled_hosts(platform: str) -> bool:
            platform_hosts = remote_host_pools.get(platform, {})
            return any(host_info["enabled"] for host_info in platform_hosts.values())

        for p in platforms:
            if has_enabled_hosts(p):
                enabled_platforms.append(p)
            elif p in remote_host_pools:
                defined_but_disabled.append(p)
            else:
                self.log.warning("No remote hosts found for platform '%s' in "
                                 "reactor config map, skipping", p)
        if defined_but_disabled:
            msg = 'Platforms specified in config map, but have all remote hosts disabled' \
                  ' {}'.format(defined_but_disabled)
            raise RuntimeError(msg)

        final_platforms = self._limit_platforms(enabled_platforms)
        self.log.info("platforms in limits : %s", final_platforms)
        if not final_platforms:
            self.log.error("platforms in limits are empty")
            raise RuntimeError("No platforms to build for")

        self.workflow.build_dir.init_build_dirs(final_platforms, self.workflow.source)

        return final_platforms
    def __init__(self, tasker, workflow,
                 odcs_url=None,
                 odcs_insecure=False,
                 odcs_openidc_secret_path=None,
                 odcs_ssl_secret_path=None,
                 koji_target=None,
                 koji_hub=None,
                 koji_ssl_certs_dir=None,
                 signing_intent=None,
                 compose_ids=tuple(),
                 repourls=None,
                 minimum_time_to_expire=MINIMUM_TIME_TO_EXPIRE,
                 ):
        """
        :param tasker: DockerTasker instance
        :param workflow: DockerBuildWorkflow instance
        :param odcs_url: URL of ODCS (On Demand Compose Service)
        :param odcs_insecure: If True, don't check SSL certificates for `odcs_url`
        :param odcs_openidc_secret_path: directory to look in for a `token` file
        :param odcs_ssl_secret_path: directory to look in for `cert` file - a PEM file
                                     containing both cert and key
        :param koji_target: str, contains build tag to be used when requesting compose from "tag"
        :param koji_hub: str, koji hub (xmlrpc), required if koji_target is used
        :param koji_ssl_certs_dir: str, path to "cert", and "serverca"
                                   used when Koji's identity certificate is not trusted
        :param signing_intent: override the signing intent from git repo configuration
        :param compose_ids: use the given compose_ids instead of requesting a new one
        :param repourls: list of str, URLs to the repo files
        :param minimum_time_to_expire: int, used in deciding when to extend compose's time
                                       to expire in seconds
        """
        super(ResolveComposesPlugin, self).__init__(tasker, workflow)

        if signing_intent and compose_ids:
            raise ValueError('signing_intent and compose_ids cannot be used at the same time')

        self.signing_intent = signing_intent
        self.compose_ids = compose_ids
        self.odcs_fallback = {
            'api_url': odcs_url,
            'insecure': odcs_insecure,
            'auth': {
                'ssl_certs_dir': odcs_ssl_secret_path,
                'openidc_dir': odcs_openidc_secret_path
            }
        }

        self.koji_target = koji_target
        self.koji_fallback = {
            'hub_url': koji_hub,
            'auth': {
                'ssl_certs_dir': koji_ssl_certs_dir
            }
        }
        if koji_target:
            if not get_koji(self.workflow, self.koji_fallback)['hub_url']:
                raise ValueError('koji_hub is required when koji_target is used')

        self.minimum_time_to_expire = minimum_time_to_expire

        self._koji_session = None
        self._odcs_client = None
        self.odcs_config = None
        self.compose_config = None
        self.composes_info = None
        self._parent_signing_intent = None
        self.repourls = repourls or []
        self.inherit = self.workflow.source.config.inherit
        self.plugin_result = self.workflow.prebuild_results.get(PLUGIN_KOJI_PARENT_KEY)
        self.allow_inheritance = self.inherit and not (is_scratch_build() or is_isolated_build())
        self.all_compose_ids = list(self.compose_ids)