From 88379bbce32e7726cbcb8888af85c863fcaab986 Mon Sep 17 00:00:00 2001 From: Guillaume Giffard Date: Fri, 7 Jun 2024 08:22:27 +0200 Subject: [PATCH 1/3] client: allow to provision Google BYOC [MILK-135] [MILK-135] --- aiven/client/cli.py | 9 ++++++++- aiven/client/client.py | 13 +++++++++++-- tests/test_cli.py | 26 +++++++++++++++++++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/aiven/client/cli.py b/aiven/client/cli.py index eec0c3a..222b35c 100644 --- a/aiven/client/cli.py +++ b/aiven/client/cli.py @@ -5936,10 +5936,17 @@ 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 (AWS)", + ) def byoc__provision(self) -> None: """Provision resources for a Bring Your Own Cloud cloud.""" 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..94b94cd 100644 --- a/aiven/client/client.py +++ b/aiven/client/client.py @@ -1,4 +1,4 @@ -# Copyright 2015, Aiven, https://aiven.io/ +# Copright 2015, Aiven, https://aiven.io/ # # This file is under the Apache License, Version 2.0. # See the file `LICENSE` for details. @@ -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..264ea74 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,18 +1815,23 @@ 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, ) From 2d41bea347c25b18379e02bf5986516632ab919f Mon Sep 17 00:00:00 2001 From: Guillaume Giffard Date: Fri, 7 Jun 2024 08:45:35 +0200 Subject: [PATCH 2/3] workflows: ease local testing [MILK-135] - replace 'pip install -e .[dev]' by 'make install-py' - create a default 'make' target to locally run: install-py, validate-style, lint and test [MILK-135] --- .github/workflows/build.yaml | 3 +-- Makefile | 6 ++++++ aiven/client/cli.py | 2 +- aiven/client/client.py | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) 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 222b35c..6ff2738 100644 --- a/aiven/client/cli.py +++ b/aiven/client/cli.py @@ -5938,7 +5938,7 @@ def byoc__list(self) -> None: @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 (AWS)", + 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.""" diff --git a/aiven/client/client.py b/aiven/client/client.py index 94b94cd..d42cadc 100644 --- a/aiven/client/client.py +++ b/aiven/client/client.py @@ -1,4 +1,4 @@ -# Copright 2015, Aiven, https://aiven.io/ +# Copyright 2015, Aiven, https://aiven.io/ # # This file is under the Apache License, Version 2.0. # See the file `LICENSE` for details. From a13cd49436eb5ed0eb0ed338e48539a18ab319fa Mon Sep 17 00:00:00 2001 From: Guillaume Giffard Date: Tue, 18 Jun 2024 14:05:20 +0200 Subject: [PATCH 3/3] client: test mutually exclusive provision args [MILK-135] [MILK-135] --- aiven/client/cli.py | 4 ++++ tests/test_cli.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/aiven/client/cli.py b/aiven/client/cli.py index 6ff2738..b5da7e4 100644 --- a/aiven/client/cli.py +++ b/aiven/client/cli.py @@ -5942,6 +5942,10 @@ def byoc__list(self) -> None: ) 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, diff --git a/tests/test_cli.py b/tests/test_cli.py index 264ea74..373f5d7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1835,6 +1835,21 @@ def test_byoc_provision(provider: str, region: str, byoc_account_id: str) -> Non ) +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"}