diff --git a/setup.py b/setup.py index c63cce6d..b29c7c7d 100644 --- a/setup.py +++ b/setup.py @@ -142,6 +142,7 @@ def get_dependency_links(): "iib-add-bundles = pubtools._quay.iib_operations:iib_add_entrypoint", "iib-remove-operators = pubtools._quay.iib_operations:iib_remove_entrypoint", "iib-build-from-scratch = pubtools._quay.iib_operations:iib_from_scratch_entrypoint", + "iib-add-deprecations = pubtools._quay.iib_operations:iib_add_deprecations_entrypoint", ], }, include_package_data=True, diff --git a/src/pubtools/_quay/iib_operations.py b/src/pubtools/_quay/iib_operations.py index fbd05915..f40f7fb7 100644 --- a/src/pubtools/_quay/iib_operations.py +++ b/src/pubtools/_quay/iib_operations.py @@ -213,62 +213,28 @@ def _sign_index_image( return current_signatures -def task_iib_add_bundles( - bundles: List[str], - archs: List[str], - index_image: str, - deprecation_list: List[str], +def _sign_and_push( + build_details: Any, + tag: str, signing_keys: List[str], - hub: Any, task_id: str, target_settings: Dict[str, Any], - target_name: str, ) -> None: - """ - Perform all the necessary actions for the 'PushAddIIBBundles' entrypoint. - - Args: - bundles ([str]): - Bundles to add to the index image. - archs ([str]): - Architectures to build the index image for. - index_image (str): - Index image to add the bundles to. - deprecation_list ([str]): - Bundles to deprecate in the index image. - signing_keys ([str]): - Signing keys to be used. - hub (HubProxy): - Instance of XMLRPC pub-hub proxy. - task_id (str): - ID of the pub task. - target_settings (dict): - Dictionary containing settings necessary for performing the operation. - target_name (str): - Name of the target. - """ - image_schema_tag = "{host}/{namespace}/{repo}:{tag}" - verify_target_settings(target_settings) - quay_client = QuayClient( - target_settings["dest_quay_user"], target_settings["dest_quay_password"], "quay.io" - ) - - # Build new index image in IIB - build_details = OperatorPusher.iib_add_bundles( - bundles=bundles, - archs=archs, - index_image=index_image, - deprecation_list=deprecation_list, - build_tags=["{0}-{1}".format(index_image.split(":")[1], task_id)], - target_settings=target_settings, - ) - if not build_details: - sys.exit(1) - _, tag = build_details.index_image.split(":", 1) index_stamp = timestamp() quay_operator_namespace = target_settings.get( "quay_operator_namespace", target_settings["quay_namespace"] ) + # Copy target settings and override username and password for quay_operator_namespace + index_image_ts = target_settings.copy() + index_image_ts["dest_quay_user"] = index_image_ts.get( + "index_image_quay_user", index_image_ts["dest_quay_user"] + ) + index_image_ts["dest_quay_password"] = index_image_ts.get( + "index_image_quay_password", index_image_ts["dest_quay_password"] + ) + quay_client = QuayClient( + index_image_ts["dest_quay_user"], index_image_ts["dest_quay_password"], "quay.io" + ) item_processor = item_processor_for_internal_data( quay_client, target_settings["quay_host"].rstrip("/"), @@ -278,7 +244,7 @@ def task_iib_add_bundles( ) item_processor.extractor.full_extract = True - # Add bundles task doesn't work with pushitem so we create VirtualPushItem to enable + # IIB task doesn't work with pushitem so we create VirtualPushItem to enable # existing code for fetching needed data. vitem = VirtualPushItem( metadata={"tags": {target_settings["quay_operator_repository"]: [tag]}}, @@ -300,6 +266,7 @@ def task_iib_add_bundles( target_settings, pre_push=True, ) + image_schema_tag = "{host}/{namespace}/{repo}:{tag}" dest_image = image_schema_tag.format( host=target_settings.get("quay_host", "quay.io").rstrip("/"), namespace=quay_operator_namespace, @@ -314,14 +281,6 @@ def task_iib_add_bundles( ) # Push image to Quay - # Copy target settings and override username and password for quay_operator_namespace - index_image_ts = target_settings.copy() - index_image_ts["dest_quay_user"] = index_image_ts.get( - "index_image_quay_user", index_image_ts["dest_quay_user"] - ) - index_image_ts["dest_quay_password"] = index_image_ts.get( - "index_image_quay_password", index_image_ts["dest_quay_password"] - ) ContainerImagePusher.run_tag_images( build_details.index_image, [dest_image], True, index_image_ts ) @@ -339,7 +298,7 @@ def task_iib_add_bundles( ) # after push sign - current_signatures = _sign_index_image( + _sign_index_image( build_details.internal_index_image_copy_resolved, [tag, f"{tag}-{index_stamp}"], signing_keys, @@ -347,19 +306,62 @@ def task_iib_add_bundles( target_settings, pre_push=False, ) - _remove_index_image_signatures(outdated_manifests, current_signatures, target_settings) +def task_iib_add_bundles( + bundles: List[str], + archs: List[str], + index_image: str, + deprecation_list: List[str], + signing_keys: List[str], + task_id: str, + target_settings: Dict[str, Any], +) -> None: + """ + Perform all the necessary actions for the 'PushAddIIBBundles' entrypoint. + + Args: + bundles ([str]): + Bundles to add to the index image. + archs ([str]): + Architectures to build the index image for. + index_image (str): + Index image to add the bundles to. + deprecation_list ([str]): + Bundles to deprecate in the index image. + signing_keys ([str]): + Signing keys to be used. + task_id (str): + ID of the pub task. + target_settings (dict): + Dictionary containing settings necessary for performing the operation. + """ + verify_target_settings(target_settings) + + # Build new index image in IIB + build_details = OperatorPusher.iib_add_bundles( + bundles=bundles, + archs=archs, + index_image=index_image, + deprecation_list=deprecation_list, + build_tags=["{0}-{1}".format(index_image.split(":")[1], task_id)], + target_settings=target_settings, + ) + if not build_details: + sys.exit(1) + _, tag = build_details.index_image.split(":", 1) + + _sign_and_push(build_details, tag, signing_keys, task_id, target_settings) + + def task_iib_remove_operators( operators: List[str], archs: List[str], index_image: str, signing_keys: List[str], - hub: Any, task_id: str, target_settings: Dict[str, Any], - target_name: str, ) -> None: """ Perform all the necessary actions for the 'PushRemoveIIBOperators' entrypoint. @@ -373,16 +375,11 @@ def task_iib_remove_operators( Index image to remove the operators from. signing_keys (str): Signing keys to be used. - hub (HubProxy): - Instance of XMLRPC pub-hub proxy. task_id (str): ID of the pub task. target_settings (dict): Dictionary containing settings necessary for performing the operation. - target_name (str): - Name of the target. """ - image_schema_tag = "{host}/{namespace}/{repo}:{tag}" verify_target_settings(target_settings) # Build new index image in IIB @@ -393,95 +390,11 @@ def task_iib_remove_operators( build_tags=["{0}-{1}".format(index_image.split(":")[1], task_id)], target_settings=target_settings, ) - if not build_details: sys.exit(1) _, tag = build_details.index_image.split(":", 1) - index_stamp = timestamp() - quay_operator_namespace = target_settings.get( - "quay_operator_namespace", target_settings["quay_namespace"] - ) - quay_client = QuayClient( - target_settings["dest_quay_user"], target_settings["dest_quay_password"], "quay.io" - ) - item_processor = item_processor_for_internal_data( - quay_client, - target_settings["quay_host"].rstrip("/"), - target_settings["docker_settings"]["docker_reference_registry"], - target_settings.get("retry_sleep_time", 5), - quay_operator_namespace, - ) - # Remove operators task doesn't work with pushitem so we create VirtualPushItem to enable - # existing code for fetching needed data. - vitem = VirtualPushItem( - metadata={"tags": {target_settings["quay_operator_repository"]: [tag]}}, - repos={target_settings["quay_operator_repository"]: [tag]}, - ) - existing_manifests = item_processor.generate_existing_manifests_metadata(vitem) - outdated_manifests = [] - for ref, _tag, man_arch_dig in existing_manifests: - if not man_arch_dig: - continue - outdated_manifests.append((man_arch_dig.digest, _tag, ref)) - - current_signatures = _sign_index_image( - build_details.internal_index_image_copy_resolved, - [tag, f"{tag}-{index_stamp}"], - signing_keys, - task_id, - target_settings, - pre_push=True, - ) - - dest_image = image_schema_tag.format( - host=target_settings.get("quay_host", "quay.io").rstrip("/"), - namespace=quay_operator_namespace, - repo=get_internal_container_repo_name(target_settings["quay_operator_repository"]), - tag=tag, - ) - - dest_image_stamp = image_schema_tag.format( - host=target_settings.get("quay_host", "quay.io").rstrip("/"), - namespace=quay_operator_namespace, - repo=get_internal_container_repo_name(target_settings["quay_operator_repository"]), - tag="%s-%s" % (tag, index_stamp), - ) - - # Push image to Quay - # Copy target settings and override username and password for quay_operator_namespace - index_image_ts = target_settings.copy() - index_image_ts["dest_quay_user"] = index_image_ts.get( - "index_image_quay_user", index_image_ts["dest_quay_user"] - ) - index_image_ts["dest_quay_password"] = index_image_ts.get( - "index_image_quay_password", index_image_ts["dest_quay_password"] - ) - - ContainerImagePusher.run_tag_images( - build_details.index_image, [dest_image], True, index_image_ts - ) - iib_feed, iib_namespace, iib_intermediate_repo = parse_index_image(build_details) - # Permanent index image with proxy as a host must be used because skopeo cannot handle - # login to two Quay namespaces at the same time - permanent_index_image_proxy = image_schema_tag.format( - host=iib_feed, - namespace=iib_namespace, - repo=iib_intermediate_repo, - tag=build_details.build_tags[0], - ) - ContainerImagePusher.run_tag_images( - permanent_index_image_proxy, [dest_image_stamp], True, index_image_ts - ) - current_signatures = _sign_index_image( - build_details.internal_index_image_copy_resolved, - [tag, f"{tag}-{index_stamp}"], - signing_keys, - task_id, - target_settings, - pre_push=False, - ) - _remove_index_image_signatures(outdated_manifests, current_signatures, target_settings) + _sign_and_push(build_details, tag, signing_keys, task_id, target_settings) def task_iib_build_from_scratch( @@ -489,10 +402,8 @@ def task_iib_build_from_scratch( archs: List[str], index_image_tag: str, signing_keys: List[str], - hub: Any, task_id: str, target_settings: Dict[str, Any], - target_name: str, ) -> None: """ Perform all the necessary actions for the 'PushIIBBuildFromScratch' entrypoint. @@ -506,16 +417,11 @@ def task_iib_build_from_scratch( Tag to be applied to the new index image. signing_keys (str): Signing keys to be used. - hub (HubProxy): - Instance of XMLRPC pub-hub proxy. task_id (str): ID of the pub task. target_settings (dict): Dictionary containing settings necessary for performing the operation. - target_name (str): - Name of the target. """ - image_schema_tag = "{host}/{namespace}/{repo}:{tag}" verify_target_settings(target_settings) # Build new index image in IIB @@ -527,87 +433,50 @@ def task_iib_build_from_scratch( ) if not build_details: sys.exit(1) - index_stamp = timestamp() - quay_operator_namespace = target_settings.get( - "quay_operator_namespace", target_settings["quay_namespace"] - ) - quay_client = QuayClient( - target_settings["dest_quay_user"], target_settings["dest_quay_password"], "quay.io" - ) - item_processor = item_processor_for_internal_data( - quay_client, - target_settings["quay_host"].rstrip("/"), - target_settings["docker_settings"]["docker_reference_registry"], - target_settings.get("retry_sleep_time", 5), - quay_operator_namespace, - ) - # Build from scratch task doesn't work with pushitem so we create VirtualPushItem to enable - # existing code for fetching needed data. - vitem = VirtualPushItem( - metadata={"tags": {target_settings["quay_operator_repository"]: [index_image_tag]}}, - repos={target_settings["quay_operator_repository"]: [index_image_tag]}, - ) - existing_manifests = item_processor.generate_existing_manifests_metadata(vitem) - outdated_manifests = [] - for ref, tag, man_arch_dig in existing_manifests: - if not man_arch_dig: - continue - outdated_manifests.append((man_arch_dig.digest, tag, ref)) - current_signatures = _sign_index_image( - build_details.internal_index_image_copy_resolved, - [index_image_tag, f"{index_image_tag}-{index_stamp}"], - signing_keys, - task_id, - target_settings, - pre_push=True, - ) - dest_image = image_schema_tag.format( - host=target_settings.get("quay_host", "quay.io").rstrip("/"), - namespace=quay_operator_namespace, - repo=get_internal_container_repo_name(target_settings["quay_operator_repository"]), - tag=index_image_tag, - ) - dest_image_stamp = image_schema_tag.format( - host=target_settings.get("quay_host", "quay.io").rstrip("/"), - namespace=quay_operator_namespace, - repo=get_internal_container_repo_name(target_settings["quay_operator_repository"]), - tag="%s-%s" % (index_image_tag, index_stamp), - ) + _sign_and_push(build_details, index_image_tag, signing_keys, task_id, target_settings) - # Push image to Quay - # Copy target settings and override username and password for quay_operator_namespace - index_image_ts = target_settings.copy() - index_image_ts["dest_quay_user"] = index_image_ts.get( - "index_image_quay_user", index_image_ts["dest_quay_user"] - ) - index_image_ts["dest_quay_password"] = index_image_ts.get( - "index_image_quay_password", index_image_ts["dest_quay_password"] - ) - ContainerImagePusher.run_tag_images( - build_details.index_image, [dest_image], True, index_image_ts - ) - iib_feed, iib_namespace, iib_intermediate_repo = parse_index_image(build_details) - # Permanent index image with proxy as a host must be used because skopeo cannot handle - # login to two Quay namespaces at the same time - permanent_index_image_proxy = image_schema_tag.format( - host=iib_feed, - namespace=iib_namespace, - repo=iib_intermediate_repo, - tag=build_details.build_tags[0], - ) - ContainerImagePusher.run_tag_images( - permanent_index_image_proxy, [dest_image_stamp], True, index_image_ts - ) - current_signatures = _sign_index_image( - build_details.internal_index_image_copy_resolved, - [index_image_tag, f"{index_image_tag}-{index_stamp}"], - signing_keys, - task_id, - target_settings, - pre_push=False, + +def task_iib_add_deprecations( + index_image: str, + deprecation_schema: str, + operator_package: str, + signing_keys: List[str], + task_id: str, + target_settings: Dict[str, Any], +) -> None: + """ + Perform all the necessary actions for the 'PushAddIIBDeprecations' entrypoint. + + Args: + index_image (str): + Index image to add the bundles to. + deprecation_schema (str): + JSON formatted deprecation schema. + operator_package (str): + Operator package to add deprecations to. + signing_keys ([str]): + Signing keys to be used. + task_id (str): + ID of the pub task. + target_settings (dict): + Dictionary containing settings necessary for performing the operation. + """ + verify_target_settings(target_settings) + + # Build new index image in IIB + build_details = OperatorPusher.iib_add_deprecations( + index_image=index_image, + deprecation_schema=deprecation_schema, + operator_package=operator_package, + build_tags=["{0}-{1}".format(index_image.split(":")[1], task_id)], + target_settings=target_settings, ) - _remove_index_image_signatures(outdated_manifests, current_signatures, target_settings) + if not build_details: + sys.exit(1) + _, tag = build_details.index_image.split(":", 1) + + _sign_and_push(build_details, tag, signing_keys, task_id, target_settings) def iib_add_entrypoint( @@ -616,10 +485,8 @@ def iib_add_entrypoint( index_image: str, deprecation_list: List[str], signing_keys: List[str], - hub: Any, task_id: str, target_settings: Dict[str, Any], - target_name: str, ) -> None: """Entry point for use in another python code.""" task_iib_add_bundles( @@ -628,10 +495,8 @@ def iib_add_entrypoint( index_image, deprecation_list, signing_keys, - hub, task_id, target_settings, - target_name, ) @@ -640,15 +505,11 @@ def iib_remove_entrypoint( archs: List[str], index_image: str, signing_keys: List[str], - hub: Any, task_id: str, target_settings: Dict[str, Any], - target_name: str, ) -> None: """Entry point for use in another python code.""" - task_iib_remove_operators( - operators, archs, index_image, signing_keys, hub, task_id, target_settings, target_name - ) + task_iib_remove_operators(operators, archs, index_image, signing_keys, task_id, target_settings) def iib_from_scratch_entrypoint( @@ -656,12 +517,29 @@ def iib_from_scratch_entrypoint( archs: List[str], index_image_tag: str, signing_keys: List[str], - hub: Any, task_id: str, target_settings: Dict[str, Any], - target_name: str, ) -> None: """Entry point for use in another python code.""" task_iib_build_from_scratch( - bundles, archs, index_image_tag, signing_keys, hub, task_id, target_settings, target_name + bundles, archs, index_image_tag, signing_keys, task_id, target_settings + ) + + +def iib_add_deprecations_entrypoint( + index_image: str, + deprecation_schema: str, + operator_package: str, + signing_keys: List[str], + task_id: str, + target_settings: Dict[str, Any], +) -> None: + """Entry point for use in another python code.""" + task_iib_add_deprecations( + index_image, + deprecation_schema, + operator_package, + signing_keys, + task_id, + target_settings, ) diff --git a/src/pubtools/_quay/operator_pusher.py b/src/pubtools/_quay/operator_pusher.py index a74481ba..2afd3816 100644 --- a/src/pubtools/_quay/operator_pusher.py +++ b/src/pubtools/_quay/operator_pusher.py @@ -388,6 +388,58 @@ def iib_remove_operators( env_vars, ) + @classmethod + @tx.instrument_func() + def iib_add_deprecations( + cls, + index_image: str, + deprecation_schema: str, + operator_package: str, + build_tags: Optional[List[str]] = None, + target_settings: Dict[str, Any] = {}, + ) -> Any: + """ + Construct and execute pubtools-iib command to add deprecations of an operator package. + + Args: + index_image (str): + Index image to add the bundles to. + deprecation_schema (str): + JSON formatted deprecation schema. + operator_package (str): + Operator package to add deprecations to. + build_tags ([str]): + Extra tags that the new index image should be tagged with. + target_settings (dict): + Settings used for setting the value of pubtools-iib parameters. + + Returns (dict): + Build details provided by IIB. + """ + LOG.info( + "Requesting IIB to add deprecations to package '{0}' in index image '{1}'".format( + operator_package, index_image + ) + ) + args, env_vars = cls.pubtools_iib_get_common_args(target_settings) + + if index_image: + args += ["--index-image", index_image] + if deprecation_schema: + args += ["--deprecation-schema", deprecation_schema] + if operator_package: + args += ["--operator-package", operator_package] + if build_tags: + for build_tag in build_tags: + args += ["--build-tag", build_tag] + + return run_entrypoint( + ("pubtools-iib", "console_scripts", "pubtools-iib-add-deprecations"), + "pubtools-iib-add-deprecations", + args, + env_vars, + ) + def get_existing_index_images(self, quay_client: QuayClient) -> List[Tuple[str, str, str]]: """ Return existing index images for non-fbc push items. diff --git a/tests/test_iib_operations.py b/tests/test_iib_operations.py index 1603076c..6e7f8d31 100644 --- a/tests/test_iib_operations.py +++ b/tests/test_iib_operations.py @@ -304,17 +304,14 @@ def test_task_iib_add_bundles( "docker-content-digest": "manifest_list_digest", }, ) - mock_hub = mock.MagicMock() iib_operations.task_iib_add_bundles( ["bundle1", "bundle2"], ["arch1", "arch2"], "some-registry.com/redhat-namespace/new-index-image:8", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -436,17 +433,14 @@ def test_task_iib_add_bundles_missing_manifest_list( json=None, headers={"Content-Type": "application/vnd.docker.distribution.manifest.list.v2+json"}, ) - mock_hub = mock.MagicMock() iib_operations.task_iib_add_bundles( ["bundle1", "bundle2"], ["arch1", "arch2"], "some-registry.com/redhat-namespace/new-index-image:8", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -565,7 +559,6 @@ def test_task_iib_add_bundles_operator_ns( signer_wrapper_entry_point, signer_wrapper_run_entry_point, ) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -625,10 +618,8 @@ def test_task_iib_add_bundles_operator_ns( "some-registry.com/redhat-namespace/new-index-image:8", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -892,7 +883,6 @@ def test_task_iib_remove_operators( signer_wrapper_entry_point, signer_wrapper_run_entry_point, ) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: mock_manifest_list_requests( @@ -917,10 +907,8 @@ def test_task_iib_remove_operators( ["arch1", "arch2"], "some-registry.com/redhat-namespace/new-index-image:5", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -979,7 +967,6 @@ def test_task_iib_remove_operators_missing_manifest_list( signer_wrapper_entry_point, signer_wrapper_run_entry_point, ) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: m.get( @@ -992,10 +979,8 @@ def test_task_iib_remove_operators_missing_manifest_list( ["arch1", "arch2"], "some-registry.com/iib-namespace/new-index-image:8", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -1056,7 +1041,6 @@ def test_task_iib_remove_operators_operator_ns( signer_wrapper_entry_point, signer_wrapper_run_entry_point, ) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -1077,10 +1061,8 @@ def test_task_iib_remove_operators_operator_ns( ["arch1", "arch2"], "some-registry.com/redhat-namespace/new-index-image:5", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -1139,7 +1121,6 @@ def test_task_iib_build_from_scratch( signer_wrapper_entry_point, signer_wrapper_run_entry_point, ) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -1162,10 +1143,8 @@ def test_task_iib_build_from_scratch( ["arch1", "arch2"], "8", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -1421,7 +1400,6 @@ def test_task_iib_build_from_scratch_missing_manifest_list( signer_wrapper_entry_point, signer_wrapper_run_entry_point, ) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: m.get( "https://quay.io/v2/some-namespace/operators----index-image/manifests/8", @@ -1433,10 +1411,8 @@ def test_task_iib_build_from_scratch_missing_manifest_list( ["arch1", "arch2"], "8", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -1583,7 +1559,6 @@ def test_task_iib_build_from_scratch_operator_ns( signer_wrapper_run_entry_point, ) # mock_get_index_image_signatures) - mock_hub = mock.MagicMock() with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -1604,10 +1579,8 @@ def test_task_iib_build_from_scratch_operator_ns( ["arch1", "arch2"], "8", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_verify_target_settings.assert_called_once_with(target_settings) @@ -1838,19 +1811,100 @@ def test_task_iib_build_from_scratch_operator_ns( ) +@mock.patch("pubtools._quay.iib_operations.ContainerImagePusher.run_tag_images") +@mock.patch("pubtools._quay.iib_operations.OperatorPusher.iib_add_deprecations") +@mock.patch("pubtools._quay.iib_operations.verify_target_settings") +def test_task_iib_add_deprecations( + mock_verify_target_settings, + mock_iib_add_deprecations, + mock_run_tag_images, + mock_timestamp, + signer_wrapper_entry_point, + signer_wrapper_run_entry_point, + msg_signer_wrapper_save_signatures_file, + signer_wrapper_remove_signatures, + fake_quay_client_get_operator_quay_client, + target_settings, + fake_cert_key_paths, + v2s1_manifest, + src_manifest_list, + fixture_run_in_parallel, +): + fake_setup( + fake_quay_client_get_operator_quay_client, + mock_iib_add_deprecations, + signer_wrapper_entry_point, + signer_wrapper_run_entry_point, + ) + + with requests_mock.Mocker() as m: + mock_manifest_list_requests( + m, + "https://quay.io/v2/some-namespace/operators----index-image/manifests/8", + src_manifest_list, + v2s1_manifest, + ) + # manifests for removal of old signatures + m.get( + "https://quay.io" + "/v2/some-namespace/operators----index-image/manifests/manifest_list_digest", + json=src_manifest_list, + headers={ + "Content-Type": "application/vnd.docker.distribution.manifest.list.v2+json", + "docker-content-digest": "manifest_list_digest", + }, + ) + + iib_operations.task_iib_add_deprecations( + "some-registry.com/redhat-namespace/new-index-image:5", + '{"a": "b"}', + "operator1", + ["some-key"], + "1", + target_settings, + ) + + mock_verify_target_settings.assert_called_once_with(target_settings) + mock_iib_add_deprecations.assert_called_once_with( + index_image="some-registry.com/redhat-namespace/new-index-image:5", + deprecation_schema='{"a": "b"}', + operator_package="operator1", + build_tags=["5-1"], + target_settings=target_settings, + ) + assert mock_run_tag_images.call_count == 2 + assert mock_run_tag_images.call_args_list[0] == mock.call( + "some-registry.com/iib-namespace/new-index-image:8", + [ + "quay.io/some-namespace/operators----index-image:8", + ], + True, + target_settings, + ) + assert mock_run_tag_images.call_args_list[1] == mock.call( + "some-registry.com/iib-namespace/iib:8-1", + [ + "quay.io/some-namespace/operators----index-image:8-timestamp", + ], + True, + target_settings, + ) + signer_wrapper_remove_signatures.mock_calls == [ + mock.call([1]), + mock.call([("operators/index-image", "sha256:5555555555")]), + ] + + @mock.patch("pubtools._quay.iib_operations.task_iib_add_bundles") def test_iib_add_entrypoint(mock_add_bundles, target_settings): - mock_hub = mock.MagicMock() iib_operations.iib_add_entrypoint( ["bundle1", "bundle2"], ["arch1", "arch2"], "some-registry.com/index-image:5", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_add_bundles.assert_called_once_with( @@ -1859,25 +1913,20 @@ def test_iib_add_entrypoint(mock_add_bundles, target_settings): "some-registry.com/index-image:5", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) @mock.patch("pubtools._quay.iib_operations.task_iib_remove_operators") def test_iib_remove_entrypoint(mock_remove_operators, target_settings): - mock_hub = mock.MagicMock() iib_operations.iib_remove_entrypoint( ["operator1", "operator2"], ["arch1", "arch2"], "some-registry.com/index-image:5", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_remove_operators.assert_called_once_with( @@ -1885,25 +1934,20 @@ def test_iib_remove_entrypoint(mock_remove_operators, target_settings): ["arch1", "arch2"], "some-registry.com/index-image:5", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) @mock.patch("pubtools._quay.iib_operations.task_iib_build_from_scratch") def test_iib_from_scratch_entrypoint(mock_build_from_scratch, target_settings): - mock_hub = mock.MagicMock() iib_operations.iib_from_scratch_entrypoint( ["bundle1", "bundle2"], ["arch1", "arch2"], "12", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) mock_build_from_scratch.assert_called_once_with( @@ -1911,17 +1955,35 @@ def test_iib_from_scratch_entrypoint(mock_build_from_scratch, target_settings): ["arch1", "arch2"], "12", ["some-key"], - mock_hub, "1", target_settings, - "some-target", + ) + + +@mock.patch("pubtools._quay.iib_operations.task_iib_add_deprecations") +def test_iib_add_deprecations(mock_add_deprecations, target_settings): + iib_operations.iib_add_deprecations_entrypoint( + "some-registry.com/redhat-namespace/new-index-image:5", + '{"a": "b"}', + "operator1", + ["some-key"], + "1", + target_settings, + ) + + mock_add_deprecations.assert_called_once_with( + "some-registry.com/redhat-namespace/new-index-image:5", + '{"a": "b"}', + "operator1", + ["some-key"], + "1", + target_settings, ) @mock.patch("pubtools._quay.iib_operations.OperatorPusher.iib_add_bundles") def test_task_iib_add_bundles_fail(mock_iib_add_bundles, target_settings): mock_iib_add_bundles.return_value = False - mock_hub = mock.MagicMock() with pytest.raises(SystemExit): iib_operations.task_iib_add_bundles( ["bundle1", "bundle2"], @@ -1929,42 +1991,48 @@ def test_task_iib_add_bundles_fail(mock_iib_add_bundles, target_settings): "some-registry.com/redhat-namespace/new-index-image:5", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) @mock.patch("pubtools._quay.iib_operations.OperatorPusher.iib_remove_operators") def test_task_iib_remove_operators_fail(mock_iib_remove_operators, target_settings): mock_iib_remove_operators.return_value = False - mock_hub = mock.MagicMock() with pytest.raises(SystemExit): iib_operations.task_iib_remove_operators( ["operator1", "operator2"], ["arch1", "arch2"], "some-registry.com/redhat-namespace/new-index-image:5", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) @mock.patch("pubtools._quay.iib_operations.OperatorPusher.iib_add_bundles") def test_task_iib_build_from_scratch_fail(mock_iib_add_bundles, target_settings): mock_iib_add_bundles.return_value = False - mock_hub = mock.MagicMock() with pytest.raises(SystemExit): iib_operations.task_iib_build_from_scratch( ["bundle1", "bundle2"], ["arch1", "arch2"], "12", ["some-key"], - mock_hub, "1", target_settings, - "some-target", + ) + + +@mock.patch("pubtools._quay.iib_operations.OperatorPusher.iib_add_deprecations") +def test_task_iib_add_deprecations_fail(mock_iib_add_deprecations, target_settings): + mock_iib_add_deprecations.return_value = False + with pytest.raises(SystemExit): + iib_operations.task_iib_add_deprecations( + "some-registry.com/redhat-namespace/new-index-image:5", + '{"a": "b"}', + "operator1", + ["some-key"], + "1", + target_settings, ) diff --git a/tests/test_integration.py b/tests/test_integration.py index e273977d..7186ead8 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1384,8 +1384,6 @@ def test_task_iib_add_bundles( "signing_key": "sig-key", } - mock_hub = mock.MagicMock() - with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -1420,10 +1418,8 @@ def test_task_iib_add_bundles( "some-registry.com/redhat-namespace/new-index-image:5", ["bundle3", "bundle4"], ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) signer_wrapper_entry_point.assert_has_calls( [ @@ -1524,8 +1520,6 @@ def test_task_iib_remove_operators( "signing_key": "sig-key", } - mock_hub = mock.MagicMock() - with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -1558,10 +1552,8 @@ def test_task_iib_remove_operators( ["arch1", "arch2"], "some-registry.com/redhat-namespace/new-index-image:5", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) signer_wrapper_entry_point.assert_has_calls( @@ -1659,8 +1651,6 @@ def test_task_iib_build_from_scratch( "signing_key": "sig-key", } - mock_hub = mock.MagicMock() - with requests_mock.Mocker() as m: mock_manifest_list_requests( m, @@ -1689,10 +1679,8 @@ def test_task_iib_build_from_scratch( ["arch1", "arch2"], "8", ["some-key"], - mock_hub, "1", target_settings, - "some-target", ) diff --git a/tests/test_operator_pusher.py b/tests/test_operator_pusher.py index 5780846a..487fa223 100644 --- a/tests/test_operator_pusher.py +++ b/tests/test_operator_pusher.py @@ -303,6 +303,45 @@ def test_iib_remove_operators(mock_run_entrypoint, target_settings, operator_pus ) +@mock.patch("pubtools._quay.operator_pusher.run_entrypoint") +def test_iib_add_deprecations(mock_run_entrypoint, target_settings, operator_push_item_ok): + mock_run_entrypoint.return_value = "some-data" + pusher = operator_pusher.OperatorPusher([operator_push_item_ok], "3", target_settings) + result = pusher.iib_add_deprecations( + "registry.com/rh-osbs/iib-pub-pending:v4.5", + '{"a": "b"}', + "operator1", + ["tag1", "tag2"], + pusher.target_settings, + ) + + assert result == "some-data" + mock_run_entrypoint.assert_called_once_with( + ("pubtools-iib", "console_scripts", "pubtools-iib-add-deprecations"), + "pubtools-iib-add-deprecations", + [ + "--iib-server", + "iib-server.com", + "--iib-krb-principal", + "some-principal@REDHAT.COM", + "--overwrite-from-index", + "--iib-krb-ktfile", + "/etc/pub/some.keytab", + "--index-image", + "registry.com/rh-osbs/iib-pub-pending:v4.5", + "--deprecation-schema", + '{"a": "b"}', + "--operator-package", + "operator1", + "--build-tag", + "tag1", + "--build-tag", + "tag2", + ], + {"OVERWRITE_FROM_INDEX_TOKEN": "some-user:some-pass"}, + ) + + @mock.patch("pubtools._quay.operator_pusher.ContainerImagePusher.run_tag_images") @mock.patch("pubtools._quay.operator_pusher.OperatorPusher.iib_add_bundles") @mock.patch("pubtools._quay.operator_pusher.run_entrypoint")