From 5f8f35656e81d0b86a7aaab0250a2738fb59bda7 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 11:51:20 +0000 Subject: [PATCH 01/18] test(mc): initial multicloud IaC boilerplate GKE, AKS, Kind --- test/multicloud/.gitignore | 7 ++ test/multicloud/Makefile | 40 ++++++++++ test/multicloud/README.md | 77 +++++++++++++++++++ .../live/retina-aks/.terraform.lock.hcl | 40 ++++++++++ test/multicloud/live/retina-aks/main.tf | 16 ++++ test/multicloud/live/retina-aks/providers.tf | 34 ++++++++ test/multicloud/live/retina-aks/variables.tf | 35 +++++++++ .../live/retina-gke/.terraform.lock.hcl | 38 +++++++++ test/multicloud/live/retina-gke/main.tf | 16 ++++ test/multicloud/live/retina-gke/providers.tf | 30 ++++++++ test/multicloud/live/retina-gke/variables.tf | 23 ++++++ .../live/retina-kind/.terraform.lock.hcl | 54 +++++++++++++ test/multicloud/live/retina-kind/main.tf | 18 +++++ test/multicloud/live/retina-kind/providers.tf | 30 ++++++++ test/multicloud/live/retina-kind/variables.tf | 5 ++ test/multicloud/modules/aks/main.tf | 41 ++++++++++ test/multicloud/modules/aks/outputs.tf | 20 +++++ test/multicloud/modules/aks/provider.tf | 9 +++ test/multicloud/modules/aks/variables.tf | 22 ++++++ test/multicloud/modules/gke/main.tf | 41 ++++++++++ test/multicloud/modules/gke/output.tf | 20 +++++ test/multicloud/modules/gke/provider.tf | 9 +++ test/multicloud/modules/gke/variables.tf | 19 +++++ test/multicloud/modules/kind/main.tf | 20 +++++ test/multicloud/modules/kind/output.tf | 19 +++++ test/multicloud/modules/kind/provider.tf | 9 +++ test/multicloud/modules/kind/variables.tf | 4 + test/multicloud/modules/retina/main.tf | 27 +++++++ test/multicloud/modules/retina/provider.tf | 8 ++ test/multicloud/modules/retina/variables.tf | 5 ++ 30 files changed, 736 insertions(+) create mode 100644 test/multicloud/.gitignore create mode 100644 test/multicloud/Makefile create mode 100644 test/multicloud/README.md create mode 100644 test/multicloud/live/retina-aks/.terraform.lock.hcl create mode 100644 test/multicloud/live/retina-aks/main.tf create mode 100644 test/multicloud/live/retina-aks/providers.tf create mode 100644 test/multicloud/live/retina-aks/variables.tf create mode 100644 test/multicloud/live/retina-gke/.terraform.lock.hcl create mode 100644 test/multicloud/live/retina-gke/main.tf create mode 100644 test/multicloud/live/retina-gke/providers.tf create mode 100644 test/multicloud/live/retina-gke/variables.tf create mode 100644 test/multicloud/live/retina-kind/.terraform.lock.hcl create mode 100644 test/multicloud/live/retina-kind/main.tf create mode 100644 test/multicloud/live/retina-kind/providers.tf create mode 100644 test/multicloud/live/retina-kind/variables.tf create mode 100644 test/multicloud/modules/aks/main.tf create mode 100644 test/multicloud/modules/aks/outputs.tf create mode 100644 test/multicloud/modules/aks/provider.tf create mode 100644 test/multicloud/modules/aks/variables.tf create mode 100644 test/multicloud/modules/gke/main.tf create mode 100644 test/multicloud/modules/gke/output.tf create mode 100644 test/multicloud/modules/gke/provider.tf create mode 100644 test/multicloud/modules/gke/variables.tf create mode 100644 test/multicloud/modules/kind/main.tf create mode 100644 test/multicloud/modules/kind/output.tf create mode 100644 test/multicloud/modules/kind/provider.tf create mode 100644 test/multicloud/modules/kind/variables.tf create mode 100644 test/multicloud/modules/retina/main.tf create mode 100644 test/multicloud/modules/retina/provider.tf create mode 100644 test/multicloud/modules/retina/variables.tf diff --git a/test/multicloud/.gitignore b/test/multicloud/.gitignore new file mode 100644 index 0000000000..7df4bdc931 --- /dev/null +++ b/test/multicloud/.gitignore @@ -0,0 +1,7 @@ +terraform.tfvars +.terraform +terraform.tfstate +*terraform.tfstate.* +kubeconfig.yaml +service-key.json +kubeconfig.yaml \ No newline at end of file diff --git a/test/multicloud/Makefile b/test/multicloud/Makefile new file mode 100644 index 0000000000..2ee40c30c5 --- /dev/null +++ b/test/multicloud/Makefile @@ -0,0 +1,40 @@ +PREFIX ?= retina +STACK_NAME ?= $(PREFIX)-aks + +plan: + cd live/$(STACK_NAME) && \ + tofu fmt && tofu init && tofu plan + +apply: + cd live/$(STACK_NAME) && \ + tofu apply --auto-approve + +quick: + @make plan + @make apply + +gke: export STACK_NAME=$(PREFIX)-gke +gke: + @make quick + +aks: export STACK_NAME=$(PREFIX)-aks +aks: + @make quick + +kind: export STACK_NAME=$(PREFIX)-kind +kind: + @make quick + +destroy: + cd live/$(STACK_NAME) && \ + tofu destroy --auto-approve + +clean: destroy + @cd live/$(STACK_NAME) && \ + rm -rf .terraform && rm terraform.tfstate && rm terraform.tfstate.backup + @if [ $(STACK_NAME) == $(PREFIX)-kind ]; then \ + rm -rf live/$(STACK_NAME)/mc-kind-config; \ + fi + +kind-kubeconfig: + @kubectl config set-context live/$(PREFIX)-kind/mc-kind-config diff --git a/test/multicloud/README.md b/test/multicloud/README.md new file mode 100644 index 0000000000..02ecbcd0a0 --- /dev/null +++ b/test/multicloud/README.md @@ -0,0 +1,77 @@ +# Multi Cloud Retina +This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructure as Code (IaC) to create Kubernetes infrastructure on multi-cloud and deploy [microsoft/retina](https://github.com/microsoft/retina) via Helm provider. + +## Modules available + +* [aks](./modules/aks/) +* [gke](./modules/gke/) +* [kind](./modules/kind/) +* [retina](./modules/retina/) + +## Prerequisites + +AKS: + +1. create an Azure account +3. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) + +GKE: + +1. create a gcloud account, project and enable billing +2. create a service account and service account key +3. [Enable Kubernetes Engine API](https://console.developers.google.com/apis/api/container.googleapis.com/overview?project=mc-retina) +4. [Install gcloud](https://cloud.google.com/sdk/docs/install) + +Kind: + +1. Docker installed on the host machine + + +## Quickstart + +To deploy an AKS cluster and install retina, create file `live/retina-aks/terraform.tfvars` with the Azure TenantID and SubscriptionID + +```sh +# example values +subscription_id = "d6050d84-e4dd-463d-afc7-a6ab3dc33ab7" +tenant_id = "ac8a4ccd-35f1-4f95-a688-f68e3d89adfc" +``` + +To deploy a GKE cluster export `GOOGLE_APPLICATION_CREDENTIALS` env variable to point to the path where your [service account key](https://cloud.google.com/iam/docs/keys-create-delete) is located. + +```sh +# example +export GOOGLE_APPLICATION_CREDENTIALS=/Users/srodi/src/retina/test/multicloud/live/retina-gke/service-key.json +``` + +Format code, initialize OpenTofu, plan and apply the stack to create infra and deploy retina + +### Create + +* AKS: + ```sh + make aks + ``` +* GKE: + ```sh + make gke + ``` +* Kind: + ```sh + make kind + ``` + +To destroy the cluster + +```sh +# destroy AKS and cleanup local state files +# set a different stack as needed (i.e. retina-gke, retina-kind) +export STACK_NAME=retina-aks +make clean +``` + +## Providers references + +* [GKE resource documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster) +* [AKS resource documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster) +* [Kind resource documentation](https://registry.terraform.io/providers/tehcyx/kind/latest/docs/resources/cluster) \ No newline at end of file diff --git a/test/multicloud/live/retina-aks/.terraform.lock.hcl b/test/multicloud/live/retina-aks/.terraform.lock.hcl new file mode 100644 index 0000000000..5c20d26e2a --- /dev/null +++ b/test/multicloud/live/retina-aks/.terraform.lock.hcl @@ -0,0 +1,40 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/azurerm" { + version = "4.15.0" + constraints = ">= 2.0.0" + hashes = [ + "h1:0YxkmS5jTUl1LIG+71sgKg/YdlgAoHNr3wyyZjJO8vY=", + "h1:xE74Yb3iZZF2F1hQy4B8YVCk0gLAp99pJgZX4eIXYMg=", + "zh:0a104acfc45de410d9786bdbf540009dbb7db5632fe7c6846fdb5f865007d0b4", + "zh:186f20452ca913e84de0fc9b2dc7872c6480813afe11ea076bd60c45aa2d66d0", + "zh:2d540a98254188f17d64c02847e4d178b49979871a2a05283f78d336f3f25d45", + "zh:34fdffad86800af74dd2f4c9b3a32fb4f1463ba453bb0f634a9389f503869bc6", + "zh:38751b0bb8d03c34acb63dbddf6ebe01d99e6b75a9d94ae3b3fb1c60bf43c45a", + "zh:4234e0e56e87983d387d7323d8bb49838054c5cebeb121dbb5aa4dd3255f211f", + "zh:4ead322049485495d07afe2334d82a47997fc7638b9e39512000d4499dc3a782", + "zh:74e8a9fdfbe0bb91c6542176dc14d3e95be2c3c77cca10ae57aa67116b5a6b95", + "zh:9f03e13551cd68d2f7cd2d46f74ffc33f0656e0aa8c9095ed259385aaeaf4957", + "zh:f86fce72cbdf72f52412b9099023115bece67c5df55970c4429ef0f1bdc3c473", + ] +} + +provider "registry.opentofu.org/hashicorp/helm" { + version = "2.17.0" + constraints = "2.17.0" + hashes = [ + "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", + "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", + "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", + "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", + "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", + "zh:3976400ceba6dda4636e1d297e3097e1831de5628afa534a166de98a70d1dcbe", + "zh:54440ef14f342b41d75c1aded7487bfcc3f76322b75894235b47b7e89ac4bfa4", + "zh:6512e2ab9f2fa31cbb90d9249647b5c5798f62eb1215ec44da2cdaa24e38ad25", + "zh:795f327ca0b8c5368af0ed03d5d4f6da7260692b4b3ca0bd004ed542e683464d", + "zh:ba659e1d94f224bc3f1fd34cbb9d2663e3a8e734108e5a58eb49eda84b140978", + "zh:c5c8575c4458835c2acbc3d1ed5570589b14baa2525d8fbd04295c097caf41eb", + "zh:e0877a5dac3de138e61eefa26b2f5a13305a17259779465899880f70e11314e0", + ] +} diff --git a/test/multicloud/live/retina-aks/main.tf b/test/multicloud/live/retina-aks/main.tf new file mode 100644 index 0000000000..237471fe09 --- /dev/null +++ b/test/multicloud/live/retina-aks/main.tf @@ -0,0 +1,16 @@ +module "aks" { + source = "../../modules/aks" + location = var.location + resource_group_name = var.resource_group_name + prefix = var.prefix + labels = var.labels +} + +module "retina" { + depends_on = [module.aks] + source = "../../modules/retina" +} + +output "kubeconfig_command" { + value = module.aks.azure_get_kubeconfig +} diff --git a/test/multicloud/live/retina-aks/providers.tf b/test/multicloud/live/retina-aks/providers.tf new file mode 100644 index 0000000000..2d19ff792b --- /dev/null +++ b/test/multicloud/live/retina-aks/providers.tf @@ -0,0 +1,34 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 2.0.0" + } + helm = { + source = "hashicorp/helm" + version = "2.17.0" + } + } +} + +# Initialize the Azure provider +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } + subscription_id = var.subscription_id + tenant_id = var.tenant_id +} + +# Initialize the Helm provider +provider "helm" { + kubernetes { + host = module.aks.host + client_certificate = base64decode(module.aks.client_certificate) + client_key = base64decode(module.aks.client_key) + cluster_ca_certificate = base64decode(module.aks.cluster_ca_certificate) + } +} diff --git a/test/multicloud/live/retina-aks/variables.tf b/test/multicloud/live/retina-aks/variables.tf new file mode 100644 index 0000000000..886aacc47e --- /dev/null +++ b/test/multicloud/live/retina-aks/variables.tf @@ -0,0 +1,35 @@ +variable "subscription_id" { + description = "The subscription ID for the Azure account." + type = string +} + +variable "tenant_id" { + description = "The tenant ID for the Azure account." + type = string +} + +variable "location" { + description = "The Azure Cloud location where AKS will be deployed to." + type = string + default = "uksouth" +} + +variable "resource_group_name" { + description = "The name of the resource group." + type = string + default = "mc-rg" +} + +variable "prefix" { + description = "A prefix to add to all resources." + type = string + default = "mc" +} + +variable "labels" { + description = "A map of labels to add to all resources." + type = map(string) + default = { + "env" = "test" + } +} diff --git a/test/multicloud/live/retina-gke/.terraform.lock.hcl b/test/multicloud/live/retina-gke/.terraform.lock.hcl new file mode 100644 index 0000000000..9b2ad80a97 --- /dev/null +++ b/test/multicloud/live/retina-gke/.terraform.lock.hcl @@ -0,0 +1,38 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/google" { + version = "6.17.0" + constraints = ">= 6.17.0" + hashes = [ + "h1:7m+L8x7ClWUFAd4uJJENXp9O4K8HtpL50434jPR9pqs=", + "zh:0614cc52deb5914795253aecf19b4cbb5aa7e8a186839a33907ce5c35e23d537", + "zh:0b28ea31ec3b119aafc4c37a5992c29266c876db288dfc5bbfbde36631a533f1", + "zh:1b2c5df40ac55ec7c3db2b7c556ace7545fca4ccfacf605b7588a4e2be564ba8", + "zh:1db9a278cfddcaa7d9119acf231164438df07932bdabce95931a68bd3689cd39", + "zh:3729b7a9936f5ad545f7d06d11d05ce78b4bbe9941e77bf004a2b798e6a0866c", + "zh:3b7e35183a8d7980207ae7d082c490d7c2270f907e5de9e8393c6c4c32b07b3c", + "zh:581e14963dfef608285af0c08ccb5da4bdb8ae049366418d4863a4fd9fa55b74", + "zh:89d29f2d1269a30c6149bbaaae3cbe8fe0c6ed13874b77bf784ea6bbd73aee58", + "zh:c7c690c1f9fe0cbc69d4eb21727f2cf4b7ba016385184d27527d570832c393be", + "zh:dc1536fc325a0561bf0f606a38bed29e8dd2f4bec6d6e8a5301696d89c1c8079", + ] +} + +provider "registry.opentofu.org/hashicorp/helm" { + version = "2.17.0" + constraints = "2.17.0" + hashes = [ + "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", + "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", + "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", + "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", + "zh:3976400ceba6dda4636e1d297e3097e1831de5628afa534a166de98a70d1dcbe", + "zh:54440ef14f342b41d75c1aded7487bfcc3f76322b75894235b47b7e89ac4bfa4", + "zh:6512e2ab9f2fa31cbb90d9249647b5c5798f62eb1215ec44da2cdaa24e38ad25", + "zh:795f327ca0b8c5368af0ed03d5d4f6da7260692b4b3ca0bd004ed542e683464d", + "zh:ba659e1d94f224bc3f1fd34cbb9d2663e3a8e734108e5a58eb49eda84b140978", + "zh:c5c8575c4458835c2acbc3d1ed5570589b14baa2525d8fbd04295c097caf41eb", + "zh:e0877a5dac3de138e61eefa26b2f5a13305a17259779465899880f70e11314e0", + ] +} diff --git a/test/multicloud/live/retina-gke/main.tf b/test/multicloud/live/retina-gke/main.tf new file mode 100644 index 0000000000..4e0280c95f --- /dev/null +++ b/test/multicloud/live/retina-gke/main.tf @@ -0,0 +1,16 @@ +module "gke" { + source = "../../modules/gke" + location = var.location + prefix = var.prefix + project = var.project + machine_type = var.machine_type +} + +module "retina" { + depends_on = [module.gke] + source = "../../modules/retina" +} + +output "kubeconfig_command" { + value = module.gke.gcloud_get_kubeconfig +} diff --git a/test/multicloud/live/retina-gke/providers.tf b/test/multicloud/live/retina-gke/providers.tf new file mode 100644 index 0000000000..313da6ab99 --- /dev/null +++ b/test/multicloud/live/retina-gke/providers.tf @@ -0,0 +1,30 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 6.17.0" + } + helm = { + source = "hashicorp/helm" + version = "2.17.0" + } + } +} + +# Initialize the Google provider +provider "google" { + project = var.project + region = var.location +} + +data "google_client_config" "current" {} + +# Initialize the Helm provider +provider "helm" { + kubernetes { + token = data.google_client_config.current.access_token + host = module.gke.host + cluster_ca_certificate = base64decode(module.gke.cluster_ca_certificate) + } +} \ No newline at end of file diff --git a/test/multicloud/live/retina-gke/variables.tf b/test/multicloud/live/retina-gke/variables.tf new file mode 100644 index 0000000000..9e00f0f537 --- /dev/null +++ b/test/multicloud/live/retina-gke/variables.tf @@ -0,0 +1,23 @@ +variable "project" { + description = "The Google Cloud project where resources will be deployed." + type = string + default = "mc-retina" +} + +variable "location" { + description = "The Google Cloud location where GKE will be deployed to." + type = string + default = "eu-central1" +} + +variable "prefix" { + description = "A prefix to add to all resources." + type = string + default = "mc" +} + +variable "machine_type" { + description = "The machine type to use for the GKE nodes." + type = string + default = "e2-standard-4" +} diff --git a/test/multicloud/live/retina-kind/.terraform.lock.hcl b/test/multicloud/live/retina-kind/.terraform.lock.hcl new file mode 100644 index 0000000000..0a5f2baaa1 --- /dev/null +++ b/test/multicloud/live/retina-kind/.terraform.lock.hcl @@ -0,0 +1,54 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/helm" { + version = "2.17.0" + constraints = "2.17.0" + hashes = [ + "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", + "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", + "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", + "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", + "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", + "zh:3976400ceba6dda4636e1d297e3097e1831de5628afa534a166de98a70d1dcbe", + "zh:54440ef14f342b41d75c1aded7487bfcc3f76322b75894235b47b7e89ac4bfa4", + "zh:6512e2ab9f2fa31cbb90d9249647b5c5798f62eb1215ec44da2cdaa24e38ad25", + "zh:795f327ca0b8c5368af0ed03d5d4f6da7260692b4b3ca0bd004ed542e683464d", + "zh:ba659e1d94f224bc3f1fd34cbb9d2663e3a8e734108e5a58eb49eda84b140978", + "zh:c5c8575c4458835c2acbc3d1ed5570589b14baa2525d8fbd04295c097caf41eb", + "zh:e0877a5dac3de138e61eefa26b2f5a13305a17259779465899880f70e11314e0", + ] +} + +provider "registry.opentofu.org/hashicorp/local" { + version = "2.5.2" + constraints = "2.5.2" + hashes = [ + "h1:6lS+5A/4WFAqY3/RHWFRBSiFVLPRjvLaUgxPQvjXLHU=", + "h1:MBgBjJljfDl1i2JPcIoH4hW+2XLJ+D1l12iH/xd3uTo=", + "zh:25b95b76ceaa62b5c95f6de2fa6e6242edbf51e7fc6c057b7f7101aa4081f64f", + "zh:3c974fdf6b42ca6f93309cf50951f345bfc5726ec6013b8832bcd3be0eb3429e", + "zh:5de843bf6d903f5cca97ce1061e2e06b6441985c68d013eabd738a9e4b828278", + "zh:86beead37c7b4f149a54d2ae633c99ff92159c748acea93ff0f3603d6b4c9f4f", + "zh:8e52e81d3dc50c3f79305d257da7fde7af634fed65e6ab5b8e214166784a720e", + "zh:9882f444c087c69559873b2d72eec406a40ede21acb5ac334d6563bf3a2387df", + "zh:a4484193d110da4a06c7bffc44cc6b61d3b5e881cd51df2a83fdda1a36ea25d2", + "zh:a53342426d173e29d8ee3106cb68abecdf4be301a3f6589e4e8d42015befa7da", + "zh:d25ef2aef6a9004363fc6db80305d30673fc1f7dd0b980d41d863b12dacd382a", + "zh:fa2d522fb323e2121f65b79709fd596514b293d816a1d969af8f72d108888e4c", + ] +} + +provider "registry.opentofu.org/tehcyx/kind" { + version = "0.7.0" + constraints = "0.7.0" + hashes = [ + "h1:9ci1+3JBxvMRZ0pnzoVNmw7NrBCAfzqOPyhm+I8Rxag=", + "zh:171a2fb0137bfbdebd56cd65afd2e0e2167315fe4cb6a07a218db40cb17339c3", + "zh:3260b078b7997ddfd03845326ffaeed7f678eeaaf7918430356f22e299e36f22", + "zh:4066ab3feb482a0dd1bfff6590d89a0ec30478f63c9d8253cfdadb4b8db2234d", + "zh:537af73261d53f4840d1f89d8e5835c52ddb97102e6314f6aea9b8e49c43d610", + "zh:d63e94d828ba0339600d992b0a6695cff939b0aaac1c39b31d38e3c4f3823674", + "zh:f971c617bf6b37d07a5042f13a9ab02b42d0ceb14934174eecc81abeec233c40", + ] +} diff --git a/test/multicloud/live/retina-kind/main.tf b/test/multicloud/live/retina-kind/main.tf new file mode 100644 index 0000000000..2d86438f6c --- /dev/null +++ b/test/multicloud/live/retina-kind/main.tf @@ -0,0 +1,18 @@ +module "kind" { + source = "../../modules/kind" + prefix = var.prefix +} + +module "retina" { + depends_on = [module.kind] + source = "../../modules/retina" +} + +# output "kubeconfig" { +# value = module.kind.kubeconfig +# } + +# resource "local_file" "kubeconfig" { +# content = module.kind.kubeconfig +# filename = "${path.module}/kubeconfig.yaml" +# } diff --git a/test/multicloud/live/retina-kind/providers.tf b/test/multicloud/live/retina-kind/providers.tf new file mode 100644 index 0000000000..6ecb335411 --- /dev/null +++ b/test/multicloud/live/retina-kind/providers.tf @@ -0,0 +1,30 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + kind = { + source = "tehcyx/kind" + version = "0.7.0" + } + helm = { + source = "hashicorp/helm" + version = "2.17.0" + } + local = { + source = "hashicorp/local" + version = "2.5.2" + } + } +} + +# Initialize the kind provider +provider "kind" {} + +# Initialize the Helm provider +provider "helm" { + kubernetes { + host = module.kind.host + client_certificate = module.kind.client_certificate + client_key = module.kind.client_key + cluster_ca_certificate = module.kind.cluster_ca_certificate + } +} \ No newline at end of file diff --git a/test/multicloud/live/retina-kind/variables.tf b/test/multicloud/live/retina-kind/variables.tf new file mode 100644 index 0000000000..347514bd40 --- /dev/null +++ b/test/multicloud/live/retina-kind/variables.tf @@ -0,0 +1,5 @@ +variable "prefix" { + description = "A prefix to add to all resources." + type = string + default = "mc" +} \ No newline at end of file diff --git a/test/multicloud/modules/aks/main.tf b/test/multicloud/modules/aks/main.tf new file mode 100644 index 0000000000..25279a6ff7 --- /dev/null +++ b/test/multicloud/modules/aks/main.tf @@ -0,0 +1,41 @@ +resource "azurerm_resource_group" "aks_rg" { + name = var.resource_group_name + location = var.location +} + +resource "azurerm_kubernetes_cluster" "aks" { + name = "${var.prefix}-aks" + location = azurerm_resource_group.aks_rg.location + resource_group_name = azurerm_resource_group.aks_rg.name + dns_prefix = "${var.prefix}-aks-dns" + kubernetes_version = "1.29.8" + + default_node_pool { + name = "agentpool" + node_count = 2 + vm_size = "Standard_D4ds_v5" + os_disk_size_gb = 128 + os_disk_type = "Ephemeral" + max_pods = 110 + type = "VirtualMachineScaleSets" + node_labels = var.labels + } + + identity { + type = "SystemAssigned" + } + + network_profile { + network_plugin = "azure" + network_plugin_mode = "overlay" + load_balancer_profile { + managed_outbound_ip_count = 1 + } + pod_cidr = "10.244.0.0/16" + service_cidr = "10.0.0.0/16" + dns_service_ip = "10.0.0.10" + outbound_type = "loadBalancer" + } + + tags = var.labels +} diff --git a/test/multicloud/modules/aks/outputs.tf b/test/multicloud/modules/aks/outputs.tf new file mode 100644 index 0000000000..e68f4af052 --- /dev/null +++ b/test/multicloud/modules/aks/outputs.tf @@ -0,0 +1,20 @@ +output "azure_get_kubeconfig" { + value = "az aks get-credentials --resource-group ${azurerm_resource_group.aks_rg.name} --name ${azurerm_kubernetes_cluster.aks.name} --admin" + description = "Run this command to fetch the kubeconfig for your AKS cluster" +} + +output "host" { + value = azurerm_kubernetes_cluster.aks.kube_config.0.host +} + +output "client_certificate" { + value = azurerm_kubernetes_cluster.aks.kube_config.0.client_certificate +} + +output "client_key" { + value = azurerm_kubernetes_cluster.aks.kube_config.0.client_key +} + +output "cluster_ca_certificate" { + value = azurerm_kubernetes_cluster.aks.kube_config.0.cluster_ca_certificate +} diff --git a/test/multicloud/modules/aks/provider.tf b/test/multicloud/modules/aks/provider.tf new file mode 100644 index 0000000000..91f859c3d0 --- /dev/null +++ b/test/multicloud/modules/aks/provider.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 2.0.0" + } + } +} diff --git a/test/multicloud/modules/aks/variables.tf b/test/multicloud/modules/aks/variables.tf new file mode 100644 index 0000000000..1efe504a65 --- /dev/null +++ b/test/multicloud/modules/aks/variables.tf @@ -0,0 +1,22 @@ +variable "location" { + description = "The VM location." + type = string + default = "UK South" +} + +variable "resource_group_name" { + description = "The name of the resource group." + type = string +} + +variable "prefix" { + description = "A prefix to add to all resources." + type = string + default = "example-vm" +} + +variable "labels" { + description = "A map of labels to add to all resources." + type = map(string) + default = {} +} diff --git a/test/multicloud/modules/gke/main.tf b/test/multicloud/modules/gke/main.tf new file mode 100644 index 0000000000..df63426c23 --- /dev/null +++ b/test/multicloud/modules/gke/main.tf @@ -0,0 +1,41 @@ +resource "google_service_account" "default" { + account_id = "${var.prefix}-gke-service-account" + display_name = "GKE Service Account for ${var.project}" +} + +resource "google_container_cluster" "gke" { + name = "${var.prefix}-gke-cluster" + location = var.location + + # We can't create a cluster with no node pool defined, but we want to only use + # separately managed node pools. So we create the smallest possible default + # node pool and immediately delete it. + remove_default_node_pool = true + initial_node_count = 1 + deletion_protection = false + + # Required to configure Kubernetes provider + master_auth { + client_certificate_config { + issue_client_certificate = true + } + } +} + +resource "google_container_node_pool" "gke_preemptible_nodes" { + name = "${var.prefix}-node-pool" + location = var.location + cluster = google_container_cluster.gke.name + node_count = 1 + + node_config { + preemptible = true + machine_type = var.machine_type + + # Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles. + service_account = google_service_account.default.email + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform" + ] + } +} \ No newline at end of file diff --git a/test/multicloud/modules/gke/output.tf b/test/multicloud/modules/gke/output.tf new file mode 100644 index 0000000000..7f2a248aaa --- /dev/null +++ b/test/multicloud/modules/gke/output.tf @@ -0,0 +1,20 @@ +output "gcloud_get_kubeconfig" { + value = "gcloud container clusters get-credentials ${google_container_cluster.gke.name} --region ${google_container_cluster.gke.location} --project ${google_container_cluster.gke.project}" + description = "Run this command to fetch the kubeconfig for your GKE cluster" +} + +output "host" { + value = "https://${google_container_cluster.gke.endpoint}" +} + +output "client_certificate" { + value = google_container_cluster.gke.master_auth.0.client_certificate +} + +output "client_key" { + value = google_container_cluster.gke.master_auth.0.client_key +} + +output "cluster_ca_certificate" { + value = google_container_cluster.gke.master_auth.0.cluster_ca_certificate +} \ No newline at end of file diff --git a/test/multicloud/modules/gke/provider.tf b/test/multicloud/modules/gke/provider.tf new file mode 100644 index 0000000000..d0fb68a508 --- /dev/null +++ b/test/multicloud/modules/gke/provider.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 6.17.0" + } + } +} \ No newline at end of file diff --git a/test/multicloud/modules/gke/variables.tf b/test/multicloud/modules/gke/variables.tf new file mode 100644 index 0000000000..9971acce00 --- /dev/null +++ b/test/multicloud/modules/gke/variables.tf @@ -0,0 +1,19 @@ +variable "project" { + description = "The Google Cloud project where resources will be deployed." + type = string +} + +variable "location" { + description = "The Google Cloud location where GKE will be deployed to." + type = string +} + +variable "prefix" { + description = "A prefix to add to all resources." + type = string +} + +variable "machine_type" { + description = "The machine type to use for the GKE nodes." + type = string +} \ No newline at end of file diff --git a/test/multicloud/modules/kind/main.tf b/test/multicloud/modules/kind/main.tf new file mode 100644 index 0000000000..2558d114aa --- /dev/null +++ b/test/multicloud/modules/kind/main.tf @@ -0,0 +1,20 @@ +resource "kind_cluster" "kind" { + name = "${var.prefix}-kind" + wait_for_ready = true + kind_config { + kind = "Cluster" + api_version = "kind.x-k8s.io/v1alpha4" + + node { + role = "control-plane" + } + + node { + role = "worker" + } + + node { + role = "worker" + } + } +} \ No newline at end of file diff --git a/test/multicloud/modules/kind/output.tf b/test/multicloud/modules/kind/output.tf new file mode 100644 index 0000000000..52d91e490c --- /dev/null +++ b/test/multicloud/modules/kind/output.tf @@ -0,0 +1,19 @@ +output "kubeconfig" { + value = kind_cluster.kind.kubeconfig +} + +output "host" { + value = kind_cluster.kind.endpoint +} + +output "client_certificate" { + value = kind_cluster.kind.client_certificate +} + +output "client_key" { + value = kind_cluster.kind.client_key +} + +output "cluster_ca_certificate" { + value = kind_cluster.kind.cluster_ca_certificate +} \ No newline at end of file diff --git a/test/multicloud/modules/kind/provider.tf b/test/multicloud/modules/kind/provider.tf new file mode 100644 index 0000000000..aaa6ec7f40 --- /dev/null +++ b/test/multicloud/modules/kind/provider.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0.0" + required_providers { + kind = { + source = "tehcyx/kind" + version = "0.7.0" + } + } +} \ No newline at end of file diff --git a/test/multicloud/modules/kind/variables.tf b/test/multicloud/modules/kind/variables.tf new file mode 100644 index 0000000000..2dd9eaf4b0 --- /dev/null +++ b/test/multicloud/modules/kind/variables.tf @@ -0,0 +1,4 @@ +variable "prefix" { + description = "A prefix to add to all resources." + type = string +} \ No newline at end of file diff --git a/test/multicloud/modules/retina/main.tf b/test/multicloud/modules/retina/main.tf new file mode 100644 index 0000000000..33ad03d1a4 --- /dev/null +++ b/test/multicloud/modules/retina/main.tf @@ -0,0 +1,27 @@ +resource "helm_release" "retina" { + name = "retina" + repository = "oci://ghcr.io/microsoft/retina/charts" + chart = "retina" + version = var.retina_version + namespace = "kube-system" + + set { + name = "image.tag" + value = var.retina_version + } + + set { + name = "operator.tag" + value = var.retina_version + } + + set { + name = "logLevel" + value = "info" + } + + # set { + # name = "enabledPlugin_linux" + # value = "[\"dropreason\",\"packetforward\",\"linuxutil\",\"dns\"]" + # } +} diff --git a/test/multicloud/modules/retina/provider.tf b/test/multicloud/modules/retina/provider.tf new file mode 100644 index 0000000000..83de5829ac --- /dev/null +++ b/test/multicloud/modules/retina/provider.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + helm = { + source = "hashicorp/helm" + version = "2.17.0" + } + } +} diff --git a/test/multicloud/modules/retina/variables.tf b/test/multicloud/modules/retina/variables.tf new file mode 100644 index 0000000000..829f1bd161 --- /dev/null +++ b/test/multicloud/modules/retina/variables.tf @@ -0,0 +1,5 @@ +variable "retina_version" { + description = "The tag to apply to all resources." + type = string + default = "v0.0.23" +} From 944e23caeb137dbb950d3ec798548f057cd23d8a Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 12:01:06 +0000 Subject: [PATCH 02/18] test(mc): fix md linting --- test/multicloud/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/multicloud/README.md b/test/multicloud/README.md index 02ecbcd0a0..7a1e086d0b 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -1,4 +1,5 @@ # Multi Cloud Retina + This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructure as Code (IaC) to create Kubernetes infrastructure on multi-cloud and deploy [microsoft/retina](https://github.com/microsoft/retina) via Helm provider. ## Modules available @@ -13,7 +14,7 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu AKS: 1. create an Azure account -3. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) +2. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) GKE: @@ -26,7 +27,6 @@ Kind: 1. Docker installed on the host machine - ## Quickstart To deploy an AKS cluster and install retina, create file `live/retina-aks/terraform.tfvars` with the Azure TenantID and SubscriptionID @@ -49,14 +49,19 @@ Format code, initialize OpenTofu, plan and apply the stack to create infra and d ### Create * AKS: + ```sh make aks ``` + * GKE: + ```sh make gke ``` + * Kind: + ```sh make kind ``` From a49036201c4ba52f550f9ecb26f7f40191769d00 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 12:02:22 +0000 Subject: [PATCH 03/18] test(mc): fix more md linting --- test/multicloud/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multicloud/README.md b/test/multicloud/README.md index 7a1e086d0b..85716d0916 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -79,4 +79,4 @@ make clean * [GKE resource documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster) * [AKS resource documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster) -* [Kind resource documentation](https://registry.terraform.io/providers/tehcyx/kind/latest/docs/resources/cluster) \ No newline at end of file +* [Kind resource documentation](https://registry.terraform.io/providers/tehcyx/kind/latest/docs/resources/cluster) From 171891d8fc60568ece4da1aeea8afa9b43acf46b Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 12:26:10 +0000 Subject: [PATCH 04/18] test(mc): add OpenTofu installation link --- test/multicloud/README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/multicloud/README.md b/test/multicloud/README.md index 85716d0916..b0d7f5c698 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -11,21 +11,23 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu ## Prerequisites -AKS: +* [OpenTofu installation guide](https://opentofu.org/docs/intro/install/) -1. create an Azure account -2. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) +* AKS: + + 1. create an Azure account + 2. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) -GKE: +* GKE: -1. create a gcloud account, project and enable billing -2. create a service account and service account key -3. [Enable Kubernetes Engine API](https://console.developers.google.com/apis/api/container.googleapis.com/overview?project=mc-retina) -4. [Install gcloud](https://cloud.google.com/sdk/docs/install) + 1. create a gcloud account, project and enable billing + 2. create a service account and service account key + 3. [Enable Kubernetes Engine API](https://console.developers.google.com/apis/api/container.googleapis.com/overview?project=mc-retina) + 4. [Install gcloud](https://cloud.google.com/sdk/docs/install) -Kind: +* Kind: -1. Docker installed on the host machine + 1. Docker installed on the host machine ## Quickstart From 09e7c088f75045ecf3ef457789260d255d043008 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 14:53:30 +0000 Subject: [PATCH 05/18] test(mc): lock providers --- test/multicloud/.gitignore | 3 +-- test/multicloud/live/retina-aks/providers.tf | 4 ++-- .../live/retina-gke/.terraform.lock.hcl | 2 ++ test/multicloud/live/retina-gke/providers.tf | 4 ++-- .../live/retina-kind/.terraform.lock.hcl | 20 +------------------ test/multicloud/live/retina-kind/providers.tf | 6 +----- test/multicloud/modules/aks/provider.tf | 4 ++-- test/multicloud/modules/gke/provider.tf | 4 ++-- test/multicloud/modules/kind/provider.tf | 2 +- 9 files changed, 14 insertions(+), 35 deletions(-) diff --git a/test/multicloud/.gitignore b/test/multicloud/.gitignore index 7df4bdc931..e9552db743 100644 --- a/test/multicloud/.gitignore +++ b/test/multicloud/.gitignore @@ -2,6 +2,5 @@ terraform.tfvars .terraform terraform.tfstate *terraform.tfstate.* -kubeconfig.yaml service-key.json -kubeconfig.yaml \ No newline at end of file +mc-kind-config diff --git a/test/multicloud/live/retina-aks/providers.tf b/test/multicloud/live/retina-aks/providers.tf index 2d19ff792b..264d724c95 100644 --- a/test/multicloud/live/retina-aks/providers.tf +++ b/test/multicloud/live/retina-aks/providers.tf @@ -1,9 +1,9 @@ terraform { - required_version = ">= 1.0.0" + required_version = "1.8.3" required_providers { azurerm = { source = "hashicorp/azurerm" - version = ">= 2.0.0" + version = "4.15.0" } helm = { source = "hashicorp/helm" diff --git a/test/multicloud/live/retina-gke/.terraform.lock.hcl b/test/multicloud/live/retina-gke/.terraform.lock.hcl index 9b2ad80a97..ed3aacfe1c 100644 --- a/test/multicloud/live/retina-gke/.terraform.lock.hcl +++ b/test/multicloud/live/retina-gke/.terraform.lock.hcl @@ -6,6 +6,7 @@ provider "registry.opentofu.org/hashicorp/google" { constraints = ">= 6.17.0" hashes = [ "h1:7m+L8x7ClWUFAd4uJJENXp9O4K8HtpL50434jPR9pqs=", + "h1:aZkLSXbqbNThCCLAX1x0g8KTJANQAIosYq3xpy8JhFQ=", "zh:0614cc52deb5914795253aecf19b4cbb5aa7e8a186839a33907ce5c35e23d537", "zh:0b28ea31ec3b119aafc4c37a5992c29266c876db288dfc5bbfbde36631a533f1", "zh:1b2c5df40ac55ec7c3db2b7c556ace7545fca4ccfacf605b7588a4e2be564ba8", @@ -23,6 +24,7 @@ provider "registry.opentofu.org/hashicorp/helm" { version = "2.17.0" constraints = "2.17.0" hashes = [ + "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", diff --git a/test/multicloud/live/retina-gke/providers.tf b/test/multicloud/live/retina-gke/providers.tf index 313da6ab99..ac23c59c0e 100644 --- a/test/multicloud/live/retina-gke/providers.tf +++ b/test/multicloud/live/retina-gke/providers.tf @@ -1,9 +1,9 @@ terraform { - required_version = ">= 1.0.0" + required_version = "1.8.3" required_providers { google = { source = "hashicorp/google" - version = ">= 6.17.0" + version = "6.17.0" } helm = { source = "hashicorp/helm" diff --git a/test/multicloud/live/retina-kind/.terraform.lock.hcl b/test/multicloud/live/retina-kind/.terraform.lock.hcl index 0a5f2baaa1..afc28ace1d 100644 --- a/test/multicloud/live/retina-kind/.terraform.lock.hcl +++ b/test/multicloud/live/retina-kind/.terraform.lock.hcl @@ -20,30 +20,12 @@ provider "registry.opentofu.org/hashicorp/helm" { ] } -provider "registry.opentofu.org/hashicorp/local" { - version = "2.5.2" - constraints = "2.5.2" - hashes = [ - "h1:6lS+5A/4WFAqY3/RHWFRBSiFVLPRjvLaUgxPQvjXLHU=", - "h1:MBgBjJljfDl1i2JPcIoH4hW+2XLJ+D1l12iH/xd3uTo=", - "zh:25b95b76ceaa62b5c95f6de2fa6e6242edbf51e7fc6c057b7f7101aa4081f64f", - "zh:3c974fdf6b42ca6f93309cf50951f345bfc5726ec6013b8832bcd3be0eb3429e", - "zh:5de843bf6d903f5cca97ce1061e2e06b6441985c68d013eabd738a9e4b828278", - "zh:86beead37c7b4f149a54d2ae633c99ff92159c748acea93ff0f3603d6b4c9f4f", - "zh:8e52e81d3dc50c3f79305d257da7fde7af634fed65e6ab5b8e214166784a720e", - "zh:9882f444c087c69559873b2d72eec406a40ede21acb5ac334d6563bf3a2387df", - "zh:a4484193d110da4a06c7bffc44cc6b61d3b5e881cd51df2a83fdda1a36ea25d2", - "zh:a53342426d173e29d8ee3106cb68abecdf4be301a3f6589e4e8d42015befa7da", - "zh:d25ef2aef6a9004363fc6db80305d30673fc1f7dd0b980d41d863b12dacd382a", - "zh:fa2d522fb323e2121f65b79709fd596514b293d816a1d969af8f72d108888e4c", - ] -} - provider "registry.opentofu.org/tehcyx/kind" { version = "0.7.0" constraints = "0.7.0" hashes = [ "h1:9ci1+3JBxvMRZ0pnzoVNmw7NrBCAfzqOPyhm+I8Rxag=", + "h1:nFhFHmE5+dCd9S9dEMwnMNWzyxoVipYobkhXYoDbhgA=", "zh:171a2fb0137bfbdebd56cd65afd2e0e2167315fe4cb6a07a218db40cb17339c3", "zh:3260b078b7997ddfd03845326ffaeed7f678eeaaf7918430356f22e299e36f22", "zh:4066ab3feb482a0dd1bfff6590d89a0ec30478f63c9d8253cfdadb4b8db2234d", diff --git a/test/multicloud/live/retina-kind/providers.tf b/test/multicloud/live/retina-kind/providers.tf index 6ecb335411..7b8baf2518 100644 --- a/test/multicloud/live/retina-kind/providers.tf +++ b/test/multicloud/live/retina-kind/providers.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0.0" + required_version = "1.8.3" required_providers { kind = { source = "tehcyx/kind" @@ -9,10 +9,6 @@ terraform { source = "hashicorp/helm" version = "2.17.0" } - local = { - source = "hashicorp/local" - version = "2.5.2" - } } } diff --git a/test/multicloud/modules/aks/provider.tf b/test/multicloud/modules/aks/provider.tf index 91f859c3d0..33705925cf 100644 --- a/test/multicloud/modules/aks/provider.tf +++ b/test/multicloud/modules/aks/provider.tf @@ -1,9 +1,9 @@ terraform { - required_version = ">= 1.0.0" + required_version = "1.8.3" required_providers { azurerm = { source = "hashicorp/azurerm" - version = ">= 2.0.0" + version = "4.15.0" } } } diff --git a/test/multicloud/modules/gke/provider.tf b/test/multicloud/modules/gke/provider.tf index d0fb68a508..dbf7e91ddc 100644 --- a/test/multicloud/modules/gke/provider.tf +++ b/test/multicloud/modules/gke/provider.tf @@ -1,9 +1,9 @@ terraform { - required_version = ">= 1.0.0" + required_version = "1.8.3" required_providers { google = { source = "hashicorp/google" - version = ">= 6.17.0" + version = "6.17.0" } } } \ No newline at end of file diff --git a/test/multicloud/modules/kind/provider.tf b/test/multicloud/modules/kind/provider.tf index aaa6ec7f40..9a655cac22 100644 --- a/test/multicloud/modules/kind/provider.tf +++ b/test/multicloud/modules/kind/provider.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0.0" + required_version = "1.8.3" required_providers { kind = { source = "tehcyx/kind" From 52f0acd506587870f1bce5fcf0940b4b1f2a9781 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 15:37:20 +0000 Subject: [PATCH 06/18] test(mc): add terratest and GH workflow --- .github/workflows/test-multicloud.yml | 25 +++++++ test/multicloud/Makefile | 8 ++- .../examples/aks/.terraform.lock.hcl | 20 ++++++ test/multicloud/examples/aks/main.tf | 7 ++ test/multicloud/examples/aks/providers.tf | 20 ++++++ test/multicloud/examples/aks/variables.tf | 29 +++++++++ .../examples/gke/.terraform.lock.hcl | 20 ++++++ test/multicloud/examples/gke/main.tf | 7 ++ test/multicloud/examples/gke/providers.tf | 15 +++++ test/multicloud/examples/gke/variables.tf | 19 ++++++ .../examples/kind/.terraform.lock.hcl | 16 +++++ test/multicloud/examples/kind/main.tf | 4 ++ test/multicloud/examples/kind/providers.tf | 12 ++++ .../multicloud/examples/kind/test-kind-config | 3 + test/multicloud/examples/kind/variables.tf | 4 ++ test/multicloud/live/retina-kind/main.tf | 9 --- test/multicloud/test/example_aks_test.go | 38 +++++++++++ test/multicloud/test/example_gke_test.go | 32 +++++++++ test/multicloud/test/example_kind_test.go | 27 ++++++++ test/multicloud/test/go.mod | 38 +++++++++++ test/multicloud/test/go.sum | 65 +++++++++++++++++++ 21 files changed, 406 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/test-multicloud.yml create mode 100644 test/multicloud/examples/aks/.terraform.lock.hcl create mode 100644 test/multicloud/examples/aks/main.tf create mode 100644 test/multicloud/examples/aks/providers.tf create mode 100644 test/multicloud/examples/aks/variables.tf create mode 100644 test/multicloud/examples/gke/.terraform.lock.hcl create mode 100644 test/multicloud/examples/gke/main.tf create mode 100644 test/multicloud/examples/gke/providers.tf create mode 100644 test/multicloud/examples/gke/variables.tf create mode 100644 test/multicloud/examples/kind/.terraform.lock.hcl create mode 100644 test/multicloud/examples/kind/main.tf create mode 100644 test/multicloud/examples/kind/providers.tf create mode 100644 test/multicloud/examples/kind/test-kind-config create mode 100644 test/multicloud/examples/kind/variables.tf create mode 100644 test/multicloud/test/example_aks_test.go create mode 100644 test/multicloud/test/example_gke_test.go create mode 100644 test/multicloud/test/example_kind_test.go create mode 100644 test/multicloud/test/go.mod create mode 100644 test/multicloud/test/go.sum diff --git a/.github/workflows/test-multicloud.yml b/.github/workflows/test-multicloud.yml new file mode 100644 index 0000000000..3501cabf88 --- /dev/null +++ b/.github/workflows/test-multicloud.yml @@ -0,0 +1,25 @@ +name: Test Multicloud + +on: + pull_request: + paths: + - 'test/multicloud/**' + +jobs: + multicloud-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: '1.23' + + - name: Install dependencies + run: go mod download + + - name: Run tests + run: make test \ No newline at end of file diff --git a/test/multicloud/Makefile b/test/multicloud/Makefile index 2ee40c30c5..715e86ec2f 100644 --- a/test/multicloud/Makefile +++ b/test/multicloud/Makefile @@ -1,6 +1,8 @@ PREFIX ?= retina STACK_NAME ?= $(PREFIX)-aks +.PHONY: init plan apply quick gke aks kind destroy clean kind-kubeconfig test + plan: cd live/$(STACK_NAME) && \ tofu fmt && tofu init && tofu plan @@ -32,9 +34,9 @@ destroy: clean: destroy @cd live/$(STACK_NAME) && \ rm -rf .terraform && rm terraform.tfstate && rm terraform.tfstate.backup - @if [ $(STACK_NAME) == $(PREFIX)-kind ]; then \ - rm -rf live/$(STACK_NAME)/mc-kind-config; \ - fi kind-kubeconfig: @kubectl config set-context live/$(PREFIX)-kind/mc-kind-config + +test: + @cd test && go test -v -count=1 -timeout 30m ./... diff --git a/test/multicloud/examples/aks/.terraform.lock.hcl b/test/multicloud/examples/aks/.terraform.lock.hcl new file mode 100644 index 0000000000..3d7443dac3 --- /dev/null +++ b/test/multicloud/examples/aks/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/azurerm" { + version = "4.15.0" + constraints = "4.15.0" + hashes = [ + "h1:xE74Yb3iZZF2F1hQy4B8YVCk0gLAp99pJgZX4eIXYMg=", + "zh:0a104acfc45de410d9786bdbf540009dbb7db5632fe7c6846fdb5f865007d0b4", + "zh:186f20452ca913e84de0fc9b2dc7872c6480813afe11ea076bd60c45aa2d66d0", + "zh:2d540a98254188f17d64c02847e4d178b49979871a2a05283f78d336f3f25d45", + "zh:34fdffad86800af74dd2f4c9b3a32fb4f1463ba453bb0f634a9389f503869bc6", + "zh:38751b0bb8d03c34acb63dbddf6ebe01d99e6b75a9d94ae3b3fb1c60bf43c45a", + "zh:4234e0e56e87983d387d7323d8bb49838054c5cebeb121dbb5aa4dd3255f211f", + "zh:4ead322049485495d07afe2334d82a47997fc7638b9e39512000d4499dc3a782", + "zh:74e8a9fdfbe0bb91c6542176dc14d3e95be2c3c77cca10ae57aa67116b5a6b95", + "zh:9f03e13551cd68d2f7cd2d46f74ffc33f0656e0aa8c9095ed259385aaeaf4957", + "zh:f86fce72cbdf72f52412b9099023115bece67c5df55970c4429ef0f1bdc3c473", + ] +} diff --git a/test/multicloud/examples/aks/main.tf b/test/multicloud/examples/aks/main.tf new file mode 100644 index 0000000000..d9bf43381a --- /dev/null +++ b/test/multicloud/examples/aks/main.tf @@ -0,0 +1,7 @@ +module "aks" { + source = "../../modules/aks" + location = var.location + resource_group_name = var.resource_group_name + prefix = var.prefix + labels = var.labels +} diff --git a/test/multicloud/examples/aks/providers.tf b/test/multicloud/examples/aks/providers.tf new file mode 100644 index 0000000000..8ec4828f25 --- /dev/null +++ b/test/multicloud/examples/aks/providers.tf @@ -0,0 +1,20 @@ +terraform { + required_version = "1.8.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.15.0" + } + } +} + +# Initialize the Azure provider +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } + subscription_id = var.subscription_id + tenant_id = var.tenant_id +} diff --git a/test/multicloud/examples/aks/variables.tf b/test/multicloud/examples/aks/variables.tf new file mode 100644 index 0000000000..1e5a2140d7 --- /dev/null +++ b/test/multicloud/examples/aks/variables.tf @@ -0,0 +1,29 @@ +variable "subscription_id" { + description = "The subscription ID for the Azure account." + type = string +} + +variable "tenant_id" { + description = "The tenant ID for the Azure account." + type = string +} + +variable "location" { + description = "The Azure Cloud location where AKS will be deployed to." + type = string +} + +variable "resource_group_name" { + description = "The name of the resource group." + type = string +} + +variable "prefix" { + description = "A prefix to add to all resources." + type = string +} + +variable "labels" { + description = "A map of labels to add to all resources." + type = map(string) +} diff --git a/test/multicloud/examples/gke/.terraform.lock.hcl b/test/multicloud/examples/gke/.terraform.lock.hcl new file mode 100644 index 0000000000..f110175d5e --- /dev/null +++ b/test/multicloud/examples/gke/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/google" { + version = "6.17.0" + constraints = "6.17.0" + hashes = [ + "h1:aZkLSXbqbNThCCLAX1x0g8KTJANQAIosYq3xpy8JhFQ=", + "zh:0614cc52deb5914795253aecf19b4cbb5aa7e8a186839a33907ce5c35e23d537", + "zh:0b28ea31ec3b119aafc4c37a5992c29266c876db288dfc5bbfbde36631a533f1", + "zh:1b2c5df40ac55ec7c3db2b7c556ace7545fca4ccfacf605b7588a4e2be564ba8", + "zh:1db9a278cfddcaa7d9119acf231164438df07932bdabce95931a68bd3689cd39", + "zh:3729b7a9936f5ad545f7d06d11d05ce78b4bbe9941e77bf004a2b798e6a0866c", + "zh:3b7e35183a8d7980207ae7d082c490d7c2270f907e5de9e8393c6c4c32b07b3c", + "zh:581e14963dfef608285af0c08ccb5da4bdb8ae049366418d4863a4fd9fa55b74", + "zh:89d29f2d1269a30c6149bbaaae3cbe8fe0c6ed13874b77bf784ea6bbd73aee58", + "zh:c7c690c1f9fe0cbc69d4eb21727f2cf4b7ba016385184d27527d570832c393be", + "zh:dc1536fc325a0561bf0f606a38bed29e8dd2f4bec6d6e8a5301696d89c1c8079", + ] +} diff --git a/test/multicloud/examples/gke/main.tf b/test/multicloud/examples/gke/main.tf new file mode 100644 index 0000000000..88677ecbbb --- /dev/null +++ b/test/multicloud/examples/gke/main.tf @@ -0,0 +1,7 @@ +module "gke" { + source = "../../modules/gke" + location = var.location + prefix = var.prefix + project = var.project + machine_type = var.machine_type +} diff --git a/test/multicloud/examples/gke/providers.tf b/test/multicloud/examples/gke/providers.tf new file mode 100644 index 0000000000..f1423d15d9 --- /dev/null +++ b/test/multicloud/examples/gke/providers.tf @@ -0,0 +1,15 @@ +terraform { + required_version = "1.8.3" + required_providers { + google = { + source = "hashicorp/google" + version = "6.17.0" + } + } +} + +# Initialize the Google provider +provider "google" { + project = var.project + region = var.location +} diff --git a/test/multicloud/examples/gke/variables.tf b/test/multicloud/examples/gke/variables.tf new file mode 100644 index 0000000000..2e2da23167 --- /dev/null +++ b/test/multicloud/examples/gke/variables.tf @@ -0,0 +1,19 @@ +variable "project" { + description = "The Google Cloud project where resources will be deployed." + type = string +} + +variable "location" { + description = "The Google Cloud location where GKE will be deployed to." + type = string +} + +variable "prefix" { + description = "A prefix to add to all resources." + type = string +} + +variable "machine_type" { + description = "The machine type to use for the GKE nodes." + type = string +} diff --git a/test/multicloud/examples/kind/.terraform.lock.hcl b/test/multicloud/examples/kind/.terraform.lock.hcl new file mode 100644 index 0000000000..b610e36285 --- /dev/null +++ b/test/multicloud/examples/kind/.terraform.lock.hcl @@ -0,0 +1,16 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/tehcyx/kind" { + version = "0.7.0" + constraints = "0.7.0" + hashes = [ + "h1:nFhFHmE5+dCd9S9dEMwnMNWzyxoVipYobkhXYoDbhgA=", + "zh:171a2fb0137bfbdebd56cd65afd2e0e2167315fe4cb6a07a218db40cb17339c3", + "zh:3260b078b7997ddfd03845326ffaeed7f678eeaaf7918430356f22e299e36f22", + "zh:4066ab3feb482a0dd1bfff6590d89a0ec30478f63c9d8253cfdadb4b8db2234d", + "zh:537af73261d53f4840d1f89d8e5835c52ddb97102e6314f6aea9b8e49c43d610", + "zh:d63e94d828ba0339600d992b0a6695cff939b0aaac1c39b31d38e3c4f3823674", + "zh:f971c617bf6b37d07a5042f13a9ab02b42d0ceb14934174eecc81abeec233c40", + ] +} diff --git a/test/multicloud/examples/kind/main.tf b/test/multicloud/examples/kind/main.tf new file mode 100644 index 0000000000..c2484af1cb --- /dev/null +++ b/test/multicloud/examples/kind/main.tf @@ -0,0 +1,4 @@ +module "kind" { + source = "../../modules/kind" + prefix = var.prefix +} \ No newline at end of file diff --git a/test/multicloud/examples/kind/providers.tf b/test/multicloud/examples/kind/providers.tf new file mode 100644 index 0000000000..23178d677b --- /dev/null +++ b/test/multicloud/examples/kind/providers.tf @@ -0,0 +1,12 @@ +terraform { + required_version = "1.8.3" + required_providers { + kind = { + source = "tehcyx/kind" + version = "0.7.0" + } + } +} + +# Initialize the kind provider +provider "kind" {} diff --git a/test/multicloud/examples/kind/test-kind-config b/test/multicloud/examples/kind/test-kind-config new file mode 100644 index 0000000000..2ebf5e0ed5 --- /dev/null +++ b/test/multicloud/examples/kind/test-kind-config @@ -0,0 +1,3 @@ +apiVersion: v1 +kind: Config +preferences: {} diff --git a/test/multicloud/examples/kind/variables.tf b/test/multicloud/examples/kind/variables.tf new file mode 100644 index 0000000000..2dd9eaf4b0 --- /dev/null +++ b/test/multicloud/examples/kind/variables.tf @@ -0,0 +1,4 @@ +variable "prefix" { + description = "A prefix to add to all resources." + type = string +} \ No newline at end of file diff --git a/test/multicloud/live/retina-kind/main.tf b/test/multicloud/live/retina-kind/main.tf index 2d86438f6c..6f71163ccf 100644 --- a/test/multicloud/live/retina-kind/main.tf +++ b/test/multicloud/live/retina-kind/main.tf @@ -7,12 +7,3 @@ module "retina" { depends_on = [module.kind] source = "../../modules/retina" } - -# output "kubeconfig" { -# value = module.kind.kubeconfig -# } - -# resource "local_file" "kubeconfig" { -# content = module.kind.kubeconfig -# filename = "${path.module}/kubeconfig.yaml" -# } diff --git a/test/multicloud/test/example_aks_test.go b/test/multicloud/test/example_aks_test.go new file mode 100644 index 0000000000..7bbdf6fa4d --- /dev/null +++ b/test/multicloud/test/example_aks_test.go @@ -0,0 +1,38 @@ +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func TestAKSExample(t *testing.T) { + t.Parallel() + + opts := &terraform.Options{ + TerraformDir: "../examples/aks", + + Vars: map[string]interface{}{ + "prefix": "test", + "location": "uksouth", + "subscription_id": "d6050d84-e4dd-463d-afc7-a6ab3dc33ab7", // TODO: replace with actual project once we get azure "public" access + "tenant_id": "ac8a4ccd-35f1-4f95-a688-f68e3d89adfc", + "resource_group_name": "test", + "labels": map[string]string{ + "environment": "test", + "owner": "test", + "project": "test", + }, + }, + } + + // clean up at the end of the test + defer terraform.Destroy(t, opts) + + terraform.Init(t, opts) + + // TODO: uncomment once we get creds for azure "public" + // terraform.Apply(t, opts) + + // TODO: add actual tests here +} diff --git a/test/multicloud/test/example_gke_test.go b/test/multicloud/test/example_gke_test.go new file mode 100644 index 0000000000..9c0ac4e0f8 --- /dev/null +++ b/test/multicloud/test/example_gke_test.go @@ -0,0 +1,32 @@ +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func TestGKEExample(t *testing.T) { + t.Parallel() + + opts := &terraform.Options{ + TerraformDir: "../examples/gke", + + Vars: map[string]interface{}{ + "prefix": "test", + "location": "eu-central1", + "project": "mc-retina", // TODO: replace with actual project once we get gcloud access + "machine_type": "e2-standard-4", + }, + } + + // clean up at the end of the test + defer terraform.Destroy(t, opts) + + terraform.Init(t, opts) + + // TODO: uncomment once we get creds for gcloud + // terraform.Apply(t, opts) + + // TODO: add actual tests here +} diff --git a/test/multicloud/test/example_kind_test.go b/test/multicloud/test/example_kind_test.go new file mode 100644 index 0000000000..c53fb09e84 --- /dev/null +++ b/test/multicloud/test/example_kind_test.go @@ -0,0 +1,27 @@ +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func TestKindExample(t *testing.T) { + t.Parallel() + + opts := &terraform.Options{ + TerraformDir: "../examples/kind", + + Vars: map[string]interface{}{ + "prefix": "test", + }, + } + + // clean up at the end of the test + defer terraform.Destroy(t, opts) + + terraform.Init(t, opts) + terraform.Apply(t, opts) + + // TODO: add actual tests here +} diff --git a/test/multicloud/test/go.mod b/test/multicloud/test/go.mod new file mode 100644 index 0000000000..ae4189f910 --- /dev/null +++ b/test/multicloud/test/go.mod @@ -0,0 +1,38 @@ +module github.com/microsoft/retina/test/multicloud/test + +go 1.23.4 + +require ( + github.com/agext/levenshtein v1.2.3 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gruntwork-io/terratest v0.48.1 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter/v2 v2.2.3 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/hashicorp/hcl/v2 v2.22.0 // indirect + github.com/hashicorp/terraform-json v0.23.0 // indirect + github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/tmccombs/hcl2json v0.6.4 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/zclconf/go-cty v1.15.0 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.22.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/test/multicloud/test/go.sum b/test/multicloud/test/go.sum new file mode 100644 index 0000000000..cc74f71e43 --- /dev/null +++ b/test/multicloud/test/go.sum @@ -0,0 +1,65 @@ +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gruntwork-io/terratest v0.48.1 h1:pnydDjkWbZCUYXvQkr24y21fBo8PfJC5hRGdwbl1eXM= +github.com/gruntwork-io/terratest v0.48.1/go.mod h1:U2EQW4Odlz75XJUH16Kqkr9c93p+ZZtkpVez7GkZFa4= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk= +github.com/hashicorp/go-getter/v2 v2.2.3/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M= +github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= +github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI= +github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= +github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 h1:ofNAzWCcyTALn2Zv40+8XitdzCgXY6e9qvXwN9W0YXg= +github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tmccombs/hcl2json v0.6.4 h1:/FWnzS9JCuyZ4MNwrG4vMrFrzRgsWEOVi+1AyYUVLGw= +github.com/tmccombs/hcl2json v0.6.4/go.mod h1:+ppKlIW3H5nsAsZddXPy2iMyvld3SHxyjswOZhavRDk= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= +github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From ae2d0acd099e969614a4a0857954ed0cc4d60f6d Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 15:41:35 +0000 Subject: [PATCH 07/18] test(mc): fix working dir for mc GH workflow --- .github/workflows/test-multicloud.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-multicloud.yml b/.github/workflows/test-multicloud.yml index 3501cabf88..4073bcc3c4 100644 --- a/.github/workflows/test-multicloud.yml +++ b/.github/workflows/test-multicloud.yml @@ -20,6 +20,8 @@ jobs: - name: Install dependencies run: go mod download + working-directory: test/multicloud/ - name: Run tests - run: make test \ No newline at end of file + run: make test + working-directory: test/multicloud/ \ No newline at end of file From 63c4bf09e4b561996a8ccbf31bfaed8cc6fa8a1a Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 15:45:45 +0000 Subject: [PATCH 08/18] test(mc): add setup-opentofu to GH workflow --- .github/workflows/test-multicloud.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test-multicloud.yml b/.github/workflows/test-multicloud.yml index 4073bcc3c4..6281341efb 100644 --- a/.github/workflows/test-multicloud.yml +++ b/.github/workflows/test-multicloud.yml @@ -10,6 +10,10 @@ jobs: runs-on: ubuntu-latest steps: + - uses: opentofu/setup-opentofu@v1 + with: + tofu_version: 1.8.3 + - name: Checkout code uses: actions/checkout@v2 From 4233201521512fd66a503656dea8a32722babe32 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Fri, 24 Jan 2025 17:12:02 +0000 Subject: [PATCH 09/18] test(mc): add reference to terratest --- test/multicloud/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/multicloud/README.md b/test/multicloud/README.md index b0d7f5c698..1986a37126 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -77,6 +77,14 @@ export STACK_NAME=retina-aks make clean ``` +### Test + +The test framework is levergaing Go and [Terratest](https://terratest.gruntwork.io/docs/). To run tests: + +```sh +make test +``` + ## Providers references * [GKE resource documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster) From f3e2e6f562f1590df3b0f643c99522d5f7aab2c4 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 09:57:21 +0000 Subject: [PATCH 10/18] test(mc): add architecture diagram --- test/multicloud/README.md | 2 + test/multicloud/diagrams/diagram.excalidraw | 3366 +++++++++++++++++++ test/multicloud/diagrams/diagram.svg | 2 + 3 files changed, 3370 insertions(+) create mode 100644 test/multicloud/diagrams/diagram.excalidraw create mode 100644 test/multicloud/diagrams/diagram.svg diff --git a/test/multicloud/README.md b/test/multicloud/README.md index 1986a37126..70cb159719 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -2,6 +2,8 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructure as Code (IaC) to create Kubernetes infrastructure on multi-cloud and deploy [microsoft/retina](https://github.com/microsoft/retina) via Helm provider. +![Architecture Diagram](./diagrams/diagram.svg) + ## Modules available * [aks](./modules/aks/) diff --git a/test/multicloud/diagrams/diagram.excalidraw b/test/multicloud/diagrams/diagram.excalidraw new file mode 100644 index 0000000000..8049513551 --- /dev/null +++ b/test/multicloud/diagrams/diagram.excalidraw @@ -0,0 +1,3366 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "zghIcLCzAMCMHoPa6KCP5", + "type": "rectangle", + "x": 919, + "y": 483, + "width": 286, + "height": 426, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "Zw", + "roundness": { + "type": 3 + }, + "seed": 618936138, + "version": 144, + "versionNonce": 1644653718, + "isDeleted": false, + "boundElements": [ + { + "id": "o_HSEmb0pecqRgBJDEBRp", + "type": "arrow" + }, + { + "id": "RBNxQ4pEgxmBXnHdIaBf9", + "type": "arrow" + }, + { + "id": "xhoCMjoiXLgPLJUmc7WuE", + "type": "arrow" + } + ], + "updated": 1737971092328, + "link": null, + "locked": false + }, + { + "id": "0S628Xmv8YIAFSDx8-05e", + "type": "rectangle", + "x": 1343, + "y": 443, + "width": 311, + "height": 503, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "Zx", + "roundness": { + "type": 3 + }, + "seed": 1054405910, + "version": 48, + "versionNonce": 564948438, + "isDeleted": false, + "boundElements": [ + { + "id": "HYF4G_hkcZFNdgAl0YQNb", + "type": "arrow" + }, + { + "id": "-4dHrHQZE2TDSvs-vgcAo", + "type": "arrow" + }, + { + "id": "o_HSEmb0pecqRgBJDEBRp", + "type": "arrow" + } + ], + "updated": 1737971037967, + "link": null, + "locked": false + }, + { + "id": "uLVKBxcndIG-qzR2NQnMF", + "type": "rectangle", + "x": 1854.5, + "y": 915.5, + "width": 311, + "height": 365.00000000000006, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "Zy", + "roundness": { + "type": 3 + }, + "seed": 1560720842, + "version": 336, + "versionNonce": 747983318, + "isDeleted": false, + "boundElements": [ + { + "id": "-4dHrHQZE2TDSvs-vgcAo", + "type": "arrow" + }, + { + "id": "RBNxQ4pEgxmBXnHdIaBf9", + "type": "arrow" + } + ], + "updated": 1737971057148, + "link": null, + "locked": false + }, + { + "id": "R4AeEioM2INhMP9rnYnHe", + "type": "rectangle", + "x": 1856.5, + "y": 347.5, + "width": 311, + "height": 503, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "Zz", + "roundness": { + "type": 3 + }, + "seed": 719699734, + "version": 234, + "versionNonce": 37331222, + "isDeleted": false, + "boundElements": [ + { + "id": "r_IiMCnJET5n-m5aE4N6J", + "type": "arrow" + }, + { + "id": "HYF4G_hkcZFNdgAl0YQNb", + "type": "arrow" + }, + { + "id": "xhoCMjoiXLgPLJUmc7WuE", + "type": "arrow" + }, + { + "id": "1G4RvWl5j3Eq0orLwRNb1", + "type": "arrow" + }, + { + "id": "JenUnqPQU9n29FUsRjstV", + "type": "arrow" + } + ], + "updated": 1737971550725, + "link": null, + "locked": false + }, + { + "id": "zXqDMrjv50TU6s8f0xi2s", + "type": "rectangle", + "x": 1847.078125, + "y": -36, + "width": 231.859375, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0y", + "roundness": null, + "seed": 886375254, + "version": 125, + "versionNonce": 425608714, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Eh9WaurLCaoIoY157lFTc" + }, + { + "id": "sSBpGKS5X6pi-Hat4HUBJ", + "type": "arrow" + }, + { + "id": "WlzkJ1a1P1Er7kfA1RP4T", + "type": "arrow" + } + ], + "updated": 1737971176481, + "link": null, + "locked": false + }, + { + "id": "O4E1OnJgXZMVXYZqcHbbf", + "type": "rectangle", + "x": 1881.3203125, + "y": 58, + "width": 163.375, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0z", + "roundness": null, + "seed": 558246038, + "version": 234, + "versionNonce": 1718596042, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "iafWgom0hD1fD-mok9szu" + }, + { + "id": "sSBpGKS5X6pi-Hat4HUBJ", + "type": "arrow" + }, + { + "id": "TxfM-J3QLXhdIlqgtcSp3", + "type": "arrow" + }, + { + "id": "r_IiMCnJET5n-m5aE4N6J", + "type": "arrow" + }, + { + "id": "J_prQC5yc7ywuZigF71Wh", + "type": "arrow" + } + ], + "updated": 1737971184547, + "link": null, + "locked": false + }, + { + "id": "ysLRakRFsF7DlEwBVIfpv", + "type": "rectangle", + "x": 2444.4140625, + "y": 74, + "width": 225.65625, + "height": 60, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b12", + "roundness": null, + "seed": 1464182870, + "version": 847, + "versionNonce": 1974440970, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "UoF1VeVtOBF-B_pHGbkiD" + }, + { + "id": "WlzkJ1a1P1Er7kfA1RP4T", + "type": "arrow" + }, + { + "id": "EL7fKQS2Z0a_heFdNlDpe", + "type": "arrow" + }, + { + "id": "-FO1qNsJmZSIC7MG10S17", + "type": "arrow" + } + ], + "updated": 1737971476328, + "link": null, + "locked": false + }, + { + "id": "9pGuk9pLc645Jva07NwPP", + "type": "rectangle", + "x": 1417.08984375, + "y": 503, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b13", + "roundness": null, + "seed": 1482304918, + "version": 54, + "versionNonce": 1221402454, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "n6fgzgLn1UV2wrjYVoVDr" + } + ], + "updated": 1737970947812, + "link": null, + "locked": false + }, + { + "id": "nlTAqIR7zMcS6PGUnUiPG", + "type": "rectangle", + "x": 1420.06640625, + "y": 704, + "width": 154.921875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b14", + "roundness": null, + "seed": 1730939606, + "version": 93, + "versionNonce": 1874844694, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "RK06UCyMyn_5XDjMl8d_D" + } + ], + "updated": 1737970950262, + "link": null, + "locked": false + }, + { + "id": "fz7IX_5gQKgv9w7KWCF9F", + "type": "rectangle", + "x": 1415.05078125, + "y": 796, + "width": 173.296875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b15", + "roundness": null, + "seed": 307249174, + "version": 137, + "versionNonce": 234210442, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "kgSbIGb4Oi7kNTwp2QkrU" + } + ], + "updated": 1737970951221, + "link": null, + "locked": false + }, + { + "id": "oKOWo7KV9Y8J3AQR1lX-P", + "type": "rectangle", + "x": 989.09765625, + "y": 805, + "width": 153.20312500000003, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1C", + "roundness": null, + "seed": 2062767318, + "version": 226, + "versionNonce": 700710410, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "YBOf_ZI3--rqMICNXDl5o" + } + ], + "updated": 1737970946099, + "link": null, + "locked": false + }, + { + "id": "xPpUhfUnNbsMPlojZlr0W", + "type": "rectangle", + "x": 980.1328125, + "y": 543, + "width": 162.078125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "klCQzqbRxuqhJ44QC9Oku" + ], + "frameId": null, + "index": "b1E", + "roundness": null, + "seed": 1538824022, + "version": 267, + "versionNonce": 763874250, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "03ZfRAoP-dkIsVdwuMcGm" + } + ], + "updated": 1737970941082, + "link": null, + "locked": false + }, + { + "id": "sSBpGKS5X6pi-Hat4HUBJ", + "type": "arrow", + "x": 1963.00803125, + "y": 8.5, + "width": 0, + "height": 43.699999999999996, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1F", + "roundness": { + "type": 2 + }, + "seed": 1318534294, + "version": 467, + "versionNonce": 2147339786, + "isDeleted": false, + "boundElements": [], + "updated": 1737971184547, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 43.699999999999996 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "zXqDMrjv50TU6s8f0xi2s", + "focus": -0.000001886919603150646, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "O4E1OnJgXZMVXYZqcHbbf", + "focus": 0.0000026778882929564303, + "gap": 5.799999999999997, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Eh9WaurLCaoIoY157lFTc", + "type": "text", + "x": 1869.5478744506836, + "y": -26.5, + "width": 186.9198760986328, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1Z", + "roundness": null, + "seed": 570447254, + "version": 124, + "versionNonce": 1946965270, + "isDeleted": false, + "boundElements": [], + "updated": 1737970467013, + "link": null, + "locked": false, + "text": "Multi-Cloud Project", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "zXqDMrjv50TU6s8f0xi2s", + "originalText": "Multi-Cloud Project", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "iafWgom0hD1fD-mok9szu", + "type": "text", + "x": 1893.917854309082, + "y": 67.5, + "width": 138.17991638183594, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1a", + "roundness": null, + "seed": 1775055574, + "version": 225, + "versionNonce": 1441458314, + "isDeleted": false, + "boundElements": [], + "updated": 1737971184547, + "link": null, + "locked": false, + "text": "OpenTofu IaC", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "O4E1OnJgXZMVXYZqcHbbf", + "originalText": "OpenTofu IaC", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "UoF1VeVtOBF-B_pHGbkiD", + "type": "text", + "x": 2499.9722213745117, + "y": 79, + "width": 114.53993225097656, + "height": 50, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1d", + "roundness": null, + "seed": 404085398, + "version": 838, + "versionNonce": 911934358, + "isDeleted": false, + "boundElements": [], + "updated": 1737971223954, + "link": null, + "locked": false, + "text": "GO Testing\nFramework", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ysLRakRFsF7DlEwBVIfpv", + "originalText": "GO Testing Framework", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "n6fgzgLn1UV2wrjYVoVDr", + "type": "text", + "x": 1465.7064208984375, + "y": 512.5, + "width": 46.219970703125, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1e", + "roundness": null, + "seed": 1827280854, + "version": 48, + "versionNonce": 2005438678, + "isDeleted": false, + "boundElements": [], + "updated": 1737970219802, + "link": null, + "locked": false, + "text": "AKS ", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "9pGuk9pLc645Jva07NwPP", + "originalText": "AKS ", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "RK06UCyMyn_5XDjMl8d_D", + "type": "text", + "x": 1471.6273498535156, + "y": 713.5, + "width": 51.79998779296875, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1f", + "roundness": null, + "seed": 784641302, + "version": 94, + "versionNonce": 1999275926, + "isDeleted": false, + "boundElements": [], + "updated": 1737970228691, + "link": null, + "locked": false, + "text": "KIND", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "nlTAqIR7zMcS6PGUnUiPG", + "originalText": "KIND", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "kgSbIGb4Oi7kNTwp2QkrU", + "type": "text", + "x": 1469.239242553711, + "y": 805.5, + "width": 64.91995239257812, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1g", + "roundness": null, + "seed": 454728278, + "version": 136, + "versionNonce": 1384911050, + "isDeleted": false, + "boundElements": [], + "updated": 1737970238236, + "link": null, + "locked": false, + "text": "Retina", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fz7IX_5gQKgv9w7KWCF9F", + "originalText": "Retina", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "YBOf_ZI3--rqMICNXDl5o", + "type": "text", + "x": 1041.7192306518555, + "y": 814.5, + "width": 47.95997619628906, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1n", + "roundness": null, + "seed": 1108719382, + "version": 222, + "versionNonce": 1030092746, + "isDeleted": false, + "boundElements": [], + "updated": 1737970255474, + "link": null, + "locked": false, + "text": "Helm ", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "oKOWo7KV9Y8J3AQR1lX-P", + "originalText": "Helm ", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "03ZfRAoP-dkIsVdwuMcGm", + "type": "text", + "x": 1033.291893005371, + "y": 552.5, + "width": 55.75996398925781, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "klCQzqbRxuqhJ44QC9Oku" + ], + "frameId": null, + "index": "b1p", + "roundness": null, + "seed": 2128046486, + "version": 267, + "versionNonce": 1559104842, + "isDeleted": false, + "boundElements": [], + "updated": 1737970255474, + "link": null, + "locked": false, + "text": "Azure", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "xPpUhfUnNbsMPlojZlr0W", + "originalText": "Azure", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "U6X68vlOQPsistV7KGQj7", + "type": "rectangle", + "x": 982.9609375, + "y": 716, + "width": 162.078125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8IJVdH1tDYshWtx-RzqUy" + ], + "frameId": null, + "index": "b1u", + "roundness": null, + "seed": 1066099146, + "version": 321, + "versionNonce": 1510947478, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "n5AzOpyhjDk4cJALwlppo" + } + ], + "updated": 1737970944829, + "link": null, + "locked": false + }, + { + "id": "n5AzOpyhjDk4cJALwlppo", + "type": "text", + "x": 1038.1000061035156, + "y": 725.5, + "width": 51.79998779296875, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8IJVdH1tDYshWtx-RzqUy" + ], + "frameId": null, + "index": "b1v", + "roundness": null, + "seed": 1880135818, + "version": 337, + "versionNonce": 110019274, + "isDeleted": false, + "boundElements": [], + "updated": 1737970255474, + "link": null, + "locked": false, + "text": "KIND", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "U6X68vlOQPsistV7KGQj7", + "originalText": "KIND", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "6vHcegO-bhhAWthKg5DLF", + "type": "rectangle", + "x": 982.9609375, + "y": 632, + "width": 162.078125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "dBEY2fEZd5U8JDWibmeLQ" + ], + "frameId": null, + "index": "b1w", + "roundness": null, + "seed": 2042518742, + "version": 322, + "versionNonce": 2099680970, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "7FCUVEMtLqp4KBg0vB5g0" + } + ], + "updated": 1737970943673, + "link": null, + "locked": false + }, + { + "id": "7FCUVEMtLqp4KBg0vB5g0", + "type": "text", + "x": 1000.5100250244141, + "y": 641.5, + "width": 126.97994995117188, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "dBEY2fEZd5U8JDWibmeLQ" + ], + "frameId": null, + "index": "b1x", + "roundness": null, + "seed": 46682646, + "version": 338, + "versionNonce": 1151342666, + "isDeleted": false, + "boundElements": [], + "updated": 1737970255474, + "link": null, + "locked": false, + "text": "Google Cloud", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "6vHcegO-bhhAWthKg5DLF", + "originalText": "Google Cloud", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "cvMVx90aAz8Snv2pIMyEP", + "type": "rectangle", + "x": 1422.2734375, + "y": 610, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1y", + "roundness": null, + "seed": 504440010, + "version": 148, + "versionNonce": 1612320074, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "7x5KHRGKh6towsi_8LYpB" + } + ], + "updated": 1737970949157, + "link": null, + "locked": false + }, + { + "id": "7x5KHRGKh6towsi_8LYpB", + "type": "text", + "x": 1472.5700073242188, + "y": 619.5, + "width": 42.8599853515625, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1z", + "roundness": null, + "seed": 518388618, + "version": 144, + "versionNonce": 1811483594, + "isDeleted": false, + "boundElements": [], + "updated": 1737970242587, + "link": null, + "locked": false, + "text": "GKE", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cvMVx90aAz8Snv2pIMyEP", + "originalText": "GKE", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "w-30O_eesbT44MY2r9VIi", + "type": "text", + "x": 1544, + "y": 455, + "width": 76.61996459960938, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b21", + "roundness": null, + "seed": 274873098, + "version": 33, + "versionNonce": 344674902, + "isDeleted": false, + "boundElements": [ + { + "id": "TxfM-J3QLXhdIlqgtcSp3", + "type": "arrow" + } + ], + "updated": 1737970326763, + "link": null, + "locked": false, + "text": "Modules", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Modules", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "A19y-iFjO8jPxtueSWwhh", + "type": "text", + "x": 1090, + "y": 497, + "width": 92.65994262695312, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b23", + "roundness": null, + "seed": 1289638218, + "version": 41, + "versionNonce": 1506505930, + "isDeleted": false, + "boundElements": null, + "updated": 1737970297494, + "link": null, + "locked": false, + "text": "Providers", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Providers", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "TxfM-J3QLXhdIlqgtcSp3", + "type": "arrow", + "x": 1971.3696285377284, + "y": 103, + "width": 395.36962853772843, + "height": 341, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b28", + "roundness": { + "type": 2 + }, + "seed": 1369408406, + "version": 163, + "versionNonce": 1645571990, + "isDeleted": false, + "boundElements": null, + "updated": 1737971184547, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -395.36962853772843, + 341 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "O4E1OnJgXZMVXYZqcHbbf", + "focus": -0.32677741038380365, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "w-30O_eesbT44MY2r9VIi", + "focus": -0.8955844703788051, + "gap": 11, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "8AUKqnBI6Ff1R4wt0slqa", + "type": "rectangle", + "x": 1930.58984375, + "y": 407.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b29", + "roundness": null, + "seed": 1981592854, + "version": 231, + "versionNonce": 1503908374, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "eoIm4zi0FVKJOECWWL7TP" + } + ], + "updated": 1737970947812, + "link": null, + "locked": false + }, + { + "id": "Rg3n2f_ms7-kJ94iZVPrE", + "type": "rectangle", + "x": 1933.56640625, + "y": 608.5, + "width": 154.921875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2A", + "roundness": null, + "seed": 1244766806, + "version": 270, + "versionNonce": 1096754902, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "k5JMWXVEMnO8AA6zcZaht" + } + ], + "updated": 1737970950262, + "link": null, + "locked": false + }, + { + "id": "cK83p_ezogmd5Hf_eZwz2", + "type": "rectangle", + "x": 1928.55078125, + "y": 700.5, + "width": 173.296875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2B", + "roundness": null, + "seed": 1068951446, + "version": 314, + "versionNonce": 497421770, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "7ok5BbnOLbhPq6AgN4GYB" + } + ], + "updated": 1737970951221, + "link": null, + "locked": false + }, + { + "id": "eoIm4zi0FVKJOECWWL7TP", + "type": "text", + "x": 1979.2064208984375, + "y": 417, + "width": 46.219970703125, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2C", + "roundness": null, + "seed": 1994491094, + "version": 226, + "versionNonce": 1844995478, + "isDeleted": false, + "boundElements": [], + "updated": 1737970406988, + "link": null, + "locked": false, + "text": "AKS ", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "8AUKqnBI6Ff1R4wt0slqa", + "originalText": "AKS ", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "k5JMWXVEMnO8AA6zcZaht", + "type": "text", + "x": 1985.1273498535156, + "y": 618, + "width": 51.79998779296875, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2D", + "roundness": null, + "seed": 1095137814, + "version": 272, + "versionNonce": 543491414, + "isDeleted": false, + "boundElements": [], + "updated": 1737970406988, + "link": null, + "locked": false, + "text": "KIND", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Rg3n2f_ms7-kJ94iZVPrE", + "originalText": "KIND", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "7ok5BbnOLbhPq6AgN4GYB", + "type": "text", + "x": 1982.739242553711, + "y": 710, + "width": 64.91995239257812, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2E", + "roundness": null, + "seed": 1977272150, + "version": 314, + "versionNonce": 1165016342, + "isDeleted": false, + "boundElements": [], + "updated": 1737970406988, + "link": null, + "locked": false, + "text": "Retina", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cK83p_ezogmd5Hf_eZwz2", + "originalText": "Retina", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "BFUrWgvUgo1Tm7uLzxqJb", + "type": "rectangle", + "x": 1935.7734375, + "y": 514.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2F", + "roundness": null, + "seed": 1156803734, + "version": 325, + "versionNonce": 987000458, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "q3iv3crLU6YUmmSjnjJ7r" + } + ], + "updated": 1737970949157, + "link": null, + "locked": false + }, + { + "id": "q3iv3crLU6YUmmSjnjJ7r", + "type": "text", + "x": 1986.0700073242188, + "y": 524, + "width": 42.8599853515625, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2G", + "roundness": null, + "seed": 205875670, + "version": 322, + "versionNonce": 995265750, + "isDeleted": false, + "boundElements": [], + "updated": 1737970406989, + "link": null, + "locked": false, + "text": "GKE", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BFUrWgvUgo1Tm7uLzxqJb", + "originalText": "GKE", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "0zdoqgDRvg-ebTICP9SFX", + "type": "text", + "x": 2057.5, + "y": 359.5, + "width": 87.31996154785156, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2I", + "roundness": null, + "seed": 1430875222, + "version": 219, + "versionNonce": 1470198934, + "isDeleted": false, + "boundElements": [], + "updated": 1737970406989, + "link": null, + "locked": false, + "text": "Examples", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Examples", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "2YGILj7S2n9PeADdx2TMY", + "type": "rectangle", + "x": 1928.58984375, + "y": 975.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2N", + "roundness": null, + "seed": 739942346, + "version": 263, + "versionNonce": 2047805078, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "A_JFPEAqBW9EPietZYM8a" + } + ], + "updated": 1737970455777, + "link": null, + "locked": false + }, + { + "id": "mIlz4x0AjaordLAqI-DWY", + "type": "rectangle", + "x": 1931.56640625, + "y": 1176.5, + "width": 154.921875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2O", + "roundness": null, + "seed": 1141380746, + "version": 302, + "versionNonce": 761452822, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "uv0MN_ZBtwcWuq7WETscI" + } + ], + "updated": 1737970455778, + "link": null, + "locked": false + }, + { + "id": "A_JFPEAqBW9EPietZYM8a", + "type": "text", + "x": 1944.996452331543, + "y": 985, + "width": 110.63990783691406, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2Q", + "roundness": null, + "seed": 791116810, + "version": 269, + "versionNonce": 249414614, + "isDeleted": false, + "boundElements": [], + "updated": 1737970455778, + "link": null, + "locked": false, + "text": "Retina-AKS", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "2YGILj7S2n9PeADdx2TMY", + "originalText": "Retina-AKS", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "uv0MN_ZBtwcWuq7WETscI", + "type": "text", + "x": 1946.7973861694336, + "y": 1186, + "width": 124.45991516113281, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2R", + "roundness": null, + "seed": 1102015178, + "version": 318, + "versionNonce": 2098415190, + "isDeleted": false, + "boundElements": [], + "updated": 1737970455778, + "link": null, + "locked": false, + "text": "Retina-KIND", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "mIlz4x0AjaordLAqI-DWY", + "originalText": "Retina-KIND", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "y5OM8zL9aH4eV1vQRfRA8", + "type": "rectangle", + "x": 1933.7734375, + "y": 1082.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2T", + "roundness": null, + "seed": 1572257866, + "version": 357, + "versionNonce": 1858341782, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "cgV-AqaregAAVrxZQQPP7" + } + ], + "updated": 1737970455778, + "link": null, + "locked": false + }, + { + "id": "cgV-AqaregAAVrxZQQPP7", + "type": "text", + "x": 1948.2400436401367, + "y": 1092, + "width": 114.51991271972656, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2U", + "roundness": null, + "seed": 508307210, + "version": 365, + "versionNonce": 279587030, + "isDeleted": false, + "boundElements": [], + "updated": 1737970455778, + "link": null, + "locked": false, + "text": "Retina-GKE", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "y5OM8zL9aH4eV1vQRfRA8", + "originalText": "Retina-GKE", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "CDhoAiwZsuutyGpxSBtr1", + "type": "text", + "x": 2055.5, + "y": 927.5, + "width": 37.23997497558594, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2W", + "roundness": null, + "seed": 1795255434, + "version": 257, + "versionNonce": 80994134, + "isDeleted": false, + "boundElements": [ + { + "id": "J_prQC5yc7ywuZigF71Wh", + "type": "arrow" + } + ], + "updated": 1737970481192, + "link": null, + "locked": false, + "text": "Live", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Live", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "r_IiMCnJET5n-m5aE4N6J", + "type": "arrow", + "x": 1972, + "y": 107, + "width": 6.9854166666666515, + "height": 239.5, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2Y", + "roundness": { + "type": 2 + }, + "seed": 1848447382, + "version": 149, + "versionNonce": 132873418, + "isDeleted": false, + "boundElements": null, + "updated": 1737971184548, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 6.9854166666666515, + 239.5 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "O4E1OnJgXZMVXYZqcHbbf", + "focus": -0.09965711827521635, + "gap": 5, + "fixedPoint": null + }, + "endBinding": { + "elementId": "R4AeEioM2INhMP9rnYnHe", + "focus": -0.15752101431660293, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "J_prQC5yc7ywuZigF71Wh", + "type": "arrow", + "x": 1973, + "y": 106.99999999999989, + "width": 388, + "height": 812.0000000000001, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2Z", + "roundness": { + "type": 2 + }, + "seed": 26578774, + "version": 401, + "versionNonce": 876832714, + "isDeleted": false, + "boundElements": [], + "updated": 1737971284718, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 388, + 564.0000000000001 + ], + [ + 84, + 812.0000000000001 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "O4E1OnJgXZMVXYZqcHbbf", + "focus": 0.0886395475001259, + "gap": 5, + "fixedPoint": null + }, + "endBinding": { + "elementId": "CDhoAiwZsuutyGpxSBtr1", + "focus": -1.262777842966161, + "gap": 8.5, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "HYF4G_hkcZFNdgAl0YQNb", + "type": "arrow", + "x": 1858, + "y": 607, + "width": 207, + "height": 5, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2a", + "roundness": { + "type": 2 + }, + "seed": 1979137814, + "version": 57, + "versionNonce": 1112572054, + "isDeleted": false, + "boundElements": null, + "updated": 1737971124821, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -207, + 5 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "R4AeEioM2INhMP9rnYnHe", + "focus": -0.01676823498239903, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "0S628Xmv8YIAFSDx8-05e", + "focus": -0.3087739884174268, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "nm5O_cFaqDOe1J9pTEhmu", + "type": "text", + "x": 1708, + "y": 574, + "width": 125.63990783691406, + "height": 25, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2b", + "roundness": null, + "seed": 183796746, + "version": 85, + "versionNonce": 62722378, + "isDeleted": false, + "boundElements": null, + "updated": 1737971128309, + "link": null, + "locked": false, + "text": "Instantiates", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Instantiates", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "VBZOWyP-GhRCxXcLTHwB_", + "type": "text", + "x": 1657.180046081543, + "y": 1047.5, + "width": 125.63990783691406, + "height": 25, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2c", + "roundness": null, + "seed": 739676554, + "version": 124, + "versionNonce": 2038259082, + "isDeleted": false, + "boundElements": [], + "updated": 1737971132189, + "link": null, + "locked": false, + "text": "Instantiates", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Instantiates", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "-4dHrHQZE2TDSvs-vgcAo", + "type": "arrow", + "x": 1853, + "y": 1104, + "width": 200, + "height": 187, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2d", + "roundness": { + "type": 2 + }, + "seed": 471021322, + "version": 35, + "versionNonce": 2134311690, + "isDeleted": false, + "boundElements": null, + "updated": 1737971136385, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -200, + -187 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "uLVKBxcndIG-qzR2NQnMF", + "focus": -0.4659911403889994, + "gap": 1.5, + "fixedPoint": null + }, + "endBinding": { + "elementId": "0S628Xmv8YIAFSDx8-05e", + "focus": 0.19663384921609758, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "o_HSEmb0pecqRgBJDEBRp", + "type": "arrow", + "x": 1343, + "y": 673, + "width": 136, + "height": 4, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2e", + "roundness": { + "type": 2 + }, + "seed": 144078154, + "version": 29, + "versionNonce": 1175139926, + "isDeleted": false, + "boundElements": null, + "updated": 1737971114288, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -136, + 4 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "0S628Xmv8YIAFSDx8-05e", + "focus": 0.10182047895250676, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "zghIcLCzAMCMHoPa6KCP5", + "focus": -0.06784021665538253, + "gap": 2, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "13azSEVgK_dcdndesOJU4", + "type": "text", + "x": 1271, + "y": 644, + "width": 47.19996643066406, + "height": 25, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2f", + "roundness": null, + "seed": 1546120586, + "version": 7, + "versionNonce": 591726474, + "isDeleted": false, + "boundElements": null, + "updated": 1737971117472, + "link": null, + "locked": false, + "text": "Uses", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Uses", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "JMh5UJvRSjgcfPdc_YCR7", + "type": "text", + "x": 1597.400016784668, + "y": 1134.5, + "width": 47.19996643066406, + "height": 25, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2g", + "roundness": null, + "seed": 1271206422, + "version": 3, + "versionNonce": 1160150, + "isDeleted": false, + "boundElements": null, + "updated": 1737971110710, + "link": null, + "locked": false, + "text": "Uses", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Uses", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "RBNxQ4pEgxmBXnHdIaBf9", + "type": "arrow", + "x": 1854, + "y": 1110, + "width": 758, + "height": 242, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2h", + "roundness": { + "type": 2 + }, + "seed": 2027055370, + "version": 185, + "versionNonce": 450718806, + "isDeleted": false, + "boundElements": null, + "updated": 1737971102355, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -326, + 51 + ], + [ + -758, + -191 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "uLVKBxcndIG-qzR2NQnMF", + "focus": 0.05997730828840719, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "zghIcLCzAMCMHoPa6KCP5", + "focus": 0.6958348470250035, + "gap": 10, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "k-K-sqJPwGdOAbF7FgGcz", + "type": "text", + "x": 1512.400016784668, + "y": 262.5, + "width": 47.19996643066406, + "height": 25, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2i", + "roundness": null, + "seed": 1588338186, + "version": 3, + "versionNonce": 1246659606, + "isDeleted": false, + "boundElements": null, + "updated": 1737971106415, + "link": null, + "locked": false, + "text": "Uses", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Uses", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "xhoCMjoiXLgPLJUmc7WuE", + "type": "arrow", + "x": 1858, + "y": 605, + "width": 795, + "height": 311, + "angle": 0, + "strokeColor": "#f08c00", + "backgroundColor": "#a5d8ff", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2j", + "roundness": { + "type": 2 + }, + "seed": 1794620630, + "version": 236, + "versionNonce": 489375370, + "isDeleted": false, + "boundElements": null, + "updated": 1737971095964, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -277, + -311 + ], + [ + -795, + -122 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "R4AeEioM2INhMP9rnYnHe", + "focus": -0.4198735871757071, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "zghIcLCzAMCMHoPa6KCP5", + "focus": -0.8018651582326861, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "WlzkJ1a1P1Er7kfA1RP4T", + "type": "arrow", + "x": 1964, + "y": 9, + "width": 474, + "height": 84.63600506869611, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2k", + "roundness": { + "type": 2 + }, + "seed": 217245642, + "version": 192, + "versionNonce": 227064650, + "isDeleted": false, + "boundElements": null, + "updated": 1737971481423, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 249, + 24 + ], + [ + 474, + 84.63600506869611 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "zXqDMrjv50TU6s8f0xi2s", + "focus": 0.6904324140279195, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "ysLRakRFsF7DlEwBVIfpv", + "focus": -0.3604083592296213, + "gap": 6.4140625, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "0jJYOpQUuReGklXS3eCHd", + "type": "rectangle", + "x": 2433.5, + "y": 357.5, + "width": 311, + "height": 503, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2p", + "roundness": { + "type": 3 + }, + "seed": 507557578, + "version": 387, + "versionNonce": 1340323542, + "isDeleted": false, + "boundElements": [ + { + "id": "EL7fKQS2Z0a_heFdNlDpe", + "type": "arrow" + }, + { + "id": "1G4RvWl5j3Eq0orLwRNb1", + "type": "arrow" + } + ], + "updated": 1737971510934, + "link": null, + "locked": false + }, + { + "id": "yXs1C5HAV_quiAwVGmj9-", + "type": "rectangle", + "x": 2507.58984375, + "y": 417.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2q", + "roundness": null, + "seed": 1465077130, + "version": 383, + "versionNonce": 1531846538, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "c-HWcR62JO098FZH-Exyy" + } + ], + "updated": 1737971303713, + "link": null, + "locked": false + }, + { + "id": "XKA3gCRYDhwXJMOPsnTYe", + "type": "rectangle", + "x": 2510.56640625, + "y": 618.5, + "width": 154.921875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2r", + "roundness": null, + "seed": 1734675530, + "version": 422, + "versionNonce": 289359114, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "UPzd8AvyIY1ANthQMQL-2" + } + ], + "updated": 1737971303713, + "link": null, + "locked": false + }, + { + "id": "sVoinvy16hzPyLe8OLqLD", + "type": "rectangle", + "x": 2505.55078125, + "y": 710.5, + "width": 173.296875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2s", + "roundness": null, + "seed": 1951462154, + "version": 466, + "versionNonce": 1984236170, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "r_UUPiappL6TFrgWoMu3T" + } + ], + "updated": 1737971303713, + "link": null, + "locked": false + }, + { + "id": "c-HWcR62JO098FZH-Exyy", + "type": "text", + "x": 2556.2064208984375, + "y": 427, + "width": 46.219970703125, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2t", + "roundness": null, + "seed": 814875082, + "version": 378, + "versionNonce": 137731658, + "isDeleted": false, + "boundElements": [], + "updated": 1737971303713, + "link": null, + "locked": false, + "text": "AKS ", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "yXs1C5HAV_quiAwVGmj9-", + "originalText": "AKS ", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "UPzd8AvyIY1ANthQMQL-2", + "type": "text", + "x": 2562.1273498535156, + "y": 628, + "width": 51.79998779296875, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2u", + "roundness": null, + "seed": 1195587722, + "version": 424, + "versionNonce": 2145784778, + "isDeleted": false, + "boundElements": [], + "updated": 1737971303713, + "link": null, + "locked": false, + "text": "KIND", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "XKA3gCRYDhwXJMOPsnTYe", + "originalText": "KIND", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "r_UUPiappL6TFrgWoMu3T", + "type": "text", + "x": 2559.739242553711, + "y": 720, + "width": 64.91995239257812, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2v", + "roundness": null, + "seed": 1210029898, + "version": 466, + "versionNonce": 454502730, + "isDeleted": false, + "boundElements": [], + "updated": 1737971303713, + "link": null, + "locked": false, + "text": "Retina", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "sVoinvy16hzPyLe8OLqLD", + "originalText": "Retina", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "DTsWo6ztMP02RFmBj6e-D", + "type": "rectangle", + "x": 2512.7734375, + "y": 524.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2w", + "roundness": null, + "seed": 327294474, + "version": 477, + "versionNonce": 95907850, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "pRnKaRijr0r7prQVxvfOw" + } + ], + "updated": 1737971303713, + "link": null, + "locked": false + }, + { + "id": "pRnKaRijr0r7prQVxvfOw", + "type": "text", + "x": 2563.0700073242188, + "y": 534, + "width": 42.8599853515625, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2x", + "roundness": null, + "seed": 1181076682, + "version": 474, + "versionNonce": 706797258, + "isDeleted": false, + "boundElements": [], + "updated": 1737971303713, + "link": null, + "locked": false, + "text": "GKE", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "DTsWo6ztMP02RFmBj6e-D", + "originalText": "GKE", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "K11qeT79l6Z6nKat1Vns3", + "type": "text", + "x": 2663.5, + "y": 371.5, + "width": 41.059967041015625, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2y", + "roundness": null, + "seed": 644195210, + "version": 430, + "versionNonce": 347405066, + "isDeleted": false, + "boundElements": [], + "updated": 1737971373887, + "link": null, + "locked": false, + "text": "Unit", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Unit", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "GdXv0Fvpyz0tdxI9bskx0", + "type": "rectangle", + "x": 2830.5, + "y": 429.5, + "width": 311, + "height": 350, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2z", + "roundness": { + "type": 3 + }, + "seed": 1407292694, + "version": 536, + "versionNonce": 1282920086, + "isDeleted": false, + "boundElements": [ + { + "id": "JenUnqPQU9n29FUsRjstV", + "type": "arrow" + } + ], + "updated": 1737971550724, + "link": null, + "locked": false + }, + { + "id": "45JovtXM2WCeBgd46-RNa", + "type": "rectangle", + "x": 2904.58984375, + "y": 489.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b30", + "roundness": null, + "seed": 1549435478, + "version": 516, + "versionNonce": 1433501270, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "KK9wBCN7chtrFnhnHDCnN" + } + ], + "updated": 1737971415407, + "link": null, + "locked": false + }, + { + "id": "1UpFRPtuqe5oDMaRyOIOy", + "type": "rectangle", + "x": 2907.56640625, + "y": 690.5, + "width": 154.921875, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b31", + "roundness": null, + "seed": 1506002838, + "version": 555, + "versionNonce": 551182550, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "EebjZsSTiA0RgmiXs7pw-" + } + ], + "updated": 1737971415407, + "link": null, + "locked": false + }, + { + "id": "KK9wBCN7chtrFnhnHDCnN", + "type": "text", + "x": 2917.7764587402344, + "y": 499, + "width": 117.07989501953125, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b33", + "roundness": null, + "seed": 630938134, + "version": 548, + "versionNonce": 245056406, + "isDeleted": false, + "boundElements": [], + "updated": 1737971415407, + "link": null, + "locked": false, + "text": "Retina-AKS ", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "45JovtXM2WCeBgd46-RNa", + "originalText": "Retina-AKS ", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "EebjZsSTiA0RgmiXs7pw-", + "type": "text", + "x": 2922.7973861694336, + "y": 700, + "width": 124.45991516113281, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b34", + "roundness": null, + "seed": 1016309590, + "version": 594, + "versionNonce": 1875105302, + "isDeleted": false, + "boundElements": [], + "updated": 1737971415407, + "link": null, + "locked": false, + "text": "Retina-KIND", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "1UpFRPtuqe5oDMaRyOIOy", + "originalText": "Retina-KIND", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "fnS2X4EuJY-tTrtQBIe8A", + "type": "rectangle", + "x": 2909.7734375, + "y": 596.5, + "width": 143.453125, + "height": 44, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b36", + "roundness": null, + "seed": 1648773590, + "version": 610, + "versionNonce": 609002326, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "82dXVu6Pnfd0kT49q4C9w" + } + ], + "updated": 1737971415407, + "link": null, + "locked": false + }, + { + "id": "82dXVu6Pnfd0kT49q4C9w", + "type": "text", + "x": 2924.2400436401367, + "y": 606, + "width": 114.51991271972656, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b37", + "roundness": null, + "seed": 1305124630, + "version": 644, + "versionNonce": 13224086, + "isDeleted": false, + "boundElements": [], + "updated": 1737971415407, + "link": null, + "locked": false, + "text": "Retina-GKE", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fnS2X4EuJY-tTrtQBIe8A", + "originalText": "Retina-GKE", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "0xZrHBzEv0Ezz_B9ggGOG", + "type": "text", + "x": 3006.5, + "y": 443.5, + "width": 111.73991394042969, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b38", + "roundness": null, + "seed": 143805526, + "version": 578, + "versionNonce": 674077066, + "isDeleted": false, + "boundElements": [ + { + "id": "-FO1qNsJmZSIC7MG10S17", + "type": "arrow" + } + ], + "updated": 1737971476328, + "link": null, + "locked": false, + "text": "Integration", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Integration", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "EL7fKQS2Z0a_heFdNlDpe", + "type": "arrow", + "x": 2560, + "y": 138, + "width": 0, + "height": 217, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b39", + "roundness": { + "type": 2 + }, + "seed": 328428886, + "version": 28, + "versionNonce": 1900773450, + "isDeleted": false, + "boundElements": null, + "updated": 1737971470062, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 217 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "ysLRakRFsF7DlEwBVIfpv", + "focus": -0.024442597978119374, + "gap": 4, + "fixedPoint": null + }, + "endBinding": { + "elementId": "0jJYOpQUuReGklXS3eCHd", + "focus": -0.1864951768488746, + "gap": 2.5, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "-FO1qNsJmZSIC7MG10S17", + "type": "arrow", + "x": 2562, + "y": 135, + "width": 443, + "height": 297, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3A", + "roundness": { + "type": 2 + }, + "seed": 634268810, + "version": 62, + "versionNonce": 1354947210, + "isDeleted": false, + "boundElements": null, + "updated": 1737971477960, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 318, + 94 + ], + [ + 443, + 297 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "ysLRakRFsF7DlEwBVIfpv", + "focus": 0.46713186808073004, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "0xZrHBzEv0Ezz_B9ggGOG", + "focus": -0.6700273879929672, + "gap": 11.5, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "1G4RvWl5j3Eq0orLwRNb1", + "type": "arrow", + "x": 2429, + "y": 587, + "width": 262, + "height": 17, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3B", + "roundness": { + "type": 2 + }, + "seed": 383119562, + "version": 49, + "versionNonce": 607055690, + "isDeleted": false, + "boundElements": null, + "updated": 1737971531455, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -262, + 17 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "0jJYOpQUuReGklXS3eCHd", + "focus": 0.12378805454028145, + "gap": 4.5, + "fixedPoint": null + }, + "endBinding": { + "elementId": "R4AeEioM2INhMP9rnYnHe", + "focus": 0.0575605699153006, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "ia3p_InHfk6eqkomGTQVy", + "type": "text", + "x": 2352, + "y": 558, + "width": 47.19996643066406, + "height": 25, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3C", + "roundness": null, + "seed": 1107965066, + "version": 79, + "versionNonce": 1846142166, + "isDeleted": false, + "boundElements": null, + "updated": 1737971535976, + "link": null, + "locked": false, + "text": "Uses", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Uses", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "RYcoP2a7h3PmEmilpAoEr", + "type": "text", + "x": 2890.400016784668, + "y": 971.5, + "width": 47.19996643066406, + "height": 25, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3D", + "roundness": null, + "seed": 422145994, + "version": 82, + "versionNonce": 1186784906, + "isDeleted": false, + "boundElements": [], + "updated": 1737971541173, + "link": null, + "locked": false, + "text": "Uses", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Uses", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "JenUnqPQU9n29FUsRjstV", + "type": "arrow", + "x": 2993, + "y": 780, + "width": 828, + "height": 228, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b3E", + "roundness": { + "type": 2 + }, + "seed": 1211336010, + "version": 277, + "versionNonce": 439205910, + "isDeleted": false, + "boundElements": null, + "updated": 1737971555301, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -77, + 228 + ], + [ + -828, + 6 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "GdXv0Fvpyz0tdxI9bskx0", + "focus": -0.3088045944123118, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "R4AeEioM2INhMP9rnYnHe", + "focus": 0.4765988876330307, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/test/multicloud/diagrams/diagram.svg b/test/multicloud/diagrams/diagram.svg new file mode 100644 index 0000000000..afa9a3c21b --- /dev/null +++ b/test/multicloud/diagrams/diagram.svg @@ -0,0 +1,2 @@ +Multi-Cloud ProjectOpenTofu IaCGO TestingFrameworkAKS KINDRetinaHelm AzureKINDGoogle CloudGKEModulesProvidersAKS KINDRetinaGKEExamplesRetina-AKSRetina-KINDRetina-GKELiveInstantiatesInstantiatesUsesUsesUsesAKS KINDRetinaGKEUnitRetina-AKS Retina-KINDRetina-GKEIntegrationUsesUses \ No newline at end of file From d5474febbe1e0a811915243b35a463447c7c5625 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 10:14:51 +0000 Subject: [PATCH 11/18] test(mc): update doc as per comments --- test/multicloud/README.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/test/multicloud/README.md b/test/multicloud/README.md index 70cb159719..a71dccbc84 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -20,6 +20,14 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu 1. create an Azure account 2. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) + To deploy an AKS cluster and install retina, create file `live/retina-aks/terraform.tfvars` with the Azure TenantID and SubscriptionID + + ```sh + # example values + subscription_id = "d6050d84-e4dd-463d-afc7-a6ab3dc33ab7" + tenant_id = "ac8a4ccd-35f1-4f95-a688-f68e3d89adfc" + ``` + * GKE: 1. create a gcloud account, project and enable billing @@ -27,31 +35,25 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu 3. [Enable Kubernetes Engine API](https://console.developers.google.com/apis/api/container.googleapis.com/overview?project=mc-retina) 4. [Install gcloud](https://cloud.google.com/sdk/docs/install) + To deploy a GKE cluster export `GOOGLE_APPLICATION_CREDENTIALS` env variable to point to the path where your [service account key](https://cloud.google.com/iam/docs/keys-create-delete) is located. + + ```sh + # example + export GOOGLE_APPLICATION_CREDENTIALS=/Users/srodi/src/retina/test/multicloud/live/retina-gke/service-key.json + ``` + * Kind: 1. Docker installed on the host machine ## Quickstart -To deploy an AKS cluster and install retina, create file `live/retina-aks/terraform.tfvars` with the Azure TenantID and SubscriptionID +The following Make targets can be used to manage each stack lifecycle. -```sh -# example values -subscription_id = "d6050d84-e4dd-463d-afc7-a6ab3dc33ab7" -tenant_id = "ac8a4ccd-35f1-4f95-a688-f68e3d89adfc" -``` - -To deploy a GKE cluster export `GOOGLE_APPLICATION_CREDENTIALS` env variable to point to the path where your [service account key](https://cloud.google.com/iam/docs/keys-create-delete) is located. - -```sh -# example -export GOOGLE_APPLICATION_CREDENTIALS=/Users/srodi/src/retina/test/multicloud/live/retina-gke/service-key.json -``` +### Create Format code, initialize OpenTofu, plan and apply the stack to create infra and deploy retina -### Create - * AKS: ```sh From ca1703cbff70180fe9197e69ee87cf66b5c9c53a Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 11:11:30 +0000 Subject: [PATCH 12/18] test(mc): refactor vars to parameterize all inputs --- test/multicloud/examples/aks/main.tf | 4 ++ test/multicloud/examples/aks/variables.tf | 4 ++ test/multicloud/modules/aks/main.tf | 44 ++++++++++-------- test/multicloud/modules/aks/variables.tf | 56 +++++++++++++++++++++++ 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/test/multicloud/examples/aks/main.tf b/test/multicloud/examples/aks/main.tf index d9bf43381a..0f503e4b18 100644 --- a/test/multicloud/examples/aks/main.tf +++ b/test/multicloud/examples/aks/main.tf @@ -5,3 +5,7 @@ module "aks" { prefix = var.prefix labels = var.labels } + +output kubeconfig { + value = module.aks.azure_get_kubeconfig +} diff --git a/test/multicloud/examples/aks/variables.tf b/test/multicloud/examples/aks/variables.tf index 1e5a2140d7..d3dd636636 100644 --- a/test/multicloud/examples/aks/variables.tf +++ b/test/multicloud/examples/aks/variables.tf @@ -11,19 +11,23 @@ variable "tenant_id" { variable "location" { description = "The Azure Cloud location where AKS will be deployed to." type = string + default = "UK South" } variable "resource_group_name" { description = "The name of the resource group." type = string + default = "example-rg" } variable "prefix" { description = "A prefix to add to all resources." type = string + default = "example-mc" } variable "labels" { description = "A map of labels to add to all resources." type = map(string) + default = {} } diff --git a/test/multicloud/modules/aks/main.tf b/test/multicloud/modules/aks/main.tf index 25279a6ff7..a7352bd589 100644 --- a/test/multicloud/modules/aks/main.tf +++ b/test/multicloud/modules/aks/main.tf @@ -8,33 +8,39 @@ resource "azurerm_kubernetes_cluster" "aks" { location = azurerm_resource_group.aks_rg.location resource_group_name = azurerm_resource_group.aks_rg.name dns_prefix = "${var.prefix}-aks-dns" - kubernetes_version = "1.29.8" + kubernetes_version = var.kubernetes_version - default_node_pool { - name = "agentpool" - node_count = 2 - vm_size = "Standard_D4ds_v5" - os_disk_size_gb = 128 - os_disk_type = "Ephemeral" - max_pods = 110 - type = "VirtualMachineScaleSets" - node_labels = var.labels + dynamic "default_node_pool" { + for_each = [var.default_node_pool] + content { + name = default_node_pool.value.name + node_count = default_node_pool.value.node_count + vm_size = default_node_pool.value.vm_size + os_disk_size_gb = default_node_pool.value.os_disk_size_gb + os_disk_type = default_node_pool.value.os_disk_type + max_pods = default_node_pool.value.max_pods + type = default_node_pool.value.type + node_labels = default_node_pool.value.node_labels + } } identity { type = "SystemAssigned" } - network_profile { - network_plugin = "azure" - network_plugin_mode = "overlay" - load_balancer_profile { - managed_outbound_ip_count = 1 + dynamic "network_profile" { + for_each = [var.network_profile] + content { + network_plugin = network_profile.value.network_plugin + network_plugin_mode = network_profile.value.network_plugin_mode + load_balancer_profile { + managed_outbound_ip_count = network_profile.value.load_balancer_profile.managed_outbound_ip_count + } + pod_cidr = network_profile.value.pod_cidr + service_cidr = network_profile.value.service_cidr + dns_service_ip = network_profile.value.dns_service_ip + outbound_type = network_profile.value.outbound_type } - pod_cidr = "10.244.0.0/16" - service_cidr = "10.0.0.0/16" - dns_service_ip = "10.0.0.10" - outbound_type = "loadBalancer" } tags = var.labels diff --git a/test/multicloud/modules/aks/variables.tf b/test/multicloud/modules/aks/variables.tf index 1efe504a65..d5a5ebb597 100644 --- a/test/multicloud/modules/aks/variables.tf +++ b/test/multicloud/modules/aks/variables.tf @@ -20,3 +20,59 @@ variable "labels" { type = map(string) default = {} } + +variable "network_profile" { + description = "Network profile configuration" + type = object({ + network_plugin = string + network_plugin_mode = string + load_balancer_profile = object({ + managed_outbound_ip_count = number + }) + pod_cidr = string + service_cidr = string + dns_service_ip = string + outbound_type = string + }) + default = { + network_plugin = "azure" + network_plugin_mode = "overlay" + load_balancer_profile = { + managed_outbound_ip_count = 1 + } + pod_cidr = "10.244.0.0/16" + service_cidr = "10.0.0.0/16" + dns_service_ip = "10.0.0.10" + outbound_type = "loadBalancer" + } +} + +variable "default_node_pool" { + description = "Default node pool configuration" + type = object({ + name = string + node_count = number + vm_size = string + os_disk_size_gb = number + os_disk_type = string + max_pods = number + type = string + node_labels = map(string) + }) + default = { + name = "agentpool" + node_count = 2 + vm_size = "Standard_D4ds_v5" + os_disk_size_gb = 128 + os_disk_type = "Ephemeral" + max_pods = 110 + type = "VirtualMachineScaleSets" + node_labels = {} + } +} + +variable "kubernetes_version" { + description = "The version of Kubernetes to use for the AKS cluster." + type = string + default = "1.29.8" +} From 316741ee8f5b964c3e53407a139c5a8898e259db Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 11:35:16 +0000 Subject: [PATCH 13/18] test(mc): refactor retina vars and add retina-kind integration test --- .../retina-kind/.terraform.lock.hcl | 34 +++++++++++++++++++ .../examples/integration/retina-kind/main.tf | 10 ++++++ .../integration/retina-kind/providers.tf | 26 ++++++++++++++ .../integration/retina-kind/test-kind-config | 3 ++ .../integration/retina-kind/variables.tf | 11 ++++++ test/multicloud/modules/retina/main.tf | 24 ++++--------- test/multicloud/modules/retina/variables.tf | 22 ++++++++++++ .../test/integration_retina_kind_test.go | 28 +++++++++++++++ 8 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 test/multicloud/examples/integration/retina-kind/.terraform.lock.hcl create mode 100644 test/multicloud/examples/integration/retina-kind/main.tf create mode 100644 test/multicloud/examples/integration/retina-kind/providers.tf create mode 100644 test/multicloud/examples/integration/retina-kind/test-kind-config create mode 100644 test/multicloud/examples/integration/retina-kind/variables.tf create mode 100644 test/multicloud/test/integration_retina_kind_test.go diff --git a/test/multicloud/examples/integration/retina-kind/.terraform.lock.hcl b/test/multicloud/examples/integration/retina-kind/.terraform.lock.hcl new file mode 100644 index 0000000000..a641109262 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/.terraform.lock.hcl @@ -0,0 +1,34 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/helm" { + version = "2.17.0" + constraints = "2.17.0" + hashes = [ + "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", + "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", + "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", + "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", + "zh:3976400ceba6dda4636e1d297e3097e1831de5628afa534a166de98a70d1dcbe", + "zh:54440ef14f342b41d75c1aded7487bfcc3f76322b75894235b47b7e89ac4bfa4", + "zh:6512e2ab9f2fa31cbb90d9249647b5c5798f62eb1215ec44da2cdaa24e38ad25", + "zh:795f327ca0b8c5368af0ed03d5d4f6da7260692b4b3ca0bd004ed542e683464d", + "zh:ba659e1d94f224bc3f1fd34cbb9d2663e3a8e734108e5a58eb49eda84b140978", + "zh:c5c8575c4458835c2acbc3d1ed5570589b14baa2525d8fbd04295c097caf41eb", + "zh:e0877a5dac3de138e61eefa26b2f5a13305a17259779465899880f70e11314e0", + ] +} + +provider "registry.opentofu.org/tehcyx/kind" { + version = "0.7.0" + constraints = "0.7.0" + hashes = [ + "h1:nFhFHmE5+dCd9S9dEMwnMNWzyxoVipYobkhXYoDbhgA=", + "zh:171a2fb0137bfbdebd56cd65afd2e0e2167315fe4cb6a07a218db40cb17339c3", + "zh:3260b078b7997ddfd03845326ffaeed7f678eeaaf7918430356f22e299e36f22", + "zh:4066ab3feb482a0dd1bfff6590d89a0ec30478f63c9d8253cfdadb4b8db2234d", + "zh:537af73261d53f4840d1f89d8e5835c52ddb97102e6314f6aea9b8e49c43d610", + "zh:d63e94d828ba0339600d992b0a6695cff939b0aaac1c39b31d38e3c4f3823674", + "zh:f971c617bf6b37d07a5042f13a9ab02b42d0ceb14934174eecc81abeec233c40", + ] +} diff --git a/test/multicloud/examples/integration/retina-kind/main.tf b/test/multicloud/examples/integration/retina-kind/main.tf new file mode 100644 index 0000000000..47945e1b57 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/main.tf @@ -0,0 +1,10 @@ +module "kind" { + source = "../../../modules/kind" + prefix = var.prefix +} + +module "retina" { + depends_on = [module.kind] + source = "../../../modules/retina" + retina_version = var.retina_version +} diff --git a/test/multicloud/examples/integration/retina-kind/providers.tf b/test/multicloud/examples/integration/retina-kind/providers.tf new file mode 100644 index 0000000000..7b8baf2518 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/providers.tf @@ -0,0 +1,26 @@ +terraform { + required_version = "1.8.3" + required_providers { + kind = { + source = "tehcyx/kind" + version = "0.7.0" + } + helm = { + source = "hashicorp/helm" + version = "2.17.0" + } + } +} + +# Initialize the kind provider +provider "kind" {} + +# Initialize the Helm provider +provider "helm" { + kubernetes { + host = module.kind.host + client_certificate = module.kind.client_certificate + client_key = module.kind.client_key + cluster_ca_certificate = module.kind.cluster_ca_certificate + } +} \ No newline at end of file diff --git a/test/multicloud/examples/integration/retina-kind/test-kind-config b/test/multicloud/examples/integration/retina-kind/test-kind-config new file mode 100644 index 0000000000..2ebf5e0ed5 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/test-kind-config @@ -0,0 +1,3 @@ +apiVersion: v1 +kind: Config +preferences: {} diff --git a/test/multicloud/examples/integration/retina-kind/variables.tf b/test/multicloud/examples/integration/retina-kind/variables.tf new file mode 100644 index 0000000000..e9d9024233 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/variables.tf @@ -0,0 +1,11 @@ +variable "prefix" { + description = "A prefix to add to all resources." + type = string + default = "mc" +} + +variable "retina_version" { + description = "The tag to apply to all resources." + type = string + default = "v0.0.23" +} \ No newline at end of file diff --git a/test/multicloud/modules/retina/main.tf b/test/multicloud/modules/retina/main.tf index 33ad03d1a4..3d0d0f3400 100644 --- a/test/multicloud/modules/retina/main.tf +++ b/test/multicloud/modules/retina/main.tf @@ -5,23 +5,11 @@ resource "helm_release" "retina" { version = var.retina_version namespace = "kube-system" - set { - name = "image.tag" - value = var.retina_version + dynamic "set" { + for_each = var.values + content { + name = set.value.name + value = set.value.value + } } - - set { - name = "operator.tag" - value = var.retina_version - } - - set { - name = "logLevel" - value = "info" - } - - # set { - # name = "enabledPlugin_linux" - # value = "[\"dropreason\",\"packetforward\",\"linuxutil\",\"dns\"]" - # } } diff --git a/test/multicloud/modules/retina/variables.tf b/test/multicloud/modules/retina/variables.tf index 829f1bd161..daaa2b717e 100644 --- a/test/multicloud/modules/retina/variables.tf +++ b/test/multicloud/modules/retina/variables.tf @@ -3,3 +3,25 @@ variable "retina_version" { type = string default = "v0.0.23" } + +variable "values" { + description = "Configuration for set blocks, this corresponds to Helm values.yaml" + type = list(object({ + name = string + value = string + })) + default = [ + { + name = "image.tag" + value = "v0.0.23" + }, + { + name = "operator.tag" + value = "v0.0.23" + }, + { + name = "logLevel" + value = "info" + } + ] +} diff --git a/test/multicloud/test/integration_retina_kind_test.go b/test/multicloud/test/integration_retina_kind_test.go new file mode 100644 index 0000000000..5afbfd48a6 --- /dev/null +++ b/test/multicloud/test/integration_retina_kind_test.go @@ -0,0 +1,28 @@ +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func TestRetinaKindIntegration(t *testing.T) { + t.Parallel() + + opts := &terraform.Options{ + TerraformDir: "../examples/integration/retina-kind", + + Vars: map[string]interface{}{ + "prefix": "test", + "retina_version": "v0.0.24", + }, + } + + // clean up at the end of the test + defer terraform.Destroy(t, opts) + + terraform.Init(t, opts) + terraform.Apply(t, opts) + + // TODO: add actual tests here +} From ae070203a28bc48374b243abbfb6659ce5591250 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 11:41:28 +0000 Subject: [PATCH 14/18] test(mc): update integration test prefix (tests run in parallel) --- test/multicloud/test/integration_retina_kind_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/multicloud/test/integration_retina_kind_test.go b/test/multicloud/test/integration_retina_kind_test.go index 5afbfd48a6..9f471ed3bc 100644 --- a/test/multicloud/test/integration_retina_kind_test.go +++ b/test/multicloud/test/integration_retina_kind_test.go @@ -13,7 +13,7 @@ func TestRetinaKindIntegration(t *testing.T) { TerraformDir: "../examples/integration/retina-kind", Vars: map[string]interface{}{ - "prefix": "test", + "prefix": "test-integration", "retina_version": "v0.0.24", }, } From 5b54a471b6383bdf54c03e470dfb4d24b8293e47 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 15:38:44 +0000 Subject: [PATCH 15/18] test(mc): update integration test for retina-kind --- .../examples/integration/retina-kind/main.tf | 16 +++ .../retina-kind/test-integration-kind-config | 3 + test/multicloud/test/go.mod | 43 +++++- test/multicloud/test/go.sum | 127 ++++++++++++++++++ .../test/integration_retina_kind_test.go | 19 +++ test/multicloud/test/testUtils.go | 103 ++++++++++++++ 6 files changed, 307 insertions(+), 4 deletions(-) create mode 100644 test/multicloud/examples/integration/retina-kind/test-integration-kind-config create mode 100644 test/multicloud/test/testUtils.go diff --git a/test/multicloud/examples/integration/retina-kind/main.tf b/test/multicloud/examples/integration/retina-kind/main.tf index 47945e1b57..95799c3e03 100644 --- a/test/multicloud/examples/integration/retina-kind/main.tf +++ b/test/multicloud/examples/integration/retina-kind/main.tf @@ -8,3 +8,19 @@ module "retina" { source = "../../../modules/retina" retina_version = var.retina_version } + +output "host" { + value = module.kind.host +} + +output "cluster_ca_certificate" { + value = module.kind.cluster_ca_certificate +} + +output "client_certificate" { + value = module.kind.client_certificate +} + +output "client_key" { + value = module.kind.client_key +} diff --git a/test/multicloud/examples/integration/retina-kind/test-integration-kind-config b/test/multicloud/examples/integration/retina-kind/test-integration-kind-config new file mode 100644 index 0000000000..2ebf5e0ed5 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/test-integration-kind-config @@ -0,0 +1,3 @@ +apiVersion: v1 +kind: Config +preferences: {} diff --git a/test/multicloud/test/go.mod b/test/multicloud/test/go.mod index ae4189f910..e768135864 100644 --- a/test/multicloud/test/go.mod +++ b/test/multicloud/test/go.mod @@ -6,7 +6,19 @@ require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gruntwork-io/terratest v0.48.1 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -17,22 +29,45 @@ require ( github.com/hashicorp/hcl/v2 v2.22.0 // indirect github.com/hashicorp/terraform-json v0.23.0 // indirect github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.5 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/tmccombs/hcl2json v0.6.4 // indirect github.com/ulikunitz/xz v0.5.10 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/zclconf/go-cty v1.15.0 // indirect golang.org/x/crypto v0.29.0 // indirect - golang.org/x/mod v0.18.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.31.0 // indirect + golang.org/x/oauth2 v0.24.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.22.0 // indirect + golang.org/x/time v0.8.0 // indirect + golang.org/x/tools v0.26.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.32.1 // indirect + k8s.io/apimachinery v0.32.1 // indirect + k8s.io/client-go v0.32.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect + k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/test/multicloud/test/go.sum b/test/multicloud/test/go.sum index cc74f71e43..9990bc6862 100644 --- a/test/multicloud/test/go.sum +++ b/test/multicloud/test/go.sum @@ -4,8 +4,40 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gruntwork-io/terratest v0.48.1 h1:pnydDjkWbZCUYXvQkr24y21fBo8PfJC5hRGdwbl1eXM= github.com/gruntwork-io/terratest v0.48.1/go.mod h1:U2EQW4Odlz75XJUH16Kqkr9c93p+ZZtkpVez7GkZFa4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -26,8 +58,20 @@ github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2 github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 h1:ofNAzWCcyTALn2Zv40+8XitdzCgXY6e9qvXwN9W0YXg= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -36,30 +80,113 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tmccombs/hcl2json v0.6.4 h1:/FWnzS9JCuyZ4MNwrG4vMrFrzRgsWEOVi+1AyYUVLGw= github.com/tmccombs/hcl2json v0.6.4/go.mod h1:+ppKlIW3H5nsAsZddXPy2iMyvld3SHxyjswOZhavRDk= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc= +k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k= +k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= +k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU= +k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= +k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= +k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= +sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/test/multicloud/test/integration_retina_kind_test.go b/test/multicloud/test/integration_retina_kind_test.go index 9f471ed3bc..6a6882a69a 100644 --- a/test/multicloud/test/integration_retina_kind_test.go +++ b/test/multicloud/test/integration_retina_kind_test.go @@ -25,4 +25,23 @@ func TestRetinaKindIntegration(t *testing.T) { terraform.Apply(t, opts) // TODO: add actual tests here + // test the cluster is accessible with the ca cert, client cert and client key + caCert := terraform.Output(t, opts, "cluster_ca_certificate") + clientCert := terraform.Output(t, opts, "client_certificate") + clientKey := terraform.Output(t, opts, "client_key") + host := terraform.Output(t, opts, "host") + + // test the cluster is accessible with the ca cert, client cert and client key + checkClusterAccess(t, caCert, clientCert, clientKey, host) + + // create a Kubernetes clientset + clientSet, err := buildClientSet(caCert, clientCert, clientKey, host) + if err != nil { + t.Fatalf("Failed to create Kubernetes clientset: %v", err) + } + + // check the retina pods logs for errors + checkRetinaLogs(t, clientSet) + + // TODO: add more tests here } diff --git a/test/multicloud/test/testUtils.go b/test/multicloud/test/testUtils.go new file mode 100644 index 0000000000..f3a30416c9 --- /dev/null +++ b/test/multicloud/test/testUtils.go @@ -0,0 +1,103 @@ +package test + +import ( + "bufio" + "context" + "fmt" + "io" + "strings" + "testing" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +func buildClientSet(caCert, clientCert, clientKey, host string) (*kubernetes.Clientset, error) { + // Create a TLS REST config using the provided certificates + config := &rest.Config{ + Host: host, + TLSClientConfig: rest.TLSClientConfig{ + CAData: []byte(caCert), + CertData: []byte(clientCert), + KeyData: []byte(clientKey), + }, + } + // Create a Kubernetes client + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, err + } + return clientset, nil +} + +func checkClusterAccess(t *testing.T, caCert, clientCert, clientKey, host string) { + // Create a TLS config using the provided certificates + tlsClientConfig := rest.TLSClientConfig{ + CAData: []byte(caCert), + CertData: []byte(clientCert), + KeyData: []byte(clientKey), + } + // Create a Kubernetes client config + config := &rest.Config{ + Host: host, + TLSClientConfig: tlsClientConfig, + } + // Create a Kubernetes client + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + t.Fatalf("Failed to create Kubernetes client: %v", err) + } + // Test the cluster is accessible by listing namespaces + _, err = clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + t.Fatalf("Failed to list namespaces: %v", err) + } +} + +func checkLogsForErrors(logs io.ReadCloser) error { + scanner := bufio.NewScanner(logs) + for scanner.Scan() { + line := scanner.Text() + // print a debug line + fmt.Printf("Log line: %s\n", line) + // Check if the line contains the word "error" + if strings.Contains(strings.ToLower(line), "error") { + // create a new error with the log line + return fmt.Errorf("Error found in logs: %s", line) + } + } + // Check for any scanner errors + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +func checkRetinaLogs(t *testing.T, clientset *kubernetes.Clientset) { + // Get the logs for the retina pods + pods, err := clientset.CoreV1().Pods("kube-system").List(context.TODO(), metav1.ListOptions{ + LabelSelector: "k8s-app=retina", + }) + if err != nil { + t.Fatalf("Failed to list pods: %v", err) + } + // Stream the logs for each pod + for _, pod := range pods.Items { + // Get the logs for the pod + req := clientset.CoreV1().Pods("kube-system").GetLogs(pod.Name, &v1.PodLogOptions{}) + // Stream the logs + logs, err := req.Stream(context.Background()) + if err != nil { + t.Fatalf("Failed to get logs for pod %s: %v", pod.Name, err) + } + // Check the logs for errors + err = checkLogsForErrors(logs) + if err != nil { + t.Fatalf("Failed to check logs for errors: %v", err) + } + // Close the logs stream + logs.Close() + } +} From 021e250783df066e37b33e2a16bd754bf69376aa Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 15:41:37 +0000 Subject: [PATCH 16/18] test(mc): address comment on README.md --- test/multicloud/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/multicloud/README.md b/test/multicloud/README.md index a71dccbc84..f82939a532 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -72,7 +72,9 @@ Format code, initialize OpenTofu, plan and apply the stack to create infra and d make kind ``` -To destroy the cluster +### Clean up + +To destroy the cluster specify the `STACK_NAME` and run `make clean`. ```sh # destroy AKS and cleanup local state files From 9bfc55b286bfe54390758c7c1a5b6fea7f7b0fc0 Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Mon, 27 Jan 2025 16:44:14 +0000 Subject: [PATCH 17/18] test(mc): run tofu fmt and add sensitive to secret outputs --- test/multicloud/examples/aks/main.tf | 5 +++-- test/multicloud/examples/aks/variables.tf | 2 +- .../examples/integration/retina-kind/main.tf | 16 ++++++++++------ test/multicloud/modules/kind/main.tf | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/test/multicloud/examples/aks/main.tf b/test/multicloud/examples/aks/main.tf index 0f503e4b18..c926605307 100644 --- a/test/multicloud/examples/aks/main.tf +++ b/test/multicloud/examples/aks/main.tf @@ -6,6 +6,7 @@ module "aks" { labels = var.labels } -output kubeconfig { - value = module.aks.azure_get_kubeconfig +output "kubeconfig" { + value = module.aks.azure_get_kubeconfig + sensitive = true } diff --git a/test/multicloud/examples/aks/variables.tf b/test/multicloud/examples/aks/variables.tf index d3dd636636..ec3e945824 100644 --- a/test/multicloud/examples/aks/variables.tf +++ b/test/multicloud/examples/aks/variables.tf @@ -11,7 +11,7 @@ variable "tenant_id" { variable "location" { description = "The Azure Cloud location where AKS will be deployed to." type = string - default = "UK South" + default = "UK South" } variable "resource_group_name" { diff --git a/test/multicloud/examples/integration/retina-kind/main.tf b/test/multicloud/examples/integration/retina-kind/main.tf index 95799c3e03..ff0b1bd434 100644 --- a/test/multicloud/examples/integration/retina-kind/main.tf +++ b/test/multicloud/examples/integration/retina-kind/main.tf @@ -4,23 +4,27 @@ module "kind" { } module "retina" { - depends_on = [module.kind] - source = "../../../modules/retina" + depends_on = [module.kind] + source = "../../../modules/retina" retina_version = var.retina_version } output "host" { - value = module.kind.host + value = module.kind.host + sensitive = true } output "cluster_ca_certificate" { - value = module.kind.cluster_ca_certificate + value = module.kind.cluster_ca_certificate + sensitive = true } output "client_certificate" { - value = module.kind.client_certificate + value = module.kind.client_certificate + sensitive = true } output "client_key" { - value = module.kind.client_key + value = module.kind.client_key + sensitive = true } diff --git a/test/multicloud/modules/kind/main.tf b/test/multicloud/modules/kind/main.tf index 2558d114aa..42b66b4b7b 100644 --- a/test/multicloud/modules/kind/main.tf +++ b/test/multicloud/modules/kind/main.tf @@ -1,8 +1,8 @@ resource "kind_cluster" "kind" { - name = "${var.prefix}-kind" + name = "${var.prefix}-kind" wait_for_ready = true kind_config { - kind = "Cluster" + kind = "Cluster" api_version = "kind.x-k8s.io/v1alpha4" node { From a2b7094f4fd1ac5a293a5302464a84f10d63400a Mon Sep 17 00:00:00 2001 From: Simone Rodigari Date: Tue, 28 Jan 2025 13:54:18 +0000 Subject: [PATCH 18/18] test(mc): refactor output, utils and add GKE flow (commented) --- test/multicloud/.gitignore | 2 +- test/multicloud/examples/gke/main.tf | 2 + test/multicloud/examples/gke/outputs.tf | 14 +++++ .../examples/integration/retina-kind/main.tf | 20 ------ .../integration/retina-kind/outputs.tf | 19 ++++++ test/multicloud/examples/kind/outputs.tf | 19 ++++++ .../multicloud/examples/kind/test-kind-config | 3 - test/multicloud/live/retina-gke/main.tf | 4 -- test/multicloud/live/retina-gke/outputs.tf | 3 + test/multicloud/modules/aks/outputs.tf | 4 ++ test/multicloud/modules/gke/main.tf | 7 --- test/multicloud/modules/gke/output.tf | 10 +-- test/multicloud/modules/kind/output.tf | 5 ++ test/multicloud/test/example_gke_test.go | 28 ++++++++- test/multicloud/test/example_kind_test.go | 18 +++++- .../test/integration_retina_kind_test.go | 12 ++-- test/multicloud/test/testUtils.go | 61 ++++++++++++------- 17 files changed, 157 insertions(+), 74 deletions(-) create mode 100644 test/multicloud/examples/gke/outputs.tf create mode 100644 test/multicloud/examples/integration/retina-kind/outputs.tf create mode 100644 test/multicloud/examples/kind/outputs.tf delete mode 100644 test/multicloud/examples/kind/test-kind-config create mode 100644 test/multicloud/live/retina-gke/outputs.tf diff --git a/test/multicloud/.gitignore b/test/multicloud/.gitignore index e9552db743..6f829cf6f9 100644 --- a/test/multicloud/.gitignore +++ b/test/multicloud/.gitignore @@ -3,4 +3,4 @@ terraform.tfvars terraform.tfstate *terraform.tfstate.* service-key.json -mc-kind-config +*-kind-config diff --git a/test/multicloud/examples/gke/main.tf b/test/multicloud/examples/gke/main.tf index 88677ecbbb..daf79438c6 100644 --- a/test/multicloud/examples/gke/main.tf +++ b/test/multicloud/examples/gke/main.tf @@ -5,3 +5,5 @@ module "gke" { project = var.project machine_type = var.machine_type } + +data "google_client_config" "current" {} \ No newline at end of file diff --git a/test/multicloud/examples/gke/outputs.tf b/test/multicloud/examples/gke/outputs.tf new file mode 100644 index 0000000000..1d146ecf0f --- /dev/null +++ b/test/multicloud/examples/gke/outputs.tf @@ -0,0 +1,14 @@ +output "host" { + value = module.gke.host + sensitive = true +} + +output "cluster_ca_certificate" { + value = module.gke.cluster_ca_certificate + sensitive = true +} + +output "access_token" { + value = data.google_client_config.current.access_token + sensitive = true +} \ No newline at end of file diff --git a/test/multicloud/examples/integration/retina-kind/main.tf b/test/multicloud/examples/integration/retina-kind/main.tf index ff0b1bd434..8bd5749095 100644 --- a/test/multicloud/examples/integration/retina-kind/main.tf +++ b/test/multicloud/examples/integration/retina-kind/main.tf @@ -8,23 +8,3 @@ module "retina" { source = "../../../modules/retina" retina_version = var.retina_version } - -output "host" { - value = module.kind.host - sensitive = true -} - -output "cluster_ca_certificate" { - value = module.kind.cluster_ca_certificate - sensitive = true -} - -output "client_certificate" { - value = module.kind.client_certificate - sensitive = true -} - -output "client_key" { - value = module.kind.client_key - sensitive = true -} diff --git a/test/multicloud/examples/integration/retina-kind/outputs.tf b/test/multicloud/examples/integration/retina-kind/outputs.tf new file mode 100644 index 0000000000..cdc064fec7 --- /dev/null +++ b/test/multicloud/examples/integration/retina-kind/outputs.tf @@ -0,0 +1,19 @@ +output "host" { + value = module.kind.host + sensitive = true +} + +output "cluster_ca_certificate" { + value = module.kind.cluster_ca_certificate + sensitive = true +} + +output "client_certificate" { + value = module.kind.client_certificate + sensitive = true +} + +output "client_key" { + value = module.kind.client_key + sensitive = true +} diff --git a/test/multicloud/examples/kind/outputs.tf b/test/multicloud/examples/kind/outputs.tf new file mode 100644 index 0000000000..cdc064fec7 --- /dev/null +++ b/test/multicloud/examples/kind/outputs.tf @@ -0,0 +1,19 @@ +output "host" { + value = module.kind.host + sensitive = true +} + +output "cluster_ca_certificate" { + value = module.kind.cluster_ca_certificate + sensitive = true +} + +output "client_certificate" { + value = module.kind.client_certificate + sensitive = true +} + +output "client_key" { + value = module.kind.client_key + sensitive = true +} diff --git a/test/multicloud/examples/kind/test-kind-config b/test/multicloud/examples/kind/test-kind-config deleted file mode 100644 index 2ebf5e0ed5..0000000000 --- a/test/multicloud/examples/kind/test-kind-config +++ /dev/null @@ -1,3 +0,0 @@ -apiVersion: v1 -kind: Config -preferences: {} diff --git a/test/multicloud/live/retina-gke/main.tf b/test/multicloud/live/retina-gke/main.tf index 4e0280c95f..de30d24493 100644 --- a/test/multicloud/live/retina-gke/main.tf +++ b/test/multicloud/live/retina-gke/main.tf @@ -10,7 +10,3 @@ module "retina" { depends_on = [module.gke] source = "../../modules/retina" } - -output "kubeconfig_command" { - value = module.gke.gcloud_get_kubeconfig -} diff --git a/test/multicloud/live/retina-gke/outputs.tf b/test/multicloud/live/retina-gke/outputs.tf new file mode 100644 index 0000000000..1954916e98 --- /dev/null +++ b/test/multicloud/live/retina-gke/outputs.tf @@ -0,0 +1,3 @@ +output "kubeconfig_command" { + value = module.gke.gcloud_get_kubeconfig +} diff --git a/test/multicloud/modules/aks/outputs.tf b/test/multicloud/modules/aks/outputs.tf index e68f4af052..e71ca414ff 100644 --- a/test/multicloud/modules/aks/outputs.tf +++ b/test/multicloud/modules/aks/outputs.tf @@ -5,16 +5,20 @@ output "azure_get_kubeconfig" { output "host" { value = azurerm_kubernetes_cluster.aks.kube_config.0.host + sensitive = true } output "client_certificate" { value = azurerm_kubernetes_cluster.aks.kube_config.0.client_certificate + sensitive = true } output "client_key" { value = azurerm_kubernetes_cluster.aks.kube_config.0.client_key + sensitive = true } output "cluster_ca_certificate" { value = azurerm_kubernetes_cluster.aks.kube_config.0.cluster_ca_certificate + sensitive = true } diff --git a/test/multicloud/modules/gke/main.tf b/test/multicloud/modules/gke/main.tf index df63426c23..c4615b7858 100644 --- a/test/multicloud/modules/gke/main.tf +++ b/test/multicloud/modules/gke/main.tf @@ -13,13 +13,6 @@ resource "google_container_cluster" "gke" { remove_default_node_pool = true initial_node_count = 1 deletion_protection = false - - # Required to configure Kubernetes provider - master_auth { - client_certificate_config { - issue_client_certificate = true - } - } } resource "google_container_node_pool" "gke_preemptible_nodes" { diff --git a/test/multicloud/modules/gke/output.tf b/test/multicloud/modules/gke/output.tf index 7f2a248aaa..692cb7eddf 100644 --- a/test/multicloud/modules/gke/output.tf +++ b/test/multicloud/modules/gke/output.tf @@ -5,16 +5,10 @@ output "gcloud_get_kubeconfig" { output "host" { value = "https://${google_container_cluster.gke.endpoint}" -} - -output "client_certificate" { - value = google_container_cluster.gke.master_auth.0.client_certificate -} - -output "client_key" { - value = google_container_cluster.gke.master_auth.0.client_key + sensitive = true } output "cluster_ca_certificate" { value = google_container_cluster.gke.master_auth.0.cluster_ca_certificate + sensitive = true } \ No newline at end of file diff --git a/test/multicloud/modules/kind/output.tf b/test/multicloud/modules/kind/output.tf index 52d91e490c..1b5b5f3698 100644 --- a/test/multicloud/modules/kind/output.tf +++ b/test/multicloud/modules/kind/output.tf @@ -1,19 +1,24 @@ output "kubeconfig" { value = kind_cluster.kind.kubeconfig + sensitive = true } output "host" { value = kind_cluster.kind.endpoint + sensitive = true } output "client_certificate" { value = kind_cluster.kind.client_certificate + sensitive = true } output "client_key" { value = kind_cluster.kind.client_key + sensitive = true } output "cluster_ca_certificate" { value = kind_cluster.kind.cluster_ca_certificate + sensitive = true } \ No newline at end of file diff --git a/test/multicloud/test/example_gke_test.go b/test/multicloud/test/example_gke_test.go index 9c0ac4e0f8..2f9980d0e8 100644 --- a/test/multicloud/test/example_gke_test.go +++ b/test/multicloud/test/example_gke_test.go @@ -14,8 +14,8 @@ func TestGKEExample(t *testing.T) { Vars: map[string]interface{}{ "prefix": "test", - "location": "eu-central1", - "project": "mc-retina", // TODO: replace with actual project once we get gcloud access + "location": "europe-west2", // London + "project": "mc-retina", // TODO: replace with actual project once we get gcloud access "machine_type": "e2-standard-4", }, } @@ -28,5 +28,27 @@ func TestGKEExample(t *testing.T) { // TODO: uncomment once we get creds for gcloud // terraform.Apply(t, opts) - // TODO: add actual tests here + // // get outputs + // caCert := terraform.Output(t, opts, "cluster_ca_certificate") + // host := terraform.Output(t, opts, "host") + // token := terraform.Output(t, opts, "access_token") + + // caCertString, err := decodeBase64(caCert) + // if err != nil { + // t.Fatalf("Failed to decode ca cert: %v", err) + // } + + // // build the REST config + // restConfig := createRESTConfigWithBearer(caCertString, token, host) + + // // create a Kubernetes clientset + // clientSet, err := buildClientSet(restConfig) + // if err != nil { + // t.Fatalf("Failed to create Kubernetes clientset: %v", err) + // } + + // // test the cluster is accessible + // testClusterAccess(t, clientSet) + + // // TODO: add more tests here } diff --git a/test/multicloud/test/example_kind_test.go b/test/multicloud/test/example_kind_test.go index c53fb09e84..f16affa4dd 100644 --- a/test/multicloud/test/example_kind_test.go +++ b/test/multicloud/test/example_kind_test.go @@ -23,5 +23,21 @@ func TestKindExample(t *testing.T) { terraform.Init(t, opts) terraform.Apply(t, opts) - // TODO: add actual tests here + // get outputs + caCert := terraform.Output(t, opts, "cluster_ca_certificate") + clientCert := terraform.Output(t, opts, "client_certificate") + clientKey := terraform.Output(t, opts, "client_key") + host := terraform.Output(t, opts, "host") + + // build the REST config + restConfig := createRESTConfigWithClientCert(caCert, clientCert, clientKey, host) + + // create a Kubernetes clientset + clientSet, err := buildClientSet(restConfig) + if err != nil { + t.Fatalf("Failed to create Kubernetes clientset: %v", err) + } + + // test the cluster is accessible + testClusterAccess(t, clientSet) } diff --git a/test/multicloud/test/integration_retina_kind_test.go b/test/multicloud/test/integration_retina_kind_test.go index 6a6882a69a..110f6dc191 100644 --- a/test/multicloud/test/integration_retina_kind_test.go +++ b/test/multicloud/test/integration_retina_kind_test.go @@ -24,22 +24,24 @@ func TestRetinaKindIntegration(t *testing.T) { terraform.Init(t, opts) terraform.Apply(t, opts) - // TODO: add actual tests here - // test the cluster is accessible with the ca cert, client cert and client key + // get outputs caCert := terraform.Output(t, opts, "cluster_ca_certificate") clientCert := terraform.Output(t, opts, "client_certificate") clientKey := terraform.Output(t, opts, "client_key") host := terraform.Output(t, opts, "host") - // test the cluster is accessible with the ca cert, client cert and client key - checkClusterAccess(t, caCert, clientCert, clientKey, host) + // build the REST config + restConfig := createRESTConfigWithClientCert(caCert, clientCert, clientKey, host) // create a Kubernetes clientset - clientSet, err := buildClientSet(caCert, clientCert, clientKey, host) + clientSet, err := buildClientSet(restConfig) if err != nil { t.Fatalf("Failed to create Kubernetes clientset: %v", err) } + // test the cluster is accessible + testClusterAccess(t, clientSet) + // check the retina pods logs for errors checkRetinaLogs(t, clientSet) diff --git a/test/multicloud/test/testUtils.go b/test/multicloud/test/testUtils.go index f3a30416c9..dd1e24924e 100644 --- a/test/multicloud/test/testUtils.go +++ b/test/multicloud/test/testUtils.go @@ -3,6 +3,7 @@ package test import ( "bufio" "context" + "encoding/base64" "fmt" "io" "strings" @@ -14,16 +15,7 @@ import ( "k8s.io/client-go/rest" ) -func buildClientSet(caCert, clientCert, clientKey, host string) (*kubernetes.Clientset, error) { - // Create a TLS REST config using the provided certificates - config := &rest.Config{ - Host: host, - TLSClientConfig: rest.TLSClientConfig{ - CAData: []byte(caCert), - CertData: []byte(clientCert), - KeyData: []byte(clientKey), - }, - } +func buildClientSet(config *rest.Config) (*kubernetes.Clientset, error) { // Create a Kubernetes client clientset, err := kubernetes.NewForConfig(config) if err != nil { @@ -32,22 +24,36 @@ func buildClientSet(caCert, clientCert, clientKey, host string) (*kubernetes.Cli return clientset, nil } -func checkClusterAccess(t *testing.T, caCert, clientCert, clientKey, host string) { - // Create a TLS config using the provided certificates - tlsClientConfig := rest.TLSClientConfig{ - CAData: []byte(caCert), - CertData: []byte(clientCert), - KeyData: []byte(clientKey), +// Create a Bearer token REST config +func createRESTConfigWithBearer(caCert, bearerToken, host string) *rest.Config { + config := &rest.Config{ + Host: host, + BearerToken: bearerToken, + TLSClientConfig: rest.TLSClientConfig{ + CAData: []byte(caCert), + }, } - // Create a Kubernetes client config + return config +} + +// Create REST config with client cert and key +func createRESTConfigWithClientCert(caCert, clientCert, clientKey, host string) *rest.Config { config := &rest.Config{ - Host: host, - TLSClientConfig: tlsClientConfig, + Host: host, + TLSClientConfig: rest.TLSClientConfig{ + CAData: []byte(caCert), + CertData: []byte(clientCert), + KeyData: []byte(clientKey), + }, } - // Create a Kubernetes client - clientset, err := kubernetes.NewForConfig(config) + return config +} + +func testClusterAccess(t *testing.T, clientset *kubernetes.Clientset) { + // Test the cluster is accessible by listing nodes + _, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) if err != nil { - t.Fatalf("Failed to create Kubernetes client: %v", err) + t.Fatalf("Failed to list nodes: %v", err) } // Test the cluster is accessible by listing namespaces _, err = clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) @@ -101,3 +107,14 @@ func checkRetinaLogs(t *testing.T, clientset *kubernetes.Clientset) { logs.Close() } } + +// function to convert base64 encoded string to plain text +func decodeBase64(encoded string) (string, error) { + // decode the base64 encoded string + decoded, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + return "", err + } + // return the decoded string + return string(decoded), nil +}