[KOGITO-7981] Provide a Build CRD for the kaniko Builder (refactor) Signed-off-by: Davide Salerno <dsalerno@redhat.com>
diff --git a/.github/workflows/test-go.yml b/.github/workflows/test-go.yml index b45229d..402ab32 100644 --- a/.github/workflows/test-go.yml +++ b/.github/workflows/test-go.yml
@@ -1,6 +1,9 @@ name: go on: - pull_request: {} + pull_request: + types: [opened, reopened] + branches: + - main jobs: unit: @@ -11,7 +14,7 @@ steps: - uses: actions/setup-go@v2 with: - go-version: 1.18 + go-version: 1.19 - uses: actions/checkout@v2 with: fetch-depth: 0
diff --git a/README.md b/README.md index 9c230b7..1a898e6 100644 --- a/README.md +++ b/README.md
@@ -103,13 +103,14 @@ 8. Default configuration -A configmap called kogito-builder-config will be created under the kogito-builder namespace at the first application of a workflow, it contains: +A configmap called kogito-serverless-operator-builder-config will be created under the kogito-serverless-operator-system +namespace when the Operator will be installer and it contains: -- BUILDER_RESOURCE_DEFAULT = Dockerfile -- WORKFLOW_DEFAULT_EXTENSION = .sw.json +- DEFAULT_BUILDER_RESOURCE = kogito_builder_dockerfile.yaml +- DEFAULT_WORKFLOW_DEXTENSION = .sw.json - DEFAULT_KANIKO_SECRET_DEFAULT = regcred -- DEFAULT_REGISTRY_REPO = quay.io/kiegroup -- Dockerfile = dockerfile content +- DEFAULT_REGISTRY_REPO = quay.io/kiegroup +- kogito_builder_dockerfile.yaml = dockerfile content For the local development the DEFAULT_REGISTRY_REPO must be changed
diff --git a/builder/builder.go b/builder/builder.go index d5c000e..fb28716 100644 --- a/builder/builder.go +++ b/builder/builder.go
@@ -37,7 +37,7 @@ } func (b *Builder) getImageBuilder(workflowID string, workflowDefinition []byte) ImageBuilder { - containerFile := b.cm.Data[constants.BUILDER_RESOURCE_NAME_DEFAULT] + containerFile := b.cm.Data[b.cm.Data[constants.DEFAULT_BUILDER_RESOURCE_NAME_KEY]] ib := NewImageBuilder(workflowID, workflowDefinition, []byte(containerFile)) ib.OnNamespace(constants.BUILDER_NAMESPACE_DEFAULT) ib.WithPodMiddleName(constants.BUILDER_IMG_NAME_DEFAULT) @@ -95,7 +95,7 @@ build, err := builder.NewBuild(platform, kb.ImageName, kb.PodMiddleName). WithResource(constants.BUILDER_RESOURCE_NAME_DEFAULT, kb.ContainerFile). - WithResource(kb.WorkflowID+b.cm.Data[constants.WORKFLOW_DEFAULT_EXTENSION_KEY], kb.WorkflowDefinition). + WithResource(kb.WorkflowID+b.cm.Data[constants.DEFAULT_WORKFLOW_EXTENSION_KEY], kb.WorkflowDefinition). WithClient(cli). Schedule() if err != nil { @@ -129,7 +129,7 @@ build, err := builder.NewBuild(platform, kb.ImageName, kb.PodMiddleName). WithResource(constants.BUILDER_RESOURCE_NAME_DEFAULT, kb.ContainerFile). - WithResource(kb.WorkflowID+b.cm.Data[constants.WORKFLOW_DEFAULT_EXTENSION_KEY], kb.WorkflowDefinition). + WithResource(kb.WorkflowID+b.cm.Data[constants.DEFAULT_WORKFLOW_EXTENSION_KEY], kb.WorkflowDefinition). WithClient(cli). Schedule() if err != nil {
diff --git a/config/crd/bases/sw.kogito.kie.org_kogitoserverlessbuilds.yaml b/config/crd/bases/sw.kogito.kie.org_kogitoserverlessbuilds.yaml index 4811b7b..29a2d98 100644 --- a/config/crd/bases/sw.kogito.kie.org_kogitoserverlessbuilds.yaml +++ b/config/crd/bases/sw.kogito.kie.org_kogitoserverlessbuilds.yaml
@@ -36,9 +36,8 @@ spec: description: KogitoServerlessBuildSpec defines the desired state of KogitoServerlessBuild properties: - dockerfile: - description: Dockerfile content used for the build @TODO load from - configmap + containerFile: + description: ContainerFile content used for the build format: byte type: string imageName:
diff --git a/config/manager/kogito_builder_dockerfile.yaml b/config/manager/kogito_builder_dockerfile.yaml new file mode 100644 index 0000000..39e10fe --- /dev/null +++ b/config/manager/kogito_builder_dockerfile.yaml
@@ -0,0 +1,25 @@ +FROM quay.io/mdessi/kogito-swf-builder:latest AS builder + + # Copy from build context to skeleton resources project +COPY * ./resources/ + +RUN /home/kogito/launch/build-app.sh ./resources + + #============================= + # Runtime Run + #============================= +FROM registry.access.redhat.com/ubi8/openjdk-11:latest + +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' + + # We make four distinct layers so if there are application changes the library layers can be re-used +COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/lib/ /deployments/lib/ +COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/*.jar /deployments/ +COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/app/ /deployments/app/ +COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/quarkus/ /deployments/quarkus/ + +EXPOSE 8080 +USER 185 +ENV AB_JOLOKIA_OFF="" +ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 4033ccc..56794e7 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml
@@ -8,9 +8,34 @@ - files: - controller_manager_config.yaml name: manager-config +- files: + - Dockerfile=kogito_builder_dockerfile.yaml + literals: + - DEFAULT_BUILDER_RESOURCE_NAME=Dockerfile + - DEFAULT_KANIKO_SECRET_DEFAULT=regcred + - DEFAULT_REGISTRY_REPO=quay.io/kiegroup + - DEFAULT_WORKFLOW_EXTENSION_KEY=.sw.json + name: builder-config + apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller newName: quay.io/dsalerno/kogito-serverless-operator newTag: 0.0.1 +# Patching the manager deployment file to add an env var with the operator namespace in +patchesJson6902: +- patch: |- + - op: add + path: /spec/template/spec/containers/0/env + value: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + target: + group: apps + kind: Deployment + name: controller-manager + namespace: system + version: v1
diff --git a/constants/const.go b/constants/const.go index 650b4ea..9520eb5 100644 --- a/constants/const.go +++ b/constants/const.go
@@ -16,25 +16,14 @@ package constants const ( - BUILDER_CM_NAME = "kogito-builder-config" + BUILDER_CM_NAME = "kogito-serverless-operator-builder-config" BUILDER_NAMESPACE_DEFAULT = "kogito-builder" BUILDER_IMG_NAME_DEFAULT = "platform" BUILDER_RESOURCE_NAME_DEFAULT = "Dockerfile" DEFAULT_IMAGES_TAG = ":latest" - BUILDER_RESOURCE_NAME_DEFAULT_KEY = "BUILDER_RESOURCE_NAME_DEFAULT" - WORKFLOW_DEFAULT_EXTENSION_KEY = "WORKFLOW_DEFAULT_EXTENSION" + DEFAULT_BUILDER_RESOURCE_NAME_KEY = "DEFAULT_BUILDER_RESOURCE_NAME" + DEFAULT_WORKFLOW_EXTENSION_KEY = "DEFAULT_WORKFLOW_EXTENSION" DEFAULT_REGISTRY_REPO_KEY = "DEFAULT_REGISTRY_REPO" - DEFAULT_KANIKO_SECRET_KEY = "DEFAULT_KANIKO_SECRET_DEFAULT" + DEFAULT_KANIKO_SECRET_KEY = "DEFAULT_KANIKO_SECRET_DEFAULT" // #gitleaks:allow ) - -func GetKogitoBuilderConfigMap() map[string]string { - cmData := make(map[string]string) - - cmData[DEFAULT_REGISTRY_REPO_KEY] = "quay.io/kiegroup" - cmData[DEFAULT_KANIKO_SECRET_KEY] = "regcred" - cmData[WORKFLOW_DEFAULT_EXTENSION_KEY] = ".sw.json" - cmData[BUILDER_RESOURCE_NAME_DEFAULT_KEY] = BUILDER_RESOURCE_NAME_DEFAULT - - return cmData -}
diff --git a/controllers/kogitoserverlessbuild_controller.go b/controllers/kogitoserverlessbuild_controller.go index 6e9392b..45e890e 100644 --- a/controllers/kogitoserverlessbuild_controller.go +++ b/controllers/kogitoserverlessbuild_controller.go
@@ -24,7 +24,9 @@ "github.com/ricardozanini/kogito-builder/api" clientr "github.com/ricardozanini/kogito-builder/client" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" @@ -36,8 +38,9 @@ // KogitoServerlessBuildReconciler reconciles a KogitoServerlessBuild object type KogitoServerlessBuildReconciler struct { client.Client - Scheme *runtime.Scheme - Recorder record.EventRecorder + Scheme *runtime.Scheme + Recorder record.EventRecorder + defaultBuildConf corev1.ConfigMap } //+kubebuilder:rbac:groups=sw.kogito.kie.org,resources=kogitoserverlessbuilds,verbs=get;list;watch;create;update;patch;delete @@ -57,12 +60,17 @@ err := r.Client.Get(ctx, req.NamespacedName, instance) if err == nil { phase := instance.Status.BuildPhase - configMap, _ := utils.GetConfigMap(r.Client, constants.BUILDER_NAMESPACE_DEFAULT) - if len(configMap.Data[constants.BUILDER_RESOURCE_NAME_DEFAULT]) == 0 { - return ctrl.Result{}, nil + if r.defaultBuildConf.Data == nil { + r.defaultBuildConf, err = utils.GetConfigMap(r.Client) } - builder := builder.NewBuilder(ctx, configMap) + if err != nil || len(r.defaultBuildConf.Data[r.defaultBuildConf.Data[constants.DEFAULT_BUILDER_RESOURCE_NAME_KEY]]) == 0 { + return ctrl.Result{}, errors.NewNotFound(schema.GroupResource{ + Resource: "ConfigMap", + }, "builder-config") + } + + builder := builder.NewBuilder(ctx, r.defaultBuildConf) if phase == api.BuildPhaseNone { workflow, err := r.retrieveWorkflowFromCR(instance.Spec.WorkflowId, ctx, req)
diff --git a/controllers/kogitoserverlessworkflow_controller.go b/controllers/kogitoserverlessworkflow_controller.go index 0cee03a..6fa35d5 100644 --- a/controllers/kogitoserverlessworkflow_controller.go +++ b/controllers/kogitoserverlessworkflow_controller.go
@@ -20,8 +20,6 @@ "context" apiv08 "github.com/davidesalerno/kogito-serverless-operator/api/v08" "github.com/davidesalerno/kogito-serverless-operator/builder" - "github.com/davidesalerno/kogito-serverless-operator/constants" - "github.com/davidesalerno/kogito-serverless-operator/utils" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/record" @@ -52,7 +50,6 @@ // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.2/pkg/reconcile func (r *KogitoServerlessWorkflowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := ctrllog.FromContext(ctx) - utils.InitConfigMap(r.Client, constants.BUILDER_NAMESPACE_DEFAULT, log) instance := &apiv08.KogitoServerlessWorkflow{} err := r.Client.Get(ctx, req.NamespacedName, instance) if err != nil {
diff --git a/operator.yaml b/operator.yaml index 2d45c71..ccfe473 100644 --- a/operator.yaml +++ b/operator.yaml
@@ -9,7 +9,7 @@ kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.8.0 + controller-gen.kubebuilder.io/version: v0.9.2 creationTimestamp: null name: kogitoserverlessbuilds.sw.kogito.kie.org spec: @@ -37,43 +37,28 @@ spec: description: KogitoServerlessBuildSpec defines the desired state of KogitoServerlessBuild properties: - buildPhase: - description: BuildPhase -- - type: string - dockerfile: + containerFile: + description: ContainerFile content used for the build format: byte type: string imageName: + description: Image name type: string podMiddleName: + description: Middlename of the pod type: string workflowId: + description: Workflow's unique identifier type: string type: object status: description: KogitoServerlessBuildStatus defines the observed state of KogitoServerlessBuild properties: - applied: - description: KogitoServerlessBuildSpec defines the desired state of KogitoServerlessBuild - properties: - buildPhase: - description: BuildPhase -- - type: string - dockerfile: - format: byte - type: string - imageName: - type: string - podMiddleName: - type: string - workflowId: - type: string - type: object buildPhase: - description: BuildPhase -- + description: Current kaniko buildphase type: string builder: - description: Build is the Schema for the builder API. Follows the Kubernetes resource structure, but it's not tied to it. Can be used in any environment. + description: Kaniko's build, used to ping the build to update the buildphase properties: meta: description: ObjectReference is a subset of the kubernetes k8s.io/apimachinery/pkg/apis/meta/v1.Object interface. Objects in this API not necessarily represent Kubernetes objects, but this structure can help when needed. @@ -242,15 +227,15 @@ resourceVolume: description: reference to where the build resources are located properties: - refName: + referenceName: description: ReferenceName name of the object holding the resources reference type: string - refType: + referenceType: description: ReferenceType type of the resource holding the reference type: string required: - - refName - - refType + - referenceName + - referenceType type: object startedAt: description: the time when it started @@ -258,51 +243,21 @@ type: string type: object type: object - deployments: - properties: - ready: - description: Deployments are ready to serve requests - items: - type: string - type: array - starting: - description: Deployments are starting, may or may not succeed - items: - type: string - type: array - stopped: - description: Deployments are not starting, unclear what next step will be - items: - type: string - type: array - type: object - phase: - description: ConditionType - type of condition - type: string - version: - type: string workflowId: + description: Workflow's unique identifier type: string - required: - - deployments type: object type: object served: true storage: true subresources: status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.8.0 + controller-gen.kubebuilder.io/version: v0.9.2 creationTimestamp: null name: kogitoserverlessworkflows.sw.kogito.kie.org spec: @@ -1909,12 +1864,6 @@ type: object served: true storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] --- apiVersion: v1 kind: ServiceAccount @@ -2036,12 +1985,6 @@ - apiGroups: - sw.kogito.kie.org resources: - - kogitoserverlessbuilds/finalizers - verbs: - - update -- apiGroups: - - sw.kogito.kie.org - resources: - kogitoserverlessbuilds/status verbs: - get @@ -2165,6 +2108,18 @@ --- apiVersion: v1 data: + BUILDER_RESOURCE_NAME_DEFAULT: kogito_builder_dockerfile.yaml + DEFAULT_KANIKO_SECRET_DEFAULT: regcred + DEFAULT_REGISTRY_REPO: quay.io/dsalerno + DEFAULT_WORKFLOW_EXTENSION_KEY: .sw.json + kogito_builder_dockerfile.yaml: "FROM quay.io/mdessi/kogito-swf-builder:latest AS builder\n \n # Copy from build context to skeleton resources project\nCOPY * ./resources/\n\nRUN /home/kogito/launch/build-app.sh ./resources\n \n #=============================\n # Runtime Run\n #=============================\nFROM registry.access.redhat.com/ubi8/openjdk-11:latest\n\nENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'\n \n # We make four distinct layers so if there are application changes the library layers can be re-used\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/lib/ /deployments/lib/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/*.jar /deployments/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/app/ /deployments/app/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/quarkus/ /deployments/quarkus/\n\nEXPOSE 8080\nUSER 185\nENV AB_JOLOKIA_OFF=\"\"\nENV JAVA_OPTS=\"-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager\"\nENV JAVA_APP_JAR=\"/deployments/quarkus-run.jar\"\n" +kind: ConfigMap +metadata: + name: kogito-serverless-operator-builder-config + namespace: kogito-serverless-operator-system +--- +apiVersion: v1 +data: controller_manager_config.yaml: | apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 kind: ControllerManagerConfig @@ -2223,7 +2178,7 @@ - --upstream=http://127.0.0.1:8080/ - --logtostderr=true - --v=0 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.11.0 + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.0 name: kube-rbac-proxy ports: - containerPort: 8443 @@ -2242,7 +2197,12 @@ - --leader-elect command: - /manager - image: quay.io/mdessi/kogito-serverless-operator:0.0.1 + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: quay.io/dsalerno/kogito-serverless-operator:0.0.1 livenessProbe: httpGet: path: /healthz
diff --git a/utils/workflow.go b/utils/workflow.go index 31c1627..e83708c 100644 --- a/utils/workflow.go +++ b/utils/workflow.go
@@ -18,12 +18,11 @@ import ( "context" "encoding/json" + "errors" apiv08 "github.com/davidesalerno/kogito-serverless-operator/api/v08" "github.com/davidesalerno/kogito-serverless-operator/constants" "github.com/davidesalerno/kogito-serverless-operator/converters" - "github.com/go-logr/logr" "github.com/ricardozanini/kogito-builder/util/log" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -48,7 +47,13 @@ return jsonWorkflow, nil } -func GetConfigMap(client client.Client, namespace string) (corev1.ConfigMap, error) { +func GetConfigMap(client client.Client) (corev1.ConfigMap, error) { + + namespace, found := os.LookupEnv("POD_NAMESPACE") + + if !found { + return corev1.ConfigMap{}, errors.New("ConfigMap not found") + } existingConfigMap := corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{ @@ -70,49 +75,3 @@ return existingConfigMap, nil } } - -func CreateConfigMap(client client.Client, namespace string, cmData map[string]string, log logr.Logger) (cm corev1.ConfigMap, error error) { - myDep := &appsv1.Deployment{} - error = client.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: constants.BUILDER_CM_NAME}, myDep) - - cm = corev1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: constants.BUILDER_CM_NAME, - Namespace: namespace, - }, - Data: cmData, - } - cm.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ConfigMap")) - cm.SetOwnerReferences(myDep.GetOwnerReferences()) - error = client.Create(context.TODO(), &cm) - if error != nil { - log.Error(error, "configmap create error") - return cm, error - } else { - return cm, nil - } -} - -func InitConfigMap(client client.Client, namespace string, log logr.Logger) (cm corev1.ConfigMap, error error) { - configMap, err := GetConfigMap(client, namespace) - if err != nil { - wd, _ := os.Getwd() - dockerFile, _ := os.ReadFile(wd + "/builder/Dockerfile") - cmData := constants.GetKogitoBuilderConfigMap() - cmData[constants.BUILDER_RESOURCE_NAME_DEFAULT] = string(dockerFile) - - _, errx := CreateConfigMap(client, constants.BUILDER_NAMESPACE_DEFAULT, cmData, log) - if errx != nil { - log.Error(err, "configmap error ") - } else { - log.Info(constants.BUILDER_CM_NAME+" created", "") - } - return GetConfigMap(client, namespace) - } else { - return configMap, err - } -}