def test_dict_of_config_values(self, container_registry_login_mock):
        registries = {
            'registry.redhat.io':
            ConfigValue({
                'username': '******',
                'password': '******'
            }),
            'registry.internal.example.xyz':
            ConfigValue({
                'username': '******',
                'password': '******'
            })
        }

        container_registries_login(registries)

        calls = [
            call(container_registry_uri='registry.redhat.io',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None),
            call(container_registry_uri='registry.internal.example.xyz',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None)
        ]
        container_registry_login_mock.assert_has_calls(calls)
Exemple #2
0
    def test_given_command_short_name_exists(self,
                                             container_registry_login_mock):
        registries = {
            'registry.redhat.io': {
                'username': '******',
                'password': '******'
            },
            'registry.internal.example.xyz': {
                'username': '******',
                'password': '******'
            }
        }

        container_registries_login(registries=registries,
                                   container_command_short_name='fake-podman')

        calls = [
            call(container_registry_uri='registry.redhat.io',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None,
                 container_command_short_name='fake-podman'),
            call(container_registry_uri='registry.internal.example.xyz',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None,
                 container_command_short_name='fake-podman')
        ]
        container_registry_login_mock.assert_has_calls(calls)
    def test_list_of_dicts_with_containers_config_auth_file(
            self, container_registry_login_mock):
        registries = {
            'registry.redhat.io': {
                'username': '******',
                'password': '******',
                'tls-verify': False
            },
            'registry.internal.example.xyz': {
                'username': '******',
                'password': '******',
                'tls-verify': True
            }
        }

        container_registries_login(registries, '/tmp/mock/auth.json')

        calls = [
            call(container_registry_uri='registry.redhat.io',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file='/tmp/mock/auth.json'),
            call(container_registry_uri='registry.internal.example.xyz',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file='/tmp/mock/auth.json')
        ]
        container_registry_login_mock.assert_has_calls(calls)
Exemple #4
0
    def test_list_of_dicts_with_tls_verify_value(
            self, container_registry_login_mock):
        registries = [{
            'uri': 'registry.redhat.io',
            'username': '******',
            'password': '******',
            'tls-verify': False
        }, {
            'uri': 'registry.internal.example.xyz',
            'username': '******',
            'password': '******',
            'tls-verify': True
        }]

        container_registries_login(registries)

        calls = [
            call(container_registry_uri='registry.redhat.io',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=False,
                 containers_config_auth_file=None,
                 container_command_short_name=None),
            call(container_registry_uri='registry.internal.example.xyz',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None,
                 container_command_short_name=None)
        ]
        container_registry_login_mock.assert_has_calls(calls)
