Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oc new-app/new-build/process: add --env-file/--param-file parameters #12164

Merged
merged 2 commits into from
Dec 14, 2016

Conversation

mmilata
Copy link
Contributor

@mmilata mmilata commented Dec 6, 2016

@mmilata
Copy link
Contributor Author

mmilata commented Dec 6, 2016

[test]

@@ -82,6 +82,22 @@ os::cmd::expect_success_and_not_text 'oc new-app ruby-helloworld-sample --param
os::cmd::expect_success_and_text 'oc new-app php PASS=one,two=three -o yaml' 'value: one,two=three'
os::cmd::expect_success_and_not_text 'oc new-app php PASS=one,two=three -o yaml' 'no longer accepts comma-separated list'

# check that we can populate template parameters from file
param_file="${OS_ROOT}/test/testdata/test-cmd-newapp-params.env"
os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} -o yaml" 'value: thisisapassword'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use jsonpath to query for the specific value you want to check instead of checking that some small string exists in the broader YAML output. See https://github.com/openshift/origin/blob/master/test/cmd/newapp.sh#L65

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!

@mmilata
Copy link
Contributor Author

mmilata commented Dec 7, 2016

@bparees PTAL

@bparees
Copy link
Contributor

bparees commented Dec 7, 2016

flake #8571
[test]

