Skip to content

Commit e55bd03

Browse files
authored
1546 byoi (#88)
* Add fields to the CRDs Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * WIP Create test Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Refactor code to split in testable functions Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * WIP Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Do something actually useful in tests - Create a random namespace - Create an artifact - Check that CreateConfigmap doesn't error Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * WIP Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Refactor before each so that we can change the artifact object per test Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * WIP Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * WIP Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Run kaniko to build the Dockerfile Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Build the image from Dockerfile with kaniko Currently can build an image. For example apply these: ``` kind: Secret apiVersion: v1 metadata: name: mydockerfile stringData: Dockerfile: | FROM ubuntu RUN touch myfile --- kind: OSArtifact apiVersion: build.kairos.io/v1alpha2 metadata: name: hello-kairos spec: imageName: "quay.io/kairos/core-opensuse-leap:latest" baseImageDockerfile: name: "mydockerfile" key: "Dockerfile" iso: true ``` Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Clarify that convert-to-kairos is not yet implemented Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Remove implemented TODO Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * WIP Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Bump linting action Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Fix linting errors Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Bump it again Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Unexport function and run controller tests in CI Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Unexport the other one too Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Extract case to a function Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Split controller tests in a separate job so that they run on a fresh cluster and they run in parallel Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Remove non-implemented functionality Will happen as part of this: kairos-io/kairos#1721 Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * go mod tidy Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> * Try to use a random (free) port in tests because sometimes we collide Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me> --------- Signed-off-by: Dimitris Karakasilis <dimitris@karakasilis.me>
1 parent 09058c0 commit e55bd03

File tree

13 files changed

+401
-92
lines changed

13 files changed

+401
-92
lines changed

.github/workflows/lint.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ env:
1515
FORCE_COLOR: 1
1616
jobs:
1717
call-workflow:
18-
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.6
18+
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.8
1919
with:
2020
yamldirs: ".github/workflows/ config/ tools-image/"
2121
is-go: true

.github/workflows/test.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@ concurrency:
1414
cancel-in-progress: true
1515

1616
jobs:
17-
docker:
17+
e2e-tests:
1818
runs-on: ubuntu-latest
1919
steps:
2020
- name: Checkout
2121
uses: actions/checkout@v3
2222
- name: Test
2323
run: |
2424
make kind-e2e-tests
25+
controller-tests:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v3
30+
- name: Test
31+
run: |
32+
make controller-tests

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ kind-setup:
263263
kind-setup-image: docker-build
264264
kind load docker-image --name $(CLUSTER_NAME) ${IMG}
265265

266+
kind-teardown:
267+
kind delete cluster --name ${CLUSTER_NAME} || true
268+
266269
.PHONY: test_deps
267270
test_deps:
268271
go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
@@ -275,8 +278,10 @@ unit-tests: test_deps
275278
e2e-tests:
276279
GINKGO=$(GINKGO) KUBE_VERSION=${KUBE_VERSION} $(ROOT_DIR)/script/test.sh
277280

278-
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
281+
controller-tests: ginkgo kind-setup install undeploy-dev deploy-dev
282+
USE_EXISTING_CLUSTER=true go run github.com/onsi/ginkgo/v2/ginkgo -v run controllers/.
279283

284+
kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests
280285

281286
kubesplit: manifests kustomize
282287
rm -rf helm-chart

api/v1alpha2/osartifact_types.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,17 @@ import (
2424

2525
// OSArtifactSpec defines the desired state of OSArtifact
2626
type OSArtifactSpec struct {
27+
// There are 3 ways to specify a Kairos image:
28+
29+
// Points to a prepared kairos image (e.g. a released one)
2730
ImageName string `json:"imageName,omitempty"`
2831

32+
// Points to a vanilla (non-Kairos) image. osbuilder will try to convert this to a Kairos image
33+
BaseImageName string `json:"baseImageName,omitempty"`
34+
35+
// Points to a Secret that contains a Dockerfile. osbuilder will build the image using that Dockerfile and will try to create a Kairos image from it.
36+
BaseImageDockerfile *SecretKeySelector `json:"baseImageDockerfile,omitempty"`
37+
2938
ISO bool `json:"iso,omitempty"`
3039

3140
//Disk-only stuff

api/v1alpha2/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/build.kairos.io_osartifacts.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ spec:
4141
properties:
4242
azureImage:
4343
type: boolean
44+
baseImageDockerfile:
45+
description: Points to a Secret that contains a Dockerfile. osbuilder
46+
will build the image using that Dockerfile and will try to create
47+
a Kairos image from it.
48+
properties:
49+
key:
50+
type: string
51+
name:
52+
type: string
53+
required:
54+
- name
55+
type: object
56+
baseImageName:
57+
description: Points to a vanilla (non-Kairos) image. osbuilder will
58+
try to convert this to a Kairos image
59+
type: string
4460
bundles:
4561
items:
4662
type: string
@@ -7834,6 +7850,7 @@ spec:
78347850
grubConfig:
78357851
type: string
78367852
imageName:
7853+
description: Points to a prepared kairos image (e.g. a released one)
78377854
type: string
78387855
imagePullSecrets:
78397856
items:

controllers/job.go

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package controllers
1818

1919
import (
2020
"fmt"
21+
2122
"k8s.io/apimachinery/pkg/api/resource"
2223
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2324

@@ -292,6 +293,17 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
292293
},
293294
}
294295

296+
if artifact.Spec.BaseImageDockerfile != nil {
297+
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
298+
Name: "dockerfile",
299+
VolumeSource: corev1.VolumeSource{
300+
Secret: &corev1.SecretVolumeSource{
301+
SecretName: artifact.Spec.BaseImageDockerfile.Name,
302+
},
303+
},
304+
})
305+
}
306+
295307
if artifact.Spec.CloudConfigRef != nil {
296308
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
297309
Name: "cloudconfig",
@@ -304,11 +316,40 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
304316
})
305317
}
306318

