Skip to content

feat(openstack-sync-operator): migrate Ironic runbook shell-operator onto the generic openstack-sync-operator - #2229

Closed
haseebsyed12 wants to merge 1 commit into
mainfrom
openstack-sync-plugin-ironic-runbooks
Closed

feat(openstack-sync-operator): migrate Ironic runbook shell-operator onto the generic openstack-sync-operator#2229
haseebsyed12 wants to merge 1 commit into
mainfrom
openstack-sync-plugin-ironic-runbooks

Conversation

@haseebsyed12

@haseebsyed12 haseebsyed12 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

#2314

What does this change do?

Upgrade impact

  • This change requires operator action to upgrade. If checked, add the
    upgrade-impact label and a release note: run scriv create from the
    repository root and describe the required action in the generated
    changelog.d/ file. See RELEASING.md.

Operator action means anything a deployment has to do beyond a normal resync:
deploy repo or values changes, new or removed secrets, enabling or disabling a
component, or a manual one-time step.

@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 2 times, most recently from a21fc91 to 8625220 Compare August 24, 2026 13:07
@haseebsyed12 haseebsyed12 changed the title feat(openstack-sync-operator): ironic runbooks plugin feat(openstack-sync-operator): migrate Ironic runbook shell-operator onto the generic openstack-sync-operator Aug 24, 2026
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 7 times, most recently from b6a86ea to f16fcd4 Compare August 31, 2026 18:49
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 4 times, most recently from cc3de1a to 641d20c Compare August 31, 2026 19:46
@haseebsyed12
haseebsyed12 marked this pull request as ready for review August 31, 2026 19:48
@haseebsyed12
haseebsyed12 requested a review from a team August 31, 2026 19:48
@haseebsyed12 haseebsyed12 added the upgrade-impact Requires operator action to upgrade; needs a changelog.d/ release note fragment label Sep 1, 2026
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 2 times, most recently from e610929 to f4f810f Compare September 2, 2026 14:32
Comment thread .pre-commit-config.yaml Outdated
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch from f4f810f to 7af6827 Compare September 3, 2026 07:55
@haseebsyed12
haseebsyed12 requested a review from cardoe September 3, 2026 07:56
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 5 times, most recently from 0a11efd to 2906664 Compare September 3, 2026 19:02
@cardoe

cardoe commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Comparing this against the old shell-operator-ironic script, I think we've reintroduced a bug I already fixed once in 319dabc0.

patch_runbook() and set_traits() both build the request path from the runbook name:

def patch_runbook(conn: Any, name: str, patch: list[dict[str, Any]]) -> dict[str, Any]:
"""Apply a JSON patch to the runbook named *name*."""
response = _request(conn, "PATCH", f"{_RUNBOOKS_PATH}/{name}", json=patch)
return _json_body(response)
def delete_runbook(conn: Any, name: str) -> None:
"""Delete the runbook named *name*, treating an absent one as success."""
try:
_request(conn, "DELETE", f"{_RUNBOOKS_PATH}/{name}")
except openstack_exceptions.NotFoundException:
LOG.info("Runbook %s is already absent from Ironic", name)
def set_traits(conn: Any, name: str, traits: list[str]) -> None:
"""Replace every trait on the runbook named *name* with *traits*."""
_request(conn, "PUT", f"{_RUNBOOKS_PATH}/{name}/traits", json={"traits": traits})

and reconcile.py calls them with spec["runbookName"] instead of the runbook's uuid, even though the runbook object it already has in hand carries one:

def ensure_runbook(conn: Any, spec: dict[str, Any]) -> dict[str, Any]:
"""Create or converge the runbook *spec* describes, and return it."""
name = str(spec["runbookName"])
existing = client.get_runbook(conn, name)
if existing is None:
payload = build_payload(spec)
LOG.info(
"Creating Ironic runbook %s with %s step(s)", name, len(payload["steps"])
)
return client.create_runbook(conn, payload)
if is_managed_runbook(existing):
LOG.info("Ironic runbook %s already exists and is operator-owned", name)
else:
LOG.info(
"Adopting existing Ironic runbook %s; the CR is an ownership claim "
"for it, so the operator markers are being written to its extra",
name,
)
operations = _patch_operations(existing, spec)
if not operations:
return existing
LOG.info(
"Updating Ironic runbook %s: %s",
name,
", ".join(operation["path"] for operation in operations),
)
return client.patch_runbook(conn, name, operations)

def reconcile_traits(
conn: Any, runbook: dict[str, Any], spec: dict[str, Any]
) -> list[str]:
"""Converge the traits of *runbook* onto *spec*, and return the result."""
name = str(spec["runbookName"])
desired = desired_traits(spec)
current = [str(trait) for trait in runbook.get("traits") or []]
if sorted(current) == sorted(desired):
return current
LOG.info(
"Setting traits on Ironic runbook %s: have=%s want=%s",
name,
sorted(current),
sorted(desired),
)
client.set_traits(conn, name, desired)
return desired

That's the exact pattern 319dabc0 moved away from - the traits PUT and the runbook PATCH both needed the UUID against a real Ironic on the same microversion (1.112) this plugin targets. FakeBaremetal in the tests keys everything by name, so it won't catch this - this'll break the first time a runbook gets updated or its traits change against a real cluster.

We should be passing existing["uuid"] / runbook["uuid"] into patch_runbook and set_traits, not the name.

@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 2 times, most recently from 683a301 to 65b8d1a Compare September 4, 2026 07:38
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch 2 times, most recently from 2e6b8f5 to 98ea358 Compare September 4, 2026 14:22
…shell-operator-ironic` runbook controller which is no longer deployed by `components/ironic`
@haseebsyed12
haseebsyed12 force-pushed the openstack-sync-plugin-ironic-runbooks branch from 98ea358 to b5e9a93 Compare September 4, 2026 18:59
@haseebsyed12
haseebsyed12 deleted the openstack-sync-plugin-ironic-runbooks branch September 4, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

upgrade-impact Requires operator action to upgrade; needs a changelog.d/ release note fragment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants