Skip to content

Commit 908c303

Browse files
committed
PUC-1420: Implement an Ironic Runbook operator
feat: implemented an ironic runbook kubernetes controller feat: created an ironic runbook crd
1 parent 8001350 commit 908c303

22 files changed

+988
-0
lines changed

.github/workflows/containers.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ jobs:
3333
- dnsmasq
3434
- ironic-nautobot-client
3535
- understack-tests
36+
- shell-operator-ironic
3637
uses: ./.github/workflows/build-container-reuse.yaml
3738
secrets: inherit
3839
with:

components/ironic/kustomization.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ resources:
1212
# working due to the way the chart hardcodes the config-file parameter which then
1313
# takes precedence over the directory
1414
- configmap-ironic-bin.yaml
15+
- ./runbook-crd
16+
- ./runbook-operator
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Ironic Runbook Kubernetes CRD
2+
3+
Kubernetes Custom Resource Definition (CRD) for managing Ironic baremetal runbooks. Runbooks define automated sequences of operations (cleaning, configuration, firmware updates) to be executed on baremetal nodes.
4+
5+
## What is a Runbook?
6+
7+
A Runbook is a collection of ordered steps that define automated operations on baremetal nodes in Ironic. Runbooks enable:
8+
9+
- **Automated Cleaning**: Prepare nodes for reuse (disk wiping, BIOS config, firmware updates)
10+
- **Declarative Workflows**: Define repeatable, version-controlled sequences
11+
- **Trait-Based Matching**: Runbooks match to nodes when the runbook name matches a node trait
12+
13+
## Quick Start
14+
15+
### Installation
16+
17+
```bash
18+
# Install the CRD
19+
kubectl apply -f bases/baremetal.ironicproject.org_runbooks.yaml
20+
```
21+
22+
### Create Your First Runbook
23+
24+
```bash
25+
# Apply a minimal example
26+
kubectl apply -f samples/runbook_v1alpha1_minimal.yaml
27+
28+
# Verify it was created
29+
kubectl get runbooks
30+
kubectl describe runbook minimal-runbook
31+
```
32+
33+
### View Available Samples
34+
35+
```bash
36+
# List all sample runbooks
37+
ls samples/
38+
39+
# Apply a specific sample
40+
kubectl apply -f samples/runbook_bios_config.yaml
41+
```
42+
43+
## Field Requirements
44+
45+
### ✅ Required Fields
46+
47+
| Field | Type | Description |
48+
|-------|------|-------------|
49+
| `spec.runbookName` | string | Runbook name matching CUSTOM_* pattern |
50+
| `spec.steps` | array | Ordered list of steps (minimum 1) |
51+
| `steps[].interface` | enum | Hardware interface (bios, raid, deploy, etc.) |
52+
| `steps[].step` | string | Step name (non-empty) |
53+
| `steps[].order` | integer | Execution order (>= 0, unique) |
54+
55+
### ❌ Optional Fields
56+
57+
| Field | Type | Default | Description |
58+
|-------|------|---------|-------------|
59+
| `spec.disableRamdisk` | boolean | `false` | Skip ramdisk booting |
60+
| `spec.public` | boolean | `false` | Public accessibility |
61+
| `spec.owner` | string | `null` | Project/tenant owner |
62+
| `spec.extra` | object | `{}` | Additional metadata |
63+
| `steps[].args` | object | `{}` | Step-specific arguments |
64+
65+
## Minimal Example
66+
67+
```yaml
68+
apiVersion: baremetal.ironicproject.org/v1alpha1
69+
kind: IronicRunbook
70+
metadata:
71+
name: minimal-runbook
72+
namespace: default
73+
spec:
74+
runbookName: CUSTOM_MINIMAL
75+
steps:
76+
- interface: deploy
77+
step: erase_devices
78+
order: 1
79+
```
80+
81+
## Sample Runbooks
82+
83+
| Sample | Use Case | Description |
84+
|--------|----------|-------------|
85+
| `runbook_v1alpha1_minimal.yaml` | Learning | Minimal example with required fields only |
86+
| `runbook_v1alpha1_complete.yaml` | Reference | Complete example with all fields |
87+
| `runbook_bios_config.yaml` | Compute Nodes | BIOS configuration for virtualization |
88+
| `runbook_raid_config.yaml` | Storage Nodes | RAID setup (OS + data volumes) |
89+
| `runbook_firmware_update.yaml` | Maintenance | Firmware updates (BIOS, BMC, NIC) |
90+
| `runbook_disk_cleaning.yaml` | Node Reuse | Secure disk erasure |
91+
| `runbook_gpu_node_setup.yaml` | ML/AI | GPU node configuration |
92+
93+
## Support
94+
95+
- **Ironic Documentation**: https://docs.openstack.org/ironic/latest/
96+
- **Kubernetes CRDs**: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/
97+
98+
---
99+
100+
**Version**: v1alpha1
101+
**API Group**: baremetal.ironicproject.org
102+
**Kind**: IronicRunbook
103+
**Short Name**: rb
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: ironicrunbooks.baremetal.ironicproject.org
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.13.0
7+
spec:
8+
group: baremetal.ironicproject.org
9+
names:
10+
kind: IronicRunbook
11+
listKind: IronicRunbookList
12+
plural: ironicrunbooks
13+
singular: ironicrunbook
14+
shortNames:
15+
- rb
16+
scope: Namespaced
17+
versions:
18+
- name: v1alpha1
19+
served: true
20+
storage: true
21+
schema:
22+
openAPIV3Schema:
23+
description: IronicRunbook represents a collection of ordered steps that define automated operations on baremetal nodes
24+
type: object
25+
required:
26+
- spec
27+
properties:
28+
apiVersion:
29+
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
30+
type: string
31+
kind:
32+
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
33+
type: string
34+
metadata:
35+
type: object
36+
spec:
37+
description: IronicRunbookSpec defines the desired state of IronicRunbook
38+
type: object
39+
required:
40+
- runbookName
41+
- steps
42+
properties:
43+
runbookName:
44+
description: 'RunbookName is the unique name of the runbook (REQUIRED). Must match trait naming convention, typically CUSTOM_*. This name is used to match runbooks to nodes via traits.'
45+
type: string
46+
pattern: '^CUSTOM_[A-Z0-9_]+$'
47+
minLength: 1
48+
maxLength: 255
49+
steps:
50+
description: 'Steps is an ordered list of operations to execute (REQUIRED). Minimum 1 step required.'
51+
type: array
52+
minItems: 1
53+
items:
54+
description: RunbookStep defines a single step in the runbook
55+
type: object
56+
required:
57+
- interface
58+
- step
59+
- order
60+
properties:
61+
interface:
62+
description: 'Interface specifies which hardware interface handles this step (REQUIRED). Must be one of the valid Ironic cleaning interfaces.'
63+
type: string
64+
enum:
65+
- bios
66+
- raid
67+
- deploy
68+
- management
69+
- power
70+
- storage
71+
- vendor
72+
- rescue
73+
- console
74+
- boot
75+
- inspect
76+
- network
77+
- firmware
78+
step:
79+
description: 'Step is the name of the step to execute (REQUIRED). Must be a valid step name for the specified interface.'
80+
type: string
81+
minLength: 1
82+
maxLength: 255
83+
order:
84+
description: 'Order defines the execution sequence (REQUIRED). Must be >= 0 and unique within the runbook. Lower numbers execute first.'
85+
type: integer
86+
minimum: 0
87+
args:
88+
description: 'Args contains step-specific arguments (OPTIONAL). Structure depends on the interface and step. Default: {}'
89+
type: object
90+
x-kubernetes-preserve-unknown-fields: true
91+
disableRamdisk:
92+
description: 'DisableRamdisk skips booting the ramdisk for cleaning operations (OPTIONAL). Use when steps can run without IPA (Ironic Python Agent). Default: false'
93+
type: boolean
94+
default: false
95+
public:
96+
description: 'Public makes the runbook accessible to all projects/tenants (OPTIONAL). Cannot be true if owner is set. Default: false'
97+
type: boolean
98+
default: false
99+
owner:
100+
description: 'Owner identifies the project/tenant that owns this runbook (OPTIONAL). Cannot be set if public is true. Default: null'
101+
type: string
102+
nullable: true
103+
maxLength: 255
104+
extra:
105+
description: 'Extra contains additional metadata (OPTIONAL). Use for descriptions, versions, maintainer info, etc. Default: {}'
106+
type: object
107+
x-kubernetes-preserve-unknown-fields: true
108+
status:
109+
description: RunbookStatus defines the observed state of Runbook
110+
type: object
111+
properties:
112+
ironicUUID:
113+
description: IronicUUID is the UUID of this runbook in the Ironic API
114+
type: string
115+
syncStatus:
116+
description: SyncStatus indicates the synchronization state with Ironic
117+
type: string
118+
enum:
119+
- Synced
120+
- Pending
121+
- Failed
122+
- Unknown
123+
lastSyncTime:
124+
description: LastSyncTime is the timestamp of the last successful sync with Ironic
125+
type: string
126+
format: date-time
127+
observedGeneration:
128+
description: ObservedGeneration reflects the generation of the most recently observed Runbook
129+
type: integer
130+
format: int64
131+
conditions:
132+
description: Conditions represent the latest available observations of the runbook's state
133+
type: array
134+
items:
135+
description: Condition contains details for one aspect of the current state of this API Resource
136+
type: object
137+
required:
138+
- type
139+
- status
140+
- lastTransitionTime
141+
properties:
142+
type:
143+
description: Type of condition (e.g., Ready, Validated, Synced)
144+
type: string
145+
status:
146+
description: Status of the condition (True, False, Unknown)
147+
type: string
148+
enum:
149+
- "True"
150+
- "False"
151+
- Unknown
152+
lastTransitionTime:
153+
description: LastTransitionTime is the last time the condition transitioned from one status to another
154+
type: string
155+
format: date-time
156+
reason:
157+
description: Reason contains a programmatic identifier indicating the reason for the condition's last transition
158+
type: string
159+
message:
160+
description: Message is a human readable message indicating details about the transition
161+
type: string
162+
subresources:
163+
status: {}
164+
additionalPrinterColumns:
165+
- name: Runbook Name
166+
type: string
167+
description: The runbook name used for trait matching
168+
jsonPath: .spec.runbookName
169+
- name: Steps
170+
type: integer
171+
description: Number of steps in the runbook
172+
jsonPath: .spec.steps[*]
173+
- name: Public
174+
type: boolean
175+
description: Whether the runbook is public
176+
jsonPath: .spec.public
177+
- name: Sync Status
178+
type: string
179+
description: Synchronization status with Ironic
180+
jsonPath: .status.syncStatus
181+
- name: Age
182+
type: date
183+
jsonPath: .metadata.creationTimestamp
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: kustomize.config.k8s.io/v1beta1
2+
kind: Kustomization
3+
4+
# Namespace for runbook resources
5+
namespace: openstack
6+
7+
# Create namespace if it doesn't exist
8+
resources:
9+
- bases/baremetal.ironicproject.org_runbooks.yaml
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# BIOS Configuration Runbook
2+
#
3+
# This runbook configures BIOS settings for compute nodes.
4+
# Common use case: Enabling virtualization features for hypervisor nodes.
5+
#
6+
# Matches nodes with trait: CUSTOM_COMPUTE_BIOS
7+
8+
apiVersion: baremetal.ironicproject.org/v1alpha1
9+
kind: IronicRunbook
10+
metadata:
11+
name: compute-bios-config
12+
namespace: baremetal-system
13+
labels:
14+
use-case: bios-configuration
15+
hardware-type: compute
16+
spec:
17+
runbookName: CUSTOM_COMPUTE_BIOS
18+
19+
steps:
20+
- interface: bios
21+
step: apply_configuration
22+
order: 1
23+
args:
24+
settings:
25+
# Enable logical processors (hyperthreading)
26+
- name: LogicalProc
27+
value: Enabled
28+
29+
# Enable virtualization technology
30+
- name: VirtualizationTechnology
31+
value: Enabled
32+
33+
# Enable Intel VT-d (IOMMU)
34+
- name: VtForDirectIo
35+
value: Enabled
36+
37+
# Enable SR-IOV support
38+
- name: SRIOV
39+
value: Enabled
40+
41+
# Set boot mode to UEFI
42+
- name: BootMode
43+
value: Uefi
44+
45+
# Enable secure boot
46+
- name: SecureBoot
47+
value: Enabled
48+
49+
extra:
50+
description: "BIOS configuration for compute nodes with virtualization support"
51+
version: "1.0.0"
52+
use_case: "Hypervisor node preparation"
53+
hardware_compatibility:
54+
- "Dell PowerEdge R740"
55+
- "Dell PowerEdge R640"
56+
- "HPE ProLiant DL380 Gen10"
57+
notes: |
58+
This runbook enables common virtualization features required for
59+
running KVM/QEMU workloads. Adjust settings based on your specific
60+
hardware and requirements.

0 commit comments

Comments
 (0)