Add netboot type

This commit is contained in:
mudler 2022-11-24 18:35:00 +01:00
parent 85adc00f5a
commit 78f2008759
14 changed files with 489 additions and 3 deletions

View File

@ -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"

View 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{})
}

View File

@ -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

View File

@ -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.

View File

@ -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

View 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

View 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

View 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

View File

@ -0,0 +1,6 @@
apiVersion: build.kairos.io/v1alpha1
kind: NetbootDeployment
metadata:
name: netbootdeployment-sample
spec:
# TODO(user): Add fields here

View File

@ -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

View 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,
}
}

View 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,
}}
}

3
go.sum
View File

@ -189,7 +189,6 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobuffalo/flect v0.2.4 h1:BSYA8+T60cdyq+vynaSUjqSVI9mDEg9ZfQUXKmfjo4I=
github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8=
@ -278,7 +277,6 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
@ -828,7 +826,6 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717 h1:hI3jKY4Hpf63ns040onEbB3dAkR/H/P83hw1TG8dD3Y=
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -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 {