Skip to main content

How to Import an Existing Building Block Definition into OpenTofu as-code

What is this guide about?

This guide explains how to import existing building block definitions from the meshPanel into OpenTofu/Terraform for infrastructure-as-code management. After completing this guide, your building block definition will be managed through OpenTofu, allowing you to version control and manage it alongside your other infrastructure code.

Prerequisites

Before you begin, ensure you have:

  • meshStack Terraform Provider configured: You need a working OpenTofu/Terraform configuration with the meshStack provider set up. Ensure your OpenTofu version is at least 1.11, as we need support for write-only attributes.
  • API key with appropriate permissions: An API key with permissions to read, create and update building block definitions inside the target workspace. This API key is used to authenticate the meshstack provider against the meshStack public API. Note that when creating a new API key, a ready-to-copy meshstack provider configuration with pre-filled authentication is shown by the meshPanel.
  • Access to the meshPanel: To retrieve the building block definition UUID
  • Basic OpenTofu/Terraform knowledge: Familiarity with resources and import blocks

Step by Step Guide

1. Locate the Building Block Definition UUID

First, navigate to the building block definition you want to import in the meshPanel and note its UUID.

Building Block Definition in meshPanel

You can find the UUID in the details view of the building block definition. For this example, we'll use UUID 31cbe9ff-99b2-44a3-b381-9908d8617363.

2. Create an Import Block with Skeleton Configuration

Create an OpenTofu configuration file with an import block and a skeleton resource definition. The import block tells OpenTofu which existing resource to import, and the resource block will be filled with the actual values after import:

import {
id = "31cbe9ff-99b2-44a3-b381-9908d8617363" # fill in the actual UUID here
to = meshstack_building_block_definition.howto_example
}

resource "meshstack_building_block_definition" "howto_example" {
metadata = {
owned_by_workspace = "devops-platform"
}

spec = {
description = ""
display_name = ""
}

version_spec = {
draft = true # Set to false if the building block definition has already been released/published
implementation = {
terraform = {
repository_url = ""
terraform_version = ""
}
}
}
}

3. Run OpenTofu Plan to See Required Fields

Run tofu plan to see what OpenTofu will import. The plan output shows the differences between your skeleton configuration and the actual resource in meshStack:

meshstack_building_block_definition.howto_example: Preparing import... [id=31cbe9ff-99b2-44a3-b381-9908d8617363]
meshstack_building_block_definition.howto_example: Refreshing state...

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place (current -> planned)

OpenTofu will perform the following actions:

# meshstack_building_block_definition.howto_example will be updated in-place
# (imported from "31cbe9ff-99b2-44a3-b381-9908d8617363")
~ resource "meshstack_building_block_definition" "howto_example" {
~ metadata = {
owned_by_workspace = "devops-platform"
- tags = {
# ...SHORTENED
- "Clearance" = [
- "public",
]
} -> null
uuid = "31cbe9ff-99b2-44a3-b381-9908d8617363"
}
ref = {
kind = "meshBuildingBlockDefinition"
uuid = "31cbe9ff-99b2-44a3-b381-9908d8617363"
}
~ spec = {
~ description = "The AKS Starterkit provides application teams with a pre-configured Kubernetes environment following Likvid Bank's best practices. It includes a Git repository, a CI/CD pipeline using GitHub Actions, and a secure container registry integration." -> ""
~ display_name = "AKS Starterkit" -> ""
- notification_subscribers = [
- "user:alice@meshcloud.io",
- "user:bob@meshcloud.io",
] -> null
- readme = # ...SHORTENED
~ run_transparency = true -> false
symbol = # ...SHORTENED
target_type = "WORKSPACE_LEVEL"
use_in_landing_zones_only = false
}
# ...SHORTENED
~ version_spec = {
deletion_mode = "DELETE"
draft = true
~ implementation = {
~ terraform = {
async = false
- ref_name = "071f5887cd289ba91e18c281ef3d81b58d3e5021" -> null
- repository_path = "modules/aks/starterkit/buildingblock" -> null
~ repository_url = "https://github.com/meshcloud/meshstack-hub.git" -> ""
~ terraform_version = "1.9.0" -> ""
~ use_mesh_http_backend_fallback = true -> false
}
}
- inputs = {
- "creator" = {
- assignment_type = "AUTHOR" -> null
- description = "Information about the creator of the resources who will be assigned Project Admin role" -> null
- display_name = "Creator" -> null
- is_environment = false -> null
- type = "CODE" -> null
- updateable_by_consumer = false -> null
},
- # ...SHORTENED
} -> null
only_apply_once_per_tenant = false
- outputs = {
# ...SHORTENED
- "summary" = {
- assignment_type = "SUMMARY" -> null
- display_name = "Summary" -> null
- type = "STRING" -> null
},
} -> null
- permissions = [
- "BUILDINGBLOCK_DELETE",
- "BUILDINGBLOCK_LIST",
- "BUILDINGBLOCK_SAVE",
# ...SHORTENED
] -> null
runner_ref = {
kind = "meshBuildingBlockRunner"
uuid = "66ddc814-1e69-4dad-b5f1-3a5bce51c01f"
}
state = "DRAFT"
version_number = 6
}
~ versions = [
# ...SHORTENED
~ {
~ content_hash = "v1:b63ef1949f0e72840f43673f77c2b578b765eff7afdb84ae44016c93c21a0e06" -> "v1:099043c3b311aacc9a3af282a53d3e3988ff8cc234a233d5a5cb183eb3975df2"
number = 6
state = "DRAFT"
uuid = "8e508dfd-d683-4ef9-9415-edbdd78e92da"
},
]
}

Plan: 1 to import, 0 to add, 1 to change, 0 to destroy.
warning

Do not run tofu apply at this point unless you really want to modify the existing resource in meshStack. The goal is to import the resource as-is without making any changes.

4. Fill in Resource Configuration to Match Existing State

Using the plan output from step 3, update your resource configuration to match the actual values from meshStack. The goal is to eliminate all differences so that tofu plan shows no changes.

tip

You can use AI assistants like GitHub Copilot CLI or Claude to help complete this potentially tedious task by analyzing your local plan output and configuration files. You may try the following prompt:

Run tofu plan and check for changes upon resource import of the meshstack_building_block_definition. Change the current configuration such that no changes remain except for possible changes related to secret_value or other computed outputs. Never run tofu apply or destroy.

For example, looking at the plan output above, you need to add the tags to prevent them from being removed:

resource "meshstack_building_block_definition" "howto_example" {
metadata = {
owned_by_workspace = "devops-platform"
tags = {
BBEnvironment = ["prod", "dev", "qa", "test"]
BusinessUnit = ["IT"]
Clearance = ["public"]
}
}
# ...more config SHORTENED
}

For sensitive values which, for example, are contained within the inputs argument, the secret_value attribute can be specified as an empty string, as that write-only attribute is only applied if the corresponding secret_version is changed. Upon import, the secret_version is set to the current secret_hash value provided by the backend.

5. Verify Plan Shows No Changes

After filling in all resource fields, run tofu plan again to verify there are no differences:

tofu plan

You should see just the import, no changes:

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

This confirms that your Terraform configuration perfectly matches the existing building block definition in meshStack.

6. Import the Resource

Now you can safely import the resource by running:

tofu apply

This will import the building block definition into your Terraform state without making any changes to the actual resource in meshStack.

After the import completes successfully, you can remove the import block from your configuration (or keep it as documentation that this resource was imported).

Concepts

Guides