def run(self):
        """
        run the plugin
        """
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        resolve_comp_result = self.workflow.data.prebuild_results.get(
            PLUGIN_RESOLVE_COMPOSES_KEY)
        flatpak_util = FlatpakUtil(workflow_config=self.workflow.conf,
                                   source_config=self.workflow.source.config,
                                   composes=resolve_comp_result['composes'])

        compose_info = flatpak_util.get_flatpak_compose_info()
        source = flatpak_util.get_flatpak_source_info()

        builder = FlatpakBuilder(source, None, None)

        builder.precheck()

        flatpak_update = functools.partial(self.update_dockerfile, builder,
                                           compose_info)
        self.workflow.build_dir.for_each_platform(flatpak_update)

        create_files = functools.partial(
            self.create_includepkgs_file_and_cleanupscript, builder)
        self.workflow.build_dir.for_all_platforms_copy(create_files)
Пример #2
0
    def run(self):
        """
        run the plugin
        """
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        flatpak_yaml = self.workflow.source.config.flatpak
        if flatpak_yaml is None:
            return
        labels = flatpak_yaml.get('labels')
        if not labels:
            return

        labels_str = " ".join(
            label_to_string(k, v) for k, v in sorted(labels.items()))
        label_line = f"\nLABEL {labels_str}\n"

        def add_labels_to_df(build_dir: BuildDir) -> None:
            dockerfile = build_dir.dockerfile
            # put labels at the end of dockerfile (since they change metadata and do not interact
            # with FS, this should cause no harm)
            dockerfile.lines = dockerfile.lines + [label_line]

        self.workflow.build_dir.for_each_platform(add_labels_to_df)
Пример #3
0
    def run(self):
        """
        run the plugin
        """
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        flatpak_yaml = self.workflow.source.config.flatpak
        if flatpak_yaml is None:
            return
        labels = flatpak_yaml.get('labels')
        if not labels:
            return

        dockerfile = df_parser(self.workflow.builder.df_path, workflow=self.workflow)
        lines = dockerfile.lines

        # Sort to get repeatable results with Python2
        formatted_labels = []
        for k in sorted(labels):
            formatted_labels.append(label_to_string(k, labels[k]))

        # put labels at the end of dockerfile (since they change metadata and do not interact
        # with FS, this should cause no harm)
        lines.append('\nLABEL ' + " ".join(formatted_labels) + '\n')
        dockerfile.lines = lines