@@ -168,8 +165,12 @@ func NewCmdNewApplication(name, baseName string, f *clientcmd.Factory, out, erro
cmd.Flags().StringSliceVarP(&config.TemplateFiles, "file", "f", config.TemplateFiles, "Path to a template file to use for the app.")
cmd.MarkFlagFilename("file", "yaml", "yml", "json")
cmd.Flags().StringArrayVarP(&config.TemplateParameters, "param", "p", config.TemplateParameters, "Specify a key-value pair (e.g., -p FOO=BAR) to set/override a parameter value in the template.")
cmd.Flags().StringVar(&config.TemplateParametersFile, "param-file", "", "File containing environment parameter values to set/override in the template.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/environment//

env, duplicateEnv, envErrs := cmdutil.ParseEnvironmentArguments(c.Environment)
for _, s := range duplicateEnv {
fmt.Fprintf(c.ErrOut, "warning: The environment variable %q was overwritten", s)
func parseAndCombine(what string, cmdline []string, file string, stdin io.Reader, errout io.Writer) (app.Environment, []error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

godoc

func ParseEnvironment(vals ...string) Environment {
// ParseEnvironmentAllowEmpty converts the provided strings in key=value form
// into environment entries. If case there's no equals sign in a string, it's
// considered as a key with empty
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"considered as a key with empty value"

@@ -44,6 +70,22 @@ func (e Environment) Add(envs ...map[string]string) {
}
}

// Join adds the environment variables to the current environment. In case of
// key confilct the old value is kept. Conflicting keys are returned as a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conflict

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will edit go files with :set spell from now.

@bparees
Copy link
Contributor

bparees commented Dec 7, 2016

@mmilata what was the ultimate resolution to the "how to handle multiline values in files" question? i see you're using a library, what does it support as far as multiline values? did @smarterclayton agree to it?

@bparees
Copy link
Contributor

bparees commented Dec 7, 2016

@openshift/api-review needs review for new command line args (support providing a file for list of env/parameter key/values) and also agreement on the multiline value syntax supported within the files.

@mmilata
Copy link
Contributor Author

mmilata commented Dec 7, 2016

@bparees Clayton suggested this one. It supports \n and \\ replacement when the right hand side is enclosed in quotes. There's some bash incompatibility but that could easily be improved.

@bparees
Copy link
Contributor

bparees commented Dec 7, 2016

@bparees Clayton suggested this one. It supports \n and \ replacement when the right hand side is enclosed in quotes. There's some bash incompatibility but that could easily be improved.

cool. (and thanks @smarterclayton)

@bparees bparees self-assigned this Dec 7, 2016
@@ -6,7 +6,7 @@ trap os::test::junit::reconcile_output EXIT
(
set +e
oc delete all,templates --all
oc delete user someval
oc delete user someval someval=moreval someval=moreval2 someval=moreval3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test in that file creates these users but doesn't delete them thus you can't run that file twice in a row. Not related to the envfile feature at all.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm a little surprised "=" is even a valid character in a username, but ok cool.

@@ -88,6 +88,9 @@ os::cmd::expect_success_and_not_text "oc process -f '${required_params}' require
os::cmd::expect_success_and_text "oc process -f '${required_params}' --value=required_param='`cat ${OS_ROOT}/test/testdata/multiline.txt`'" 'also,with=commas'
os::cmd::expect_success_and_text "oc process -f '${required_params}' --param=required_param='`cat ${OS_ROOT}/test/testdata/multiline.txt`'" 'also,with=commas'

# set template parameters from parameter file with multiline values
param_file="${OS_ROOT}/test/testdata/template_required_params.env"
os::cmd::expect_success_and_text "oc process -f '${required_params}' --param-file=${param_file} -o yaml" 'first$'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test from stdin?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see it's covered in test/cmd/templates.sh

i wonder if we shouldn't combine test/cmd/templates.sh and test/cmd/process.sh, seems like we probably have overlap and it's not like process can do anything except work with templates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, makes sense. Should I do that as part of this PR or open a new one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's just do it here.

@@ -168,8 +165,12 @@ func NewCmdNewApplication(name, baseName string, f *clientcmd.Factory, out, erro
cmd.Flags().StringSliceVarP(&config.TemplateFiles, "file", "f", config.TemplateFiles, "Path to a template file to use for the app.")
cmd.MarkFlagFilename("file", "yaml", "yml", "json")
cmd.Flags().StringArrayVarP(&config.TemplateParameters, "param", "p", config.TemplateParameters, "Specify a key-value pair (e.g., -p FOO=BAR) to set/override a parameter value in the template.")
cmd.Flags().StringVar(&config.TemplateParametersFile, "param-file", "", "File containing parameter values to set/override in the template.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accept multiple files, i.e. StringArrayVar

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all of these

@@ -168,8 +165,12 @@ func NewCmdNewApplication(name, baseName string, f *clientcmd.Factory, out, erro
cmd.Flags().StringSliceVarP(&config.TemplateFiles, "file", "f", config.TemplateFiles, "Path to a template file to use for the app.")
cmd.MarkFlagFilename("file", "yaml", "yml", "json")
cmd.Flags().StringArrayVarP(&config.TemplateParameters, "param", "p", config.TemplateParameters, "Specify a key-value pair (e.g., -p FOO=BAR) to set/override a parameter value in the template.")
cmd.Flags().StringVar(&config.TemplateParametersFile, "param-file", "", "File containing parameter values to set/override in the template.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all of these

//
//If "file" is "-" the file contents will be read from argument "stdin" (unless
//it's nil).
func parseAndCombine(what string, cmdline []string, filename string, stdin io.Reader, errout io.Writer) (app.Environment, []error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract this into common library code (app or something even higher)

// Join adds the environment variables to the current environment. In case of
// key conflict the old value is kept. Conflicting keys are returned as a
// slice.
func (e Environment) Join(more Environment) []string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably more consistent to call this AddIfNotPresent(...)

@smarterclayton
Copy link
Contributor

smarterclayton commented Dec 7, 2016 via email

@mmilata
Copy link
Contributor Author

mmilata commented Dec 8, 2016

Pushed version that addresses problems found in review so far. test/cmd/process.sh has been merged into test/cmd/templates.sh, the individual tests were left as-is.
PTAL

@bparees
Copy link
Contributor

bparees commented Dec 8, 2016

@openshift/cli-review ptal

@mmilata
Copy link
Contributor Author

mmilata commented Dec 8, 2016

Flake #8571 & outdated man pages which are regenerated now. [test]

@mmilata
Copy link
Contributor Author

mmilata commented Dec 8, 2016

Documentation: openshift/openshift-docs#3347

@mmilata
Copy link
Contributor Author

mmilata commented Dec 8, 2016

Still flake #8571.

// ParseEnvironmentAllowEmpty converts the provided strings in key=value form
// into environment entries. In case there's no equals sign in a string, it's
// considered as a key with empty value.
func ParseEnvironmentAllowEmpty(vals ...string) Environment {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case there's no equals sign in a string, it's considered as a key with empty value

Is this only for docker compose?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

@@ -24,6 +30,26 @@ func ParseEnvironment(vals ...string) Environment {
return env
}

func ParseEnvironment(vals ...string) (Environment, []string, []error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it would accepts invalid things for env keys. What happens if you do for example

--env="S P A C E S=test"

or have that pair in the file? Env vars are very strict about what's accepted for names, since you still have validArgumentEnvironment, make use of it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also godoc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added IsValidArgumentEnvironment check to ParseEnvironment as well as LoadEnvironmentFile because godotenv library allows such keys.

return env, nil
}

// ParseAndCombineEnvironment parses key-value records from the command line
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"... parses key=value records ..." for clarity.

errs = append(errs, fileErr)
}

duplicates = vars.AddIfNotPresent(fileVars)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make it clear in the godoc for this function that env pairs coming in the first argument takes precedence over the ones in files.

//
// If a file is "-" the file contents will be read from argument stdin (unless
// it's nil).
func ParseAndCombineEnvironment(cmdline []string, filenames []string, stdin io.Reader, dupfn func(string, string) error) (Environment, []error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just call it env []string or envs []string instead of cmdline []string, for proper separation of concerns. This function doesn't understand anything about cmd line stuff, and it's exported.

// If a file is "-" the file contents will be read from argument stdin (unless
// it's nil).
func ParseAndCombineEnvironment(cmdline []string, filenames []string, stdin io.Reader, dupfn func(string, string) error) (Environment, []error) {
vars, duplicates, errs := ParseEnvironment(cmdline...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

godoc should also mention that this function doesn't return parsing errors right away, but accumulates it with the ones returned by the provided duplicates function.

}

for _, fname := range filenames {
fileVars, fileErr := LoadEnvironmentFile(fname, stdin)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

godoc should also mention that it doesn't fail right away for errors loading the provided file. In fact, it feels like it should, if I do something completely wrong like --env-file=/nonexistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I'll change the function to return after encountering first error.

@@ -82,6 +82,20 @@ os::cmd::expect_success_and_not_text 'oc new-app ruby-helloworld-sample --param
os::cmd::expect_success_and_text 'oc new-app php PASS=one,two=three -o yaml' 'value: one,two=three'
os::cmd::expect_success_and_not_text 'oc new-app php PASS=one,two=three -o yaml' 'no longer accepts comma-separated list'

# check that we can populate template parameters from file
param_file="${OS_ROOT}/test/testdata/test-cmd-newapp-params.env"
os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_PASSWORD\")].value}'" 'thisisapassword'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--param-file needs failure test cases. Things like

--param-file invalid
--param-file /path/to/empty-params-file
--param-file /path/to/malformed-params-file (keys with invalid chars like *&*$%&=test, lines without a KEY=VALUE pattern, etc) 
--param-file /path/to/access-denied-file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add failure test cases. How can I cause access denied if the tests are run as root? Should empty file really cause an error?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can I cause access denied if the tests are run as root?

Ok, I'm ok with skipping this one. :)

Should empty file really cause an error?

No, it's ok to just interpret that as "no env vars to set", but still should have a test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also

--param-file directory

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, passing a directory does nothing, silently. Opened joho/godotenv#22 and updated the branch with a workaround that Stats the file first.


# check that we can set environment variables from env file
env_file="${OS_ROOT}/test/testdata/test-cmd-newapp-env.env"
os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for --env-file failure test cases.

@mmilata
Copy link
Contributor Author

mmilata commented Dec 9, 2016

Updated, PTAL @fabianofranz

@mmilata
Copy link
Contributor Author

mmilata commented Dec 12, 2016

flake #8502 [test]

@mmilata
Copy link
Contributor Author

mmilata commented Dec 12, 2016

still #8502 [test]

@mmilata
Copy link
Contributor Author

mmilata commented Dec 13, 2016

flake #12235 [test]

@mmilata
Copy link
Contributor Author

mmilata commented Dec 13, 2016

flake #9886, posibly #11747

@bparees
Copy link
Contributor

bparees commented Dec 14, 2016

lgtm but needs a rebase.

@openshift-bot openshift-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 14, 2016
test/cmd/process.sh has been merged into test/cmd/templates.sh since
they test the same functionality.
@openshift-bot
Copy link
Contributor

Evaluated for origin test up to 53e4af7

@mmilata
Copy link
Contributor Author

mmilata commented Dec 14, 2016

@bparees rebased.

@openshift-bot
Copy link
Contributor

continuous-integration/openshift-jenkins/test SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pr_origin/12372/) (Base Commit: 41702ed)

@openshift-bot openshift-bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Dec 14, 2016
@bparees
Copy link
Contributor

bparees commented Dec 14, 2016

[merge]

@openshift-bot
Copy link
Contributor

Evaluated for origin merge up to 53e4af7

@openshift-bot
Copy link
Contributor

openshift-bot commented Dec 14, 2016

continuous-integration/openshift-jenkins/merge SUCCESS (https://ci.openshift.redhat.com/jenkins/job/test_pr_origin/12373/) (Base Commit: ec9ff39) (Image: devenv-rhel7_5544)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants