Required setters for apply

This commit is contained in:
Phani Teja Marupaka
2020-06-22 20:17:17 -07:00
parent a895220743
commit 68ab3b87d9
12 changed files with 75 additions and 25 deletions

View File

@@ -50,6 +50,8 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
set.Flags().MarkHidden("partial") set.Flags().MarkHidden("partial")
set.Flags().StringVar(&setterVersion, "version", "", set.Flags().StringVar(&setterVersion, "version", "",
"use this version of the setter format") "use this version of the setter format")
set.Flags().BoolVar(&r.CreateSetter.Required, "required", false,
"indicates that this setter must be set by package consumer before live apply/preview")
set.Flags().StringVar(&r.CreateSetter.SchemaPath, "schema-path", "", set.Flags().StringVar(&r.CreateSetter.SchemaPath, "schema-path", "",
`openAPI schema file path for setter constraints -- file content `+ `openAPI schema file path for setter constraints -- file content `+
`e.g. {"type": "string", "maxLength": 15, "enum": ["allowedValue1", "allowedValue2"]}`) `e.g. {"type": "string", "maxLength": 15, "enum": ["allowedValue1", "allowedValue2"]}`)

View File

@@ -79,7 +79,7 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []string) error {
return err return err
} }
table := newTable(c.OutOrStdout(), r.Markdown) table := newTable(c.OutOrStdout(), r.Markdown)
table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT"}) table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED"})
for i := range r.List.Setters { for i := range r.List.Setters {
s := r.List.Setters[i] s := r.List.Setters[i]
v := s.Value v := s.Value
@@ -89,8 +89,14 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, args []string) error {
v = strings.Join(s.ListValues, ",") v = strings.Join(s.ListValues, ",")
v = fmt.Sprintf("[%s]", v) v = fmt.Sprintf("[%s]", v)
} }
var required string
if s.Required {
required = "Yes"
} else {
required = "No"
}
table.Append([]string{ table.Append([]string{
s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count)}) s.Name, v, s.SetBy, s.Description, fmt.Sprintf("%d", s.Count), required})
} }
table.Render() table.Render()

View File

@@ -34,6 +34,7 @@ openAPI:
name: replicas name: replicas
value: "3" value: "3"
setBy: me setBy: me
required: true
description: "hello world" description: "hello world"
`, `,
input: ` input: `
@@ -44,8 +45,8 @@ metadata:
spec: spec:
replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"} replicas: 3 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
replicas 3 me hello world 1 replicas 3 me hello world 1 Yes
`, `,
}, },
{ {
@@ -74,6 +75,8 @@ openAPI:
name: tag name: tag
value: "1.7.9" value: "1.7.9"
setBy: me3 setBy: me3
required: true
isSet: false
io.k8s.cli.substitutions.image: io.k8s.cli.substitutions.image:
x-k8s-cli: x-k8s-cli:
substitution: substitution:
@@ -100,10 +103,10 @@ spec:
- name: nginx2 - name: nginx2
image: nginx # {"$ref": "#/definitions/io.k8s.cli.setters.image"} image: nginx # {"$ref": "#/definitions/io.k8s.cli.setters.image"}
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image nginx me2 hello world 2 2 image nginx me2 hello world 2 2 No
replicas 3 me1 hello world 1 1 replicas 3 me1 hello world 1 1 No
tag 1.7.9 me3 hello world 3 1 tag 1.7.9 me3 hello world 3 1 Yes
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
image IMAGE:TAG [image,tag] image IMAGE:TAG [image,tag]
`, `,
@@ -174,10 +177,10 @@ spec:
- name: nginx2 - name: nginx2
image: nginx image: nginx
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image nginx me2 hello world 2 3 image nginx me2 hello world 2 3 No
replicas 3 me1 hello world 1 2 replicas 3 me1 hello world 1 2 No
tag 1.7.9 me3 hello world 3 2 tag 1.7.9 me3 hello world 3 2 No
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
image IMAGE:TAG [image,tag] image IMAGE:TAG [image,tag]
`, `,
@@ -202,6 +205,7 @@ openAPI:
name: image name: image
value: "nginx" value: "nginx"
setBy: me2 setBy: me2
required: true
io.k8s.cli.setters.tag: io.k8s.cli.setters.tag:
description: "hello world 3" description: "hello world 3"
x-k8s-cli: x-k8s-cli:
@@ -249,8 +253,8 @@ spec:
- name: nginx2 - name: nginx2
image: nginx image: nginx
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
image nginx me2 hello world 2 3 image nginx me2 hello world 2 3 Yes
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
image IMAGE:TAG [image,tag] image IMAGE:TAG [image,tag]
`, `,
@@ -277,6 +281,7 @@ openAPI:
- b - b
- c - c
setBy: me setBy: me
required: true
`, `,
input: ` input: `
apiVersion: example.com/v1beta1 apiVersion: example.com/v1beta1
@@ -290,8 +295,8 @@ spec:
- "b" - "b"
- "c" - "c"
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
list [a,b,c] me hello world 1 list [a,b,c] me hello world 1 Yes
`, `,
}, },
@@ -327,6 +332,8 @@ openAPI:
setter: setter:
name: my-tag-setter name: my-tag-setter
value: 1.7.9 value: 1.7.9
required: true
isSet: true
io.k8s.cli.substitutions.my-image-subst: io.k8s.cli.substitutions.my-image-subst:
x-k8s-cli: x-k8s-cli:
substitution: substitution:
@@ -353,10 +360,10 @@ openAPI:
name: my-other-setter name: my-other-setter
value: nginxotherthing value: nginxotherthing
`, `,
expected: ` NAME VALUE SET BY DESCRIPTION COUNT expected: ` NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
my-image-setter nginx 2 my-image-setter nginx 2 No
my-other-setter nginxotherthing 1 my-other-setter nginxotherthing 1 No
my-tag-setter 1.7.9 2 my-tag-setter 1.7.9 2 Yes
SUBSTITUTION PATTERN REFERENCES SUBSTITUTION PATTERN REFERENCES
my-image-subst ${my-image-setter}::${my-tag-setter} [my-image-setter,my-tag-setter] my-image-subst ${my-image-setter}::${my-tag-setter} [my-image-setter,my-tag-setter]
my-nested-subst something/${my-image-subst}/${my-other-setter} [my-image-subst,my-other-setter] my-nested-subst something/${my-image-subst}/${my-other-setter} [my-image-subst,my-other-setter]