Пример #4
0
    def _update_extra(self, extra):
        if not isinstance(self.workflow.source, GitSource):
            raise RuntimeError('git source required')

        try:
            isolated = self.workflow.user_params['isolated']
        except (IndexError, AttributeError, KeyError):
            isolated = False
        self.log.info("build is isolated: %r", isolated)
        extra['image']['isolated'] = isolated

        fs_koji_task_id = self._filesystem_koji_task_id
        if fs_koji_task_id is not None:
            extra['filesystem_koji_task_id'] = fs_koji_task_id

        extra['image'].update(get_parent_image_koji_data(self.workflow))

        resolve_comp_result = self.workflow.data.prebuild_results.get(
            PLUGIN_RESOLVE_COMPOSES_KEY)
        if resolve_comp_result['composes']:
            extra['image']['odcs'] = {
                'compose_ids':
                [item['id'] for item in resolve_comp_result['composes']],
                'signing_intent':
                resolve_comp_result['signing_intent'],
                'signing_intent_overridden':
                resolve_comp_result['signing_intent_overridden'],
            }
        if self.workflow.data.all_yum_repourls:
            extra['image'][
                'yum_repourls'] = self.workflow.data.all_yum_repourls

        if is_flatpak_build(self.workflow):
            flatpak_util = FlatpakUtil(
                workflow_config=self.workflow.conf,
                source_config=self.workflow.source.config,
                composes=resolve_comp_result['composes'])
            flatpak_compose_info = flatpak_util.get_flatpak_compose_info()
            if flatpak_compose_info:
                koji_metadata = flatpak_compose_info.koji_metadata()
                extra['image'].update(koji_metadata)
                extra['osbs_build']['subtypes'].append('flatpak')

        self.set_help(extra)
        self.set_operators_metadata(extra)
        self.set_pnc_build_metadata(extra)
        self.set_remote_sources_metadata(extra)
        self.set_remote_source_file_metadata(extra)

        self.set_go_metadata(extra)
        self.set_group_manifest_info(extra)
        extra['osbs_build']['kind'] = KOJI_KIND_IMAGE_BUILD
        # OSBS2 TBD
        extra['osbs_build']['engine'] = 'podman'
        if has_operator_appregistry_manifest(self.workflow):
            extra['osbs_build']['subtypes'].append(KOJI_SUBTYPE_OP_APPREGISTRY)
        if has_operator_bundle_manifest(self.workflow):
            extra['osbs_build']['subtypes'].append(KOJI_SUBTYPE_OP_BUNDLE)
        if self.userdata:
            extra['custom_user_metadata'] = self.userdata
    def run(self):
        """
        run the plugin
        """
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        self._load_compose_info()
        compose_info = get_flatpak_compose_info(self.workflow)

        self._load_source()
        source = get_flatpak_source_info(self.workflow)

        builder = FlatpakBuilder(source, None, None)

        builder.precheck()

        # Update the dockerfile

        # We need to enable all the modules other than the platform pseudo-module
        enable_modules_str = ' '.join(builder.get_enable_modules())

        install_packages_str = ' '.join(builder.get_install_packages())

        replacements = {
            '@ENABLE_MODULES@': enable_modules_str,
            '@INSTALL_PACKAGES@': install_packages_str,
            '@RELEASE@': compose_info.main_module.version,
        }

        dockerfile = df_parser(self.workflow.builder.df_path,
                               workflow=self.workflow)
        content = dockerfile.content

        # Perform the substitutions; simple approach - should be efficient enough
        for old, new in replacements.items():
            content = content.replace(old, new)

        dockerfile.content = content

        # Create a file describing which packages from the base yum repositories are included

        includepkgs = builder.get_includepkgs()
        includepkgs_path = os.path.join(self.workflow.builder.df_dir,
                                        FLATPAK_INCLUDEPKGS_FILENAME)
        with open(includepkgs_path, 'w') as f:
            f.write('includepkgs = ' + ','.join(includepkgs) + '\n')

        # Create the cleanup script

        cleanupscript = os.path.join(self.workflow.builder.df_dir,
                                     FLATPAK_CLEANUPSCRIPT_FILENAME)
        with open(cleanupscript, 'w') as f:
            f.write(builder.get_cleanup_script())
        os.chmod(cleanupscript, 0o0500)
Пример #6
0
def get_image_components(workflow: DockerBuildWorkflow,
                         image_platform: str) -> List[RpmComponent]:
    """
    Re-package the output of the `rpmqa` or `flatpak_create_oci`(for flatpak) plugin into the format
    required for the metadata.
    """
    components: List[RpmComponent]
    if is_flatpak_build(workflow):
        flatpak_result = workflow.data.postbuild_results[
            PLUGIN_FLATPAK_CREATE_OCI][image_platform]
        components = flatpak_result['components']
    else:
        components = workflow.data.postbuild_results[
            PostBuildRPMqaPlugin.key][image_platform]
    return components or []
