Skip to content

Commit

Permalink
1546 byoi (#88)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
jimmykarily committed Aug 31, 2023
1 parent 09058c0 commit e55bd03
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ env:
FORCE_COLOR: 1
jobs:
call-workflow:
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.6
uses: kairos-io/linting-composite-action/.github/workflows/reusable-linting.yaml@v0.0.8
with:
yamldirs: ".github/workflows/ config/ tools-image/"
is-go: true
10 changes: 9 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@ concurrency:
cancel-in-progress: true

jobs:
docker:
e2e-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Test
run: |
make kind-e2e-tests
controller-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Test
run: |
make controller-tests
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ kind-setup:
kind-setup-image: docker-build
kind load docker-image --name $(CLUSTER_NAME) ${IMG}

kind-teardown:
kind delete cluster --name ${CLUSTER_NAME} || true

.PHONY: test_deps
test_deps:
go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
Expand All @@ -275,8 +278,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
controller-tests: ginkgo kind-setup install undeploy-dev deploy-dev
USE_EXISTING_CLUSTER=true go run github.com/onsi/ginkgo/v2/ginkgo -v run controllers/.

kind-e2e-tests: ginkgo kind-setup install undeploy-dev deploy-dev e2e-tests

kubesplit: manifests kustomize
rm -rf helm-chart
Expand Down
9 changes: 9 additions & 0 deletions api/v1alpha2/osartifact_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,17 @@ import (

// OSArtifactSpec defines the desired state of OSArtifact
type OSArtifactSpec struct {
// There are 3 ways to specify a Kairos image:

// Points to a prepared kairos image (e.g. a released one)
ImageName string `json:"imageName,omitempty"`

// Points to a vanilla (non-Kairos) image. osbuilder will try to convert this to a Kairos image
BaseImageName string `json:"baseImageName,omitempty"`

// 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.
BaseImageDockerfile *SecretKeySelector `json:"baseImageDockerfile,omitempty"`

ISO bool `json:"iso,omitempty"`

//Disk-only stuff
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions config/crd/bases/build.kairos.io_osartifacts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ spec:
properties:
azureImage:
type: boolean
baseImageDockerfile:
description: 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.
properties:
key:
type: string
name:
type: string
required:
- name
type: object
baseImageName:
description: Points to a vanilla (non-Kairos) image. osbuilder will
try to convert this to a Kairos image
type: string
bundles:
items:
type: string
Expand Down Expand Up @@ -7834,6 +7850,7 @@ spec:
grubConfig:
type: string
imageName:
description: Points to a prepared kairos image (e.g. a released one)
type: string
imagePullSecrets:
items:
Expand Down
103 changes: 100 additions & 3 deletions controllers/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package controllers

import (
"fmt"

"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -292,6 +293,17 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
},
}

if artifact.Spec.BaseImageDockerfile != nil {
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: "dockerfile",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: artifact.Spec.BaseImageDockerfile.Name,
},
},
})
}

if artifact.Spec.CloudConfigRef != nil {
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
Name: "cloudconfig",
Expand All @@ -304,11 +316,40 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
})
}

for i := range artifact.Spec.ImagePullSecrets {
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets[i])
podSpec.ImagePullSecrets = append(podSpec.ImagePullSecrets, artifact.Spec.ImagePullSecrets...)

podSpec.InitContainers = []corev1.Container{}
// Base image can be:
// - built from a dockerfile and converted to a kairos one
// - built by converting an existing image to a kairos one
// - a prebuilt kairos image
if artifact.Spec.BaseImageDockerfile != nil {
podSpec.InitContainers = append(podSpec.InitContainers, baseImageBuildContainers()...)
} else if artifact.Spec.BaseImageName != "" { // Existing base image - non kairos
podSpec.InitContainers = append(podSpec.InitContainers,
unpackContainer("baseimage-non-kairos", r.ToolImage, artifact.Spec.BaseImageName))
} else { // Existing Kairos base image
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName))
}

podSpec.InitContainers = []corev1.Container{unpackContainer("baseimage", r.ToolImage, artifact.Spec.ImageName)}
// If base image was a non kairos one, either one we built with kaniko or prebuilt,
// convert it to a Kairos one, in a best effort manner.
if artifact.Spec.BaseImageDockerfile != nil || artifact.Spec.BaseImageName != "" {
podSpec.InitContainers = append(podSpec.InitContainers,
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "convert-to-kairos",
Image: "busybox",
Command: []string{"/bin/echo"},
Args: []string{"TODO"},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
},
})
}

