diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b81749d..511f767 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -32,8 +32,7 @@ jobs: python-version: ${{ matrix.python-version }} - id: dependencies - run: | - pip install -e .[dev] + run: make install-py - id: validate-style run: make validate-style diff --git a/Makefile b/Makefile index 6c199c5..a314291 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,13 @@ release = 1 PYTHON ?= python3 PYTHON_DIRS = aiven tests +all: install-py validate-style lint test + +install-py: + $(PYTHON) -m pip install -e .[dev] + test: pytest + lint: ruff flake8 mypy reformat: diff --git a/aiven/client/cli.py b/aiven/client/cli.py index eec0c3a..b5da7e4 100644 --- a/aiven/client/cli.py +++ b/aiven/client/cli.py @@ -5936,10 +5936,21 @@ def byoc__list(self) -> None: @arg("--organization-id", required=True, help="Identifier of the organization of the custom cloud environment") @arg("--byoc-id", required=True, help="Identifier of the custom cloud environment that defines the BYOC cloud") @arg("--aws-iam-role-arn", help="The IAM role that Aiven is authorized to assume to operate the cloud (AWS)") + @arg( + "--google-privilege-bearing-service-account-id", + help="The privilege-bearing service account that Aiven is authorized to impersonate to operate the cloud (Google)", + ) def byoc__provision(self) -> None: """Provision resources for a Bring Your Own Cloud cloud.""" + if self.args.aws_iam_role_arn and self.args.google_privilege_bearing_service_account_id: + raise argx.UserError( + "--aws-iam-role-arn and --google-privilege-bearing-service-account-id are mutually exclusive." + ) output = self.client.byoc_provision( - organization_id=self.args.organization_id, byoc_id=self.args.byoc_id, aws_iam_role_arn=self.args.aws_iam_role_arn + organization_id=self.args.organization_id, + byoc_id=self.args.byoc_id, + aws_iam_role_arn=self.args.aws_iam_role_arn, + google_privilege_bearing_service_account_id=self.args.google_privilege_bearing_service_account_id, ) self.print_response(output) diff --git a/aiven/client/client.py b/aiven/client/client.py index 48a8005..d42cadc 100644 --- a/aiven/client/client.py +++ b/aiven/client/client.py @@ -2750,9 +2750,18 @@ def byoc_update( def byoc_list(self, *, organization_id: str) -> Mapping[Any, Any]: return self.verify(self.get, self.build_path("organization", organization_id, "custom-cloud-environments")) - def byoc_provision(self, *, organization_id: str, byoc_id: str, aws_iam_role_arn: str | None) -> Mapping[Any, Any]: + def byoc_provision( + self, + *, + organization_id: str, + byoc_id: str, + aws_iam_role_arn: str | None = None, + google_privilege_bearing_service_account_id: str | None = None, + ) -> Mapping[Any, Any]: if aws_iam_role_arn is not None: body = {"aws_iam_role_arn": aws_iam_role_arn} + elif google_privilege_bearing_service_account_id is not None: + body = {"google_privilege_bearing_service_account_id": google_privilege_bearing_service_account_id} else: body = {} return self.verify( diff --git a/tests/test_cli.py b/tests/test_cli.py index 6070fba..373f5d7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1790,12 +1790,23 @@ def test_byoc_update() -> None: ) -def test_byoc_provision() -> None: +@pytest.mark.parametrize( + "provider,region,byoc_account_id", + [ + ("aws", "eu-west-2", "arn:aws:iam::123456789012:role/role-name"), + ( + "google", + "europe-north1", + "projects/aiven-test-byoa/serviceAccounts/aiven-cce4bafaf95155@aiven-test-byoa.iam.gserviceaccount.com", + ), + ], +) +def test_byoc_provision(provider: str, region: str, byoc_account_id: str) -> None: aiven_client = mock.Mock(spec_set=AivenClient) aiven_client.byoc_provision.return_value = { "custom_cloud_environment": { - "cloud_provider": "aws", - "cloud_region": "eu-west-2", + "cloud_provider": provider, + "cloud_region": region, "contact_emails": [], "custom_cloud_environment_id": "d6a490ad-f43d-49d8-b3e5-45bc5dbfb387", "deployment_model": "standard", @@ -1804,21 +1815,41 @@ def test_byoc_provision() -> None: "state": "creating", } } + byoc_account_id_args = { + "aws": "--aws-iam-role-arn", + "google": "--google-privilege-bearing-service-account-id", + } args = [ "byoc", "provision", "--organization-id=org123456789a", "--byoc-id=d6a490ad-f43d-49d8-b3e5-45bc5dbfb387", - "--aws-iam-role-arn=arn:aws:iam::123456789012:role/role-name", + f"{byoc_account_id_args[provider]}={byoc_account_id}", ] build_aiven_cli(aiven_client).run(args=args) aiven_client.byoc_provision.assert_called_once_with( organization_id="org123456789a", byoc_id="d6a490ad-f43d-49d8-b3e5-45bc5dbfb387", - aws_iam_role_arn="arn:aws:iam::123456789012:role/role-name", + aws_iam_role_arn=byoc_account_id if provider == "aws" else None, + google_privilege_bearing_service_account_id=byoc_account_id if provider == "google" else None, ) +def test_byoc_provision_args() -> None: + aiven_client = mock.Mock(spec_set=AivenClient) + args = [ + "byoc", + "provision", + "--organization-id=org123456789a", + "--byoc-id=d6a490ad-f43d-49d8-b3e5-45bc5dbfb387", + "--aws-iam-role-arn=arn:aws:iam::123456789012:role/role-name", + "--google-privilege-bearing-service-account-id=" + "projects/aiven-test-byoa/serviceAccounts/aiven-cce4bafaf95155@aiven-test-byoa.iam.gserviceaccount.com", + ] + build_aiven_cli(aiven_client).run(args=args) + aiven_client.byoc_provision.assert_not_called() + + def test_byoc_delete() -> None: aiven_client = mock.Mock(spec_set=AivenClient) aiven_client.byoc_delete.return_value = {"message": "deleting"}