307-
for i := range artifact.Spec.ImagePullSecrets {
308-
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets[i])
319+
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets...)
320+
321+
podSpec.InitContainers = []corev1.Container{}
322+
// Base image can be:
323+
// - built from a dockerfile and converted to a kairos one
324+
// - built by converting an existing image to a kairos one
325+
// - a prebuilt kairos image
326+
if artifact.Spec.BaseImageDockerfile != nil {
327+
podSpec.InitContainers = append(podSpec.InitContainers, baseImageBuildContainers()...)
328+
} else if artifact.Spec.BaseImageName != "" { // Existing base image - non kairos
329+
podSpec.InitContainers = append(podSpec.InitContainers,
330+
unpackContainer("baseimage-non-kairos", r.ToolImage, artifact.Spec.BaseImageName))
331+
} else { // Existing Kairos base image
332+
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName))
309333
}
310334

311-
podSpec.InitContainers = []corev1.Container{unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName)}
335+
// If base image was a non kairos one, either one we built with kaniko or prebuilt,
336+
// convert it to a Kairos one, in a best effort manner.
337+
if artifact.Spec.BaseImageDockerfile != nil || artifact.Spec.BaseImageName != "" {
338+
podSpec.InitContainers = append(podSpec.InitContainers,
339+
corev1.Container{
340+
ImagePullPolicy: corev1.PullAlways,
341+
Name: "convert-to-kairos",
342+
Image: "busybox",
343+
Command: []string{"/bin/echo"},
344+
Args: []string{"TODO"},
345+
VolumeMounts: []corev1.VolumeMount{
346+
{
347+
Name: "rootfs",
348+
MountPath: "/rootfs",
349+
},
350+
},
351+
})
352+
}
312353

313354
for i, bundle := range artifact.Spec.Bundles {
314355
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer(fmt.Sprint(i), r.ToolImage, bundle))
@@ -352,3 +393,59 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
352393
func ptr[T any](val T) *T {
353394
return &val
354395
}
396+
397+
func baseImageBuildContainers() []corev1.Container {
398+
return []corev1.Container{
399+
corev1.Container{
400+
ImagePullPolicy: corev1.PullAlways,
401+
Name: "kaniko-build",
402+
Image: "gcr.io/kaniko-project/executor:latest",
403+
Args: []string{
404+
"--dockerfile", "dockerfile/Dockerfile",
405+
"--context", "dir://workspace",
406+
"--destination", "whatever", // We don't push, but it needs this
407+
"--tar-path", "/rootfs/image.tar",
408+
"--no-push",
409+
},
410+
VolumeMounts: []corev1.VolumeMount{
411+
{
412+
Name: "rootfs",
413+
MountPath: "/rootfs",
414+
},
415+
{
416+
Name: "dockerfile",
417+
MountPath: "/workspace/dockerfile",
418+
},
419+
},
420+
},
421+
corev1.Container{
422+
ImagePullPolicy: corev1.PullAlways,
423+
Name: "image-extractor",
424+
Image: "quay.io/luet/base",
425+
Args: []string{
426+
"util", "unpack", "--local", "file:////rootfs/image.tar", "/rootfs",
427+
},
428+
VolumeMounts: []corev1.VolumeMount{
429+
{
430+
Name: "rootfs",
431+
MountPath: "/rootfs",
432+
},
433+
},
434+
},
435+
corev1.Container{
436+
ImagePullPolicy: corev1.PullAlways,
437+
Name: "cleanup",
438+
Image: "busybox",
439+
Command: []string{"/bin/rm"},
440+
Args: []string{
441+
"/rootfs/image.tar",
442+
},
443+
VolumeMounts: []corev1.VolumeMount{
444+
{
445+
Name: "rootfs",
446+
MountPath: "/rootfs",
447+
},
448+
},
449+
},
450+
}
451+
}

