Skip to content

Commit fddd13f

Browse files
committed
fix(resmgr): blueprint schema fidelity; add vnc_floating_ip
Bring pcd_cluster_blueprint in line with what the blueprint API actually stores and what the product actually exposes, verified against PCD 2026.4 and the PCD UI source. Remove vm_high_availability and auto_resource_rebalancing. They are cluster-scoped: the blueprint API does not store them (a POST carrying both returns an object with neither key) and the UI never sends them in blueprintConfigBody. A user setting them here believed HA/DRR were on when nothing had happened. They remain on pcd_cluster, where they take effect. Optional+Computed, so omitting configs are unaffected. Make networking_type and enable_distributed_routing Computed-only. No product surface exposes them — the UI hardcodes ovn / true and pcdctl has no blueprint capability at all — but the API requires both on create with no server default (omitted or "" networkingType is rejected; omitted enableDistributedRouting is a 500). The provider now takes the UI's role and supplies the product values, and rejects any attempt to configure them, so Terraform cannot produce a region the UI never would. Add vnc_floating_ip on the resource and data source. resmgr silently discards vncFloatingIp on POST and persists it only on PUT (identical body: POST stores null, PUT stores the value); the UI never trips this because it sets the IP on a later save. On create the provider follows the POST with a PUT when the value is set. The API's null is modelled as "" so a user can clear it with vnc_floating_ip = "" and get a stable plan. Full lifecycle verified live — create, update, clear, omit, never-set — each followed by "No changes". Reword instance_shared_storage to match the UI toggle it maps to and reference vm_storage, so the flag is discoverable next to the path it qualifies. Fix the example, which set the now read-only networking_type.
1 parent cf06510 commit fddd13f

6 files changed

Lines changed: 132 additions & 108 deletions

File tree

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,32 @@ All notable changes to this project are documented here. The format is based on
66

77
## [Unreleased]
88

