Skip to content

Commit f3daa9f

Browse files
Added sync for external CIDR
1 parent d8160c8 commit f3daa9f

File tree

7 files changed

+127
-60
lines changed

7 files changed

+127
-60
lines changed

README.md

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@ This Terraform module enables CAST AI Omni functionality for a Kubernetes cluste
77
- Enables CAST AI Omni functionality for existing clusters
88
- Installs and configures Liqo for multi-cluster networking
99
- Deploys CAST AI Omni Agent for cluster management
10-
- Automatic extraction of network configuration from GKE clusters
10+
- Automatic extraction of network configuration from GKE clusters (including external CIDR from Liqo)
1111
- Support for both zonal and regional GKE clusters
12-
- Configurable IPAM and network settings
12+
- Automatic synchronization with Liqo IPAM for external CIDR allocation
1313

1414
## Prerequisites
1515

1616
- An existing Kubernetes cluster onboarded to CAST AI
1717
- CAST AI API credentials
18+
- `kubectl` configured with access to your Kubernetes cluster
1819
- Terraform >= 1.11
19-
- CAST AI Terraform provider >= 8.1.1
20-
- Helm provider >= 3.0.0
20+
- CAST AI Terraform provider >= 8.1.0
21+
- Helm provider >= 2.0
22+
- Null provider >= 3.0
2123
- Google provider >= 4.0 (for GKE clusters)
2224

2325
## What This Module Installs
@@ -31,54 +33,49 @@ This Terraform module enables CAST AI Omni functionality for a Kubernetes cluste
3133
### Complete GKE Example
3234

3335
```hcl
36+
data "google_client_config" "default" {}
37+
3438
data "google_container_cluster" "gke" {
3539
project = var.gke_project_id
3640
location = var.gke_cluster_location
3741
name = var.gke_cluster_name
3842
}
3943
4044
locals {
41-
# Extract subnet and region/zone information
42-
subnet_name = element(reverse(split("/", data.google_container_cluster.gke.subnetwork)), 0)
45+
# The subnetwork can be a full path like "projects/PROJECT/regions/REGION/subnetworks/SUBNET"
46+
# or just the subnet name
47+
subnet_name = element(reverse(split("/", data.google_container_cluster.gke.subnetwork)), 0)
48+
49+
# Determine region from location (if zonal, extract region; if regional, use as-is)
4350
is_zonal_cluster = length(regexall("^.*-[a-z]$", var.gke_cluster_location)) > 0
4451
cluster_region = local.is_zonal_cluster ? regex("^(.*)-[a-z]$", var.gke_cluster_location)[0] : var.gke_cluster_location
4552
cluster_zone = local.is_zonal_cluster ? var.gke_cluster_location : ""
4653
}
4754
55+
# Get subnet details to retrieve the IP CIDR range
4856
data "google_compute_subnetwork" "gke_subnet" {
4957
project = var.gke_project_id
5058
name = local.subnet_name
5159
region = local.cluster_region
5260
}
5361
5462
module "castai-omni-cluster" {
55-
source = "github.com/castai/terraform-castai-omni-cluster"
63+
source = "../.."
5664
57-
# CAST AI Configuration
58-
api_url = "https://api.cast.ai"
65+
api_url = var.castai_api_url
5966
api_token = var.castai_api_token
6067
organization_id = var.organization_id
6168
cluster_id = var.cluster_id
6269
cluster_name = var.gke_cluster_name
70+
cluster_region = local.cluster_region
71+
cluster_zone = local.cluster_zone
6372
64-
# Cluster Location
65-
cluster_region = local.cluster_region
66-
cluster_zone = local.cluster_zone
67-
68-
# Kubernetes Configuration
69-
api_server_address = "https://${data.google_container_cluster.gke.endpoint}"
70-
71-
# Network Configuration
72-
external_cidr = var.external_cidr
73+
api_server_address = "https://${data.google_container_cluster.gke.endpoint}"
7374
pod_cidr = data.google_container_cluster.gke.cluster_ipv4_cidr
7475
service_cidr = data.google_container_cluster.gke.services_ipv4_cidr
7576
reserved_subnet_cidrs = [data.google_compute_subnetwork.gke_subnet.ip_cidr_range]
76-
77-
# Liqo Configuration
78-
liqo_chart_version = "v1.0.1-5"
7977
}
8078
81-
# Create edge location
8279
module "castai_gcp_edge_location" {
8380
source = "github.com/castai/terraform-castai-omni-edge-location"
8481
@@ -89,44 +86,60 @@ module "castai_gcp_edge_location" {
8986
region = "europe-west4"
9087
}
9188
89+
tags = {
90+
ManagedBy = "terraform"
91+
}
92+
9293
depends_on = [module.castai-omni-cluster]
9394
}
9495
```
9596

9697
### Required Providers
9798

