Compare commits

..

11 Commits

Author SHA1 Message Date
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
Ettore Di Giacinto
82847a139d ⬆️ Bump elemental-cli 2022-11-07 21:50:30 +01:00
Ettore Di Giacinto
f5611e684f ⬆️ Bump elemental 2022-11-07 19:27:08 +01:00
Ettore Di Giacinto
6b7ae5af02 add bc and qemu-tools 2022-11-05 18:17:22 +00:00
Ettore Di Giacinto
ece128a0b5 Fixup artifact names 2022-11-05 16:26:15 +00:00
Ettore Di Giacinto
4b2be221b3 Add kubesplit target 2022-11-03 23:46:36 +00:00
Ettore Di Giacinto
4f87e2329c Add logic to controller to build disks 2022-11-03 23:42:09 +00:00
Ettore Di Giacinto
dc6fb2c6be Set default menu 2022-11-04 00:22:44 +01:00
Ettore Di Giacinto
dc55928694 Add scripts to generate raw images
See: https://github.com/kairos-io/kairos/issues/377
2022-11-03 22:04:50 +00:00
11 changed files with 191 additions and 19 deletions

View File

@@ -276,4 +276,10 @@ unit-tests: test_deps
e2e-tests:
GINKGO=$(GINKGO) KUBE_VERSION=${KUBE_VERSION} $(ROOT_DIR)/script/test.sh
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
kubesplit: manifests kustomize
rm -rf helm-chart
mkdir helm-chart
$(KUSTOMIZE) build config/default | kubesplit -helm helm-chart

View File

@@ -30,7 +30,18 @@ type OSArtifactSpec struct {
// Foo is an example field of OSArtifact. Edit osartifact_types.go to remove/update
ImageName string `json:"imageName,omitempty"`
ISO bool `json:"iso,omitempty"`
// This needs to be revisited
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"`
GRUBConfig string `json:"grubConfig,omitempty"`

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

@@ -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,
@@ -140,12 +141,19 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
})
}
cloudImgCmd := fmt.Sprintf(
"/raw-images.sh /rootfs /public/%s.raw",
artifact.Name,
)
if artifact.Spec.CloudConfig != "" {
volumeMounts = append(volumeMounts, v1.VolumeMount{
Name: "config",
MountPath: "/iso/iso-overlay/cloud_config.yaml",
SubPath: "config",
})
cloudImgCmd += " /iso/iso-overlay/cloud_config.yaml"
}
if artifact.Spec.CloudConfig != "" || artifact.Spec.GRUBConfig != "" {
@@ -167,6 +175,78 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
VolumeMounts: volumeMounts,
}
buildCloudImageContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-cloud-image",
Image: r.ToolImage,
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},
Name: "build-azure-cloud-image",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
fmt.Sprintf(
"/azure.sh /public/%s.raw /public/%s.vhd",
artifact.Name,
artifact.Name,
),
},
VolumeMounts: volumeMounts,
}
buildGCECloudImageContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
Name: "build-gce-cloud-image",
Image: r.ToolImage,
Command: []string{"/bin/bash", "-cxe"},
Args: []string{
fmt.Sprintf(
"/gce.sh /public/%s.raw /public/%s.gce.raw",
artifact.Name,
artifact.Name,
),
},
VolumeMounts: volumeMounts,
}
servingContainer := v1.Container{
ImagePullPolicy: v1.PullAlways,
SecurityContext: &v1.SecurityContext{Privileged: &privileged},
@@ -212,11 +292,28 @@ func (r *OSArtifactReconciler) genDeployment(artifact buildv1alpha1.OSArtifact)
}
pod.InitContainers = append(pod.InitContainers, buildIsoContainer)
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)
}
if artifact.Spec.AzureImage {
pod.InitContainers = append(pod.InitContainers, buildAzureCloudImageContainer)
}
if artifact.Spec.GCEImage {
pod.InitContainers = append(pod.InitContainers, buildGCECloudImageContainer)
}
if pushImage {
pod.InitContainers = append(pod.InitContainers, createImageContainer(r.ToolImage, artifact.Spec.PushOptions))
}
pod.Containers = []v1.Container{servingContainer}

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

3
go.sum
View File

@@ -189,6 +189,7 @@ 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=
@@ -277,6 +278,7 @@ 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=
@@ -826,6 +828,7 @@ 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

