Commit a615f80c authored by Arturo Contreras's avatar Arturo Contreras

Adding --set-string flag to force string values.

parent b6335b7d
......@@ -50,7 +50,8 @@ The install argument must be a chart reference, a path to a packaged chart,
a path to an unpacked chart directory or a URL.
To override values in a chart, use either the '--values' flag and pass in a file
or use the '--set' flag and pass configuration from the command line.
or use the '--set' flag and pass configuration from the command line, to force
a string value use '--set-string'.
$ helm install -f myvalues.yaml ./redis
......@@ -58,6 +59,10 @@ or
$ helm install --set name=prod ./redis
or
$ helm install --set-string long_int=1234567890 ./redis
You can specify the '--values'/'-f' flag multiple times. The priority will be given to the
last (right-most) file specified. For example, if both myvalues.yaml and override.yaml
contained a key called 'Test', the value set in override.yaml would take precedence:
......@@ -113,6 +118,7 @@ type installCmd struct {
out io.Writer
client helm.Interface
values []string
stringValues []string
nameTemplate string
version string
timeout int64
......@@ -186,6 +192,7 @@ func newInstallCmd(c helm.Interface, out io.Writer) *cobra.Command {
f.BoolVar(&inst.disableHooks, "no-hooks", false, "prevent hooks from running during install")
f.BoolVar(&inst.replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production")
f.StringArrayVar(&inst.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&inst.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringVar(&inst.nameTemplate, "name-template", "", "specify template used to name the release")
f.BoolVar(&inst.verify, "verify", false, "verify the package before installing it")
f.StringVar(&inst.keyring, "keyring", defaultKeyring(), "location of public keys used for verification")
......@@ -211,7 +218,7 @@ func (i *installCmd) run() error {
i.namespace = defaultNamespace()
}
rawVals, err := vals(i.valueFiles, i.values)
rawVals, err := vals(i.valueFiles, i.values, i.stringValues)
if err != nil {
return err
}
......@@ -325,8 +332,8 @@ func mergeValues(dest map[string]interface{}, src map[string]interface{}) map[st
}
// vals merges values from files specified via -f/--values and
// directly via --set, marshaling them to YAML
func vals(valueFiles valueFiles, values []string) ([]byte, error) {
// directly via --set or --set-string, marshaling them to YAML
func vals(valueFiles valueFiles, values []string, stringValues []string) ([]byte, error) {
base := map[string]interface{}{}
// User specified a values files via -f/--values
......@@ -359,6 +366,13 @@ func vals(valueFiles valueFiles, values []string) ([]byte, error) {
}
}
// User specified a value via --set-string
for _, value := range stringValues {
if err := strvals.ParseIntoString(value, base); err != nil {
return []byte{}, fmt.Errorf("failed parsing --set-string data: %s", err)
}
}
return yaml.Marshal(base)
}
......
......@@ -46,6 +46,7 @@ or recommendation, it will emit [WARNING] messages.
type lintCmd struct {
valueFiles valueFiles
values []string
sValues []string
namespace string
strict bool
paths []string
......@@ -71,6 +72,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
cmd.Flags().VarP(&l.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
cmd.Flags().StringArrayVar(&l.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.Flags().StringArrayVar(&l.sValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.Flags().StringVar(&l.namespace, "namespace", "default", "namespace to install the release into (only used if --install is set)")
cmd.Flags().BoolVar(&l.strict, "strict", false, "fail on lint warnings")
......@@ -192,5 +194,12 @@ func (l *lintCmd) vals() ([]byte, error) {
}
}
// User specified a value via --set-string
for _, value := range l.sValues {
if err := strvals.ParseIntoString(value, base); err != nil {
return []byte{}, fmt.Errorf("failed parsing --set-string data: %s", err)
}
}
return yaml.Marshal(base)
}
......@@ -68,6 +68,7 @@ type templateCmd struct {
chartPath string
out io.Writer
values []string
stringValues []string
nameTemplate string
showNotes bool
releaseName string
......@@ -96,6 +97,7 @@ func newTemplateCmd(out io.Writer) *cobra.Command {
f.VarP(&t.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
f.StringVar(&t.namespace, "namespace", "", "namespace to install the release into")
f.StringArrayVar(&t.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&t.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringVar(&t.nameTemplate, "name-template", "", "specify template used to name the release")
f.StringVar(&t.kubeVersion, "kube-version", defaultKubeVersion, "kubernetes version used as Capabilities.KubeVersion.Major/Minor")
f.StringVar(&t.outputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout")
......@@ -149,7 +151,7 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error {
t.namespace = defaultNamespace()
}
// get combined values and create config
rawVals, err := vals(t.valueFiles, t.values)
rawVals, err := vals(t.valueFiles, t.values, t.stringValues)
if err != nil {
return err
}
......
......@@ -37,7 +37,8 @@ a packaged chart, or a fully qualified URL. For chart references, the latest
version will be specified unless the '--version' flag is set.
To override values in a chart, use either the '--values' flag and pass in a file
or use the '--set' flag and pass configuration from the command line.
or use the '--set' flag and pass configuration from the command line, to force string
values, use '--set-string'.
You can specify the '--values'/'-f' flag multiple times. The priority will be given to the
last (right-most) file specified. For example, if both myvalues.yaml and override.yaml
......@@ -63,6 +64,7 @@ type upgradeCmd struct {
disableHooks bool
valueFiles valueFiles
values []string
stringValues []string
verify bool
keyring string
install bool
......@@ -118,6 +120,7 @@ func newUpgradeCmd(client helm.Interface, out io.Writer) *cobra.Command {
f.BoolVar(&upgrade.recreate, "recreate-pods", false, "performs pods restart for the resource if applicable")
f.BoolVar(&upgrade.force, "force", false, "force resource update through delete/recreate if needed")
f.StringArrayVar(&upgrade.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.StringArrayVar(&upgrade.stringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
f.BoolVar(&upgrade.disableHooks, "disable-hooks", false, "disable pre/post upgrade hooks. DEPRECATED. Use no-hooks")
f.BoolVar(&upgrade.disableHooks, "no-hooks", false, "disable pre/post upgrade hooks")
f.BoolVar(&upgrade.verify, "verify", false, "verify the provenance of the chart before upgrading")
......@@ -183,6 +186,7 @@ func (u *upgradeCmd) run() error {
disableHooks: u.disableHooks,
keyring: u.keyring,
values: u.values,
stringValues: u.stringValues,
namespace: u.namespace,
timeout: u.timeout,
wait: u.wait,
......@@ -191,7 +195,7 @@ func (u *upgradeCmd) run() error {
}
}
rawVals, err := vals(u.valueFiles, u.values)
rawVals, err := vals(u.valueFiles, u.values, u.stringValues)
if err != nil {
return err
}
......
......@@ -92,7 +92,7 @@ There are three potential sources of values:
- A chart's `values.yaml` file
- A values file supplied by `helm install -f` or `helm upgrade -f`
- The values passed to a `--set` flag on `helm install` or `helm upgrade`
- The values passed to a `--set` or `--set-string` flag on `helm install` or `helm upgrade`
When designing the structure of your values, keep in mind that users of your
chart may want to override them via either the `-f` flag or with the `--set`
......
......@@ -12,7 +12,8 @@ The install argument must be a chart reference, a path to a packaged chart,
a path to an unpacked chart directory or a URL.
To override values in a chart, use either the '--values' flag and pass in a file
or use the '--set' flag and pass configuration from the command line.
or use the '--set' flag and pass configuration from the command line, to force
a string value use '--set-string'.
$ helm install -f myvalues.yaml ./redis
......@@ -20,6 +21,10 @@ or
$ helm install --set name=prod ./redis
or
$ helm install --set-string long_int=1234567890 ./redis
You can specify the '--values'/'-f' flag multiple times. The priority will be given to the
last (right-most) file specified. For example, if both myvalues.yaml and override.yaml
contained a key called 'Test', the value set in override.yaml would take precedence:
......@@ -84,6 +89,7 @@ helm install [CHART]
--replace re-use the given name, even if that name is already used. This is unsafe in production
--repo string chart repository url where to locate the requested chart
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300)
--tls enable TLS for request
--tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem")
......@@ -111,4 +117,4 @@ helm install [CHART]
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 8-Mar-2018
###### Auto generated by spf13/cobra on 20-Mar-2018
......@@ -23,6 +23,7 @@ helm lint [flags] PATH
```
--namespace string namespace to install the release into (only used if --install is set) (default "default")
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--strict fail on lint warnings
-f, --values valueFiles specify values in a YAML file (can specify multiple) (default [])
```
......@@ -41,4 +42,4 @@ helm lint [flags] PATH
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 8-Mar-2018
###### Auto generated by spf13/cobra on 9-Mar-2018
......@@ -33,6 +33,7 @@ helm template [flags] CHART
--notes show the computed NOTES.txt file as well
--output-dir string writes the executed templates to files in output-dir instead of stdout
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
-f, --values valueFiles specify values in a YAML file (can specify multiple) (default [])
```
......@@ -50,4 +51,4 @@ helm template [flags] CHART
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 8-Mar-2018
###### Auto generated by spf13/cobra on 9-Mar-2018
......@@ -14,7 +14,8 @@ a packaged chart, or a fully qualified URL. For chart references, the latest
version will be specified unless the '--version' flag is set.
To override values in a chart, use either the '--values' flag and pass in a file
or use the '--set' flag and pass configuration from the command line.
or use the '--set' flag and pass configuration from the command line, to force string
values, use '--set-string'.
You can specify the '--values'/'-f' flag multiple times. The priority will be given to the
last (right-most) file specified. For example, if both myvalues.yaml and override.yaml
......@@ -52,6 +53,7 @@ helm upgrade [RELEASE] [CHART]
--reset-values when upgrading, reset the values to the ones built into the chart
--reuse-values when upgrading, reuse the last release's values, and merge in any new values. If '--reset-values' is specified, this is ignored.
--set stringArray set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-string stringArray set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--timeout int time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks) (default 300)
--tls enable TLS for request
--tls-ca-cert string path to TLS CA certificate file (default "$HELM_HOME/ca.pem")
......@@ -79,4 +81,4 @@ helm upgrade [RELEASE] [CHART]
### SEE ALSO
* [helm](helm.md) - The Helm package manager for Kubernetes.
###### Auto generated by spf13/cobra on 8-Mar-2018
###### Auto generated by spf13/cobra on 20-Mar-2018
......@@ -45,18 +45,38 @@ func ToYAML(s string) (string, error) {
func Parse(s string) (map[string]interface{}, error) {
vals := map[string]interface{}{}
scanner := bytes.NewBufferString(s)
t := newParser(scanner, vals)
t := newParser(scanner, vals, false)
err := t.parse()
return vals, err
}
//ParseInto parses a strvals line and merges the result into dest.
// Parse parses a set line and forces a string value.
//
// A set line is of the form name1=value1,name2=value2
func ParseString(s string) (map[string]interface{}, error) {
vals := map[string]interface{}{}
scanner := bytes.NewBufferString(s)
t := newParser(scanner, vals, true)
err := t.parse()
return vals, err
}
// ParseInto parses a strvals line and merges the result into dest.
//
// If the strval string has a key that exists in dest, it overwrites the
// dest version.
func ParseInto(s string, dest map[string]interface{}) error {
scanner := bytes.NewBufferString(s)
t := newParser(scanner, dest)
t := newParser(scanner, dest, false)
return t.parse()
}
// ParseIntoString parses a strvals line nad merges the result into dest.
//
// This method always returns a string as the value.
func ParseIntoString(s string, dest map[string]interface{}) error {
scanner := bytes.NewBufferString(s)
t := newParser(scanner, dest, true)
return t.parse()
}
......@@ -65,10 +85,11 @@ func ParseInto(s string, dest map[string]interface{}) error {
type parser struct {
sc *bytes.Buffer
data map[string]interface{}
st bool
}
func newParser(sc *bytes.Buffer, data map[string]interface{}) *parser {
return &parser{sc: sc, data: data}
func newParser(sc *bytes.Buffer, data map[string]interface{}, stringBool bool) *parser {
return &parser{sc: sc, data: data, st: stringBool}
}
func (t *parser) parse() error {
......@@ -133,7 +154,7 @@ func (t *parser) key(data map[string]interface{}) error {
return e
case ErrNotList:
v, e := t.val()
set(data, string(k), typedVal(v))
set(data, string(k), typedVal(v, t.st))
return e
default:
return e
......@@ -206,7 +227,7 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
return setIndex(list, i, ""), err
case ErrNotList:
v, e := t.val()
return setIndex(list, i, typedVal(v)), e
return setIndex(list, i, typedVal(v, t.st)), e
default:
return list, e
}
......@@ -265,10 +286,10 @@ func (t *parser) valList() ([]interface{}, error) {
if r, _, e := t.sc.ReadRune(); e == nil && r != ',' {
t.sc.UnreadRune()
}
list = append(list, typedVal(v))
list = append(list, typedVal(v, t.st))
return list, nil
case last == ',':
list = append(list, typedVal(v))
list = append(list, typedVal(v, t.st))
}
}
}
......@@ -298,7 +319,7 @@ func inMap(k rune, m map[rune]bool) bool {
return ok
}
func typedVal(v []rune) interface{} {
func typedVal(v []rune, st bool) interface{} {
val := string(v)
if strings.EqualFold(val, "true") {
return true
......@@ -308,8 +329,8 @@ func typedVal(v []rune) interface{} {
return false
}
// If this value does not start with zero, try parsing it to an int
if len(val) != 0 && val[0] != '0' {
// If this value does not start with zero, and not returnString, try parsing it to an int
if !st && len(val) != 0 && val[0] != '0' {
if iv, err := strconv.ParseInt(val, 10, 64); err == nil {
return iv
}
......
......@@ -65,6 +65,17 @@ func TestSetIndex(t *testing.T) {
}
func TestParseSet(t *testing.T) {
testsString := []struct {
str string
expect map[string]interface{}
err bool
}{
{
str: "long_int_string=1234567890",
expect: map[string]interface{}{"long_int_string": "1234567890"},
err: false,
},
}
tests := []struct {
str string
expect map[string]interface{}
......@@ -97,6 +108,10 @@ func TestParseSet(t *testing.T) {
str: "leading_zeros=00009",
expect: map[string]interface{}{"leading_zeros": "00009"},
},
{
str: "long_int=1234567890",
expect: map[string]interface{}{"long_int": 1234567890},
},
{
str: "name1,name2=",
err: true,
......@@ -278,6 +293,31 @@ func TestParseSet(t *testing.T) {
t.Fatalf("Error serializing parsed value: %s", err)
}
if string(y1) != string(y2) {
t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2)
}
}
for _, tt := range testsString {
got, err := ParseString(tt.str)
if err != nil {
if tt.err {
continue
}
t.Fatalf("%s: %s", tt.str, err)
}
if tt.err {
t.Errorf("%s: Expected error. Got nil", tt.str)
}
y1, err := yaml.Marshal(tt.expect)
if err != nil {
t.Fatal(err)
}
y2, err := yaml.Marshal(got)
if err != nil {
t.Fatalf("Error serializing parsed value: %s", err)
}
if string(y1) != string(y2) {
t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.str, y1, y2)
}
......
......@@ -830,6 +830,8 @@ _helm_install()
local_nonpersistent_flags+=("--repo=")
flags+=("--set=")
local_nonpersistent_flags+=("--set=")
flags+=("--set-string=")
local_nonpersistent_flags+=("--set-string=")
flags+=("--timeout=")
local_nonpersistent_flags+=("--timeout=")
flags+=("--tls")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment