diff --git a/Makefile b/Makefile index bd25d0bb0..b05168c23 100644 --- a/Makefile +++ b/Makefile @@ -177,6 +177,7 @@ ifeq (, $(shell which go-bindata)) go get github.com/go-bindata/go-bindata/v3/go-bindata@$$(go list -f '{{.Version}}' -m github.com/go-bindata/go-bindata/v3) endif go-bindata -pkg crd -o pkg/kudoctl/kudoinit/crd/bindata.go -ignore README.md -nometadata config/crds + go-bindata -pkg convert -o pkg/kudoctl/packages/convert/bindata.go -nometadata config/json-schema ./hack/update_codegen.sh .PHONY: generate-clean @@ -197,7 +198,13 @@ endif # example: make update-golden # tests in update==true mode show as failures update-golden: ## Updates golden files +ifdef _INTELLIJ_FORCE_SET_GOFLAGS + # Run tests from a Goland terminal. Goland already set '-mod=readonly' + go test ./pkg/... --update=true +else go test ./pkg/... -v -mod=readonly --update=true +endif + .PHONY: todo # Show to-do items per file. diff --git a/config/crds/kudo.dev_operatorversions.yaml b/config/crds/kudo.dev_operatorversions.yaml index de83f61f4..99695e35a 100644 --- a/config/crds/kudo.dev_operatorversions.yaml +++ b/config/crds/kudo.dev_operatorversions.yaml @@ -37,6 +37,19 @@ spec: connectionString: description: ConnectionString defines a templated string that can be used to connect to an instance of the Operator. type: string + groups: + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + prio: + type: integer + type: object + type: array operator: description: 'ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don''t make new APIs embed an underspecified API type they do not control. Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .' properties: @@ -66,6 +79,8 @@ spec: items: description: Parameter captures the variability of an OperatorVersion being instantiated in an instance. properties: + advanced: + type: boolean default: description: Default is a default value if no parameter is provided by the instance. type: string @@ -80,6 +95,10 @@ spec: items: type: string type: array + group: + type: string + hint: + type: string immutable: description: Specifies if the parameter can be changed after the initial installation of the operator type: boolean diff --git a/config/json-schema/full.json b/config/json-schema/full.json new file mode 100644 index 000000000..29324679f --- /dev/null +++ b/config/json-schema/full.json @@ -0,0 +1,200 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$recursiveAnchor": true, + "$id": "https://kudo.dev/json-schema-full", + "title": "KUDO JSON-Schema", + "type": ["object", "boolean"], + "additionalProperties": false, + "properties": { + "$id": { + "type": "string", + "format": "uri-reference", + "$comment": "Non-empty fragments not allowed.", + "pattern": "^[^#]*#?$" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$anchor": { + "type": "string", + "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$recursiveRef": { + "type": "string", + "format": "uri-reference" + }, + "$recursiveAnchor": { + "type": "boolean", + "default": false + }, + "$comment": { + "type": "string" + }, + "$defs": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "examples": { + "type": "array", + "items": true + }, + "default": true, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "additionalItems": { "$recursiveRef": "#" }, + "unevaluatedItems": { "$recursiveRef": "#" }, + "items": { + "anyOf": [ + { "$recursiveRef": "#" }, + { "$ref": "#/$defs/schemaArray" } + ] + }, + "contains": { "$recursiveRef": "#" }, + "unevaluatedProperties": { "$recursiveRef": "#" }, + "properties": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependentSchemas": { + "type": "object", + "additionalProperties": { + "$recursiveRef": "#" + } + }, + "propertyNames": { "$recursiveRef": "#" }, + "if": { "$recursiveRef": "#" }, + "then": { "$recursiveRef": "#" }, + "else": { "$recursiveRef": "#" }, + "allOf": { "$ref": "#/$defs/schemaArray" }, + "anyOf": { "$ref": "#/$defs/schemaArray" }, + "oneOf": { "$ref": "#/$defs/schemaArray" }, + "not": { "$recursiveRef": "#" }, + "advanced": { + "type": "boolean", + "default": false + }, + "hint": { + "type": "string" + }, + "listName": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "immutable": { + "type": "boolean", + "default": false + }, + "priority": { + "type": "integer" + } + }, + "$defs": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$recursiveRef": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } +} diff --git a/config/json-schema/limited.json b/config/json-schema/limited.json new file mode 100644 index 000000000..45e24e214 --- /dev/null +++ b/config/json-schema/limited.json @@ -0,0 +1,130 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$recursiveAnchor": true, + "$id": "https://kudo.dev/json-schema-limited", + "title": "Limited KUDO JSON-Schema", + "type": ["object", "boolean"], + "additionalProperties": false, + "properties": { + "type": { + "$ref": "#/$defs/simpleTypes" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "properties": { + "additionalProperties": { + "anyOf": [ + { "$ref": "#/$defs/group" }, + { "$ref": "#/$defs/parameter" } + ] + } + } + }, + "$defs": { + "group": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "const": "object" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "type": "integer" + }, + "required": { "$ref": "#/$defs/stringArray" }, + "properties": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#/$defs/group" }, + { "$ref": "#/$defs/parameter" } + ] + }, + "default": {} + } + } + }, + "parameter": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "listName" + ], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "required": { "$ref": "#/$defs/stringArray" }, + "enum": { + "type": "array", + "items": true + }, + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "advanced": { + "type": "boolean", + "default": false + }, + "hint": { + "type": "string" + }, + "listName": { + "type": "string" + }, + "trigger": { + "type": "string" + }, + "immutable": { + "type": "boolean", + "default": false + } + } + }, + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$recursiveRef": "#" } + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } +} diff --git a/go.mod b/go.mod index 92f6a690e..0005077cb 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,8 @@ require ( github.com/moby/term v0.0.0-20200915141129-7f0af18e79f2 // indirect github.com/onsi/ginkgo v1.14.1 github.com/onsi/gomega v1.10.2 + github.com/qri-io/jsonpointer v0.1.1 + github.com/qri-io/jsonschema v0.2.0 github.com/spf13/afero v1.4.0 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index bacd663f9..8e6b39702 100644 --- a/go.sum +++ b/go.sum @@ -450,11 +450,16 @@ github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4 github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/qri-io/jsonpointer v0.1.1 h1:prVZBZLL6TW5vsSB9fFHFAMBLI4b0ri5vribQlTJiBA= +github.com/qri-io/jsonpointer v0.1.1/go.mod h1:DnJPaYgiKu56EuDp8TU5wFLdZIcAnb/uH9v37ZaMV64= +github.com/qri-io/jsonschema v0.2.0 h1:is8lirh3HYwTkC0e+4jL/vWEHwzPLojnl4FWkUoeEPU= +github.com/qri-io/jsonschema v0.2.0/go.mod h1:g7DPkiOsK1xv6T/Ao5scXRkd+yTFygcANPBaaqW+VrI= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= diff --git a/pkg/apis/kudo/v1beta1/operatorversion_types.go b/pkg/apis/kudo/v1beta1/operatorversion_types.go index 29e2d9772..cda009ff3 100644 --- a/pkg/apis/kudo/v1beta1/operatorversion_types.go +++ b/pkg/apis/kudo/v1beta1/operatorversion_types.go @@ -32,7 +32,8 @@ type OperatorVersionSpec struct { // List of all tasks available in this OperatorVersion. Tasks []Task `json:"tasks,omitempty"` - Parameters []Parameter `json:"parameters,omitempty"` + Groups []ParameterGroup `json:"groups,omitempty"` + Parameters []Parameter `json:"parameters,omitempty"` // Plans maps a plan name to a plan. // +nullable diff --git a/pkg/apis/kudo/v1beta1/parameter_types.go b/pkg/apis/kudo/v1beta1/parameter_types.go index b1de4ddbc..797238701 100644 --- a/pkg/apis/kudo/v1beta1/parameter_types.go +++ b/pkg/apis/kudo/v1beta1/parameter_types.go @@ -33,4 +33,15 @@ type Parameter struct { // Defines a list of allowed values. If Default is set and Enum is not nil, the value must be in this list as well Enum *[]string `json:"enum,omitempty"` + + Group string `json:"group,omitempty"` + Advanced *bool `json:"advanced,omitempty"` + Hint string `json:"hint,omitempty"` +} + +type ParameterGroup struct { + Name string `json:"name,omitempty"` + DisplayName string `json:"displayName,omitempty"` + Description string `json:"description,omitempty"` + Priority int `json:"prio,omitempty"` } diff --git a/pkg/apis/kudo/v1beta1/parameter_types_helpers.go b/pkg/apis/kudo/v1beta1/parameter_types_helpers.go index 79a45e876..bb99199da 100644 --- a/pkg/apis/kudo/v1beta1/parameter_types_helpers.go +++ b/pkg/apis/kudo/v1beta1/parameter_types_helpers.go @@ -16,6 +16,10 @@ func (p *Parameter) IsRequired() bool { return p.Required != nil && *p.Required } +func (p *Parameter) IsAdvanced() bool { + return p.Advanced != nil && *p.Advanced +} + func (p *Parameter) IsEnum() bool { return p.Enum != nil } diff --git a/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go b/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go index 0e2b9b921..fa37a68fa 100644 --- a/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/kudo/v1beta1/zz_generated.deepcopy.go @@ -371,6 +371,11 @@ func (in *OperatorVersionSpec) DeepCopyInto(out *OperatorVersionSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Groups != nil { + in, out := &in.Groups, &out.Groups + *out = make([]ParameterGroup, len(*in)) + copy(*out, *in) + } if in.Parameters != nil { in, out := &in.Parameters, &out.Parameters *out = make([]Parameter, len(*in)) @@ -446,6 +451,11 @@ func (in *Parameter) DeepCopyInto(out *Parameter) { copy(*out, *in) } } + if in.Advanced != nil { + in, out := &in.Advanced, &out.Advanced + *out = new(bool) + **out = **in + } return } @@ -459,6 +469,22 @@ func (in *Parameter) DeepCopy() *Parameter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParameterGroup) DeepCopyInto(out *ParameterGroup) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterGroup. +func (in *ParameterGroup) DeepCopy() *ParameterGroup { + if in == nil { + return nil + } + out := new(ParameterGroup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Phase) DeepCopyInto(out *Phase) { *out = *in diff --git a/pkg/kudoctl/cmd/package_list.go b/pkg/kudoctl/cmd/package_list.go index 1e7920198..eb05d4f0a 100644 --- a/pkg/kudoctl/cmd/package_list.go +++ b/pkg/kudoctl/cmd/package_list.go @@ -53,7 +53,7 @@ func newPackageParamsCmd(fs afero.Fs, out io.Writer) *cobra.Command { Long: packageListDesc, Example: packageListExamples, } - cmd.AddCommand(newPackageListParamsCmd(fs, out)) + cmd.AddCommand(newPackageListParamsCmd(&packageListParamsCmd{fs: fs, out: out})) cmd.AddCommand(newPackageListPlansCmd(fs, out)) cmd.AddCommand(newPackageListTasksCmd(fs, out)) diff --git a/pkg/kudoctl/cmd/package_list_params.go b/pkg/kudoctl/cmd/package_list_params.go index b0498ef37..b4ea77622 100644 --- a/pkg/kudoctl/cmd/package_list_params.go +++ b/pkg/kudoctl/cmd/package_list_params.go @@ -12,7 +12,9 @@ import ( kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/generate" + "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output" "github.com/kudobuilder/kudo/pkg/kudoctl/env" + packageconvert "github.com/kudobuilder/kudo/pkg/kudoctl/packages/convert" "github.com/kudobuilder/kudo/pkg/util/convert" ) @@ -26,6 +28,8 @@ type packageListParamsCmd struct { RepoName string AppVersion string OperatorVersion string + Output output.Type + Format string } type Parameters []kudoapi.Parameter @@ -50,11 +54,16 @@ const ( # show parameters from zookeeper (where zookeeper is name of package in KUDO repository) kubectl kudo package list parameters zookeeper` -) -func newPackageListParamsCmd(fs afero.Fs, out io.Writer) *cobra.Command { - list := &packageListParamsCmd{fs: fs, out: out} + outputFormatList = "list" + outputFormatJSONSchema = "json-schema" + + TypeJSONSchema output.Type = "json-schema" + TypeJSONSchemaYaml output.Type = "json-schema-yaml" +) +func newPackageListParamsCmd(list *packageListParamsCmd) *cobra.Command { + var outputStr string cmd := &cobra.Command{ Use: "parameters [operator]", Short: "List operator parameters", @@ -75,6 +84,23 @@ func newPackageListParamsCmd(fs afero.Fs, out io.Writer) *cobra.Command { if err == nil { list.pathOrName = args[0] } + + switch output.Type(outputStr) { + case "": + // Nothing to set + case output.TypeJSON, output.TypeYAML: + list.Output = output.Type(outputStr) + list.Format = outputFormatList + case TypeJSONSchema: + list.Output = output.TypeJSON + list.Format = outputFormatJSONSchema + case TypeJSONSchemaYaml: + list.Output = output.TypeYAML + list.Format = outputFormatJSONSchema + default: + return fmt.Errorf("output must be one of json, yaml, json-schema, json-schema-yaml") + } + return list.run(&Settings) }, } @@ -86,6 +112,7 @@ func newPackageListParamsCmd(fs afero.Fs, out io.Writer) *cobra.Command { f.StringVar(&list.RepoName, "repo", "", "Name of repository configuration to use. (default defined by context)") f.StringVar(&list.AppVersion, "app-version", "", "A specific app version in the official GitHub repo. (default to the most recent)") f.StringVar(&list.OperatorVersion, "operator-version", "", "A specific operator version in the official GitHub repo. (default to the most recent)") + f.StringVarP(&outputStr, "output", "o", "", "Output format (json, yaml, json-schema or json-schema-yaml. Human readable if not specified)") return cmd } @@ -103,11 +130,18 @@ func (c *packageListParamsCmd) run(settings *env.Settings) error { return err } - if err := displayParamsTable(pr.OperatorVersion.Spec.Parameters, c.out, c.requiredOnly, c.namesOnly, c.descriptions); err != nil { - return err + switch c.Format { + case outputFormatList: + paramFile, err := packageconvert.ResourcesToParamFile(pr) + if err != nil { + return err + } + return output.WriteObject(paramFile, c.Output, c.out) + case outputFormatJSONSchema: + return packageconvert.WriteJSONSchema(pr.OperatorVersion, c.Output, c.out) + default: + return displayParamsTable(pr.OperatorVersion.Spec.Parameters, c.out, c.requiredOnly, c.namesOnly, c.descriptions) } - - return nil } func displayParamsTable(params Parameters, out io.Writer, printRequired, printNames, printDesc bool) error { diff --git a/pkg/kudoctl/cmd/package_list_params_test.go b/pkg/kudoctl/cmd/package_list_params_test.go index acedf02e4..518f71425 100644 --- a/pkg/kudoctl/cmd/package_list_params_test.go +++ b/pkg/kudoctl/cmd/package_list_params_test.go @@ -7,30 +7,57 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output" ) func TestParamsList(t *testing.T) { - file := "params-list" - out := &bytes.Buffer{} - cmd := newPackageListParamsCmd(fs, out) - if err := cmd.RunE(cmd, []string{"../packages/testdata/zk.tgz"}); err != nil { - t.Fatal(err) + tests := []struct { + name string + outputType output.Type + formatType string + err string + }{ + {name: "list-output.txt"}, + {name: "list-output.yaml", outputType: output.TypeYAML, formatType: outputFormatList}, + {name: "list-output.json", outputType: output.TypeJSON, formatType: outputFormatList}, + {name: "schema-output.yaml", outputType: output.TypeYAML, formatType: outputFormatJSONSchema}, + {name: "schema-output.json", outputType: output.TypeJSON, formatType: outputFormatJSONSchema}, } - gp := filepath.Join("testdata", file+".golden") + for _, tt := range tests { + tt := tt - if *updateGolden { - t.Log("update golden file") + t.Run(tt.name, func(t *testing.T) { - //nolint:gosec - if err := ioutil.WriteFile(gp, out.Bytes(), 0644); err != nil { - t.Fatalf("failed to update golden file: %s", err) - } - } - g, err := ioutil.ReadFile(gp) - if err != nil { - t.Fatalf("failed reading .golden: %s", err) + file := tt.name + out := &bytes.Buffer{} + params := &packageListParamsCmd{fs: fs, out: out, Output: tt.outputType, Format: tt.formatType} + + cmd := newPackageListParamsCmd(params) + + if err := cmd.RunE(cmd, []string{"./testdata/listop"}); err != nil { + t.Fatal(err) + } + + gp := filepath.Join("testdata", file+".golden") + + if *updateGolden { + t.Log("update golden file") + + //nolint:gosec + if err := ioutil.WriteFile(gp, out.Bytes(), 0644); err != nil { + t.Fatalf("failed to update golden file: %s", err) + } + } + g, err := ioutil.ReadFile(gp) + if err != nil { + t.Fatalf("failed reading .golden: %s", err) + } + + assert.Equal(t, string(g), out.String(), "output does not match .golden file %s", gp) + + }) } - assert.Equal(t, string(g), out.String(), "yaml does not match .golden file %s", gp) } diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden index 3f392f412..f1f11d17f 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo-ns.yaml.golden @@ -105,6 +105,19 @@ spec: connectionString: description: ConnectionString defines a templated string that can be used to connect to an instance of the Operator. type: string + groups: + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + prio: + type: integer + type: object + type: array operator: description: 'ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don''t make new APIs embed an underspecified API type they do not control. Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .' properties: @@ -134,6 +147,8 @@ spec: items: description: Parameter captures the variability of an OperatorVersion being instantiated in an instance. properties: + advanced: + type: boolean default: description: Default is a default value if no parameter is provided by the instance. type: string @@ -148,6 +163,10 @@ spec: items: type: string type: array + group: + type: string + hint: + type: string immutable: description: Specifies if the parameter can be changed after the initial installation of the operator type: boolean diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden index 26d5d1002..79038ce59 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo-sa.yaml.golden @@ -105,6 +105,19 @@ spec: connectionString: description: ConnectionString defines a templated string that can be used to connect to an instance of the Operator. type: string + groups: + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + prio: + type: integer + type: object + type: array operator: description: 'ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don''t make new APIs embed an underspecified API type they do not control. Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .' properties: @@ -134,6 +147,8 @@ spec: items: description: Parameter captures the variability of an OperatorVersion being instantiated in an instance. properties: + advanced: + type: boolean default: description: Default is a default value if no parameter is provided by the instance. type: string @@ -148,6 +163,10 @@ spec: items: type: string type: array + group: + type: string + hint: + type: string immutable: description: Specifies if the parameter can be changed after the initial installation of the operator type: boolean diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden index 86e43d777..d76a8e8f9 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo.json.golden @@ -147,6 +147,26 @@ "description": "ConnectionString defines a templated string that can be used to connect to an instance of the Operator.", "type": "string" }, + "groups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "prio": { + "type": "integer" + } + } + } + }, "operator": { "description": "ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, \"must refer only to types A and B\" or \"UID not honored\" or \"name must be restricted\". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control. Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .", "type": "object", @@ -187,6 +207,9 @@ "description": "Parameter captures the variability of an OperatorVersion being instantiated in an instance.", "type": "object", "properties": { + "advanced": { + "type": "boolean" + }, "default": { "description": "Default is a default value if no parameter is provided by the instance.", "type": "string" @@ -206,6 +229,12 @@ "type": "string" } }, + "group": { + "type": "string" + }, + "hint": { + "type": "string" + }, "immutable": { "description": "Specifies if the parameter can be changed after the initial installation of the operator", "type": "boolean" diff --git a/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden b/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden index 1be6a7136..61d365863 100644 --- a/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden +++ b/pkg/kudoctl/cmd/testdata/deploy-kudo.yaml.golden @@ -105,6 +105,19 @@ spec: connectionString: description: ConnectionString defines a templated string that can be used to connect to an instance of the Operator. type: string + groups: + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + prio: + type: integer + type: object + type: array operator: description: 'ObjectReference contains enough information to let you inspect or modify the referred object. --- New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs. 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage. 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted". Those cannot be well described when embedded. 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen. 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple and the version of the actual struct is irrelevant. 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type will affect numerous schemas. Don''t make new APIs embed an underspecified API type they do not control. Instead of using this type, create a locally provided and used type that is well-focused on your reference. For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .' properties: @@ -134,6 +147,8 @@ spec: items: description: Parameter captures the variability of an OperatorVersion being instantiated in an instance. properties: + advanced: + type: boolean default: description: Default is a default value if no parameter is provided by the instance. type: string @@ -148,6 +163,10 @@ spec: items: type: string type: array + group: + type: string + hint: + type: string immutable: description: Specifies if the parameter can be changed after the initial installation of the operator type: boolean diff --git a/pkg/kudoctl/cmd/testdata/list-output.json.golden b/pkg/kudoctl/cmd/testdata/list-output.json.golden new file mode 100644 index 000000000..d77de50ed --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/list-output.json.golden @@ -0,0 +1,101 @@ +{ + "apiVersion": "kudo.dev/v1beta1", + "groups": [ + { + "name": "general", + "description": "All the standard parameters", + "prio": 10 + }, + { + "name": "advanced", + "description": "Options that most users don't need to adjust", + "prio": 20 + } + ], + "parameters": [ + { + "displayName": "Node Count", + "name": "NODE_COUNT", + "description": "The number of Zookeeper nodes to create for the cluster. Should be an odd number of nodes and at least 3 to create a useful quorum.", + "required": true, + "default": 3, + "type": "integer", + "immutable": false, + "group": "general", + "hint": "Number of nodes." + }, + { + "displayName": "CPU Request", + "name": "NODE_CPU_MC", + "description": "CPU request for the containers.", + "required": true, + "default": 1000, + "type": "integer", + "immutable": false, + "group": "general", + "hint": "Allowed CPU usage in millicores." + }, + { + "displayName": "CPU Limit", + "name": "NODE_CPU_LIMIT_MC", + "description": "CPU limit for the containers.", + "required": true, + "default": 1000, + "type": "integer", + "immutable": false, + "group": "general", + "hint": "Temporary allowed CPU limit in millicores." + }, + { + "displayName": "Memory Request", + "name": "NODE_MEM_MIB", + "description": "Memory request for the containers.", + "required": true, + "default": 4096, + "type": "integer", + "immutable": false, + "group": "general", + "hint": "Allowed Memory usage in MiB." + }, + { + "displayName": "Memory Limit", + "name": "NODE_MEM_LIMIT_MIB", + "description": "Memory limit for the Cassandra node containers.", + "required": true, + "default": 4096, + "type": "integer", + "immutable": false, + "group": "general", + "hint": "Temporary allowed Memory limit in MiB." + }, + { + "displayName": "Main Docker Image", + "name": "DOCKER_IMAGE", + "description": "Zookeeper Docker image.", + "required": true, + "default": "k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10", + "type": "string", + "immutable": false, + "group": "advanced", + "advanced": true, + "hint": "Docker Image." + }, + { + "displayName": "Main Docker Image Pull Policy", + "name": "DOCKER_IMAGE_PULL_POLICY", + "description": "Zookeeper Docker image pull policy.", + "required": true, + "default": "Always", + "type": "string", + "immutable": false, + "enum": [ + "Always", + "IfNotPresent", + "Never" + ], + "group": "advanced", + "advanced": true, + "hint": "Pull policy." + } + ] +} diff --git a/pkg/kudoctl/cmd/testdata/list-output.txt.golden b/pkg/kudoctl/cmd/testdata/list-output.txt.golden new file mode 100644 index 000000000..572ecee61 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/list-output.txt.golden @@ -0,0 +1,8 @@ +Name Default Required Immutable +DOCKER_IMAGE k8s.gcr.io/kubernetes-zookeeper:... true false +DOCKER_IMAGE_PULL_POLICY Always true false +NODE_COUNT 3 true false +NODE_CPU_LIMIT_MC 1000 true false +NODE_CPU_MC 1000 true false +NODE_MEM_LIMIT_MIB 4096 true false +NODE_MEM_MIB 4096 true false diff --git a/pkg/kudoctl/cmd/testdata/list-output.yaml.golden b/pkg/kudoctl/cmd/testdata/list-output.yaml.golden new file mode 100644 index 000000000..fe3538ed8 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/list-output.yaml.golden @@ -0,0 +1,79 @@ +apiVersion: kudo.dev/v1beta1 +groups: +- description: All the standard parameters + name: general + prio: 10 +- description: Options that most users don't need to adjust + name: advanced + prio: 20 +parameters: +- default: 3 + description: The number of Zookeeper nodes to create for the cluster. Should be an odd number of nodes and at least 3 to create a useful quorum. + displayName: Node Count + group: general + hint: Number of nodes. + immutable: false + name: NODE_COUNT + required: true + type: integer +- default: 1000 + description: CPU request for the containers. + displayName: CPU Request + group: general + hint: Allowed CPU usage in millicores. + immutable: false + name: NODE_CPU_MC + required: true + type: integer +- default: 1000 + description: CPU limit for the containers. + displayName: CPU Limit + group: general + hint: Temporary allowed CPU limit in millicores. + immutable: false + name: NODE_CPU_LIMIT_MC + required: true + type: integer +- default: 4096 + description: Memory request for the containers. + displayName: Memory Request + group: general + hint: Allowed Memory usage in MiB. + immutable: false + name: NODE_MEM_MIB + required: true + type: integer +- default: 4096 + description: Memory limit for the Cassandra node containers. + displayName: Memory Limit + group: general + hint: Temporary allowed Memory limit in MiB. + immutable: false + name: NODE_MEM_LIMIT_MIB + required: true + type: integer +- advanced: true + default: k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10 + description: Zookeeper Docker image. + displayName: Main Docker Image + group: advanced + hint: Docker Image. + immutable: false + name: DOCKER_IMAGE + required: true + type: string +- advanced: true + default: Always + description: Zookeeper Docker image pull policy. + displayName: Main Docker Image Pull Policy + enum: + - Always + - IfNotPresent + - Never + group: advanced + hint: Pull policy. + immutable: false + name: DOCKER_IMAGE_PULL_POLICY + required: true + type: string + diff --git a/pkg/kudoctl/cmd/testdata/listop/operator.yaml b/pkg/kudoctl/cmd/testdata/listop/operator.yaml new file mode 100644 index 000000000..5a150f1d9 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/listop/operator.yaml @@ -0,0 +1,40 @@ +apiVersion: kudo.dev/v1beta1 +name: "zookeeper" +operatorVersion: "0.1.0" +appVersion: "3.4.10" +kudoVersion: 0.2.0 +kubernetesVersion: 1.15.0 +maintainers: + - name: Alena Varkockova + email: avarkockova@mesosphere.com + - name: Tom Runyon + email: runyontr@gmail.com + - name: Ken Sipe + email: kensipe@gmail.com +url: https://zookeeper.apache.org/ +tasks: + - name: app + kind: Apply + spec: + resources: + - statefulset.yaml +plans: + deploy: + strategy: serial + phases: + - name: zookeeper + strategy: parallel + steps: + - name: everything + tasks: + - infra + - app + validation: + strategy: serial + phases: + - name: connection + strategy: parallel + steps: + - name: connection + tasks: + - validation \ No newline at end of file diff --git a/pkg/kudoctl/cmd/testdata/listop/params.yaml b/pkg/kudoctl/cmd/testdata/listop/params.yaml new file mode 100644 index 000000000..ae2dc5792 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/listop/params.yaml @@ -0,0 +1,72 @@ +apiVersion: kudo.dev/v1beta1 +groups: + - name: general + title: "Main Parameters" + description: "All the standard parameters" + prio: 10 + - name: advanced + title: "Advanced Configuration" + description: "Options that most users don't need to adjust" + prio: 20 +parameters: + - name: NODE_COUNT + description: "The number of Zookeeper nodes to create for the cluster. Should be an odd number of nodes and at least 3 to create a useful quorum." + default: "3" + displayName: "Node Count" + hint: "Number of nodes." + type: integer + group: general + + - name: NODE_CPU_MC + displayName: "CPU Request" + hint: "Allowed CPU usage in millicores." + description: "CPU request for the containers." + type: integer + default: "1000" + group: general + + - name: NODE_CPU_LIMIT_MC + displayName: "CPU Limit" + hint: "Temporary allowed CPU limit in millicores." + description: "CPU limit for the containers." + default: "1000" + type: integer + group: general + + - name: NODE_MEM_MIB + displayName: "Memory Request" + description: "Memory request for the containers." + hint: "Allowed Memory usage in MiB." + default: "4096" + type: integer + group: general + + - name: NODE_MEM_LIMIT_MIB + displayName: "Memory Limit" + description: "Memory limit for the Cassandra node containers." + hint: "Temporary allowed Memory limit in MiB." + default: "4096" + type: integer + group: general + + - name: DOCKER_IMAGE + displayName: "Main Docker Image" + type: string + description: "Zookeeper Docker image." + hint: "Docker Image." + default: "k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10" + advanced: true + group: advanced + + - name: DOCKER_IMAGE_PULL_POLICY + displayName: "Main Docker Image Pull Policy" + type: string + description: "Zookeeper Docker image pull policy." + hint: "Pull policy." + default: "Always" + advanced: true + group: advanced + enum: + - "Always" + - "IfNotPresent" + - "Never" diff --git a/pkg/kudoctl/cmd/testdata/listop/templates/statefulset.yaml b/pkg/kudoctl/cmd/testdata/listop/templates/statefulset.yaml new file mode 100644 index 000000000..e727386a2 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/listop/templates/statefulset.yaml @@ -0,0 +1,90 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Name }} + namespace: {{ .Namespace }} +spec: + selector: + matchLabels: + app: zookeeper + zookeeper: {{ .Name }} + serviceName: {{ .Name }}-hs + replicas: {{ .Params.NODE_COUNT }} + updateStrategy: + type: RollingUpdate + podManagementPolicy: Parallel + template: + metadata: + labels: + app: zookeeper + zookeeper: {{ .Name }} + spec: + containers: + - name: kubernetes-zookeeper + imagePullPolicy: {{ .Params.DOCKER_IMAGE_PULL_POLICY }} + image: "{{ .Params.DOCKER_IMAGE }}" + resources: + requests: + memory: "{{ $.Params.NODE_MEM_MIB }}Mi" + cpu: "{{ $.Params.NODE_CPU_MC }}m" + limits: + memory: "{{ $.Params.NODE_MEM_LIMIT_MIB }}Mi" + cpu: "{{ $.Params.NODE_CPU_LIMIT_MC }}m" + ports: + - containerPort: 2181 + name: client + - containerPort: 2888 + name: server + - containerPort: 3888 + name: leader-election + command: + - sh + - -c + - "start-zookeeper \ + --servers=3 \ + --data_dir=/var/lib/zookeeper/data \ + --data_log_dir=/var/lib/zookeeper/data/log \ + --conf_dir=/opt/zookeeper/conf \ + --client_port=2181 \ + --election_port=3888 \ + --server_port=2888 \ + --tick_time=2000 \ + --init_limit=10 \ + --sync_limit=5 \ + --heap=512M \ + --max_client_cnxns=60 \ + --snap_retain_count=3 \ + --purge_interval=12 \ + --max_session_timeout=40000 \ + --min_session_timeout=4000 \ + --log_level=INFO" + readinessProbe: + exec: + command: + - sh + - -c + - "zookeeper-ready 2181" + initialDelaySeconds: 10 + timeoutSeconds: 5 + livenessProbe: + exec: + command: + - sh + - -c + - "zookeeper-ready 2181" + initialDelaySeconds: 10 + timeoutSeconds: 5 + volumeMounts: + - name: datadir + mountPath: /var/lib/zookeeper + securityContext: + runAsUser: 1000 + fsGroup: 1000 + volumeClaimTemplates: + - metadata: + name: datadir + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 2Gi diff --git a/pkg/kudoctl/cmd/testdata/listop/templates/validation.yaml b/pkg/kudoctl/cmd/testdata/listop/templates/validation.yaml new file mode 100644 index 000000000..e04a60050 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/listop/templates/validation.yaml @@ -0,0 +1,27 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: zookeeper-validation +spec: + template: + metadata: + name: "validation" + spec: + restartPolicy: Never + containers: + - name: kubernetes-zookeeper + imagePullPolicy: {{ .Params.DOCKER_IMAGE_PULL_POLICY }} + image: "{{ .Params.DOCKER_IMAGE }}" + env: + - name: CONN + value: zk-zk-0.zk-hs:2181,zk-zk-1.zk-hs:2181,zk-zk-2.zk-hs:2181 + resources: + requests: + memory: "{{ $.Params.NODE_MEM_MIB }}Mi" + cpu: "{{ $.Params.NODE_CPU_MC }}m" + command: + - sh + - -c + - "/opt/zookeeper/bin/zkCLI.sh \ + --server $CONN \ + ls /" diff --git a/pkg/kudoctl/cmd/testdata/params-list.golden b/pkg/kudoctl/cmd/testdata/params-list.golden deleted file mode 100644 index dbd0d2a08..000000000 --- a/pkg/kudoctl/cmd/testdata/params-list.golden +++ /dev/null @@ -1,3 +0,0 @@ -Name Default Required Immutable -cpus 0.25 true false -memory 1Gi true false diff --git a/pkg/kudoctl/cmd/testdata/schema-output.json.golden b/pkg/kudoctl/cmd/testdata/schema-output.json.golden new file mode 100644 index 000000000..ba6b6ea8d --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/schema-output.json.golden @@ -0,0 +1,97 @@ +{ + "title": "Parameters for zookeeper-3.4.10-0.1.0", + "description": "All parameters for this operator", + "type": "object", + "properties": { + "advanced": { + "title": "advanced", + "description": "Options that most users don't need to adjust", + "priority": 20, + "type": "object", + "properties": { + "DOCKER_IMAGE": { + "title": "Main Docker Image", + "description": "Zookeeper Docker image.", + "default": "k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10", + "type": "string", + "advanced": true, + "hint": "Docker Image.", + "listName": "DOCKER_IMAGE" + }, + "DOCKER_IMAGE_PULL_POLICY": { + "title": "Main Docker Image Pull Policy", + "description": "Zookeeper Docker image pull policy.", + "default": "Always", + "enum": [ + "Always", + "IfNotPresent", + "Never" + ], + "type": "string", + "advanced": true, + "hint": "Pull policy.", + "listName": "DOCKER_IMAGE_PULL_POLICY" + } + }, + "required": [ + "DOCKER_IMAGE", + "DOCKER_IMAGE_PULL_POLICY" + ] + }, + "general": { + "title": "general", + "description": "All the standard parameters", + "priority": 10, + "type": "object", + "properties": { + "NODE_COUNT": { + "title": "Node Count", + "description": "The number of Zookeeper nodes to create for the cluster. Should be an odd number of nodes and at least 3 to create a useful quorum.", + "default": "3", + "type": "integer", + "hint": "Number of nodes.", + "listName": "NODE_COUNT" + }, + "NODE_CPU_LIMIT_MC": { + "title": "CPU Limit", + "description": "CPU limit for the containers.", + "default": "1000", + "type": "integer", + "hint": "Temporary allowed CPU limit in millicores.", + "listName": "NODE_CPU_LIMIT_MC" + }, + "NODE_CPU_MC": { + "title": "CPU Request", + "description": "CPU request for the containers.", + "default": "1000", + "type": "integer", + "hint": "Allowed CPU usage in millicores.", + "listName": "NODE_CPU_MC" + }, + "NODE_MEM_LIMIT_MIB": { + "title": "Memory Limit", + "description": "Memory limit for the Cassandra node containers.", + "default": "4096", + "type": "integer", + "hint": "Temporary allowed Memory limit in MiB.", + "listName": "NODE_MEM_LIMIT_MIB" + }, + "NODE_MEM_MIB": { + "title": "Memory Request", + "description": "Memory request for the containers.", + "default": "4096", + "type": "integer", + "hint": "Allowed Memory usage in MiB.", + "listName": "NODE_MEM_MIB" + } + }, + "required": [ + "NODE_COUNT", + "NODE_CPU_MC", + "NODE_CPU_LIMIT_MC", + "NODE_MEM_MIB", + "NODE_MEM_LIMIT_MIB" + ] + } + } +} diff --git a/pkg/kudoctl/cmd/testdata/schema-output.yaml.golden b/pkg/kudoctl/cmd/testdata/schema-output.yaml.golden new file mode 100644 index 000000000..a33ae3532 --- /dev/null +++ b/pkg/kudoctl/cmd/testdata/schema-output.yaml.golden @@ -0,0 +1,81 @@ +description: All parameters for this operator +properties: + advanced: + description: Options that most users don't need to adjust + priority: 20 + properties: + DOCKER_IMAGE: + advanced: true + default: k8s.gcr.io/kubernetes-zookeeper:1.0-3.4.10 + description: Zookeeper Docker image. + hint: Docker Image. + listName: DOCKER_IMAGE + title: Main Docker Image + type: string + DOCKER_IMAGE_PULL_POLICY: + advanced: true + default: Always + description: Zookeeper Docker image pull policy. + enum: + - Always + - IfNotPresent + - Never + hint: Pull policy. + listName: DOCKER_IMAGE_PULL_POLICY + title: Main Docker Image Pull Policy + type: string + required: + - DOCKER_IMAGE + - DOCKER_IMAGE_PULL_POLICY + title: advanced + type: object + general: + description: All the standard parameters + priority: 10 + properties: + NODE_COUNT: + default: "3" + description: The number of Zookeeper nodes to create for the cluster. Should be an odd number of nodes and at least 3 to create a useful quorum. + hint: Number of nodes. + listName: NODE_COUNT + title: Node Count + type: integer + NODE_CPU_LIMIT_MC: + default: "1000" + description: CPU limit for the containers. + hint: Temporary allowed CPU limit in millicores. + listName: NODE_CPU_LIMIT_MC + title: CPU Limit + type: integer + NODE_CPU_MC: + default: "1000" + description: CPU request for the containers. + hint: Allowed CPU usage in millicores. + listName: NODE_CPU_MC + title: CPU Request + type: integer + NODE_MEM_LIMIT_MIB: + default: "4096" + description: Memory limit for the Cassandra node containers. + hint: Temporary allowed Memory limit in MiB. + listName: NODE_MEM_LIMIT_MIB + title: Memory Limit + type: integer + NODE_MEM_MIB: + default: "4096" + description: Memory request for the containers. + hint: Allowed Memory usage in MiB. + listName: NODE_MEM_MIB + title: Memory Request + type: integer + required: + - NODE_COUNT + - NODE_CPU_MC + - NODE_CPU_LIMIT_MC + - NODE_MEM_MIB + - NODE_MEM_LIMIT_MIB + title: general + type: object +title: Parameters for zookeeper-3.4.10-0.1.0 +type: object + diff --git a/pkg/kudoctl/kudoinit/crd/bindata.go b/pkg/kudoctl/kudoinit/crd/bindata.go index afdf27a38..171fd3b60 100644 --- a/pkg/kudoctl/kudoinit/crd/bindata.go +++ b/pkg/kudoctl/kudoinit/crd/bindata.go @@ -120,7 +120,7 @@ func configCrdsKudoDev_operatorsYaml() (*asset, error) { return a, nil } -var _configCrdsKudoDev_operatorversionsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x3c\x6b\x8f\x1b\x37\x92\xdf\xe7\x57\x14\x26\x1f\x9c\x04\x52\x6b\x9d\xec\xe2\x0e\xf3\x2d\x6b\xc7\x87\xb9\x78\x6d\xc3\x8f\x3d\x1c\x72\x01\x86\x6a\x56\xab\xb9\xc3\x26\xfb\xf8\x90\xac\x0b\xf2\xdf\x0f\x55\x64\x3f\xa4\xd1\xa3\x2d\x27\xb9\x2c\x6e\xfa\x4b\xa2\x6e\xb2\x58\xef\x17\x6b\x7c\x35\x9f\xcf\xaf\x44\xab\xfe\x8e\xce\x2b\x6b\x6e\x40\xb4\x0a\x3f\x06\x34\xf4\xcb\x17\xf7\xff\xea\x0b\x65\x17\xeb\xa7\x57\xf7\xca\xc8\x1b\x78\x16\x7d\xb0\xcd\x5b\xf4\x36\xba\x12\x9f\x63\xa5\x8c\x0a\xca\x9a\xab\x06\x83\x90\x22\x88\x9b\x2b\x00\x61\x8c\x0d\x82\x5e\x7b\xfa\x09\x50\x5a\x13\x9c\xd5\x1a\xdd\x7c\x85\xa6\xb8\x8f\x4b\x5c\x46\xa5\x25\x3a\x06\xde\x1d\xbd\xfe\x53\xf1\xe7\xe2\x4f\x57\x00\xa5\x43\xde\xfe\x5e\x35\xe8\x83\x68\xda\x1b\x30\x51\xeb\x2b\x00\x23\x1a\xbc\x01\xdb\xa2\x13\xc1\xba\xbc\xd3\x17\xf7\x51\xda\x42\xe2\xfa\xca\xb7\x58\xd2\x99\x2b\x67\x63\x7b\x03\xfd\xfb\xb4\x33\xa3\x93\x48\x79\x9d\x81\x64\xca\xf9\x8b\x56\x3e\xfc\x70\xe8\xeb\x4b\xe5\x03\xaf\x68\x75\x74\x42\x3f\x44\x81\x3f\x7a\x65\x56\x51\x0b\xf7\xe0\xf3\x15\x80\x2f\x6d\x8b\x37\xf0\x8a\xd0\x68\x45\x89\xf2\x0a\xa0\xdb\x4c\x68\xcd\x33\x6d\xeb\xa7\x4b\x0c\xe2\x69\x82\x57\xd6\xd8\x88\x84\x34\x10\x4c\xf3\xdd\x9b\xdb\xbf\x7f\xfb\x6e\xe7\x35\x80\x44\x5f\x3a\xd5\x06\x66\xe2\x1e\xe2\xa0\x3c\x84\x1a\x21\xed\x81\xca\x3a\xfe\xb9\x8f\x3e\x7c\xf7\xe6\xb6\xe8\x01\xb6\x8e\xbe\x07\xd5\x31\x2c\x3d\x23\x2d\x19\xbd\xdd\x3b\xfe\x09\x61\x98\x8f\x96\xa4\x1e\x98\xce\xcf\x07\xa1\xcc\x44\x81\xad\x20\xd4\xca\x83\xc3\xd6\xa1\x47\x93\x14\x86\x5e\x0b\x03\x76\xf9\x0f\x2c\x43\x01\xef\x90\x31\x04\x5f\xdb\xa8\x25\xe9\xd1\x1a\x5d\x00\x87\xa5\x5d\x19\xf5\x3f\x3d\x34\x0f\xc1\xf2\x31\x5a\x04\xf4\x01\x94\x09\xe8\x8c\xd0\xb0\x16\x3a\xe2\x0c\x84\x91\xd0\x88\x2d\x38\x24\xb8\x10\xcd\x08\x02\x2f\xf1\x05\xfc\xcd\x3a\x04\x65\x2a\x7b\x03\x75\x08\xad\xbf\x59\x2c\x56\x2a\x74\x16\x50\xda\xa6\x89\x46\x85\xed\x82\x95\x59\x2d\x63\xb0\xce\x2f\x24\xae\x51\x2f\xbc\x5a\xcd\x85\x2b\x6b\x15\xb0\x0c\xd1\xe1\x42\xb4\x6a\xce\xc8\x1a\xb6\x82\xa2\x91\x5f\xb8\x6c\x33\xfe\xc9\x0e\xf3\xc2\x96\xb4\xc2\x07\xa7\xcc\x6a\xf4\x81\x55\xf4\x04\x97\x49\x49\x49\xb4\x22\x6f\x4d\x54\x0c\xcc\xa4\x57\xc4\x8f\xb7\xdf\xbf\x7b\x0f\xdd\xd1\x89\xe1\x89\xb7\xc3\x52\x3f\xb0\x99\x58\xa4\x4c\x85\x2e\xad\xac\x9c\x6d\x18\x0a\x1a\xd9\x5a\x65\x02\xff\x28\xb5\x42\x13\xc0\xc7\x65\xa3\x02\xc9\xef\xbf\x23\xfa\x40\x12\x28\xe0\x19\x9b\x3e\x2c\x11\x62\x2b\x45\x40\x59\xc0\xad\x81\x67\xa2\x41\xfd\x4c\x78\xfc\xcd\x99\x4c\xdc\xf4\x73\x62\xde\x34\x36\x8f\xbd\xd6\xfe\xe2\xc4\xa7\xd1\x87\xce\xb7\x1c\x91\xc9\x9e\xe1\xbd\x6b\xb1\xdc\xb1\x00\x89\x5e\x39\xd2\xd8\x20\x02\x92\x9e\xef\x6d\x28\x76\x40\x1f\x36\xc1\x64\x86\xed\x41\x33\x3c\x41\x26\x24\x1f\x6c\xb0\x24\x54\xdf\xf1\xe7\x87\x9b\x77\xa8\x79\xb6\xb7\xbc\x27\x45\x40\xc0\xa6\x25\x3b\x93\x9d\xee\x85\x5a\x04\x28\x85\x61\xb9\x7b\x94\x64\x8c\xf9\x38\xfa\x5f\x61\x40\x19\x1f\x84\x29\x31\x59\x3d\xf6\xa4\x17\x9f\x42\x41\xe7\xb3\xce\x60\xfe\xe4\x35\x0b\xee\x2d\x56\xe8\x90\xce\x24\x5d\x12\xca\x78\x40\x63\xe3\xaa\x66\xf5\x73\x4d\x72\x37\xc1\x82\xc6\x00\x5b\x1b\x09\xc7\x96\x30\xb6\x0e\x1a\x2b\x55\xb5\x65\x4c\x1d\x81\x21\xb1\x75\x2e\x69\x3e\x9f\xc3\x2b\xdc\x10\xa1\xbe\x77\x62\x84\x35\x08\x87\x20\x95\x2f\x6d\x74\x62\x85\x12\x96\x58\x8a\xe8\x99\x66\xa9\xaa\x4a\x95\x51\x87\x6d\xc6\x75\x49\x7c\x23\xf3\x89\x5e\xac\x10\x36\x35\x1a\xc0\x66\x89\x52\xa2\x04\x65\xc8\x1d\xfb\x02\xe0\x69\x01\xb7\x2b\x63\xe9\xfc\x4a\xa1\x96\xf4\xee\x96\xdc\x5b\xa9\xa3\x44\x32\x58\xb3\xcd\x5f\x60\x53\xab\xb2\x66\x24\xc8\x04\x57\x68\xd0\x09\xad\xb7\x50\x5b\x06\x50\x00\xbc\xb0\xae\x97\xc4\x0c\xba\x20\xde\x79\x6b\xf2\x91\x2f\x08\xd4\x1b\x11\x12\x9c\xa5\x0d\x35\x39\xee\x2d\x38\xe1\x50\x6f\xc9\xc9\x28\x46\x4f\x94\x21\x0a\x9d\x90\x2f\x00\xbe\x21\x33\x4f\x1f\x13\x3d\x35\xea\x36\xa3\xea\x41\x35\xad\xf5\x5e\x2d\x35\xb2\x36\x48\xc9\x96\xa4\x2a\x55\xf2\x3a\x8e\x49\xca\x48\xb5\x56\x72\x0c\xf4\xd6\x40\x63\x7d\x18\xd8\xc2\x1f\xfc\x8c\xc4\xe2\x12\xb7\x5b\xe1\x02\xb1\x55\x38\x56\x03\x87\xa4\x37\xac\xb4\x1e\xb4\xba\xc7\x19\x5c\x37\xd1\x87\x24\x44\xb0\x46\x6f\x39\x4e\x90\x93\x80\xef\x98\xe0\xbf\x5e\x93\xbc\xaf\x3f\xdc\x3e\x67\xae\x65\x5e\xa5\x97\x14\x8f\x81\xf7\x2f\xb1\x87\x8d\xf2\xba\xe0\xc3\xde\xd7\xd6\x23\x69\x7d\x76\x78\x1b\xd4\xba\x13\x2e\xca\x5d\x89\x16\x00\xdf\x12\x8b\x4a\x6b\xbc\xf2\x81\xdc\x27\x73\x8b\x75\xb0\x00\xf8\x6b\xd6\x14\x52\xb8\x44\x65\x56\xa6\x8a\x75\x38\xcc\x52\x08\xed\xb7\x80\x8b\x7a\x7f\x0d\x2c\xb7\x69\xef\x2c\x6b\x42\x23\xee\xd1\x83\x0a\x50\x0b\x27\x99\xc9\xd1\x93\x93\x0f\x16\x5a\x87\x52\x95\x01\x36\x64\xb8\x1b\xa5\x35\xd4\xa2\x6d\x91\x50\xf9\x73\x01\xef\x6b\xec\x74\xaa\xd7\x02\xd5\xb4\x0e\x4b\xe5\x91\xb9\x66\xd7\xe8\xf4\x16\xf2\xab\x02\xa0\x0b\x47\xc4\x0b\xd1\xbd\x87\x46\xb4\x2d\xfb\x07\x0b\x02\x3e\xbc\x7d\x49\xa0\x95\x67\x4f\xd1\x3a\x2b\x63\x89\x20\x9a\xa5\x5a\x45\x15\xb6\xc9\x8e\x23\xfb\x13\x8e\xde\xad\xc3\x9c\x12\xd0\x89\x14\x65\x14\x49\x3d\x45\xb4\x0c\x79\xa4\x25\xa5\xf0\x59\x37\x40\x62\x8b\x46\xa2\x29\xb7\x84\x12\x19\x79\x8d\x29\x21\x9c\x0d\x91\x30\xb6\x1a\x93\x3b\x35\x72\x9c\xa0\x74\x1e\x2a\x6b\xb8\x0f\x2e\x96\x49\x8b\x9d\x43\x8d\x6b\x61\x42\x01\xf0\x97\x02\xfe\xa3\x17\x3e\x0a\xaf\xf4\x16\xca\x5a\x98\x15\x82\x0a\x3b\x02\xed\x9c\x83\xf2\x3b\xf6\xcd\x86\xab\x6d\x99\xb2\xe4\x59\x0e\x97\x39\x8d\xe9\xf6\xd0\xc3\xd2\x11\x55\x45\x9e\xc9\xc4\x06\x9d\x8d\xbe\x4b\x7a\x0a\x80\xe7\xd6\x3c\x79\x12\x58\xd6\x60\x70\xc3\x7e\x23\x1d\x44\x6e\x37\x1a\x89\x2e\x1b\x1b\x4a\xfa\x98\x00\x87\x1a\xb7\x20\x2d\x8b\x2b\xe7\xe6\xa4\x9e\x3e\xa0\x90\xc4\x80\xe8\x93\x5b\xcf\x88\xcc\x52\x42\x4e\xdc\x27\x94\x35\x8b\xde\xae\x95\xe4\x53\x64\xf6\xf9\x09\xb0\x60\x66\x91\x31\xcc\x2b\x5b\xf2\x17\x6b\xc8\xbf\xba\x64\x85\xe4\x91\x0b\xf6\x44\xf8\x51\x34\xad\xc6\x19\x67\x1f\xaa\xc4\xde\x61\x7b\x56\x56\x21\x1b\xe5\x59\x22\x0e\x57\xca\x07\x27\x92\x7b\x1f\xa5\x0d\x75\x5c\x16\xa5\x6d\x16\x54\x4f\x38\x83\x01\x3d\xe5\x04\x8b\xa5\xb6\xcb\x05\x09\x4b\x78\x9c\x3f\x2d\x9e\xfe\xcb\xa2\x87\x35\x06\xb5\x58\x3f\x5d\xb0\x2b\x28\x56\xf6\x8b\x97\x7f\xf9\xf6\x5b\x28\x9e\x3c\x88\x2c\xc7\xc3\x30\x9c\xc8\x88\x0f\xc6\x25\xe2\xfe\x9e\x92\x65\x8e\x84\x87\x61\xf0\x4c\x28\xa4\xa7\xea\x7c\xf5\x84\xb3\x9f\xdc\x56\x39\x92\xf5\xf6\xd8\x2a\x4c\xf1\xb8\x4f\xb7\x39\x36\x64\x0d\x10\x06\x28\xad\x72\x98\xbf\xcd\x92\x36\xe4\x80\x3f\xa4\xe3\x14\x58\x41\xe4\xc0\xf0\xef\xef\x5e\xbf\x5a\xfc\x9b\x4d\x98\x81\x28\x4b\xf4\x3e\xa5\x3b\x0d\x3b\x31\x1f\x29\x40\xf9\x2e\x13\x7a\x47\x5f\x8a\x46\x18\x55\xa1\x0f\x45\x86\x86\xce\xff\xf8\xcd\x4f\x7b\x2a\xa2\x12\xbf\xfa\xd4\xb5\x0b\xed\xca\x27\x62\xfa\xbd\xb0\x51\xa1\x66\x94\x5a\x2b\x33\xd2\x1b\x46\x36\x90\x89\xd8\x8c\x6c\x44\x8e\x0f\x37\x70\x4d\xd6\x31\x3a\xfa\x67\x72\xfa\xbf\x5c\xc3\x97\x1b\x0e\x32\x1c\x03\xae\xd3\x81\x7d\x8d\xc1\x71\x21\x4b\x70\x38\x98\x55\x3f\x38\xb5\x5a\x21\x85\x6b\x4e\x9b\x29\x35\xfd\x8a\x62\x89\xaa\xc0\xd8\xd1\x62\x06\x41\xfc\xec\x6d\x73\x1f\x91\x1f\xbf\xf9\xe9\x1a\xbe\xdc\xa5\x8b\xa2\x24\x7e\x84\x6f\xc8\x81\x30\x65\xad\x95\x5f\x65\xa7\xea\xb7\x26\x88\x8f\x04\xb3\xa4\xc0\x64\xfa\x68\x57\x8b\x35\x82\xb7\x4d\x8a\x50\xf3\x94\xc6\x49\xd8\x88\x2d\xd1\xd0\xb1\x92\xa4\x2a\x38\x9e\xee\x55\x60\xef\x5f\x3f\x7f\x7d\x93\x4e\x23\xb1\xad\x4c\xe7\xe6\x2b\x45\xf5\x55\xf2\x9e\x54\x2b\xb0\xcc\x09\x91\x98\x84\x44\x39\x60\xf6\x88\xc9\x03\x57\x91\xb2\xf6\x03\x36\x36\x41\xd7\x1f\x96\x43\x87\xd5\x9c\xe3\xd0\xbe\x71\xfd\x9f\x15\x1d\x13\x89\xe3\xba\x7f\x02\x71\xaf\x46\x7a\x77\x92\xb8\xc1\x1f\x12\x7d\xd2\x96\x9e\x48\x2b\xb1\x0d\x7e\x41\xa1\x7b\xad\x70\xb3\xd8\x58\x77\xaf\xcc\x6a\x4e\x8a\x35\x4f\xd2\xf6\x0b\x6e\x92\x2c\xbe\xe0\xff\x5c\x4c\x0b\xb7\x37\xa6\x12\xc4\x8b\x7f\x0f\xaa\xe8\x1c\xbf\xb8\x88\x28\xb7\x9b\x29\x4f\x21\xed\x5d\x97\xe1\xee\xed\x25\xb3\x48\xe9\x59\x6e\x7e\x8c\x3c\x59\x23\x64\x72\x75\xc2\x6c\x7f\x73\xa5\x25\xd6\x45\x47\x67\x6f\xe7\x39\x05\x98\x0b\x23\xe7\x7d\x8a\x5a\x6e\x2f\xe2\x55\x54\x93\x0c\x95\x12\xee\xdf\x45\x95\xa3\xba\xc8\x2a\x8f\xb4\x00\xe8\x69\x85\x13\x0d\x06\x74\x07\x52\x02\x15\xb0\x39\x98\x29\xec\x50\xff\xa6\x83\x00\xa5\x68\x49\x40\xb9\x45\x26\x9c\x12\x4b\xa5\x29\x1b\x4e\x4e\x78\xbf\x97\xb7\xc4\x94\x1e\x53\x09\x17\x14\x97\xe0\x14\xeb\x86\xfa\xfa\x50\x22\x71\x3a\x85\x21\xd4\x2a\x11\x75\x38\xfc\x71\x0f\xf3\xe7\x69\x6d\xea\x3c\xe5\x8d\x39\x9e\xa6\x10\xd7\x33\x87\x96\xf4\x49\xe2\x32\xd5\xd2\xa7\xb0\x3c\x2b\x91\x7d\x5c\xa6\xa1\xdb\xff\x18\x58\x4d\x49\xac\x59\xa1\x1b\x2f\x25\x7e\xd7\x76\xc3\x58\x0e\x24\x70\xee\x9d\x7b\x1a\x97\xe3\xac\x7c\xab\xc5\xf6\xd5\x51\x27\xbf\x8f\xf3\xb0\x7e\xa7\xa7\xb2\xdc\xc2\x87\x5b\x7f\x31\x1a\x68\x62\x33\x55\xc4\xb9\xcf\xa3\x95\x4f\xd9\x80\xd6\x76\x33\x6a\x94\xde\x56\x63\x3d\xf0\x18\x38\x0b\xf8\xde\xc4\xa6\xcb\x0d\x8c\xd2\x7d\xc9\x1a\x87\x1a\xba\x4b\x5b\x18\xb0\x48\x55\xc2\x11\x94\x8e\x1a\xd2\x44\x72\xbb\x25\xc2\x39\xb1\x3d\xb8\x42\x35\x4d\x0c\x62\xa9\xa7\x49\x25\xfb\x73\x2a\xa8\xab\x3d\x2d\xc9\x42\x4a\xc9\x8e\x04\x51\x05\x74\x59\xdd\x55\x50\x42\x27\xb5\xd7\xba\xef\x6f\x8f\xfb\xef\x27\x91\x5f\x5a\xab\x51\x98\x83\x6b\x8e\x27\x0d\x7b\x98\x5f\xbf\xca\xb9\x26\x1d\x3b\x6e\xd8\xe5\x24\xbe\xd3\xaf\x9c\xa5\x75\xcd\x3d\xa8\x94\x46\x2e\xc4\xc6\x49\xf8\x5d\xba\xa3\x78\xf6\xfa\xc3\xab\xf7\x77\xb4\xde\xf4\xb5\x62\xe7\xbf\x34\xcb\x59\x70\x6a\x9b\x93\xec\xff\x32\xa9\x77\xca\xa1\xb4\xd5\xaa\x14\xfe\x06\xe0\xe7\x9f\xa1\x60\x4f\xe8\x0b\x86\x07\xbf\xfc\x72\x7d\xa9\x76\xe7\xf6\xc0\x91\xd0\xb3\xc7\x91\xb7\x79\x71\x9f\x7d\x1f\x10\xaa\xf2\x3d\x4c\x0a\xd9\x4b\xdc\x71\x66\x42\xeb\xde\x99\xf9\x19\x25\xf8\x9b\x1a\x43\x8d\x6e\xe4\x15\x49\x2d\x7c\xac\x2a\x75\xce\xdf\x9d\x92\x72\xae\x27\x26\x91\xf5\x3e\xad\x05\x25\x29\xcc\x33\x59\x4c\x93\x16\x26\x09\x7c\x85\xc1\x03\x7e\xc4\x32\x86\xae\x41\x95\xaa\x88\x41\x95\x59\x87\x7d\xa7\x0b\xb7\x7d\xd7\x36\x17\x03\x23\xb3\xbf\x4b\x1d\x8b\x3b\xce\x57\xd2\x21\x5c\xa2\xf0\x49\x5c\xde\xe0\x47\xe5\x03\x71\x87\x18\xb3\x51\x1e\x41\x85\x27\x1e\xee\x24\xb6\xda\x6e\xef\x2e\xf6\x64\xec\x53\xe6\xbc\x6c\x12\x5b\xb6\x2d\x8e\x24\x3d\x78\x25\x82\xd0\x93\xc4\xc5\xdd\x5d\x3a\xf5\x52\xd4\x4e\xe4\x0c\xa7\xdc\x11\xf1\xee\x80\xab\x13\x52\xf2\xcd\xaa\xd0\x6f\x4e\x06\xf0\xdd\xcc\x82\xe4\x30\x10\x2b\xc0\xa3\x53\xa9\x4f\xfd\xa6\x16\x9e\xe9\x27\xf9\x60\xaf\xd6\xa5\x25\xe3\x0e\x87\x03\xdc\xb9\xd4\xa1\x65\x98\x93\xc4\x90\x8f\x6f\x44\x4b\x68\xf1\xc6\xa4\x26\x5c\xbf\xf3\xd7\x4e\xcd\x2e\x0b\x09\x0f\x4f\xdb\x61\x44\x17\xcc\x7c\xc0\x36\x73\xa1\x6b\x5f\xfc\xd0\xe7\x98\x19\x83\xa3\x51\xf6\x3c\x47\xd2\x73\xca\x39\xa7\x67\x42\x00\xa3\x87\xb1\x3d\x0d\x69\x37\x4c\x31\x75\x99\xc9\xb4\x79\xc4\xe3\x8e\x03\xc3\xf5\xcd\x43\xc2\xc1\x07\xbe\x6c\x10\xc3\xcd\xe2\x71\x5e\xc0\x79\xa1\x1c\x41\x71\x74\x99\xd4\x5f\x05\x50\x1e\x61\xab\x1c\x18\xb9\x83\xcf\x42\xb2\x65\x19\x0f\x5c\x13\xed\x3e\xd3\xa4\x92\x9e\xf3\xb2\x49\xcf\x44\x09\xe5\xc5\xc2\xdf\x4f\x38\x7b\x22\xbf\x2e\x40\xe0\x7c\xbe\xb3\xbf\xf2\x88\x9f\xfa\x74\x90\xdc\x4f\xc5\xd5\xf6\x13\xd4\xf4\xb5\x93\x98\x1a\x89\xbd\x85\x76\xd9\xb7\x8f\x4b\xe6\xd1\xd0\xe3\xd2\xc2\x2c\x92\xbf\x18\x32\x16\x1e\x26\x91\x60\xe3\x51\x6f\x31\xa6\xe0\x0c\x0f\x27\xf0\xc3\x44\xad\x39\x57\x84\xe0\x22\x5e\x98\x71\x9e\x63\xd4\xef\xcd\xa2\xcf\x09\x67\x0f\xa2\xce\xe0\xda\x29\x04\x0d\x5e\x87\x7e\x3e\x44\xe0\x0c\x3f\x4f\x1c\x7d\xc4\xd2\x76\xf0\x79\x39\x14\x2e\x69\x3d\x88\xb5\x50\xba\xcb\x4d\x99\x67\x27\x2f\xdf\x61\x72\x29\xff\x5e\xf8\xfb\x54\x0d\xaf\xb4\x5d\x0a\x3d\x83\xd6\xea\x6d\x63\x5d\x5b\xab\x12\x14\xc5\xd6\x66\x67\xb6\x45\x6b\x68\xe3\x52\xab\x52\x6f\x47\x58\x31\x96\x17\x04\xe0\xe3\x7d\xd1\x09\xba\x7f\xca\x13\x9e\xdd\xfc\x70\x18\xe2\x04\x87\x78\x16\x82\x6f\xa5\x7c\xe2\x40\x7f\x1f\x4c\xec\x23\x50\x3e\xb7\xb1\xb9\xd6\xf4\x10\x53\x5f\x7f\x6d\x95\x84\x8d\x53\x3c\xce\x52\xf2\xe8\x19\x44\xb3\x68\x84\xf3\xb5\xd0\x9a\x7b\xf2\x7c\x85\xc9\x4a\xcf\x1d\xef\x56\x38\x8f\x50\xa2\xe3\xd0\x9e\xaf\x31\xd3\x8d\x20\x01\xc9\xb7\x81\x7c\xee\x0f\xca\xc8\x74\xdb\x29\xed\xc6\x78\x25\xb1\xbf\xcf\x17\x6d\xeb\xac\x28\x6b\x50\x7c\xa7\x28\x46\xb7\xd0\xe9\xf6\x98\xb2\x7b\xbe\x30\x16\xeb\xfe\xb2\x34\xe7\xbf\x08\x9e\xb4\xff\x1f\xde\x26\x3b\xf0\x14\x4d\x55\x87\xe4\x12\x4b\xdb\x74\xf7\x9e\x36\xfa\x7e\x22\xab\xab\x1b\x98\x00\xc7\xf7\x8b\x8d\x5a\xd5\x01\x1c\xae\x95\x57\x61\x1f\xb1\x71\x53\xbd\x33\x7b\x5e\xd2\x9d\x60\x40\x79\x1f\x8f\x16\x1f\x53\x62\xe6\xa9\x51\x93\x23\xe2\x1e\x45\x74\xd1\xb6\xfd\x85\x57\x46\xd7\x52\x3d\x44\x35\xb1\xc3\xd6\xce\x3a\x9a\xfb\x9b\x15\xbe\xc9\x75\x58\xa2\x39\x15\x98\x26\x39\x75\x69\xcd\xc9\x30\x7f\xbe\xf6\xa2\xa7\x12\x41\xe8\xcf\x07\xd3\xd5\x8a\xa7\x9a\x40\x30\x95\x32\xbb\xeb\xb9\x2e\x91\x4c\x07\xe2\x72\xf1\x80\x35\xc7\xc2\xe0\x64\x42\x5a\x51\xde\x8b\xd5\x49\x86\xec\x10\x80\x8a\x4b\x6c\xc2\xad\xdb\xcb\x06\x36\x4b\xb7\xd2\xfd\xbb\xca\x6a\x89\x8e\xaa\x72\x61\xe0\xc3\xdb\x97\x3c\xf1\x90\xbf\x05\xe1\x96\x42\xeb\xa2\x1b\x35\xe8\x39\x31\x6e\xd2\xcc\x78\x6e\xb4\x0c\x3a\x75\x00\x1d\x7a\xab\xd7\x98\x3b\x04\x09\x4e\x37\x05\xe1\xc8\x6b\x8c\x2e\xc0\x7a\x1f\x90\x37\xc9\xe1\x04\x42\xf5\x54\xb6\x32\x91\x67\xb9\x56\xff\x6c\x35\xea\x21\xbd\x50\xc7\x7b\x60\x0f\x64\x30\xbe\xfb\xdc\x6d\x15\x7d\xc9\xd3\x0c\x43\x23\xe9\xae\xfb\xec\xef\xb2\x44\xbe\x4a\x03\x85\xdd\xf5\x07\xc2\xd7\xad\x70\x68\xc2\xd7\xc3\x78\x58\x9a\x5a\x0a\x5c\x19\x0c\x6d\x09\x86\xdf\x0d\x96\xb5\xb6\x8d\x7c\x2a\x43\x28\x6b\xa5\xe5\xd7\x7d\xa7\xa2\xa0\x48\x53\xf4\xfd\xf5\x43\x21\xf5\xd3\x98\xa4\x8e\x77\x19\x60\x5a\x3a\xbf\x9b\x29\xa9\x16\xf3\x60\x60\x1a\x14\x4a\x59\x9d\x48\x24\x76\xd4\xa7\x1e\x13\x2f\xee\xf2\x8b\xae\x2e\xe3\x51\x98\x7c\x67\x24\x4f\x9e\x3b\xbd\x26\x42\xb3\x3e\xa7\x03\xe9\xf9\x84\x8a\xa4\xfa\xb5\x01\xde\xe3\x99\x02\xe3\x53\xe1\x9d\xc8\x9c\x2e\x00\x38\xb1\xa6\x9a\x54\x47\xc0\xc4\xd2\xab\xb5\x27\x29\x98\x84\x7b\x3f\x95\xfc\x99\x5a\x3e\x91\x51\xbf\x2a\xfd\x1b\x61\xc2\xf7\x6e\x82\x27\x3c\x1d\x9e\xcf\x88\xee\xc2\xae\x5e\xef\xfd\x2e\xef\xec\x9d\xe4\xe9\x6e\x8e\xdd\x1d\x96\x4a\x91\xae\xd3\xe3\x86\x89\xaa\x60\xe1\x3f\xbf\xfb\xdb\xcb\x01\x2d\xd8\x73\xd7\xc3\x87\x1c\x3e\xc9\xd5\xd0\x8b\xd1\xdc\x96\xcc\x13\xe1\x54\xac\x1c\x9b\xdc\x3d\xc8\xa8\xd8\xae\x9c\x90\x24\xf8\x17\xce\x1e\xb8\x86\xda\x21\xe6\xc3\xce\x62\x26\x26\x55\x0d\x7b\x25\x9b\x1f\xe6\x8e\x13\x7c\xec\xa7\xe7\x7e\xa5\xe2\xee\x71\x92\xf8\x71\x92\xf8\x71\x92\xf8\x71\x92\xf8\x71\x92\xf8\x71\x92\xf8\xb3\x27\x89\xcf\x67\xe4\xe7\xa6\x89\x3f\x77\x9e\x78\x42\x96\x76\x66\xa6\xf8\x71\xaa\xf8\x71\xaa\xf8\x9f\x69\xaa\x78\x82\xc6\x9f\xaa\x03\xff\x19\x66\x8b\x3f\xb3\xcf\xff\x07\x9c\x30\x9e\x48\xd1\x89\x29\xe3\x3f\xec\x9c\xf1\xa4\x49\xa6\x09\xb3\xc6\xff\x7f\xa6\x8d\x27\x70\xec\xe8\xc4\xf1\x1f\x70\xe6\xf8\xb7\x9a\x21\x5a\x7f\xf2\x1f\x04\x1f\xfb\x1b\xe7\x20\x42\xf4\x9f\xf0\x57\xce\xbc\x7e\xe7\xef\x9c\xed\xd2\xa3\x5b\x4f\xfe\x43\xe7\x83\x88\x3c\x78\x99\x40\x8e\xda\x46\x3e\x58\xaa\x8d\xf3\x9b\x01\x6d\xca\x0f\xda\x80\xf2\xd5\xfe\x3f\xf7\x70\x9d\x86\x0b\xbb\x7f\xbf\x81\x7f\x96\xd6\xa4\x56\x8c\xbf\x81\x1f\x7f\xba\x82\xdc\x66\xed\x1a\x0c\xfc\xf2\x7f\x03\x00\x00\xff\xff\xf3\x7d\xfe\x4e\x21\x43\x00\x00") +var _configCrdsKudoDev_operatorversionsYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x3c\x6b\x8f\x1b\x37\x92\xdf\xe7\x57\x14\x26\x1f\x9c\x04\x52\x6b\x9d\xec\xe2\x0e\xf3\x2d\x6b\x27\x87\xb9\x78\x6d\xc3\x8f\x3d\x1c\x72\x01\x86\x6a\x96\xd4\xdc\x61\x93\x3c\x3e\x24\xeb\x82\xfc\xf7\x43\x15\xd9\xad\x96\x46\x8f\x1e\x39\xce\x65\x71\xee\x2f\x89\xba\xc9\x62\xbd\x5f\xac\xf1\xd5\x74\x3a\xbd\x12\x4e\xfd\x1d\x7d\x50\xd6\xdc\x80\x70\x0a\x3f\x44\x34\xf4\x2b\x54\xf7\xff\x1a\x2a\x65\x67\xab\xa7\x57\xf7\xca\xc8\x1b\x78\x96\x42\xb4\xed\x1b\x0c\x36\xf9\x1a\x9f\xe3\x42\x19\x15\x95\x35\x57\x2d\x46\x21\x45\x14\x37\x57\x00\xc2\x18\x1b\x05\xbd\x0e\xf4\x13\xa0\xb6\x26\x7a\xab\x35\xfa\xe9\x12\x4d\x75\x9f\xe6\x38\x4f\x4a\x4b\xf4\x0c\xbc\x3b\x7a\xf5\xa7\xea\xcf\xd5\x9f\xae\x00\x6a\x8f\xbc\xfd\x9d\x6a\x31\x44\xd1\xba\x1b\x30\x49\xeb\x2b\x00\x23\x5a\xbc\x01\xeb\xd0\x8b\x68\x7d\xd9\x19\xaa\xfb\x24\x6d\x25\x71\x75\x15\x1c\xd6\x74\xe6\xd2\xdb\xe4\x6e\xa0\x7f\x9f\x77\x16\x74\x32\x29\xaf\x0a\x90\x42\x39\x7f\xd1\x2a\xc4\x1f\x0f\x7d\x7d\xa1\x42\xe4\x15\x4e\x27\x2f\xf4\x43\x14\xf8\x63\x50\x66\x99\xb4\xf0\x0f\x3e\x5f\x01\x84\xda\x3a\xbc\x81\x97\x84\x86\x13\x35\xca\x2b\x80\x6e\x33\xa1\x35\x2d\xb4\xad\x9e\xce\x31\x8a\xa7\x19\x5e\xdd\x60\x2b\x32\xd2\x40\x30\xcd\x77\xaf\x6f\xff\xfe\xed\xdb\x9d\xd7\x00\x12\x43\xed\x95\x8b\xcc\xc4\x3d\xc4\x41\x05\x88\x0d\x42\xde\x03\x0b\xeb\xf9\xe7\x3e\xfa\xf0\xdd\xeb\xdb\xaa\x07\xe8\x3c\x7d\x8f\xaa\x63\x58\x7e\x06\x5a\x32\x78\xbb\x77\xfc\x13\xc2\xb0\x1c\x2d\x49\x3d\x30\x9f\x5f\x0e\x42\x59\x88\x02\xbb\x80\xd8\xa8\x00\x1e\x9d\xc7\x80\x26\x2b\x0c\xbd\x16\x06\xec\xfc\x1f\x58\xc7\x0a\xde\x22\x63\x08\xa1\xb1\x49\x4b\xd2\xa3\x15\xfa\x08\x1e\x6b\xbb\x34\xea\x7f\x7a\x68\x01\xa2\xe5\x63\xb4\x88\x18\x22\x28\x13\xd1\x1b\xa1\x61\x25\x74\xc2\x09\x08\x23\xa1\x15\x1b\xf0\x48\x70\x21\x99\x01\x04\x5e\x12\x2a\xf8\x9b\xf5\x08\xca\x2c\xec\x0d\x34\x31\xba\x70\x33\x9b\x2d\x55\xec\x2c\xa0\xb6\x6d\x9b\x8c\x8a\x9b\x19\x2b\xb3\x9a\xa7\x68\x7d\x98\x49\x5c\xa1\x9e\x05\xb5\x9c\x0a\x5f\x37\x2a\x62\x1d\x93\xc7\x99\x70\x6a\xca\xc8\x1a\xb6\x82\xaa\x95\x5f\xf8\x62\x33\xe1\xc9\x0e\xf3\xe2\x86\xb4\x22\x44\xaf\xcc\x72\xf0\x81\x55\xf4\x04\x97\x49\x49\x49\xb4\xa2\x6c\xcd\x54\x6c\x99\x49\xaf\x88\x1f\x6f\xbe\x7f\xfb\x0e\xba\xa3\x33\xc3\x33\x6f\xb7\x4b\xc3\x96\xcd\xc4\x22\x65\x16\xe8\xf3\xca\x85\xb7\x2d\x43\x41\x23\x9d\x55\x26\xf2\x8f\x5a\x2b\x34\x11\x42\x9a\xb7\x2a\x92\xfc\xfe\x3b\x61\x88\x24\x81\x0a\x9e\xb1\xe9\xc3\x1c\x21\x39\x29\x22\xca\x0a\x6e\x0d\x3c\x13\x2d\xea\x67\x22\xe0\x27\x67\x32\x71\x33\x4c\x89\x79\xe3\xd8\x3c\xf4\x5a\xfb\x8b\x33\x9f\x06\x1f\x3a\xdf\x72\x44\x26\x7b\x86\xf7\xd6\x61\xbd\x63\x01\x12\x83\xf2\xa4\xb1\x51\x44\x24\x3d\xdf\xdb\x50\xed\x80\x3e\x6c\x82\xd9\x0c\xdd\x41\x33\x3c\x41\x26\x64\x1f\x6c\xb0\x26\x54\xdf\xf2\xe7\x87\x9b\x77\xa8\x79\xb6\xb7\xbc\x27\x45\x40\xc4\xd6\x91\x9d\xc9\x4e\xf7\x62\x23\x22\xd4\xc2\xb0\xdc\x03\x4a\x32\xc6\x72\x1c\xfd\xaf\x30\xa0\x4c\x88\xc2\xd4\x98\xad\x1e\x7b\xd2\xab\xc7\x50\xc0\x3e\xfd\x01\x3b\x00\x54\xc4\xf6\xc0\xeb\x53\x3c\x7c\x48\xf0\xc1\x05\x27\xd1\x29\x30\x54\x70\x5a\x6c\xc8\xad\x5f\x0c\xc3\x7c\xcc\x66\xe7\x95\x3d\xbd\x99\x9c\xe1\x12\xfd\x81\x35\x47\x14\x7d\xf8\x51\x78\x2f\x36\x7b\xdf\xba\xe0\x71\x46\x85\x9e\xbc\x62\xc0\x6f\x70\x81\x1e\x49\xf8\x64\xd4\x42\x99\x00\x68\x6c\x5a\x36\xec\x07\x7c\x9b\xfd\x7e\xb4\xa0\x31\xc2\xc6\x26\x52\x16\x47\xaa\x63\x3d\xb4\x56\xaa\xc5\x86\x55\xc6\x13\x18\xb2\x9f\x2e\x36\x4c\xa7\x53\x78\x89\x6b\xd2\xb8\xd0\x47\x13\x42\x1a\x84\x47\x92\x4b\x6d\x93\x17\x4b\x94\x30\xc7\x5a\xa4\xc0\xca\x27\xd5\x62\xa1\xea\xa4\xe3\xa6\xe0\x3a\x27\x05\x26\x3f\x96\x82\x58\x22\xac\x1b\x34\x80\xed\x1c\xa5\x44\x09\xca\x50\x5c\x0c\x15\xc0\xd3\x0a\x6e\x97\xc6\xd2\xf9\x0b\x85\x5a\xd2\xbb\x5b\x8a\x33\xb5\x4e\x12\xc9\x73\x9a\x4d\xf9\x02\xeb\x46\xd5\x0d\x23\x41\xbe\x70\x89\x06\xbd\xd0\x7a\x03\x8d\x65\x00\x15\xc0\x0f\xd6\xf7\x26\x31\x81\x2e\x9b\xea\xc2\x26\x05\xab\x1f\x08\xd4\x6b\x11\x33\x9c\xb9\x8d\x0d\x45\xd0\x0d\x78\xe1\x51\x6f\xc8\xdb\x2b\x46\x4f\xd4\x31\x09\x9d\x91\xaf\x00\xbe\x21\x7f\x9b\x3f\x66\x7a\x1a\xd4\xae\xa0\x1a\x40\xb5\xce\x86\xa0\xe6\x1a\xd9\x2c\xa5\x64\x97\xa6\x16\xaa\xe6\x75\x9c\x1c\x28\x23\xd5\x4a\xc9\x21\xd0\x5b\x03\xad\x0d\x71\xcb\x16\xfe\x10\x26\x24\x16\x9f\xb9\xed\x84\x8f\xc4\x56\xe1\x59\x0d\x3c\x92\xc2\xb2\xf7\x08\xa0\xd5\x3d\x4e\xe0\xba\x4d\x21\x66\x21\x82\x35\x7a\xc3\x01\x9b\xbc\x35\x7c\xc7\x04\xff\xf5\x9a\xe4\x7d\xfd\xfe\xf6\x39\x73\xad\xf0\x2a\xbf\x24\xfb\x00\xde\x3f\xc7\x1e\x36\xca\xeb\x8a\x0f\x7b\xd7\xd8\x80\xe4\x7e\x4a\xe4\x59\xa3\xd6\x9d\x70\x51\xee\x4a\xb4\x02\xf8\x96\x58\x54\x5b\x13\x54\x88\x14\xc7\x98\x5b\xac\x83\x15\xc0\x5f\x8b\xa6\x90\xc2\x65\x2a\x8b\x32\x2d\x58\x87\xe3\x24\xe7\x32\xfd\x16\xf0\x49\xef\xaf\x81\xf9\x26\xef\x9d\x14\x4d\x68\xc5\x3d\x06\x50\x11\x1a\xe1\x25\x33\x39\x05\x8a\xb6\xd1\x82\xf3\x28\x55\x1d\x61\x4d\x1e\x74\xad\xb4\x86\x46\x38\x87\x84\xca\x9f\x2b\x78\xd7\x60\xa7\x53\xbd\x16\xa8\xd6\x79\xac\x55\x40\xe6\x9a\x5d\xa1\xd7\x1b\x28\xaf\x2a\x80\x2e\x2f\x20\x5e\x88\xee\x3d\xb4\xc2\x39\x76\xd4\x16\x04\xbc\x7f\xf3\x82\x40\xab\xc0\x2e\xdb\x79\x2b\x53\x8d\x20\xda\xb9\x5a\x26\x15\x37\xd9\x8e\x13\x3b\x76\x4e\xa3\x9c\xc7\x92\x9b\xd1\x89\x14\xee\x15\x49\x3d\xa7\x16\x05\xf2\x40\x4b\x6a\x11\x8a\x6e\x80\x44\x87\x46\xa2\xa9\x37\x84\x12\x19\x79\x83\xd9\x8b\x4f\xb6\x29\x49\x72\x1a\xf9\x4c\x82\x3e\xc8\x14\xbb\x50\x51\x34\x3c\x44\x9f\xea\xac\xc5\xde\xa3\xc6\x95\x30\xb1\x02\xf8\x4b\x05\xff\xd1\x0b\x1f\x45\x50\x7a\x03\x75\x23\xcc\x12\x41\xc5\x1d\x81\x76\xce\x41\x85\x1d\xfb\x66\xc3\xd5\xb6\xce\xe5\xca\xa4\xe4\x2d\x25\x9f\xec\xf6\xd0\xc3\xd2\x11\x8b\x05\x79\x26\x93\x5a\xf4\x36\x85\x2e\xfb\xac\x00\x9e\x5b\xf3\xe4\x49\x64\x59\x83\xc1\x35\xfb\x8d\x7c\x10\xc5\xbf\x64\x24\xfa\x62\x6c\x28\xe9\x63\x06\x1c\x1b\xdc\x80\xb4\x2c\xae\x52\x24\x91\x7a\x86\x88\x42\x12\x03\x52\xc8\xf1\xb5\x20\x32\xc9\x95\x11\x71\x9f\x50\xd6\x2c\x7a\xbb\x52\x92\x4f\x91\x25\xf8\x66\xc0\x82\x99\x45\xc6\x30\x5d\xd8\x9a\xbf\x58\x43\xfe\xd5\x67\x2b\x24\x8f\x5c\xb1\x27\xc2\x0f\xa2\x75\x1a\x27\x9c\x06\xaa\x1a\x7b\x87\x1d\x58\x59\x85\x6c\x55\x60\x89\x78\x5c\xaa\x10\xbd\xc8\xee\x7d\x90\xbf\x35\x69\x5e\xd5\xb6\x9d\x51\x61\xe7\x0d\x46\x0c\x94\x9c\xcd\xe6\xda\xce\x67\x24\x2c\x11\x70\xfa\xb4\x7a\xfa\x2f\xb3\x1e\xd6\x10\xd4\x6c\xf5\x74\xc6\xae\xa0\x5a\xda\x2f\x5e\xfc\xe5\xdb\x6f\xa1\x7a\xf2\x20\xb2\x9c\x8e\xe5\xc7\x4a\x93\x83\x71\x89\xb8\xbf\xa7\x64\x85\x23\xf1\x61\x3e\x02\xe7\x63\xf0\xa2\xf3\xd5\x23\xce\x7e\x72\xbb\x28\x91\xac\xb7\x47\xa7\x30\x27\x46\x7d\xdd\xc3\xb1\xa1\x68\x80\x30\x40\xf9\xad\xc7\xf2\x6d\x92\xb5\xa1\x64\x5e\xdb\xba\x88\x02\x2b\x88\x12\x18\xfe\xfd\xed\xab\x97\xb3\x7f\xb3\x19\x33\x10\x75\x8d\x21\xe4\xbc\xb3\x65\x27\x16\x12\x05\xa8\xd0\xa5\xa4\x6f\xe9\x4b\xd5\x0a\xa3\x16\x18\x62\x55\xa0\xa1\x0f\x3f\x7d\xf3\xf3\x9e\x8a\xa8\xcc\xaf\xbe\x86\xe8\x42\xbb\x0a\x99\x98\x7e\x2f\xac\x55\x6c\x18\x25\x67\x65\x41\x7a\xcd\xc8\x46\x32\x11\x5b\x90\x4d\xc8\xf1\xe1\x06\xae\xc9\x3a\x06\x47\xff\x42\x4e\xff\xd7\x6b\xf8\x72\xcd\x41\x86\x63\xc0\x75\x3e\xb0\x2f\xf6\x38\x2e\x14\x09\x6e\x0f\x66\xd5\x8f\x5e\x2d\x97\x48\xe1\x9a\xeb\x17\xaa\x11\xbe\xa2\x58\xa2\x16\x60\xec\x60\x31\x83\x20\x7e\xf6\xb6\xb9\x8f\xc8\x4f\xdf\xfc\x7c\x0d\x5f\xee\xd2\x45\x51\x12\x3f\xc0\x37\xe4\x40\x98\x32\x67\xe5\x57\xc5\xa9\x86\x8d\x89\xe2\x03\xc1\xac\x29\x30\x99\x3e\xda\x35\x62\x85\x10\x6c\x9b\x23\xd4\x34\xe7\xd3\x12\xd6\x62\x43\x34\x74\xac\x24\xa9\x0a\x8e\xa7\x7b\xa5\xf0\xbb\x57\xcf\x5f\xdd\xe4\xd3\x48\x6c\x4b\xd3\xb9\xf9\x85\xa2\x42\x37\x7b\x4f\x2a\xda\x58\xe6\x84\x48\xca\x42\xa2\x64\xbc\x78\xc4\xec\x81\x17\x89\xca\xa7\x03\x36\x36\x42\xd7\x1f\xd6\xa5\x87\xd5\x9c\xe3\xd0\xbe\x71\xfd\x9f\x55\x7f\x23\x89\x3b\x9e\x87\xef\x12\xf7\x72\xa0\x77\x27\x89\xdb\xfa\x43\xa2\x4f\xda\x3a\x10\x69\x35\xba\x18\x66\x14\xba\x57\x0a\xd7\xb3\xb5\xf5\xf7\xca\x2c\xa7\xa4\x58\xd3\x2c\xed\x30\xe3\x6e\xd5\xec\x0b\xfe\xcf\xc5\xb4\x70\x9f\x69\x2c\x41\xbc\xf8\xf7\xa0\x8a\xce\x09\xb3\x8b\x88\xf2\xbb\x99\xf2\x18\xd2\xde\x76\x19\xee\xde\x5e\x32\x8b\x9c\x9e\x95\x2e\xd4\xc0\x93\xb5\x42\x66\x57\x27\xcc\xe6\x93\x2b\x2d\xb1\x2e\x79\x3a\x7b\x33\x2d\x29\xc0\x54\x18\x39\xed\x53\xd4\x7a\x73\x11\xaf\x92\x1a\x65\xa8\x94\x70\xff\x2e\xaa\x9c\xd4\x45\x56\x79\xa2\x44\x75\xc2\x8b\x16\x23\xfa\xc7\xf4\x04\x76\xa8\x7f\xdd\x41\x80\x5a\x38\x12\x50\xe9\x55\x0a\xaf\xc4\x5c\x69\xca\x86\xb3\x13\xde\x6f\xaa\xce\x31\xa7\xc7\x54\xc2\x45\xc5\xbd\x10\x8a\x75\xdb\x46\xc7\xa1\x44\xe2\x5c\x3b\x42\xc8\x15\x6d\x3d\x22\xb6\x8e\x15\x73\x6b\x35\x0a\x73\x44\xb4\x0b\x91\x74\x3c\x06\x60\x87\xf6\xe7\x79\x6d\x6e\x22\x96\x8d\x25\x22\xe7\x20\xd9\xb3\x97\x96\xf4\x69\xe6\x3c\x57\xe3\xa7\xe8\x84\x51\x7d\x93\xf3\xbd\x97\x3d\x74\xfb\x1f\x5b\x61\x51\x1a\x6c\x96\xe8\x87\x4b\x49\x62\x8d\x5d\x33\x96\x5b\x12\x38\x7b\x2f\xed\xa9\xcb\x71\x3e\xdf\xeb\xd9\xc5\x79\xbb\x7e\xa7\x3d\x36\xdf\xc0\xfb\xdb\x70\x31\x1a\x68\x52\x3b\x56\xc4\xa5\x65\xa7\x55\xc8\xf9\x84\xd6\x76\x3d\xe8\x79\xdf\x2e\x86\x7a\x10\x30\x72\x1e\xf1\xbd\x49\x6d\x97\x5d\x18\xa5\xfb\xa2\x37\x6d\xab\xf0\x2e\xf1\x61\xc0\x22\xd7\x19\x47\x50\x3a\x6a\x8a\x23\xc9\x3d\xd5\x89\xca\x4f\xbe\xec\xb9\x94\x9d\x8d\x32\x47\x2d\xe6\xec\x66\xd5\xb6\x29\x8a\xb9\x1e\xa7\x10\x25\x18\x61\xe8\xf2\x68\x37\x70\x40\xac\x1f\x39\x53\x93\x20\x16\x11\x7d\xb1\x34\x15\x95\xd0\xd9\xe2\xb4\xee\x6f\x49\x86\xb7\x38\x17\x3b\x8c\x53\x9d\xc7\x1d\xcc\xaf\x5f\x96\x44\x99\x8e\x1d\xb6\x7d\x4b\x05\xd2\xa9\x76\x49\x31\xbb\x16\x31\x2c\x94\x46\xae\x22\x87\x15\xc4\x5d\xbe\xe9\x7a\xf6\xea\xfd\xcb\x77\x77\xb4\xde\xf4\x85\x6e\xe7\x7c\x35\xab\x98\xe0\xbc\xbc\x54\x08\xff\x65\x72\x07\x9e\xf3\x00\xa7\x55\x2d\xc2\x0d\xc0\x2f\xbf\x40\xc5\x6e\x3c\x54\x0c\x0f\x7e\xfd\xf5\xfa\x52\x61\x96\xde\xc6\x51\x07\xbc\xc3\x91\x37\x65\x71\x5f\x3a\x1c\x10\xaa\x0a\x3d\x4c\xca\x37\xe6\xb8\xe3\x47\x85\xd6\xbd\x1f\x0d\x13\xaa\x4e\xd6\x0d\xc6\x06\xfd\xc0\x21\x93\x5a\x84\xb4\x58\xa8\x73\xae\xf6\x94\x94\x4b\x31\x34\x8a\xac\x77\x79\x2d\x28\x49\x39\x0a\x93\xc5\x34\x69\x61\xb2\xc0\x97\x18\x03\xe0\x07\xac\x53\xec\xba\x6b\xb9\x04\xda\xaa\x32\xeb\x70\xe8\x74\xe1\xb6\xef\xfd\x97\x4a\x66\xe0\x71\xee\x72\xbb\xe5\x8e\x93\xad\x7c\x08\xd7\x57\x7c\x12\xd7\x66\xf8\x41\x85\x48\xdc\x21\xc6\xac\x55\x40\x50\xf1\x49\x80\x3b\x89\x4e\xdb\xcd\xdd\xc5\x4e\x94\xdd\xd9\x94\x97\x8d\x62\xcb\xc6\xe1\x40\xd2\x5b\x87\x48\x10\x7a\x92\xb8\x32\xbd\xcb\xa7\x5e\x8a\xda\x85\x3d\x79\xe2\xdd\x01\x2f\x2b\xa4\xe4\xfb\x79\xa1\x5f\x9f\xcc\x3e\x76\xd3\x22\x92\xc3\x96\x58\x01\x01\xbd\xca\x4d\xf6\xd7\x8d\x08\x4c\x3f\xc9\x07\x7b\xb5\xae\x2d\x19\x77\x3c\x1c\x5b\xcf\xe5\x3d\x8e\x61\x8e\x12\x43\x39\xbe\x15\x8e\xd0\xe2\x8d\x59\x4d\xb8\xf9\xc0\x5f\x3b\x35\xbb\x2c\x1a\x3d\x3c\x6d\x87\x11\x5d\x1c\x0d\x11\x5d\xe1\x42\xd7\x7b\xf9\xb1\x4f\x90\x0b\x06\x47\x03\xfc\x79\x8e\xe4\xe7\x94\x73\xce\xcf\x88\xd8\x49\x0f\x63\x7b\x1a\xd2\x6e\x98\x62\xea\x0a\x93\x69\xf3\x80\xc7\x1d\x07\xb6\x97\x80\x0f\x09\x87\x10\xf9\xa6\x44\x6c\xef\xa7\x8f\xf3\x02\xce\x0b\xe5\x08\x8a\x83\x2b\xc9\xfe\x1e\x83\x52\x18\xbb\x28\x81\x91\xaf\x1f\x58\x48\xb6\xae\xd3\x81\xcb\xc6\xdd\x67\x9c\x54\xf2\x73\x5e\x36\xf9\x19\x29\xa1\xb2\x58\x84\xfb\x11\x67\x8f\xe4\xd7\x05\x08\x9c\x4f\xb5\xf6\x57\x1e\xf1\x53\x8f\x07\xc9\xcd\x60\x5c\x6e\x1e\xa1\xa6\xaf\xbc\xc4\xdc\x05\xed\x2d\xb4\x4b\xfc\x43\x9a\x33\x8f\xb6\x0d\x3a\x2d\xcc\x2c\xfb\x8b\x6d\xc6\xc2\x23\x49\x12\x6c\x3a\xea\x2d\x86\x14\x9c\xe1\xe1\x08\x7e\x98\xa4\x35\xe7\x8a\x10\x7d\xc2\x0b\x93\xdd\x73\x8c\xfa\xbd\x59\xf4\x31\xe1\xec\x41\xd4\xd9\xba\x76\x0a\x41\x5b\xaf\x43\x3f\x1f\x22\x70\x86\x9f\x27\x8e\x3e\x62\x69\x3b\xf8\xbc\xd8\xd6\x4c\x79\x3d\x88\x95\x50\xba\xcb\x4d\x99\x67\x27\x47\x38\x60\x74\x1f\xe2\x9d\x08\xf7\xb9\x10\x5f\x6a\x3b\x17\x7a\x02\xce\xea\x4d\x6b\xbd\x6b\x54\x0d\x8a\x62\x6b\xbb\x33\x21\xa5\x35\xb8\x34\xd7\xaa\xd6\x9b\x01\x56\x8c\xe5\x05\x01\xf8\x78\x53\xf7\x53\x0f\x2f\x3c\x1c\xa9\x39\xc1\x21\x9e\xa8\xe1\x2b\xb5\x90\x39\xd0\x5f\x66\x13\xfb\x08\x54\x28\x3d\x78\x2e\x73\x03\xa4\x7c\x29\xb1\xb2\x4a\xc2\xda\x2b\x1e\x8a\xaa\x79\x80\x11\x92\x99\xb5\xc2\x87\x46\x68\xcd\x17\x0a\x7c\xff\xca\x4a\xcf\xed\x7a\x27\x7c\x40\xa8\xd1\x73\x68\x2f\x77\xb0\xf9\x3a\x93\x80\x94\xab\x4c\x3e\xf7\x47\x65\x64\xbe\xaa\x95\x76\x6d\x82\x92\xd8\x0f\x23\x08\xe7\xbc\x15\x75\x03\x8a\x2f\x44\xc5\xe0\x0a\x3d\x5f\x7d\x53\x76\xcf\xb7\xdd\x62\xd5\xdf\xf4\x96\xfc\x17\x21\x90\xf6\xff\x23\xd8\x6c\x07\x81\xa2\xa9\xea\x90\x9c\x63\x6d\xdb\xee\xd2\xd6\xa6\xd0\xcf\xf5\x75\x75\x03\x13\xe0\xf9\x72\xb4\x55\xcb\x26\x82\xc7\x95\x0a\x2a\xee\x23\x36\xbc\x11\xe8\xcc\x9e\x97\x74\x27\x18\x50\x21\xa4\xa3\xc5\xc7\x98\x98\x79\x6a\x60\xe9\x88\xb8\x07\x11\x5d\x38\xd7\xdf\xd6\x15\x74\x2d\xd5\x43\x54\x13\x7b\x74\x76\xd2\xd1\xdc\x5f\x0b\xf1\x35\xb4\xc7\x1a\xcd\xa9\xc0\x34\xca\xa9\x4b\x6b\x4e\x86\xf9\xf3\xb5\x17\x3d\x0b\x11\x85\xfe\x78\x30\x5d\xad\x78\xaa\xff\x04\x63\x29\xb3\xbb\x9e\xeb\x12\xc9\x74\x20\x2e\x17\x0f\x58\x73\x2c\x0c\x8e\x26\xc4\x89\xfa\x5e\x2c\x4f\x32\x64\x87\x00\x54\x5c\x62\x13\x6e\xdd\x5e\x36\xb0\x49\xbe\x52\xef\xdf\x2d\xac\x96\xe8\xa9\x2a\x17\x06\xde\xbf\x79\xc1\xe3\x1a\xe5\x5b\x14\x7e\x2e\xb4\xae\xba\x39\x89\x9e\x13\xc3\x26\xcd\x84\xa7\x8f\xeb\xa8\x73\xf3\xd1\x63\xb0\x7a\x85\xa5\x43\x90\xe1\x74\x23\x1c\x9e\xbc\xc6\xe0\xf6\xae\xf7\x01\x65\x93\xdc\x9e\x40\xa8\x9e\xca\x56\x46\xf2\xac\xd4\xea\x1f\xad\x46\x3d\xa4\x1f\xd4\xf1\x1e\xd8\x03\x19\x0c\x2f\x6e\x77\x5b\x45\x5f\xf2\x28\xc6\xb6\x91\x74\xd7\x7d\x0e\x77\x45\x22\x5f\xe5\xb1\xd4\xee\xee\x06\xe1\x6b\x27\x3c\x9a\xf8\xf5\x76\xc8\x30\x8f\x5c\x45\xae\x0c\xb6\x6d\x09\x86\xdf\x8d\x27\x3a\xeb\x12\x9f\xca\x10\xea\x46\x69\xf9\x75\xdf\xa9\xa8\x28\xd2\x54\xfd\xe5\xc0\xa1\x90\xfa\x38\x26\xa9\xe3\x5d\x06\x18\x97\xce\xef\x66\x4a\xca\x61\x19\x2f\xcd\x53\x4e\x39\xab\x13\x99\xc4\x8e\xfa\xdc\x63\xe2\xc5\x5d\x7e\xd1\xd5\x65\x3c\xc7\x53\x2e\xbc\xe4\xc9\x73\xc7\xd7\x44\x68\x56\xe7\x74\x20\x3f\x8f\xa8\x48\x16\xbf\x35\xc0\x7b\x3c\x53\x60\x3c\x16\xde\x89\xcc\xe9\x02\x80\x23\x6b\xaa\x51\x75\x04\x8c\x2c\xbd\x9c\x3d\x49\xc1\x28\xdc\xfb\xd9\xf6\x8f\xd4\xf2\x91\x8c\xfa\x4d\xe9\x5f\x0b\x13\xbf\xf7\x23\x3c\xe1\xe9\xf0\x7c\x46\x74\x17\x76\xf5\x7a\xef\x77\x79\x67\xef\x24\x4f\x77\x73\xec\xee\xb0\x5c\x8a\x74\x9d\x1e\xbf\x1d\x07\x8b\x16\xfe\xf3\xbb\xbf\xbd\xd8\xa2\x05\x7b\xee\x7a\xfb\xa1\x84\x4f\x72\x35\xf4\x62\x30\x74\x26\xcb\xdf\x15\x50\xb1\x72\x6c\xfe\xfb\x20\xa3\x92\x5b\x7a\x21\x49\xf0\x3f\x78\x7b\xe0\x06\x6c\x87\x98\xf7\x3b\x8b\x99\x98\x5c\x35\xec\x95\x6c\x61\x3b\xbd\x9e\xe1\x63\x3f\xfa\xf7\x1b\x15\x77\x9f\xc7\xa0\x3f\x8f\x41\x7f\x1e\x83\xfe\x3c\x06\xfd\x79\x0c\xfa\xf3\x18\xf4\x47\x8f\x41\x8f\x98\x22\x3a\x33\x0a\xfd\xb1\xc3\xd0\x23\xb2\xb4\x33\x03\xd1\x9f\x47\xa2\x3f\x8f\x44\xff\x33\x8d\x44\x8f\xd0\xf8\x53\x75\xe0\x3f\xc3\x60\xf4\x47\xf6\xf9\xff\x80\xe3\xd1\x23\x29\x3a\x31\x22\xfd\x87\x1d\x92\x1e\x35\xc9\x34\x62\x50\xfa\xff\xcf\xa8\xf4\x08\x8e\x1d\x1d\x97\xfe\x03\x0e\x4c\x7f\xaa\x19\xa2\xd5\xa3\xff\xac\xfc\xd8\x5f\xca\x47\x11\x53\x78\xc4\xdf\xca\xf3\xfa\x9d\xbf\x96\xb7\xf3\x80\x7e\x35\xfa\xcf\xe5\x0f\x22\xf2\xe0\x65\x06\x39\x68\x1b\x85\x68\xa9\x36\x2e\x6f\xb6\x68\x53\x7e\xe0\x22\xca\x97\xfb\xff\x68\xc8\x75\x1e\x2e\xec\xfe\x15\x10\xfe\x59\x5b\x93\x5b\x31\xe1\x06\x7e\xfa\xf9\x0a\x4a\x9b\xb5\x6b\x30\xf0\xcb\xff\x0d\x00\x00\xff\xff\x6e\xb3\x6e\xd3\x67\x45\x00\x00") func configCrdsKudoDev_operatorversionsYamlBytes() ([]byte, error) { return bindataRead( diff --git a/pkg/kudoctl/packages/convert/bindata.go b/pkg/kudoctl/packages/convert/bindata.go new file mode 100644 index 000000000..d14912c2b --- /dev/null +++ b/pkg/kudoctl/packages/convert/bindata.go @@ -0,0 +1,272 @@ +// Code generated by go-bindata. (@generated) DO NOT EDIT. + + //Package convert generated by go-bindata.// sources: +// config/json-schema/full.json +// config/json-schema/limited.json +package convert + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +// Name return file name +func (fi bindataFileInfo) Name() string { + return fi.name +} + +// Size return file size +func (fi bindataFileInfo) Size() int64 { + return fi.size +} + +// Mode return file mode +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} + +// ModTime return file modify time +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} + +// IsDir return file whether a directory +func (fi bindataFileInfo) IsDir() bool { + return fi.mode&os.ModeDir != 0 +} + +// Sys return file is sys mode +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _configJsonSchemaFullJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x58\x4b\x73\xdb\x36\x10\xbe\xfb\x57\x60\x60\x9f\x32\xa6\x25\xf7\x66\x5d\x3a\x9a\xe6\x92\x3e\xa4\x4e\xd2\x5e\xaa\x51\x3a\x10\xb9\xa4\x90\xe2\xc1\x80\x80\x2a\x55\xa3\xff\xde\xe1\x1b\x20\x41\x8b\xb4\xda\xdc\x2c\x60\x1f\xdf\x2e\x76\xbf\x5d\xfa\x7c\x87\x10\x7e\xc8\xc2\x3d\x70\x82\x17\x08\xef\xb5\x4e\xb3\xc5\x6c\xf6\x25\x93\x22\x28\x8f\x9f\xa4\x4a\x66\x91\x22\xb1\x9e\x7d\x37\x7f\x7e\x09\xe6\x2f\xb3\x4a\xfe\xb1\x50\x56\x10\x1a\x95\xd1\x03\x2c\x45\xb8\x97\x0a\x2f\x90\x56\x06\xca\x3b\x1a\xd9\x46\xff\x32\x91\x7c\x8a\xe0\x60\x5b\x0f\x62\xc3\x58\x69\x49\x53\xcd\x20\x97\xff\xe9\xf7\xf7\x6b\xf4\xe3\xa7\xf5\x2a\xf8\x64\x39\xd2\xa7\x34\xbf\xdd\x60\xb9\xfb\x02\xa1\xc6\x8f\x08\xef\xa4\x64\x40\x04\xde\x16\x02\x24\x8a\xa8\xa6\x52\x10\xf6\xab\x92\x29\x28\x4d\x21\xc3\x0b\x14\x13\x96\x95\x70\x52\xfb\x38\x8f\xbc\x81\x58\xfe\x68\x9d\xe0\x4c\x2b\x2a\x92\xc2\x71\x71\x1e\x4b\xc5\x89\xce\x6f\x8c\xa2\x81\x82\x18\x14\x88\x10\x5a\x81\x87\x50\x72\x0e\xa2\x10\x59\x49\x11\x00\x4f\xf5\x09\xc5\x8a\x24\xf9\x69\x86\x84\xd4\x88\x30\x26\xff\x86\xe8\xa9\xd5\x4a\x89\xd6\xa0\x44\xae\xf4\x79\xf3\xf9\x7e\xfb\xee\xfe\xfb\x07\x5c\x5c\x5e\x1e\x2b\x7c\xcd\xdb\x4c\xc3\xd8\xb1\x42\xea\xb7\xb9\x6a\xc5\x81\xb4\x0c\xfe\x20\xc1\x3f\xdb\x4d\x50\xfe\x31\x0f\x5e\x9e\x16\x7f\x6e\xdf\x75\x31\x2a\x88\x6f\x49\x62\xd7\x58\x55\x4f\x1f\xff\x17\xab\xcb\xc1\x4c\xd4\xd5\xd4\x58\x8e\x20\x26\x86\xe9\xba\x86\x5c\x83\xed\x7b\x0f\x21\x74\xe5\x23\x88\x33\x9f\x70\x5d\xcd\xf5\xf9\x40\x15\x9f\xfb\x99\xc1\xf7\xb8\x36\xef\x80\x3d\x5f\x1c\xcf\x75\x5b\x8d\x82\x19\x41\x16\x2a\x9a\xe6\x00\xc6\xaa\xc0\x91\xf0\x94\x81\x37\x38\xa2\x14\x39\xb5\xb1\x51\x0d\x3c\xab\x08\xa2\xe3\xb6\x06\x5f\x73\x07\x42\x98\x1b\xa6\x69\xca\x60\xed\x2d\x03\x61\xf8\x0e\x54\x6b\x1b\x8e\x21\x33\x79\x72\x7e\xa1\x82\x72\xc3\xf1\x02\xcd\x1d\x1f\x9c\x1c\xab\xf3\x21\x5b\x9d\xb0\x6a\x7b\xd3\xf4\x78\xe3\x7e\xa2\x9b\x69\x7a\x9c\x1c\x7f\x06\x91\xe8\x7d\x53\x1b\x65\x49\xcc\x8a\x42\x9b\x09\x29\x56\x90\x10\x4d\x0f\xf0\x41\x68\x48\x40\x61\x1b\xe1\x34\xd5\xf7\xe5\xeb\xcc\x5b\x13\x2d\x49\x4c\x68\x4f\x05\x09\x1c\x7b\x51\x7c\xa8\x6a\x62\x7a\x10\x93\x34\xfb\x31\x18\x41\xbf\x1a\x68\x8c\xdc\xc4\x06\x9c\x1c\x7f\x90\x42\x13\x2a\xde\x16\x8a\xad\xdc\x4c\x94\xeb\x26\x3c\xd8\x9e\xbb\xb8\x3c\x2c\x32\x05\xd9\x74\xf5\x7e\xa6\x15\x7c\x35\x54\x41\xe4\xb7\x50\x16\xcc\xb2\x60\x0a\x8b\x10\x52\x10\x11\x08\xfd\xd1\xd2\x7d\x2b\x75\x56\xf7\x9e\x9c\xda\xbe\x2b\x29\x97\x3c\x43\x29\xb2\x0e\x2d\x81\xf0\x77\xe9\x58\xae\xab\xe4\x1b\x7d\x22\x4e\x05\xc3\x6d\x1a\x98\xbe\x24\xd1\x9c\x63\x7f\x3b\xa5\x90\x59\xa4\x8f\xac\xd8\x06\x91\x38\x68\x26\x98\x76\x9b\xec\xd9\xb9\x70\x7b\xa7\x09\xb1\xcd\x1f\x42\x5b\x27\xe8\xf6\x69\xdc\xae\x1d\x1a\x68\xd8\x08\x38\x10\x66\x88\x86\x68\xa4\x06\xed\x76\xf2\x50\x62\x87\x87\xa8\x3f\xf5\xc5\x02\x56\xd7\xa7\x37\xba\xb0\xdb\xfb\x63\xc2\x9a\x30\xde\x7d\x9b\xeb\xb7\x5c\x21\x2a\xba\xf7\x76\xd5\x7f\x8e\xa2\x8a\xf5\xb4\x22\xbc\x56\xe8\xce\x90\x31\x98\x1b\x06\x29\xbf\x21\x6e\x82\xec\x10\x48\x17\xba\x97\x37\x3c\x41\xbc\x5a\xbb\xf1\x75\x19\xbd\x07\x71\x5d\x0a\x58\x06\xd7\xa5\x08\x63\xeb\x78\x80\x0e\x9c\x72\xaf\xe5\xab\x56\x1a\x2b\x2f\x05\x4c\x92\x17\x52\x8f\x00\x1d\x1d\x88\x08\xbd\xa3\x60\xe2\xb8\xde\xd3\xf1\x8b\x3b\xa3\x99\xce\x5f\x71\xac\xbc\x56\x34\xc9\x87\xe8\x48\x71\xca\xb9\xd1\x64\xe7\xdf\xd0\x27\x05\x95\x2a\x2a\x15\xd5\x27\x9f\x21\x5a\x4d\xf6\xbb\xba\x52\x2f\xe5\xf7\xb9\xf3\x51\x82\xed\xa7\xb9\x3e\xe0\x7c\xc3\xa1\x33\x67\xfa\x4f\xe9\x20\xf6\xac\x1e\xaf\x60\xb7\x1d\x7b\x17\xfc\x57\x56\x91\x9b\xd7\x2a\xd7\x93\x3d\x32\x2d\xd3\xd5\x66\xd0\xce\x9b\xde\x24\xee\xbd\x28\xea\xc7\x97\x47\x52\xff\x4f\xa4\xf9\xed\x7c\xeb\xa0\x1e\x73\x21\xb7\xb8\xba\xf3\xc9\x5e\x73\xc6\x6f\x2e\xe7\x5e\xe5\x5a\xbc\xdb\xdf\x00\x3c\x59\xdb\x6c\xdb\x82\xbb\xbb\xdc\xfd\x1b\x00\x00\xff\xff\x45\x47\xff\xdc\x6d\x12\x00\x00") + +func configJsonSchemaFullJsonBytes() ([]byte, error) { + return bindataRead( + _configJsonSchemaFullJson, + "config/json-schema/full.json", + ) +} + +func configJsonSchemaFullJson() (*asset, error) { + bytes, err := configJsonSchemaFullJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "config/json-schema/full.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _configJsonSchemaLimitedJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x56\x3d\x6f\xdb\x30\x10\xdd\xf3\x2b\x08\x36\x63\x1c\x25\xdd\xe2\x2d\x40\x97\xb4\x45\x5c\x34\xed\x64\x78\xa0\xa5\xb3\x7c\xa9\x44\x2a\x24\x65\xc0\x30\xfc\xdf\x0b\x8a\xfa\xa0\x28\x32\xb6\x83\x02\x5d\x0c\xeb\x78\xef\xbe\xde\x3b\x4a\x87\x2b\x42\xe8\xb5\x4a\xb7\x50\x32\x3a\x27\x74\xab\x75\xa5\xe6\x49\xf2\xaa\x04\x9f\x59\xf3\xad\x90\x79\x92\x49\xb6\xd1\xc9\xe7\xbb\xfb\x87\xd9\xdd\x43\xd2\xfa\xdf\x34\x60\x09\x69\x2d\x15\xee\xe0\x91\xa7\x5b\x21\xe9\x9c\x68\x59\x83\x3d\xc3\xcc\x0d\xfa\xa7\xce\xc4\x6d\x06\x3b\x37\xfa\xac\xc0\x12\x35\x64\x36\x98\x46\x5d\x80\x81\x7c\xb7\x56\xf2\xed\xf7\x97\x05\xf9\xfa\xb2\x78\x9e\xbd\x38\x39\xf5\xbe\x32\x5e\x4b\x2a\xd6\xaf\x90\x6a\x7a\x43\xe8\x5a\x88\x02\x18\xa7\xab\xc6\x81\x65\x19\x6a\x14\x9c\x15\x3f\xa4\xa8\x40\x6a\x04\x45\xe7\x64\xc3\x0a\x65\x2b\xab\x5c\xb3\x19\xc2\x10\xd5\x3e\xd9\xce\x36\xa6\x96\x4f\xc9\x75\x06\x1b\x95\x28\x2c\xab\x02\x7e\xed\x2b\x50\xb4\xf1\x39\xde\xb4\xc0\xb6\xea\x1e\xd9\x46\xa2\x4a\x4b\xe4\xf9\xd8\x39\x03\x95\x4a\xac\x4c\x75\xe7\x42\x02\xc5\xc6\x7b\xec\xce\x8d\x07\xdf\x2f\x4c\x07\xcb\xde\x44\xc8\x61\xda\x57\x2e\x45\x5d\xd1\x2e\x5b\xd4\xad\x62\x92\x95\xa0\x41\x52\x72\xec\x3d\x57\xed\x3f\x6b\x31\xbf\x47\xcb\xbc\x81\x0c\xa3\xb5\x29\x02\xed\x76\x04\x9e\x68\xaa\x27\x2e\x3e\x8f\x29\x81\x8d\x2d\x15\x5c\x69\x27\x53\x7f\xe6\xb4\x3b\x21\x30\xca\x88\x0f\x0c\x93\x79\x36\xbc\x92\x28\x24\xea\x7d\x0c\x8b\x5c\x43\x0e\x32\x0c\x96\xf0\x56\xa3\x04\xb3\x61\x01\xb6\x6c\xda\x47\x29\xd9\x9e\x7a\x39\x83\xc3\x8b\x73\xf2\x1e\x2f\x2e\x3e\x22\x38\x72\xbe\xe8\x22\xae\x41\xe1\x11\x47\x7c\xde\x64\x1a\x5e\x36\xac\x2e\x0c\xef\x87\x01\x72\x1c\x6b\xb5\x5b\xae\x3e\xfa\xbf\x92\xa7\x43\xcc\xd2\x13\xa7\xc3\x43\x81\x4a\x3f\xb3\x12\x3a\x72\x57\xa7\xe5\xfd\x9f\x54\x3a\x0c\xb3\xbb\xd8\xa7\x8d\x5e\xa2\x40\xe0\x75\x19\xab\x83\x35\xee\x23\x2e\x51\x43\xa9\xda\xe4\xe1\xed\x0d\xac\x7d\x58\x89\xa1\x2a\x9d\x4b\xdd\x57\xe3\xc1\xd3\xe6\x3b\x55\x8e\x2a\xbd\x30\x0d\x21\xb4\x44\xfe\xd4\x82\xef\x27\x87\x35\xc7\xb7\x1a\x9e\x42\x63\x20\x8e\xac\xc9\x68\x23\xdc\x01\xb1\x6c\xc7\x78\x6a\x79\x0a\x0c\x7d\x78\x79\x46\x76\xa8\x91\x77\x30\xf2\x16\xb9\xfe\x88\xa4\x7a\xf1\x7f\x00\xab\x25\xe6\xf9\x68\x5d\xcf\x86\x62\x59\xd6\x9a\xad\xe3\x5b\x74\xd9\x20\x82\xf7\x89\xfd\xac\xb1\xb2\x0f\xdc\x28\x63\xe9\x04\x89\xf7\x74\xd4\x7e\x5d\xfd\x6c\x05\x45\xfd\x7c\x8e\xb2\x9c\x7c\xed\x92\x39\x17\x90\x2f\xda\x40\xb3\xfd\x0b\xc7\x31\xf1\xba\x28\xc6\xcf\xe5\x7a\xec\x31\x79\x5f\x78\x1c\xac\xc6\xf5\x3a\xd7\xc2\xe9\xf9\x38\xa3\xf0\x08\x1e\x88\x0d\x2c\x48\x7f\x34\x70\xb7\x5c\x0d\x9f\x28\x57\xc7\xab\xbf\x01\x00\x00\xff\xff\x1d\xf9\xe7\x5f\xf9\x0a\x00\x00") + +func configJsonSchemaLimitedJsonBytes() ([]byte, error) { + return bindataRead( + _configJsonSchemaLimitedJson, + "config/json-schema/limited.json", + ) +} + +func configJsonSchemaLimitedJson() (*asset, error) { + bytes, err := configJsonSchemaLimitedJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "config/json-schema/limited.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "config/json-schema/full.json": configJsonSchemaFullJson, + "config/json-schema/limited.json": configJsonSchemaLimitedJson, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{nil, map[string]*bintree{ + "config": &bintree{nil, map[string]*bintree{ + "json-schema": &bintree{nil, map[string]*bintree{ + "full.json": &bintree{configJsonSchemaFullJson, map[string]*bintree{}}, + "limited.json": &bintree{configJsonSchemaLimitedJson, map[string]*bintree{}}, + }}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} diff --git a/pkg/kudoctl/packages/convert/json-schema-extensions.go b/pkg/kudoctl/packages/convert/json-schema-extensions.go new file mode 100644 index 000000000..235e7acdc --- /dev/null +++ b/pkg/kudoctl/packages/convert/json-schema-extensions.go @@ -0,0 +1,39 @@ +package convert + +import ( + "context" + + "github.com/qri-io/jsonpointer" + "github.com/qri-io/jsonschema" +) + +// Advanced keyword +type IsAdvanced bool + +// newIsAdvanced is a jsonschama.KeyMaker +func newIsAdvanced() jsonschema.Keyword { + return new(IsAdvanced) +} + +// Register implements jsonschema.Keyword +func (f *IsAdvanced) Register(uri string, registry *jsonschema.SchemaRegistry) {} + +// Resolve implements jsonschema.Keyword +func (f *IsAdvanced) Resolve(pointer jsonpointer.Pointer, uri string) *jsonschema.Schema { + return nil +} + +// ValidateKeyword implements jsonschema.Keyword +func (f *IsAdvanced) ValidateKeyword(ctx context.Context, currentState *jsonschema.ValidationState, data interface{}) { + isAdvanced, _ := data.(bool) + if isAdvanced { + + currentState.Local.HasKeyword("default") + + } +} + +func init() { + jsonschema.LoadDraft2019_09() + jsonschema.RegisterKeyword("advanced", newIsAdvanced) +} diff --git a/pkg/kudoctl/packages/convert/json-schema.go b/pkg/kudoctl/packages/convert/json-schema.go new file mode 100644 index 000000000..2951d44dc --- /dev/null +++ b/pkg/kudoctl/packages/convert/json-schema.go @@ -0,0 +1,254 @@ +package convert + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + + "github.com/qri-io/jsonschema" + + kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" + "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output" + "github.com/kudobuilder/kudo/pkg/util/convert" +) + +const ( + jsonSchemaTypeObject = "object" + jsonSchemaTypeString = "string" +) + +type jsonSchema struct { + Schema string `json:"$schema,omitempty"` + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + Priority int `json:"priority,omitempty"` + Default interface{} `json:"default,omitempty"` + Enum []interface{} `json:"enum,omitempty"` + Type string `json:"type,omitempty"` + Immutable bool `json:"immutable,omitempty"` + Advanced bool `json:"advanced,omitempty"` + Hint string `json:"hint,omitempty"` + Trigger string `json:"trigger,omitempty"` + ListName string `json:"listName,omitempty"` + Properties map[string]*jsonSchema `json:"properties,omitempty"` + Required []string `json:"required,omitempty"` +} + +func (j *jsonSchema) hasRequiredPropertyWithoutDefault() bool { + for _, pName := range j.Required { + prop := j.Properties[pName] + + if prop.Default == nil { + return true + } + if prop.hasRequiredPropertyWithoutDefault() { + return true + } + } + return false +} + +func newSchema() *jsonSchema { + return &jsonSchema{ + Properties: map[string]*jsonSchema{}, + Required: []string{}, + } +} + +func buildGroups(ov *kudoapi.OperatorVersion) map[string]kudoapi.ParameterGroup { + groups := map[string]kudoapi.ParameterGroup{} + for _, g := range ov.Spec.Groups { + groups[g.Name] = g + } + for _, p := range ov.Spec.Parameters { + if p.Group != "" { + if _, ok := groups[p.Group]; !ok { + groups[p.Group] = kudoapi.ParameterGroup{ + Name: p.Group, + } + } + } + } + + return groups +} + +func buildTopLevelGroups(groups map[string]kudoapi.ParameterGroup) map[string]*jsonSchema { + topLevelGroups := map[string]*jsonSchema{} + + for _, v := range groups { + g := newSchema() + + g.Type = jsonSchemaTypeObject + + if v.DisplayName != "" { + g.Title = v.DisplayName + } else { + g.Title = v.Name + } + if v.Description != "" { + g.Description = v.Description + } + if v.Priority != 0 { + g.Priority = v.Priority + } + + topLevelGroups[v.Name] = g + } + + return topLevelGroups +} + +func jsonSchemaTypeFromKudoType(parameterType kudoapi.ParameterType) string { + switch parameterType { + // Most types are exactly as in json-schema + case kudoapi.StringValueType, + kudoapi.IntegerValueType, + kudoapi.NumberValueType, + kudoapi.BooleanValueType, + kudoapi.ArrayValueType: + return string(parameterType) + + // Objects are the equivalent to maps + case kudoapi.MapValueType: + return jsonSchemaTypeObject + + // All other types are defined as strings + default: + return jsonSchemaTypeString + } +} + +func UnwrapToJSONType(wrapped string, parameterType kudoapi.ParameterType) (unwrapped interface{}, err error) { + switch parameterType { + case kudoapi.MapValueType, + kudoapi.ArrayValueType, + kudoapi.NumberValueType, + kudoapi.BooleanValueType: + return convert.UnwrapParamValue(&wrapped, parameterType) + case kudoapi.IntegerValueType, + kudoapi.StringValueType: + // We keep integers as strings, as JSON only supports numbers, which may not always map correctly to integers + return wrapped, nil + default: + return wrapped, nil + } +} + +func UnwrapEnumValues(values []string, parameterType kudoapi.ParameterType) ([]interface{}, error) { + result := make([]interface{}, 0, len(values)) + for _, v := range values { + vUnwrapped, err := UnwrapToJSONType(v, parameterType) + if err != nil { + return nil, err + } + result = append(result, vUnwrapped) + } + return result, nil +} + +func buildParamSchema(p kudoapi.Parameter) (*jsonSchema, error) { + var err error + + param := newSchema() + + if p.DisplayName != "" { + param.Title = p.DisplayName + } + if p.Description != "" { + param.Description = p.Description + } + if p.HasDefault() { + if param.Default, err = UnwrapToJSONType(*p.Default, p.Type); err != nil { + return nil, fmt.Errorf("failed to convert default value %s: %v", *p.Default, err) + } + } + param.Type = jsonSchemaTypeFromKudoType(p.Type) + if p.IsImmutable() { + param.Immutable = true + } + if p.IsAdvanced() { + param.Advanced = true + } + if p.Hint != "" { + param.Hint = p.Hint + } + if p.Trigger != "" { + param.Trigger = p.Trigger + } + param.ListName = p.Name + if p.IsEnum() { + if param.Enum, err = UnwrapEnumValues(p.EnumValues(), p.Type); err != nil { + return nil, fmt.Errorf("failed to convert enum values: %v", err) + } + } + + return param, nil +} + +func WriteJSONSchema(ov *kudoapi.OperatorVersion, outputType output.Type, out io.Writer) error { + root := newSchema() + topLevelGroups := buildTopLevelGroups(buildGroups(ov)) + + root.Properties = topLevelGroups + root.Type = jsonSchemaTypeObject + root.Description = "All parameters for this operator" + root.Title = fmt.Sprintf("Parameters for %s", ov.Name) + + for _, p := range ov.Spec.Parameters { + param, err := buildParamSchema(p) + if err != nil { + return fmt.Errorf("failed to convert parameter %s: %v", p.Name, err) + } + + // Assign to correct parent + parent := topLevelGroups[p.Group] + if parent == nil { + parent = root + } + + if p.IsRequired() { + parent.Required = append(parent.Required, p.Name) + } + + parent.Properties[p.Name] = param + } + + for k, v := range topLevelGroups { + if v.hasRequiredPropertyWithoutDefault() { + root.Required = append(root.Required, k) + } + } + + buf := new(bytes.Buffer) + err := output.WriteObject(root, output.TypeJSON, buf) + if err != nil { + return err + } + + schemaJSON := MustAsset("config/json-schema/limited.json") + + s := &jsonschema.Schema{} + if err := json.Unmarshal(schemaJSON, s); err != nil { + return fmt.Errorf("failed to unmarshal json-schema: %v", err) + } + + var doc interface{} + if err := json.Unmarshal(buf.Bytes(), &doc); err != nil { + return fmt.Errorf("error parsing JSON bytes: %s", err.Error()) + } + + vs := s.Validate(context.TODO(), doc) + errs := *vs.Errs + if len(errs) > 0 { + for _, e := range errs { + fmt.Printf("Error: %v\n", e) + } + fmt.Printf("%s\n", buf.String()) + return fmt.Errorf("failed to validate json schema") + } + + return output.WriteObject(root, outputType, out) +} diff --git a/pkg/kudoctl/packages/convert/json-schema_test.go b/pkg/kudoctl/packages/convert/json-schema_test.go new file mode 100644 index 000000000..dd722cc59 --- /dev/null +++ b/pkg/kudoctl/packages/convert/json-schema_test.go @@ -0,0 +1,108 @@ +package convert + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" + "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output" +) + +var update = flag.Bool("update", false, "update .golden files") + +func Test_JsonSchemaExport(t *testing.T) { + + tests := []struct { + name string + ov *kudoapi.OperatorVersion + outputType output.Type + err string + }{ + {name: "simple.json", ov: simpleOv(), outputType: output.TypeJSON}, + {name: "simple.yaml", ov: simpleOv(), outputType: output.TypeYAML}, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + out := &bytes.Buffer{} + err := WriteJSONSchema(tt.ov, tt.outputType, out) + assert.NoError(t, err) + + rendered := out.String() + + gf := fmt.Sprintf("testdata/%s.golden", tt.name) + + if *update { + t.Log("update golden file") + + //nolint:gosec + if err := ioutil.WriteFile(gf, []byte(rendered), 0644); err != nil { + t.Fatalf("failed to update golden file: %s", err) + } + } + + golden, err := ioutil.ReadFile(gf) + if err != nil { + t.Fatalf("failed reading .golden: %s", err) + } + + assert.Equal(t, string(golden), rendered, "for golden file: %s", gf) + }) + } + +} + +func simpleOv() *kudoapi.OperatorVersion { + return &kudoapi.OperatorVersion{ + ObjectMeta: v1.ObjectMeta{ + Name: "Test", + }, + Spec: kudoapi.OperatorVersionSpec{ + Groups: []kudoapi.ParameterGroup{ + { + Name: "simplegroup", + DisplayName: "SimpleGroup", + Description: "The description for this group.", + Priority: 10, + }, + }, + Parameters: []kudoapi.Parameter{ + { + Name: "my-param", + DisplayName: "MyParam", + Description: "My parameter description", + Type: kudoapi.StringValueType, + Immutable: boolPtr(true), + Default: strPointer("defaultVal"), + Hint: "My Param Hint.", + Trigger: "my-plan", + }, + { + Name: "grouped-param", + DisplayName: "GroupedParam", + Description: "My parameter description in a group", + Type: kudoapi.IntegerValueType, + Immutable: boolPtr(false), + Default: strPointer("23"), + Hint: "My Group Param Hint.", + Group: "simplegroup", + }, + }, + }, + } +} + +func boolPtr(v bool) *bool { + return &v +} +func strPointer(v string) *string { + return &v +} diff --git a/pkg/kudoctl/packages/convert/parameters.go b/pkg/kudoctl/packages/convert/parameters.go index a715d5218..91d750b82 100644 --- a/pkg/kudoctl/packages/convert/parameters.go +++ b/pkg/kudoctl/packages/convert/parameters.go @@ -8,6 +8,88 @@ import ( utilconvert "github.com/kudobuilder/kudo/pkg/util/convert" ) +func ParameterGroupsToPackageType(groups []kudoapi.ParameterGroup) packages.Groups { + if len(groups) == 0 { + return nil + } + + result := make([]packages.Group, 0, len(groups)) + + for _, group := range groups { + result = append(result, packages.Group{ + Name: group.Name, + DisplayName: group.DisplayName, + Description: group.Description, + Priority: group.Priority, + }) + } + + return result +} + +func ParameterGroupsToCRDType(groups packages.Groups) []kudoapi.ParameterGroup { + if len(groups) == 0 { + return nil + } + result := make([]kudoapi.ParameterGroup, 0, len(groups)) + + for _, group := range groups { + result = append(result, kudoapi.ParameterGroup{ + Name: group.Name, + DisplayName: group.DisplayName, + Description: group.Description, + Priority: group.Priority, + }) + } + + return result +} + +func ParametersToPackageType(parameters []kudoapi.Parameter) (packages.Parameters, error) { + result := make([]packages.Parameter, 0, len(parameters)) + + for _, parameter := range parameters { + var defaultVal interface{} = nil + if parameter.HasDefault() { + var err error + defaultVal, err = utilconvert.UnwrapParamValue(parameter.Default, parameter.Type) + if err != nil { + return nil, fmt.Errorf("failed to convert %s default for parameter '%s': %w", parameter.Type, parameter.Name, err) + } + } + var enumValues *[]interface{} + if parameter.IsEnum() { + var ev []interface{} + for _, v := range parameter.EnumValues() { + v := v + vUnwrapped, err := utilconvert.UnwrapParamValue(&v, parameter.Type) + if err != nil { + return nil, fmt.Errorf("failed to convert %s enum value '%s' for parameter '%s': %w", parameter.Type, v, parameter.Name, err) + } + ev = append(ev, vUnwrapped) + } + enumValues = &ev + } + + result = append(result, packages.Parameter{ + DisplayName: parameter.DisplayName, + Name: parameter.Name, + Description: parameter.Description, + Required: parameter.Required, + Advanced: parameter.Advanced, + Hint: parameter.Hint, + Group: parameter.Group, + Default: defaultVal, + Trigger: parameter.Trigger, + Type: parameter.Type, + Immutable: parameter.Immutable, + Enum: enumValues, + }) + } + + return result, nil +} + // ParametersToCRDType converts parameters to an array of 'Parameter' defined in the KUDO API. func ParametersToCRDType(parameters packages.Parameters) ([]kudoapi.Parameter, error) { result := make([]kudoapi.Parameter, 0, len(parameters)) @@ -36,6 +118,9 @@ func ParametersToCRDType(parameters packages.Parameters) ([]kudoapi.Parameter, e Name: parameter.Name, Description: parameter.Description, Required: parameter.Required, + Advanced: parameter.Advanced, + Hint: parameter.Hint, + Group: parameter.Group, Default: d, Trigger: parameter.Trigger, Type: parameter.Type, diff --git a/pkg/kudoctl/packages/convert/resources.go b/pkg/kudoctl/packages/convert/resources.go index 456d1a023..88d6967a8 100644 --- a/pkg/kudoctl/packages/convert/resources.go +++ b/pkg/kudoctl/packages/convert/resources.go @@ -14,6 +14,21 @@ import ( "github.com/kudobuilder/kudo/pkg/util/kudo" ) +func ResourcesToParamFile(resources *packages.Resources) (*packages.ParamsFile, error) { + groups := ParameterGroupsToPackageType(resources.OperatorVersion.Spec.Groups) + params, err := ParametersToPackageType(resources.OperatorVersion.Spec.Parameters) + if err != nil { + return nil, err + } + + result := &packages.ParamsFile{ + APIVersion: packages.APIVersion, + Groups: groups, + Parameters: params, + } + return result, nil +} + func FilesToResources(files *packages.Files) (*packages.Resources, error) { if files.Operator == nil { return nil, errors.New("operator.yaml file is missing") @@ -54,6 +69,8 @@ func FilesToResources(files *packages.Files) (*packages.Resources, error) { return nil, err } + groups := ParameterGroupsToCRDType(files.Params.Groups) + fv := &kudoapi.OperatorVersion{ TypeMeta: metav1.TypeMeta{ Kind: "OperatorVersion", @@ -72,6 +89,7 @@ func FilesToResources(files *packages.Files) (*packages.Resources, error) { Templates: files.Templates, Tasks: files.Operator.Tasks, Parameters: parameters, + Groups: groups, Plans: files.Operator.Plans, UpgradableFrom: nil, }, diff --git a/pkg/kudoctl/packages/convert/testdata/simple.json.golden b/pkg/kudoctl/packages/convert/testdata/simple.json.golden new file mode 100644 index 000000000..32603b6e4 --- /dev/null +++ b/pkg/kudoctl/packages/convert/testdata/simple.json.golden @@ -0,0 +1,33 @@ +{ + "title": "Parameters for Test", + "description": "All parameters for this operator", + "type": "object", + "properties": { + "my-param": { + "title": "MyParam", + "description": "My parameter description", + "default": "defaultVal", + "type": "string", + "immutable": true, + "hint": "My Param Hint.", + "trigger": "my-plan", + "listName": "my-param" + }, + "simplegroup": { + "title": "SimpleGroup", + "description": "The description for this group.", + "priority": 10, + "type": "object", + "properties": { + "grouped-param": { + "title": "GroupedParam", + "description": "My parameter description in a group", + "default": "23", + "type": "integer", + "hint": "My Group Param Hint.", + "listName": "grouped-param" + } + } + } + } +} diff --git a/pkg/kudoctl/packages/convert/testdata/simple.yaml.golden b/pkg/kudoctl/packages/convert/testdata/simple.yaml.golden new file mode 100644 index 000000000..7127abacd --- /dev/null +++ b/pkg/kudoctl/packages/convert/testdata/simple.yaml.golden @@ -0,0 +1,27 @@ +description: All parameters for this operator +properties: + my-param: + default: defaultVal + description: My parameter description + hint: My Param Hint. + immutable: true + listName: my-param + title: MyParam + trigger: my-plan + type: string + simplegroup: + description: The description for this group. + priority: 10 + properties: + grouped-param: + default: "23" + description: My parameter description in a group + hint: My Group Param Hint. + listName: grouped-param + title: GroupedParam + type: integer + title: SimpleGroup + type: object +title: Parameters for Test +type: object + diff --git a/pkg/util/convert/convert.go b/pkg/util/convert/convert.go index 5a309ac8b..55ce3dc2f 100644 --- a/pkg/util/convert/convert.go +++ b/pkg/util/convert/convert.go @@ -2,6 +2,7 @@ package convert import ( "fmt" + "strconv" "sigs.k8s.io/yaml" @@ -30,6 +31,12 @@ func UnwrapParamValue(wrapped *string, parameterType kudoapi.ParameterType) (unw unwrapped, err = ToYAMLMap(StringValue(wrapped)) case kudoapi.ArrayValueType: unwrapped, err = ToYAMLArray(StringValue(wrapped)) + case kudoapi.IntegerValueType: + unwrapped, err = strconv.ParseInt(StringValue(wrapped), 10, 32) + case kudoapi.NumberValueType: + unwrapped, err = strconv.ParseFloat(StringValue(wrapped), 64) + case kudoapi.BooleanValueType: + unwrapped, err = strconv.ParseBool(StringValue(wrapped)) case kudoapi.StringValueType: fallthrough default: