Skip to content

Commit

Permalink
Add ability to pass pod annotations and labels at the template level (a…
Browse files Browse the repository at this point in the history
…rgoproj#798)

* Add ability to pass pod annotations and labels at the template level

**What**
- Add ability to set `template.metadata.annotations` and `template.metadata.labels` as pod metadata

**Why**
Labels are helpful when searching for k8s resources.

Annotations are another type of metadata k8s supports. They can be used by various tools like [kube2iam](https://github.com/jtblin/kube2iam).

**Testing**
Add metadata to templates. Submit job. Test annotations and labels were added with `kubectl describe pod <pod-name>`. See `examples/pod-metadata.yaml`.

* Fix broken json tags

* Update codegen

* Update generated files
  • Loading branch information
Lukasz Lempart authored and alexmt committed Mar 19, 2018
1 parent d8be028 commit 3b2c426
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 1 deletion.
21 changes: 21 additions & 0 deletions api/openapi-spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,23 @@
"type": "string",
"format": "item"
},
"io.argoproj.workflow.v1alpha1.Metadata": {
"description": "Pod metdata",
"properties": {
"annotations": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"labels": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"io.argoproj.workflow.v1alpha1.Outputs": {
"description": "Outputs hold parameters, artifacts, and results from a step",
"properties": {
Expand Down Expand Up @@ -700,6 +717,10 @@
"description": "Inputs describe what inputs parameters and artifacts are supplied to this template",
"$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Inputs"
},
"metadata": {
"description": "Metdata sets the pods's metadata, i.e. annotations and labels",
"$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Metadata"
},
"name": {
"description": "Name is the name of the template",
"type": "string"
Expand Down
32 changes: 32 additions & 0 deletions examples/pod-metadata.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This template demonstrates a how pod annotations and labels may be set at the template level
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: steps-
spec:
entrypoint: hello-hello-hello

templates:
- name: hello-hello-hello
steps:
- - name: hello1
template: whalesay
arguments:
parameters:
- name: message
value: "hello1"

- name: whalesay
inputs:
parameters:
- name: message
container:
image: docker/whalesay
command: [cowsay]
args: ["{{inputs.parameters.message}}"]
metadata:
annotations:
iam.amazonaws.com/role: role-arn
labels:
app: whalesay
tier: demo
44 changes: 43 additions & 1 deletion pkg/apis/workflow/v1alpha1/openapi_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,42 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
},
},
},
"github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Metadata": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Pod metdata",
Properties: map[string]spec.Schema{
"annotations": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "",
},
},
},
},
},
"labels": {
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &spec.SchemaOrBool{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "",
},
},
},
},
},
},
},
},
Dependencies: []string{},
},
"github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Outputs": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Expand Down Expand Up @@ -1185,6 +1221,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
Ref: ref("k8s.io/api/core/v1.Affinity"),
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Description: "Metdata sets the pods's metadata, i.e. annotations and labels",
Ref: ref("github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Metadata"),
},
},
"daemon": {
SchemaProps: spec.SchemaProps{
Description: "Deamon will allow a workflow to proceed to the next step so long as the container reaches readiness",
Expand Down Expand Up @@ -1299,7 +1341,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
},
},
Dependencies: []string{
"github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ArtifactLocation", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.DAGTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Inputs", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Outputs", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ResourceTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.RetryStrategy", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ScriptTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Sidecar", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.SuspendTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.WorkflowStep", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.Container", "k8s.io/api/core/v1.Toleration"},
"github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ArtifactLocation", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.DAGTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Inputs", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Metadata", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Outputs", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ResourceTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.RetryStrategy", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ScriptTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Sidecar", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.SuspendTemplate", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.WorkflowStep", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.Container", "k8s.io/api/core/v1.Toleration"},
},
"github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ValueFrom": {
Schema: spec.Schema{
Expand Down
9 changes: 9 additions & 0 deletions pkg/apis/workflow/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ type Template struct {
// Overrides the affinity set at the workflow level (if any)
Affinity *apiv1.Affinity `json:"affinity,omitempty"`

// Metdata sets the pods's metadata, i.e. annotations and labels
Metadata Metadata `json:"metadata,omitempty"`

// Deamon will allow a workflow to proceed to the next step so long as the container reaches readiness
Daemon *bool `json:"daemon,omitempty"`

Expand Down Expand Up @@ -197,6 +200,12 @@ type Inputs struct {
Artifacts []Artifact `json:"artifacts,omitempty"`
}

// Pod metdata
type Metadata struct {
Annotations map[string]string `json:"annotations,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}

// Parameter indicate a passed string parameter to a service template with an optional default value
type Parameter struct {
// Name is the parameter name
Expand Down
31 changes: 31 additions & 0 deletions pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,36 @@ func (in *Item) DeepCopy() *Item {
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Metadata) DeepCopyInto(out *Metadata) {
*out = *in
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
return
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metadata.
func (in *Metadata) DeepCopy() *Metadata {
if in == nil {
return nil
}
out := new(Metadata)
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeStatus) DeepCopyInto(out *NodeStatus) {
*out = *in
Expand Down Expand Up @@ -630,6 +660,7 @@ func (in *Template) DeepCopyInto(out *Template) {
(*in).DeepCopyInto(*out)
}
}
in.Metadata.DeepCopyInto(&out.Metadata)
if in.Daemon != nil {
in, out := &in.Daemon, &out.Daemon
if *in == nil {
Expand Down
7 changes: 7 additions & 0 deletions workflow/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ spec:
entrypoint: whalesay
templates:
- name: whalesay
metadata:
annotations:
annotationKey1: "annotationValue1"
annotationKey2: "annotationValue2"
labels:
labelKey1: "labelValue1"
labelKey2: "labelValue2"
container:
image: docker/whalesay:latest
command: [cowsay]
Expand Down
12 changes: 12 additions & 0 deletions workflow/controller/workflowpod.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ func (woc *wfOperationCtx) createWorkflowPod(nodeName string, mainCtr apiv1.Cont
}

addSchedulingConstraints(&pod, wfSpec, tmpl)
addMetadata(&pod, tmpl)

err = addVolumeReferences(&pod, wfSpec, tmpl, woc.wf.Status.PersistentVolumeClaims)
if err != nil {
Expand Down Expand Up @@ -278,6 +279,17 @@ func (woc *wfOperationCtx) newExecContainer(name string, privileged bool) *apiv1
return &exec
}

// addMetadata applies metadata specified in the template
func addMetadata(pod *apiv1.Pod, tmpl *wfv1.Template) {
for k, v := range tmpl.Metadata.Annotations {
pod.ObjectMeta.Annotations[k] = v
}

for k, v := range tmpl.Metadata.Labels {
pod.ObjectMeta.Labels[k] = v
}
}

// addSchedulingConstraints applies any node selectors or affinity rules to the pod, either set in the workflow or the template
func addSchedulingConstraints(pod *apiv1.Pod, wfSpec *wfv1.WorkflowSpec, tmpl *wfv1.Template) {
// Set nodeSelector (if specified)
Expand Down
19 changes: 19 additions & 0 deletions workflow/controller/workflowpod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,22 @@ func TestTolerations(t *testing.T) {
assert.NotNil(t, pod.Spec.Tolerations)
assert.Equal(t, pod.Spec.Tolerations[0].Key, "nvidia.com/gpu")
}

// TestMetadata verifies ability to carry forward annotations and labels
func TestMetadata(t *testing.T) {
woc := newWoc()
woc.executeContainer(woc.wf.Spec.Entrypoint, &woc.wf.Spec.Templates[0], "")
podName := getPodName(woc.wf)
pod, err := woc.controller.kubeclientset.CoreV1().Pods("").Get(podName, metav1.GetOptions{})

assert.Nil(t, err)
assert.NotNil(t, pod.ObjectMeta)
assert.NotNil(t, pod.ObjectMeta.Annotations)
assert.NotNil(t, pod.ObjectMeta.Labels)
for k, v := range woc.wf.Spec.Templates[0].Metadata.Annotations {
assert.Equal(t, pod.ObjectMeta.Annotations[k], v)
}
for k, v := range woc.wf.Spec.Templates[0].Metadata.Labels {
assert.Equal(t, pod.ObjectMeta.Labels[k], v)
}
}

0 comments on commit 3b2c426

Please sign in to comment.