9+
## [0.1.6] - 2026-08-15
10+
11+
### Fixed
12+
- **`pcd_cluster_blueprint` silently accepted `vm_high_availability` and
13+
`auto_resource_rebalancing`.** These are cluster-scoped settings: the blueprint API does
14+
not store them (a POST carrying them returns an object without either key), and the PCD
15+
UI never sends them. A user who set them on the blueprint believed HA/DRR were enabled
16+
when nothing had happened. Both attributes are removed; they live on `pcd_cluster`, where
17+
they take effect. Not a breaking change for configurations that omitted them.
18+
- **`networking_type` and `enable_distributed_routing` are now read-only.** No product
19+
surface exposes them (the PCD UI hardcodes `ovn`/`true`; `pcdctl` has no blueprint
20+
capability), yet the API requires both on create with no server default. The provider now
21+
supplies the product values itself and rejects attempts to configure them, so a Terraform
22+
user cannot put a region into a state the UI would never produce.
23+
24+
### Added
25+
- **`pcd_cluster_blueprint.vnc_floating_ip`** (and on the data source): the floating IP
26+
through which VM VNC consoles are reached. Set `""` to clear. Works around a resmgr
27+
quirk where `POST /v2/blueprint` silently discards `vncFloatingIp` and only `PUT`
28+
persists it — on create the provider follows the POST with a PUT when the value is set.
29+
30+
### Changed
31+
- `instance_shared_storage` documentation now matches the UI toggle it maps to ("Enable
32+
if this path is mounted as shared storage (e.g. NFS) across all hosts") and references
33+
`vm_storage`, so the flag is discoverable next to the path it qualifies.
34+
935
## [0.1.5] - 2026-08-15
1036

1137
### Fixed

docs/data-sources/cluster_blueprint.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ data "pcd_cluster_blueprint" "example" {
2828
### Read-Only
2929

3030
- `dns_domain_name` (String) The internal DNS domain name for VMs.
31-
- `enable_distributed_routing` (Boolean) Whether distributed routing is enabled.
31+
- `enable_distributed_routing` (Boolean) Whether distributed routing is enabled for the region. PCD-set; not user-configurable.
3232
- `image_library_shared_storage` (Boolean) Whether the image library uses shared storage.
3333
- `image_library_storage` (String) The image library storage location.
34-
- `instance_shared_storage` (Boolean) Whether instance storage is shared.
35-
- `networking_type` (String) The networking type (`ovn` or `ovs`).
34+
- `instance_shared_storage` (Boolean) Whether `vm_storage` is mounted as shared storage (e.g. NFS) across all hosts.
35+
- `networking_type` (String) The networking type PCD selected for the region (`ovn`). PCD-set; not user-configurable.
3636
- `storage_backends_json` (String, Sensitive) The Cinder storage backends as a JSON string (contains credentials).
3737
- `virtual_networking` (Attributes) Virtual (tenant) networking settings. (see [below for nested schema](#nestedatt--virtual_networking))
38-
- `vm_storage` (String) The VM ephemeral storage path.
38+
- `vm_storage` (String) The path on each hypervisor where instance (ephemeral) storage lives.
39+
- `vnc_floating_ip` (String) The floating IP through which VM VNC consoles are reached, if any.
3940

4041
<a id="nestedatt--virtual_networking"></a>
4142
### Nested Schema for `virtual_networking`

docs/resources/cluster_blueprint.md

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ Manages a PCD cluster blueprint — the shared, declarative configuration that v
1717
# the existing blueprint (see import.sh) and then manage it here.
1818
resource "pcd_cluster_blueprint" "example" {
1919
name = "cluster-1"
20-
networking_type = "ovn"
2120
dns_domain_name = "example.local."
2221
2322
virtual_networking = {
@@ -26,9 +25,21 @@ resource "pcd_cluster_blueprint" "example" {
2625
vnid_range = "1000:2000"
2726
}
2827
28+
# Where instance (ephemeral) disks live on each hypervisor. Set
29+
# instance_shared_storage = true only if this path is mounted as shared
30+
# storage (e.g. NFS) across all hosts.
31+
vm_storage = "/opt/data/instances"
32+
instance_shared_storage = false
33+
34+
# Optional: a floating IP through which VM VNC consoles are reached.
35+
# vnc_floating_ip = "203.0.113.10"
36+
2937
# storage_backends_json is omitted here so the imported Cinder backends are
3038
# preserved. It is required only when creating a brand-new blueprint, and it
3139
# carries driver credentials (sensitive).
40+
41+
# networking_type and enable_distributed_routing are set by PCD (ovn / true)
42+
# and are read-only here; they appear in state but are not configurable.
3243
}
3344
```
3445

@@ -41,27 +52,19 @@ resource "pcd_cluster_blueprint" "example" {
4152

4253
### Optional
4354

44-
- `auto_resource_rebalancing` (Attributes) Automatic workload-rebalancing settings. (see [below for nested schema](#nestedatt--auto_resource_rebalancing))
4555
- `dns_domain_name` (String) The internal DNS domain name suffix for VMs (not Designate).
46-
- `enable_distributed_routing` (Boolean) Whether cluster-wide distributed routing is enabled.
4756
- `image_library_shared_storage` (Boolean) Whether the image library uses shared storage.
4857
- `image_library_storage` (String) The image library storage location.
49-
- `instance_shared_storage` (Boolean) Whether instance ephemeral storage is shared.
50-
- `networking_type` (String) The networking type: `ovn` (default) or `ovs`.
58+
- `instance_shared_storage` (Boolean) Set `true` when `vm_storage` is mounted as shared storage (e.g. NFS) across all hosts, so PCD can treat instance disks as shared. Matches the UI's "Enable if this path is mounted as shared storage across all hosts" toggle. Defaults to `false` (local disk).
5159
- `storage_backends_json` (String, Sensitive) The Cinder storage backends as a JSON string (contains credentials). Read back from the server; set it only to change backends.
5260
- `virtual_networking` (Attributes) Virtual (tenant) networking settings. (see [below for nested schema](#nestedatt--virtual_networking))
53-
- `vm_high_availability` (Attributes) VM high-availability settings. (see [below for nested schema](#nestedatt--vm_high_availability))
54-
- `vm_storage` (String) The VM ephemeral storage path.
55-
56-
<a id="nestedatt--auto_resource_rebalancing"></a>
57-
### Nested Schema for `auto_resource_rebalancing`
58-
59-
Optional:
61+
- `vm_storage` (String) The path on each hypervisor where instance (ephemeral) storage lives, e.g. `/opt/data/instances`.
62+
- `vnc_floating_ip` (String) A floating IP through which VM VNC consoles are reached. Leave unset for none.
6063

61-
- `enabled` (Boolean) Whether auto-rebalancing is enabled.
62-
- `rebalancing_frequency_mins` (Number) Rebalancing frequency in minutes (1-60).
63-
- `rebalancing_strategy` (String) `vm_workload_consolidation` or `node_resource_consolidation`.
64+
### Read-Only
6465

66+
- `enable_distributed_routing` (Boolean) Whether distributed routing is enabled. Always `true` — set by the provider to match the product; not user-configurable.
67+
- `networking_type` (String) The region's networking type. Always `ovn` — set by the provider to match the product; not user-configurable.
6568

6669
<a id="nestedatt--virtual_networking"></a>
6770
### Nested Schema for `virtual_networking`
@@ -72,14 +75,6 @@ Optional:
7275
- `underlay_type` (String) The underlay type: `vlan` or `other`.
7376
- `vnid_range` (String) The VLAN/VNI segmentation ID range (e.g. `1000:2000`).
7477

75-
76-
<a id="nestedatt--vm_high_availability"></a>
77-
### Nested Schema for `vm_high_availability`
78-
79-
Optional:
80-
81-
- `enabled` (Boolean) Auto-detect host failure and recover VMs.
82-
8378
## Import
8479

8580
Import is supported using the following syntax:

examples/resources/pcd_cluster_blueprint/resource.tf

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
# the existing blueprint (see import.sh) and then manage it here.
33
resource "pcd_cluster_blueprint" "example" {
44
name = "cluster-1"
5-
networking_type = "ovn"
65
dns_domain_name = "example.local."
76

87
virtual_networking = {
@@ -11,7 +10,19 @@ resource "pcd_cluster_blueprint" "example" {
1110
vnid_range = "1000:2000"
1211
}
1312

13+
# Where instance (ephemeral) disks live on each hypervisor. Set
14+
# instance_shared_storage = true only if this path is mounted as shared
15+
# storage (e.g. NFS) across all hosts.
16+
vm_storage = "/opt/data/instances"
17+
instance_shared_storage = false
18+
19+
# Optional: a floating IP through which VM VNC consoles are reached.
20+
# vnc_floating_ip = "203.0.113.10"
21+
1422
# storage_backends_json is omitted here so the imported Cinder backends are
1523
# preserved. It is required only when creating a brand-new blueprint, and it
1624
# carries driver credentials (sensitive).
25+
26+
# networking_type and enable_distributed_routing are set by PCD (ovn / true)
27+
# and are read-only here; they appear in state but are not configurable.
1728
}

internal/services/resmgr/blueprint_data_source.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type blueprintDataSourceModel struct {
3939
ImageLibrarySharedStorage types.Bool `tfsdk:"image_library_shared_storage"`
4040
InstanceSharedStorage types.Bool `tfsdk:"instance_shared_storage"`
4141
VMStorage types.String `tfsdk:"vm_storage"`
42+
VNCFloatingIP types.String `tfsdk:"vnc_floating_ip"`
4243
StorageBackendsJSON types.String `tfsdk:"storage_backends_json"`
4344
}
4445

@@ -53,9 +54,9 @@ type blueprintAPI struct {
5354
ImageLibrarySharedStorage bool `json:"imageLibrarySharedStorage"`
5455
InstanceSharedStorage bool `json:"instanceSharedStorage"`
5556
VMStorage string `json:"vmStorage"`
56-
VMHighAvailability *haAPI `json:"vmHighAvailability"`
57-
AutoResourceRebalancing *rebalanceAPI `json:"autoResourceRebalancing"`
58-
StorageBackends json.RawMessage `json:"storageBackends"`
57+
// Pointer: the API returns null for "no floating IP".
58+
VNCFloatingIP *string `json:"vncFloatingIp"`
59+
StorageBackends json.RawMessage `json:"storageBackends"`
5960
}
6061

6162
type haAPI struct {
@@ -89,8 +90,8 @@ func (d *blueprintDataSource) Schema(_ context.Context, _ datasource.SchemaReque
8990
MarkdownDescription: "Reads a PCD cluster blueprint by name.",
9091
Attributes: map[string]schema.Attribute{
9192
"name": schema.StringAttribute{Required: true, MarkdownDescription: "The blueprint (cluster) name."},
92-
"networking_type": schema.StringAttribute{Computed: true, MarkdownDescription: "The networking type (`ovn` or `ovs`)."},
93-
"enable_distributed_routing": schema.BoolAttribute{Computed: true, MarkdownDescription: "Whether distributed routing is enabled."},
93+
"networking_type": schema.StringAttribute{Computed: true, MarkdownDescription: "The networking type PCD selected for the region (`ovn`). PCD-set; not user-configurable."},
94+
"enable_distributed_routing": schema.BoolAttribute{Computed: true, MarkdownDescription: "Whether distributed routing is enabled for the region. PCD-set; not user-configurable."},
9495
"dns_domain_name": schema.StringAttribute{Computed: true, MarkdownDescription: "The internal DNS domain name for VMs."},
9596
"virtual_networking": schema.SingleNestedAttribute{
9697
Computed: true,
@@ -103,8 +104,9 @@ func (d *blueprintDataSource) Schema(_ context.Context, _ datasource.SchemaReque
103104
},
104105
"image_library_storage": schema.StringAttribute{Computed: true, MarkdownDescription: "The image library storage location."},
105106
"image_library_shared_storage": schema.BoolAttribute{Computed: true, MarkdownDescription: "Whether the image library uses shared storage."},
106-
"instance_shared_storage": schema.BoolAttribute{Computed: true, MarkdownDescription: "Whether instance storage is shared."},
107-
"vm_storage": schema.StringAttribute{Computed: true, MarkdownDescription: "The VM ephemeral storage path."},
107+
"vm_storage": schema.StringAttribute{Computed: true, MarkdownDescription: "The path on each hypervisor where instance (ephemeral) storage lives."},
108+
"instance_shared_storage": schema.BoolAttribute{Computed: true, MarkdownDescription: "Whether `vm_storage` is mounted as shared storage (e.g. NFS) across all hosts."},
109+
"vnc_floating_ip": schema.StringAttribute{Computed: true, MarkdownDescription: "The floating IP through which VM VNC consoles are reached, if any."},
108110
"storage_backends_json": schema.StringAttribute{Computed: true, Sensitive: true, MarkdownDescription: "The Cinder storage backends as a JSON string (contains credentials)."},
109111
},
110112
}
@@ -141,6 +143,11 @@ func (d *blueprintDataSource) Read(ctx context.Context, req datasource.ReadReque
141143
data.ImageLibrarySharedStorage = types.BoolValue(bp.ImageLibrarySharedStorage)
142144
data.InstanceSharedStorage = types.BoolValue(bp.InstanceSharedStorage)
143145
data.VMStorage = types.StringValue(bp.VMStorage)
146+
if bp.VNCFloatingIP != nil {
147+
data.VNCFloatingIP = types.StringValue(*bp.VNCFloatingIP)
148+
} else {
149+
data.VNCFloatingIP = types.StringValue("")
150+
}
144151

145152
if bp.VirtualNetworking != nil {
146153
obj, diags := types.ObjectValue(virtualNetworkingAttrTypes, map[string]attr.Value{

0 commit comments

Comments
 (0)