9899
```hcl
100+
data "google_client_config" "default" {}
101+
102+
data "google_container_cluster" "gke" {
103+
project = var.gke_project_id
104+
location = var.gke_cluster_location
105+
name = var.gke_cluster_name
106+
}
107+
99108
terraform {
100109
required_version = ">= 1.11"
101110
102111
required_providers {
103112
castai = {
104113
source = "castai/castai"
105-
version = ">= 8.1.1"
106-
}
107-
helm = {
108-
source = "hashicorp/helm"
109-
version = ">= 3.0.0"
114+
version = ">= 8.1.0"
110115
}
111116
google = {
112117
source = "hashicorp/google"
113118
version = ">= 4.0"
114119
}
120+
helm = {
121+
source = "hashicorp/helm"
122+
version = ">= 2.0"
123+
}
115124
}
116125
}
117126
118-
provider "castai" {
119-
api_token = var.castai_api_token
120-
api_url = "https://api.cast.ai"
127+
provider "google" {
128+
project = var.gke_project_id
121129
}
122130
123131
provider "helm" {
124-
kubernetes {
132+
kubernetes = {
125133
host = "https://${data.google_container_cluster.gke.endpoint}"
126134
token = data.google_client_config.default.access_token
127-
cluster_ca_certificate = base64decode(data.google_container_cluster.gke.master_auth[0].cluster_ca_certificate)
135+
cluster_ca_certificate = base64decode(data.google_container_cluster.gke.master_auth.0.cluster_ca_certificate)
128136
}
129137
}
138+
139+
provider "castai" {
140+
api_token = var.castai_api_token
141+
api_url = var.castai_api_url
142+
}
130143
```
131144