Пример #7
0
    def run(self) -> Optional[Dict[str, Dict[str, Any]]]:
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return None

        resolve_comp_result: Dict[str, Any] = self.workflow.data.plugins_results[
            PLUGIN_RESOLVE_COMPOSES_KEY]
        flatpak_util = FlatpakUtil(workflow_config=self.workflow.conf,
                                   source_config=self.workflow.source.config,
                                   composes=resolve_comp_result['composes'])
        source = flatpak_util.get_flatpak_source_info()
        if not source:
            raise RuntimeError("flatpak_create_dockerfile must be run before flatpak_create_oci")

        build_flatpak_image = functools.partial(self.build_flatpak_image, source)

        return self.workflow.build_dir.for_each_platform(build_flatpak_image)
    def run(self):
        """
        run the plugin
        """
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        self._load_source_spec()
        source_spec = get_flatpak_source_spec(self.workflow)
        module_info = ModuleSpec.from_str(source_spec)

        # Load additional information from the flatpak section

        flatpak_yaml = self.workflow.source.config.flatpak

        base_image = flatpak_yaml.get('base_image', self.default_base_image)
        name = flatpak_yaml.get('name', module_info.name)
        component = flatpak_yaml.get('component', module_info.name)

        # Create the dockerfile

        df_path = os.path.join(self.workflow.builder.df_dir,
                               DOCKERFILE_FILENAME)
        with open(df_path, 'w') as fp:
            fp.write(
                DOCKERFILE_TEMPLATE.format(
                    name=name,
                    component=component,
                    cleanupscript=FLATPAK_CLEANUPSCRIPT_FILENAME,
                    includepkgs=FLATPAK_INCLUDEPKGS_FILENAME,
                    stream=module_info.stream.replace('-', '_'),
                    base_image=base_image,
                    relative_repos_path=RELATIVE_REPOS_PATH,
                    rpm_qf_args=rpm_qf_args(),
                    yum_repos_dir=YUM_REPOS_DIR))

        self.workflow.builder.set_df_path(df_path)

        # set source registry and organization
        source_registry_docker_uri = get_source_registry(
            self.workflow)['uri'].docker_uri
        organization = get_registries_organization(self.workflow)
        self.workflow.builder.dockerfile_images.set_source_registry(
            source_registry_docker_uri, organization)
    def run(self):
        """
        run the plugin
        """
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        flatpak_util = FlatpakUtil(workflow_config=self.workflow.conf,
                                   source_config=self.workflow.source.config,
                                   composes=None)
        source_spec = flatpak_util.get_flatpak_source_spec()
        module_info = ModuleSpec.from_str(source_spec)

        # Load additional information from the flatpak section

        flatpak_yaml = self.workflow.source.config.flatpak

        base_image = flatpak_yaml.get('base_image', self.default_base_image)
        name = flatpak_yaml.get('name', module_info.name)
        component = flatpak_yaml.get('component', module_info.name)

        # Create the dockerfile

        def _create_dockerfile(build_dir: BuildDir) -> List[Path]:
            content = DOCKERFILE_TEMPLATE.format(
                name=name,
                component=component,
                cleanupscript=FLATPAK_CLEANUPSCRIPT_FILENAME,
                includepkgs=FLATPAK_INCLUDEPKGS_FILENAME,
                stream=module_info.stream.replace('-', '_'),
                base_image=base_image,
                relative_repos_path=RELATIVE_REPOS_PATH,
                rpm_qf_args=rpm_qf_args(),
                yum_repos_dir=YUM_REPOS_DIR)
            build_dir.dockerfile_path.write_text(content, "utf-8")
            return [build_dir.dockerfile_path]

        created_files = self.workflow.build_dir.for_all_platforms_copy(
            _create_dockerfile)

        dockerfile_path = created_files[0]
        self.workflow.reset_dockerfile_images(str(dockerfile_path))
Пример #10
0
    def run(self):
        if is_flatpak_build(self.workflow):
            # We'll extract the filesystem anyways for a Flatpak instead of exporting
            # the docker image directly, so squash just slows things down.
            self.log.info('flatpak build, skipping plugin')
            return

        # This plugin is obsoleted. This line change is just for the test pass.
        if getattr(self.workflow, "skip_layer_squash", False):
            return  # enable build plugins to prevent unnecessary squashes
        if self.save_archive:
            output_path = os.path.join(self.workflow.source.workdir,
                                       EXPORTED_SQUASHED_IMAGE_NAME)
            metadata = {"path": output_path}
        else:
            output_path = None

        # Squash the image and output tarfile
        # If the parameter dont_load is set to True squashed image won't be
        # loaded in to Docker daemon. If it's set to False it will be loaded.
        new_id = Squash(log=self.log,
                        image=self.image,
                        from_layer=self.from_layer,
                        tag=self.tag,
                        output_path=output_path,
                        load_image=not self.dont_load).run()

        if ':' not in new_id:
            # Older versions of the daemon do not include the prefix
            new_id = 'sha256:{}'.format(new_id)

        if not self.dont_load:
            self.workflow.data.image_id = new_id

        if self.save_archive:
            metadata.update(
                get_exported_image_metadata(output_path,
                                            IMAGE_TYPE_DOCKER_ARCHIVE))
            # OSBS2 TBD exported_image_sequence will not work for multiple platform
            self.workflow.data.exported_image_sequence.append(metadata)