for i, bundle := range artifact.Spec.Bundles {
podSpec.InitContainers = append(podSpec.InitContainers, unpackContainer(fmt.Sprint(i), r.ToolImage, bundle))
Expand Down Expand Up @@ -352,3 +393,59 @@ func (r *OSArtifactReconciler) newBuilderPod(pvcName string, artifact *osbuilder
func ptr[T any](val T) *T {
return &val
}

func baseImageBuildContainers() []corev1.Container {
return []corev1.Container{
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "kaniko-build",
Image: "gcr.io/kaniko-project/executor:latest",
Args: []string{
"--dockerfile", "dockerfile/Dockerfile",
"--context", "dir://workspace",
"--destination", "whatever", // We don't push, but it needs this
"--tar-path", "/rootfs/image.tar",
"--no-push",
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
{
Name: "dockerfile",
MountPath: "/workspace/dockerfile",
},
},
},
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "image-extractor",
Image: "quay.io/luet/base",
Args: []string{
"util", "unpack", "--local", "file:////rootfs/image.tar", "/rootfs",
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
},
},
corev1.Container{
ImagePullPolicy: corev1.PullAlways,
Name: "cleanup",
Image: "busybox",
Command: []string{"/bin/rm"},
Args: []string{
"/rootfs/image.tar",
},
VolumeMounts: []corev1.VolumeMount{
{
Name: "rootfs",
MountPath: "/rootfs",
},
},
},
}
}
43 changes: 36 additions & 7 deletions controllers/osartifact_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package controllers
import (
"context"
"fmt"

osbuilder "github.com/kairos-io/osbuilder/api/v1alpha2"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -99,41 +100,69 @@ func (r *OSArtifactReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}
}

func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
// generate configmap required for building a custom image
// CreateConfigMap generates a configmap required for building a custom image
func (r *OSArtifactReconciler) CreateConfigMap(ctx context.Context, artifact *osbuilder.OSArtifact) error {
cm := r.genConfigMap(artifact)
if cm.Labels == nil {
cm.Labels = map[string]string{}
}
cm.Labels[artifactLabel] = artifact.Name
if err := controllerutil.SetOwnerReference(artifact, cm, r.Scheme()); err != nil {
return ctrl.Result{Requeue: true}, err
return err
}
if err := r.Create(ctx, cm); err != nil && !apierrors.IsAlreadyExists(err) {
return ctrl.Result{Requeue: true}, err
return err
}

return nil
}

func (r *OSArtifactReconciler) createPVC(ctx context.Context, artifact *osbuilder.OSArtifact) (*corev1.PersistentVolumeClaim, error) {
pvc := r.newArtifactPVC(artifact)
if pvc.Labels == nil {
pvc.Labels = map[string]string{}
}
pvc.Labels[artifactLabel] = artifact.Name
if err := controllerutil.SetOwnerReference(artifact, pvc, r.Scheme()); err != nil {
return ctrl.Result{Requeue: true}, err
return pvc, err
}
if err := r.Create(ctx, pvc); err != nil {
return ctrl.Result{Requeue: true}, err
return pvc, err
}

return pvc, nil
}

func (r *OSArtifactReconciler) createBuilderPod(ctx context.Context, artifact *osbuilder.OSArtifact, pvc *corev1.PersistentVolumeClaim) (*corev1.Pod, error) {
pod := r.newBuilderPod(pvc.Name, artifact)
if pod.Labels == nil {
pod.Labels = map[string]string{}
}
pod.Labels[artifactLabel] = artifact.Name
if err := controllerutil.SetOwnerReference(artifact, pod, r.Scheme()); err != nil {
return ctrl.Result{Requeue: true}, err
return pod, err
}

if err := r.Create(ctx, pod); err != nil {
return pod, err
}

return pod, nil
}

func (r *OSArtifactReconciler) startBuild(ctx context.Context, artifact *osbuilder.OSArtifact) (ctrl.Result, error) {
err := r.CreateConfigMap(ctx, artifact)
if err != nil {
return ctrl.Result{Requeue: true}, err
}

pvc, err := r.createPVC(ctx, artifact)
if err != nil {
return ctrl.Result{Requeue: true}, err
}

_, err = r.createBuilderPod(ctx, artifact, pvc)
if err != nil {
return ctrl.Result{Requeue: true}, err
}

Expand Down
Loading

0 comments on commit e55bd03

Please sign in to comment.