From a825ba9cd239c66ba6f55a0358b35b0c9e7d4487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Tich=C3=A1k?= Date: Thu, 29 Oct 2026 15:41:18 +0100 Subject: [PATCH] [core] OCTRL-1108 jit-k8s files are generated and used for k8s deployment when env vars are set --- common/utils/utils.go | 16 ++++++++++++---- common/utils/utils_test.go | 5 +++++ configuration/template/dplutil.go | 14 +++++++++++++- core/task/manager.go | 7 +++++++ core/task/managerk8s.go | 6 +++--- docs/kubernetes_ecs.md | 2 +- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/common/utils/utils.go b/common/utils/utils.go index d04008ce9..01b7d7288 100644 --- a/common/utils/utils.go +++ b/common/utils/utils.go @@ -197,14 +197,22 @@ func ExtractTaskClassName(taskName string) (string, error) { return matches[1], nil } +// JitK8sPrefix is the name prefix of JIT workflows and task classes generated to run on Kubernetes. +const JitK8sPrefix = "jit-k8s-" + // TrimJitPrefix removes the JIT prefix from task class names. -// For example, "jit-ad6f2b64b7502198430d7d7f93f15bf94c088cab-qc-pp-TPC-CalibQC_long" becomes "qc-pp-TPC-CalibQC_long". +// For example, "jit-ad6f2b64b7502198430d7d7f93f15bf94c088cab-qc-pp-TPC-CalibQC_long" becomes "qc-pp-TPC-CalibQC_long", +// as does "jit-k8s-ad6f2b64b7502198430d7d7f93f15bf94c088cab-qc-pp-TPC-CalibQC_long". // If input does not contain a JIT prefix, it is returned as it is. func TrimJitPrefix(taskClassName string) string { + nParts := 3 + if strings.HasPrefix(taskClassName, JitK8sPrefix) { + nParts = 4 + } if strings.HasPrefix(taskClassName, "jit-") { - parts := strings.SplitN(taskClassName, "-", 3) - if len(parts) > 2 { - return parts[2] + parts := strings.SplitN(taskClassName, "-", nParts) + if len(parts) == nParts { + return parts[nParts-1] } } return taskClassName diff --git a/common/utils/utils_test.go b/common/utils/utils_test.go index 5669b89d2..1033070e4 100644 --- a/common/utils/utils_test.go +++ b/common/utils/utils_test.go @@ -33,6 +33,11 @@ var _ = Describe("Utils", func() { Expect(result).To(Equal("qc-pp-TPC-CalibQC_long")) }) + It("should remove the Kubernetes JIT prefix correctly", func() { + result := TrimJitPrefix("jit-k8s-ad6f2b64b7502198430d7d7f93f15bf94c088cab-qc-pp-TPC-CalibQC_long") + Expect(result).To(Equal("qc-pp-TPC-CalibQC_long")) + }) + It("should return the original string if no JIT prefix is present", func() { result := TrimJitPrefix("qc-pp-TPC-CalibQC_long") Expect(result).To(Equal("qc-pp-TPC-CalibQC_long")) diff --git a/configuration/template/dplutil.go b/configuration/template/dplutil.go index e6bd0ceec..1da68ea9d 100644 --- a/configuration/template/dplutil.go +++ b/configuration/template/dplutil.go @@ -29,6 +29,7 @@ import ( "encoding/hex" "fmt" "github.com/AliceO2Group/Control/common/logger/infologger" + "github.com/AliceO2Group/Control/common/utils" "os" "os/exec" "path/filepath" @@ -38,6 +39,7 @@ import ( "github.com/AliceO2Group/Control/configuration/componentcfg" "github.com/AliceO2Group/Control/core/repos" + "github.com/spf13/viper" ) // extractConfigURIs looks for configuration URIs in the provided DPL commands and extracts them @@ -74,6 +76,12 @@ func extractConfigURIs(dplCommand string) (uris []string) { func jitDplGenerate(confSvc ConfigurationService, varStack map[string]string, workflowRepo repos.IRepo, dplCommand string, userWfName string) (jitWorkflowName string, err error) { envId, _ := varStack["environment_id"] + // When enabled, the JIT workflow gets a separate name (and files), whose tasks are deployed via the K8s path + jitK8sEnabled := varStack["jit_k8s_enabled"] == "true" + if jitK8sEnabled && !viper.GetBool("enableKubernetes") { + return "", fmt.Errorf("jit_k8s_enabled is set, but Kubernetes support is not enabled in core (enableKubernetes)") + } + var payloads []string configURIs := extractConfigURIs(dplCommand) @@ -140,7 +148,11 @@ func jitDplGenerate(confSvc ConfigurationService, varStack map[string]string, wo for _, payload := range payloads { hash.Write([]byte(payload)) } - jitWorkflowName = "jit-" + hex.EncodeToString(hash.Sum(nil)) + if jitK8sEnabled { + jitWorkflowName = utils.JitK8sPrefix + hex.EncodeToString(hash.Sum(nil)) + } else { + jitWorkflowName = "jit-" + hex.EncodeToString(hash.Sum(nil)) + } // We now have a workflow name made out of a hash that should be unique with respect to // 1) DPL command and diff --git a/core/task/manager.go b/core/task/manager.go index 8c83bccca..3a4e340e9 100644 --- a/core/task/manager.go +++ b/core/task/manager.go @@ -251,6 +251,13 @@ func getTaskClassList(taskClassesRequired []string) (taskClassList []*taskclass. return } + // DPL generates JIT tasks with control mode fairmq, those generated to run on Kubernetes + // are told apart by their name and switched to kubernetes_fairmq. + if strings.HasPrefix(taskClassStruct.Identifier.Name, utils.JitK8sPrefix) && + taskClassStruct.Control.Mode == controlmode.FAIRMQ { + taskClassStruct.Control.Mode = controlmode.KUBERNETES_FAIRMQ + } + taskClassStruct.Identifier.RepoIdentifier = repo.GetIdentifier() taskClassStruct.Identifier.Hash = repo.GetHash() taskClassList = append(taskClassList, &taskClassStruct) diff --git a/core/task/managerk8s.go b/core/task/managerk8s.go index fb21ba4d1..7d730842e 100644 --- a/core/task/managerk8s.go +++ b/core/task/managerk8s.go @@ -64,9 +64,9 @@ const ( ) // jitClassNameRe matches JIT-generated task class identifiers of the form -// "jit-<40-hex-char-sha1>-" (see configuration/template/dplutil.go) -// and captures the devicename, e.g. "readout-proxy" or "Dispatcher". -var jitClassNameRe = regexp.MustCompile(`^jit-[0-9a-f]{40}-(.+)$`) +// "jit-<40-hex-char-sha1>-" or "jit-k8s-<40-hex-char-sha1>-" +// (see configuration/template/dplutil.go) and captures the devicename, e.g. "readout-proxy" or "Dispatcher". +var jitClassNameRe = regexp.MustCompile(`^jit-(?:k8s-)?[0-9a-f]{40}-(.+)$`) // k8sEnvRegistry maps ECS environment IDs to K8s custom Environment names. type k8sEnvRegistry struct { diff --git a/docs/kubernetes_ecs.md b/docs/kubernetes_ecs.md index c704b7482..87a95bc13 100644 --- a/docs/kubernetes_ecs.md +++ b/docs/kubernetes_ecs.md @@ -67,7 +67,7 @@ Since some tasks are deployed with known values ahead of time (image, env vars, ### DPL and JIT -DPL tasks work similarly to those mentioned before: they use `kubernetes_fairmq` in their workflow YAML manifests. However, there is a problem: JIT tasks' manifests are created the moment they are run. So for now you need to first run the workflow to generate those tasks, then change the control mode after they've been generated. This will be changed in the future. +DPL tasks work similarly to those mentioned before: they use `kubernetes_fairmq` in their workflow YAML manifests. JIT tasks are different, as their manifests are generated by DPL the moment the workflow is run, always with control mode `fairmq`. To run them on Kubernetes, set the environment variable `jit_k8s_enabled` to `true` (requires `enableKubernetes` in core). The JIT workflow is then generated under the name `jit-k8s-` instead of `jit-`, and core switches the control mode of its tasks to `kubernetes_fairmq` when loading them. All JIT tasks are deployed using the shared `dpl` TaskTemplate. ## Running tasks (`KubectlTask`)