Compare commits

..

10 Commits

Author SHA1 Message Date
mudler
78f2008759 Add netboot type 2022-11-24 18:35:27 +01:00
Ettore Di Giacinto
85adc00f5a Merge pull request #18 from Ognian/master
add --efi-dir option to build-arm-iamge.sh
2022-11-18 11:12:01 +01:00
Ognian
8a9b3e9f71 cp dir content not dir
Signed-off-by: Ognian <Ognian@users.noreply.github.com>
2022-11-16 17:24:57 +01:00
Ognian
78ff22e647 add --efi-dir option to build-arm-iamge.sh
This option allows modification of raspberry pi boot options.
see https://www.raspberrypi.com/documentation/computers/config_txt.html#what-is-config-txt

Signed-off-by: Ognian <Ognian@users.noreply.github.com>
2022-11-16 12:23:56 +01:00
Ettore Di Giacinto
4522e14e32 Merge pull request #17 from Ognian/master
propagate --local to elemental pull-image in build-arm-image.sh
2022-11-14 18:32:50 +01:00
Ognian
097b4a30db Merge pull request #1 from Ognian/Ognian-patch-1
propagate --local to elemental pull-image
2022-11-14 18:21:34 +01:00
Ognian
40560a4b02 propagate --local to elemental pull-image
fixes https://github.com/kairos-io/kairos/issues/419
2022-11-14 18:19:21 +01:00
Ettore Di Giacinto
4997cf18ee Fixup duplicated crd def 2022-11-07 22:25:58 +00:00
Ettore Di Giacinto
7ae1f7105a Add option to build netboot files and disk image size 2022-11-07 22:02:32 +00:00
Ettore Di Giacinto
ebbd1c9a1a Add netboot script 2022-11-07 21:23:20 +00:00
21 changed files with 592 additions and 9 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

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

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

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

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

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

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

View File

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

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 {

View File

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

View File

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

View File

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