Skip to content

Commit 9da0ded

Browse files
grubmeshiclaude
andcommitted
feat: back meshstack_tenant with the v4 tenant API + migration
Reimplement meshstack_tenant on the shared v4 body (platform_ref, landing_zone_ref, platform_tenant_id, status, ref, wait_for_completion): - v3->v4 state upgrade (SchemaVersion 1): the upgrader resolves the tenant via the list endpoint (Configure runs before UpgradeResourceState) and backfills uuid + refs. - moved support from meshstack_tenant_v4 (shared body -> non-destructive). - import accepts a tenant UUID or the legacy workspace.project.location.platform composite. - singular data source reimplemented over TenantV4.List (composite key). - deprecate the meshstack_tenant_v4 resource (-> meshstack_tenant + moved) and the singular meshstack_tenant / meshstack_tenant_v4 data sources (-> plural meshstack_tenants). - rename the plural tenants data source's internal identifiers off the _v4 suffix (HCL name meshstack_tenants unchanged). Shared the v4 body schema + state mapping between meshstack_tenant and meshstack_tenant_v4. Adds a WithRawBlock test helper for moved-block configs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f3d3123 commit 9da0ded

17 files changed

Lines changed: 784 additions & 402 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
# v0.24.0
22

33
BREAKING CHANGES:
4-
- `meshstack_tenant_v4`: the tenant now references its platform and landing zone by ref instead of by identifier, aligning with other meshObject references. `spec.platform_identifier` (a string) is replaced by `spec.platform_ref` (`{uuid, kind}`) and `spec.landing_zone_identifier` (a string) by `spec.landing_zone_ref` (`{name, kind}`, where `name` is the landing zone identifier). Assign the referenced resources' computed `ref` outputs directly, e.g. `platform_ref = meshstack_platform.example.ref` and `landing_zone_ref = meshstack_landingzone.example.ref`. Both data sources expose the refs as computed outputs. Requires meshStack with the meshTenant v4 API carrying `platformRef`/`landingZoneRef`.
5-
6-
FEATURES:
7-
- `meshstack_landingzone` resource and data source now expose a computed `ref` output (`{name, kind}`) suitable for use as `landing_zone_ref` in `meshstack_tenant_v4`, matching the existing `ref` outputs on other resources.
4+
- `meshstack_tenant` now runs on the meshTenant v4 API and the resource body changed accordingly (the move itself upgrades state in place, without recreating the tenant): `metadata.platform_identifier``spec.platform_ref` (`{uuid, kind}`), `spec.local_id``spec.platform_tenant_id`, `spec.landing_zone_identifier``spec.landing_zone_ref` (`{name, kind}`), `metadata.assigned_tags``status.tags`, and `spec.quotas` is now a set. New computed `ref`, richer `status`, and a `wait_for_completion` toggle. Import accepts either the tenant UUID or the legacy `workspace.project.location.platform` composite. Requires meshStack with the meshTenant v4 API carrying `platformRef`/`landingZoneRef`. Upgrade caveats: the automatic state upgrade queries the backend and expects exactly one active tenant for the composite (it errors otherwise); and if you previously omitted the landing zone, set `landing_zone_ref` after upgrading, because it is `RequiresReplace` — leaving it unset forces a tenant recreate.
5+
- `meshstack_tenant_v4`: references its platform and landing zone by ref instead of by identifier. `spec.platform_identifier``spec.platform_ref` (`{uuid, kind}`) and `spec.landing_zone_identifier``spec.landing_zone_ref` (`{name, kind}`, where `name` is the landing zone identifier). Assign the referenced resources' computed `ref` outputs directly, e.g. `platform_ref = meshstack_platform.example.ref` and `landing_zone_ref = meshstack_landingzone.example.ref`.
86

97
FEATURES:
8+
- `meshstack_landingzone` resource and data source now expose a computed `ref` output (`{name, kind}`) suitable for use as `landing_zone_ref` in tenant resources, matching the existing `ref` outputs on other resources.
9+
- `meshstack_tenant` supports migrating from `meshstack_tenant_v4` with a `moved` block (both share the v4 body, so the move is non-destructive).
1010
- `meshstack_building_block_definition`: `version_spec.inputs` and `version_spec.outputs` now support an optional `display_order` (number) attribute that controls how inputs/outputs are arranged in meshPanel. It defaults to the already set value when omitted, or `0` if there is none.
1111