View File

@@ -64,6 +64,7 @@ openAPI:
name: replicas name: replicas
value: "4" value: "4"
setBy: pw setBy: pw
isSet: true
`, `,
expectedResources: ` expectedResources: `
apiVersion: apps/v1 apiVersion: apps/v1
@@ -158,6 +159,7 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "4" value: "4"
isSet: true
`, `,
expectedResources: ` expectedResources: `
apiVersion: apps/v1 apiVersion: apps/v1
@@ -229,6 +231,7 @@ openAPI:
setter: setter:
name: tag name: tag
value: "1.8.1" value: "1.8.1"
isSet: true
io.k8s.cli.substitutions.image: io.k8s.cli.substitutions.image:
x-k8s-cli: x-k8s-cli:
substitution: substitution:
@@ -539,6 +542,7 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "4" value: "4"
isSet: true
`, `,
expectedResources: ` expectedResources: `
apiVersion: apps/v1 apiVersion: apps/v1
@@ -639,6 +643,7 @@ openAPI:
listValues: listValues:
- "10" - "10"
- "11" - "11"
isSet: true
`, `,
expectedResources: ` expectedResources: `
apiVersion: example.com/v1beta1 apiVersion: example.com/v1beta1
@@ -771,6 +776,7 @@ openAPI:
setter: setter:
name: my-image-setter name: my-image-setter
value: ubuntu value: ubuntu
isSet: true
io.k8s.cli.setters.my-tag-setter: io.k8s.cli.setters.my-tag-setter:
x-k8s-cli: x-k8s-cli:
setter: setter:

View File

@@ -34,8 +34,8 @@ openAPI:
`, `,
}, },
expectedStdOut: ` expectedStdOut: `
NAME VALUE SET BY DESCRIPTION COUNT NAME VALUE SET BY DESCRIPTION COUNT REQUIRED
replicas 3 1 replicas 3 1 No
`, `,
}, },
} }

View File

@@ -54,6 +54,7 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "4" value: "4"
isSet: true
`, `,
}, },
}, },

View File