132145
## Inputs
@@ -140,7 +153,6 @@ provider "helm" {
140153
| cluster_region | Kubernetes cluster region | `string` | - | yes |
141154
| cluster_zone | Kubernetes cluster zone | `string` | - | yes |
142155
| api_server_address | Kubernetes API server address | `string` | - | yes |
143-
| external_cidr | External CIDR for IPAM configuration | `string` | - | yes |
144156
| pod_cidr | Pod CIDR for network configuration | `string` | - | yes |
145157
| service_cidr | Service CIDR for network configuration | `string` | - | yes |
146158
| reserved_subnet_cidrs | List of reserved subnet CIDRs | `list(string)` | - | yes |
@@ -162,6 +174,7 @@ The module automatically extracts network configuration from your GKE cluster:
162174
- **Subnet CIDR**: Retrieved from the cluster's subnetwork
163175
- **Pod CIDR**: Retrieved from `cluster_ipv4_cidr`
164176
- **Service CIDR**: Retrieved from `services_ipv4_cidr`
177+
- **External CIDR**: Automatically extracted from Liqo network resources after IPAM initialization
165178
- **Region/Zone**: Automatically determined from cluster location
166179

167180
## Liqo Configuration
@@ -172,6 +185,20 @@ The module includes a GKE-specific submodule that:
172185
- Sets up topology labels for GKE region and zone
173186
- Enables virtual node capabilities for edge locations
174187

188+
## Installation Order and Dependencies
189+
190+
The module ensures proper installation order by:
191+
192+
1. **Liqo Installation** - Installs the Liqo Helm chart with network configuration
193+
2. **Network Resource Readiness Check** - Waits for Liqo network resources to be ready:
194+
- Waits for `networks.ipam.liqo.io` CRD to be established
195+
- Waits for the external CIDR network resource to be created and populated
196+
- Validates that the `status.cidr` field contains the external CIDR value
197+
3. **CAST AI Omni Cluster** - Enables Omni functionality in CAST AI
198+
4. **CAST AI Omni Agent** - Deploys the agent for cluster management
199+
200+
This ordering ensures that Liqo's IPAM system is fully initialized and the external CIDR network resource is available before proceeding with CAST AI components.
201+
175202
## Examples
176203

177204
See the [examples/onboarding-with-existing-gke-cluster](./examples/onboarding-with-existing-gke-cluster) directory for a complete working example.

examples/onboarding-with-existing-gke-cluster/main.tf

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ data "google_compute_subnetwork" "gke_subnet" {
2424
region = local.cluster_region
2525
}
2626

27-
module "castai-omni-cluster" {
27+
module "castai_omni_cluster" {
2828
source = "../.."
2929

3030
api_url = var.castai_api_url
@@ -36,25 +36,17 @@ module "castai-omni-cluster" {
3636
cluster_zone = local.cluster_zone
3737

3838
api_server_address = "https://${data.google_container_cluster.gke.endpoint}"
39-
external_cidr = var.external_cidr
4039
pod_cidr = data.google_container_cluster.gke.cluster_ipv4_cidr
4140
service_cidr = data.google_container_cluster.gke.services_ipv4_cidr
4241
reserved_subnet_cidrs = [data.google_compute_subnetwork.gke_subnet.ip_cidr_range]
4342
}
4443

45-
module "castai_gcp_edge_location" {
46-
source = "github.com/castai/terraform-castai-omni-edge-location"
44+
module "castai_omni_edge_location_gcp" {
45+
source = "github.com/castai/terraform-castai-omni-edge-location-gcp"
4746

4847
cluster_id = var.cluster_id
4948
organization_id = var.organization_id
49+
region = "europe-west4"
5050

51-
gcp = {
52-
region = "europe-west4"
53-
}
54-
55-
tags = {
56-
ManagedBy = "terraform"
57-
}
58-
59-
depends_on = [module.castai-omni-cluster]
51+
depends_on = [module.castai_omni_cluster]
6052
}

examples/onboarding-with-existing-gke-cluster/variables.tf

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,3 @@ variable "cluster_id" {
3434
description = "Cast AI Cluster ID"
3535
type = string
3636
}
37-
38-
variable "external_cidr" {
39-
description = "External CIDR for IPAM configuration"
40-
type = string
41-
}

main.tf

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ locals {
99
module "liqo" {
1010
source = "./modules/gke"
1111

12+
namespace = local.omni_namespace
1213
liqo_chart_version = var.liqo_chart_version
1314
cluster_name = var.cluster_name
1415
cluster_region = var.cluster_region
@@ -19,12 +20,67 @@ module "liqo" {
1920
reserved_subnet_cidrs = var.reserved_subnet_cidrs
2021
}
2122

23+
# Wait for Liqo network resources to be ready before proceeding
24+
resource "null_resource" "wait_for_liqo_network" {
25+
provisioner "local-exec" {
26+
command = <<-EOT
27+
set -e
28+
29+
echo "Waiting for Liqo networks.ipam.liqo.io CRD to be established..."
30+
kubectl wait --for condition=established --timeout=300s crd/networks.ipam.liqo.io
31+
32+
echo "Waiting for external CIDR network resource to be created..."
33+
timeout=300
34+
elapsed=0
35+
interval=5
36+
37+
while [ $elapsed -lt $timeout ]; do
38+
CIDR=$(kubectl get networks.ipam.liqo.io -n ${local.omni_namespace} \
39+
-l ipam.liqo.io/network-type=external-cidr \
40+
-o jsonpath='{.items[0].status.cidr}' 2>/dev/null || echo "")
41+
42+
if [ -n "$CIDR" ]; then
43+
echo "External CIDR network resource is ready: $CIDR"
44+
exit 0
45+
fi
46+
47+
echo "Waiting for external CIDR to be populated... ($elapsed/$timeout seconds)"
48+
sleep $interval
49+
elapsed=$((elapsed + interval))
50+
done
51+
52+
echo "Timeout waiting for external CIDR network resource"
53+
exit 1
54+
EOT
55+
}
56+
57+
depends_on = [module.liqo]
58+
}
59+
60+
# Extract the external CIDR value from Liqo network resource
61+
data "external" "liqo_external_cidr" {
62+
program = ["bash", "-c", <<-EOT
63+
CIDR=$(kubectl get networks.ipam.liqo.io -n ${local.omni_namespace} \
64+
-l ipam.liqo.io/network-type=external-cidr \
65+
-o jsonpath='{.items[0].status.cidr}' 2>/dev/null)
66+
67+
if [ -z "$CIDR" ]; then
68+
echo '{"cidr":""}'
69+
else
70+
echo "{\"cidr\":\"$CIDR\"}"
71+
fi
72+
EOT
73+
]
74+
75+
depends_on = [null_resource.wait_for_liqo_network]
76+
}
77+
2278
# Enabling CAST AI Omni functionality for a given cluster
2379
resource "castai_omni_cluster" "this" {
2480
cluster_id = var.cluster_id
2581
organization_id = var.organization_id
2682

27-
depends_on = [module.liqo]
83+
depends_on = [null_resource.wait_for_liqo_network]
2884
}
2985

3086
# CAST AI Omni Agent Helm Release
@@ -40,7 +96,7 @@ resource "helm_release" "omni_agent" {
4096
set = [
4197
{
4298
name = "network.externalCIDR"
43-
value = var.external_cidr
99+
value = data.external.liqo_external_cidr.result.cidr
44100
},
45101
{
46102
name = "network.podCIDR"

modules/gke/variables.tf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
variable "namespace" {
22
description = "Kubernetes namespace to install liqo"
33
type = string
4-
default = "liqo"
54
}
65

76
variable "liqo_chart_version" {

variables.tf

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ variable "api_server_address" {
4646
type = string
4747
}
4848

49-
variable "external_cidr" {
50-
description = "External CIDR for IPAM configuration"
51-
type = string
52-
default = "10.0.0.0/16"
53-
}
54-
5549
variable "pod_cidr" {
5650
description = "Pod CIDR for network configuration"
5751
type = string

versions.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@ terraform {
1010
source = "hashicorp/helm"
1111
version = ">= 3.0.0"
1212
}
13+
null = {
14+
source = "hashicorp/null"
15+
version = ">= 3.0"
16+
}
1317
}
1418
}

0 commit comments

Comments
 (0)