1212
FIXES:
1313
- `meshstack_building_block`: A `content_hash` wired from a definition's computed `content_hash` no longer triggers a re-run when the value changed only because the hash-algorithm version changed (e.g. after upgrading the provider). Such version-only differences are now recognized and ignored, while genuine content changes still re-run. Setting an arbitrary (non-versioned) `content_hash` to force a manual re-run continues to work.
1414

15+
DEPRECATIONS:
16+
- `meshstack_tenant_v4` (resource) is deprecated in favor of `meshstack_tenant`; migrate with a `moved` block. The resource stays registered for now.
17+
- The singular tenant data sources `meshstack_tenant` and `meshstack_tenant_v4` are deprecated in favor of the plural `meshstack_tenants` data source (which filters by workspace/project/platform).
18+
19+
NOTES:
20+
- The plural tenants data source is `meshstack_tenants` (the internal `*_v4` naming was dropped; the HCL type name is unchanged).
21+
1522
# v0.23.1
1623

1724
FIXES:

docs/data-sources/tenant.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ page_title: "meshstack_tenant Data Source - terraform-provider-meshstack"
44
subcategory: ""
55
description: |-
66
Single tenant by workspace, project, and platform.
7+
~> Preview: This resource is in preview. Breaking changes are possible without prior notice due to changes in the underlying meshStack preview API https://docs.meshcloud.io/api/technical-specifications#preview-endpoints or due to changes in this provider. Please ensure you are running the latest version of the provider and report any bugs via GitHub issues https://github.com/meshcloud/terraform-provider-meshstack/issues or via support@meshcloud.io.
78
---
89

910
# meshstack_tenant (Data Source)
1011

1112
Single tenant by workspace, project, and platform.
1213