@@ -162,6 +162,11 @@ type SetterDefinition struct {
// Example -- may be used for t-shirt sizing values by allowing cpu to be // Example -- may be used for t-shirt sizing values by allowing cpu to be
// set to small, medium or large, and then mapping these values to cpu values -- 0.5, 2, 8 // set to small, medium or large, and then mapping these values to cpu values -- 0.5, 2, 8
EnumValues map[string]string `yaml:"enumValues,omitempty"` EnumValues map[string]string `yaml:"enumValues,omitempty"`
// Required indicates that the setter must be set by package consumer before
// live apply/preview. This field is added to the setter definition to record
// the package publisher's intent to make the setter required to be set.
Required bool `yaml:"required,omitempty"`
} }
func (sd SetterDefinition) AddToFile(path string) error { func (sd SetterDefinition) AddToFile(path string) error {

View File

@@ -132,12 +132,12 @@ func (dd DeleterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
return nil, errors.Errorf("setter is used in substitution %s, please delete the substitution first", subst) return nil, errors.Errorf("setter is used in substitution %s, please delete the substitution first", subst)
} }
_, err = definitions.Pipe(yaml.FieldClearer{Name:key}) _, err = definitions.Pipe(yaml.FieldClearer{Name: key})
if err != nil { if err != nil {
return nil, err return nil, err
} }
// remove definitions if it's empty // remove definitions if it's empty
_, err = object.Pipe(yaml.Lookup(openapi.SupplementaryOpenAPIFieldName), yaml.FieldClearer{Name:"definitions", IfEmpty: true}) _, err = object.Pipe(yaml.Lookup(openapi.SupplementaryOpenAPIFieldName), yaml.FieldClearer{Name: "definitions", IfEmpty: true})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -181,6 +181,8 @@ func (l *List) listSubst(object *yaml.RNode) error {
} }
// count returns the number of fields set by the setter with name // count returns the number of fields set by the setter with name
// set filter is leveraged for this but the resources are not written
// back to files as only LocalPackageReader is invoked and not writer
func (l *List) count(path, name string) (int, error) { func (l *List) count(path, name string) (int, error) {
s := &Set{Name: name} s := &Set{Name: name}
err := kio.Pipeline{ err := kio.Pipeline{

View File

@@ -419,6 +419,10 @@ func (s SetOpenAPI) Filter(object *yaml.RNode) (*yaml.RNode, error) {
return nil, err return nil, err
} }
if err := def.PipeE(&yaml.FieldSetter{Name: "isSet", StringValue: "true"}); err != nil {
return nil, err
}
if s.Description != "" { if s.Description != "" {
d, err := object.Pipe(yaml.LookupCreate( d, err := object.Pipe(yaml.LookupCreate(
yaml.MappingNode, "openAPI", "definitions", key)) yaml.MappingNode, "openAPI", "definitions", key))

View File

@@ -927,6 +927,8 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "4" value: "4"
required: true
isSet: true
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
setter: setter:
@@ -946,6 +948,8 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "3" value: "3"
required: true
isSet: true
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
setter: setter:
@@ -974,6 +978,7 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "3" value: "3"
isSet: true
`, `,
}, },
{ {
@@ -1013,6 +1018,7 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "3" value: "3"
isSet: true
description: hello world description: hello world
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
@@ -1059,6 +1065,7 @@ openAPI:
name: replicas name: replicas
value: "3" value: "3"
setBy: carl setBy: carl
isSet: true
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
setter: setter:
@@ -1106,6 +1113,7 @@ openAPI:
setter: setter:
name: replicas name: replicas
value: "3" value: "3"
isSet: true
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
setter: setter:
@@ -1159,6 +1167,7 @@ openAPI:
enumValues: enumValues:
foo: bar foo: bar
baz: biz baz: biz
isSet: true
io.k8s.cli.setters.no-match-2': io.k8s.cli.setters.no-match-2':
x-k8s-cli: x-k8s-cli:
setter: setter:
@@ -1245,6 +1254,7 @@ openAPI:
setter: setter:
name: args name: args
listValues: ["1"] listValues: ["1"]
required: true
`, `,
expected: ` expected: `
openAPI: openAPI:
@@ -1255,6 +1265,8 @@ openAPI:
setter: setter:
name: args name: args
listValues: ["2", "3", "4"] listValues: ["2", "3", "4"]
required: true
isSet: true
`, `,
}, },
} }

View File

@@ -37,6 +37,11 @@ type SetterCreator struct {
// FieldValue if set will add the OpenAPI reference to fields if they have this value. // FieldValue if set will add the OpenAPI reference to fields if they have this value.
// Optional. If unspecified match all field values. // Optional. If unspecified match all field values.
FieldValue string FieldValue string
// Required indicates that the setter must be set by package consumer before
// live apply/preview. This field is added to the setter definition to record
// the package publisher's intent to make the setter required to be set.
Required bool
} }
func (c SetterCreator) Create(openAPIPath, resourcesPath string) error { func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
@@ -47,7 +52,7 @@ func (c SetterCreator) Create(openAPIPath, resourcesPath string) error {
// Update the OpenAPI definitions to hace the setter // Update the OpenAPI definitions to hace the setter
sd := setters2.SetterDefinition{ sd := setters2.SetterDefinition{
Name: c.Name, Value: c.FieldValue, Description: c.Description, SetBy: c.SetBy, Name: c.Name, Value: c.FieldValue, Description: c.Description, SetBy: c.SetBy,
Type: c.Type, Schema: schema, Type: c.Type, Schema: schema, Required: c.Required,
} }
if err := sd.AddToFile(openAPIPath); err != nil { if err := sd.AddToFile(openAPIPath); err != nil {
return err return err