Пример #11
0
    def run(self) -> Dict[str, Union[List, Dict[str, List[str]]]]:
        is_source_build = PLUGIN_FETCH_SOURCES_KEY in self.workflow.data.prebuild_results

        if not is_source_build and not is_flatpak_build(self.workflow):
            self.log.info('not a flatpak or source build, skipping plugin')
            return {'pushed_images': [],
                    'repositories': self.get_repositories()}

        pushed_images = []
        wf_data = self.workflow.data

        tag_conf = wf_data.tag_conf

        images = []
        if is_source_build:
            source_image = self.source_get_unique_image()
            plugin_results = wf_data.buildstep_result[PLUGIN_SOURCE_CONTAINER_KEY]
            image = plugin_results['image_metadata']
            tag_conf.add_unique_image(source_image)
            images.append((image, source_image))
        else:
            for image_platform in get_platforms(self.workflow.data):
                plugin_results = wf_data.postbuild_results[PLUGIN_FLATPAK_CREATE_OCI]
                image = plugin_results[image_platform]['metadata']
                registry_image = tag_conf.get_unique_images_with_platform(image_platform)[0]
                images.append((image, registry_image))

        insecure = self.registry.get('insecure', False)

        docker_push_secret = self.registry.get('secret', None)
        self.log.info("Registry %s secret %s", self.registry['uri'], docker_push_secret)

        for image, registry_image in images:
            max_retries = DOCKER_PUSH_MAX_RETRIES

            for retry in range(max_retries + 1):
                self.push_with_skopeo(image, registry_image, insecure, docker_push_secret)

                if is_source_build:
                    manifests_dict = get_all_manifests(registry_image, self.registry['uri'],
                                                       insecure,
                                                       docker_push_secret, versions=('v2',))
                    try:
                        koji_source_manifest_response = manifests_dict['v2']
                    except KeyError as exc:
                        raise RuntimeError(
                            f'Unable to fetch v2 schema 2 digest for {registry_image.to_str()}'
                        ) from exc

                    wf_data.koji_source_manifest = koji_source_manifest_response.json()

                digests = get_manifest_digests(registry_image, self.registry['uri'],
                                               insecure, docker_push_secret)

                if not (digests.v2 or digests.oci) and (retry < max_retries):
                    sleep_time = DOCKER_PUSH_BACKOFF_FACTOR * (2 ** retry)
                    self.log.info("Retrying push because V2 schema 2 or "
                                  "OCI manifest not found in %is", sleep_time)

                    time.sleep(sleep_time)
                else:
                    break

            pushed_images.append(registry_image)

        self.log.info("All images were tagged and pushed")

        return {'pushed_images': pushed_images,
                'repositories': self.get_repositories()}
    def run(self):
        if not is_flatpak_build(self.workflow):
            self.log.info('not flatpak build, skipping plugin')
            return

        source = get_flatpak_source_info(self.workflow)
        if source is None:
            raise RuntimeError(
                "flatpak_create_dockerfile must be run before flatpak_create_oci"
            )

        self.builder = FlatpakBuilder(source,
                                      self.workflow.source.workdir,
                                      'var/tmp/flatpak-build',
                                      parse_manifest=parse_rpm_output,
                                      flatpak_metadata=self.flatpak_metadata)

        df_labels = df_parser(self.workflow.builder.df_path,
                              workflow=self.workflow).labels
        self.builder.add_labels(df_labels)

        tarred_filesystem, manifest = self._export_filesystem()
        self.log.info('filesystem tarfile written to %s', tarred_filesystem)
        self.log.info('manifest written to %s', manifest)

        image_components = self.builder.get_components(manifest)
        self.workflow.image_components = image_components

        ref_name, outfile, tarred_outfile = self.builder.build_container(
            tarred_filesystem)

        self.log.info('Marking filesystem image "%s" for removal',
                      self.workflow.builder.image_id)
        defer_removal(self.workflow, self.workflow.builder.image_id)

        image_id = self._get_oci_image_id(outfile)
        self.log.info('New OCI image ID is %s', image_id)
        self.workflow.builder.image_id = image_id

        labels = Labels(df_labels)
        _, image_name = labels.get_name_and_value(Labels.LABEL_TYPE_NAME)
        _, image_version = labels.get_name_and_value(Labels.LABEL_TYPE_VERSION)
        _, image_release = labels.get_name_and_value(Labels.LABEL_TYPE_RELEASE)

        name = '{}-{}'.format(self.key, image_name)
        tag = '{}-{}'.format(image_version, image_release)
        # The OCI id is tracked by the builder. The image will be removed in the exit phase
        # No need to mark it for removal after pushing to the local storage
        self._copy_oci_to_local_storage(outfile, name, tag)

        metadata = get_exported_image_metadata(outfile, IMAGE_TYPE_OCI)
        metadata['ref_name'] = ref_name
        self.workflow.exported_image_sequence.append(metadata)

        self.log.info('OCI image is available as %s', outfile)

        metadata = get_exported_image_metadata(tarred_outfile,
                                               IMAGE_TYPE_OCI_TAR)
        metadata['ref_name'] = ref_name
        self.workflow.exported_image_sequence.append(metadata)

        self.log.info('OCI tarfile is available as %s', tarred_outfile)