@@ -163,6 +163,160 @@ When bonding is configured, the `ctlplaneInterface` should be set to the bond in
163163(e.g., `bond0`), and the physical interfaces specified in `bondInterfaces` will be configured
164164as members of the bond during node provisioning.
165165
166+ == Using custom OS Images with Provision Server
167+
168+ By default, OpenStackBaremetalSet automatically creates an `OpenStackProvisionServer` to
169+ serve the bundled OS image for node provisioning. However, you can use a custom provision
170+ server with a different OS image to boot the EDPM nodes. This assumes you have already built
171+ a qcow2 image with all the required packages for EDPM deployment. For instructions on building
172+ custom images, refer to the
173+ https://github.com/openstack-k8s-operators/edpm-image-builder[edpm-image-builder].
174+
175+ The `OpenStackProvisionServer` resource serves OS images (qcow2 format) for baremetal node
176+ provisioning. If you already have a qcow2 image, you can package it in a container image and
177+ use it with the custom provision server.
178+
179+ === Container Image Requirements
180+
181+ The container image used for `osContainerImageUrl` must:
182+
183+ . Contain the qcow2 disk image file and its checksum file
184+ . Have an entrypoint script (like `copy_out.sh`) that copies the qcow2 file to the directory
185+ specified by the `DEST_DIR` environment variable
186+ . Exit successfully after copying the file (it runs as an init container)
187+
188+ === Building a Container Image from an Existing qcow2
189+
190+ If you have an existing qcow2 image, you can package it using the `copy_out.sh` script from
191+ the https://github.com/openstack-k8s-operators/edpm-image-builder[edpm-image-builder]
192+ repository.
193+
194+ ==== Step 1: Generate Checksum File
195+
196+ *Required:* Create a checksum file for your qcow2 image. The provision server requires a
197+ checksum file to function properly - the checksum discovery agent will fail if no checksum
198+ file is found. The provision server supports MD5, SHA256, or SHA512 checksums. The checksum
199+ file must contain the hash type in its filename (e.g., `md5`, `sha256`, or `sha512`):
200+
201+ [,sh]
202+ ----
203+ # For SHA256 (recommended)
204+ sha256sum my-custom-image.qcow2 > my-custom-image.qcow2.sha256sum
205+
206+ # Or for MD5
207+ md5sum my-custom-image.qcow2 > my-custom-image.qcow2.md5sum
208+
209+ # Or for SHA512
210+ sha512sum my-custom-image.qcow2 > my-custom-image.qcow2.sha512sum
211+ ----
212+
213+ ==== Step 2: Clone the Repository
214+
215+ Clone the edpm-image-builder repository to get the `copy_out.sh` script:
216+
217+ [,sh]
218+ ----
219+ git clone https://github.com/openstack-k8s-operators/edpm-image-builder.git
220+ cd edpm-image-builder
221+ ----
222+
223+ ==== Step 3: Create Containerfile
224+
225+ Create a `Containerfile` (or `Dockerfile`) in the same directory. Copy both your qcow2 image
226+ and its checksum file (checksum is required):
227+
228+ [,dockerfile]
229+ ----
230+ FROM registry.access.redhat.com/ubi9/ubi-minimal:9.6
231+
232+ # Copy your qcow2 image and checksum file into the container
233+ # The copy_out.sh script expects files in the root directory (/) by default
234+ COPY my-custom-image.qcow2 /
235+ COPY my-custom-image.qcow2.sha256sum /
236+
237+ # Copy the copy_out.sh script from the repository
238+ COPY copy_out.sh /copy_out.sh
239+ RUN chmod +x /copy_out.sh
240+
241+ ENTRYPOINT ["/copy_out.sh"]
242+ ----
243+
244+ *Note:*
245+
246+ * Replace `my-custom-image.qcow2` with your actual qcow2 filename
247+ * Replace `my-custom-image.qcow2.sha256sum` with your checksum filename (must contain `md5`,
248+ `sha256`, or `sha512` in the filename to be detected by the provision server)
249+ * The files are copied to `/` (root directory) because `copy_out.sh` expects to find them
250+ there by default (the default `SRC_DIR` is `/`). You can set `ENV SRC_DIR=<path>` in your
251+ Containerfile if you want to use a different source directory.
252+ * The `copy_out.sh` script handles both compressed (`.qcow2.gz`) and uncompressed (`.qcow2`)
253+ images
254+
255+ ==== Step 4: Build and Push
256+
257+ Build and push the container image:
258+
259+ [,sh]
260+ ----
261+ buildah bud -f Containerfile -t <your-registry>/my-custom-os-image:latest
262+ buildah push <your-registry>/my-custom-os-image:latest
263+ ----
264+
265+ Or using podman/docker:
266+
267+ [,sh]
268+ ----
269+ podman build -f Containerfile -t <your-registry>/my-custom-os-image:latest
270+ podman push <your-registry>/my-custom-os-image:latest
271+ ----
272+
273+ === Using a Custom Image with OpenStackProvisionServer
274+
275+ After building and pushing your container image, use it with the `OpenStackProvisionServer`
276+ resource:
277+
278+ [,yaml]
279+ ----
280+ apiVersion: baremetal.openstack.org/v1beta1
281+ kind: OpenStackProvisionServer
282+ metadata:
283+ name: openstackprovisionserver
284+ spec:
285+ interface: enp1s0
286+ port: 6190
287+ osImage: my-custom-image.qcow2 # qcow2 file inside the container
288+ osContainerImageUrl: <your-registry>/my-custom-os-image:latest
289+ apacheImageUrl: registry.redhat.io/ubi9/httpd-24:latest
290+ agentImageUrl: quay.io/openstack-k8s-operators/openstack-baremetal-operator-agent:latest
291+ ----
292+
293+ === Using a Custom Provision Server with OpenStackDataPlaneNodeSet
294+
295+ If you've created a custom `OpenStackProvisionServer` (as shown above), you can reference it
296+ in your `OpenStackDataPlaneNodeSet` resource using the `baremetalSetTemplate` field. The
297+ `OpenStackDataPlaneNodeSet` is managed by the
298+ https://github.com/openstack-k8s-operators/openstack-operator[openstack-operator] and allows
299+ you to specify baremetal host provisioning details.
300+
301+ Simply set the `provisionServerName` field in the `baremetalSetTemplate`:
302+
303+ [,yaml]
304+ ----
305+ apiVersion: dataplane.openstack.org/v1beta1
306+ kind: OpenStackDataPlaneNodeSet
307+ metadata:
308+ name: example-nodeset
309+ spec:
310+ baremetalSetTemplate:
311+ provisionServerName: openstackprovisionserver
312+ osImage: my-custom-image.qcow2
313+ deploymentSSHSecret: custom-ssh-secret
314+ ctlplaneInterface: enp1s0
315+ nodes:
316+ edpm-compute-0:
317+ hostName: edpm-compute-0
318+ ----
319+
166320=== Relevant Status Condition
167321
168322`NodeSetBaremetalProvisionReady` condition in status condtions reflects the status of
0 commit comments