14+
~> **Preview:** This resource is in preview. Breaking changes are possible without prior notice due to changes in the underlying [meshStack preview API](https://docs.meshcloud.io/api/technical-specifications#preview-endpoints) or due to changes in this provider. Please ensure you are running the latest version of the provider and report any bugs via [GitHub issues](https://github.com/meshcloud/terraform-provider-meshstack/issues) or via support@meshcloud.io.
15+
1316
## Example Usage
1417

1518
```terraform
@@ -32,30 +35,52 @@ data "meshstack_tenant" "name" {
3235
### Read-Only
3336

3437
- `spec` (Attributes) Tenant specification. (see [below for nested schema](#nestedatt--spec))
38+
- `status` (Attributes) Tenant status. (see [below for nested schema](#nestedatt--status))
3539

3640
<a id="nestedatt--metadata"></a>
3741
### Nested Schema for `metadata`
3842

3943
Required:
4044

41-
- `owned_by_project` (String)
42-
- `owned_by_workspace` (String)
43-
- `platform_identifier` (String)
45+
- `owned_by_project` (String) Identifier of the project the tenant belongs to.
46+
- `owned_by_workspace` (String) Identifier of the workspace the tenant belongs to.
47+
- `platform_identifier` (String) Identifier of the target platform (`<platform>.<location>`).
4448

4549
Read-Only:
4650

47-
- `assigned_tags` (Map of List of String)
51+
- `created_on` (String)
4852
- `deleted_on` (String)
53+
- `marked_for_deletion_on` (String)
54+
- `uuid` (String) The unique identifier (UUID) of the tenant.
4955

5056

5157
<a id="nestedatt--spec"></a>
5258
### Nested Schema for `spec`
5359

5460
Read-Only:
5561

56-
- `landing_zone_identifier` (String)
57-
- `local_id` (String)
58-
- `quotas` (Attributes List) (see [below for nested schema](#nestedatt--spec--quotas))
62+
- `landing_zone_ref` (Attributes) (see [below for nested schema](#nestedatt--spec--landing_zone_ref))
63+
- `platform_ref` (Attributes) (see [below for nested schema](#nestedatt--spec--platform_ref))
64+
- `platform_tenant_id` (String)
65+
- `quotas` (Attributes Set) (see [below for nested schema](#nestedatt--spec--quotas))
66+
67+
<a id="nestedatt--spec--landing_zone_ref"></a>
68+
### Nested Schema for `spec.landing_zone_ref`
69+
70+
Read-Only:
71+
72+
- `kind` (String)
73+
- `name` (String)
74+
75+
76+
<a id="nestedatt--spec--platform_ref"></a>
77+
### Nested Schema for `spec.platform_ref`
78+
79+
Read-Only:
80+
81+
- `kind` (String)
82+
- `uuid` (String)
83+
5984

6085
<a id="nestedatt--spec--quotas"></a>
6186
### Nested Schema for `spec.quotas`
@@ -64,3 +89,15 @@ Read-Only:
6489

6590
- `key` (String)
6691
- `value` (Number)
92+
93+
94+
95+
<a id="nestedatt--status"></a>
96+
### Nested Schema for `status`
97+
98+
Read-Only:
99+
100+
- `platform_type_identifier` (String)
101+
- `platform_workspace_identifier` (String)
102+
- `tags` (Map of List of String)
103+
- `tenant_name` (String)

docs/resources/tenant.md

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,31 @@
33
page_title: "meshstack_tenant Resource - terraform-provider-meshstack"
44
subcategory: ""
55
description: |-
6-
Single tenant by workspace, project, and platform.
6+
Manages a meshTenant.
7+
~> Preview: This resource is in preview. Breaking changes are possible without prior notice due to changes in the underlying meshStack preview API https://docs.meshcloud.io/api/technical-specifications#preview-endpoints or due to changes in this provider. Please ensure you are running the latest version of the provider and report any bugs via GitHub issues https://github.com/meshcloud/terraform-provider-meshstack/issues or via support@meshcloud.io.
78
---
89

910
# meshstack_tenant (Resource)
1011

11-
Single tenant by workspace, project, and platform.
12+
Manages a `meshTenant`.
13+
14+
~> **Preview:** This resource is in preview. Breaking changes are possible without prior notice due to changes in the underlying [meshStack preview API](https://docs.meshcloud.io/api/technical-specifications#preview-endpoints) or due to changes in this provider. Please ensure you are running the latest version of the provider and report any bugs via [GitHub issues](https://github.com/meshcloud/terraform-provider-meshstack/issues) or via support@meshcloud.io.
1215

1316
## Example Usage
1417

1518
```terraform
1619
resource "meshstack_tenant" "example" {
1720
metadata = {
18-
owned_by_workspace = data.meshstack_workspace.example.metadata.name
19-
owned_by_project = data.meshstack_project.example.metadata.name
20-
platform_identifier = data.meshstack_platform.example.identifier
21+
owned_by_workspace = data.meshstack_workspace.example.metadata.name
22+
owned_by_project = data.meshstack_project.example.metadata.name
2123
}
2224
2325
spec = {
24-
landing_zone_identifier = data.meshstack_landingzone.example.metadata.name
26+
platform_ref = data.meshstack_platform.example.ref
27+
landing_zone_ref = data.meshstack_landingzone.example.ref
2528
}
29+
30+
# wait_for_completion = true
2631
}
2732
```
2833

@@ -31,36 +36,104 @@ resource "meshstack_tenant" "example" {
3136

3237
### Required
3338

34-
- `metadata` (Attributes) Tenant metadata. Workspace, project and platform of the target tenant must be set here. (see [below for nested schema](#nestedatt--metadata))
39+
- `metadata` (Attributes) Metadata of the tenant. The `owned_by_workspace` and `owned_by_project` attributes must be set here. (see [below for nested schema](#nestedatt--metadata))
3540
- `spec` (Attributes) Tenant specification. (see [below for nested schema](#nestedatt--spec))
3641

42+
### Optional
43+
44+
- `wait_for_completion` (Boolean) Wait for tenant creation/deletion to complete. Note that tenant creation is considered complete when `spec.platformTenantId` is set and not necessarily when replication is finished. Defaults to `true`.
45+
46+
### Read-Only
47+
48+
- `ref` (Attributes) Reference to this tenant, can be used as `target_ref` in building block resources. (see [below for nested schema](#nestedatt--ref))
49+
- `status` (Attributes) Tenant status. (see [below for nested schema](#nestedatt--status))
50+
3751
<a id="nestedatt--metadata"></a>
3852
### Nested Schema for `metadata`
3953

4054
Required:
4155

42-
- `owned_by_project` (String) Identifier of the project the tenant belongs to.
43-
- `owned_by_workspace` (String) Identifier of the workspace the tenant belongs to.
44-
- `platform_identifier` (String) Identifier of the target platform.
56+
- `owned_by_project` (String) The identifier of the project that the tenant belongs to.
57+
- `owned_by_workspace` (String) The identifier of the workspace that the tenant belongs to.
4558

4659
Read-Only:
4760

48-
- `assigned_tags` (Map of List of String) Tags assigned to this tenant originating from workspace, payment method and project.
49-
- `deleted_on` (String) If the tenant has been submitted for deletion by a workspace manager, the date is shown here (e.g. 2020-12-22T09:37:43Z).
61+
- `created_on` (String) The creation timestamp of the meshTenant (e.g. `2020-12-22T09:37:43Z`).
62+
- `deleted_on` (String) The deletion timestamp of the tenant (e.g. `2020-12-22T09:37:43Z`).
63+
- `marked_for_deletion_on` (String) The timestamp when the tenant was marked for deletion (e.g. `2020-12-22T09:37:43Z`).
64+
- `uuid` (String) The unique identifier (UUID) of the tenant.
5065

5166

5267
<a id="nestedatt--spec"></a>
5368
### Nested Schema for `spec`
5469

70+
Required:
71+
72+
- `platform_ref` (Attributes) Reference to the platform this tenant belongs to, identified by its uuid. (see [below for nested schema](#nestedatt--spec--platform_ref))
73+
74+
Optional:
75+
76+
- `landing_zone_ref` (Attributes) Reference to the landing zone to assign to this tenant, identified by its name (the landing zone identifier). (see [below for nested schema](#nestedatt--spec--landing_zone_ref))
77+
- `platform_tenant_id` (String) The identifier of the tenant on the platform (e.g. GCP project ID or Azure subscription ID). If this is not set, a new tenant will be created. If this is set, an existing tenant will be imported. Otherwise, this field will be empty until a successful replication has run.
78+
- `quotas` (Attributes Set) Landing zone quota settings will be applied by default but can be changed here. (see [below for nested schema](#nestedatt--spec--quotas))
79+
80+
<a id="nestedatt--spec--platform_ref"></a>
81+
### Nested Schema for `spec.platform_ref`
82+
83+
Required:
84+
85+
- `uuid` (String) UUID of the platform.
86+
87+
Optional:
88+
89+
- `kind` (String) meshObject type, always `meshPlatform`.
90+
91+
92+
<a id="nestedatt--spec--landing_zone_ref"></a>
93+
### Nested Schema for `spec.landing_zone_ref`
94+
95+
Required:
96+
97+
- `name` (String) The name (identifier) of the landing zone.
98+
5599
Optional:
56100

57-
- `landing_zone_identifier` (String) Identifier of landing zone to assign to this tenant. **Note:** This field is only optional for platform type SERVICEREGISTRY, otherwise it is required.
58-
- `local_id` (String) Tenant ID local to the platform (e.g. GCP project ID, Azure subscription ID). Setting the local ID means that a tenant with this ID should be imported into meshStack. Not setting a local ID means that a new tenant should be created. Field will be empty until a successful replication has run. **Note:** Importing is a high-privileged operation and setting this field is possible only when using API Keys with admin permissions for saving tenants.
59-
- `quotas` (Attributes List) Set of applied tenant quotas. By default the landing zone quotas are applied to new tenants. (see [below for nested schema](#nestedatt--spec--quotas))
101+
- `kind` (String) meshObject type, always `meshLandingZone`.
102+
60103

61104
<a id="nestedatt--spec--quotas"></a>
62105
### Nested Schema for `spec.quotas`
63106

107+
Required:
108+
109+
- `key` (String)
110+
- `value` (Number)
111+
112+
113+
114+
<a id="nestedatt--ref"></a>
115+
### Nested Schema for `ref`
116+
117+
Read-Only:
118+
119+
- `kind` (String) meshObject type, always `meshTenant`.
120+
- `uuid` (String) UUID of the meshTenant.
121+
122+
123+
<a id="nestedatt--status"></a>
124+
### Nested Schema for `status`
125+
126+
Read-Only:
127+
128+
- `platform_type_identifier` (String) Identifier of the platform type.
129+
- `platform_workspace_identifier` (String) Some platforms create representations of workspaces, in such cases this will contain the identifier of the workspace on the platform.
130+
- `quotas` (Attributes Set) The effective quotas applied to the tenant. (see [below for nested schema](#nestedatt--status--quotas))
131+
- `tags` (Map of List of String) Tags assigned to this tenant.
132+
- `tenant_name` (String) The full tenant name, a concatenation of the workspace identifier, project identifier and platform identifier.
133+
134+
<a id="nestedatt--status--quotas"></a>
135+
### Nested Schema for `status.quotas`
136+
64137
Read-Only:
65138

66139
- `key` (String)

docs/resources/tenant_v4.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ Manages a `meshTenant` with API version 4.
1818
```terraform
1919
resource "meshstack_tenant_v4" "example" {
2020
metadata = {
21-
owned_by_workspace = one(data.meshstack_projects.example_all_projects_in_workspace.projects).metadata.owned_by_workspace
22-
owned_by_project = one(data.meshstack_projects.example_all_projects_in_workspace.projects).metadata.name
21+
owned_by_workspace = data.meshstack_workspace.example.metadata.name
22+
owned_by_project = data.meshstack_project.example.metadata.name
2323
}
2424
2525
spec = {
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
resource "meshstack_tenant" "example" {
22
metadata = {
3-
owned_by_workspace = data.meshstack_workspace.example.metadata.name
4-
owned_by_project = data.meshstack_project.example.metadata.name
5-
platform_identifier = data.meshstack_platform.example.identifier
3+
owned_by_workspace = data.meshstack_workspace.example.metadata.name
4+
owned_by_project = data.meshstack_project.example.metadata.name
65
}
76

87
spec = {
9-
landing_zone_identifier = data.meshstack_landingzone.example.metadata.name
8+
platform_ref = data.meshstack_platform.example.ref
9+
landing_zone_ref = data.meshstack_landingzone.example.ref
1010
}
11+
12+
# wait_for_completion = true
1113
}

examples/resources/meshstack_tenant_v4/resource.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
resource "meshstack_tenant_v4" "example" {
22
metadata = {
3-
owned_by_workspace = one(data.meshstack_projects.example_all_projects_in_workspace.projects).metadata.owned_by_workspace
4-
owned_by_project = one(data.meshstack_projects.example_all_projects_in_workspace.projects).metadata.name
3+
owned_by_workspace = data.meshstack_workspace.example.metadata.name
4+
owned_by_project = data.meshstack_project.example.metadata.name
55
}
66

77
spec = {

internal/provider/acctest/testconfig/build_tenant_v3.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ package testconfig
22

33
import "testing"
44

5-
// TenantV3 builds a tenant (v3) config using the provided prerequisite addresses.
6-
func TenantV3(t *testing.T, projectAddr, platformAddr, landingZoneAddr Traversal) (config Config, tenantAddr Traversal) {
5+
// Tenant builds a meshstack_tenant config (v4 body) using the provided prerequisite addresses.
6+
func Tenant(t *testing.T, projectAddr, platformAddr, landingZoneAddr Traversal) (config Config, tenantAddr Traversal) {
77
t.Helper()
88
return Resource{Name: "tenant"}.Config(t).WithFirstBlock(
99
ExtractAddress(&tenantAddr),
1010
Descend("metadata")(
1111
Descend("owned_by_workspace")(SetAddr(projectAddr, "metadata", "owned_by_workspace")),
1212
Descend("owned_by_project")(SetAddr(projectAddr, "metadata", "name")),
13-
Descend("platform_identifier")(SetAddr(platformAddr, "identifier")),
1413
),
1514
Descend("spec")(
16-
Descend("landing_zone_identifier")(SetAddr(landingZoneAddr, "metadata", "name")),
15+
Descend("platform_ref")(SetRawExpr("%s", platformAddr.Join("ref"))),
16+
Descend("landing_zone_ref")(SetRawExpr("%s", landingZoneAddr.Join("ref"))),
1717
),
1818
), tenantAddr
1919
}

internal/provider/acctest/testconfig/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,19 @@ func (c Config) Join(others ...Config) Config {
9898
return result
9999
}
100100

101+
// WithRawBlock parses raw HCL (e.g. a `moved {}` block) and appends its blocks to a cloned Config.
102+
func (c Config) WithRawBlock(raw string) Config {
103+
c.t.Helper()
104+
result := clone(c)
105+
parsed, diags := hclwrite.ParseConfig([]byte(raw), "", hcl.Pos{Line: 1, Column: 1})
106+
require.False(c.t, diags.HasErrors(), "WithRawBlock: failed to parse raw HCL: %s", diags.Error())
107+
for _, block := range parsed.Body().Blocks() {
108+
result.internal.Body().AppendNewline()
109+
result.internal.Body().AppendBlock(block)
110+
}
111+
return result
112+
}
113+
101114
// WithFirstBlock applies consumers to the first block of a cloned Config and returns the new Config.
102115
func (c Config) WithFirstBlock(consumers ...ExpressionConsumer) Config {
103116
c.t.Helper()

internal/provider/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func (p *MeshStackProvider) DataSources(_ context.Context) []func() datasource.D
208208
NewTagDefinitionDataSource,
209209
NewTagDefinitionsDataSource,
210210
NewTenantV4DataSource,
211-
NewTenantsV4DataSource,
211+
NewTenantsDataSource,
212212
NewLandingZoneDataSource,
213213
NewPlatformDataSource,
214214
NewPaymentMethodDataSource,

0 commit comments

Comments
 (0)