Repository: argoproj/argo (go)

Issue:
CronWorkflow does not work with controller-instanceid
Checklist:

 * [x] I've included the version.
 * [x] I've included reproduction steps.
 * [x] I've included the workflow YAML.
 * [x] I've included the logs.
 
**What happened**:
The workflow controller panic when starting cron workflow with label `workflows.argoproj.io/controller-instanceid` since `2.7.0`

**What you expected to happen**:
The Workflow should run

**How to reproduce it (as minimally and precisely as possible)**:
Add the following `CronWorkflow`

```
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
  name: hello-world
  labels:
    workflows.argoproj.io/controller-instanceid: test-controller
spec:
  schedule: "* * * * *"
  workflowMetadata:
    labels:
      label1: value1
    annotations:
      annotation2: value2
  workflowSpec:
    entrypoint: whalesay
    templates:
      - name: whalesay
        container:
          image: docker/whalesay:latest
          command: [cowsay]
          args: ["hello world"]
```
**Anything else we need to know?**:

**Environment**:
- Argo version: 2.7.0
```
argo: v2.7.0
  BuildDate: 2020-03-31T23:35:04Z
  GitCommit: 4d1175eb68f6578ed5d599f877be9b4855d33ce9
  GitTreeState: clean
  GitTag: v2.7.0
  GoVersion: go1.13.4
  Compiler: gc
  Platform: linux/amd64
```
- Kubernetes version :
```
serverVersion:
  buildDate: "2020-01-31T20:00:26Z"
  compiler: gc
  gitCommit: c52f59bbba5fbf21fbb18e9a06f96e563fe4c20a
  gitTreeState: clean
  gitVersion: v1.14.8
  goVersion: go1.12.10
  major: "1"
  minor: "14"
  platform: linux/amd64
```

**Other debugging information (if applicable)**:
- workflow-controller logs:
```
time="2020-04-06T08:35:00Z" level=info msg="Running hello-world"
panic: assignment to entry in nil map

goroutine 495 [running]:
github.com/argoproj/argo/workflow/common.toWorkflow(...)
        /go/src/github.com/argoproj/argo/workflow/common/convert.go:56
github.com/argoproj/argo/workflow/common.ConvertCronWorkflowToWorkflow(0xc0009f6380, 0x1)
        /go/src/github.com/argoproj/argo/workflow/common/convert.go:11 +0x8b0
github.com/argoproj/argo/workflow/cron.(*cronWfOperationCtx).Run(0xc000dbcf00)
        /go/src/github.com/argoproj/argo/workflow/cron/operator.go:59 +0x229
github.com/robfig/cron/v3.(*Cron).startJob.func1(0xc0000b8dc0, 0x1a5a5e0, 0xc000dbcf00)
        /go/pkg/mod/github.com/robfig/cron/v3@v3.0.1/cron.go:312 +0x69
created by github.com/robfig/cron/v3.(*Cron).startJob
        /go/pkg/mod/github.com/robfig/cron/v3@v3.0.1/cron.go:310 +0x73
```

**Logs**

```
time="2020-04-06T08:35:00Z" level=info msg="Running hello-world"
panic: assignment to entry in nil map

goroutine 495 [running]:
github.com/argoproj/argo/workflow/common.toWorkflow(...)
        /go/src/github.com/argoproj/argo/workflow/common/convert.go:56
github.com/argoproj/argo/workflow/common.ConvertCronWorkflowToWorkflow(0xc0009f6380, 0x1)
        /go/src/github.com/argoproj/argo/workflow/common/convert.go:11 +0x8b0
github.com/argoproj/argo/workflow/cron.(*cronWfOperationCtx).Run(0xc000dbcf00)
        /go/src/github.com/argoproj/argo/workflow/cron/operator.go:59 +0x229
github.com/robfig/cron/v3.(*Cron).startJob.func1(0xc0000b8dc0, 0x1a5a5e0, 0xc000dbcf00)
        /go/pkg/mod/github.com/robfig/cron/v3@v3.0.1/cron.go:312 +0x69
created by github.com/robfig/cron/v3.(*Cron).startJob
        /go/pkg/mod/github.com/robfig/cron/v3@v3.0.1/cron.go:310 +0x73
```

---
<!-- Issue Author: Don't delete this message to ecourage other users to support your issue! -->
**Message from the maintainers**:

If you are impacted by this bug please add a 👍 reaction to this issue! We often sort issues this way to know what to prioritize.


Pull request:
fix: Fixes panic in toWorkflow method
Fixes #2599

