Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions dynamic_values/subnet.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ locals {
[
for value in var.subnets[zone] :
{
name = value.name # Subnet shortname
prefix_name = "${var.prefix}-${value.name}" # Creates a name of the prefix and subnet name
zone = index(keys(var.subnets), zone) + 1 # Zone 1, 2, or 3
zone_name = "${var.region}-${index(keys(var.subnets), zone) + 1}" # Contains region and zone
cidr = value.cidr # CIDR Block
no_prefix = value.no_addr_prefix # If true will not create addr prefix for subnet under any circumstance
count = index(var.subnets[zone], value) + 1 # Count of the subnet within the zone
acl = value.acl_name
name = value.name
resource_name = (var.prefix != null ? "${var.prefix}-${value.name}" : value.name)
prefix_name = "${var.prefix}-${value.name}" # Creates a name of the prefix and subnet name
zone = index(keys(var.subnets), zone) + 1 # Zone 1, 2, or 3
zone_name = "${var.region}-${index(keys(var.subnets), zone) + 1}" # Contains region and zone
cidr = value.cidr # CIDR Block
no_prefix = value.no_addr_prefix # If true will not create addr prefix for subnet under any circumstance
count = index(var.subnets[zone], value) + 1 # Count of the subnet within the zone
acl = value.acl_name
# Public gateway ID
public_gateway = (
lookup(value, "public_gateway", null) == true && lookup(var.use_public_gateways, zone, null) != null
Expand All @@ -34,7 +35,13 @@ locals {
# Convert list to map
subnet_map = {
for subnet in local.subnet_list :
"${var.prefix}-${subnet.name}" => subnet
"${subnet.zone}-${subnet.name}" => merge(
subnet,
{
subnet_id = "${subnet.zone}-${subnet.name}",
resource_name = var.prefix != null ? "${var.prefix}-${subnet.name}" : subnet.name
}
)
}
}

Expand Down
9 changes: 6 additions & 3 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,12 @@ locals {
}

resource "ibm_is_vpn_gateway" "vpn_gateway" {
for_each = local.vpn_gateway_map
name = var.prefix != null ? "${var.prefix}-${each.key}" : each.key
subnet = local.subnets["${local.vpc_name}-${each.value.subnet_name}"].id
for_each = local.vpn_gateway_map
name = var.prefix != null ? "${var.prefix}-${each.key}" : each.key
subnet = one([
for k, s in local.subnets :
s.id if endswith(k, "-${each.value.subnet_name}")
])
mode = each.value.mode
resource_group = each.value.resource_group == null ? var.resource_group_id : each.value.resource_group
tags = var.tags
Expand Down
10 changes: 5 additions & 5 deletions subnet.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ locals {
resource "ibm_is_vpc_address_prefix" "subnet_prefix" {
# Address prefixes replace subnet prefixes
# Only create prefix if creating subnets, flag not set to disable prefix creation, and no specific prefixes were supplied
for_each = { for k, v in local.subnet_object : k => v if(v.no_prefix == false && var.create_subnets == true && length(local.address_prefixes) == 0) }
name = each.value.prefix_name
for_each = { for k, v in local.subnet_object : v.subnet_id => v if(v.no_prefix == false && var.create_subnets == true && length(local.address_prefixes) == 0) }
name = each.value.resource_name
zone = each.value.zone_name
vpc = local.vpc_id
cidr = each.value.cidr
Expand All @@ -33,12 +33,12 @@ resource "ibm_is_vpc_address_prefix" "subnet_prefix" {
##############################################################################

resource "ibm_is_subnet" "subnet" {
for_each = var.create_subnets ? local.subnet_object : {}
for_each = var.create_subnets ? { for k, v in local.subnet_object : v.subnet_id => v } : {}
vpc = local.vpc_id
name = each.key
name = each.value.resource_name
zone = each.value.zone_name
resource_group = var.resource_group_id
ipv4_cidr_block = length(keys(local.address_prefixes)) == 0 && !each.value.no_prefix ? ibm_is_vpc_address_prefix.subnet_prefix[each.value.prefix_name].cidr : each.value.cidr
ipv4_cidr_block = length(keys(local.address_prefixes)) == 0 && !each.value.no_prefix ? ibm_is_vpc_address_prefix.subnet_prefix[each.value.subnet_id].cidr : each.value.cidr
network_acl = ibm_is_network_acl.network_acl[each.value.acl].id
public_gateway = each.value.public_gateway
tags = var.tags
Expand Down
106 changes: 106 additions & 0 deletions update/schematics_update_vpc_v8_to_v9.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env bash
set -euo pipefail

echo ""
echo "=============================================================="
echo " SLZ VPC v8 → v9 Migration Script for IBM Schematics"
echo "=============================================================="

WORKSPACE_ID=""
REGION=""
RESOURCE_GROUP=""

while getopts "w:r:g:" opt; do
case "$opt" in
w) WORKSPACE_ID="$OPTARG" ;;
r) REGION="$OPTARG" ;;
g) RESOURCE_GROUP="$OPTARG" ;;
*) ;;
esac
done

if [[ -z "$WORKSPACE_ID" || -z "$REGION" ]]; then
echo "❌ Usage: $0 -w WORKSPACE_ID -r REGION [-g RESOURCE_GROUP]"
exit 1
fi

echo "Using:"
echo " Workspace : $WORKSPACE_ID"
echo " Region : $REGION"
echo " Resource Group: ${RESOURCE_GROUP:-Default}"
echo ""

echo "🔐 Logging in..."
ibmcloud target -r "$REGION" >/dev/null

if [[ -n "$RESOURCE_GROUP" ]]; then
ibmcloud target -g "$RESOURCE_GROUP" >/dev/null
fi

echo "🔍 Fetching remote Schematics state..."
STATE_JSON=$(ibmcloud schematics state pull -id "$WORKSPACE_ID")

if [[ -z "$STATE_JSON" ]]; then
echo "❌ Could not retrieve workspace state"
exit 1
fi

echo "🔍 Extracting subnet keys..."
SUBNET_KEYS=$(echo "$STATE_JSON" | jq -r '
.resources[]?
| select(.type=="ibm_is_subnet")
| select(.module|contains("module.slz_vpc"))
| .instances[].index_key
')

if [[ -z "$SUBNET_KEYS" ]]; then
echo "❌ No SLZ VPC subnets found in workspace state."
exit 1
fi

echo ""
echo "Found subnets:"
echo "$SUBNET_KEYS"
echo ""

echo "🛠 Generating migration commands..."
COMMANDS_FILE="schematics_migration.txt"
: > "$COMMANDS_FILE"

for OLD_KEY in $SUBNET_KEYS; do
ZONE_SUFFIX=$(echo "$OLD_KEY" | awk -F '-' '{print $NF}')
NEW_KEY="1-subnet-$ZONE_SUFFIX"

printf '%s\n' \
"ibmcloud schematics state mv -id \"$WORKSPACE_ID\" \"module.slz_vpc.ibm_is_subnet.subnet[\\\"$OLD_KEY\\\"]\" \"module.slz_vpc.ibm_is_subnet.subnet[\\\"$NEW_KEY\\\"]\"" \
>> "$COMMANDS_FILE"

printf '%s\n' \
"ibmcloud schematics state mv -id \"$WORKSPACE_ID\" \"module.slz_vpc.ibm_is_vpc_address_prefix.subnet_prefix[\\\"$OLD_KEY\\\"]\" \"module.slz_vpc.ibm_is_vpc_address_prefix.subnet_prefix[\\\"$NEW_KEY\\\"]\"" \
>> "$COMMANDS_FILE"
done

echo ""
echo "=============================================================="
echo "Generated Schematics Migration Commands"
echo "=============================================================="
cat "$COMMANDS_FILE"

echo ""
read -r -p "Apply these migration commands now? (y/N): " CONFIRM

if [[ "$CONFIRM" != "y" ]]; then
echo "❌ Migration cancelled."
exit 0
fi

echo ""
echo "🚀 Applying migration..."
while IFS= read -r CMD; do
echo "Running: $CMD"
eval "$CMD"
done < "$COMMANDS_FILE"

echo ""
echo "✅ Migration completed successfully!"
echo "Run 'ibmcloud schematics plan -id $WORKSPACE_ID' to verify no subnets are recreated."
206 changes: 206 additions & 0 deletions update/update_version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
# Updating from v8 to v9

Version 9 of the Landing Zone VPC module changes how **subnets and VPC address prefixes are identified in Terraform state**.
Subnets and address prefixes now use a **stable, prefix-independent `resource_name`** as the Terraform state key.

In version 9, subnets and address prefixes use a **stable, prefix-independent `resource_name`** as the Terraform state key.

:information_source: **Important:**
Without migrating existing Terraform state, updating the `prefix` value will result in **subnet and address prefix destruction and recreation**.

Follow the steps below to safely upgrade to version 9 **without recreating networking resources**.

## Before you begin

Make sure you have recent versions of these command-line prerequisites.

- [IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cli-getting-started)
- [IBM Cloud CLI plug-ins](https://cloud.ibm.com/docs/cli?topic=cli-plug-ins):
- `is` plug-in (vpc-infrastructure)
- For IBM Schematics deployments: `sch` plug-in (schematics)
- JSON processor `jq` (https://jqlang.github.io/jq/)
- [Curl](). To test whether curl is installed on your system, run the following command:

```sh
curl -V
```

If you need to install curl, see https://everything.curl.dev/install/index.html.

## Select a procedure

Select the procedure that matches where you deployed the code.

- [Deployed with Schematics](#deployed-with-schematics)
- [Local Terraform](#local-terraform)

## Deployed with Schematics

If you deployed your IBM Cloud infrastructure by using Schematics, the `schematics_update_v8_to_v9.sh` script creates a Schematics job. [View the script](schematics_update_v8_to_v9.sh).

### Schematics process

1. Set the environment variables:

1. Set the IBM Cloud API key that has access to your IBM Cloud project or Schematics workspace. Run the following command:

```sh
export IBMCLOUD_API_KEY="<API-KEY>" #pragma: allowlist secret
```

Replace `<API-KEY>` with the value of your API key.

1. Find your Schematics workspace ID:
- If you are using IBM Cloud Projects:
1. Go to [Projects](https://cloud.ibm.com/projects)
1. Select the workspace associated with your VPC deployment
1. Click the **Configurations** tab.
1. Click the configuration name that is associated with your VPC deployment.
1. Under **Workspace** copy the ID.

- If you are not using IBM Cloud Projects:
1. Go to [Schematics Workspaces](https://cloud.ibm.com/schematics/workspaces)
1. Select the location that the workspace is in.
1. Select the workspace associated with your VPC deployment.
1. Click **Settings**.
1. Copy the **Workspace ID**.

1. Run the following command to set the workspace ID as an environment variable:

```sh
export WORKSPACE_ID="<workspace-id>"
```

1. Download the script by running this Curl command:

```sh
curl https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/update/schematics_update_v8_to_v9.sh > schematics_update_v8_to_v9.sh
```

1. Identify the region where the VPC is deployed.

1. Run the script:

```sh
bash schematics_update_v8_to_v9.sh \
-w "$WORKSPACE_ID" \
-r "<region>" \
[-g "<resource-group>"]
```

- -w : Schematics workspace ID
- -r : Region where the workspace resources are deployed
- -g : (Optional) Resource group to target


The script:

- Pulls the remote Schematics Terraform state
- Detects SLZ VPC subnet and address prefix resources
- Migrates state keys using `ibmcloud schematics state mv`



1. Monitor the status of the job by selecting the workspace from your [Schematics workspaces dashboard](https://cloud.ibm.com/schematics/workspaces).
- When the job completes successfully, go to the next step.
- If the job fails, see [Reverting changes](#reverting-changes).

### Apply the changes in Schematics

1. Update your configuration to consume version 9 of the Landing Zone VPC module.
1. In Schematics, click Generate plan and verify:

- No subnets are destroyed or re-created
- No address prefixes are destroyed or re-created
- Only in-place name updates are shown

1. Click Apply plan.

1. If the job is successful, follow the steps in [Clean up](#clean-up). If the job fails, see [Reverting changes](#reverting-changes).

## Local Terraform

If you store both the Terraform code and state file locally, run the `update_v8_to_v9.sh` script locally. [View the script](schematics_update_v8_to_v9.sh).

1. Set the IBM Cloud API key that has access to your VPCs as an environment variable by running the following command:

```sh
export IBMCLOUD_API_KEY="<API-KEY>" #pragma: allowlist secret
```

Replace `<API-KEY>` with the value of your API key.

1. Change to the directory containing your Terraform state file.

1. Download the script to the directory with the state file by running this Curl command:

```sh
curl https://raw.githubusercontent.com/terraform-ibm-modules/terraform-ibm-landing-zone-vpc/main/update/update_v8_to_v9.sh > update_v8_to_v9.sh
```

1. Run the script from the directory with the state file:

```sh
bash update_v8_to_v9.sh
```

The script:

- Reads the local Terraform state

- Detects prefix-based subnet and address prefix keys

- Generates terraform state mv commands

- Prompts for confirmation before applying changes


1. Initialize, check the planned changes, and apply the changes:


1. Run the `terraform init` command to pull the latest version.
1. Run the `terraform plan` command to make sure that none of the VPC resources will be re-created.

- You should see in-place updates to names. No resources should be set to be destroyed or re-created.

1. Run `terraform apply` to upgrade to the 9 version of the module and apply the update in place.
1. If the commands are successful, follow the steps in [Clean up](#clean-up).

### Expected Terraform plan after migration

#### After migrating the state and updating the prefix value:

- Subnets are updated in place

- Address prefixes are updated in place

- No CIDR changes occur

- No subnet or address prefix resources are re-created


```sh
Example
~ name = "testvpc-vpc-subnet-a" -> "testvpc1-vpc-subnet-a"
```

### Clean up

After a successful migration, remove temporary files created by the script:

```sh
rm moved.json revert.json
```

## Reverting changes

If the script fails, run the script again with the `-z` option to undo the changes. The script uses the `revert.json` file that was created when you ran the script without the `-z` option.

```sh
bash schematics_update_v8_to_v9.sh -z
```

- If you ran the job in Schematics, a new workspace job reverts the state to what existed before you ran the script initially.
- If your code and state file are on your computer, the script reverts changes to the local Terraform state file.

:exclamation: **Important:** After you revert the changes, don't run any other steps in this process. Create an IBM Cloud support case and include information about the script and errors. For more information, see [Creating support cases](https://cloud.ibm.com/docs/get-support?topic=get-support-open-case&interface=ui).
Loading