Exemple #5
0
    def test_dict_of_dicts_with_uri_keys(self, container_registry_login_mock):
        registries = {
            'redhat': {
                'uri': 'registry.redhat.io',
                'username': '******',
                'password': '******'
            },
            'internal': {
                'uri': 'registry.internal.example.xyz',
                'username': '******',
                'password': '******'
            }
        }

        container_registries_login(registries)

        calls = [
            call(container_registry_uri='registry.redhat.io',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None,
                 container_command_short_name=None),
            call(container_registry_uri='registry.internal.example.xyz',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=True,
                 containers_config_auth_file=None,
                 container_command_short_name=None)
        ]
        container_registry_login_mock.assert_has_calls(calls)
    def test_list_of_dicts(self, container_registry_login_mock):
        registries = [{
            'uri': 'registry.redhat.io',
            'username': '******',
            'password': '******'
        }, {
            'uri': 'registry.internal.example.xyz',
            'username': '******',
            'password': '******'
        }]

        container_registries_login(registries,
                                   containers_config_tls_verify=False)

        calls = [
            call(container_registry_uri='registry.redhat.io',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=False,
                 containers_config_auth_file=None),
            call(container_registry_uri='registry.internal.example.xyz',
                 container_registry_username='******',
                 container_registry_password='******',
                 container_registry_tls_verify=False,
                 containers_config_auth_file=None)
        ]
        container_registry_login_mock.assert_has_calls(calls)
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        image_version = self.get_value('container-image-version').lower()
        application_name = self.get_value('application-name')
        service_name = self.get_value('service-name')
        organization = self.get_value('organization')
        image_tar_file = self.get_value('image-tar-file')
        destination_url = self.get_value('destination-url')

        image_registry_uri = destination_url
        image_registry_organization = organization
        image_repository = f"{application_name}-{service_name}"
        image_tag = f"{image_registry_uri}/{image_registry_organization}" \
                    f"/{image_repository}:{image_version}"

        try:
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value('containers-config-auth-file')
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_auth_file=containers_config_auth_file
            )

            # push image
            sh.skopeo.copy( # pylint: disable=no-member
                f"--src-tls-verify={str(self.get_value('src-tls-verify'))}",
                f"--dest-tls-verify={str(self.get_value('dest-tls-verify'))}",
                f"--authfile={containers_config_auth_file}",
                f'docker-archive:{image_tar_file}',
                f'docker://{image_tag}',
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err'
            )
        except sh.ErrorReturnCode as error:
            step_result.success = False
            step_result.message = f'Error pushing container image ({image_tar_file}) ' \
                f' to tag ({image_tag}) using skopeo: {error}'

        step_result.add_artifact(name='container-image-registry-uri', value=image_registry_uri)
        step_result.add_artifact(
            name='container-image-registry-organization',
            value=image_registry_organization
        )
        step_result.add_artifact(name='container-image-repository', value=image_repository)
        step_result.add_artifact(name='container-image-name', value=image_repository)
        step_result.add_artifact(name='container-image-version', value=image_version)
        step_result.add_artifact(name='container-image-tag', value=image_tag)

        return step_result
    def test_list_of_dicts_missing_username(self):
        registries = [{'uri': 'registry.redhat.io', 'password': '******'}]

        with self.assertRaisesRegex(
                AssertionError, r"Configuration for container registry "
                r"must specify a 'username': {'uri': 'registry.redhat.io', 'password': '******'}"
        ):
            container_registries_login(registries)
    def test_dict_of_dicts_missing_password(self):
        registries = {'registry.redhat.io': {'username': '******'}}

        with self.assertRaisesRegex(
                AssertionError,
                r"Configuration for container registry \(registry.redhat.io\) "
                r"must specify a 'password': {'username': '******'}"
        ):
            container_registries_login(registries)
    def test_registries_none(self, container_registry_login):
        registries = None

        container_registries_login(registries)

        container_registry_login.assert_not_called()
