def __init__(self, tasker, workflow, nvr=None, destdir="/root/buildinfo/", use_final_dockerfile=False): """ constructor :param tasker: DockerTasker instance :param workflow: DockerBuildWorkflow instance :param nvr: name-version-release, will be appended to Dockerfile-. If not specified, try to get it from Name, Version, Release labels. :param destdir: directory in the image to put Dockerfile-N-V-R into :param use_final_dockerfile: bool, when set to True, uses final version of processed dockerfile, when set to False, uses Dockerfile from time when this plugin was executed """ # call parent constructor super(AddDockerfilePlugin, self).__init__(tasker, workflow) self.use_final_dockerfile = use_final_dockerfile if nvr is None: labels = DockerfileParser(self.workflow.builder.df_path).labels name = get_preferred_label(labels, 'name') version = get_preferred_label(labels, 'version') release = get_preferred_label(labels, 'release') if name is None or version is None or release is None: raise ValueError("You have to specify either nvr arg or Name/Version/Release labels.") nvr = "{0}-{1}-{2}".format(name, version, release) nvr = nvr.replace("/", "-") self.df_name = '{0}-{1}'.format(DOCKERFILE_FILENAME, nvr) self.df_dir = destdir self.df_path = os.path.join(self.df_dir, self.df_name) # we are not using final dockerfile, so let's copy current snapshot if not self.use_final_dockerfile: local_df_path = os.path.join(self.workflow.builder.df_dir, self.df_name) shutil.copy2(self.workflow.builder.df_path, local_df_path)
def get_build(self, metadata): start_time = int(atomic_reactor_start_time) labels = df_parser(self.workflow.builder.df_path, workflow=self.workflow).labels component = get_preferred_label(labels, 'com.redhat.component') version = get_preferred_label(labels, 'version') release = get_preferred_label(labels, 'release') source = self.workflow.source if not isinstance(source, GitSource): raise RuntimeError('git source required') extra = {'image': {}} koji_task_id = metadata.get('labels', {}).get('koji-task-id') if koji_task_id is not None: self.log.info("build configuration created by Koji Task ID %s", koji_task_id) try: extra['container_koji_task_id'] = int(koji_task_id) except ValueError: self.log.error("invalid task ID %r", koji_task_id, exc_info=1) fs_result = self.workflow.prebuild_results.get(AddFilesystemPlugin.key) if fs_result is not None: try: fs_task_id = fs_result['filesystem-koji-task-id'] except KeyError: self.log.error( "%s: expected filesystem-koji-task-id in result", AddFilesystemPlugin.key) else: try: task_id = int(fs_task_id) except ValueError: self.log.error("invalid task ID %r", fs_task_id, exc_info=1) else: extra['filesystem_koji_task_id'] = task_id build = { 'name': component, 'version': version, 'release': release, 'source': "{0}#{1}".format(source.uri, source.commit_id), 'start_time': start_time, 'end_time': int(time.time()), 'extra': extra, } if self.metadata_only: build['metadata_only'] = True return build
def get_build(self, metadata): start_time = int(atomic_reactor_start_time) labels = df_parser(self.workflow.builder.df_path, workflow=self.workflow).labels component = get_preferred_label(labels, 'com.redhat.component') version = get_preferred_label(labels, 'version') release = get_preferred_label(labels, 'release') source = self.workflow.source if not isinstance(source, GitSource): raise RuntimeError('git source required') extra = {'image': {}} koji_task_id = metadata.get('labels', {}).get('koji-task-id') if koji_task_id is not None: self.log.info("build configuration created by Koji Task ID %s", koji_task_id) try: extra['container_koji_task_id'] = int(koji_task_id) except ValueError: self.log.error("invalid task ID %r", koji_task_id, exc_info=1) fs_result = self.workflow.prebuild_results.get(AddFilesystemPlugin.key) if fs_result is not None: try: fs_task_id = fs_result['filesystem-koji-task-id'] except KeyError: self.log.error("%s: expected filesystem-koji-task-id in result", AddFilesystemPlugin.key) else: try: task_id = int(fs_task_id) except ValueError: self.log.error("invalid task ID %r", fs_task_id, exc_info=1) else: extra['filesystem_koji_task_id'] = task_id build = { 'name': component, 'version': version, 'release': release, 'source': "{0}#{1}".format(source.uri, source.commit_id), 'start_time': start_time, 'end_time': int(time.time()), 'extra': extra, } if self.metadata_only: build['metadata_only'] = True return build
def get_label(label_name): try: return get_preferred_label( self.workflow.built_image_inspect[INSPECT_CONFIG] ['Labels'], label_name) except KeyError: raise RuntimeError("Missing label '%s'." % label_name)
def get_label(label_name): try: return get_preferred_label( self.workflow.built_image_inspect[INSPECT_CONFIG]['Labels'], label_name) except KeyError: raise RuntimeError("Missing label '%s'." % label_name)
def run(self): """ run the plugin """ parser = df_parser(self.workflow.builder.df_path, workflow=self.workflow) dockerfile_labels = parser.labels release = get_preferred_label(dockerfile_labels, 'release') if release is not None and not self.append: self.log.debug("release set explicitly so not incrementing") return component_label = get_preferred_label_key(dockerfile_labels, 'com.redhat.component') try: component = dockerfile_labels[component_label] except KeyError: raise RuntimeError("missing label: {}".format(component_label)) version_label = get_preferred_label_key(dockerfile_labels, 'version') try: version = dockerfile_labels[version_label] except KeyError: raise RuntimeError('missing label: {}'.format(version_label)) if self.append: next_release = self.get_next_release_append( component, version, release) else: next_release = self.get_next_release_standard(component, version) # Always set preferred release label - other will be set if old-style # label is present release_labels = get_all_label_keys('release') preferred_release_label = get_preferred_label_key( dockerfile_labels, 'release') old_style_label = get_all_label_keys('com.redhat.component')[1] release_labels_to_be_set = [preferred_release_label] if old_style_label in dockerfile_labels.keys(): release_labels_to_be_set = release_labels # No release labels are set so set them for release_label in release_labels_to_be_set: self.log.info("setting %s=%s", release_label, next_release) # Write the label back to the file (this is a property setter) dockerfile_labels[release_label] = next_release
def run(self): """ run the plugin """ parser = df_parser(self.workflow.builder.df_path, workflow=self.workflow) dockerfile_labels = parser.labels release = get_preferred_label(dockerfile_labels, 'release') if release is not None and not self.append: self.log.debug("release set explicitly so not incrementing") return component_label = get_preferred_label_key(dockerfile_labels, 'com.redhat.component') try: component = dockerfile_labels[component_label] except KeyError: raise RuntimeError("missing label: {}".format(component_label)) version_label = get_preferred_label_key(dockerfile_labels, 'version') try: version = dockerfile_labels[version_label] except KeyError: raise RuntimeError('missing label: {}'.format(version_label)) if self.append: next_release = self.get_next_release_append(component, version, release) else: next_release = self.get_next_release_standard(component, version) # Always set preferred release label - other will be set if old-style # label is present release_labels = get_all_label_keys('release') preferred_release_label = get_preferred_label_key(dockerfile_labels, 'release') old_style_label = get_all_label_keys('com.redhat.component')[1] release_labels_to_be_set = [preferred_release_label] if old_style_label in dockerfile_labels.keys(): release_labels_to_be_set = release_labels # No release labels are set so set them for release_label in release_labels_to_be_set: self.log.info("setting %s=%s", release_label, next_release) # Write the label back to the file (this is a property setter) dockerfile_labels[release_label] = next_release
def get_build(self, metadata): start_time = int(atomic_reactor_start_time) labels = df_parser(self.workflow.builder.df_path, workflow=self.workflow).labels component = get_preferred_label(labels, 'com.redhat.component') version = get_preferred_label(labels, 'version') release = get_preferred_label(labels, 'release') source = self.workflow.source if not isinstance(source, GitSource): raise RuntimeError('git source required') extra = {'image': {'autorebuild': is_rebuild(self.workflow)}} koji_task_id = metadata.get('labels', {}).get('koji-task-id') if koji_task_id is not None: self.log.info("build configuration created by Koji Task ID %s", koji_task_id) try: extra['container_koji_task_id'] = int(koji_task_id) except ValueError: self.log.error("invalid task ID %r", koji_task_id, exc_info=1) fs_result = self.workflow.prebuild_results.get(AddFilesystemPlugin.key) if fs_result is not None: try: fs_task_id = fs_result['filesystem-koji-task-id'] except KeyError: self.log.error("%s: expected filesystem-koji-task-id in result", AddFilesystemPlugin.key) else: try: task_id = int(fs_task_id) except ValueError: self.log.error("invalid task ID %r", fs_task_id, exc_info=1) else: extra['filesystem_koji_task_id'] = task_id # Append media_types from pulp pull pulp_pull_results = self.workflow.postbuild_results.get(PLUGIN_PULP_PULL_KEY) if pulp_pull_results: extra['image']['media_types'] = sorted(list(set(pulp_pull_results))) # Append parent_build_id from koji parent parent_results = self.workflow.prebuild_results.get(PLUGIN_KOJI_PARENT_KEY) or {} parent_id = parent_results.get('parent-image-koji-build', {}).get('id') if parent_id is not None: try: parent_id = int(parent_id) except ValueError: self.log.exception("invalid koji parent id %r", parent_id) else: extra['image']['parent_build_id'] = parent_id # Append isolated build flag try: isolated = str(metadata['labels']['isolated']).lower() == 'true' except (IndexError, AttributeError, KeyError): isolated = False self.log.info("build is isolated: %r", isolated) extra['image']['isolated'] = isolated help_result = self.workflow.prebuild_results.get(AddHelpPlugin.key) if isinstance(help_result, dict) and 'help_file' in help_result and 'status' in help_result: if help_result['status'] == AddHelpPlugin.NO_HELP_FILE_FOUND: extra['image']['help'] = None elif help_result['status'] == AddHelpPlugin.HELP_GENERATED: extra['image']['help'] = help_result['help_file'] else: self.log.error("Unknown result from add_help plugin: %s", help_result) flatpak_source_info = get_flatpak_source_info(self.workflow) if flatpak_source_info is not None: extra['image'].update(flatpak_source_info.koji_metadata()) resolve_comp_result = self.workflow.prebuild_results.get(PLUGIN_RESOLVE_COMPOSES_KEY) if resolve_comp_result: 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'], } build = { 'name': component, 'version': version, 'release': release, 'source': "{0}#{1}".format(source.uri, source.commit_id), 'start_time': start_time, 'end_time': int(time.time()), 'extra': extra, } if self.metadata_only: build['metadata_only'] = True return build
def get_build(self, metadata, worker_metadatas): start_time = int(atomic_reactor_start_time) labels = df_parser(self.workflow.builder.df_path, workflow=self.workflow).labels component = get_preferred_label(labels, 'com.redhat.component') version = get_preferred_label(labels, 'version') release = get_preferred_label(labels, 'release') source = self.workflow.source if not isinstance(source, GitSource): raise RuntimeError('git source required') extra = {'image': {'autorebuild': is_rebuild(self.workflow)}} koji_task_id = metadata.get('labels', {}).get('koji-task-id') if koji_task_id is not None: self.log.info("build configuration created by Koji Task ID %s", koji_task_id) try: extra['container_koji_task_id'] = int(koji_task_id) except ValueError: self.log.error("invalid task ID %r", koji_task_id, exc_info=1) try: isolated = str(metadata['labels']['isolated']).lower() == 'true' except (IndexError, AttributeError, KeyError): isolated = False self.log.info("build is isolated: %r", isolated) extra['image']['isolated'] = isolated fs_result = self.workflow.prebuild_results.get(AddFilesystemPlugin.key) if fs_result is not None: try: fs_task_id = fs_result['filesystem-koji-task-id'] except KeyError: self.log.error("%s: expected filesystem-koji-task-id in result", AddFilesystemPlugin.key) else: try: task_id = int(fs_task_id) except ValueError: self.log.error("invalid task ID %r", fs_task_id, exc_info=1) else: extra['filesystem_koji_task_id'] = task_id parent_id = self.get_parent_image_koji_build_id() if parent_id is not None: try: parent_id = int(parent_id) except ValueError: self.log.exception("invalid koji parent id %r", parent_id) else: extra.setdefault('image', {}) extra['image']['parent_build_id'] = parent_id flatpak_source_info = get_flatpak_source_info(self.workflow) if flatpak_source_info is not None: extra['image'].update(flatpak_source_info.koji_metadata()) if koji_task_id: koji_task_owner = get_koji_task_owner(self.session, koji_task_id, default=None)['name'] else: koji_task_owner = None extra['submitter'] = self.session.getLoggedInUser()['name'] resolve_comp_result = self.workflow.prebuild_results.get(PLUGIN_RESOLVE_COMPOSES_KEY) if resolve_comp_result: 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'], } self.set_help(extra, worker_metadatas) self.set_media_types(extra, worker_metadatas) self.remove_unavailable_manifest_digests(worker_metadatas) self.set_group_manifest_info(extra, worker_metadatas) build = { 'name': component, 'version': version, 'release': release, 'source': "{0}#{1}".format(source.uri, source.commit_id), 'start_time': start_time, 'end_time': int(time.time()), 'extra': extra, 'owner': koji_task_owner, } return build
def get_release(self): labels = df_parser(self.workflow.builder.df_path, workflow=self.workflow).labels return get_preferred_label(labels, 'release')
def get_build(self, metadata, worker_metadatas): start_time = int(atomic_reactor_start_time) labels = df_parser(self.workflow.builder.df_path, workflow=self.workflow).labels component = get_preferred_label(labels, 'com.redhat.component') version = get_preferred_label(labels, 'version') release = get_preferred_label(labels, 'release') source = self.workflow.source if not isinstance(source, GitSource): raise RuntimeError('git source required') extra = {'image': {'autorebuild': is_rebuild(self.workflow)}} koji_task_id = metadata.get('labels', {}).get('koji-task-id') if koji_task_id is not None: self.log.info("build configuration created by Koji Task ID %s", koji_task_id) try: extra['container_koji_task_id'] = int(koji_task_id) except ValueError: self.log.error("invalid task ID %r", koji_task_id, exc_info=1) try: isolated = str(metadata['labels']['isolated']).lower() == 'true' except (IndexError, AttributeError, KeyError): isolated = False self.log.info("build is isolated: %r", isolated) extra['image']['isolated'] = isolated fs_result = self.workflow.prebuild_results.get(AddFilesystemPlugin.key) if fs_result is not None: try: fs_task_id = fs_result['filesystem-koji-task-id'] except KeyError: self.log.error( "%s: expected filesystem-koji-task-id in result", AddFilesystemPlugin.key) else: try: task_id = int(fs_task_id) except ValueError: self.log.error("invalid task ID %r", fs_task_id, exc_info=1) else: extra['filesystem_koji_task_id'] = task_id parent_id = self.get_parent_image_koji_build_id() if parent_id is not None: try: parent_id = int(parent_id) except ValueError: self.log.exception("invalid koji parent id %r", parent_id) else: extra.setdefault('image', {}) extra['image']['parent_build_id'] = parent_id flatpak_source_info = get_flatpak_source_info(self.workflow) if flatpak_source_info is not None: extra['image'].update(flatpak_source_info.koji_metadata()) if koji_task_id: koji_task_owner = get_koji_task_owner(self.session, koji_task_id, default=None)['name'] else: koji_task_owner = None extra['submitter'] = self.session.getLoggedInUser()['name'] resolve_comp_result = self.workflow.prebuild_results.get( PLUGIN_RESOLVE_COMPOSES_KEY) if resolve_comp_result: 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'], } self.set_help(extra, worker_metadatas) self.set_media_types(extra, worker_metadatas) self.remove_unavailable_manifest_digests(worker_metadatas) self.set_group_manifest_info(extra, worker_metadatas) build = { 'name': component, 'version': version, 'release': release, 'source': "{0}#{1}".format(source.uri, source.commit_id), 'start_time': start_time, 'end_time': int(time.time()), 'extra': extra, 'owner': koji_task_owner, } return build
def run(self): """ run the plugin The plugin returns None if exception occurred, self.NO_HELP_FILE_FOUND if no help found or self.HELP_GENERATED if help man page was generated """ result = {'help_file': self.help_file, 'status': None} help_path = os.path.join(self.workflow.builder.df_dir, self.help_file) if not os.path.exists(help_path): self.log.info("File %s not found", help_path) result['status'] = self.NO_HELP_FILE_FOUND return result dockerfile = df_parser(self.workflow.builder.df_path, workflow=self.workflow) labels = dockerfile.labels with open(help_path, 'r+') as help_file: lines = help_file.readlines() if not lines[0].startswith("% "): lines.insert( 0, "%% %s (1) Container Image Pages\n" % (get_preferred_label(labels, "name") or "")) lines.insert( 1, "%% %s\n" % (get_preferred_label(labels, "maintainer") or "")) lines.insert( 2, "%% %s\n" % dt.fromtimestamp(atomic_reactor_start_time).strftime( format="%B %-d, %Y")) help_file.seek(0) help_file.truncate() help_file.writelines(lines) self.log.info( "added metadata to %s for generating nicer manpages", help_path) man_path = os.path.join(self.workflow.builder.df_dir, self.man_filename) go_md2man_cmd = [ 'go-md2man', '-in={}'.format(help_path), '-out={}'.format(man_path) ] try: check_output(go_md2man_cmd, stderr=STDOUT) except OSError as e: if e.errno == errno.ENOENT: raise RuntimeError( "Help file is available, but go-md2man is not present in a buildroot" ) raise except CalledProcessError as e: raise RuntimeError( "Error running %s: %r, exit code: %s, output: '%s'" % (e.cmd, e, e.returncode, e.output)) if not os.path.exists(man_path): raise RuntimeError( "go-md2man run complete, but man file is not found") # Include the help file in the docker file lines = dockerfile.lines content = 'ADD {0} /{0}'.format(self.man_filename) # put it before last instruction lines.insert(-1, content + '\n') dockerfile.lines = lines self.log.info("added %s", man_path) result['status'] = self.HELP_GENERATED return result
def run(self): """ run the plugin The plugin returns None if exception occurred, self.NO_HELP_FILE_FOUND if no help found or self.HELP_GENERATED if help man page was generated """ result = { 'help_file': self.help_file, 'status': None } help_path = os.path.join(self.workflow.builder.df_dir, self.help_file) if not os.path.exists(help_path): self.log.info("File %s not found", help_path) result['status'] = self.NO_HELP_FILE_FOUND return result dockerfile = df_parser(self.workflow.builder.df_path, workflow=self.workflow) labels = dockerfile.labels with open(help_path, 'r+') as help_file: lines = help_file.readlines() if not lines[0].startswith("% "): lines.insert(0, "%% %s (1) Container Image Pages\n" % (get_preferred_label(labels, "name") or "")) lines.insert(1, "%% %s\n" % (get_preferred_label(labels, "maintainer") or "")) lines.insert(2, "%% %s\n" % dt.fromtimestamp(atomic_reactor_start_time) .strftime(format="%B %-d, %Y")) help_file.seek(0) help_file.truncate() help_file.writelines(lines) self.log.info("added metadata to %s for generating nicer manpages", help_path) man_path = os.path.join(self.workflow.builder.df_dir, self.man_filename) go_md2man_cmd = ['go-md2man', '-in={}'.format(help_path), '-out={}'.format(man_path)] try: check_output(go_md2man_cmd, stderr=STDOUT) except OSError as e: if e.errno == errno.ENOENT: raise RuntimeError( "Help file is available, but go-md2man is not present in a buildroot") raise except CalledProcessError as e: raise RuntimeError("Error running %s: %r, exit code: %s, output: '%s'" % ( e.cmd, e, e.returncode, e.output)) if not os.path.exists(man_path): raise RuntimeError("go-md2man run complete, but man file is not found") # Include the help file in the docker file lines = dockerfile.lines content = 'ADD {0} /{0}'.format(self.man_filename) # put it before last instruction lines.insert(-1, content + '\n') dockerfile.lines = lines self.log.info("added %s", man_path) result['status'] = self.HELP_GENERATED return result