@@ -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
@@ -70,6 +70,8 @@ RUN mkdir /config
RUN zypper in -y jq docker git curl gptfdisk kpartx sudo
# Netboot
RUN zypper in -y cdrtools
# cloud images
RUN zypper in -y bc qemu-tools
# ISO build config
COPY ./config.yaml /config/manifest.yaml
@@ -84,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

@@ -3,13 +3,15 @@
# Transform a raw image disk to azure vhd
RAWIMAGE="$1"
VHDDISK="${2:-disk.vhd}"
cp -rf $RAWIMAGE $VHDDISK.work
MB=$((1024*1024))
size=$(qemu-img info -f raw --output json "$RAWIMAGE" | gawk 'match($0, /"virtual-size": ([0-9]+),/, val) {print val[1]}')
# shellcheck disable=SC2004
ROUNDED_SIZE=$(((($size+$MB-1)/$MB)*$MB))
echo "Resizing raw image to $ROUNDED_SIZE"
qemu-img resize -f raw "$RAWIMAGE" $ROUNDED_SIZE
qemu-img resize -f raw "$VHDDISK.work" $ROUNDED_SIZE
echo "Converting $RAWIMAGE to $VHDDISK"
qemu-img convert -f raw -o subformat=fixed,force_size -O vpc "$RAWIMAGE" "$VHDDISK"
echo "Done"
qemu-img convert -f raw -o subformat=fixed,force_size -O vpc "$VHDDISK.work" "$VHDDISK"
echo "Done"
rm -rf "$VHDDISK.work"

View File

@@ -2,15 +2,14 @@
# Transform a raw image disk to gce compatible
RAWIMAGE="$1"
OUT="${2:-$RAWIMAGE.gce.raw}"
cp -rf $RAWIMAGE $OUT
GB=$((1024*1024*1024))
size=$(qemu-img info -f raw --output json "$RAWIMAGE" | gawk 'match($0, /"virtual-size": ([0-9]+),/, val) {print val[1]}')
size=$(qemu-img info -f raw --output json "$OUT" | gawk 'match($0, /"virtual-size": ([0-9]+),/, val) {print val[1]}')
# shellcheck disable=SC2004
ROUNDED_SIZE=$(echo "$size/$GB+1"|bc)
echo "Resizing raw image from \"$size\"MB to \"$ROUNDED_SIZE\"GB"
qemu-img resize -f raw "$RAWIMAGE" "$ROUNDED_SIZE"G
echo "Compressing raw image $RAWIMAGE to $RAWIMAGE.tar.gz"
tar -c -z --format=oldgnu -f "$RAWIMAGE".tar.gz $RAWIMAGE
echo "Restoring size to original raw image"
qemu-img resize -f raw "$RAWIMAGE" --shrink "$size"
echo "Done"
qemu-img resize -f raw "$OUT" "$ROUNDED_SIZE"G
echo "Compressing raw image $OUT to $OUT.tar.gz"
tar -c -z --format=oldgnu -f "$OUT".tar.gz $OUT

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

@@ -1,10 +1,15 @@
#!/bin/bash
# Generates EFI bootable images (statically)
# luet util unpack <image> rootfs
# docker run -v $PWD:/output --entrypoint /raw-images.sh -ti --rm test-image /output/rootfs /output/foo.raw cloud-init.yaml
# This is a re-adaptation of https://github.com/rancher/elemental-toolkit/blob/v0.8.10-1/images/img-builder.sh, which was dropped
# How to use:
# First extract the image which you want to create an image from:
### luet util unpack <image> rootfs
# Then convert it to a raw disk (EFI only):
### docker run -v $PWD:/output --entrypoint /raw-images.sh -ti --rm test-image /output/rootfs /output/foo.raw cloud-init.yaml
: "${OEM_LABEL:=COS_OEM}"
: "${RECOVERY_LABEL:=COS_RECOVERY}"
: "${EXTEND:=}"
DIRECTORY=$1
OUT=${2:-disk.raw}
@@ -26,6 +31,8 @@ echo "Generating squashfs from $DIRECTORY"
mksquashfs $DIRECTORY recovery.squashfs -b 1024k -comp xz -Xbcj x86
mv recovery.squashfs /build/root/cOS/recovery.squashfs
grub2-editenv /build/root/grub_oem_env set "default_menu_entry=Kairos"
# Create a 2GB filesystem for RECOVERY including the contents for root (grub config and squasfs container)
truncate -s $((2048*1024*1024)) rootfs.part
mkfs.ext2 -L "${RECOVERY_LABEL}" -d /build/root rootfs.part
@@ -60,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