Exemple #11
0
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        # get the pgp private key to sign the image with
        signer_pgp_private_key = self.get_value([
            'signer-pgp-private-key', 'container-image-signer-pgp-private-key'
        ])

        # get the uri to the image to sign
        container_image_address = self._get_deploy_time_container_image_address(
        )

        image_signatures_directory = self.create_working_dir_sub_dir(
            sub_dir_relative_path='image-signature')
        try:
            # import the PGP key and get the finger print
            signer_pgp_private_key_fingerprint = import_pgp_key(
                pgp_private_key=signer_pgp_private_key)
            step_result.add_artifact(
                name='container-image-signature-signer-private-key-fingerprint',
                value=signer_pgp_private_key_fingerprint)

            # login to any provider container registries
            # NOTE 1: can not use auth file, even though we want to, because podman image sign
            #         does not accept authfile.
            #         https://github.com/containers/podman/issues/10866
            # NOTE 2: have to force login to use podman because even though logging in with
            #         any of the tools should work, in testing the podman sign only worked
            #         from within the python virtual environment if the login happened with podman.
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_tls_verify=util.strtobool(
                    self.get_value('src-tls-verify')),
                container_command_short_name='podman')

            # sign the image
            signature_file_path = PodmanSign.__sign_image(
                pgp_private_key_fingerprint=signer_pgp_private_key_fingerprint,
                image_signatures_directory=image_signatures_directory,
                container_image_address=container_image_address)
            step_result.add_artifact(
                name='container-image-signed-address',
                value=container_image_address,
            )
            step_result.add_artifact(
                name='container-image-signature-file-path',
                value=signature_file_path,
            )
            signature_name = os.path.relpath(signature_file_path,
                                             image_signatures_directory)
            step_result.add_artifact(name='container-image-signature-name',
                                     value=signature_name)

            # upload the image signature
            container_image_signature_destination_url = self.get_value(
                'container-image-signature-destination-url')
            if container_image_signature_destination_url:
                container_image_signature_destination_uri = \
                    f"{container_image_signature_destination_url}/{signature_name}"
                step_result.add_artifact(
                    name='container-image-signature-uri',
                    description='URI of the uploaded container image signature',
                    value=container_image_signature_destination_uri)

                upload_result = upload_file(
                    file_path=signature_file_path,
                    destination_uri=container_image_signature_destination_uri,
                    username=self.get_value(
                        'container-image-signature-destination-username'),
                    password=self.get_value(
                        'container-image-signature-destination-password'))
                step_result.add_artifact(
                    name='container-image-signature-upload-results',
                    description='Results of uploading the container image signature' \
                                ' to the given destination.',
                    value=upload_result
                )
        except (RuntimeError, StepRunnerException) as error:
            step_result.success = False
            step_result.message = str(error)

        return step_result
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        # get config
        image_spec_file = self.get_value('imagespecfile')
        tls_verify = self.get_value('tls-verify')
        if isinstance(tls_verify, str):
            tls_verify = bool(util.strtobool(tls_verify))

        # create local build tag
        image_registry_organization = self.get_value('organization')
        build_full_tag, build_short_tag, image_registry_uri, image_repository, image_version = \
            determine_container_image_build_tag_info(
                image_version=self.get_value('container-image-version'),
                organization=image_registry_organization,
                application_name=self.get_value('application-name'),
                service_name=self.get_value('service-name')
            )

        try:
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value('containers-config-auth-file')
            if not containers_config_auth_file:
                containers_config_auth_file = os.path.join(
                    self.work_dir_path,
                    'container-auth.json'
                )
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_auth_file=containers_config_auth_file,
                containers_config_tls_verify=tls_verify
            )

            # perform build
            sh.buildah.bud(  # pylint: disable=no-member
                '--format=' + self.get_value('format'),
                '--tls-verify=' + str(tls_verify).lower(),
                '--layers', '-f', image_spec_file,
                '-t', build_full_tag,
                '--authfile', containers_config_auth_file,
                self.get_value('context'),
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err'
            )

        except sh.ErrorReturnCode as error:  # pylint: disable=undefined-variable
            step_result.success = False
            step_result.message = 'Issue invoking buildah bud with given image ' \
                f'specification file ({image_spec_file}): {error}'
            return step_result

        # add artifacts
        step_result.add_artifact(
            name='container-image-registry-uri',
            value=image_registry_uri,
            description='Registry URI poriton of the container image tag' \
                ' of the built container image.'
        )
        step_result.add_artifact(
            name='container-image-registry-organization',
            value=image_registry_organization,
            description='Organization portion of the container image tag' \
                ' of the built container image.'
        )
        step_result.add_artifact(
            name='container-image-repository',
            value=image_repository,
            description='Repository portion of the container image tag' \
                ' of the built container image.'
        )
        step_result.add_artifact(
            name='container-image-name',
            value=image_repository,
            description='Another way to reference the' \
                ' repository portion of the container image tag of the built container image.'
        )
        step_result.add_artifact(
            name='container-image-version',
            value=image_version,
            description='Version portion of the container image tag of the built container image.'
        )
        step_result.add_artifact(
            name='container-image-tag',
            value=build_full_tag,
            description='Full container image tag of the built container,' \
                ' including the registry URI.'
        )
        step_result.add_artifact(
            name='container-image-short-tag',
            value=build_short_tag,
            description='Short container image tag of the built container image,' \
                ' excluding the registry URI.'
        )

        return step_result
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        context = self.get_value('context')
        image_spec_file = self.get_value('imagespecfile')
        image_spec_file_location = context + '/' + image_spec_file
        application_name = self.get_value('application-name')
        service_name = self.get_value('service-name')
        tls_verify = self.get_value('tls-verify')

        if not os.path.exists(image_spec_file_location):
            step_result.success = False
            step_result.message = 'Image specification file does not exist in location: ' \
                f'{image_spec_file_location}'
            return step_result

        image_tag_version = self.get_value('container-image-version')
        if image_tag_version is None:
            image_tag_version = 'latest'
            print('No image tag version found in metadata. Using latest')

        destination = "localhost/{application_name}/{service_name}".format(
            application_name=application_name, service_name=service_name)
        tag = "{destination}:{version}".format(destination=destination,
                                               version=image_tag_version)

        try:
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value(
                'containers-config-auth-file')
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_auth_file=containers_config_auth_file,
                containers_config_tls_verify=tls_verify)

            # perform build
            #
            # NOTE: using --storage-driver=vfs so that container does not need escalated privileges
            #       vfs is less efficient then fuse (which would require host mounts),
            #       but such is the price we pay for security.
            sh.buildah.bud(  # pylint: disable=no-member
                '--storage-driver=vfs',
                '--format=' + self.get_value('format'),
                '--tls-verify=' + str(tls_verify).lower(),
                '--layers',
                '-f',
                image_spec_file,
                '-t',
                tag,
                '--authfile',
                containers_config_auth_file,
                context,
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err')

            step_result.add_artifact(name='container-image-version', value=tag)
        except sh.ErrorReturnCode as error:  # pylint: disable=undefined-variable
            step_result.success = False
            step_result.message = 'Issue invoking buildah bud with given image ' \
                f'specification file ({image_spec_file}): {error}'
            return step_result

        image_tar_file = f'image-{application_name}-{service_name}-{image_tag_version}.tar'
        image_tar_path = os.path.join(self.work_dir_path, image_tar_file)
        try:
            # Check to see if the tar docker-archive file already exists
            #   this needs to be run as buildah does not support overwritting
            #   existing files.
            #
            # NOTE: using --storage-driver=vfs so that container does not need escalated privileges
            #       vfs is less efficient then fuse (which would require host mounts),
            #       but such is the price we pay for security.
            if os.path.exists(image_tar_path):
                os.remove(image_tar_path)
            sh.buildah.push(  # pylint: disable=no-member
                '--storage-driver=vfs',
                tag,
                "docker-archive:" + image_tar_path,
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err')

            step_result.add_artifact(name='image-tar-file',
                                     value=image_tar_path)
        except sh.ErrorReturnCode as error:  # pylint: disable=undefined-variable
            step_result.success = False
            step_result.message = f'Issue invoking buildah push to tar file ' \
                f'({image_tar_path}): {error}'
            return step_result

        return step_result
Exemple #14
0
    def _run_step(self):  # pylint: disable=too-many-locals
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        # get src image config
        pull_registry_type = self.get_value([
            'container-image-pull-registry-type',
            'container-image-registry-type'
        ])
        container_image_pull_address = self.get_value(
            ['container-image-pull-address', 'container-image-build-address'])
        source_tls_verify = self.get_value(
            ['source-tls-verify', 'src-tls-verify'])
        if isinstance(source_tls_verify, str):
            source_tls_verify = bool(util.strtobool(source_tls_verify))

        # create destination config
        push_registry_type = self.get_value([
            'container-image-push-registry-type',
            'container-image-registry-type'
        ])
        container_image_push_registry = self.get_value(
            ['container-image-push-registry', 'destination-url'])
        container_image_push_repository = self.get_value(
            ['container-image-push-repository', 'container-image-repository'])
        container_image_push_tag = self.get_value([
            'container-image-push-tag', 'container-image-tag',
            'container-image-version'
        ])
        dest_tls_verify = self.get_value('dest-tls-verify')
        if isinstance(dest_tls_verify, str):
            dest_tls_verify = bool(util.strtobool(dest_tls_verify))
        container_image_push_short_address = \
            f"{container_image_push_repository}:{container_image_push_tag}"
        container_image_push_address_by_tag = f"{container_image_push_registry}" \
           f"/{container_image_push_short_address}"

        try:
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value(
                'containers-config-auth-file')
            if not containers_config_auth_file:
                containers_config_auth_file = os.path.join(
                    self.work_dir_path, 'container-auth.json')
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_auth_file=containers_config_auth_file,
                containers_config_tls_verify=dest_tls_verify)

            # push image
            sh.skopeo.copy(  # pylint: disable=no-member
                f"--src-tls-verify={str(source_tls_verify).lower()}",
                f"--dest-tls-verify={str(dest_tls_verify).lower()}",
                f"--authfile={containers_config_auth_file}",
                f'{pull_registry_type}{container_image_pull_address}',
                f'{push_registry_type}{container_image_push_address_by_tag}',
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err')
        except sh.ErrorReturnCode as error:
            step_result.success = False
            step_result.message = f'Error pushing container image ({container_image_pull_address}) ' \
                f' to tag ({container_image_push_address_by_tag}) using skopeo: {error}'

        # add address part artifacts
        step_result.add_artifact(
            name='container-image-push-registry',
            value=container_image_push_registry,
            description=
            'Container image registry container image was pushed to.')
        step_result.add_artifact(
            name='container-image-push-repository',
            value=container_image_push_repository,
            description=
            'Container image repository container image was pushed to.')
        step_result.add_artifact(
            name='container-image-push-tag',
            value=container_image_push_tag,
            description='Container image tag container image was pushed to.')

        # add address by tag artifacts
        step_result.add_artifact(
            name='container-image-address-by-tag',
            value=container_image_push_address_by_tag,
            description='Pushed container image address by tag.')
        step_result.add_artifact(
            name='container-image-short-address-by-tag',
            value=container_image_push_short_address,
            description=
            'Pushed container image short address (no registry) by tag.')

        # add address by digest artifacts
        if step_result.success:
            try:
                print("Get pushed container image digest")
                container_image_digest = get_container_image_digest(
                    container_image_address=container_image_push_address_by_tag,
                    containers_config_auth_file=containers_config_auth_file)

                container_image_short_address_by_digest = \
                    f"{container_image_push_repository}@{container_image_digest}"
                container_image_address_by_digest = \
                    f"{container_image_push_registry}/{container_image_short_address_by_digest}"

                step_result.add_artifact(
                    name='container-image-push-digest',
                    value=container_image_digest,
                    description=
                    'Container image digest container image was pushed to.')
                step_result.add_artifact(
                    name='container-image-address-by-digest',
                    value=container_image_address_by_digest,
                    description='Pushed container image address by digest.')
                step_result.add_artifact(
                    name='container-image-short-address-by-digest',
                    value=container_image_short_address_by_digest,
                    description=
                    'Pushed container image short address (no registry) by digest.'
                )
            except RuntimeError as error:
                step_result.success = False
                step_result.message = f"Error getting pushed container image digest: {error}"

        return step_result
Exemple #15
0
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        # get config
        image_pull_tag = self.get_value(
            ['container-image-pull-tag', 'container-image-tag'])
        pull_repository_type = self.get_value([
            'container-image-pull-repository-type',
            'container-image-repository-type'
        ])
        push_repository_type = self.get_value([
            'container-image-push-repository-type',
            'container-image-repository-type'
        ])
        dest_tls_verify = self.get_value('dest-tls-verify')
        if isinstance(dest_tls_verify, str):
            dest_tls_verify = bool(util.strtobool(dest_tls_verify))
        source_tls_verify = self.get_value(
            ['source-tls-verify', 'src-tls-verify'])
        if isinstance(source_tls_verify, str):
            source_tls_verify = bool(util.strtobool(source_tls_verify))

        # create push tag
        image_version = self.get_value('container-image-version')
        if image_version is None:
            image_version = 'latest'
            print('No image tag version found in metadata. Using latest')
        image_version = image_version.lower()
        image_registry_uri = self.get_value('destination-url')
        image_registry_organization = self.get_value('organization')
        image_repository = f"{self.get_value('application-name')}-{self.get_value('service-name')}"
        image_push_short_tag = f"{image_registry_organization}/{image_repository}:{image_version}"
        image_push_tag = f"{image_registry_uri}/{image_push_short_tag}"

        try:
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value(
                'containers-config-auth-file')
            if not containers_config_auth_file:
                containers_config_auth_file = os.path.join(
                    self.work_dir_path, 'container-auth.json')
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_auth_file=containers_config_auth_file,
                containers_config_tls_verify=dest_tls_verify)

            # push image
            sh.skopeo.copy(  # pylint: disable=no-member
                f"--src-tls-verify={str(source_tls_verify).lower()}",
                f"--dest-tls-verify={str(dest_tls_verify).lower()}",
                f"--authfile={containers_config_auth_file}",
                f'{pull_repository_type}{image_pull_tag}',
                f'{push_repository_type}{image_push_tag}',
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err')
        except sh.ErrorReturnCode as error:
            step_result.success = False
            step_result.message = f'Error pushing container image ({image_pull_tag}) ' \
                f' to tag ({image_push_tag}) using skopeo: {error}'

        # add artifacts
        step_result.add_artifact(
            name='container-image-registry-uri',
            value=image_registry_uri,
            description='Registry URI poriton of the container image tag' \
                ' of the pushed container image.'
        )
        step_result.add_artifact(
            name='container-image-registry-organization',
            value=image_registry_organization,
            description='Organization portion of the container image tag' \
                ' of the pushed container image.'
        )
        step_result.add_artifact(
            name='container-image-repository',
            value=image_repository,
            description='Repository portion of the container image tag' \
                ' of the pushed container image.'
        )
        step_result.add_artifact(
            name='container-image-name',
            value=image_repository,
            description='Another way to reference the' \
                ' repository portion of the container image tag of the pushed container image.'
        )
        step_result.add_artifact(
            name='container-image-version',
            value=image_version,
            description=
            'Version portion of the container image tag of the pushed container image.'
        )
        step_result.add_artifact(
            name='container-image-tag',
            value=image_push_tag,
            description='Full container image tag of the pushed container,' \
                ' including the registry URI.'
        )
        step_result.add_artifact(
            name='container-image-short-tag',
            value=image_push_short_tag,
            description='Short container image tag of the pushed container image,' \
                ' excluding the registry URI.'
        )

        return step_result
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        # get values
        builder_image = self.get_value('s2i-builder-image')

        # determine tls flag
        tls_verify = self.get_value('tls-verify')
        if isinstance(tls_verify, str):
            tls_verify = bool(util.strtobool(tls_verify))
        if tls_verify:
            s2i_tls_flags = ['--tlsverify']
        else:
            s2i_tls_flags = []

        # determine the generated imagespec file
        s2i_working_dir = self.create_working_dir_sub_dir('s2i-context')
        imagespecfile = self.write_working_file(
            os.path.join(s2i_working_dir, 'Containerfile.s2i-gen'))

        # determine image scripts url flags
        # use user provided url if given,
        # else try and inspect from builder image
        s2i_image_scripts_url = self.get_value('s2i-image-scripts-url')
        if not s2i_image_scripts_url:
            print(
                'Attempt to inspect builder image for label for image scripts url'
            )

            # attempt to auth with container image registries
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value(
                'containers-config-auth-file')
            if not containers_config_auth_file:
                containers_config_auth_file = os.path.join(
                    self.work_dir_path, 'container-auth.json')
            try:
                container_registries_login(
                    registries=self.get_value('container-registries'),
                    containers_config_auth_file=containers_config_auth_file,
                    containers_config_tls_verify=tls_verify)
            except RuntimeError as error:
                step_result.message += "WARNING: error authenticating with" \
                    " container image registries to be able to pull s2i builder image" \
                    f" to inspect for image scripts url: {error}\n"

            # if not given, attempt to get from builder image labels
            try:
                container_image_details = inspect_container_image(
                    container_image_address=builder_image,
                    containers_config_auth_file=containers_config_auth_file)

                s2i_image_scripts_url = container_image_details['OCIv1']['config']['Labels']\
                    [SourceToImage.CONTAINER_LABEL_SCRIPTS_URL]
            except RuntimeError as error:
                step_result.message += "WARNING: failed to inspect s2i builder image" \
                    f" ({builder_image}) to dynamically determine image scripts url." \
                    f" S2I default will be used: {error}\n"
            except KeyError as error:
                step_result.message += "WARNING: failed to find s2i scripts url label" \
                    f" ({SourceToImage.CONTAINER_LABEL_SCRIPTS_URL}) on s2i builder image" \
                    f" ({builder_image}) to dynamically determine image scripts url." \
                    f" S2I default will be used: Could not find key ({error}).\n"

        # if determined image scripts url set the flag
        # else s2i will use its default (image:///usr/libexec/s2i)
        if s2i_image_scripts_url:
            s2i_image_scripts_url_flags = [
                '--image-scripts-url', s2i_image_scripts_url
            ]
        else:
            s2i_image_scripts_url_flags = []

        try:
            # perform build
            print(
                'Use s2i to generate imagespecfile and accompanying resources')
            sh.s2i.build(  # pylint: disable=no-member
                self.get_value('context'),
                builder_image,
                '--loglevel',
                self.get_value('s2i-loglevel'),
                *s2i_tls_flags,
                '--as-dockerfile',
                imagespecfile,
                *s2i_image_scripts_url_flags,
                *self.get_value('s2i-additional-arguments'),
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err')
        except sh.ErrorReturnCode as error:  # pylint: disable=undefined-variable
            step_result.success = False
            step_result.message += f'Issue invoking s2i build: {error}'

        # add artifacts
        step_result.add_artifact(
            name='imagespecfile',
            value=imagespecfile,
            description=
            'File defining the container image to build generated by s2i')
        step_result.add_artifact(
            name='context',
            value=s2i_working_dir,
            description=
            'Context to use when building the imagespecfile generated by S2I.')

        return step_result
    def _run_step(self):
        """Runs the step implemented by this StepImplementer.

        Returns
        -------
        StepResult
            Object containing the dictionary results of this step.
        """
        step_result = StepResult.from_step_implementer(self)

        # get config
        image_spec_file = self.get_value('imagespecfile')
        tls_verify = self.get_value('tls-verify')
        if isinstance(tls_verify, str):
            tls_verify = bool(util.strtobool(tls_verify))

        # create local build tag
        container_image_build_address, container_image_build_short_address, \
        contaimer_image_registry, container_image_repository, container_image_tag = \
            determine_container_image_address_info(
                contaimer_image_registry='localhost',
                container_image_tag=self.get_value([
                    'container-image-tag',
                    'container-image-version'
                ]),
                organization=self.get_value('organization'),
                application_name=self.get_value('application-name'),
                service_name=self.get_value('service-name')
            )

        try:
            # login to any provider container registries
            # NOTE: important to specify the auth file because depending on the context this is
            #       being run in python process may not have permissions to default location
            containers_config_auth_file = self.get_value('containers-config-auth-file')
            if not containers_config_auth_file:
                containers_config_auth_file = os.path.join(
                    self.work_dir_path,
                    'container-auth.json'
                )
            container_registries_login(
                registries=self.get_value('container-registries'),
                containers_config_auth_file=containers_config_auth_file,
                containers_config_tls_verify=tls_verify
            )

            # perform build
            sh.buildah.bud(  # pylint: disable=no-member
                '--format=' + self.get_value('format'),
                '--tls-verify=' + str(tls_verify).lower(),
                '--layers', '-f', image_spec_file,
                '-t', container_image_build_address,
                '--authfile', containers_config_auth_file,
                self.get_value('context'),
                _out=sys.stdout,
                _err=sys.stderr,
                _tee='err'
            )

        except sh.ErrorReturnCode as error:  # pylint: disable=undefined-variable
            step_result.success = False
            step_result.message = 'Issue invoking buildah bud with given image ' \
                f'specification file ({image_spec_file}): {error}'

        # get image digest
        container_image_digest = None
        if step_result.success:
            try:
                print("Get container image digest")
                container_image_digest = get_container_image_digest(
                    container_image_address=container_image_build_address
                )
            except RuntimeError as error:
                step_result.success = False
                step_result.message = f"Error getting built container image digest: {error}"

        # add artifacts
        add_container_build_step_result_artifacts(
            step_result=step_result,
            contaimer_image_registry=contaimer_image_registry,
            container_image_repository=container_image_repository,
            container_image_tag=container_image_tag,
            container_image_digest=container_image_digest,
            container_image_build_address=container_image_build_address,
            container_image_build_short_address=container_image_build_short_address
        )

        return step_result