diff --git a/test/multicloud/README.md b/test/multicloud/README.md index dc7bd0c230..287914439d 100644 --- a/test/multicloud/README.md +++ b/test/multicloud/README.md @@ -4,12 +4,18 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu ![Architecture Diagram](./diagrams/diagram.svg) +An example Hubble UI visualization on GKE dataplane v1 (no Cilium). [See GKE network overview doc](https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview). + ## Modules available -* [aks](./modules/aks/) -* [gke](./modules/gke/) -* [kind](./modules/kind/) -* [retina](./modules/retina/) +* [aks](./modules/aks/): Deploy Azure Kubernetes Service cluster. +* [gke](./modules/gke/): Deploy Google Kubernetes Engine cluster. +* [kind](./modules/kind/): Deploy KIND cluster. +* [helm-release](./modules/helm-release/): Deploy a Helm Chart, used to deploy Retina and Prometheus. +* [kubernetes-lb](./modules/kubernetes-lb/): Create a Kubernetes Service of type Load Balancer, used to expose Prometheus. +* [grafana](./modules/grafana/): Set up multiple Prometheus data sources in Grafana Cloud. +* [aks-nsg](./modules/aks-nsg/): Inboud and outbount rules for AKS Load Balancer. +* [gke-firewall](./modules/gke-firewall/): Inboud and outbount rules for GKE Load Balancer. ## Prerequisites @@ -17,10 +23,10 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu * AKS: - 1. create an Azure account - 2. [Install az](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) + 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 + To deploy an AKS cluster and install retina, create file `live/retina-aks/terraform.tfvars` with the Azure TenantID and SubscriptionID. ```sh # example values @@ -30,10 +36,10 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu * 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). 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. @@ -42,12 +48,25 @@ This project leverages [OpenTofu](https://opentofu.org/docs/intro/) Infrastructu export GOOGLE_APPLICATION_CREDENTIALS=/Users/srodi/src/retina/test/multicloud/live/retina-gke/service-key.json ``` +* Grafana + + 1. Set up a [Grafana Cloud free account](https://grafana.com/pricing/) and start an instance. + 2. Create a [Service Account](https://grafana.com/docs/grafana/latest/administration/service-accounts/#create-a-service-account-in-grafana). + 3. Export `GRAFANA_AUTH` environmnet variable containing the service account token. + + ```sh + # example + export GRAFANA_AUTH=glsa_s0MeRan0mS7r1ng_1ab2c345 + ``` + * Kind: 1. Docker installed on the host machine ## Quickstart +![Hubble on GKE v1 dataplane (no Cilium)](./diagrams/mc-gke-hubble.png) + The following Make targets can be used to manage each stack lifecycle. ### Create @@ -93,15 +112,20 @@ make test ## 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) +Resources documentation: + +* [GKE](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster) +* [AKS](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster) +* [Kind](https://registry.terraform.io/providers/tehcyx/kind/latest/docs/resources/cluster) +* [Helm Release](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) +* [Kubernetes LB Service](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service) +* [Grafana Data Source](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/data_source) ## Troubleshooting In case the test fails due to timeout, validate the resource was created by the provider, and if it is, you can import into OpenTofu state. -Here is an example on how to import resources for `modules/gke` +Here is an example on how to import resources for `modules/gke`: ```sh # move to the stack directory @@ -110,4 +134,10 @@ tofu import module.gke.google_container_cluster.gke europe-west2/test-gke-cluste tofu import module.gke.google_service_account.default projects/mc-retina/serviceAccounts/test-gke-service-account@mc-retina.iam.gserviceaccount.com ``` ->Note: each resource documentation contains a section on how to import resources into the State. [Example for google_container_cluster resource](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#import) +>Note: each resource documentation contains a section on how to import resources into the State. [Example for google_container_cluster resource](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/container_cluster#import). + +## Multi-Cloud + +The [live/](./live/) directory contains the multi-cloud / multi-cluster stacks to deploy clusters, install Retina, install Prometheus, expose all Prometheus using load blanaces, and configure a Grafana Cloud instance to consume prometheus data sources to visualize multiple cluster in a single Grafana dashboard. + +![Architecture Diagram](./diagrams/diagram-mc.svg) diff --git a/test/multicloud/diagrams/diagram-mc.svg b/test/multicloud/diagrams/diagram-mc.svg new file mode 100644 index 0000000000..9d27baa8ad --- /dev/null +++ b/test/multicloud/diagrams/diagram-mc.svg @@ -0,0 +1,2 @@ +Google CloudGKEDeploymentPrometheusRetinaLoad BalancerAzureAKSDeploymentPrometheusRetinaLoad BalancerGrafanaCloud \ No newline at end of file diff --git a/test/multicloud/diagrams/mc-gke-hubble-ui.png b/test/multicloud/diagrams/mc-gke-hubble-ui.png new file mode 100644 index 0000000000..7e59ea3ec9 Binary files /dev/null and b/test/multicloud/diagrams/mc-gke-hubble-ui.png differ diff --git a/test/multicloud/diagrams/mc-gke-hubble.png b/test/multicloud/diagrams/mc-gke-hubble.png new file mode 100644 index 0000000000..4e24e1841d Binary files /dev/null and b/test/multicloud/diagrams/mc-gke-hubble.png differ diff --git a/test/multicloud/diagrams/mc.excalidraw b/test/multicloud/diagrams/mc.excalidraw new file mode 100644 index 0000000000..29933ea48e --- /dev/null +++ b/test/multicloud/diagrams/mc.excalidraw @@ -0,0 +1,1668 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "5_W8BA86fmJwBrO8OOuPX", + "type": "rectangle", + "x": -2249.8401050585435, + "y": -4831.408627109235, + "width": 733.8626026995305, + "height": 578.2723004694836, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b30", + "roundness": null, + "seed": 1293699874, + "version": 116, + "versionNonce": 615131390, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Ob0OCX23MOiEbsyYw09Q_" + } + ], + "updated": 1738868692592, + "link": null, + "locked": false + }, + { + "id": "d28sVSeqD7ZfcpnCUPhEV", + "type": "rectangle", + "x": -2215.00442430737, + "y": -4787.864026170268, + "width": 664.1912411971831, + "height": 491.1830985915493, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b31", + "roundness": null, + "seed": 191534818, + "version": 116, + "versionNonce": 1898409442, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "NA8oNuGt4fh3m1DthNwkE" + } + ], + "updated": 1738868692592, + "link": null, + "locked": false + }, + { + "id": "A2RHneu8H0fGDdpLB7tBJ", + "type": "rectangle", + "x": -1988.5520878930506, + "y": -4744.319425231301, + "width": 259.4986062206573, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b32", + "roundness": null, + "seed": 1134922018, + "version": 118, + "versionNonce": 699947326, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "CtpnCpFfWLdxLVvedMba5" + }, + { + "id": "kDU7e25YwdEMqvAFaCfwu", + "type": "arrow" + }, + { + "id": "oALAJlovVFoi_38XF4DOW", + "type": "arrow" + } + ], + "updated": 1738868692592, + "link": null, + "locked": false + }, + { + "id": "aCskzcYN27x7cynUC4saW", + "type": "rectangle", + "x": -2130.895306056196, + "y": -4580.591725700784, + "width": 254.79034624413146, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b33", + "roundness": null, + "seed": 438047970, + "version": 122, + "versionNonce": 1168604419, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "yQK62_6M8KI3F6JJLR9LS" + }, + { + "id": "kDU7e25YwdEMqvAFaCfwu", + "type": "arrow" + }, + { + "id": "jeot-u8S5-vTtE_yHkMI5", + "type": "arrow" + }, + { + "id": "Fwx5NZsMkIR2630Y4XWgt", + "type": "arrow" + } + ], + "updated": 1739265694968, + "link": null, + "locked": false + }, + { + "id": "YMdaT_7SIJWQw88SC4lKI", + "type": "rectangle", + "x": -1789.0157579341305, + "y": -4580.591725700784, + "width": 149.8206426056338, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b34", + "roundness": null, + "seed": 1095444642, + "version": 119, + "versionNonce": 251383747, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "hf32z2Siv6dHsHwUnDoa9" + }, + { + "id": "oALAJlovVFoi_38XF4DOW", + "type": "arrow" + }, + { + "id": "jeot-u8S5-vTtE_yHkMI5", + "type": "arrow" + } + ], + "updated": 1739188806761, + "link": null, + "locked": false + }, + { + "id": "Jt3KXMwuTXW_WUfPAAo20", + "type": "rectangle", + "x": -2154.041982992816, + "y": -4416.864026170268, + "width": 301.0837001173709, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b35", + "roundness": null, + "seed": 551666786, + "version": 123, + "versionNonce": 1419039171, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "uCkY73YAeDCRobquy1ap_" + }, + { + "id": "DSjqSaeG5wuUW0oTNN6gO", + "type": "arrow" + }, + { + "id": "Fwx5NZsMkIR2630Y4XWgt", + "type": "arrow" + } + ], + "updated": 1739265694968, + "link": null, + "locked": false + }, + { + "id": "kDU7e25YwdEMqvAFaCfwu", + "type": "arrow", + "x": -1926.766711398967, + "y": -4666.680927578718, + "width": 76.73309495065678, + "height": 75.98685446009404, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b36", + "roundness": { + "type": 2 + }, + "seed": 1318111010, + "version": 336, + "versionNonce": 1023779262, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -76.73309495065666, + 42.54460093896695 + ], + [ + -76.73309495065678, + 75.98685446009404 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "A2RHneu8H0fGDdpLB7tBJ", + "focus": -0.014844242323280478, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "aCskzcYN27x7cynUC4saW", + "focus": 0.0000025635547945955497, + "gap": 10.102347417840065, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "oALAJlovVFoi_38XF4DOW", + "type": "arrow", + "x": -1790.838967027979, + "y": -4666.680927578718, + "width": 76.73309495065587, + "height": 75.98685446009404, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b37", + "roundness": { + "type": 2 + }, + "seed": 1626313442, + "version": 336, + "versionNonce": 955048226, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 76.73309495065575, + 42.54460093896695 + ], + [ + 76.73309495065587, + 75.98685446009404 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "A2RHneu8H0fGDdpLB7tBJ", + "focus": 0.014844789746762505, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "YMdaT_7SIJWQw88SC4lKI", + "focus": -0.000005812897364906603, + "gap": 10.102347417840065, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Ob0OCX23MOiEbsyYw09Q_", + "type": "text", + "x": -1993.1568582131727, + "y": -4826.408627109235, + "width": 220.49610900878906, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b39", + "roundness": null, + "seed": 952504802, + "version": 210, + "versionNonce": 481848546, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "text": "Google Cloud", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": "5_W8BA86fmJwBrO8OOuPX", + "originalText": "Google Cloud", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "NA8oNuGt4fh3m1DthNwkE", + "type": "text", + "x": -1919.667890317665, + "y": -4782.864026170268, + "width": 73.51817321777344, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b3A", + "roundness": null, + "seed": 1403880866, + "version": 190, + "versionNonce": 2063256126, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "text": "GKE", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": "d28sVSeqD7ZfcpnCUPhEV", + "originalText": "GKE", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "CtpnCpFfWLdxLVvedMba5", + "type": "text", + "x": -1954.3762787402416, + "y": -4727.772476874493, + "width": 191.14698791503906, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b3B", + "roundness": null, + "seed": 1745653730, + "version": 187, + "versionNonce": 1587314850, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "text": "Deployment", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "A2RHneu8H0fGDdpLB7tBJ", + "originalText": "Deployment", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "yQK62_6M8KI3F6JJLR9LS", + "type": "text", + "x": -2103.0778459468256, + "y": -4564.044777343976, + "width": 199.15542602539062, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b3C", + "roundness": null, + "seed": 292832162, + "version": 187, + "versionNonce": 1206047358, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "text": "Prometheus", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "aCskzcYN27x7cynUC4saW", + "originalText": "Prometheus", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "hf32z2Siv6dHsHwUnDoa9", + "type": "text", + "x": -1770.3147643290677, + "y": -4564.044777343976, + "width": 112.41865539550781, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b3D", + "roundness": null, + "seed": 1664057186, + "version": 187, + "versionNonce": 977804386, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "text": "Retina", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "YMdaT_7SIJWQw88SC4lKI", + "originalText": "Retina", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "uCkY73YAeDCRobquy1ap_", + "type": "text", + "x": -2122.9611314692866, + "y": -4400.31707781346, + "width": 238.9219970703125, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "8L44eYOYO7FDP2Zg1MlGt", + "fOcHMc9ibAwtyrNzv-fW2" + ], + "frameId": null, + "index": "b3E", + "roundness": null, + "seed": 428688162, + "version": 187, + "versionNonce": 52417214, + "isDeleted": false, + "boundElements": [], + "updated": 1738868692592, + "link": null, + "locked": false, + "text": "Load Balancer", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Jt3KXMwuTXW_WUfPAAo20", + "originalText": "Load Balancer", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "ySLiFMO4r4b4LlrRsv9sX", + "type": "rectangle", + "x": -3018.538388509248, + "y": -4831.408627109235, + "width": 733.8626026995305, + "height": 578.2723004694836, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b46", + "roundness": null, + "seed": 1232693922, + "version": 111, + "versionNonce": 1820238718, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "0k-vgU5nVIbAPjb0Tq7r8" + } + ], + "updated": 1738868697737, + "link": null, + "locked": false + }, + { + "id": "aSvGjP4QbabYEHlnAgE3c", + "type": "rectangle", + "x": -2983.702707758074, + "y": -4787.864026170268, + "width": 664.1912411971831, + "height": 491.1830985915493, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b47", + "roundness": null, + "seed": 1308083810, + "version": 113, + "versionNonce": 1081301630, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "i0rUd_n3FWos5cjK1Dnu2" + } + ], + "updated": 1738868731897, + "link": null, + "locked": false + }, + { + "id": "gaSIjLioK91UP6ZKn02GG", + "type": "rectangle", + "x": -2757.250371343755, + "y": -4744.319425231301, + "width": 259.4986062206573, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b48", + "roundness": null, + "seed": 833923618, + "version": 115, + "versionNonce": 920917090, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "nfObjFuMAdQeg4qWRsBsn" + }, + { + "id": "wLDFKwCFlsFH2rDkYCIj-", + "type": "arrow" + }, + { + "id": "B2ZybM6g3eqzdDPBOWFx6", + "type": "arrow" + } + ], + "updated": 1738868731897, + "link": null, + "locked": false + }, + { + "id": "P0mrMQhq0Ho30iSPherV-", + "type": "rectangle", + "x": -2899.5935895069006, + "y": -4580.591725700784, + "width": 254.79034624413146, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b49", + "roundness": null, + "seed": 463410658, + "version": 120, + "versionNonce": 1020224259, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "tscBhKdnq7GYtaDZARFAx" + }, + { + "id": "wLDFKwCFlsFH2rDkYCIj-", + "type": "arrow" + }, + { + "id": "zWFufuHJi7CLphBMnMldg", + "type": "arrow" + }, + { + "id": "YEMWrrusmwSNpbwxTPjiY", + "type": "arrow" + } + ], + "updated": 1739265688212, + "link": null, + "locked": false + }, + { + "id": "K47BC13LcdrvsNLazxRE7", + "type": "rectangle", + "x": -2557.7140413848347, + "y": -4580.591725700784, + "width": 149.8206426056338, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4A", + "roundness": null, + "seed": 2093353378, + "version": 116, + "versionNonce": 2117781251, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "l1Vvgj_0UQDsc3lRNN_Dj" + }, + { + "id": "B2ZybM6g3eqzdDPBOWFx6", + "type": "arrow" + }, + { + "id": "zWFufuHJi7CLphBMnMldg", + "type": "arrow" + } + ], + "updated": 1739188798896, + "link": null, + "locked": false + }, + { + "id": "yKavBaPFLcmv_bmePHGVO", + "type": "rectangle", + "x": -2922.7402664435203, + "y": -4416.864026170268, + "width": 301.0837001173709, + "height": 76.63849765258216, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4B", + "roundness": null, + "seed": 1280869730, + "version": 120, + "versionNonce": 1314797507, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "MGMD6CcTmmrjeH1zsUf44" + }, + { + "id": "cfQ6jN5FceKgSHuAPjtTz", + "type": "arrow" + }, + { + "id": "YEMWrrusmwSNpbwxTPjiY", + "type": "arrow" + } + ], + "updated": 1739265688212, + "link": null, + "locked": false + }, + { + "id": "u9MMGbZqVWiGYV6ZaSm8e", + "type": "rectangle", + "x": -2464.6578684094825, + "y": -4166.047124761817, + "width": 181.03667840375587, + "height": 98, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4G", + "roundness": null, + "seed": 1387194402, + "version": 118, + "versionNonce": 109556877, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "wOH_Q7yt7xcYe_utGkmP1" + }, + { + "id": "cfQ6jN5FceKgSHuAPjtTz", + "type": "arrow" + }, + { + "id": "DSjqSaeG5wuUW0oTNN6gO", + "type": "arrow" + } + ], + "updated": 1739188783428, + "link": null, + "locked": false + }, + { + "id": "wLDFKwCFlsFH2rDkYCIj-", + "type": "arrow", + "x": -2695.464777126667, + "y": -4666.680927578718, + "width": 76.73309495065632, + "height": 75.98685446009404, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4H", + "roundness": { + "type": 2 + }, + "seed": 1587647458, + "version": 333, + "versionNonce": 1270560418, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731898, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -76.73309495065621, + 42.54460093896695 + ], + [ + -76.73309495065632, + 75.98685446009404 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "gaSIjLioK91UP6ZKn02GG", + "focus": -0.014845337170242176, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "P0mrMQhq0Ho30iSPherV-", + "focus": 0.000004272591324920846, + "gap": 10.102347417840065, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "B2ZybM6g3eqzdDPBOWFx6", + "type": "arrow", + "x": -2559.537032755679, + "y": -4666.680927578718, + "width": 76.73309495065632, + "height": 75.98685446009404, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4I", + "roundness": { + "type": 2 + }, + "seed": 1992869794, + "version": 333, + "versionNonce": 1042289250, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731898, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 76.73309495065621, + 42.54460093896695 + ], + [ + 76.73309495065632, + 75.98685446009404 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "gaSIjLioK91UP6ZKn02GG", + "focus": 0.014843694899800591, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "K47BC13LcdrvsNLazxRE7", + "focus": -0.0000029064486854885798, + "gap": 10.102347417840065, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "0k-vgU5nVIbAPjb0Tq7r8", + "type": "text", + "x": -2699.7111063245216, + "y": -4826.408627109235, + "width": 96.20803833007812, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4R", + "roundness": null, + "seed": 1357939042, + "version": 187, + "versionNonce": 385620578, + "isDeleted": false, + "boundElements": [], + "updated": 1738868697737, + "link": null, + "locked": false, + "text": "Azure", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": "ySLiFMO4r4b4LlrRsv9sX", + "originalText": "Azure", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "i0rUd_n3FWos5cjK1Dnu2", + "type": "text", + "x": -2685.0550165418067, + "y": -4782.864026170268, + "width": 66.89585876464844, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4S", + "roundness": null, + "seed": 1809712418, + "version": 187, + "versionNonce": 1955277694, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731897, + "link": null, + "locked": false, + "text": "AKS", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": "aSvGjP4QbabYEHlnAgE3c", + "originalText": "AKS", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "nfObjFuMAdQeg4qWRsBsn", + "type": "text", + "x": -2723.074562190946, + "y": -4727.772476874493, + "width": 191.14698791503906, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4T", + "roundness": null, + "seed": 501551330, + "version": 184, + "versionNonce": 1303237474, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731897, + "link": null, + "locked": false, + "text": "Deployment", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "gaSIjLioK91UP6ZKn02GG", + "originalText": "Deployment", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "tscBhKdnq7GYtaDZARFAx", + "type": "text", + "x": -2871.77612939753, + "y": -4564.044777343976, + "width": 199.15542602539062, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4U", + "roundness": null, + "seed": 1519690914, + "version": 184, + "versionNonce": 190122942, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731897, + "link": null, + "locked": false, + "text": "Prometheus", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "P0mrMQhq0Ho30iSPherV-", + "originalText": "Prometheus", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "l1Vvgj_0UQDsc3lRNN_Dj", + "type": "text", + "x": -2539.0130477797716, + "y": -4564.044777343976, + "width": 112.41865539550781, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4V", + "roundness": null, + "seed": 1268498530, + "version": 184, + "versionNonce": 1226905378, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731897, + "link": null, + "locked": false, + "text": "Retina", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "K47BC13LcdrvsNLazxRE7", + "originalText": "Retina", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "MGMD6CcTmmrjeH1zsUf44", + "type": "text", + "x": -2891.659414919991, + "y": -4400.31707781346, + "width": 238.9219970703125, + "height": 43.544600938967136, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "PaaD7t02Cbaj_dpdXMJsB", + "bt-VhRQhDFqv8jcCszqVa" + ], + "frameId": null, + "index": "b4W", + "roundness": null, + "seed": 214524962, + "version": 184, + "versionNonce": 645456894, + "isDeleted": false, + "boundElements": [], + "updated": 1738868731897, + "link": null, + "locked": false, + "text": "Load Balancer", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "yKavBaPFLcmv_bmePHGVO", + "originalText": "Load Balancer", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "wOH_Q7yt7xcYe_utGkmP1", + "type": "text", + "x": -2442.5792112144404, + "y": -4160.591725700784, + "width": 136.87936401367188, + "height": 87.08920187793427, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4b", + "roundness": null, + "seed": 251432674, + "version": 188, + "versionNonce": 1864249122, + "isDeleted": false, + "boundElements": [], + "updated": 1738868618892, + "link": null, + "locked": false, + "text": "Grafana\nCloud", + "fontSize": 34.83568075117371, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "u9MMGbZqVWiGYV6ZaSm8e", + "originalText": "Grafana Cloud", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "cfQ6jN5FceKgSHuAPjtTz", + "type": "arrow", + "x": -2466.210263509248, + "y": -4120.408627109235, + "width": 313, + "height": 218, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4c", + "roundness": { + "type": 2 + }, + "seed": 1379029549, + "version": 107, + "versionNonce": 824194339, + "isDeleted": false, + "boundElements": null, + "updated": 1739188774980, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -236, + -31 + ], + [ + -313, + -218 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "u9MMGbZqVWiGYV6ZaSm8e", + "focus": -0.14341464045019223, + "gap": 1.5523950997653628, + "fixedPoint": null + }, + "endBinding": { + "elementId": "yKavBaPFLcmv_bmePHGVO", + "focus": 0.14152504609275607, + "gap": 1.8169014084505761, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "DSjqSaeG5wuUW0oTNN6gO", + "type": "arrow", + "x": -2285.210263509248, + "y": -4119.408627109235, + "width": 285, + "height": 222, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4d", + "roundness": { + "type": 2 + }, + "seed": 1715706051, + "version": 129, + "versionNonce": 1284813517, + "isDeleted": false, + "boundElements": null, + "updated": 1739188787635, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 238, + -32 + ], + [ + 285, + -222 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "u9MMGbZqVWiGYV6ZaSm8e", + "focus": 0.1568626794957365, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "Jt3KXMwuTXW_WUfPAAo20", + "focus": -0.07796598033823895, + "gap": 1, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "zWFufuHJi7CLphBMnMldg", + "type": "arrow", + "x": -2644.210263509248, + "y": -4542.408627109235, + "width": 85, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4e", + "roundness": { + "type": 2 + }, + "seed": 226747427, + "version": 65, + "versionNonce": 32516963, + "isDeleted": false, + "boundElements": null, + "updated": 1739188798896, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 85, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "P0mrMQhq0Ho30iSPherV-", + "focus": -0.0035530507228614863, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "K47BC13LcdrvsNLazxRE7", + "focus": 0.0035530507228614863, + "gap": 1.4962221244131797, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "jeot-u8S5-vTtE_yHkMI5", + "type": "arrow", + "x": -1876.2102635092479, + "y": -4539.408627109235, + "width": 85, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4f", + "roundness": { + "type": 2 + }, + "seed": 1289027853, + "version": 77, + "versionNonce": 1647813123, + "isDeleted": false, + "boundElements": null, + "updated": 1739188818249, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 85, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "aCskzcYN27x7cynUC4saW", + "focus": 0.07473658417054697, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "YMdaT_7SIJWQw88SC4lKI", + "focus": -0.07473658417054699, + "gap": 2.194505575117205, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "YEMWrrusmwSNpbwxTPjiY", + "type": "arrow", + "x": -2785.210263509248, + "y": -4417.408627109235, + "width": 2, + "height": 83, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4g", + "roundness": { + "type": 2 + }, + "seed": 513863011, + "version": 29, + "versionNonce": 1038632803, + "isDeleted": false, + "boundElements": null, + "updated": 1739265688212, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 2, + -83 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "yKavBaPFLcmv_bmePHGVO", + "focus": -0.09208930453946242, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "P0mrMQhq0Ho30iSPherV-", + "focus": 0.07795506834372791, + "gap": 3.5446009389670508, + "fixedPoint": null + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Fwx5NZsMkIR2630Y4XWgt", + "type": "arrow", + "x": -2004.2102635092479, + "y": -4417.408627109235, + "width": 2, + "height": 88, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b4h", + "roundness": { + "type": 2 + }, + "seed": 1315153165, + "version": 24, + "versionNonce": 909877603, + "isDeleted": false, + "boundElements": null, + "updated": 1739265694968, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -2, + -88 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "Jt3KXMwuTXW_WUfPAAo20", + "focus": 0.001143488555546266, + "gap": 1, + "fixedPoint": null + }, + "endBinding": { + "elementId": "aCskzcYN27x7cynUC4saW", + "focus": 0.027660826256840885, + "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/examples/grafana/.terraform.lock.hcl b/test/multicloud/examples/grafana/.terraform.lock.hcl new file mode 100644 index 0000000000..814d628dca --- /dev/null +++ b/test/multicloud/examples/grafana/.terraform.lock.hcl @@ -0,0 +1,30 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/grafana/grafana" { + version = "3.18.3" + constraints = "3.18.3" + hashes = [ + "h1:h8jsFjj3XT5GveS9eb8+KxgErmQLE8ZKe0Cdgbi+11Q=", + "zh:15f8db87fb9d9627b2d94c7d578f96dbfd1bd8e178e984cfd1ff619ac4b2312e", + "zh:202cb8bb6b0f99b57847d7bd463c7d465e7a5f6ebd8930563b77a564a263232f", + "zh:2589bc9d77c3004b79caa9cb82821034b92cb771f9e77dbbc2717d16ee010877", + "zh:4d0811400a9d8c5147f56e6e6365649464b9d939c8e4b3e804fa33a7172e615d", + "zh:576c93474d7a7a15133e443b742a09e73c49ba8397dd1db0a3bc1615e8ed941f", + "zh:659ba97fbfaf2971b4206442aad9950ef80a9d184ee9acb1353d4bd744ef76c4", + "zh:695cbbcaaf0fb51576383ace67e75b80c2fae6c0ee9c2acf427265390dd9400a", + "zh:6dbea832d760eedffb37ee1a87c179b6ede7f236a48c85e569fccbf17ceb44e1", + "zh:786d51a46995dc81b574049f1257fc9c60137949bb1fc65ebc8b9a99537d0333", + "zh:80243a2876c4c499da80caf13fc38be2d13ec4fbcf83b150a4243a671cb25854", + "zh:8d395cd587e3f2587f90dca698cfe498577a606b27cdc83b75d35ab2425ad092", + "zh:a7a209802774b24aebec6ad4d1cf98257f30270c3493e551b7129f076a8f2198", + "zh:ac269db542be25bb525a5a9dd398ef7a72f2a81a21543182e7d2b7855e10b0de", + "zh:c8669f217de2878a9b503caa465941576155002ce9f0f48c071ecc9348a4b0ab", + "zh:d2b6205399085d22ed81345b78ebc66e8ca8703e93da6c3f1e418174ecdc71f0", + "zh:ddde96484350a433f16d23cf7649d142aa5764e122cf5f7f12d3d2b162960b56", + "zh:de14ef67291555620720bb067754d16c8a4a457ca0ea52907479ea5d91f0e9b3", + "zh:e84f064e3cf21c2445bf064a1a98d3e7cd092f8dc3a78812e4fb8a8bcde935d3", + "zh:e9281573351e6ecddf72bbec9bcd9d6f30003fdbf675a02b0b60bd0ce6a70b04", + "zh:ff3b499b47a69f3c2ad27ad8b5a6ccd0b437cae126a9b9e99d0f97d349bf5cfd", + ] +} diff --git a/test/multicloud/examples/grafana/main.tf b/test/multicloud/examples/grafana/main.tf new file mode 100644 index 0000000000..4ff0c9f541 --- /dev/null +++ b/test/multicloud/examples/grafana/main.tf @@ -0,0 +1,9 @@ +module "grafana" { + source = "../../modules/grafana" + prometheus_endpoints = { + # This is obviously wrong, but it's just an example + # and you can check on GrafanaCloud to validate the + # data source was created + some = "http://example.com:1234" + } +} \ No newline at end of file diff --git a/test/multicloud/examples/grafana/providers.tf b/test/multicloud/examples/grafana/providers.tf new file mode 100644 index 0000000000..1b8a0eb7ba --- /dev/null +++ b/test/multicloud/examples/grafana/providers.tf @@ -0,0 +1,15 @@ +# Terraform Grafana provider configuration +terraform { + required_version = "1.8.3" + required_providers { + grafana = { + source = "grafana/grafana" + version = "3.18.3" + } + } +} + +# Initialize the Grafana provider +provider "grafana" { + url = var.grafana_url +} \ No newline at end of file diff --git a/test/multicloud/examples/grafana/variables.tf b/test/multicloud/examples/grafana/variables.tf new file mode 100644 index 0000000000..5eeb127cf9 --- /dev/null +++ b/test/multicloud/examples/grafana/variables.tf @@ -0,0 +1,4 @@ +variable "grafana_url" { + description = "The URL of the Grafana instance" + type = string +} diff --git a/test/multicloud/examples/integration/prometheus-kind/main.tf b/test/multicloud/examples/integration/prometheus-kind/main.tf index 41dd85efd9..2372d3d74a 100644 --- a/test/multicloud/examples/integration/prometheus-kind/main.tf +++ b/test/multicloud/examples/integration/prometheus-kind/main.tf @@ -3,9 +3,22 @@ module "kind" { prefix = var.prefix } -module "prometheus" { +module "retina" { depends_on = [module.kind] source = "../../../modules/helm-release" + release_name = var.retina_release_name + repository_url = var.retina_repository_url + chart_version = var.retina_chart_version + chart_name = var.retina_chart_name + values = var.retina_values +} + +module "prometheus" { + depends_on = [ + module.kind, + module.retina + ] + source = "../../../modules/helm-release" release_name = var.prometheus_release_name repository_url = var.prometheus_repository_url chart_version = var.prometheus_chart_version diff --git a/test/multicloud/examples/integration/prometheus-kind/variables.tf b/test/multicloud/examples/integration/prometheus-kind/variables.tf index 887d5d925d..eb37f49968 100644 --- a/test/multicloud/examples/integration/prometheus-kind/variables.tf +++ b/test/multicloud/examples/integration/prometheus-kind/variables.tf @@ -29,19 +29,35 @@ variable "prometheus_chart_name" { } variable "prometheus_values" { - description = "Configuration for set blocks, this corresponds to Helm values.yaml" - type = list(object({ - name = string - value = string - })) - default = [ - { - name = "global.prometheus.enabled" - value = "true" - }, - { - name = "global.grafana.enabled" - value = "true" - } - ] -} \ No newline at end of file + description = "This corresponds to Helm values.yaml" + type = any +} + +variable "retina_release_name" { + description = "The name of the Helm release." + type = string + default = "retina" +} + +variable "retina_repository_url" { + description = "The URL of the Helm repository." + type = string + default = "oci://ghcr.io/microsoft/retina/charts" +} + +variable "retina_chart_version" { + description = "The version of the Helm chart to install." + type = string + default = "v0.0.24" +} + +variable "retina_chart_name" { + description = "The name of the Helm chart to install." + type = string + default = "retina" +} + +variable "retina_values" { + description = "This corresponds to Helm values.yaml" + type = any +} diff --git a/test/multicloud/examples/integration/retina-gke/variables.tf b/test/multicloud/examples/integration/retina-gke/variables.tf index 04f390204e..b3eebe843d 100644 --- a/test/multicloud/examples/integration/retina-gke/variables.tf +++ b/test/multicloud/examples/integration/retina-gke/variables.tf @@ -47,23 +47,6 @@ variable "retina_chart_name" { } variable "retina_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.24" - }, - { - name = "operator.tag" - value = "v0.0.24" - }, - { - name = "logLevel" - value = "info" - } - ] + description = "This corresponds to Helm values.yaml" + type = any } diff --git a/test/multicloud/examples/integration/retina-kind/variables.tf b/test/multicloud/examples/integration/retina-kind/variables.tf index 3735666a6e..f282bf2076 100644 --- a/test/multicloud/examples/integration/retina-kind/variables.tf +++ b/test/multicloud/examples/integration/retina-kind/variables.tf @@ -29,23 +29,6 @@ variable "retina_chart_name" { } variable "retina_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.24" - }, - { - name = "operator.tag" - value = "v0.0.24" - }, - { - name = "logLevel" - value = "info" - } - ] -} \ No newline at end of file + description = "This corresponds to Helm values.yaml" + type = any +} diff --git a/test/multicloud/image.png b/test/multicloud/image.png new file mode 100644 index 0000000000..4e24e1841d Binary files /dev/null and b/test/multicloud/image.png differ diff --git a/test/multicloud/live/files/retina-hubble.yaml b/test/multicloud/live/files/retina-hubble.yaml new file mode 100644 index 0000000000..c2befab118 --- /dev/null +++ b/test/multicloud/live/files/retina-hubble.yaml @@ -0,0 +1,30 @@ +# hubble control-plane +operator: + enabled: true + tag: v0.0.24 + repository: ghcr.io/microsoft/retina/retina-operator + +agent: + enabled: true + repository: ghcr.io/microsoft/retina/retina-agent + tag: v0.0.24 + + init: + enabled: true + repository: ghcr.io/microsoft/retina/retina-init + tag: v0.0.24 + +hubble: + relay: + tls: + server: + enabled: false + tls: + enabled: false + auto: + enabled: false + method: cronJob + certValidityDuration: 1 + schedule: "*/10 * * * *" # every 10 minutes + +enabledPlugin_linux: '["packetparser","dropreason","packetforward","linuxutil","dns"]' diff --git a/test/multicloud/live/files/retina-standard-advanced-local-operator.yaml b/test/multicloud/live/files/retina-standard-advanced-local-operator.yaml new file mode 100644 index 0000000000..b66e396261 --- /dev/null +++ b/test/multicloud/live/files/retina-standard-advanced-local-operator.yaml @@ -0,0 +1,16 @@ +# advanced/pod-level mode designed for scale +# metrics are aggregated by "local" Pod (source for outgoing traffic, destination for incoming traffic) +image: + repository: ghcr.io/microsoft/retina/retina-agent + initRepository: ghcr.io/microsoft/retina/retina-init + tag: v0.0.24 + +operator: + enabled: true + enableRetinaEndpoint: true + tag: v0.0.24 + repository: ghcr.io/microsoft/retina/retina-operator + +enabledPlugin_linux: '["packetparser","dropreason","packetforward","linuxutil","dns"]' +enablePodLevel: true +enableAnnotations: true diff --git a/test/multicloud/live/files/retina-standard-advanced-remote-operator.yaml b/test/multicloud/live/files/retina-standard-advanced-remote-operator.yaml new file mode 100644 index 0000000000..f752cb2b2a --- /dev/null +++ b/test/multicloud/live/files/retina-standard-advanced-remote-operator.yaml @@ -0,0 +1,17 @@ +# advanced/pod-level mode with scale limitations +# metrics are aggregated by source and destination Pod +image: + repository: ghcr.io/microsoft/retina/retina-agent + initRepository: ghcr.io/microsoft/retina/retina-init + tag: v0.0.24 + +operator: + enabled: true + enableRetinaEndpoint: true + tag: v0.0.24 + repository: ghcr.io/microsoft/retina/retina-operator + +enabledPlugin_linux: '["packetparser","dropreason","packetforward","linuxutil","dns"]' +enablePodLevel: true +enableAnnotations: true +remoteContext: true diff --git a/test/multicloud/live/files/retina-standard-basic-mode.yaml b/test/multicloud/live/files/retina-standard-basic-mode.yaml new file mode 100644 index 0000000000..b873e00860 --- /dev/null +++ b/test/multicloud/live/files/retina-standard-basic-mode.yaml @@ -0,0 +1,6 @@ +# basic/node-level mode +image: + rag: v0.0.24 +operator: + tag: v0.0.24 +enabledPlugin_linux: '["dropreason","packetforward","linuxutil","dns"]' diff --git a/test/multicloud/live/retina-aks/.terraform.lock.hcl b/test/multicloud/live/retina-aks/.terraform.lock.hcl index 5c20d26e2a..ddcb5ac6b1 100644 --- a/test/multicloud/live/retina-aks/.terraform.lock.hcl +++ b/test/multicloud/live/retina-aks/.terraform.lock.hcl @@ -1,11 +1,38 @@ # This file is maintained automatically by "tofu init". # Manual edits may be lost in future updates. +provider "registry.opentofu.org/grafana/grafana" { + version = "3.18.3" + constraints = "3.18.3" + hashes = [ + "h1:h8jsFjj3XT5GveS9eb8+KxgErmQLE8ZKe0Cdgbi+11Q=", + "zh:15f8db87fb9d9627b2d94c7d578f96dbfd1bd8e178e984cfd1ff619ac4b2312e", + "zh:202cb8bb6b0f99b57847d7bd463c7d465e7a5f6ebd8930563b77a564a263232f", + "zh:2589bc9d77c3004b79caa9cb82821034b92cb771f9e77dbbc2717d16ee010877", + "zh:4d0811400a9d8c5147f56e6e6365649464b9d939c8e4b3e804fa33a7172e615d", + "zh:576c93474d7a7a15133e443b742a09e73c49ba8397dd1db0a3bc1615e8ed941f", + "zh:659ba97fbfaf2971b4206442aad9950ef80a9d184ee9acb1353d4bd744ef76c4", + "zh:695cbbcaaf0fb51576383ace67e75b80c2fae6c0ee9c2acf427265390dd9400a", + "zh:6dbea832d760eedffb37ee1a87c179b6ede7f236a48c85e569fccbf17ceb44e1", + "zh:786d51a46995dc81b574049f1257fc9c60137949bb1fc65ebc8b9a99537d0333", + "zh:80243a2876c4c499da80caf13fc38be2d13ec4fbcf83b150a4243a671cb25854", + "zh:8d395cd587e3f2587f90dca698cfe498577a606b27cdc83b75d35ab2425ad092", + "zh:a7a209802774b24aebec6ad4d1cf98257f30270c3493e551b7129f076a8f2198", + "zh:ac269db542be25bb525a5a9dd398ef7a72f2a81a21543182e7d2b7855e10b0de", + "zh:c8669f217de2878a9b503caa465941576155002ce9f0f48c071ecc9348a4b0ab", + "zh:d2b6205399085d22ed81345b78ebc66e8ca8703e93da6c3f1e418174ecdc71f0", + "zh:ddde96484350a433f16d23cf7649d142aa5764e122cf5f7f12d3d2b162960b56", + "zh:de14ef67291555620720bb067754d16c8a4a457ca0ea52907479ea5d91f0e9b3", + "zh:e84f064e3cf21c2445bf064a1a98d3e7cd092f8dc3a78812e4fb8a8bcde935d3", + "zh:e9281573351e6ecddf72bbec9bcd9d6f30003fdbf675a02b0b60bd0ce6a70b04", + "zh:ff3b499b47a69f3c2ad27ad8b5a6ccd0b437cae126a9b9e99d0f97d349bf5cfd", + ] +} + provider "registry.opentofu.org/hashicorp/azurerm" { version = "4.15.0" - constraints = ">= 2.0.0" + constraints = "4.15.0" hashes = [ - "h1:0YxkmS5jTUl1LIG+71sgKg/YdlgAoHNr3wyyZjJO8vY=", "h1:xE74Yb3iZZF2F1hQy4B8YVCk0gLAp99pJgZX4eIXYMg=", "zh:0a104acfc45de410d9786bdbf540009dbb7db5632fe7c6846fdb5f865007d0b4", "zh:186f20452ca913e84de0fc9b2dc7872c6480813afe11ea076bd60c45aa2d66d0", @@ -25,7 +52,6 @@ provider "registry.opentofu.org/hashicorp/helm" { constraints = "2.17.0" hashes = [ "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", - "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", @@ -38,3 +64,21 @@ provider "registry.opentofu.org/hashicorp/helm" { "zh:e0877a5dac3de138e61eefa26b2f5a13305a17259779465899880f70e11314e0", ] } + +provider "registry.opentofu.org/hashicorp/kubernetes" { + version = "2.35.1" + constraints = "2.35.1" + hashes = [ + "h1:HvgGiweJx159xJsHIgkMQl1eVTcISwGvd8ADXFU46Rk=", + "zh:0a569918d9e81755bdacb2380e70ed304c442e957a029984cbcd9ec88e5d3635", + "zh:1d4d1241cf51d7d4a036c774add1384bb1ba9ca16146334d17c730e1b41ad3e0", + "zh:243219f415f5d8caf32a4e6b6bf596c11cf7db5501ccb4ae77cc0b084bb5d108", + "zh:2f3a33cba73918adc6f580c76b252881f22beb75277df8ca26a01eb5411348f9", + "zh:3b5247f69e72d1e94ac965fa570f448436cedb278f3f29836f6a345aa1bbd5b6", + "zh:4206bca7bf30708e235535af50529565b14f30262dc43142153a1774ee5086af", + "zh:490c80454b8808bb937498aea98e4076a74887446b05feb6e200015613b5e065", + "zh:5e39824289f7b29711681bce98fbb6c27ed221b071a8c78fd0de7f6c2dae4371", + "zh:a7bf7892217bdb0464664f62485d89d014874b0dfb564e99c364fc6dd20c6a3b", + "zh:e8251170bad1c3e2d9c22d0f4dae7239f1a364f05732f7dff5c8e4ec76a95c5a", + ] +} diff --git a/test/multicloud/live/retina-aks/locals.tf b/test/multicloud/live/retina-aks/locals.tf new file mode 100644 index 0000000000..e4f4a942e9 --- /dev/null +++ b/test/multicloud/live/retina-aks/locals.tf @@ -0,0 +1,55 @@ +locals { + location = "uksouth" + resource_group_name = "mc-rg" + prefix = "mc" + + retina_release_name = "retina" + retina_release_namespace = "kube-system" + retina_repository_url = "oci://ghcr.io/microsoft/retina/charts" + retina_chart_version = "v0.0.24" + retina_chart_name = "retina-hubble" + retina_values = yamldecode(file("../files/retina-hubble.yaml")) + + prometheus_release_name = "prometheus" + prometheus_release_namespace = "kube-system" + prometheus_repository_url = "https://prometheus-community.github.io/helm-charts" + prometheus_chart_version = "68.4.3" + prometheus_chart_name = "kube-prometheus-stack" + prometheus_values = yamldecode(file("../../../../deploy/hubble/prometheus/values.yaml")) + + aks_security_rules = [ + { + name = "Allow_Prometheus_Inbound" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + source_address_prefix = "*" + destination_port_range = "9090" + destination_address_prefix = module.prometheus_lb_aks.ip + }, + { + name = "Allow_Prometheus_Outbound" + priority = 100 + direction = "Outbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "9090" + source_address_prefix = module.prometheus_lb_aks.ip + destination_port_range = "*" + destination_address_prefix = "*" + }, + ] + + default_node_pool = { + name = "agentpool" + node_count = 3 + vm_size = "standard_a2_v2" + os_disk_size_gb = 128 + os_disk_type = "Managed" + max_pods = 110 + type = "VirtualMachineScaleSets" + node_labels = {} + } +} \ No newline at end of file diff --git a/test/multicloud/live/retina-aks/main.tf b/test/multicloud/live/retina-aks/main.tf index 60a7200e6c..c8b1b6b69b 100644 --- a/test/multicloud/live/retina-aks/main.tf +++ b/test/multicloud/live/retina-aks/main.tf @@ -1,21 +1,53 @@ module "aks" { source = "../../modules/aks" - location = var.location - resource_group_name = var.resource_group_name - prefix = var.prefix - labels = var.labels + location = local.location + resource_group_name = local.resource_group_name + prefix = local.prefix + default_node_pool = local.default_node_pool } -module "retina" { - depends_on = [module.aks] - source = "../../modules/helm-release" - release_name = var.retina_release_name - repository_url = var.retina_repository_url - chart_version = var.retina_chart_version - chart_name = var.retina_chart_name - values = var.retina_values +module "retina_aks" { + depends_on = [module.aks] + source = "../../modules/helm-release" + chart_version = local.retina_chart_version + release_name = local.retina_release_name + release_namespace = local.retina_release_namespace + repository_url = local.retina_repository_url + chart_name = local.retina_chart_name + values = local.retina_values } -output "kubeconfig_command" { - value = module.aks.azure_get_kubeconfig +module "prometheus_aks" { + depends_on = [module.aks] + source = "../../modules/helm-release" + chart_version = local.prometheus_chart_version + values = local.prometheus_values + release_name = local.prometheus_release_name + release_namespace = local.prometheus_release_namespace + repository_url = local.prometheus_repository_url + chart_name = local.prometheus_chart_name } + +module "prometheus_lb_aks" { + depends_on = [ + module.aks, + module.prometheus_aks + ] + source = "../../modules/kubernetes-lb" +} + +module "aks_nsg" { + depends_on = [module.aks] + source = "../../modules/aks-nsg" + prefix = local.prefix + resource_group_name = local.resource_group_name + security_rules = local.aks_security_rules +} + +module "grafana" { + depends_on = [module.prometheus_lb_aks] + source = "../../modules/grafana" + prometheus_endpoints = { + aks = "http://${module.prometheus_lb_aks.ip}:9090" + } +} \ No newline at end of file diff --git a/test/multicloud/live/retina-aks/outputs.tf b/test/multicloud/live/retina-aks/outputs.tf index 154ce0721b..55d6e04bd4 100644 --- a/test/multicloud/live/retina-aks/outputs.tf +++ b/test/multicloud/live/retina-aks/outputs.tf @@ -1,19 +1,3 @@ -output "host" { - value = module.aks.host - sensitive = true +output "kubeconfig_command" { + value = module.aks.azure_get_kubeconfig } - -output "client_certificate" { - value = module.aks.client_certificate - sensitive = true -} - -output "client_key" { - value = module.aks.client_key - sensitive = true -} - -output "cluster_ca_certificate" { - value = module.aks.cluster_ca_certificate - sensitive = true -} \ No newline at end of file diff --git a/test/multicloud/live/retina-aks/providers.tf b/test/multicloud/live/retina-aks/providers.tf index 264d724c95..9fd6fbc9c8 100644 --- a/test/multicloud/live/retina-aks/providers.tf +++ b/test/multicloud/live/retina-aks/providers.tf @@ -9,6 +9,14 @@ terraform { source = "hashicorp/helm" version = "2.17.0" } + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.35.1" + } + grafana = { + source = "grafana/grafana" + version = "3.18.3" + } } } @@ -32,3 +40,16 @@ provider "helm" { cluster_ca_certificate = base64decode(module.aks.cluster_ca_certificate) } } + +# Initialize the Kubernetes provider +provider "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) +} + +# Initialize the Grafana provider +provider "grafana" { + url = var.grafana_url +} diff --git a/test/multicloud/live/retina-aks/variables.tf b/test/multicloud/live/retina-aks/variables.tf index 901734c889..b74d1f9594 100644 --- a/test/multicloud/live/retina-aks/variables.tf +++ b/test/multicloud/live/retina-aks/variables.tf @@ -8,72 +8,7 @@ variable "tenant_id" { type = string } -variable "location" { - description = "The Azure Cloud location where AKS will be deployed to." +variable "grafana_url" { + description = "The URL of the Grafana instance" 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 = {} -} - -variable "retina_release_name" { - description = "The name of the Helm release." - type = string - default = "retina" -} - -variable "retina_repository_url" { - description = "The URL of the Helm repository." - type = string - default = "oci://ghcr.io/microsoft/retina/charts" -} - -variable "retina_chart_version" { - description = "The version of the Helm chart to install." - type = string - default = "v0.0.24" -} - -variable "retina_chart_name" { - description = "The name of the Helm chart to install." - type = string - default = "retina" -} - -variable "retina_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.24" - }, - { - name = "operator.tag" - value = "v0.0.24" - }, - { - name = "logLevel" - value = "info" - } - ] -} +} \ No newline at end of file diff --git a/test/multicloud/live/retina-gke/.terraform.lock.hcl b/test/multicloud/live/retina-gke/.terraform.lock.hcl index ed3aacfe1c..4b286d4122 100644 --- a/test/multicloud/live/retina-gke/.terraform.lock.hcl +++ b/test/multicloud/live/retina-gke/.terraform.lock.hcl @@ -1,11 +1,38 @@ # This file is maintained automatically by "tofu init". # Manual edits may be lost in future updates. +provider "registry.opentofu.org/grafana/grafana" { + version = "3.18.3" + constraints = "3.18.3" + hashes = [ + "h1:h8jsFjj3XT5GveS9eb8+KxgErmQLE8ZKe0Cdgbi+11Q=", + "zh:15f8db87fb9d9627b2d94c7d578f96dbfd1bd8e178e984cfd1ff619ac4b2312e", + "zh:202cb8bb6b0f99b57847d7bd463c7d465e7a5f6ebd8930563b77a564a263232f", + "zh:2589bc9d77c3004b79caa9cb82821034b92cb771f9e77dbbc2717d16ee010877", + "zh:4d0811400a9d8c5147f56e6e6365649464b9d939c8e4b3e804fa33a7172e615d", + "zh:576c93474d7a7a15133e443b742a09e73c49ba8397dd1db0a3bc1615e8ed941f", + "zh:659ba97fbfaf2971b4206442aad9950ef80a9d184ee9acb1353d4bd744ef76c4", + "zh:695cbbcaaf0fb51576383ace67e75b80c2fae6c0ee9c2acf427265390dd9400a", + "zh:6dbea832d760eedffb37ee1a87c179b6ede7f236a48c85e569fccbf17ceb44e1", + "zh:786d51a46995dc81b574049f1257fc9c60137949bb1fc65ebc8b9a99537d0333", + "zh:80243a2876c4c499da80caf13fc38be2d13ec4fbcf83b150a4243a671cb25854", + "zh:8d395cd587e3f2587f90dca698cfe498577a606b27cdc83b75d35ab2425ad092", + "zh:a7a209802774b24aebec6ad4d1cf98257f30270c3493e551b7129f076a8f2198", + "zh:ac269db542be25bb525a5a9dd398ef7a72f2a81a21543182e7d2b7855e10b0de", + "zh:c8669f217de2878a9b503caa465941576155002ce9f0f48c071ecc9348a4b0ab", + "zh:d2b6205399085d22ed81345b78ebc66e8ca8703e93da6c3f1e418174ecdc71f0", + "zh:ddde96484350a433f16d23cf7649d142aa5764e122cf5f7f12d3d2b162960b56", + "zh:de14ef67291555620720bb067754d16c8a4a457ca0ea52907479ea5d91f0e9b3", + "zh:e84f064e3cf21c2445bf064a1a98d3e7cd092f8dc3a78812e4fb8a8bcde935d3", + "zh:e9281573351e6ecddf72bbec9bcd9d6f30003fdbf675a02b0b60bd0ce6a70b04", + "zh:ff3b499b47a69f3c2ad27ad8b5a6ccd0b437cae126a9b9e99d0f97d349bf5cfd", + ] +} + provider "registry.opentofu.org/hashicorp/google" { version = "6.17.0" - constraints = ">= 6.17.0" + constraints = "6.17.0" hashes = [ - "h1:7m+L8x7ClWUFAd4uJJENXp9O4K8HtpL50434jPR9pqs=", "h1:aZkLSXbqbNThCCLAX1x0g8KTJANQAIosYq3xpy8JhFQ=", "zh:0614cc52deb5914795253aecf19b4cbb5aa7e8a186839a33907ce5c35e23d537", "zh:0b28ea31ec3b119aafc4c37a5992c29266c876db288dfc5bbfbde36631a533f1", @@ -25,7 +52,6 @@ provider "registry.opentofu.org/hashicorp/helm" { constraints = "2.17.0" hashes = [ "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", - "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", @@ -38,3 +64,21 @@ provider "registry.opentofu.org/hashicorp/helm" { "zh:e0877a5dac3de138e61eefa26b2f5a13305a17259779465899880f70e11314e0", ] } + +provider "registry.opentofu.org/hashicorp/kubernetes" { + version = "2.35.1" + constraints = "2.35.1" + hashes = [ + "h1:HvgGiweJx159xJsHIgkMQl1eVTcISwGvd8ADXFU46Rk=", + "zh:0a569918d9e81755bdacb2380e70ed304c442e957a029984cbcd9ec88e5d3635", + "zh:1d4d1241cf51d7d4a036c774add1384bb1ba9ca16146334d17c730e1b41ad3e0", + "zh:243219f415f5d8caf32a4e6b6bf596c11cf7db5501ccb4ae77cc0b084bb5d108", + "zh:2f3a33cba73918adc6f580c76b252881f22beb75277df8ca26a01eb5411348f9", + "zh:3b5247f69e72d1e94ac965fa570f448436cedb278f3f29836f6a345aa1bbd5b6", + "zh:4206bca7bf30708e235535af50529565b14f30262dc43142153a1774ee5086af", + "zh:490c80454b8808bb937498aea98e4076a74887446b05feb6e200015613b5e065", + "zh:5e39824289f7b29711681bce98fbb6c27ed221b071a8c78fd0de7f6c2dae4371", + "zh:a7bf7892217bdb0464664f62485d89d014874b0dfb564e99c364fc6dd20c6a3b", + "zh:e8251170bad1c3e2d9c22d0f4dae7239f1a364f05732f7dff5c8e4ec76a95c5a", + ] +} diff --git a/test/multicloud/live/retina-gke/locals.tf b/test/multicloud/live/retina-gke/locals.tf new file mode 100644 index 0000000000..a8d67fe6c0 --- /dev/null +++ b/test/multicloud/live/retina-gke/locals.tf @@ -0,0 +1,35 @@ +locals { + prefix = "mc" + location = "europe-west2" + + machine_type = "e2-standard-4" + + retina_release_name = "retina" + retina_repository_url = "oci://ghcr.io/microsoft/retina/charts" + retina_chart_version = "v0.0.24" + retina_release_namespace = "kube-system" + retina_chart_name = "retina-hubble" + retina_values = yamldecode(file("../files/retina-hubble.yaml")) + + prometheus_release_name = "prometheus" + prometheus_repository_url = "https://prometheus-community.github.io/helm-charts" + prometheus_chart_version = "68.4.3" + prometheus_chart_name = "kube-prometheus-stack" + prometheus_release_namespace = "kube-system" + prometheus_values = yamldecode(file("../../../../deploy/hubble/prometheus/values.yaml")) + + gke_firewall_rules = { + inbound = { + protocol = "tcp" + ports = ["9090"] + source_ranges = [module.prometheus_lb_gke.ip] + destination_ranges = ["0.0.0.0/0"] + } + outbound = { + protocol = "tcp" + ports = ["9090"] + source_ranges = ["0.0.0.0/0"] + destination_ranges = [module.prometheus_lb_gke.ip] + } + } +} \ No newline at end of file diff --git a/test/multicloud/live/retina-gke/main.tf b/test/multicloud/live/retina-gke/main.tf index 3862ba858d..e8894c205f 100644 --- a/test/multicloud/live/retina-gke/main.tf +++ b/test/multicloud/live/retina-gke/main.tf @@ -1,17 +1,53 @@ module "gke" { source = "../../modules/gke" - location = var.location - prefix = var.prefix + location = local.location + prefix = local.prefix project = var.project - machine_type = var.machine_type + machine_type = local.machine_type } -module "retina" { - depends_on = [module.gke] - source = "../../modules/helm-release" - release_name = var.retina_release_name - repository_url = var.retina_repository_url - chart_version = var.retina_chart_version - chart_name = var.retina_chart_name - values = var.retina_values +module "retina_gke" { + depends_on = [module.gke] + source = "../../modules/helm-release" + chart_version = local.retina_chart_version + release_name = local.retina_release_name + release_namespace = local.retina_release_namespace + repository_url = local.retina_repository_url + chart_name = local.retina_chart_name + values = local.retina_values } + +module "prometheus_gke" { + depends_on = [module.gke] + source = "../../modules/helm-release" + chart_version = local.prometheus_chart_version + values = local.prometheus_values + release_name = local.prometheus_release_name + release_namespace = local.prometheus_release_namespace + repository_url = local.prometheus_repository_url + chart_name = local.prometheus_chart_name +} + +module "prometheus_lb_gke" { + depends_on = [ + module.gke, + module.prometheus_gke + ] + source = "../../modules/kubernetes-lb" +} + +module "gke_firewall" { + depends_on = [module.gke] + source = "../../modules/gke-firewall" + prefix = local.prefix + inbound_firewall_rule = local.gke_firewall_rules.inbound + outbound_firewall_rule = local.gke_firewall_rules.outbound +} + +module "grafana" { + depends_on = [module.prometheus_lb_gke] + source = "../../modules/grafana" + prometheus_endpoints = { + gke = "http://${module.prometheus_lb_gke.ip}:9090" + } +} \ No newline at end of file diff --git a/test/multicloud/live/retina-gke/providers.tf b/test/multicloud/live/retina-gke/providers.tf index ac23c59c0e..77fdc2ebe6 100644 --- a/test/multicloud/live/retina-gke/providers.tf +++ b/test/multicloud/live/retina-gke/providers.tf @@ -9,16 +9,23 @@ terraform { source = "hashicorp/helm" version = "2.17.0" } + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.35.1" + } + grafana = { + source = "grafana/grafana" + version = "3.18.3" + } } } # Initialize the Google provider provider "google" { project = var.project - region = var.location + region = local.location } -data "google_client_config" "current" {} # Initialize the Helm provider provider "helm" { @@ -27,4 +34,18 @@ provider "helm" { host = module.gke.host cluster_ca_certificate = base64decode(module.gke.cluster_ca_certificate) } -} \ No newline at end of file +} + +data "google_client_config" "current" {} + +# Initialize the Kubernetes provider for GKE +provider "kubernetes" { + token = data.google_client_config.current.access_token + host = module.gke.host + cluster_ca_certificate = base64decode(module.gke.cluster_ca_certificate) +} + +# Initialize the Grafana provider +provider "grafana" { + url = var.grafana_url +} diff --git a/test/multicloud/live/retina-gke/variables.tf b/test/multicloud/live/retina-gke/variables.tf index c9299aa6ba..224f66b35d 100644 --- a/test/multicloud/live/retina-gke/variables.tf +++ b/test/multicloud/live/retina-gke/variables.tf @@ -1,69 +1,9 @@ variable "project" { - description = "The Google Cloud project where resources will be deployed." + description = "Project ID" type = string - default = "mc-retina" } -variable "location" { - description = "The Google Cloud location where GKE will be deployed to." +variable "grafana_url" { + description = "The URL of the Grafana instance" 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" -} - -variable "retina_release_name" { - description = "The name of the Helm release." - type = string - default = "retina" -} - -variable "retina_repository_url" { - description = "The URL of the Helm repository." - type = string - default = "oci://ghcr.io/microsoft/retina/charts" -} - -variable "retina_chart_version" { - description = "The version of the Helm chart to install." - type = string - default = "v0.0.24" -} - -variable "retina_chart_name" { - description = "The name of the Helm chart to install." - type = string - default = "retina" -} - -variable "retina_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.24" - }, - { - name = "operator.tag" - value = "v0.0.24" - }, - { - name = "logLevel" - value = "info" - } - ] -} +} \ No newline at end of file diff --git a/test/multicloud/live/retina-kind/.terraform.lock.hcl b/test/multicloud/live/retina-kind/.terraform.lock.hcl index afc28ace1d..a641109262 100644 --- a/test/multicloud/live/retina-kind/.terraform.lock.hcl +++ b/test/multicloud/live/retina-kind/.terraform.lock.hcl @@ -6,7 +6,6 @@ provider "registry.opentofu.org/hashicorp/helm" { constraints = "2.17.0" hashes = [ "h1:69PnHoYrrDrm7C8+8PiSvRGPI55taqL14SvQR/FGM+g=", - "h1:ShIag7wqd5Rs+zYpVMpjAh+T0ozr4XGYfSTKWqceQBY=", "zh:02690815e35131a42cb9851f63a3369c216af30ad093d05b39001d43da04b56b", "zh:27a62f12b29926387f4d71aeeee9f7ffa0ccb81a1b6066ee895716ad050d1b7a", "zh:2d0a5babfa73604b3fefc9dab9c87f91c77fce756c2e32b294e9f1290aed26c0", @@ -24,7 +23,6 @@ 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", diff --git a/test/multicloud/live/retina-kind/locals.tf b/test/multicloud/live/retina-kind/locals.tf new file mode 100644 index 0000000000..04979c8605 --- /dev/null +++ b/test/multicloud/live/retina-kind/locals.tf @@ -0,0 +1,17 @@ +locals { + prefix = "mc" + + retina_release_name = "retina" + retina_release_namespace = "kube-system" + retina_repository_url = "oci://ghcr.io/microsoft/retina/charts" + retina_chart_version = "v0.0.24" + retina_chart_name = "retina" + retina_values = yamldecode(file("../files/retina-standard-advanced-remote-operator.yaml")) + + prometheus_release_name = "prometheus" + prometheus_release_namespace = "kube-system" + prometheus_repository_url = "https://prometheus-community.github.io/helm-charts" + prometheus_chart_version = "68.4.3" + prometheus_chart_name = "kube-prometheus-stack" + prometheus_values = yamldecode(file("../../../../deploy/standard/prometheus/values.yaml")) +} \ 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 256374b30c..c847e53e84 100644 --- a/test/multicloud/live/retina-kind/main.tf +++ b/test/multicloud/live/retina-kind/main.tf @@ -1,14 +1,26 @@ module "kind" { source = "../../modules/kind" - prefix = var.prefix + prefix = local.prefix } -module "retina" { - depends_on = [module.kind] - source = "../../modules/helm-release" - release_name = var.retina_release_name - repository_url = var.retina_repository_url - chart_version = var.retina_chart_version - chart_name = var.retina_chart_name - values = var.retina_values +module "retina_kind" { + depends_on = [module.kind] + source = "../../modules/helm-release" + chart_version = local.retina_chart_version + release_name = local.retina_release_name + release_namespace = local.retina_release_namespace + repository_url = local.retina_repository_url + chart_name = local.retina_chart_name + values = local.retina_values +} + +module "prometheus_kind" { + depends_on = [module.kind] + source = "../../modules/helm-release" + chart_version = local.prometheus_chart_version + values = local.prometheus_values + release_name = local.prometheus_release_name + release_namespace = local.prometheus_release_namespace + repository_url = local.prometheus_repository_url + chart_name = local.prometheus_chart_name } diff --git a/test/multicloud/live/retina-kind/variables.tf b/test/multicloud/live/retina-kind/variables.tf deleted file mode 100644 index 06b49ab3ab..0000000000 --- a/test/multicloud/live/retina-kind/variables.tf +++ /dev/null @@ -1,51 +0,0 @@ -variable "prefix" { - description = "A prefix to add to all resources." - type = string - default = "mc" -} - -variable "retina_release_name" { - description = "The name of the Helm release." - type = string - default = "retina" -} - -variable "retina_repository_url" { - description = "The URL of the Helm repository." - type = string - default = "oci://ghcr.io/microsoft/retina/charts" -} - -variable "retina_chart_version" { - description = "The version of the Helm chart to install." - type = string - default = "v0.0.24" -} - -variable "retina_chart_name" { - description = "The name of the Helm chart to install." - type = string - default = "retina" -} - -variable "retina_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.24" - }, - { - name = "operator.tag" - value = "v0.0.24" - }, - { - name = "logLevel" - value = "info" - } - ] -} diff --git a/test/multicloud/modules/aks-nsg/main.tf b/test/multicloud/modules/aks-nsg/main.tf new file mode 100644 index 0000000000..d688a7985b --- /dev/null +++ b/test/multicloud/modules/aks-nsg/main.tf @@ -0,0 +1,35 @@ +data "azurerm_resource_group" "aks_rg" { + name = var.resource_group_name +} + +data "azurerm_subnet" "aks_subnet" { + name = "${var.prefix}-subnet" + resource_group_name = var.resource_group_name + virtual_network_name = "${var.prefix}-vnet" +} + +resource "azurerm_network_security_group" "aks_nsg" { + name = "${var.prefix}-nsg" + location = data.azurerm_resource_group.aks_rg.location + resource_group_name = data.azurerm_resource_group.aks_rg.name + + dynamic "security_rule" { + for_each = var.security_rules + content { + name = security_rule.value.name + priority = security_rule.value.priority + direction = security_rule.value.direction + access = security_rule.value.access + protocol = security_rule.value.protocol + source_port_range = security_rule.value.source_port_range + destination_port_range = security_rule.value.destination_port_range + source_address_prefix = security_rule.value.source_address_prefix + destination_address_prefix = security_rule.value.destination_address_prefix + } + } +} + +resource "azurerm_subnet_network_security_group_association" "aks_subnet_nsg" { + subnet_id = data.azurerm_subnet.aks_subnet.id + network_security_group_id = azurerm_network_security_group.aks_nsg.id +} \ No newline at end of file diff --git a/test/multicloud/modules/aks-nsg/provider.tf b/test/multicloud/modules/aks-nsg/provider.tf new file mode 100644 index 0000000000..33705925cf --- /dev/null +++ b/test/multicloud/modules/aks-nsg/provider.tf @@ -0,0 +1,9 @@ +terraform { + required_version = "1.8.3" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.15.0" + } + } +} diff --git a/test/multicloud/modules/aks-nsg/variables.tf b/test/multicloud/modules/aks-nsg/variables.tf new file mode 100644 index 0000000000..c8a59f995d --- /dev/null +++ b/test/multicloud/modules/aks-nsg/variables.tf @@ -0,0 +1,25 @@ +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 "security_rules" { + description = "A list of security rules to add to the network security group." + type = list(object({ + name = string + priority = number + direction = string + access = string + protocol = string + source_port_range = string + destination_port_range = string + source_address_prefix = string + destination_address_prefix = string + })) + default = [] +} \ No newline at end of file diff --git a/test/multicloud/modules/aks/main.tf b/test/multicloud/modules/aks/main.tf index a7352bd589..082b7a9947 100644 --- a/test/multicloud/modules/aks/main.tf +++ b/test/multicloud/modules/aks/main.tf @@ -3,6 +3,20 @@ resource "azurerm_resource_group" "aks_rg" { location = var.location } +resource "azurerm_virtual_network" "aks_vnet" { + name = "${var.prefix}-vnet" + address_space = var.vnet_address_space + location = azurerm_resource_group.aks_rg.location + resource_group_name = azurerm_resource_group.aks_rg.name +} + +resource "azurerm_subnet" "aks_subnet" { + name = "${var.prefix}-subnet" + resource_group_name = azurerm_resource_group.aks_rg.name + virtual_network_name = azurerm_virtual_network.aks_vnet.name + address_prefixes = var.subnet_address_space +} + resource "azurerm_kubernetes_cluster" "aks" { name = "${var.prefix}-aks" location = azurerm_resource_group.aks_rg.location @@ -21,6 +35,7 @@ resource "azurerm_kubernetes_cluster" "aks" { max_pods = default_node_pool.value.max_pods type = default_node_pool.value.type node_labels = default_node_pool.value.node_labels + vnet_subnet_id = azurerm_subnet.aks_subnet.id } } diff --git a/test/multicloud/modules/aks/variables.tf b/test/multicloud/modules/aks/variables.tf index d5a5ebb597..e2d89fded9 100644 --- a/test/multicloud/modules/aks/variables.tf +++ b/test/multicloud/modules/aks/variables.tf @@ -1,7 +1,6 @@ variable "location" { - description = "The VM location." + description = "Location of the AKS cluster." type = string - default = "UK South" } variable "resource_group_name" { @@ -12,7 +11,6 @@ variable "resource_group_name" { variable "prefix" { description = "A prefix to add to all resources." type = string - default = "example-vm" } variable "labels" { @@ -41,8 +39,8 @@ variable "network_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" + service_cidr = "10.1.0.0/16" + dns_service_ip = "10.1.0.10" outbound_type = "loadBalancer" } } @@ -71,6 +69,18 @@ variable "default_node_pool" { } } +variable "vnet_address_space" { + description = "The address space for the virtual network." + type = list(string) + default = ["10.0.0.0/16"] +} + +variable "subnet_address_space" { + description = "The address space for the subnet." + type = list(string) + default = ["10.0.1.0/24"] +} + variable "kubernetes_version" { description = "The version of Kubernetes to use for the AKS cluster." type = string diff --git a/test/multicloud/modules/gke-firewall/main.tf b/test/multicloud/modules/gke-firewall/main.tf new file mode 100644 index 0000000000..329edab896 --- /dev/null +++ b/test/multicloud/modules/gke-firewall/main.tf @@ -0,0 +1,31 @@ +data "google_compute_network" "vpc_network" { + name = "${var.prefix}-vpc-network" +} + +resource "google_compute_firewall" "gke_inbound_rule" { + name = "${var.prefix}-gke-inbound" + network = data.google_compute_network.vpc_network.id + + allow { + protocol = var.inbound_firewall_rule.protocol + ports = var.inbound_firewall_rule.ports + } + + source_ranges = var.inbound_firewall_rule.source_ranges + destination_ranges = var.inbound_firewall_rule.destination_ranges + target_tags = ["${var.prefix}-gke-cluster"] +} + +resource "google_compute_firewall" "gke_outbound_rule" { + name = "${var.prefix}-gke-outbound" + network = data.google_compute_network.vpc_network.id + + allow { + protocol = var.outbound_firewall_rule.protocol + ports = var.outbound_firewall_rule.ports + } + + source_ranges = var.outbound_firewall_rule.source_ranges + destination_ranges = var.outbound_firewall_rule.destination_ranges + target_tags = ["${var.prefix}-gke-cluster"] +} \ No newline at end of file diff --git a/test/multicloud/modules/gke-firewall/variables.tf b/test/multicloud/modules/gke-firewall/variables.tf new file mode 100644 index 0000000000..20cd31fa0a --- /dev/null +++ b/test/multicloud/modules/gke-firewall/variables.tf @@ -0,0 +1,36 @@ +variable "prefix" { + description = "Prefix for resource names" + type = string +} + +variable "inbound_firewall_rule" { + description = "Configuration for inbound firewall rule" + type = object({ + protocol = string + ports = list(string) + source_ranges = list(string) + destination_ranges = list(string) + }) + default = { + protocol = "tcp" + ports = [] + source_ranges = [] + destination_ranges = [] + } +} + +variable "outbound_firewall_rule" { + description = "Configuration for outbound firewall rule" + type = object({ + protocol = string + ports = list(string) + source_ranges = list(string) + destination_ranges = list(string) + }) + default = { + protocol = "tcp" + ports = [] + source_ranges = [] + destination_ranges = [] + } +} diff --git a/test/multicloud/modules/gke/main.tf b/test/multicloud/modules/gke/main.tf index 8de256d40e..8828006e59 100644 --- a/test/multicloud/modules/gke/main.tf +++ b/test/multicloud/modules/gke/main.tf @@ -3,6 +3,20 @@ resource "google_service_account" "default" { display_name = "GKE Service Account for ${var.project}" } +// Create VPC network +resource "google_compute_network" "vpc_network" { + name = "${var.prefix}-vpc-network" + auto_create_subnetworks = false +} + +// Create subnet within the VPC network +resource "google_compute_subnetwork" "subnet" { + name = "${var.prefix}-subnet" + ip_cidr_range = var.subnet_cidr + region = var.location + network = google_compute_network.vpc_network.id +} + // https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview resource "google_container_cluster" "gke" { name = "${var.prefix}-gke-cluster" @@ -14,6 +28,9 @@ resource "google_container_cluster" "gke" { remove_default_node_pool = true initial_node_count = 1 deletion_protection = false + + network = google_compute_network.vpc_network.id + subnetwork = google_compute_subnetwork.subnet.id } resource "google_container_node_pool" "gke_preemptible_nodes" { @@ -32,4 +49,4 @@ resource "google_container_node_pool" "gke_preemptible_nodes" { "https://www.googleapis.com/auth/cloud-platform" ] } -} \ No newline at end of file +} diff --git a/test/multicloud/modules/gke/variables.tf b/test/multicloud/modules/gke/variables.tf index 9971acce00..41bf0a1a1f 100644 --- a/test/multicloud/modules/gke/variables.tf +++ b/test/multicloud/modules/gke/variables.tf @@ -1,19 +1,25 @@ +variable "prefix" { + description = "Prefix for resource names" + type = string +} + variable "project" { - description = "The Google Cloud project where resources will be deployed." + description = "Project ID" type = string } variable "location" { - description = "The Google Cloud location where GKE will be deployed to." + description = "Region for the GKE cluster and subnet" type = string } -variable "prefix" { - description = "A prefix to add to all resources." +variable "machine_type" { + description = "Machine type for the GKE node pool" type = string } -variable "machine_type" { - description = "The machine type to use for the GKE nodes." +variable "subnet_cidr" { + description = "CIDR range for the subnet" type = string -} \ No newline at end of file + default = "10.0.0.0/24" +} diff --git a/test/multicloud/modules/grafana/main.tf b/test/multicloud/modules/grafana/main.tf new file mode 100644 index 0000000000..fda875b6d4 --- /dev/null +++ b/test/multicloud/modules/grafana/main.tf @@ -0,0 +1,7 @@ +resource "grafana_data_source" "prometheus" { + for_each = var.prometheus_endpoints + + name = each.key + type = "prometheus" + url = each.value +} \ No newline at end of file diff --git a/test/multicloud/modules/grafana/providers.tf b/test/multicloud/modules/grafana/providers.tf new file mode 100644 index 0000000000..358ffc729c --- /dev/null +++ b/test/multicloud/modules/grafana/providers.tf @@ -0,0 +1,10 @@ +# Terraform Grafana provider configuration +terraform { + required_version = "1.8.3" + required_providers { + grafana = { + source = "grafana/grafana" + version = "3.18.3" + } + } +} diff --git a/test/multicloud/modules/grafana/variables.tf b/test/multicloud/modules/grafana/variables.tf new file mode 100644 index 0000000000..873c3124aa --- /dev/null +++ b/test/multicloud/modules/grafana/variables.tf @@ -0,0 +1,4 @@ +variable "prometheus_endpoints" { + description = "A map of Prometheus endpoints to add as data sources." + type = map(string) +} diff --git a/test/multicloud/modules/helm-release/main.tf b/test/multicloud/modules/helm-release/main.tf index 26d03457b7..790a2acbb2 100644 --- a/test/multicloud/modules/helm-release/main.tf +++ b/test/multicloud/modules/helm-release/main.tf @@ -1,14 +1,8 @@ resource "helm_release" "release" { name = var.release_name + namespace = var.release_namespace repository = var.repository_url chart = var.chart_name version = var.chart_version - - dynamic "set" { - for_each = var.values - content { - name = set.value.name - value = set.value.value - } - } + values = [jsonencode(var.values)] } \ No newline at end of file diff --git a/test/multicloud/modules/helm-release/variables.tf b/test/multicloud/modules/helm-release/variables.tf index d2c9caa3aa..fcf86fb2de 100644 --- a/test/multicloud/modules/helm-release/variables.tf +++ b/test/multicloud/modules/helm-release/variables.tf @@ -3,6 +3,12 @@ variable "release_name" { type = string } +variable "release_namespace" { + description = "The namespace to install the Helm chart." + type = string + default = "default" +} + variable "repository_url" { description = "The URL of the Helm repository." type = string @@ -19,9 +25,6 @@ variable "chart_name" { } variable "values" { - description = "Configuration for set blocks, this corresponds to Helm values.yaml" - type = list(object({ - name = string - value = string - })) + description = "This corresponds to Helm values.yaml" + type = any } diff --git a/test/multicloud/modules/kubernetes-lb/main.tf b/test/multicloud/modules/kubernetes-lb/main.tf new file mode 100644 index 0000000000..76c28e721b --- /dev/null +++ b/test/multicloud/modules/kubernetes-lb/main.tf @@ -0,0 +1,18 @@ +resource "kubernetes_service" "load_balancer_service" { + metadata { + name = var.name + namespace = var.namespace + } + + spec { + type = "LoadBalancer" + + port { + port = var.port + target_port = var.port + protocol = "TCP" + } + + selector = var.label_selector + } +} \ No newline at end of file diff --git a/test/multicloud/modules/kubernetes-lb/outputs.tf b/test/multicloud/modules/kubernetes-lb/outputs.tf new file mode 100644 index 0000000000..c7d3e1ec2e --- /dev/null +++ b/test/multicloud/modules/kubernetes-lb/outputs.tf @@ -0,0 +1,3 @@ +output "ip" { + value = element(kubernetes_service.load_balancer_service.status[0].load_balancer[0].ingress, 0).ip +} diff --git a/test/multicloud/modules/kubernetes-lb/providers.tf b/test/multicloud/modules/kubernetes-lb/providers.tf new file mode 100644 index 0000000000..749c77ee69 --- /dev/null +++ b/test/multicloud/modules/kubernetes-lb/providers.tf @@ -0,0 +1,9 @@ +terraform { + required_version = "1.8.3" + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "2.35.1" + } + } +} diff --git a/test/multicloud/modules/kubernetes-lb/variables.tf b/test/multicloud/modules/kubernetes-lb/variables.tf new file mode 100644 index 0000000000..4b7a9fe849 --- /dev/null +++ b/test/multicloud/modules/kubernetes-lb/variables.tf @@ -0,0 +1,25 @@ +variable "name" { + description = "Name for the LoadBalancer service" + type = string + default = "prometheus" +} + +variable "namespace" { + description = "Namespace for the LoadBalancer service" + type = string + default = "kube-system" +} + +variable "label_selector" { + description = "Label selector for the backend pods" + type = map(string) + default = { + "app.kubernetes.io/name" = "prometheus" + } +} + +variable "port" { + description = "Port for the LoadBalancer service and targetPort for the pod" + type = number + default = 9090 +} \ No newline at end of file diff --git a/test/multicloud/test/integration/prometheus_kind_test.go b/test/multicloud/test/integration/prometheus_kind_test.go index 12071bfb5c..962b1efc86 100644 --- a/test/multicloud/test/integration/prometheus_kind_test.go +++ b/test/multicloud/test/integration/prometheus_kind_test.go @@ -11,11 +11,23 @@ import ( func TestPrometheusKindIntegration(t *testing.T) { t.Parallel() + jsonValues := utils.SerializeYAMLtoJSONstring(t, utils.PrometheusHelmValuesStandard) + opts := &terraform.Options{ TerraformDir: utils.ExamplesPath + "integration/prometheus-kind", Vars: map[string]interface{}{ - "prefix": "test-integration", + "prefix": "test-integration", + "prometheus_values": jsonValues, + "retina_values": map[string]interface{}{ + "image": map[string]interface{}{ + "tag": "v0.0.24", + }, + "operator": map[string]interface{}{ + "tag": "v0.0.24", + }, + "logLevel": "debug", + }, }, } diff --git a/test/multicloud/test/integration/retina_gke_test.go b/test/multicloud/test/integration/retina_gke_test.go index b2fd0c1ea9..67140ab0ce 100644 --- a/test/multicloud/test/integration/retina_gke_test.go +++ b/test/multicloud/test/integration/retina_gke_test.go @@ -20,24 +20,16 @@ func TestRetinaGKEIntegration(t *testing.T) { "project": "mc-retina", // TODO: replace with actual project once we get gcloud access "machine_type": "e2-standard-4", "retina_chart_version": utils.RetinaVersion, - "retina_values": []map[string]interface{}{ - { - "name": "logLevel", - "value": "info", - }, - { - "name": "operator.tag", - "value": utils.RetinaVersion, - }, + "retina_values": map[string]interface{}{ // Example using a public image built during testing - { - "name": "image.repository", - "value": "acnpublic.azurecr.io/xiaozhiche320/retina/retina-agent", + "image": map[string]interface{}{ + "tag": "c17d5ea-linux-amd64", + "repository": "acnpublic.azurecr.io/xiaozhiche320/retina/retina-agent", }, - { - "name": "image.tag", - "value": "c17d5ea-linux-amd64", + "operator": map[string]interface{}{ + "tag": utils.RetinaVersion, }, + "logLevel": "info", }, }, } diff --git a/test/multicloud/test/integration/retina_kind_test.go b/test/multicloud/test/integration/retina_kind_test.go index 8afc5a3ccd..8c21c2b033 100644 --- a/test/multicloud/test/integration/retina_kind_test.go +++ b/test/multicloud/test/integration/retina_kind_test.go @@ -17,6 +17,15 @@ func TestRetinaKindIntegration(t *testing.T) { Vars: map[string]interface{}{ "prefix": "test-integration", "retina_chart_version": utils.RetinaVersion, + "retina_values": map[string]interface{}{ + "image": map[string]interface{}{ + "tag": "v0.0.24", + }, + "operator": map[string]interface{}{ + "tag": "v0.0.24", + }, + "logLevel": "debug", + }, }, } diff --git a/test/multicloud/test/utils/types.go b/test/multicloud/test/utils/types.go index dc07ee8608..fabd9d0e7b 100644 --- a/test/multicloud/test/utils/types.go +++ b/test/multicloud/test/utils/types.go @@ -1,8 +1,9 @@ package utils const ( - ExamplesPath = "../../examples/" - RetinaVersion = "v0.0.24" + ExamplesPath = "../../examples/" + RetinaVersion = "v0.0.24" + PrometheusHelmValuesStandard = "../../../../deploy/standard/prometheus/values.yaml" ) type PodSelector struct { diff --git a/test/multicloud/test/utils/utils.go b/test/multicloud/test/utils/utils.go index ab03fec485..8f4e5d1291 100644 --- a/test/multicloud/test/utils/utils.go +++ b/test/multicloud/test/utils/utils.go @@ -4,8 +4,10 @@ import ( "bufio" "context" "encoding/base64" + "encoding/json" "fmt" "io" + "os" "strings" "testing" "time" @@ -15,6 +17,7 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" ) @@ -165,3 +168,32 @@ func ArePodsRunning(clientset kubernetes.Interface, podSelector PodSelector, tim } return true, nil } + +// readYAMLFile reads a YAML file from the given filename and unmarshals it into a map[string]interface{}. +// It returns the unmarshaled map and any error encountered during the process. +func readYAMLFile(filename string) (map[string]interface{}, error) { + data, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + + var result map[string]interface{} + err = yaml.Unmarshal(data, &result) + if err != nil { + return nil, err + } + return result, nil +} + +func SerializeYAMLtoJSONstring(t *testing.T, fileName string) string { + values, err := readYAMLFile(fileName) + if err != nil { + t.Fatalf("Failed to read values.yaml: %v", err) + } + + jsonValues, err := json.Marshal(values) + if err != nil { + t.Fatalf("Failed to serialize YAML to JSON: %v", err) + } + return string(jsonValues) +}