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)
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)
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
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)
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 []
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))
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)
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)