From 8edb97e53ffd0f55d2691d4266c17ff102bf3885 Mon Sep 17 00:00:00 2001 From: Elior Erez Date: Thu, 9 Jan 2025 17:34:10 +0200 Subject: [PATCH 1/2] NO-ISSUE: Set OCI bucket name to include cluster name. Upload terraform output to the generated bucket. --- .../node_controllers/oci_api_controller.py | 27 ++++++++++++++----- .../config/base_cluster_config.py | 1 - .../config/base_entity_config.py | 1 + .../config/base_infra_env_config.py | 1 - 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py b/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py index fb9683c76fc..96d0e868b39 100644 --- a/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py +++ b/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py @@ -150,8 +150,16 @@ def _create_bucket( # Need the namespace and bucket name return namespace - def _upload_iso_to_bucket(self, file_path: str, namespace: str, bucket_name: str) -> None: - log.info(f"Upload iso file to bucket object storage {file_path}") + def _upload_data_to_bucket(self, data: str, filename: str, namespace: str, bucket_name: str): + file_path = f"/tmp/{filename}" + + with os.path.open(file_path, "w") as f: + f.write(data) + + return self._upload_file_to_bucket(file_path, namespace, bucket_name) + + def _upload_file_to_bucket(self, file_path: str, namespace: str, bucket_name: str): + log.info(f"Upload file to bucket object storage {file_path}") if os.path.isfile(file_path): try: self._object_storage_client.put_object( @@ -444,11 +452,11 @@ def setup_time(self) -> str: def prepare_nodes(self) -> None: log.info("OCI prepare all nodes") - bucket_name = random_name("bucket-") + bucket_name = f"bucket-{self._entity_config.cluster_id}" namespace = self._create_bucket(bucket_name) - self._upload_iso_to_bucket(self._entity_config.iso_download_path, namespace, bucket_name) + self._upload_file_to_bucket(self._entity_config.iso_download_path, namespace, bucket_name) url_path = self._create_pre_authenticated( - random_name("preauth-"), self._entity_config.iso_download_path, namespace, bucket_name + f"preauth-{self._entity_config.cluster_id}", self._entity_config.iso_download_path, namespace, bucket_name ) terraform_variables = self._terraform_variables( @@ -460,9 +468,16 @@ def prepare_nodes(self) -> None: base_dns=self._entity_config.base_dns_domain, ) stack_id = self._create_stack( - random_name("stack-"), namespace, bucket_name, self._config.oci_infrastructure_zip_file, terraform_variables + f"stack-{self._entity_config.cluster_id}", + namespace, + bucket_name, + self._config.oci_infrastructure_zip_file, + terraform_variables, ) terraform_output = self._apply_job_from_stack(stack_id, random_name("job-")) + self._upload_data_to_bucket( + terraform_output, f"terraform-output-{self._entity_config.cluster_id}.yaml", namespace, bucket_name + ) self.cloud_provider = terraform_output def is_active(self, node_name) -> bool: diff --git a/src/assisted_test_infra/test_infra/helper_classes/config/base_cluster_config.py b/src/assisted_test_infra/test_infra/helper_classes/config/base_cluster_config.py index 63a2b91affc..11bb2f0231c 100644 --- a/src/assisted_test_infra/test_infra/helper_classes/config/base_cluster_config.py +++ b/src/assisted_test_infra/test_infra/helper_classes/config/base_cluster_config.py @@ -16,7 +16,6 @@ class BaseClusterConfig(BaseEntityConfig, ABC): All arguments must default to None and be type annotated. """ - cluster_id: str = None cluster_tags: str = None olm_operators: List[str] = None vip_dhcp_allocation: bool = None diff --git a/src/assisted_test_infra/test_infra/helper_classes/config/base_entity_config.py b/src/assisted_test_infra/test_infra/helper_classes/config/base_entity_config.py index 65da04e5ba5..6dc1852f36c 100644 --- a/src/assisted_test_infra/test_infra/helper_classes/config/base_entity_config.py +++ b/src/assisted_test_infra/test_infra/helper_classes/config/base_entity_config.py @@ -34,3 +34,4 @@ class BaseEntityConfig(BaseConfig, ABC): is_bonded: bool = None num_bonded_slaves: int = None bonding_mode: str = None + cluster_id: str = None diff --git a/src/assisted_test_infra/test_infra/helper_classes/config/base_infra_env_config.py b/src/assisted_test_infra/test_infra/helper_classes/config/base_infra_env_config.py index 71354143d5d..1bf1bb4b48a 100644 --- a/src/assisted_test_infra/test_infra/helper_classes/config/base_infra_env_config.py +++ b/src/assisted_test_infra/test_infra/helper_classes/config/base_infra_env_config.py @@ -13,7 +13,6 @@ class BaseInfraEnvConfig(BaseEntityConfig, ABC): """ infra_env_id: str = None - cluster_id: str = None static_network_config: List[dict] = None ignition_config_override: str = None verify_download_iso_ssl: bool = None From 258b17bc330b5ba6fd9616d32ea2daa5edcee2b6 Mon Sep 17 00:00:00 2001 From: dasulin Date: Mon, 13 Jan 2025 12:41:49 +0200 Subject: [PATCH 2/2] Test OCI Fix --- Makefile | 12 ++-- .../node_controllers/oci_api_controller.py | 64 +++++++++++++++++-- src/tests/test_targets.py | 11 +++- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 9c3b62f09cb..d50881ddfa9 100644 --- a/Makefile +++ b/Makefile @@ -284,6 +284,12 @@ deploy_nodes_with_install: start_load_balancer deploy_nodes: start_load_balancer TEST_TEARDOWN=no TEST=./src/tests/test_targets.py TEST_FUNC=test_target_deploy_nodes $(MAKE) test +deploy_nodes_oci: start_load_balancer + TEST_TEARDOWN=no TEST=./src/tests/test_targets.py TEST_FUNC=test_target_deploy_nodes_oci $(MAKE) test + +destroy_nodes_oci: start_load_balancer + TEST_TEARDOWN=no TEST=./src/tests/test_targets.py TEST_FUNC=test_target_destroy_nodes_oci $(MAKE) test + deploy_nodes_with_networking: start_load_balancer TEST_TEARDOWN=no TEST=./src/tests/test_targets.py TEST_FUNC=test_target_deploy_networking_with_nodes $(MAKE) test @@ -427,9 +433,3 @@ test_ctlplane_scaleup: install_k8s_api: TEST_TEARDOWN=false TEST=./src/tests/test_kube_api.py TEST_FUNC=test_kubeapi $(MAKE) test - -destroy_crs: - oc delete cd --all-namespaces --all - oc delete aci --all-namespaces --all - oc delete infraenv --all-namespaces --all - oc delete agents --all-namespaces --all diff --git a/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py b/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py index 96d0e868b39..51b19066172 100644 --- a/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py +++ b/src/assisted_test_infra/test_infra/controllers/node_controllers/oci_api_controller.py @@ -151,9 +151,9 @@ def _create_bucket( return namespace def _upload_data_to_bucket(self, data: str, filename: str, namespace: str, bucket_name: str): - file_path = f"/tmp/{filename}" + file_path = f"/tmp/oci-{self._entity_config.cluster_id}/{filename}" - with os.path.open(file_path, "w") as f: + with open(file_path, "w") as f: f.write(data) return self._upload_file_to_bucket(file_path, namespace, bucket_name) @@ -252,7 +252,7 @@ def _create_stack( bucket_name: str, terraform_zip_path: str, terraform_variable: dict, - timeout_seconds: int = 1200, + timeout_seconds: int = 1800, ) -> str: template_config = { @@ -440,10 +440,66 @@ def get_ingress_and_api_vips(self) -> dict: def destroy_all_nodes(self) -> None: log.info("OCI Destroying all nodes") + if not self._cleanup_resources: + self._generate_cleanup_resources() for resource in self._cleanup_resources[::-1]: resource() pass + def _generate_cleanup_resources(self, timeout_seconds: int = 1800) -> None: + namespace = self._object_storage_client.get_namespace().data + stack_name = f"stack-{self._entity_config.cluster_id}" + bucket_name = f"bucket-{self._entity_config.cluster_id}" + pre_auths = self._object_storage_client.list_preauthenticated_requests(namespace, bucket_name).data + objects = self._object_storage_client.list_objects(namespace, bucket_name).data.objects + + # Find relevant stack_id and create destroy job for it + stacks = self._resource_manager_client.list_stacks( + compartment_id=self._oci_compartment_oicd, display_name=stack_name + ).data + stack_id = stacks[0].id if stacks else None + job_info = { + "stack_id": stack_id, + "display_name": f"destroy-job-{self._entity_config.cluster_id}", + "operation": "DESTROY", + "apply_job_plan_resolution": oci.resource_manager.models.ApplyJobPlanResolution( + is_use_latest_job_id=False, is_auto_approved=True + ), + } + destroy_job_details = oci.resource_manager.models.CreateJobDetails(**job_info) + + # Add all relevant jobs for execution in reversed order + self._cleanup_resources.append( + CleanupResource( + self._resource_manager_client_composite_operations.delete_stack_and_wait_for_state, stack_id + ) + ) + + self._cleanup_resources.append( + CleanupResource(self._object_storage_client.delete_bucket, namespace, bucket_name) + ) + + for pre_auth in pre_auths: + self._cleanup_resources.append( + CleanupResource( + self._object_storage_client.delete_preauthenticated_request, namespace, bucket_name, pre_auth.id + ) + ) + + for obj in objects: + self._cleanup_resources.append( + CleanupResource(self._object_storage_client.delete_object, namespace, bucket_name, obj.name) + ) + + self._cleanup_resources.append( + CleanupResource( + self._resource_manager_client_composite_operations.create_job_and_wait_for_state, + destroy_job_details, + wait_for_states=[OciState.SUCCEEDED.value], + waiter_kwargs={"max_wait_seconds": timeout_seconds, "succeed_on_not_found": False}, + ) + ) + def get_cluster_network(self) -> str: pass @@ -474,7 +530,7 @@ def prepare_nodes(self) -> None: self._config.oci_infrastructure_zip_file, terraform_variables, ) - terraform_output = self._apply_job_from_stack(stack_id, random_name("job-")) + terraform_output = self._apply_job_from_stack(stack_id, f"apply-job-{self._entity_config.cluster_id}") self._upload_data_to_bucket( terraform_output, f"terraform-output-{self._entity_config.cluster_id}.yaml", namespace, bucket_name ) diff --git a/src/tests/test_targets.py b/src/tests/test_targets.py index 87921ebe8d4..b78799bf3d0 100644 --- a/src/tests/test_targets.py +++ b/src/tests/test_targets.py @@ -21,6 +21,15 @@ class TestMakefileTargets(BaseTest): def test_target_deploy_nodes(self, cluster): cluster.prepare_nodes() + @JunitTestSuite() + def test_target_deploy_nodes_oci(self, cluster): + cluster.generate_and_download_infra_env() + cluster.nodes.prepare_nodes() + + @JunitTestSuite() + def test_target_destroy_nodes_oci(self, cluster): + cluster.nodes.destroy_all_nodes() + @JunitTestSuite() def test_target_deploy_networking_with_nodes(self, cluster): cluster.prepare_for_installation() @@ -58,7 +67,7 @@ def test_delete_clusters(self, api_client: InventoryClient, cluster_configuratio @JunitTestSuite() def test_destroy_available_terraform( - self, prepared_controller_configuration: BaseNodesConfig, cluster_configuration + self, prepared_controller_configuration: BaseNodesConfig, cluster_configuration ): clusters_tf_folders = glob(f"{consts.TF_FOLDER}/*") destroyed_clusters = 0