mirror of
https://github.com/kairos-io/osbuilder.git
synced 2025-12-24 20:34:11 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78f2008759 | ||
|
|
85adc00f5a | ||
|
|
8a9b3e9f71 | ||
|
|
78ff22e647 | ||
|
|
4522e14e32 | ||
|
|
097b4a30db | ||
|
|
40560a4b02 | ||
|
|
4997cf18ee | ||
|
|
7ae1f7105a | ||
|
|
ebbd1c9a1a | ||
|
|
82847a139d | ||
|
|
f5611e684f |
9
PROJECT
9
PROJECT
@@ -16,4 +16,13 @@ resources:
|
||||
kind: OSArtifact
|
||||
path: github.com/kairos-io/osbuilder/api/v1alpha1
|
||||
version: v1alpha1
|
||||
- api:
|
||||
crdVersion: v1
|
||||
namespaced: true
|
||||
controller: true
|
||||
domain: kairos.io
|
||||
group: build
|
||||
kind: NetbootDeployment
|
||||
path: github.com/kairos-io/osbuilder/api/v1alpha1
|
||||
version: v1alpha1
|
||||
version: "3"
|
||||
|
||||
63
api/v1alpha1/netbootdeployment_types.go
Normal file
63
api/v1alpha1/netbootdeployment_types.go
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2022.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||
|
||||
// NetbootDeploymentSpec defines the desired state of NetbootDeployment
|
||||
type NetbootDeploymentSpec struct {
|
||||
CloudConfig string `json:"cloudConfig,omitempty"`
|
||||
CommandLine string `json:"cmdLine,omitempty"`
|
||||
|
||||
// TODO: Those below should be deprecated and reference an osbuild instead
|
||||
}
|
||||
|
||||
// NetbootDeploymentStatus defines the observed state of NetbootDeployment
|
||||
type NetbootDeploymentStatus struct {
|
||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
|
||||
// Important: Run "make" to regenerate code after modifying this file
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
//+kubebuilder:subresource:status
|
||||
|
||||
// NetbootDeployment is the Schema for the netbootdeployments API
|
||||
type NetbootDeployment struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec NetbootDeploymentSpec `json:"spec,omitempty"`
|
||||
Status NetbootDeploymentStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
//+kubebuilder:object:root=true
|
||||
|
||||
// NetbootDeploymentList contains a list of NetbootDeployment
|
||||
type NetbootDeploymentList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []NetbootDeployment `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&NetbootDeployment{}, &NetbootDeploymentList{})
|
||||
}
|
||||
@@ -31,10 +31,16 @@ type OSArtifactSpec struct {
|
||||
// Foo is an example field of OSArtifact. Edit osartifact_types.go to remove/update
|
||||
ImageName string `json:"imageName,omitempty"`
|
||||
// This needs to be revisited
|
||||
ISO bool `json:"iso,omitempty"`
|
||||
CloudImage bool `json:"cloudImage,omitempty"`
|
||||
AzureImage bool `json:"azureImage,omitempty"`
|
||||
GCEImage bool `json:"gceImage,omitempty"`
|
||||
ISO bool `json:"iso,omitempty"`
|
||||
|
||||
//Disk-only stuff
|
||||
DiskSize string `json:"diskSize,omitempty"`
|
||||
CloudImage bool `json:"cloudImage,omitempty"`
|
||||
AzureImage bool `json:"azureImage,omitempty"`
|
||||
GCEImage bool `json:"gceImage,omitempty"`
|
||||
|
||||
Netboot bool `json:"netboot,omitempty"`
|
||||
NetbootURL string `json:"netbootURL,omitempty"`
|
||||
|
||||
// TODO: treat cloudconfig as a secret, and take a secretRef where to store it (optionally)
|
||||
CloudConfig string `json:"cloudConfig,omitempty"`
|
||||
|
||||
@@ -40,6 +40,95 @@ func (in *LocalObjectReference) DeepCopy() *LocalObjectReference {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NetbootDeployment) DeepCopyInto(out *NetbootDeployment) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeployment.
|
||||
func (in *NetbootDeployment) DeepCopy() *NetbootDeployment {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NetbootDeployment)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *NetbootDeployment) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NetbootDeploymentList) DeepCopyInto(out *NetbootDeploymentList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]NetbootDeployment, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeploymentList.
|
||||
func (in *NetbootDeploymentList) DeepCopy() *NetbootDeploymentList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NetbootDeploymentList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *NetbootDeploymentList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NetbootDeploymentSpec) DeepCopyInto(out *NetbootDeploymentSpec) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeploymentSpec.
|
||||
func (in *NetbootDeploymentSpec) DeepCopy() *NetbootDeploymentSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NetbootDeploymentSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NetbootDeploymentStatus) DeepCopyInto(out *NetbootDeploymentStatus) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetbootDeploymentStatus.
|
||||
func (in *NetbootDeploymentStatus) DeepCopy() *NetbootDeploymentStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(NetbootDeploymentStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *OSArtifact) DeepCopyInto(out *OSArtifact) {
|
||||
*out = *in
|
||||
|
||||
@@ -35,6 +35,8 @@ spec:
|
||||
spec:
|
||||
description: OSArtifactSpec defines the desired state of OSArtifact
|
||||
properties:
|
||||
azureImage:
|
||||
type: boolean
|
||||
bundles:
|
||||
items:
|
||||
type: string
|
||||
@@ -43,6 +45,13 @@ spec:
|
||||
description: 'TODO: treat cloudconfig as a secret, and take a secretRef
|
||||
where to store it (optionally)'
|
||||
type: string
|
||||
cloudImage:
|
||||
type: boolean
|
||||
diskSize:
|
||||
description: Disk-only stuff
|
||||
type: string
|
||||
gceImage:
|
||||
type: boolean
|
||||
grubConfig:
|
||||
type: string
|
||||
imageName:
|
||||
@@ -50,7 +59,12 @@ spec:
|
||||
to remove/update
|
||||
type: string
|
||||
iso:
|
||||
description: This needs to be revisited
|
||||
type: boolean
|
||||
netboot:
|
||||
type: boolean
|
||||
netbootURL:
|
||||
type: string
|
||||
osRelease:
|
||||
type: string
|
||||
pull:
|
||||
@@ -3,17 +3,20 @@
|
||||
# It should be run by config/default
|
||||
resources:
|
||||
- bases/build.kairos.io_osartifacts.yaml
|
||||
- bases/build.kairos.io_netbootdeployments.yaml
|
||||
#+kubebuilder:scaffold:crdkustomizeresource
|
||||
|
||||
patchesStrategicMerge:
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
|
||||
# patches here are for enabling the conversion webhook for each CRD
|
||||
#- patches/webhook_in_osartifacts.yaml
|
||||
#- patches/webhook_in_netbootdeployments.yaml
|
||||
#+kubebuilder:scaffold:crdkustomizewebhookpatch
|
||||
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
|
||||
# patches here are for enabling the CA injection for each CRD
|
||||
#- patches/cainjection_in_osartifacts.yaml
|
||||
#- patches/cainjection_in_netbootdeployments.yaml
|
||||
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
|
||||
|
||||
# the following config is for teaching kustomize how to do kustomization for CRDs.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# The following patch adds a directive for certmanager to inject CA into the CRD
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||
name: netbootdeployments.build.kairos.io
|
||||
16
config/crd/patches/webhook_in_netbootdeployments.yaml
Normal file
16
config/crd/patches/webhook_in_netbootdeployments.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
# The following patch enables a conversion webhook for the CRD
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: netbootdeployments.build.kairos.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
service:
|
||||
namespace: system
|
||||
name: webhook-service
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v1
|
||||
24
config/rbac/netbootdeployment_editor_role.yaml
Normal file
24
config/rbac/netbootdeployment_editor_role.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
# permissions for end users to edit netbootdeployments.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: netbootdeployment-editor-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- build.kairos.io
|
||||
resources:
|
||||
- netbootdeployments
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- build.kairos.io
|
||||
resources:
|
||||
- netbootdeployments/status
|
||||
verbs:
|
||||
- get
|
||||
20
config/rbac/netbootdeployment_viewer_role.yaml
Normal file
20
config/rbac/netbootdeployment_viewer_role.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
# permissions for end users to view netbootdeployments.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: netbootdeployment-viewer-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- build.kairos.io
|
||||
resources:
|
||||
- netbootdeployments
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- build.kairos.io
|
||||
resources:
|
||||
- netbootdeployments/status
|
||||
verbs:
|
||||
- get
|
||||
6
config/samples/build_v1alpha1_netbootdeployment.yaml
Normal file
6
config/samples/build_v1alpha1_netbootdeployment.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: build.kairos.io/v1alpha1
|
||||
kind: NetbootDeployment
|
||||
metadata:
|
||||
name: netbootdeployment-sample
|
||||
spec:
|
||||
# TODO(user): Add fields here
|
||||
@@ -1,4 +1,5 @@
|
||||
## Append samples you want in your CSV to this file as resources ##
|
||||
resources:
|
||||
- build_v1alpha1_osartifact.yaml
|
||||
- build_v1alpha1_netbootdeployment.yaml
|
||||
#+kubebuilder:scaffold:manifestskustomizesamples
|
||||
|
||||
@@ -104,7 +104,8 @@ func osReleaseContainer(containerImage string) v1.Container {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact) *appsv1.Deployment {
|
||||
func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact, svc *v1.Service) *appsv1.Deployment {
|
||||
// TODO: svc is unused, but could be used in the future to generate the Netboot URL
|
||||
objMeta := metav1.ObjectMeta{
|
||||
Name: artifact.Name,
|
||||
Namespace: artifact.Namespace,
|
||||
@@ -179,13 +180,41 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
|
||||
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
|
||||
Name: "build-cloud-image",
|
||||
Image: r.ToolImage,
|
||||
Command: []string{"/bin/bash", "-cxe"},
|
||||
|
||||
Command: []string{"/bin/bash", "-cxe"},
|
||||
Args: []string{
|
||||
cloudImgCmd,
|
||||
},
|
||||
VolumeMounts: volumeMounts,
|
||||
}
|
||||
|
||||
if artifact.Spec.DiskSize != "" {
|
||||
buildCloudImageContainer.Env = []v1.EnvVar{{
|
||||
Name: "EXTEND",
|
||||
Value: artifact.Spec.DiskSize,
|
||||
}}
|
||||
}
|
||||
|
||||
extractNetboot := v1.Container{
|
||||
ImagePullPolicy: v1.PullAlways,
|
||||
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
|
||||
Name: "build-netboot",
|
||||
Image: r.ToolImage,
|
||||
Command: []string{"/bin/bash", "-cxe"},
|
||||
Env: []v1.EnvVar{{
|
||||
Name: "URL",
|
||||
Value: artifact.Spec.NetbootURL,
|
||||
}},
|
||||
Args: []string{
|
||||
fmt.Sprintf(
|
||||
"/netboot.sh /public/%s.iso /public/%s",
|
||||
artifact.Name,
|
||||
artifact.Name,
|
||||
),
|
||||
},
|
||||
VolumeMounts: volumeMounts,
|
||||
}
|
||||
|
||||
buildAzureCloudImageContainer := v1.Container{
|
||||
ImagePullPolicy: v1.PullAlways,
|
||||
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
|
||||
@@ -263,10 +292,14 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
|
||||
|
||||
}
|
||||
|
||||
if artifact.Spec.ISO {
|
||||
if artifact.Spec.ISO || artifact.Spec.Netboot {
|
||||
pod.InitContainers = append(pod.InitContainers, buildIsoContainer)
|
||||
}
|
||||
|
||||
if artifact.Spec.Netboot {
|
||||
pod.InitContainers = append(pod.InitContainers, extractNetboot)
|
||||
}
|
||||
|
||||
if artifact.Spec.CloudImage || artifact.Spec.AzureImage || artifact.Spec.GCEImage {
|
||||
pod.InitContainers = append(pod.InitContainers, buildCloudImageContainer)
|
||||
}
|
||||
|
||||
99
controllers/netboot-deployment.go
Normal file
99
controllers/netboot-deployment.go
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2022.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (r *NetbootDeploymentReconciler) genDeployment(artifact buildv1alpha1.NetbootDeployment) *appsv1.Deployment {
|
||||
// TODO: svc is unused, but could be used in the future to generate the Netboot URL
|
||||
objMeta := metav1.ObjectMeta{
|
||||
Name: artifact.Name,
|
||||
Namespace: artifact.Namespace,
|
||||
OwnerReferences: genNetbootOwner(artifact),
|
||||
}
|
||||
|
||||
privileged := false
|
||||
serviceAccount := false
|
||||
|
||||
servingContainer := v1.Container{
|
||||
ImagePullPolicy: v1.PullAlways,
|
||||
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
|
||||
Name: "serve",
|
||||
Args: []string{
|
||||
|
||||
"boot",
|
||||
fmt.Sprintf(),
|
||||
fmt.Sprintf(),
|
||||
fmt.Sprintf(),
|
||||
},
|
||||
Image: r.Image,
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
Name: "config",
|
||||
MountPath: "/files/config.yaml",
|
||||
SubPath: "cloudconfig",
|
||||
},
|
||||
},
|
||||
}
|
||||
// boot /files/kairos-core-opensuse-kernel /files/kairos-core-opensuse-initrd --cmdline='rd.neednet=1 ip=dhcp rd.cos.disable root=live:https://github.com/kairos-io/provider-kairos/releases/download/v1.2.0/kairos-alpine-ubuntu-v1.2.0-k3sv1.20.15+k3s1.squashfs netboot nodepair.enable config_url={{ ID "/files/config.yaml" }} console=tty1 console=ttyS0 console=tty0'
|
||||
pod := v1.PodSpec{
|
||||
HostNetwork: true,
|
||||
AutomountServiceAccountToken: &serviceAccount,
|
||||
Volumes: []v1.Volume{
|
||||
{
|
||||
Name: "config",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
ConfigMap: &v1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{Name: fmt.Sprintf("%s-netboot", artifact.Name)}}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pod.Containers = []v1.Container{servingContainer}
|
||||
|
||||
deploymentLabels := genNetDeploymentLabel(artifact.Name)
|
||||
replicas := int32(1)
|
||||
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: objMeta,
|
||||
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{MatchLabels: deploymentLabels},
|
||||
Replicas: &replicas,
|
||||
Template: v1.PodTemplateSpec{
|
||||
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: deploymentLabels,
|
||||
},
|
||||
Spec: pod,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
func genNetDeploymentLabel(s string) map[string]string {
|
||||
return map[string]string{
|
||||
"netboot": "serve" + s,
|
||||
}
|
||||
}
|
||||
145
controllers/netbootdeployment_controller.go
Normal file
145
controllers/netbootdeployment_controller.go
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Copyright 2022.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
buildv1alpha1 "github.com/kairos-io/osbuilder/api/v1alpha1"
|
||||
)
|
||||
|
||||
// NetbootDeploymentReconciler reconciles a NetbootDeployment object
|
||||
type NetbootDeploymentReconciler struct {
|
||||
client.Client
|
||||
clientSet *kubernetes.Clientset
|
||||
|
||||
Image string
|
||||
Scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
//+kubebuilder:rbac:groups=build.kairos.io,resources=netbootdeployments,verbs=get;list;watch;create;update;patch;delete
|
||||
//+kubebuilder:rbac:groups=build.kairos.io,resources=netbootdeployments/status,verbs=get;update;patch
|
||||
//+kubebuilder:rbac:groups=build.kairos.io,resources=netbootdeployments/finalizers,verbs=update
|
||||
|
||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||
// move the current state of the cluster closer to the desired state.
|
||||
// TODO(user): Modify the Reconcile function to compare the state specified by
|
||||
// the NetbootDeployment object against the actual cluster state, and then
|
||||
// perform operations to make the cluster state reflect the state specified by
|
||||
// the user.
|
||||
//
|
||||
// For more details, check Reconcile and its Result here:
|
||||
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile
|
||||
func (r *NetbootDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
logger := log.FromContext(ctx)
|
||||
var netboot buildv1alpha1.NetbootDeployment
|
||||
if err := r.Get(ctx, req.NamespacedName, &netboot); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("Reconciling %v", netboot))
|
||||
// generate configmap required for building a custom image
|
||||
desiredConfigMap := r.genConfigMap(netboot)
|
||||
logger.Info(fmt.Sprintf("Checking configmap %v", netboot))
|
||||
|
||||
cfgMap, err := r.clientSet.CoreV1().ConfigMaps(req.Namespace).Get(ctx, desiredConfigMap.Name, metav1.GetOptions{})
|
||||
if cfgMap == nil || apierrors.IsNotFound(err) {
|
||||
logger.Info(fmt.Sprintf("Creating service %v", desiredConfigMap))
|
||||
|
||||
cfgMap, err = r.clientSet.CoreV1().ConfigMaps(req.Namespace).Create(ctx, desiredConfigMap, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed while creating cfgmap")
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
if err != nil {
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
desiredDeployment := r.genDeployment(netboot)
|
||||
deployment, err := r.clientSet.AppsV1().Deployments(req.Namespace).Get(ctx, desiredDeployment.Name, metav1.GetOptions{})
|
||||
if deployment == nil || apierrors.IsNotFound(err) {
|
||||
logger.Info(fmt.Sprintf("Creating Deployment %v", deployment))
|
||||
|
||||
deployment, err = r.clientSet.AppsV1().Deployments(req.Namespace).Create(ctx, desiredDeployment, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
logger.Error(err, "Failed while creating deployment")
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
||||
// TODO(user): your logic here
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// SetupWithManager sets up the controller with the Manager.
|
||||
func (r *NetbootDeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(mgr.GetConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.clientSet = clientset
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&buildv1alpha1.NetbootDeployment{}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func genNetbootOwner(artifact buildv1alpha1.NetbootDeployment) []metav1.OwnerReference {
|
||||
return []metav1.OwnerReference{
|
||||
*metav1.NewControllerRef(&artifact.ObjectMeta, schema.GroupVersionKind{
|
||||
Group: buildv1alpha1.GroupVersion.Group,
|
||||
Version: buildv1alpha1.GroupVersion.Version,
|
||||
Kind: "NetbootDeployment",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NetbootDeploymentReconciler) genConfigMap(artifact buildv1alpha1.NetbootDeployment) *v1.ConfigMap {
|
||||
return &v1.ConfigMap{
|
||||
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("%s-netboot", artifact.Name),
|
||||
Namespace: artifact.Namespace,
|
||||
OwnerReferences: genNetbootOwner(artifact),
|
||||
},
|
||||
Data: map[string]string{
|
||||
"cloudconfig": artifact.Spec.CloudConfig,
|
||||
}}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request)
|
||||
}
|
||||
logger.Info(fmt.Sprintf("Checking deployment %v", osbuild))
|
||||
|
||||
desiredDeployment := r.genDeployment(osbuild)
|
||||
desiredDeployment := r.genDeployment(osbuild, svc)
|
||||
deployment, err := r.clientSet.AppsV1().Deployments(req.Namespace).Get(ctx, desiredDeployment.Name, v1.GetOptions{})
|
||||
if deployment == nil || apierrors.IsNotFound(err) {
|
||||
logger.Info(fmt.Sprintf("Creating Deployment %v", deployment))
|
||||
|
||||
7
main.go
7
main.go
@@ -103,6 +103,13 @@ func main() {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "OSArtifact")
|
||||
os.Exit(1)
|
||||
}
|
||||
if err = (&controllers.NetbootDeploymentReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "NetbootDeployment")
|
||||
os.Exit(1)
|
||||
}
|
||||
//+kubebuilder:scaffold:builder
|
||||
|
||||
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG ELEMENTAL_CLI_VERSION=0.20221020.3
|
||||
ARG ELEMENTAL_CLI_VERSION=0.20221107.1
|
||||
ARG LEAP_VERSION=15.4
|
||||
ARG LUET_VERSION=0.33.0
|
||||
FROM quay.io/kairos/packages:elemental-cli-system-$ELEMENTAL_CLI_VERSION AS elemental
|
||||
@@ -86,6 +86,7 @@ COPY ./arm /arm
|
||||
COPY ./gce.sh /gce.sh
|
||||
COPY ./raw-images.sh /raw-images.sh
|
||||
COPY ./azure.sh /azure.sh
|
||||
COPY ./netboot.sh /netboot.sh
|
||||
|
||||
COPY defaults.yaml /defaults.yaml
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ usage()
|
||||
echo " --local: (optional) Use local repository when building"
|
||||
echo " --directory: (optional) A directory which will be used for active/passive/recovery system"
|
||||
echo " --model: (optional) The board model"
|
||||
echo " --efi-dir: (optional) A directory with files which will be added to the efi partition"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -174,6 +175,10 @@ while [ "$#" -gt 0 ]; do
|
||||
shift 1
|
||||
model=$1
|
||||
;;
|
||||
--efi-dir)
|
||||
shift 1
|
||||
efi_dir=$1
|
||||
;;
|
||||
--final-repo)
|
||||
shift 1
|
||||
final_repo=$1
|
||||
@@ -267,7 +272,7 @@ ensure_dir_structure $TARGET
|
||||
# Download the container image
|
||||
if [ -z "$directory" ]; then
|
||||
echo ">>> Downloading container image"
|
||||
elemental pull-image $container_image $TARGET
|
||||
elemental pull-image $( (( $local_build == 'true')) && printf %s '--local' ) $container_image $TARGET
|
||||
else
|
||||
echo ">>> Copying files from $directory"
|
||||
rsync -axq --exclude='host' --exclude='mnt' --exclude='proc' --exclude='sys' --exclude='dev' --exclude='tmp' ${directory}/ $TARGET
|
||||
@@ -313,6 +318,10 @@ if [ -z "$EFI" ]; then
|
||||
fi
|
||||
|
||||
cp -rfv /arm/grub/efi/* $EFI
|
||||
if [ -n "$EFI" ] && [ -n "$efi_dir" ]; then
|
||||
echo "Copy $efi_dir to EFI directory"
|
||||
cp -rfv $efi_dir/* $EFI
|
||||
fi
|
||||
|
||||
echo ">> Writing image and partition table"
|
||||
dd if=/dev/zero of="${output_image}" bs=1024000 count="${size}" || exit 1
|
||||
|
||||
25
tools-image/netboot.sh
Executable file
25
tools-image/netboot.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# Extracts squashfs, kernel, initrd and generates a ipxe template script
|
||||
|
||||
ISO=$1
|
||||
OUTPUT_NAME=$2
|
||||
ARTIFACT_NAME=$(basename $OUTPUT_NAME)
|
||||
|
||||
isoinfo -x /rootfs.squashfs -R -i $ISO > $OUTPUT_NAME.squashfs
|
||||
isoinfo -x /boot/kernel -R -i $ISO > $OUTPUT_NAME-kernel
|
||||
isoinfo -x /boot/initrd -R -i $ISO > $OUTPUT_NAME-initrd
|
||||
|
||||
URL=${URL:-https://github.com/kairos-io/kairos/releases/download}
|
||||
|
||||
cat > $OUTPUT_NAME.ipxe << EOF
|
||||
#!ipxe
|
||||
set url ${URL}/
|
||||
set kernel $ARTIFACT_NAME-kernel
|
||||
set initrd $ARTIFACT_NAME-initrd
|
||||
set rootfs $ARTIFACT_NAME.squashfs
|
||||
# set config https://example.com/machine-config
|
||||
# set cmdline extra.values=1
|
||||
kernel \${url}/\${kernel} initrd=\${initrd} ip=dhcp rd.cos.disable root=live:\${url}/\${rootfs} netboot nodepair.enable config_url=\${config} console=tty1 console=ttyS0 \${cmdline}
|
||||
initrd \${url}/\${initrd}
|
||||
boot
|
||||
EOF
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
: "${OEM_LABEL:=COS_OEM}"
|
||||
: "${RECOVERY_LABEL:=COS_RECOVERY}"
|
||||
: "${EXTEND:=}"
|
||||
|
||||
DIRECTORY=$1
|
||||
OUT=${2:-disk.raw}
|
||||
@@ -66,6 +67,11 @@ truncate -s $((3*1024*1024)) $OUT
|
||||
# Add an extra MB at the end of the disk for the gpt headers, in fact 34 sectors would be enough, but adding some more does not hurt.
|
||||
truncate -s "+$((1024*1024))" $OUT
|
||||
|
||||
if [ -n "$EXTEND" ]; then
|
||||
echo "Extending image of $EXTEND MB"
|
||||
truncate -s "+$(($EXTEND*1024*1024))" $OUT
|
||||
fi
|
||||
|
||||
# Create the partition table in $OUT (assumes sectors of 512 bytes)
|
||||
sgdisk -n 1:2048:+2M -c 1:legacy -t 1:EF02 $OUT
|
||||
sgdisk -n 2:0:+20M -c 2:UEFI -t 2:EF00 $OUT
|
||||
|
||||
Reference in New Issue
Block a user