controllers/osartifact_controller.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package controllers
1919
import (
2020
"context"
2121
"fmt"
22+
2223
osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
2324
batchv1 "k8s.io/api/batch/v1"
2425
corev1 "k8s.io/api/core/v1"
@@ -99,41 +100,69 @@ func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request)
99100
}
100101
}
101102

102-
func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
103-
// generate configmap required for building a custom image
103+
// CreateConfigMap generates a configmap required for building a custom image
104+
func (r *OSArtifactReconciler) CreateConfigMap(ctx context.Context, artifact *osbuilder.OSArtifact) error {
104105
cm := r.genConfigMap(artifact)
105106
if cm.Labels == nil {
106107
cm.Labels = map[string]string{}
107108
}
108109
cm.Labels[artifactLabel] = artifact.Name
109110
if err := controllerutil.SetOwnerReference(artifact, cm, r.Scheme()); err != nil {
110-
return ctrl.Result{Requeue: true}, err
111+
return err
111112
}
112113
if err := r.Create(ctx, cm); err != nil && !apierrors.IsAlreadyExists(err) {
113-
return ctrl.Result{Requeue: true}, err
114+
return err
114115
}
115116

117+
return nil
118+
}
119+
120+
func (r *OSArtifactReconciler) createPVC(ctx context.Context, artifact *osbuilder.OSArtifact) (*corev1.PersistentVolumeClaim, error) {
116121
pvc := r.newArtifactPVC(artifact)
117122
if pvc.Labels == nil {
118123
pvc.Labels = map[string]string{}
119124
}
120125
pvc.Labels[artifactLabel] = artifact.Name
121126
if err := controllerutil.SetOwnerReference(artifact, pvc, r.Scheme()); err != nil {
122-
return ctrl.Result{Requeue: true}, err
127+
return pvc, err
123128
}
124129
if err := r.Create(ctx, pvc); err != nil {
125-
return ctrl.Result{Requeue: true}, err
130+
return pvc, err
126131
}
127132

133+
return pvc, nil
134+
}
135+
136+
func (r *OSArtifactReconciler) createBuilderPod(ctx context.Context, artifact *osbuilder.OSArtifact, pvc *corev1.PersistentVolumeClaim) (*corev1.Pod, error) {
128137
pod := r.newBuilderPod(pvc.Name, artifact)
129138
if pod.Labels == nil {
130139
pod.Labels = map[string]string{}
131140
}
132141
pod.Labels[artifactLabel] = artifact.Name
133142
if err := controllerutil.SetOwnerReference(artifact, pod, r.Scheme()); err != nil {
134-
return ctrl.Result{Requeue: true}, err
143+
return pod, err
135144
}
145+
136146
if err := r.Create(ctx, pod); err != nil {
147+
return pod, err
148+
}
149+
150+
return pod, nil
151+
}
152+
153+
func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
154+
err := r.CreateConfigMap(ctx, artifact)
155+
if err != nil {
156+
return ctrl.Result{Requeue: true}, err
157+
}
158+
159+
pvc, err := r.createPVC(ctx, artifact)
160+
if err != nil {
161+
return ctrl.Result{Requeue: true}, err
162+
}
163+
164+
_, err = r.createBuilderPod(ctx, artifact, pvc)
165+
if err != nil {
137166
return ctrl.Result{Requeue: true}, err
138167
}
139168

0 commit comments

Comments
 (0)