Skip to content

Commit

Permalink
feat: lint supporting rollout in multiple doc (#1176)
Browse files Browse the repository at this point in the history
- To support use cases where the yaml file may contain
  deploy, service, etc (generated from helm template)

Signed-off-by: Hui Kang <[email protected]>
  • Loading branch information
huikang authored May 14, 2021
1 parent 584c13f commit 6ba30ed
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 22 deletions.
56 changes: 45 additions & 11 deletions pkg/kubectl-argo-rollouts/cmd/lint/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package lint
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"unicode"

Expand All @@ -12,6 +13,7 @@ import (
"github.com/argoproj/argo-rollouts/pkg/kubectl-argo-rollouts/options"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
goyaml "gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

Expand Down Expand Up @@ -73,21 +75,12 @@ func unmarshal(fileBytes []byte, obj interface{}) error {
return yaml.UnmarshalStrict(fileBytes, &obj, yaml.DisallowUnknownFields)
}

func (l *LintOptions) lintResource(path string) error {
fileBytes, err := ioutil.ReadFile(path)
if err != nil {
return err
}
var un unstructured.Unstructured
err = unmarshal(fileBytes, &un)
if err != nil {
return err
}
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)
err := unmarshal(fileBytes, &ro)
if err != nil {
return err
}
Expand All @@ -98,3 +91,44 @@ func (l *LintOptions) lintResource(path string) error {
}
return nil
}

func (l *LintOptions) lintResource(path string) error {
fileBytes, err := ioutil.ReadFile(path)
if err != nil {
return err
}

var un unstructured.Unstructured

if isJSON(fileBytes) {
if err = unmarshal(fileBytes, un); err != nil {
return err
}
return validate(fileBytes, &un)
}

decoder := goyaml.NewDecoder(bytes.NewReader(fileBytes))
for {
var value interface{}
if err := decoder.Decode(&value); err != nil {
if err != io.EOF {
return err
}
break
}
valueBytes, err := goyaml.Marshal(value)
if err != nil {
return err
}

if err = yaml.UnmarshalStrict(valueBytes, &un, yaml.DisallowUnknownFields); err != nil {
return err
}

if err = validate(valueBytes, &un); err != nil {
return err
}
}

return nil
}
50 changes: 39 additions & 11 deletions pkg/kubectl-argo-rollouts/cmd/lint/lint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,45 @@ func TestLintValidRollout(t *testing.T) {
}

func TestLintInvalidRollout(t *testing.T) {
tf, o := options.NewFakeArgoRolloutsOptions()
defer tf.Cleanup()
var runCmd func(string, string)

cmd := NewCmdLint(o)
cmd.PersistentPreRunE = o.PersistentPreRunE
cmd.SetArgs([]string{"-f", "testdata/invalid.yml"})
err := cmd.Execute()
assert.Error(t, err)
tests := []struct {
filename string
errmsg string
}{

stdout := o.Out.(*bytes.Buffer).String()
stderr := o.ErrOut.(*bytes.Buffer).String()
assert.Empty(t, stdout)
assert.Equal(t, "Error: spec.strategy.maxSurge: Invalid value: intstr.IntOrString{Type:0, IntVal:0, StrVal:\"\"}: MaxSurge and MaxUnavailable both can not be zero\n", stderr)
{
"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-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",
},
}

runCmd = func(filename string, errmsg string) {
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)

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 {
runCmd(t.filename, t.errmsg)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
apiVersion: v1
kind: Service
metadata:
name: argo-rollouts-metrics
labels:
region: us-west
spec:
ports:
- name: metrics
protocol: TCP
port: 8090
targetPort: 8090
---
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: invalid-rollout
spec:
replicas: 10
strategy:
unknown-strategy:
analysis:
templates:
- templateName: integrationtests
steps:
- setWeight: 10
selector:
matchLabels:
app: invalid-rollout
template:
metadata:
labels:
app: invalid-rollout
spec:
containers:
- name: invalid-rollout
image: valid-rollout:0.0.0
ports:
- name: http
containerPort: 8080
protocol: TCP
readinessProbe:
httpGet:
path: /ping
port: 8080
periodSeconds: 5

0 comments on commit 6ba30ed

Please sign in to comment.