v0.1.7: block device boot sources, migration priority, port security, scheduler hints, and resmgr absence detection - #45
Merged
Conversation
…abled Close the gaps between what the PCD UI's Deploy VM wizard and Simple Networking can do and what the provider could express. Every change is verified live against a 2026.4 CE lab, with the API as the judge and a "No changes" plan after each step. pcd_compute_instance gains block_device (Nova block_device_mapping_v2), mirroring openstack_compute_instance_v2 so configurations port unchanged. This unlocks the four wizard boot sources the provider could not express: a NEW volume from an image (the wizard's default), an EXISTING volume, a VOLUME SNAPSHOT, and INSTALL FROM ISO (blank root at boot_index 0 + the ISO as a cdrom device at boot_index 1). image_id / image_name become optional when a block_device supplies the root disk. Nova only accepts volume_type in a block-device mapping at compute API microversion >= 2.67, so the create call negotiates 2.67 when block devices are present — on a copy of the client, so read paths keep the 2.1 response shapes they were written against. Live: all four sources reach ACTIVE; libvirt shows the ISO on hda as device='cdrom' (IDE) with the blank target on vda (virtio), exactly what the wizard produces. pcd_compute_instance gains migration_priority (normal | low | high | never), a first-class handle on the DRR service's per-VM setting. It is stored as the "migration-priority" server-metadata key — precisely what the UI's Set Migration Priority dialog writes — and kept out of the user-facing metadata map on read, so the two attributes never drift against each other; configuring the key in metadata is rejected at plan time, as is an invalid value. Updatable in place, "" clears (Nova's metadata update merges, so clearing issues an explicit delete). Live: create/update/clear round-trip; user metadata keys survive; an out-of-band UI write shows up as a plan diff back to the configured value. pcd_networking_network gains port_security_enabled (default true), on the resource and data source. false is the defining property of a Layer 2 / "Simple" network — no subnet, no DHCP, no security groups — and with segments plus the simple_network tag the UI keys on, an L2 network is now one resource. Nova refuses to boot on a subnet-less network by id, so the instance attaches through a pcd_networking_port on it (the L2 model anyway); the example shows both halves. Live: create false → true → false round-trips; a VM boots on the L2 network via a port; the UI classifies the network as Layer 2.
resmgr does not 404 for an object that is gone. `GET /resmgr/v2/clusters/<name>`
answers 200 with a body of `null` for a cluster that was deleted or never
existed — reproduced against 2026.4:
$ curl .../resmgr/v2/clusters/does-not-exist -> 200, body: null
Decoded straight into a struct that is a nil unmarshal: no error, every field
left at zero. So Read reported the resource as present-but-blank, never reached
isNotFound, and never called RemoveResource — leaving Terraform convinced a
destroyed cluster still existed. The next apply then plans no create for it, so
a region that has been torn down can never be rebuilt, which is the whole point
of the resource.
Fixed in the shared getJSON helper rather than in one Read, so the cluster,
blueprint, host-config and host reads behind host_config_assignment and
host_role all get it: read the body first, and report a 200 that carries no
object as absence. Every getJSON caller fetches a single object by name or id,
so no list response passes through here.
Found by the new pre-PR regression suite on its first live run.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Everything a VM can be created from in the UI, the placement controls that need, and one
resmgr read that was quietly wrong.
Added
block_deviceonpcd_compute_instance— the four boot sources the create-VM wizard offersand the provider could not express: boot from a new volume, from an existing volume, from a volume
snapshot, and install from an ISO. Mirrors
openstack_compute_instance_v2so configurations portacross unchanged.
volume_typein a block-device mapping needs compute microversion 2.67, so thatis negotiated for the create call alone — read paths keep the 2.1 response shapes they were
written against.
migration_priorityonpcd_compute_instance— how DRR treats a VM when balancing hosts,stored as the
migration-prioritymetadata key exactly as the UI's dialog does. Updatable inplace, coexists with user metadata, and the reserved key is rejected at plan time.
port_security_enabledonpcd_networking_network(and its data source) — with it, a Layer 2/ "Simple" network is expressible: a provider segment, no subnet, port security off, tagged
simple_network. Note that Nova refuses to boot on a subnet-less network by uuid, so those VMsattach through a
pcd_networking_port; the example says so.scheduler_hintsonpcd_compute_instance—group,different_host,same_host,additional_properties.pcd_compute_servergroupexisted but nothing could join one.Fixed
availability_zone = "<az>:<host>"no longer fails with "inconsistent result after apply".Nova reports only the zone, so an admin's host pin was being dropped on read.
resmgr absence detection.
GET /resmgr/v2/clusters/<name>answers200with a body ofnullfor a cluster that is gone, rather than a
404. That decoded into a zero-value struct with noerror, so Read reported the resource as present-but-blank and never called
RemoveResource—leaving Terraform convinced a destroyed cluster still existed, and a torn-down region impossible
to rebuild. Fixed in the shared
getJSONhelper, so the blueprint, host-config and host reads getit too.
Before and after, same state, same out-of-band deletion:
Verification
Static:
go build,go vet,gofmt,golangci-lint(0 issues), unit tests across all 11packages,
make generateclean,terraform fmt -check examples/.Live, against a two-hypervisor PCD 2026.4 CE lab: all four block-device boot sources reach ACTIVE
with the ISO landing as an IDE cdrom (confirmed in libvirt); migration priority round-trips
including an out-of-band UI change showing as drift; port security false → true → false → omitted;
the L2 network classified as Layer 2 by the UI's own rule; and the full zero-to-hero path — empty
region to blueprint, cluster, host configs, four converged roles, image, flavour, VM, volume and a
ping — in 8m54s with a clean plan afterwards.
The absence-detection fix and the import gap it sits next to were both found by the new pre-PR
regression suite on its first live run. The import gap is tracked as #44 and is not addressed here.