From 42d75e09e548be459ba6d53ebc97d931c990edae Mon Sep 17 00:00:00 2001 From: Paul Sweeney Date: Mon, 22 Jan 2024 05:11:52 +0000 Subject: [PATCH] Fix: add cronjob support for annotations, resources, and volumeMounts (#6422) * Fix: add cronjob support for annotations, resources, and volumeMounts Signed-off-by: kolossi * Fix: cronjob support change if shortcuts to chained ifs Signed-off-by: kolossi * Fix: cronjob support change if shortcuts to chained ifs Signed-off-by: kolossi --------- Signed-off-by: kolossi Co-authored-by: kolossi --- .../defwithtemplate/annotations.yaml | 20 +- .../templates/defwithtemplate/cron-task.yaml | 195 +++++++++++++++++- .../templates/defwithtemplate/resource.yaml | 73 ++++--- .../internal/component/cron-task.cue | 195 +++++++++++++++++- .../internal/trait/annotations.cue | 28 +-- .../definitions/internal/trait/resource.cue | 71 ++++--- 6 files changed, 495 insertions(+), 87 deletions(-) diff --git a/charts/vela-core/templates/defwithtemplate/annotations.yaml b/charts/vela-core/templates/defwithtemplate/annotations.yaml index 0457ef3ed..36efeb5bb 100644 --- a/charts/vela-core/templates/defwithtemplate/annotations.yaml +++ b/charts/vela-core/templates/defwithtemplate/annotations.yaml @@ -4,7 +4,7 @@ apiVersion: core.oam.dev/v1beta1 kind: TraitDefinition metadata: annotations: - definition.oam.dev/description: Add annotations on your workload. if it generates pod, add same annotations for generated pods. + definition.oam.dev/description: Add annotations on your workload. If it generates pod or job, add same annotations for generated pods. name: annotations namespace: {{ include "systemDefinitionNamespace" . }} spec: @@ -16,17 +16,21 @@ spec: template: | // +patchStrategy=jsonMergePatch patch: { - metadata: annotations: { + let annotationsContent = { for k, v in parameter { (k): v } } - if context.output.spec != _|_ && context.output.spec.template != _|_ { - spec: template: metadata: annotations: { - for k, v in parameter { - (k): v - } - } + + metadata: annotations: annotationsContent + if context.output.spec != _|_ if context.output.spec.template != _|_ { + spec: template: metadata: annotations: annotationsContent + } + if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ { + spec: jobTemplate: metadata: annotations: annotationsContent + } + if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ if context.output.spec.jobTemplate.spec != _|_ if context.output.spec.jobTemplate.spec.template != _|_ { + spec: jobTemplate: spec: template: metadata: annotations: annotationsContent } } parameter: [string]: string | null diff --git a/charts/vela-core/templates/defwithtemplate/cron-task.yaml b/charts/vela-core/templates/defwithtemplate/cron-task.yaml index ead91038c..08b110154 100644 --- a/charts/vela-core/templates/defwithtemplate/cron-task.yaml +++ b/charts/vela-core/templates/defwithtemplate/cron-task.yaml @@ -11,6 +11,138 @@ spec: schematic: cue: template: | + mountsArray: { + pvc: *[ + for v in parameter.volumeMounts.pvc { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + configMap: *[ + for v in parameter.volumeMounts.configMap { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + secret: *[ + for v in parameter.volumeMounts.secret { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + emptyDir: *[ + for v in parameter.volumeMounts.emptyDir { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + hostPath: *[ + for v in parameter.volumeMounts.hostPath { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + } + volumesArray: { + pvc: *[ + for v in parameter.volumeMounts.pvc { + { + name: v.name + persistentVolumeClaim: claimName: v.claimName + } + }, + ] | [] + + configMap: *[ + for v in parameter.volumeMounts.configMap { + { + name: v.name + configMap: { + defaultMode: v.defaultMode + name: v.cmName + if v.items != _|_ { + items: v.items + } + } + } + }, + ] | [] + + secret: *[ + for v in parameter.volumeMounts.secret { + { + name: v.name + secret: { + defaultMode: v.defaultMode + secretName: v.secretName + if v.items != _|_ { + items: v.items + } + } + } + }, + ] | [] + + emptyDir: *[ + for v in parameter.volumeMounts.emptyDir { + { + name: v.name + emptyDir: medium: v.medium + } + }, + ] | [] + + hostPath: *[ + for v in parameter.volumeMounts.hostPath { + { + name: v.name + hostPath: path: v.path + } + }, + ] | [] + } + volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath + deDupVolumesArray: [ + for val in [ + for i, vi in volumesList { + for j, vj in volumesList if j < i && vi.name == vj.name { + _ignore: true + } + vi + }, + ] if val._ignore == _|_ { + val + }, + ] output: { if context.clusterVersion.minor < 25 { apiVersion: "batch/v1beta1" @@ -90,15 +222,18 @@ spec: requests: memory: parameter.memory } } - if parameter["volumes"] != _|_ { + if parameter["volumes"] != _|_ if parameter["volumeMounts"] == _|_ { volumeMounts: [ for v in parameter.volumes { { mountPath: v.mountPath name: v.name }}] } + if parameter["volumeMounts"] != _|_ { + volumeMounts: mountsArray.pvc + mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir + mountsArray.hostPath + } }] - if parameter["volumes"] != _|_ { + if parameter["volumes"] != _|_ if parameter["volumeMounts"] == _|_ { volumes: [ for v in parameter.volumes { { name: v.name @@ -128,6 +263,9 @@ spec: } }}] } + if parameter["volumeMounts"] != _|_ { + volumes: deDupVolumesArray + } if parameter["imagePullSecrets"] != _|_ { imagePullSecrets: [ for v in parameter.imagePullSecrets { name: v @@ -224,7 +362,58 @@ spec: // +usage=Specifies the attributes of the memory resource required for the container. memory?: string - // +usage=Declare volumes and volumeMounts + volumeMounts?: { + // +usage=Mount PVC type volume + pvc?: [...{ + name: string + mountPath: string + subPath?: string + // +usage=The name of the PVC + claimName: string + }] + // +usage=Mount ConfigMap type volume + configMap?: [...{ + name: string + mountPath: string + subPath?: string + defaultMode: *420 | int + cmName: string + items?: [...{ + key: string + path: string + mode: *511 | int + }] + }] + // +usage=Mount Secret type volume + secret?: [...{ + name: string + mountPath: string + subPath?: string + defaultMode: *420 | int + secretName: string + items?: [...{ + key: string + path: string + mode: *511 | int + }] + }] + // +usage=Mount EmptyDir type volume + emptyDir?: [...{ + name: string + mountPath: string + subPath?: string + medium: *"" | "Memory" + }] + // +usage=Mount HostPath type volume + hostPath?: [...{ + name: string + mountPath: string + subPath?: string + path: string + }] + } + + // +usage=Deprecated field, use volumeMounts instead. volumes?: [...{ name: string mountPath: string diff --git a/charts/vela-core/templates/defwithtemplate/resource.yaml b/charts/vela-core/templates/defwithtemplate/resource.yaml index 5febcf1a0..3f707c062 100644 --- a/charts/vela-core/templates/defwithtemplate/resource.yaml +++ b/charts/vela-core/templates/defwithtemplate/resource.yaml @@ -13,43 +13,54 @@ spec: - statefulsets.apps - daemonsets.apps - jobs.batch + - cronjobs.batch podDisruptive: true schematic: cue: - template: | - patch: spec: template: spec: { - // +patchKey=name - containers: [{ - resources: { - if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ { - // +patchStrategy=retainKeys - requests: { - cpu: parameter.cpu - memory: parameter.memory - } - // +patchStrategy=retainKeys - limits: { - cpu: parameter.cpu - memory: parameter.memory - } + template: |2 + let resourceContent = { + resources: { + if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ { + // +patchStrategy=retainKeys + requests: { + cpu: parameter.cpu + memory: parameter.memory } - - if parameter.requests != _|_ { - // +patchStrategy=retainKeys - requests: { - cpu: parameter.requests.cpu - memory: parameter.requests.memory - } - } - if parameter.limits != _|_ { - // +patchStrategy=retainKeys - limits: { - cpu: parameter.limits.cpu - memory: parameter.limits.memory - } + // +patchStrategy=retainKeys + limits: { + cpu: parameter.cpu + memory: parameter.memory } } - }] + + if parameter.requests != _|_ { + // +patchStrategy=retainKeys + requests: { + cpu: parameter.requests.cpu + memory: parameter.requests.memory + } + } + if parameter.limits != _|_ { + // +patchStrategy=retainKeys + limits: { + cpu: parameter.limits.cpu + memory: parameter.limits.memory + } + } + } + } + + if context.output.spec != _|_ if context.output.spec.template != _|_ { + patch: spec: template: spec: { + // +patchKey=name + containers: [resourceContent] + } + } + if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ { + patch: spec: jobTemplate: spec: template: spec: { + // +patchKey=name + containers: [resourceContent] + } } parameter: { diff --git a/vela-templates/definitions/internal/component/cron-task.cue b/vela-templates/definitions/internal/component/cron-task.cue index 51ffd16e4..488bb9519 100644 --- a/vela-templates/definitions/internal/component/cron-task.cue +++ b/vela-templates/definitions/internal/component/cron-task.cue @@ -6,6 +6,138 @@ attributes: workload: type: "autodetects.core.oam.dev" } template: { + mountsArray: { + pvc: *[ + for v in parameter.volumeMounts.pvc { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + configMap: *[ + for v in parameter.volumeMounts.configMap { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + secret: *[ + for v in parameter.volumeMounts.secret { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + emptyDir: *[ + for v in parameter.volumeMounts.emptyDir { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + + hostPath: *[ + for v in parameter.volumeMounts.hostPath { + { + mountPath: v.mountPath + if v.subPath != _|_ { + subPath: v.subPath + } + name: v.name + } + }, + ] | [] + } + volumesArray: { + pvc: *[ + for v in parameter.volumeMounts.pvc { + { + name: v.name + persistentVolumeClaim: claimName: v.claimName + } + }, + ] | [] + + configMap: *[ + for v in parameter.volumeMounts.configMap { + { + name: v.name + configMap: { + defaultMode: v.defaultMode + name: v.cmName + if v.items != _|_ { + items: v.items + } + } + } + }, + ] | [] + + secret: *[ + for v in parameter.volumeMounts.secret { + { + name: v.name + secret: { + defaultMode: v.defaultMode + secretName: v.secretName + if v.items != _|_ { + items: v.items + } + } + } + }, + ] | [] + + emptyDir: *[ + for v in parameter.volumeMounts.emptyDir { + { + name: v.name + emptyDir: medium: v.medium + } + }, + ] | [] + + hostPath: *[ + for v in parameter.volumeMounts.hostPath { + { + name: v.name + hostPath: path: v.path + } + }, + ] | [] + } + volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath + deDupVolumesArray: [ + for val in [ + for i, vi in volumesList { + for j, vj in volumesList if j < i && vi.name == vj.name { + _ignore: true + } + vi + }, + ] if val._ignore == _|_ { + val + }, + ] output: { if context.clusterVersion.minor < 25 { apiVersion: "batch/v1beta1" @@ -85,15 +217,18 @@ template: { requests: memory: parameter.memory } } - if parameter["volumes"] != _|_ { + if parameter["volumes"] != _|_ if parameter["volumeMounts"] == _|_ { volumeMounts: [ for v in parameter.volumes { { mountPath: v.mountPath name: v.name }}] } + if parameter["volumeMounts"] != _|_ { + volumeMounts: mountsArray.pvc + mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir + mountsArray.hostPath + } }] - if parameter["volumes"] != _|_ { + if parameter["volumes"] != _|_ if parameter["volumeMounts"] == _|_ { volumes: [ for v in parameter.volumes { { name: v.name @@ -123,6 +258,9 @@ template: { } }}] } + if parameter["volumeMounts"] != _|_ { + volumes: deDupVolumesArray + } if parameter["imagePullSecrets"] != _|_ { imagePullSecrets: [ for v in parameter.imagePullSecrets { name: v @@ -219,7 +357,58 @@ template: { // +usage=Specifies the attributes of the memory resource required for the container. memory?: string - // +usage=Declare volumes and volumeMounts + volumeMounts?: { + // +usage=Mount PVC type volume + pvc?: [...{ + name: string + mountPath: string + subPath?: string + // +usage=The name of the PVC + claimName: string + }] + // +usage=Mount ConfigMap type volume + configMap?: [...{ + name: string + mountPath: string + subPath?: string + defaultMode: *420 | int + cmName: string + items?: [...{ + key: string + path: string + mode: *511 | int + }] + }] + // +usage=Mount Secret type volume + secret?: [...{ + name: string + mountPath: string + subPath?: string + defaultMode: *420 | int + secretName: string + items?: [...{ + key: string + path: string + mode: *511 | int + }] + }] + // +usage=Mount EmptyDir type volume + emptyDir?: [...{ + name: string + mountPath: string + subPath?: string + medium: *"" | "Memory" + }] + // +usage=Mount HostPath type volume + hostPath?: [...{ + name: string + mountPath: string + subPath?: string + path: string + }] + } + + // +usage=Deprecated field, use volumeMounts instead. volumes?: [...{ name: string mountPath: string diff --git a/vela-templates/definitions/internal/trait/annotations.cue b/vela-templates/definitions/internal/trait/annotations.cue index da2c3261b..0798430f6 100644 --- a/vela-templates/definitions/internal/trait/annotations.cue +++ b/vela-templates/definitions/internal/trait/annotations.cue @@ -1,7 +1,7 @@ annotations: { type: "trait" annotations: {} - description: "Add annotations on your workload. if it generates pod, add same annotations for generated pods." + description: "Add annotations on your workload. If it generates pod or job, add same annotations for generated pods." attributes: { podDisruptive: true appliesToWorkloads: ["*"] @@ -10,19 +10,23 @@ annotations: { template: { // +patchStrategy=jsonMergePatch patch: { - metadata: { - annotations: { - for k, v in parameter { - (k): v - } + let annotationsContent = { + for k, v in parameter { + (k): v } } - if context.output.spec != _|_ && context.output.spec.template != _|_ { - spec: template: metadata: annotations: { - for k, v in parameter { - (k): v - } - } + + metadata: { + annotations: annotationsContent + } + if context.output.spec != _|_ if context.output.spec.template != _|_ { + spec: template: metadata: annotations: annotationsContent + } + if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ { + spec: jobTemplate: metadata: annotations: annotationsContent + } + if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ if context.output.spec.jobTemplate.spec != _|_ if context.output.spec.jobTemplate.spec.template != _|_ { + spec: jobTemplate: spec: template: metadata: annotations: annotationsContent } } parameter: [string]: string | null diff --git a/vela-templates/definitions/internal/trait/resource.cue b/vela-templates/definitions/internal/trait/resource.cue index 25b61536a..7ebe0851c 100644 --- a/vela-templates/definitions/internal/trait/resource.cue +++ b/vela-templates/definitions/internal/trait/resource.cue @@ -4,43 +4,54 @@ resource: { description: "Add resource requests and limits on K8s pod for your workload which follows the pod spec in path 'spec.template.'" attributes: { podDisruptive: true - appliesToWorkloads: ["deployments.apps", "statefulsets.apps", "daemonsets.apps", "jobs.batch"] + appliesToWorkloads: ["deployments.apps", "statefulsets.apps", "daemonsets.apps", "jobs.batch", "cronjobs.batch"] } } template: { - patch: spec: template: spec: { - // +patchKey=name - containers: [{ - resources: { - if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ { - // +patchStrategy=retainKeys - requests: { - cpu: parameter.cpu - memory: parameter.memory - } - // +patchStrategy=retainKeys - limits: { - cpu: parameter.cpu - memory: parameter.memory - } - } - if parameter.requests != _|_ { - // +patchStrategy=retainKeys - requests: { - cpu: parameter.requests.cpu - memory: parameter.requests.memory - } + let resourceContent = { + resources: { + if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ { + // +patchStrategy=retainKeys + requests: { + cpu: parameter.cpu + memory: parameter.memory } - if parameter.limits != _|_ { - // +patchStrategy=retainKeys - limits: { - cpu: parameter.limits.cpu - memory: parameter.limits.memory - } + // +patchStrategy=retainKeys + limits: { + cpu: parameter.cpu + memory: parameter.memory } } - }] + + if parameter.requests != _|_ { + // +patchStrategy=retainKeys + requests: { + cpu: parameter.requests.cpu + memory: parameter.requests.memory + } + } + if parameter.limits != _|_ { + // +patchStrategy=retainKeys + limits: { + cpu: parameter.limits.cpu + memory: parameter.limits.memory + } + } + } + } + + if context.output.spec != _|_ if context.output.spec.template != _|_ { + patch: spec: template: spec: { + // +patchKey=name + containers: [resourceContent] + } + } + if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ { + patch: spec: jobTemplate: spec: template: spec: { + // +patchKey=name + containers: [resourceContent] + } } parameter: {