diff --git a/.github/workflows/publish_docs.yaml b/.github/workflows/publish_docs.yaml new file mode 100644 index 00000000..fdb17b36 --- /dev/null +++ b/.github/workflows/publish_docs.yaml @@ -0,0 +1,23 @@ +name: Publish docs via GitHub Pages +on: + push: + branches: [ main ] + +jobs: + build: + name: Deploy docs + runs-on: ubuntu-latest + steps: + - name: Checkout main + uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 'pypy3.9' + - uses: actions/cache@v4 + with: + key: ${{ github.ref }} + path: .cache + - name: Deploy docs + uses: afritzler/mkdocs-gh-pages-action@main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.reuse/dep5 b/.reuse/dep5 index 2d17e7d2..4d2cb100 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -27,6 +27,7 @@ Files: test/* CONTRIBUTING.md PROJECT + mkdocs.yml .dockerignore .golangci.yml Copyright: 2024 SAP SE or an SAP affiliate company and IronCore contributors diff --git a/Makefile b/Makefile index 4198fb78..4c6a3f82 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,9 @@ IMG ?= controller:latest # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.31.0 +# Docker image name for the mkdocs based local development setup +IMAGE=ironcore-dev/boot-operator-docs + # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) GOBIN=$(shell go env GOPATH)/bin @@ -171,6 +174,7 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION) GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION) ADDLICENSE ?= $(LOCALBIN)/addlicense GOIMPORTS ?= $(LOCALBIN)/goimports-$(GOIMPORTS_VERSION) +GEN_CRD_API_REFERENCE_DOCS ?= $(LOCALBIN)/gen-crd-api-reference-docs-$(GEN_CRD_API_REFERENCE_DOCS_VERSION) ## Tool Versions KUSTOMIZE_VERSION ?= v5.3.0 @@ -179,6 +183,7 @@ ENVTEST_VERSION ?= latest GOLANGCI_LINT_VERSION ?= v1.61.0 ADDLICENSE_VERSION ?= v1.1.1 GOIMPORTS_VERSION ?= v0.26.0 +GEN_CRD_API_REFERENCE_DOCS_VERSION ?= v0.3.0 .PHONY: kustomize kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. @@ -200,6 +205,16 @@ golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. $(GOLANGCI_LINT): $(LOCALBIN) $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION}) + +.PHONY: startdocs +startdocs: ## Start the local mkdocs based development environment. + docker build -t $(IMAGE) -f docs/Dockerfile . --load + docker run -p 8000:8000 -v `pwd`/:/docs $(IMAGE) + +.PHONY: cleandocs +cleandocs: ## Remove all local mkdocs Docker images (cleanup). + docker container prune --force --filter "label=project=boot_operator" + .PHONY: addlicense addlicense: $(ADDLICENSE) ## Download addlicense locally if necessary. $(ADDLICENSE): $(LOCALBIN) @@ -210,6 +225,15 @@ goimports: $(GOIMPORTS) ## Download goimports locally if necessary. $(GOIMPORTS): $(LOCALBIN) $(call go-install-tool,$(GOIMPORTS),golang.org/x/tools/cmd/goimports,$(GOIMPORTS_VERSION)) +.PHONY: docs +docs: gen-crd-api-reference-docs ## Run go generate to generate API reference documentation. + $(GEN_CRD_API_REFERENCE_DOCS) -api-dir ./api/v1alpha1 -config ./hack/api-reference/config.json -template-dir ./hack/api-reference/template -out-file ./docs/api-reference/api.md + +.PHONY: gen-crd-api-reference-docs +gen-crd-api-reference-docs: $(GEN_CRD_API_REFERENCE_DOCS) ## Download gen-crd-api-reference-docs locally if necessary. +$(GEN_CRD_API_REFERENCE_DOCS): $(LOCALBIN) + $(call go-install-tool,$(GEN_CRD_API_REFERENCE_DOCS),github.com/ahmetb/gen-crd-api-reference-docs,$(GEN_CRD_API_REFERENCE_DOCS_VERSION)) + # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary (ideally with version) # $2 - package url which can be installed diff --git a/README.md b/README.md index cbab3e83..fb2871b3 100644 --- a/README.md +++ b/README.md @@ -113,8 +113,6 @@ More information can be found via the [Kubebuilder Documentation](https://book.k ## Roadmap Looking ahead, the boot-Operator aims to introduce a range of enhancements to further empower Kubernetes-driven infrastructure provisioning: -- Configurable iPXE Scripts: Enable customization of iPXE script templates to accommodate diverse booting requirements. - - Custom Image Registry Support: Dynamically generate URLs for the kernel, initrd, and squashfs images from a specified image registry, facilitating streamlined updates and deployments. - Expanded Endpoints: Introduce additional endpoints, such as `/ztp` for Zero Touch Provisioning of switches and `/certs` for certificate management, broadening the operator's utility. diff --git a/api/v1alpha1/doc.go b/api/v1alpha1/doc.go new file mode 100644 index 00000000..91165b24 --- /dev/null +++ b/api/v1alpha1/doc.go @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +// Package v1alpha1 contains API Schema definitions for the settings.gardener.cloud API group +// +groupName=metal.ironcore.dev +// +kubebuilder:object:generate=true +package v1alpha1 diff --git a/api/v1alpha1/httpbootconfig_types.go b/api/v1alpha1/httpbootconfig_types.go index f839aa67..374fc7bf 100644 --- a/api/v1alpha1/httpbootconfig_types.go +++ b/api/v1alpha1/httpbootconfig_types.go @@ -10,10 +10,17 @@ import ( // HTTPBootConfigSpec defines the desired state of HTTPBootConfig type HTTPBootConfigSpec struct { - SystemUUID string `json:"systemUUID,omitempty"` + // SystemUUID is the unique identifier (UUID) of the server. + SystemUUID string `json:"systemUUID,omitempty"` + + // IgnitionSecretRef is a reference to the secret containing Ignition configuration. IgnitionSecretRef *corev1.LocalObjectReference `json:"ignitionSecretRef,omitempty"` - SystemIPs []string `json:"systemIPs,omitempty"` - UKIURL string `json:"ukiURL,omitempty"` + + // SystemIPs is a list of IP addresses assigned to the server. + SystemIPs []string `json:"systemIPs,omitempty"` + + // UKIURL is the URL where the UKI (Unified Kernel Image) is hosted. + UKIURL string `json:"ukiURL,omitempty"` } // HTTPBootConfigStatus defines the observed state of HTTPBootConfig @@ -24,9 +31,14 @@ type HTTPBootConfigStatus struct { type HTTPBootConfigState string const ( - HTTPBootConfigStateReady HTTPBootConfigState = "Ready" + // HTTPBootConfigStateReady indicates that the HTTPBootConfig has been successfully processed, and the next step (e.g., booting the server) can proceed. + HTTPBootConfigStateReady HTTPBootConfigState = "Ready" + + // HTTPBootConfigStatePending indicates that the HTTPBootConfig has not been processed yet. HTTPBootConfigStatePending HTTPBootConfigState = "Pending" - HTTPBootConfigStateError HTTPBootConfigState = "Error" + + // HTTPBootConfigStateError indicates that an error occurred while processing the HTTPBootConfig. + HTTPBootConfigStateError HTTPBootConfigState = "Error" ) // +kubebuilder:object:root=true diff --git a/api/v1alpha1/ipxebootconfig_types.go b/api/v1alpha1/ipxebootconfig_types.go index 846f2a49..a60e7763 100644 --- a/api/v1alpha1/ipxebootconfig_types.go +++ b/api/v1alpha1/ipxebootconfig_types.go @@ -13,26 +13,45 @@ import ( // IPXEBootConfigSpec defines the desired state of IPXEBootConfig type IPXEBootConfigSpec struct { - // Important: Run "make" to regenerate code after modifying this file - SystemUUID string `json:"systemUUID,omitempty"` - SystemIPs []string `json:"systemIPs,omitempty"` // TODO: Add the custom serialization. For now validate at the controller. - // TODO: remove image as this is not needed - Image string `json:"image,omitempty"` - KernelURL string `json:"kernelURL,omitempty"` - InitrdURL string `json:"initrdURL,omitempty"` + // SystemUUID is the unique identifier (UUID) of the server. + SystemUUID string `json:"systemUUID,omitempty"` + + // SystemIPs is a list of IP addresses assigned to the server. + SystemIPs []string `json:"systemIPs,omitempty"` // TODO: Implement custom serialization. Currently, validation should occur at the controller. + + // Image is deprecated and will be removed. + Image string `json:"image,omitempty"` + + // KernelURL is the URL where the kernel of the OS is hosted, eg. the URL to the Kernel layer of the OS OCI image. + KernelURL string `json:"kernelURL,omitempty"` + + // InitrdURL is the URL where the Initrd (initial RAM disk) of the OS is hosted, eg. the URL to the Initrd layer of the OS OCI image. + InitrdURL string `json:"initrdURL,omitempty"` + + // SquashfsURL is the URL where the Squashfs of the OS is hosted, eg. the URL to the Squashfs layer of the OS OCI image. SquashfsURL string `json:"squashfsURL,omitempty"` - // TODO: remove later - IPXEServerURL string `json:"ipxeServerURL,omitempty"` - IgnitionSecretRef *corev1.LocalObjectReference `json:"ignitionSecretRef,omitempty"` + + // IPXEServerURL is deprecated and will be removed. + IPXEServerURL string `json:"ipxeServerURL,omitempty"` + + // IgnitionSecretRef is a reference to the secret containing the Ignition configuration. + IgnitionSecretRef *corev1.LocalObjectReference `json:"ignitionSecretRef,omitempty"` + + // IPXEScriptSecretRef is a reference to the secret containing the custom IPXE script. IPXEScriptSecretRef *corev1.LocalObjectReference `json:"ipxeScriptSecretRef,omitempty"` } type IPXEBootConfigState string const ( - IPXEBootConfigStateReady IPXEBootConfigState = "Ready" + // IPXEBootConfigStateReady indicates that the IPXEBootConfig has been successfully processed, and the next step (e.g., booting the server) can proceed. + IPXEBootConfigStateReady IPXEBootConfigState = "Ready" + + // IPXEBootConfigStatePending indicates that the IPXEBootConfig has not been processed yet. IPXEBootConfigStatePending IPXEBootConfigState = "Pending" - IPXEBootConfigStateError IPXEBootConfigState = "Error" + + // IPXEBootConfigStateError indicates that an error occurred while processing the IPXEBootConfig. + IPXEBootConfigStateError IPXEBootConfigState = "Error" ) // IPXEBootConfigStatus defines the observed state of IPXEBootConfig diff --git a/config/samples/httpbootconfig.yaml b/config/samples/httpbootconfig.yaml index b51ebb63..5d9ca53a 100644 --- a/config/samples/httpbootconfig.yaml +++ b/config/samples/httpbootconfig.yaml @@ -9,12 +9,11 @@ metadata: app.kubernetes.io/created-by: boot-operator name: httpbootconfig-sample spec: - systemUUID: 1234 - systemIPs: - - 1.2.3.4 ignitionSecretRef: - name: ignition-sample - kernelURL: "10.0.0.1/ipxe/rootfs.vmlinuz" - initrdURL: "10.0.0.1/ipxe/rootfs.initrd" - squashfsURL: "10.0.0.1/ipxe/root.squashfs" - + name: ignition-foo + namespace: default + systemIPs: + - f55b:9d4e:e9c9:5183:f7e8:3012:60ce:497b + - 1001:194a:21fb:53d3:9de1:28f3:97ce:d31d + systemUUID: abcd648-490f-11ea-a6c2-0a94efaabcdrd + ukiURL: http://[feed:c0de::]/httpboot/foo-os-uki.efi \ No newline at end of file diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 00000000..e3215546 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,14 @@ +FROM squidfunk/mkdocs-material:latest + +LABEL project=boot_operator + +WORKDIR /docs + +COPY docs/requirements.txt requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +EXPOSE 8000 + +# Start development server by default +ENTRYPOINT ["mkdocs"] +CMD ["serve", "--dev-addr=0.0.0.0:8000"] \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..88b589fa --- /dev/null +++ b/docs/README.md @@ -0,0 +1,39 @@ +# Boot-Operator Documentation + +## Overview + +Boot Operator is a Kubernetes-based project designed to automate the deployment of tools required for booting bare metal servers. It integrates web servers and Kubernetes controllers to manage the entire process of provisioning, booting, and configuring the server. + +## Problem It Solves + +When a bare metal server boots with a network boot method (e.g., PXE or HTTP boot), it typically contacts a DHCP or proxy DHCP server to obtain the necessary information for booting. The DHCP server then provides the IP address of a TFTP server (for PXE) or a web server (for HTTP boot), along with additional boot parameters. + +Traditionally, managing these network boot servers requires manual configuration. Boot Operator automates this by incorporating the boot servers into Kubernetes deployments. By leveraging Kubernetes controllers, each machine's boot process is handled declaratively, making it simpler to manage and scale. + +## Key Components + +Boot Operator includes the following key components: + + - **IPXE Boot Server** + - Handles `/ipxe` requests + - Responds with an iPXE script, which the bare metal server uses to download the necessary OS components + - This endpoint is typically called directly by the server during boot and is commonly used in PXE boot scenarios + + - **HTTP Boot Server** + - Handles `/httpboot` requests + - Returns a JSON response containing the location of the UKI (Unified Kernel Image) that the server should download + - The DHCP server extension typically handles the response and sends the UKI image location to the server + - Common in modern cloud-native bare metal setups, especially for containers and minimal OS images + + - **Image Proxy Server** + - Handles `/image` requests + - Extracts layers from public OCI (Open Container Initiative) images, with current support for GHCR (GitHub Container Registry) only + - Downloads specific layers based on the requested URI and image specifications + - Example: + - `wget http://SERVER_ADDRESS:30007/image?imageName=ghcr.io/ironcore-dev/os-images/gardenlinux&version=1443.10&layerName=application/vnd.ironcore.image.squashfs.v1alpha1.squashfs` + + - **Ignition Server** + - Handles `/ignition` requests + - Responds with Ignition configuration content tailored to the client machine, identified by its UUID in the request URL. + +These servers leverage Kubernetes controllers and API objects to manage the boot process and serve requests from bare metal machines. The architecture and specifics of the controllers and API objects are described in the architecture section of the documentation. \ No newline at end of file diff --git a/docs/api-reference/api.md b/docs/api-reference/api.md new file mode 100644 index 00000000..28bbf93e --- /dev/null +++ b/docs/api-reference/api.md @@ -0,0 +1,613 @@ +
Packages:
+Package v1alpha1 contains API Schema definitions for the settings.gardener.cloud API group
+HTTPBootConfig is the Schema for the httpbootconfigs API
+| Field | +Description | +||||||||
|---|---|---|---|---|---|---|---|---|---|
+apiVersion+string |
+
+
+metal.ironcore.dev/v1alpha1
+
+ |
+||||||||
+kind+string + |
+HTTPBootConfig |
+||||||||
+metadata+ + +Kubernetes meta/v1.ObjectMeta + + + |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||
+spec+ + +HTTPBootConfigSpec + + + |
+
+ + +
|
+||||||||
+status+ + +HTTPBootConfigStatus + + + |
++ | +
IPXEBootConfig is the Schema for the ipxebootconfigs API
+| Field | +Description | +||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+apiVersion+string |
+
+
+metal.ironcore.dev/v1alpha1
+
+ |
+||||||||||||||||||
+kind+string + |
+IPXEBootConfig |
+||||||||||||||||||
+metadata+ + +Kubernetes meta/v1.ObjectMeta + + + |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||||||||||||
+spec+ + +IPXEBootConfigSpec + + + |
+
+ + +
|
+||||||||||||||||||
+status+ + +IPXEBootConfigStatus + + + |
++ | +
+(Appears on:HTTPBootConfig) +
+HTTPBootConfigSpec defines the desired state of HTTPBootConfig
+| Field | +Description | +
|---|---|
+systemUUID+ +string + + |
+
+ SystemUUID is the unique identifier (UUID) of the server. + |
+
+ignitionSecretRef+ + +Kubernetes core/v1.LocalObjectReference + + + |
+
+ IgnitionSecretRef is a reference to the secret containing Ignition configuration. + |
+
+systemIPs+ +[]string + + |
+
+ SystemIPs is a list of IP addresses assigned to the server. + |
+
+ukiURL+ +string + + |
+
+ UKIURL is the URL where the UKI (Unified Kernel Image) is hosted. + |
+
string alias)+(Appears on:HTTPBootConfigStatus) +
+| Value | +Description | +
|---|---|
"Error" |
+HTTPBootConfigStateError indicates that an error occurred while processing the HTTPBootConfig. + |
+
"Pending" |
+HTTPBootConfigStatePending indicates that the HTTPBootConfig has not been processed yet. + |
+
"Ready" |
+HTTPBootConfigStateReady indicates that the HTTPBootConfig has been successfully processed, and the next step (e.g., booting the server) can proceed. + |
+
+(Appears on:HTTPBootConfig) +
+HTTPBootConfigStatus defines the observed state of HTTPBootConfig
+| Field | +Description | +
|---|---|
+state+ + +HTTPBootConfigState + + + |
++ | +
+(Appears on:IPXEBootConfig) +
+IPXEBootConfigSpec defines the desired state of IPXEBootConfig
+| Field | +Description | +
|---|---|
+systemUUID+ +string + + |
+
+ SystemUUID is the unique identifier (UUID) of the server. + |
+
+systemIPs+ +[]string + + |
+
+ SystemIPs is a list of IP addresses assigned to the server. + |
+
+image+ +string + + |
+
+ Image is deprecated and will be removed. + |
+
+kernelURL+ +string + + |
+
+ KernelURL is the URL where the kernel of the OS is hosted, eg. the URL to the Kernel layer of the OS OCI image. + |
+
+initrdURL+ +string + + |
+
+ InitrdURL is the URL where the Initrd (initial RAM disk) of the OS is hosted, eg. the URL to the Initrd layer of the OS OCI image. + |
+
+squashfsURL+ +string + + |
+
+ SquashfsURL is the URL where the Squashfs of the OS is hosted, eg. the URL to the Squashfs layer of the OS OCI image. + |
+
+ipxeServerURL+ +string + + |
+
+ IPXEServerURL is deprecated and will be removed. + |
+
+ignitionSecretRef+ + +Kubernetes core/v1.LocalObjectReference + + + |
+
+ IgnitionSecretRef is a reference to the secret containing the Ignition configuration. + |
+
+ipxeScriptSecretRef+ + +Kubernetes core/v1.LocalObjectReference + + + |
+
+ IPXEScriptSecretRef is a reference to the secret containing the custom IPXE script. + |
+
string alias)+(Appears on:IPXEBootConfigStatus) +
+| Value | +Description | +
|---|---|
"Error" |
+IPXEBootConfigStateError indicates that an error occurred while processing the IPXEBootConfig. + |
+
"Pending" |
+IPXEBootConfigStatePending indicates that the IPXEBootConfig has not been processed yet. + |
+
"Ready" |
+IPXEBootConfigStateReady indicates that the IPXEBootConfig has been successfully processed, and the next step (e.g., booting the server) can proceed. + |
+
+(Appears on:IPXEBootConfig) +
+IPXEBootConfigStatus defines the observed state of IPXEBootConfig
+| Field | +Description | +
|---|---|
+state+ + +IPXEBootConfigState + + + |
+
+ Important: Run “make” to regenerate code after modifying this file + |
+
+Generated with gen-crd-api-reference-docs
+
{{ fieldName . }}
+ (Members of {{ fieldName . }} are embedded into this type.)
+
metadata field.
+ {{ end }}
+
+ {{ if or (eq (fieldName .) "spec") }}
+ Packages:
+
+ Generated with gen-crd-api-reference-docs
+
{{.Underlying}} alias){{ end -}}
++ (Appears on: + {{- $prev := "" -}} + {{- range . -}} + {{- if $prev -}}, {{ end -}} + {{- $prev = . -}} + {{ typeDisplayName . }} + {{- end -}} + ) +
+{{ end }} + +| Value | +Description | +
|---|---|
{{ typeDisplayName . }} |
+ {{ safe (renderComments .CommentLines) }} | +
| Field | +Description | +
|---|---|
+ apiVersion+ string |
+
+
+ {{apiGroup .}}
+
+ |
+
+ kind+ string + |
+ {{.Name.Name}} |
+