From 15df713909ce8b4b3f4145338a187d0a20b260a1 Mon Sep 17 00:00:00 2001 From: Zach Aller Date: Wed, 25 May 2022 14:54:11 -0500 Subject: [PATCH] feat: Ability for lint command to inspect referenced resources (#2030) Signed-off-by: zachaller --- .../validation/validation_references.go | 1 - pkg/kubectl-argo-rollouts/cmd/lint/lint.go | 259 +++++++++++++++--- .../cmd/lint/lint_test.go | 75 +++-- .../testdata/invalid-ingress-smi-multi.yml | 244 +++++++++++++++++ .../lint/testdata/invalid-nginx-canary.yml | 95 +++++++ .../cmd/lint/testdata/invalid-ping-pong.yml | 69 +++++ .../lint/testdata/invalid-service-labels.yml | 69 +++++ .../cmd/lint/testdata/invalid.json | 72 +++++ .../cmd/lint/testdata/valid-alb-canary.yml | 95 +++++++ .../cmd/lint/testdata/valid-blue-green.yml | 51 ++++ .../lint/testdata/valid-ingress-smi-multi.yml | 244 +++++++++++++++++ .../cmd/lint/testdata/valid-ingress-smi.yml | 115 ++++++++ .../lint/testdata/valid-istio-v1alpha3.yml | 88 ++++++ ...id-istio-v1beta1-mulitiple-virtualsvcs.yml | 110 ++++++++ .../cmd/lint/testdata/valid-istio-v1beta1.yml | 88 ++++++ .../cmd/lint/testdata/valid-nginx-canary.yml | 88 ++++++ .../cmd/lint/testdata/valid.json | 72 +++++ 17 files changed, 1773 insertions(+), 62 deletions(-) create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml create mode 100644 pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json diff --git a/pkg/apis/rollouts/validation/validation_references.go b/pkg/apis/rollouts/validation/validation_references.go index 5869b6ce7f..a4d5561f4a 100644 --- a/pkg/apis/rollouts/validation/validation_references.go +++ b/pkg/apis/rollouts/validation/validation_references.go @@ -105,7 +105,6 @@ func ValidateService(svc ServiceWithType, rollout *v1alpha1.Rollout) field.Error } if v, ok := rollout.Spec.Template.Labels[svcLabelKey]; !ok || v != svcLabelValue { msg := fmt.Sprintf("Service %q has unmatch lable %q in rollout", service.Name, svcLabelKey) - fmt.Println(msg) allErrs = append(allErrs, field.Invalid(fldPath, service.Name, msg)) } } diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go index 1c50a9650d..2969b53034 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint.go @@ -2,19 +2,23 @@ package lint import ( "bytes" - "encoding/json" + "fmt" "io" "io/ioutil" - "unicode" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1" "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/validation" "github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options" + ingressutil "github.com/argoproj/argo-rollouts/utils/ingress" "github.com/ghodss/yaml" "github.com/spf13/cobra" goyaml "gopkg.in/yaml.v2" + v1 "k8s.io/api/core/v1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/util/validation/field" ) type LintOptions struct { @@ -22,6 +26,11 @@ type LintOptions struct { File string } +type roAndReferences struct { + Rollout v1alpha1.Rollout + References validation.ReferencedResources +} + const ( lintExample = ` # Lint a rollout @@ -56,42 +65,10 @@ func NewCmdLint(o *options.ArgoRolloutsOptions) *cobra.Command { return cmd } -// isJSON detects if the byte array looks like json, based on the first non-whitespace character -func isJSON(fileBytes []byte) bool { - for _, b := range fileBytes { - if !unicode.IsSpace(rune(b)) { - return b == '{' - } - } - return false -} - func unmarshal(fileBytes []byte, obj interface{}) error { - if isJSON(fileBytes) { - decoder := json.NewDecoder(bytes.NewReader(fileBytes)) - decoder.DisallowUnknownFields() - return decoder.Decode(&obj) - } return yaml.UnmarshalStrict(fileBytes, &obj, yaml.DisallowUnknownFields) } -func validate(fileBytes []byte, un *unstructured.Unstructured) error { - gvk := un.GroupVersionKind() - switch { - case gvk.Group == rollouts.Group && gvk.Kind == rollouts.RolloutKind: - var ro v1alpha1.Rollout - err := unmarshal(fileBytes, &ro) - if err != nil { - return err - } - errs := validation.ValidateRollout(&ro) - if 0 < len(errs) { - return errs[0] - } - } - return nil -} - func (l *LintOptions) lintResource(path string) error { fileBytes, err := ioutil.ReadFile(path) if err != nil { @@ -99,13 +76,8 @@ func (l *LintOptions) lintResource(path string) error { } var un unstructured.Unstructured - - if isJSON(fileBytes) { - if err = unmarshal(fileBytes, un); err != nil { - return err - } - return validate(fileBytes, &un) - } + var refResource validation.ReferencedResources + var fileRollouts []v1alpha1.Rollout decoder := goyaml.NewDecoder(bytes.NewReader(fileBytes)) for { @@ -128,10 +100,213 @@ func (l *LintOptions) lintResource(path string) error { return err } - if err = validate(valueBytes, &un); err != nil { + gvk := un.GroupVersionKind() + if gvk.Group == rollouts.Group && gvk.Kind == rollouts.RolloutKind { + var ro v1alpha1.Rollout + err := unmarshal(valueBytes, &ro) + if err != nil { + return err + } + fileRollouts = append(fileRollouts, ro) + } + err = buildAllReferencedResources(un, &refResource) + if err != nil { return err } } + setServiceTypeAndManagedAnnotation(fileRollouts, refResource) + setIngressManagedAnnotation(fileRollouts, refResource) + setVirtualServiceManagedAnnotation(fileRollouts, refResource) + + var errList field.ErrorList + for _, rollout := range fileRollouts { + roRef := matchRolloutToReferences(rollout, refResource) + + errList = append(errList, validation.ValidateRollout(&roRef.Rollout)...) + errList = append(errList, validation.ValidateRolloutReferencedResources(&roRef.Rollout, roRef.References)...) + } + + for _, e := range errList { + fmt.Println(e.ErrorBody()) + } + if len(errList) > 0 { + return errList[0] + } else { + return nil + } +} + +// buildAllReferencedResources This builds a ReferencedResources object that has all the external resources for every +// rollout resource in the manifest. We will need to later match each referenced resource to its own rollout resource +// before passing the rollout object and its managed reference on to validation. +func buildAllReferencedResources(un unstructured.Unstructured, refResource *validation.ReferencedResources) error { + + valueBytes, err := un.MarshalJSON() + if err != nil { + return err + } + + gvk := un.GroupVersionKind() + switch { + case gvk.Group == v1.GroupName && gvk.Kind == "Service": + var svc v1.Service + err := unmarshal(valueBytes, &svc) + if err != nil { + return err + } + refResource.ServiceWithType = append(refResource.ServiceWithType, validation.ServiceWithType{ + Service: &svc, + }) + + case gvk.Group == "networking.istio.io" && gvk.Kind == "VirtualService": + refResource.VirtualServices = append(refResource.VirtualServices, un) + + case (gvk.Group == networkingv1.GroupName || gvk.Group == extensionsv1beta1.GroupName) && gvk.Kind == "Ingress": + var ing networkingv1.Ingress + var ingv1beta1 extensionsv1beta1.Ingress + if gvk.Version == "v1" { + err := unmarshal(valueBytes, &ing) + if err != nil { + return err + } + refResource.Ingresses = append(refResource.Ingresses, *ingressutil.NewIngress(&ing)) + } else if gvk.Version == "v1beta1" { + err := unmarshal(valueBytes, &ingv1beta1) + if err != nil { + return err + } + refResource.Ingresses = append(refResource.Ingresses, *ingressutil.NewLegacyIngress(&ingv1beta1)) + } + + } return nil } + +// matchRolloutToReferences This function goes through the global list of all ReferencedResources in the manifest and matches +// them up with their respective rollout object so that we can latter have a mapping of a single rollout object and its +// referenced resources. +func matchRolloutToReferences(rollout v1alpha1.Rollout, refResource validation.ReferencedResources) roAndReferences { + matchedReferenceResources := roAndReferences{Rollout: rollout, References: validation.ReferencedResources{}} + + for _, service := range refResource.ServiceWithType { + if service.Service.Annotations[v1alpha1.ManagedByRolloutsKey] == rollout.Name { + matchedReferenceResources.References.ServiceWithType = append(matchedReferenceResources.References.ServiceWithType, service) + } + } + for _, ingress := range refResource.Ingresses { + if ingress.GetAnnotations()[v1alpha1.ManagedByRolloutsKey] == rollout.Name { + matchedReferenceResources.References.Ingresses = append(matchedReferenceResources.References.Ingresses, ingress) + } + } + for _, virtualService := range refResource.VirtualServices { + if virtualService.GetAnnotations()[v1alpha1.ManagedByRolloutsKey] == rollout.Name { + matchedReferenceResources.References.VirtualServices = append(matchedReferenceResources.References.VirtualServices, virtualService) + } + } + + return matchedReferenceResources +} + +// setServiceTypeAndManagedAnnotation This sets the managed annotation on each service as well as figures out what +// type of service its is by looking at the rollout and set's its service type accordingly. +func setServiceTypeAndManagedAnnotation(rollouts []v1alpha1.Rollout, refResource validation.ReferencedResources) { + for _, rollout := range rollouts { + for i := range refResource.ServiceWithType { + + if refResource.ServiceWithType[i].Service.Annotations == nil { + refResource.ServiceWithType[i].Service.Annotations = make(map[string]string) + } + + if rollout.Spec.Strategy.Canary != nil { + if rollout.Spec.Strategy.Canary.CanaryService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.CanaryService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.Canary.StableService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.StableService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.Canary.PingPong != nil { + if rollout.Spec.Strategy.Canary.PingPong.PingService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.PingService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.Canary.PingPong.PongService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.PongService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + } + } + + if rollout.Spec.Strategy.BlueGreen != nil { + if rollout.Spec.Strategy.BlueGreen.ActiveService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.ActiveService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + if rollout.Spec.Strategy.BlueGreen.PreviewService == refResource.ServiceWithType[i].Service.Name { + refResource.ServiceWithType[i].Type = validation.PreviewService + refResource.ServiceWithType[i].Service.Annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + } + } + + } + } +} + +// setIngressManagedAnnotation This tries to find ingresses that have matching services in the rollout resource and if so +// it will add the managed by annotations just for linting so that we can later match up resources to a rollout resources +// for the case when we have multiple rollout resources in a single manifest. +func setIngressManagedAnnotation(rollouts []v1alpha1.Rollout, refResource validation.ReferencedResources) { + for _, rollout := range rollouts { + for i := range refResource.Ingresses { + var serviceName string + if rollout.Spec.Strategy.Canary.TrafficRouting.Nginx != nil { + serviceName = rollout.Spec.Strategy.Canary.StableService + } else if rollout.Spec.Strategy.Canary.TrafficRouting.ALB != nil { + serviceName = rollout.Spec.Strategy.Canary.StableService + if rollout.Spec.Strategy.Canary.TrafficRouting.ALB.RootService != "" { + serviceName = rollout.Spec.Strategy.Canary.TrafficRouting.ALB.RootService + } + } else if rollout.Spec.Strategy.Canary.TrafficRouting.SMI != nil { + serviceName = rollout.Spec.Strategy.Canary.TrafficRouting.SMI.RootService + } + + if ingressutil.HasRuleWithService(&refResource.Ingresses[i], serviceName) { + annotations := refResource.Ingresses[i].GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + refResource.Ingresses[i].SetAnnotations(annotations) + } + } + } +} + +// setVirtualServiceManagedAnnotation This function finds virtual services that are listed in the rollout resources and +// adds the ManagedByRolloutsKey to the annotations of the virtual services. +func setVirtualServiceManagedAnnotation(ro []v1alpha1.Rollout, refResource validation.ReferencedResources) { + for _, rollout := range ro { + for i := range refResource.VirtualServices { + if rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService != nil && rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualService.Name == refResource.VirtualServices[i].GetName() { + annotations := refResource.VirtualServices[i].GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + refResource.VirtualServices[i].SetAnnotations(annotations) + } + for _, virtualService := range rollout.Spec.Strategy.Canary.TrafficRouting.Istio.VirtualServices { + if virtualService.Name == refResource.VirtualServices[i].GetName() { + annotations := refResource.VirtualServices[i].GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[v1alpha1.ManagedByRolloutsKey] = rollout.Name + refResource.VirtualServices[i].SetAnnotations(annotations) + } + } + } + } +} diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go index 1780dbcc8b..554c4820db 100644 --- a/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go +++ b/pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go @@ -15,13 +15,30 @@ func TestLintValidRollout(t *testing.T) { cmd := NewCmdLint(o) cmd.PersistentPreRunE = o.PersistentPreRunE - for _, filename := range []string{"testdata/valid.yml", "testdata/valid-workload-ref.yaml", "testdata/valid-with-another-empty-object.yml"} { - cmd.SetArgs([]string{"-f", filename}) - err := cmd.Execute() - assert.NoError(t, err) + tests := []string{ + "testdata/valid.yml", + "testdata/valid.json", + "testdata/valid-workload-ref.yaml", + "testdata/valid-with-another-empty-object.yml", + "testdata/valid-istio-v1alpha3.yml", + "testdata/valid-istio-v1beta1.yml", + "testdata/valid-blue-green.yml", + "testdata/valid-ingress-smi.yml", + "testdata/valid-ingress-smi-multi.yml", + "testdata/valid-alb-canary.yml", + "testdata/valid-nginx-canary.yml", + "testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml", + } + + for _, filename := range tests { + t.Run(filename, func(t *testing.T) { + cmd.SetArgs([]string{"-f", filename}) + err := cmd.Execute() + assert.NoError(t, err) - stdout := o.Out.(*bytes.Buffer).String() - assert.Empty(t, stdout) + stdout := o.Out.(*bytes.Buffer).String() + assert.Empty(t, stdout) + }) } } @@ -32,36 +49,56 @@ func TestLintInvalidRollout(t *testing.T) { filename string errmsg string }{ - { "testdata/invalid.yml", "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", }, + { + "testdata/invalid.json", + "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", + }, { "testdata/invalid-multiple-docs.yml", "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", }, - { "testdata/invalid-unknown-field.yml", "Error: error unmarshaling JSON: while decoding JSON: json: unknown field \"unknown-strategy\"\n", }, + { + "testdata/invalid-service-labels.yml", + "Error: spec.strategy.canary.canaryService: Invalid value: \"istio-host-split-canary\": Service \"istio-host-split-canary\" has unmatch lable \"app\" in rollout\n", + }, + { + "testdata/invalid-ping-pong.yml", + "Error: spec.strategy.canary.pingPong.pingService: Invalid value: \"ping-service\": Service \"ping-service\" has unmatch lable \"app\" in rollout\n", + }, + { + "testdata/invalid-ingress-smi-multi.yml", + "Error: spec.strategy.canary.canaryService: Invalid value: \"rollout-smi-experiment-canary\": Service \"rollout-smi-experiment-canary\" has unmatch lable \"app\" in rollout\n", + }, + { + filename: "testdata/invalid-nginx-canary.yml", + errmsg: "Error: spec.strategy.steps[1].experiment.templates[0].weight: Invalid value: 20: Experiment template weight is only available for TrafficRouting with SMI, ALB, and Istio at this time\n", + }, } runCmd = func(filename string, errmsg string) { - tf, o := options.NewFakeArgoRolloutsOptions() - defer tf.Cleanup() + t.Run(filename, func(t *testing.T) { + tf, o := options.NewFakeArgoRolloutsOptions() + defer tf.Cleanup() - cmd := NewCmdLint(o) - cmd.PersistentPreRunE = o.PersistentPreRunE - cmd.SetArgs([]string{"-f", filename}) - err := cmd.Execute() - assert.Error(t, err) + cmd := NewCmdLint(o) + cmd.PersistentPreRunE = o.PersistentPreRunE + cmd.SetArgs([]string{"-f", filename}) + err := cmd.Execute() + assert.Error(t, err) - stdout := o.Out.(*bytes.Buffer).String() - stderr := o.ErrOut.(*bytes.Buffer).String() - assert.Empty(t, stdout) - assert.Equal(t, errmsg, stderr) + stdout := o.Out.(*bytes.Buffer).String() + stderr := o.ErrOut.(*bytes.Buffer).String() + assert.Empty(t, stdout) + assert.Equal(t, errmsg, stderr) + }) } for _, t := range tests { diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml new file mode 100644 index 0000000000..fc04b8deb7 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ingress-smi-multi.yml @@ -0,0 +1,244 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-miss +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-miss +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-miss +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split +spec: + service: rollout-smi-experiment-root + backends: + - service: rollout-smi-experiment-stable + weight: 95 + - service: rollout-smi-experiment-canary + weight: 5 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-stable + servicePort: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-root + servicePort: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary + stableService: rollout-smi-experiment-stable + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment + template: + metadata: + labels: + app: rollout-smi-experiment + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + + + + + +--- + + + + +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split-1 +spec: + service: rollout-smi-experiment-root-1 + backends: + - service: rollout-smi-experiment-stable-1 + weight: 95 + - service: rollout-smi-experiment-canary-1 + weight: 5 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable-1 + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-stable-1 + port: + number: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-root-1 + port: + number: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment-1 +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary-1 + stableService: rollout-smi-experiment-stable-1 + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split-1 + rootService: rollout-smi-experiment-root-1 + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment-1 + template: + metadata: + labels: + app: rollout-smi-experiment-1 + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml new file mode 100644 index 0000000000..ec90d8ad2d --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-nginx-canary.yml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: nginx-rollout-ingress + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: nginx-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: nginx-rollout +spec: + selector: + matchLabels: + app: nginx-rollout + template: + metadata: + labels: + app: nginx-rollout + spec: + containers: + - name: nginx-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: nginx-rollout-canary + stableService: nginx-rollout-stable + trafficRouting: + nginx: + stableIngress: nginx-rollout-ingress + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-nginx + specRef: canary + weight: 20 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml new file mode 100644 index 0000000000..a0c908dce8 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-ping-pong.yml @@ -0,0 +1,69 @@ +# Miss matched labels on service +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: invalid-rollout +spec: + revisionHistoryLimit: 1 + replicas: 10 + strategy: + canary: + pingPong: #Indicates that the ping-pong services enabled + pingService: ping-service + pongService: pong-service + maxUnavailable: 0 + maxSurge: 1 + analysis: + templates: + - templateName: integrationtests + steps: + - setWeight: 10 + - setWeight: 20 + - setWeight: 40 + - setWeight: 80 + selector: + matchLabels: + app: invalid-rollout + template: + metadata: + labels: + app: invalid-rollout + spec: + containers: + - name: invalid-rollout + image: invalid-rollout:0.0.0 + ports: + - name: http + containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /ping + port: 8080 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: ping-service +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: invalid-rollout-miss-match +--- +apiVersion: v1 +kind: Service +metadata: + name: pong-service +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: invalid-rollout-miss-match \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml new file mode 100644 index 0000000000..705597f927 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid-service-labels.yml @@ -0,0 +1,69 @@ +# Miss matched labels on service +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: invalid-rollout +spec: + revisionHistoryLimit: 1 + replicas: 10 + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + maxUnavailable: 0 + maxSurge: 1 + analysis: + templates: + - templateName: integrationtests + steps: + - setWeight: 10 + - setWeight: 20 + - setWeight: 40 + - setWeight: 80 + selector: + matchLabels: + app: invalid-rollout + template: + metadata: + labels: + app: invalid-rollout + spec: + containers: + - name: invalid-rollout + image: invalid-rollout:0.0.0 + ports: + - name: http + containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: /ping + port: 8080 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json new file mode 100644 index 0000000000..09fbae6451 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/invalid.json @@ -0,0 +1,72 @@ +{ + "apiVersion": "argoproj.io/v1alpha1", + "kind": "Rollout", + "metadata": { + "name": "invalid-rollout" + }, + "spec": { + "revisionHistoryLimit": 1, + "replicas": 1, + "strategy": { + "canary": { + "maxUnavailable": 0, + "maxSurge": 0, + "analysis": { + "templates": [ + { + "templateName": "integrationtests" + } + ] + }, + "steps": [ + { + "setWeight": 10 + }, + { + "setWeight": 20 + }, + { + "setWeight": 40 + }, + { + "setWeight": 80 + } + ] + } + }, + "selector": { + "matchLabels": { + "app": "invalid-rollout" + } + }, + "template": { + "metadata": { + "labels": { + "app": "invalid-rollout" + } + }, + "spec": { + "containers": [ + { + "name": "invalid-rollout", + "image": "invalid-rollout:0.0.0", + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + } + ], + "readinessProbe": { + "httpGet": { + "path": "/ping", + "port": 8080 + }, + "periodSeconds": 5 + } + } + ] + } + } + } +} diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml new file mode 100644 index 0000000000..c0b2131c74 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-alb-canary.yml @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: alb-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: alb-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: alb-rollout-ingress +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: alb-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: alb-rollout +spec: + selector: + matchLabels: + app: alb-rollout + template: + metadata: + labels: + app: alb-rollout + spec: + containers: + - name: alb-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: alb-rollout-canary + stableService: alb-rollout-stable + trafficRouting: + alb: + ingress: alb-rollout-ingress + rootService: alb-rollout-root + servicePort: 80 + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-alb + specRef: canary + weight: 20 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml new file mode 100644 index 0000000000..ad93ae1c5e --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-blue-green.yml @@ -0,0 +1,51 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-bluegreen +spec: + replicas: 2 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-bluegreen + template: + metadata: + labels: + app: rollout-bluegreen + spec: + containers: + - name: rollouts-demo + image: argoproj/rollouts-demo:blue + imagePullPolicy: Always + ports: + - containerPort: 8080 + strategy: + blueGreen: + activeService: rollout-bluegreen-active + previewService: rollout-bluegreen-preview + autoPromotionEnabled: false +--- +kind: Service +apiVersion: v1 +metadata: + name: rollout-bluegreen-active +spec: + selector: + app: rollout-bluegreen + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + +--- +kind: Service +apiVersion: v1 +metadata: + name: rollout-bluegreen-preview +spec: + selector: + app: rollout-bluegreen + ports: + - protocol: TCP + port: 80 + targetPort: 8080 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml new file mode 100644 index 0000000000..884eebf406 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi-multi.yml @@ -0,0 +1,244 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split +spec: + service: rollout-smi-experiment-root + backends: + - service: rollout-smi-experiment-stable + weight: 95 + - service: rollout-smi-experiment-canary + weight: 5 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-stable + servicePort: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-root + servicePort: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary + stableService: rollout-smi-experiment-stable + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment + template: + metadata: + labels: + app: rollout-smi-experiment + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + + + + + +--- + + + + +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root-1 +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment-1 +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split-1 +spec: + service: rollout-smi-experiment-root-1 + backends: + - service: rollout-smi-experiment-stable-1 + weight: 95 + - service: rollout-smi-experiment-canary-1 + weight: 5 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable-1 + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-stable-1 + port: + number: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + service: + name: rollout-smi-experiment-root-1 + port: + number: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment-1 +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary-1 + stableService: rollout-smi-experiment-stable-1 + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split-1 + rootService: rollout-smi-experiment-root-1 + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment-1 + template: + metadata: + labels: + app: rollout-smi-experiment-1 + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml new file mode 100644 index 0000000000..63f9e6cddf --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-ingress-smi.yml @@ -0,0 +1,115 @@ +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: v1 +kind: Service +metadata: + name: rollout-smi-experiment-root +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: rollout-smi-experiment +--- +apiVersion: split.smi-spec.io/v1alpha1 +kind: TrafficSplit +metadata: + name: rollout-smi-experiment-split +spec: + service: rollout-smi-experiment-root + backends: + - service: rollout-smi-experiment-stable + weight: 95 + - service: rollout-smi-experiment-canary + weight: 5 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: rollout-smi-experiment-stable + annotations: + kubernetes.io/ingress.class: nginx +spec: + rules: + - host: rollout-smi-experiment.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-stable + servicePort: 80 + - host: rollout-smi-experiment-root.local + http: + paths: + - path: / + backend: + serviceName: rollout-smi-experiment-root + servicePort: 80 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: rollout-smi-experiment +spec: + replicas: 1 + strategy: + canary: + canaryService: rollout-smi-experiment-canary + stableService: rollout-smi-experiment-stable + trafficRouting: + smi: + trafficSplitName: rollout-smi-experiment-split + rootService: rollout-smi-experiment-root + steps: + - setWeight: 5 + - experiment: + templates: + - name: experiment-smi + specRef: canary + weight: 5 + revisionHistoryLimit: 2 + selector: + matchLabels: + app: rollout-smi-experiment + template: + metadata: + labels: + app: rollout-smi-experiment + spec: + containers: + - name: rollout-smi-experiment + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml new file mode 100644 index 0000000000..1de296d451 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1alpha3.yml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-istio + specRef: canary + weight: 20 + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:red + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml new file mode 100644 index 0000000000..346de2e287 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1-mulitiple-virtualsvcs.yml @@ -0,0 +1,110 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: istio-host-split-vsvc-1 +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualServices: + - name: istio-host-split-vsvc + routes: + - primary + - name: istio-host-split-vsvc-1 + routes: + - primary + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-istio + specRef: canary + weight: 20 + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:red + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml new file mode 100644 index 0000000000..d793401a9f --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-istio-v1beta1.yml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-canary +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-host-split-stable +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: istio-host-split + +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: istio-host-split-vsvc +spec: + hosts: + - istio-host-split.com + gateways: + - istio-host-split-gateway + http: + - name: primary + route: + - destination: + host: istio-host-split-stable + weight: 100 + - destination: + host: istio-host-split-canary + weight: 0 +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: istio-host-split +spec: + strategy: + canary: + canaryService: istio-host-split-canary + stableService: istio-host-split-stable + trafficRouting: + istio: + virtualService: + name: istio-host-split-vsvc + routes: + - primary + steps: + - setWeight: 10 + - experiment: + templates: + - name: experiment-istio + specRef: canary + weight: 20 + selector: + matchLabels: + app: istio-host-split + template: + metadata: + labels: + app: istio-host-split + spec: + containers: + - name: istio-host-split + image: argoproj/rollouts-demo:red + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m \ No newline at end of file diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml new file mode 100644 index 0000000000..30fe00ca12 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid-nginx-canary.yml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-root +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-canary +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-rollout-stable +spec: + type: NodePort + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: nginx-rollout +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: nginx-rollout-ingress +spec: + rules: + - http: + paths: + - path: /* + backend: + serviceName: nginx-rollout-root + servicePort: use-annotation +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: nginx-rollout +spec: + selector: + matchLabels: + app: nginx-rollout + template: + metadata: + labels: + app: nginx-rollout + spec: + containers: + - name: nginx-rollout + image: argoproj/rollouts-demo:blue + ports: + - name: http + containerPort: 80 + protocol: TCP + resources: + requests: + memory: 16Mi + cpu: 5m + strategy: + canary: + canaryService: nginx-rollout-canary + stableService: nginx-rollout-stable + trafficRouting: + nginx: + stableIngress: nginx-rollout-ingress + steps: + - setWeight: 10 diff --git a/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json new file mode 100644 index 0000000000..df85628af7 --- /dev/null +++ b/pkg/kubectl-argo-rollouts/cmd/lint/testdata/valid.json @@ -0,0 +1,72 @@ +{ + "apiVersion": "argoproj.io/v1alpha1", + "kind": "Rollout", + "metadata": { + "name": "valid-rollout" + }, + "spec": { + "revisionHistoryLimit": 1, + "replicas": 10, + "strategy": { + "canary": { + "maxUnavailable": 0, + "maxSurge": 1, + "analysis": { + "templates": [ + { + "templateName": "integrationtests" + } + ] + }, + "steps": [ + { + "setWeight": 10 + }, + { + "setWeight": 20 + }, + { + "setWeight": 40 + }, + { + "setWeight": 80 + } + ] + } + }, + "selector": { + "matchLabels": { + "app": "valid-rollout" + } + }, + "template": { + "metadata": { + "labels": { + "app": "valid-rollout" + } + }, + "spec": { + "containers": [ + { + "name": "valid-rollout", + "image": "valid-rollout:0.0.0", + "ports": [ + { + "name": "http", + "containerPort": 8080, + "protocol": "TCP" + } + ], + "readinessProbe": { + "httpGet": { + "path": "/ping", + "port": 8080 + }, + "periodSeconds": 5 + } + } + ] + } + } + } +}