diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index ec9a1cf..ebea5cd 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -4,8 +4,6 @@ on: push: branches: [ main ] tags: [ '*' ] - pull_request: - branches: [ main ] env: REGISTRY: ghcr.io diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..cd31dca --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,33 @@ +name: Run Tests +on: + pull_request: + branches: [ main ] + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Download Go + uses: actions/setup-go@v2 + with: + go-version: 1.19 + + - name: Setup Envtest + run: | + make envtest + + - name: Build + run: go build -v ./... + + - name: Install Ginkgo + run: | + go install github.com/onsi/ginkgo/v2/ginkgo + + - name: Run tests + run: | + set -euo pipefail + KUBEBUILDER_ASSETS=$(./bin/setup-envtest use -p path 1.24.2) go test -v ./... -args -ginkgo.v diff --git a/Makefile b/Makefile index 37cd753..f993aa6 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +SHELL := /bin/bash # VERSION defines the project version for the bundle. # Update this value when you upgrade the version of your project. # To re-generate a bundle for another specific version without changing the standard setup, you can: @@ -87,7 +88,7 @@ help: ## Display this help. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role webhook paths="./..." output:artifacts + $(CONTROLLER_GEN) rbac:roleName=manager-role webhook paths="./..." output:artifacts:config=config .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. @@ -103,7 +104,7 @@ vet: ## Run go vet against code. .PHONY: test test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -i --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out ##@ Build diff --git a/charts/kwasm-operator/Chart.yaml b/charts/kwasm-operator/Chart.yaml index 7f2c20e..6d68819 100644 --- a/charts/kwasm-operator/Chart.yaml +++ b/charts/kwasm-operator/Chart.yaml @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.1 +version: 0.3.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.2.1" +appVersion: "0.3.0" diff --git a/charts/kwasm-operator/templates/deployment.yaml b/charts/kwasm-operator/templates/deployment.yaml index f3b9186..bbe8c20 100644 --- a/charts/kwasm-operator/templates/deployment.yaml +++ b/charts/kwasm-operator/templates/deployment.yaml @@ -32,6 +32,8 @@ spec: value: {{ .Release.Namespace }} - name: AUTO_PROVISION_NODES value: {{ .Values.kwasmOperator.autoProvision | quote }} + - name: CREATE_RUNTIME_CLASS + value: {{ .Values.kwasmOperator.createRuntimeClass | quote }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" diff --git a/charts/kwasm-operator/values.yaml b/charts/kwasm-operator/values.yaml index 59e3c85..c0f26dd 100644 --- a/charts/kwasm-operator/values.yaml +++ b/charts/kwasm-operator/values.yaml @@ -16,6 +16,7 @@ fullnameOverride: "" kwasmOperator: autoProvision: "false" + createRuntimeClass: "false" serviceAccount: # Specifies whether a service account should be created diff --git a/controllers/job_controller.go b/controllers/job_controller.go index fae6d57..99f5d18 100644 --- a/controllers/job_controller.go +++ b/controllers/job_controller.go @@ -22,9 +22,12 @@ import ( "github.com/rs/zerolog/log" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" + nodev1 "k8s.io/api/node/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/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -32,7 +35,8 @@ import ( // JobReconciler reconciles a Job object type JobReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme + CreateRuntimeClass bool } //+kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete @@ -66,6 +70,27 @@ func (r *JobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R return ctrl.Result{}, nil } + if r.CreateRuntimeClass { + runtimeClass := &nodev1.RuntimeClass{} + runtimeClassName := types.NamespacedName{Name: "crun", Namespace: ""} + if err := r.Get(ctx, runtimeClassName, runtimeClass); err != nil { + if apierrors.IsNotFound(err) { + log.Info().Msgf("RuntimeClass not found... Creating it now") + + dep := &nodev1.RuntimeClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "crun", + Namespace: "", + }, + Handler: "crun", + } + r.Create(ctx, dep) + ctrl.SetControllerReference(runtimeClass, dep, r.Scheme) + return ctrl.Result{}, nil + } + } + } + _, finishedType := r.isJobFinished(job) switch finishedType { case "": // ongoing diff --git a/controllers/job_controller_test.go b/controllers/job_controller_test.go new file mode 100644 index 0000000..6708823 --- /dev/null +++ b/controllers/job_controller_test.go @@ -0,0 +1,68 @@ +package controllers_test + +import ( + "context" + + "github.com/kwasm/kwasm-operator/controllers" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + nodev1 "k8s.io/api/node/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +var _ = Describe("JobController", func() { + Context("Kwasm Provisioner Job controller test", func() { + var ( + ctx context.Context + node *corev1.Node + //scheme *runtime.Scheme + //err error + //request ctrl.Request + //result ctrl.Result + ) + ctx = context.Background() + It("should create runtimeclass if CreateRuntimeClass is set", func() { + nodeName := "runtimeclass-node" + nodeNameNamespaced := types.NamespacedName{Name: nodeName, Namespace: ""} + + runtimeClassName := "crun" + runtimeClassNamespaced := types.NamespacedName{Name: runtimeClassName, Namespace: ""} + + jobNameNamespaced := types.NamespacedName{Name: nodeName + "-provision-kwasm", Namespace: namespaceName} + JobReconciler := &controllers.JobReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + CreateRuntimeClass: true, + } + kwasmReconciler := &controllers.ProvisionerReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + node = &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: nodeName, + Annotations: map[string]string{ + "kwasm.sh/kwasm-node": "true", + }, + }, + } + err := k8sClient.Create(ctx, node) + Expect(err).NotTo(HaveOccurred()) + + _, err = kwasmReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: nodeNameNamespaced, + }) + _, err = JobReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: jobNameNamespaced, + }) + // Check that the runtimeclass was created. + runtimeClass := &nodev1.RuntimeClass{} + err = k8sClient.Get(ctx, runtimeClassNamespaced, runtimeClass) + Expect(err).NotTo(HaveOccurred()) + }) + }) +}) diff --git a/controllers/provisioner_controller_test.go b/controllers/provisioner_controller_test.go index 4ae01ad..385c22b 100644 --- a/controllers/provisioner_controller_test.go +++ b/controllers/provisioner_controller_test.go @@ -4,7 +4,7 @@ import ( "context" "github.com/kwasm/kwasm-operator/controllers" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" diff --git a/controllers/suite_test.go b/controllers/suite_test.go index c89e6ef..716451b 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -22,7 +22,7 @@ import ( "path/filepath" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/go.mod b/go.mod index d67940f..686b9a0 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,9 @@ module github.com/kwasm/kwasm-operator -go 1.18 +go 1.20 require ( - github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.27.2 + github.com/onsi/gomega v1.27.3 github.com/rs/zerolog v1.29.0 github.com/stretchr/testify v1.8.1 k8s.io/api v0.26.2 @@ -26,13 +25,14 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect + github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect github.com/google/uuid v1.3.0 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -45,7 +45,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo/v2 v2.9.0 // indirect + github.com/onsi/ginkgo/v2 v2.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect diff --git a/go.sum b/go.sum index de599da..239c34c 100644 --- a/go.sum +++ b/go.sum @@ -95,6 +95,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20230309165930-d61513b1440d h1:um9/pc7tKMINFfP1eE7Wv6PRGXlcCSJkVajF7KJw3uQ= +github.com/google/pprof v0.0.0-20230309165930-d61513b1440d/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -144,10 +146,14 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.9.0 h1:Tugw2BKlNHTMfG+CheOITkYvk4LAh6MFOvikhGVnhE8= github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= +github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.2 h1:SKU0CXeKE/WVgIV1T61kSa3+IRE8Ekrv9rdXDwwTqnY= github.com/onsi/gomega v1.27.2/go.mod h1:5mR3phAHpkAVIDkHEUBY6HGVsU+cpcEscrGPB4oPlZI= +github.com/onsi/gomega v1.27.3 h1:5VwIwnBY3vbBDOJrNtA4rVdiTZCsq9B5F12pvy1Drmk= +github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/main.go b/main.go index b22f110..27317d6 100644 --- a/main.go +++ b/main.go @@ -120,9 +120,15 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Provisioner") os.Exit(1) } + var createRuntimeClass = false + if createRuntimeClassEnv, found := os.LookupEnv("CREATE_RUNTIME_CLASS"); found && strings.ToLower(createRuntimeClassEnv) == "true" { + createRuntimeClass = true + setupLog.Info("CREATE_RUNTIME_CLASS enabled") + } if err = (&controllers.JobReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + CreateRuntimeClass: createRuntimeClass, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Job") os.Exit(1)