Patch:
diff --git a/workflow/common/convert.go b/workflow/common/convert.go
index 68161507b..8ff9bead3 100644
--- a/workflow/common/convert.go
+++ b/workflow/common/convert.go
@@ -9,10 +9,6 @@ import (
 
 func ConvertCronWorkflowToWorkflow(cronWf *wfv1.CronWorkflow) *wfv1.Workflow {
 	wf := toWorkflow(cronWf.TypeMeta, cronWf.ObjectMeta, cronWf.Spec.WorkflowSpec)
-	wfLabel := wf.ObjectMeta.GetLabels()
-	if wfLabel == nil {
-		wf.Labels = make(map[string]string)
-	}
 	wf.Labels[LabelKeyCronWorkflow] = cronWf.Name
 	if cronWf.Spec.WorkflowMetadata != nil {
 		for key, label := range cronWf.Spec.WorkflowMetadata.Labels {
@@ -32,20 +28,12 @@ func ConvertCronWorkflowToWorkflow(cronWf *wfv1.CronWorkflow) *wfv1.Workflow {
 
 func ConvertWorkflowTemplateToWorkflow(template *wfv1.WorkflowTemplate) *wfv1.Workflow {
 	wf := toWorkflow(template.TypeMeta, template.ObjectMeta, template.Spec.WorkflowSpec)
-	wfLabel := wf.ObjectMeta.GetLabels()
-	if wfLabel == nil {
-		wf.Labels = make(map[string]string)
-	}
 	wf.Labels[LabelKeyWorkflowTemplate] = template.ObjectMeta.Name
 	return wf
 }
 
 func ConvertClusterWorkflowTemplateToWorkflow(template *wfv1.ClusterWorkflowTemplate) *wfv1.Workflow {
 	wf := toWorkflow(template.TypeMeta, template.ObjectMeta, template.Spec.WorkflowSpec)
-	wfLabel := wf.ObjectMeta.GetLabels()
-	if wfLabel == nil {
-		wf.Labels = make(map[string]string)
-	}
 	wf.Labels[LabelKeyClusterWorkflowTemplate] = template.ObjectMeta.Name
 
 	return wf
@@ -59,6 +47,8 @@ func toWorkflow(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectMeta, spec wfv
 		},
 		ObjectMeta: metav1.ObjectMeta{
 			GenerateName: objectMeta.GetName() + "-",
+			Labels:       make(map[string]string),
+			Annotations:  make(map[string]string),
 		},
 		Spec: spec,
 	}
@@ -66,5 +56,6 @@ func toWorkflow(typeMeta metav1.TypeMeta, objectMeta metav1.ObjectMeta, spec wfv
 	if instanceId, ok := objectMeta.GetLabels()[LabelKeyControllerInstanceID]; ok {
 		wf.ObjectMeta.GetLabels()[LabelKeyControllerInstanceID] = instanceId
 	}
+
 	return wf
 }


Test patch:
diff --git a/workflow/common/convert_test.go b/workflow/common/convert_test.go
index 23214b0fc..75c3db481 100644
--- a/workflow/common/convert_test.go
+++ b/workflow/common/convert_test.go
@@ -1,7 +1,6 @@
 package common
 
 import (
-	"fmt"
 	"testing"
 
 	"github.com/ghodss/yaml"
@@ -73,11 +72,40 @@ status:
 	var cronWf v1alpha1.CronWorkflow
 	err := yaml.Unmarshal([]byte(cronWfString), &cronWf)
 	assert.NoError(t, err)
-	fmt.Println(cronWf)
 	wf := ConvertCronWorkflowToWorkflow(&cronWf)
 	wfString, err := yaml.Marshal(wf)
 	assert.NoError(t, err)
 	assert.Equal(t, expectedWf, string(wfString))
+
+	cronWfInstanceIdString := `apiVersion: argoproj.io/v1alpha1
+kind: CronWorkflow
+metadata:
+  name: hello-world
+  labels:
+    workflows.argoproj.io/controller-instanceid: test-controller
+spec:
+  schedule: "* * * * *"
+  workflowMetadata:
+    labels:
+      label1: value1
+    annotations:
+      annotation2: value2
+  workflowSpec:
+    entrypoint: whalesay
+    templates:
+      - name: whalesay
+        container:
+          image: docker/whalesay:latest
+          command: [cowsay]
+          args: ["hello world"]
+`
+
+	err = yaml.Unmarshal([]byte(cronWfInstanceIdString), &cronWf)
+	assert.NoError(t, err)
+	wf = ConvertCronWorkflowToWorkflow(&cronWf)
+	if assert.Contains(t, wf.GetLabels(), LabelKeyControllerInstanceID) {
+		assert.Equal(t, wf.GetLabels()[LabelKeyControllerInstanceID], "test-controller")
+	}
 }
 
 const workflowTmpl = `