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

Add support for --config key=value for juju deploy #8206

Merged
merged 1 commit into from
Dec 13, 2017

Conversation

wallyworld
Copy link
Member

@wallyworld wallyworld commented Dec 12, 2017

Description of change

juju deploy help claims that it supports
$ juju deploy mysql --config foo=bar

But it didn't. It only supported --config path/to/yaml
(where the yaml file wasn't a key values but a map kyed on charm name).

Add support for --config key=value along with a yaml file.
If more than one yaml file is specified, that's an error.
If both config name values and a yaml file are specified, the config name values take precedence over the values in the yaml file.

QA steps

bootstrap
deploy a charm and specify key=value and ensure these are used

Documentation changes

None because juju didn't behave like the doc said it should.

@wallyworld wallyworld force-pushed the deploy-config branch 2 times, most recently from fc6aa0b to a21147b Compare December 12, 2017 07:13
@wallyworld
Copy link
Member Author

!!build!!

@wallyworld wallyworld force-pushed the deploy-config branch 2 times, most recently from 7487bb1 to d5e2d19 Compare December 12, 2017 08:01
@wallyworld
Copy link
Member Author

!!build!!

return errors.Trace(err)
}
if len(files) > 1 {
return errors.Errorf("only a single config YAMl file can be specified, got %d", len(files))
Copy link
Contributor

Choose a reason for hiding this comment

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

YAML

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

var configFromFile map[string]map[interface{}]interface{}
err := yaml.Unmarshal(configYAML, &configFromFile)
if err != nil {
return errors.Annotate(err, "badly formatted YAMl config file")
Copy link
Contributor

Choose a reason for hiding this comment

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

YAML

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

// So we need to combine the two here to have only one.
if apiRoot.BestFacadeVersion("Application") < 6 && len(appConfig) > 0 {
var configFromFile map[string]map[interface{}]interface{}
err := yaml.Unmarshal(configYAML, &configFromFile)
Copy link
Contributor

Choose a reason for hiding this comment

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

configYAML is (was) intentionally not decoded on the client side

I'm not sure if there's a safe way to do this with gopkg.in/yaml. Looks like it'll use encoding.TextUnmarshaler, so probably that way. If it were json, I'd suggest unmarshalling into a map[string]json.RawMessage, combining those, and then marshalling them again.

IMO, just raise an error here and people can upgrade to a newer controller. Or at least defer this work.

Copy link
Member Author

Choose a reason for hiding this comment

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

Why do we not decode client side? We're not interpreting anything or coercing into values. We're simply adding extra values.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we not decode client side?

Because we don't have the schema on the client side. We don't know which type to use. 42 could be a unmarshaled into any of string, int, or float. By unmarshaling into map[string]interface{}, you get the default-according-to-gopkg.in/yaml.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, but it goes across the wire as a string when we marshal back to yaml. So "42" will round trip back to "42" and will be parsed using the schema on the server side.

Copy link
Contributor

Choose a reason for hiding this comment

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

I chose a bad example, substitute in 42.0. That will be unmarshaled as float64 42. Float64 42 marshals as "42" and not "42.0".

If the charm setting was in fact a float, then that'd be fine. But if it's a string, you've dropped the ".0", which may not be fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed the type we unmarshal into to be:

map[string]charm.Settings

This preserves the string values as written into the YAML, ie "123.0" remains as "123.0" during the round trip as it is unmarshalled into a string value

Copy link
Contributor

Choose a reason for hiding this comment

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

charm.Settings is just a map[string]interface{}

I just tested this:

val := charm.Settings{}
yaml.Unmarshal([]byte("x: 42.0"), &val)
out, _ := yaml.Marshal(val)
fmt.Printf("%s\n", out)

and the output was x: 42

Copy link
Member Author

Choose a reason for hiding this comment

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

I had it as map[string]string and mistakenly though charm.Settings was also map[string]string.
I changed it back.

    val := map[string]string{}
    yaml.Unmarshal([]byte("x: 42.0"), &val)
    out, _ := yaml.Marshal(val)
    fmt.Printf("%s\n", out)

prints x: "42.0"

charmSettings[k] = v
}
configFromFile[applicationName] = charmSettings
configYAML, err = yaml.Marshal(configFromFile)
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't you be setting appConfig to nil somewhere here?

Copy link
Member Author

Choose a reason for hiding this comment

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

it doesn't matter because if there's a configYAML, it will mask any config map entries

Copy link
Contributor

Choose a reason for hiding this comment

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

true, but it would be nicer - no unnecessary data on the wire

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@@ -136,3 +139,70 @@ func (m stringMap) String() string {
}
return strings.Join(pairs, ";")
}

// configFlag records k=v attributes from command arguments
Copy link
Contributor

Choose a reason for hiding this comment

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

most of this is the same as common.ConfigFlag - why not just modify that a bit? AFAICS, all you need is to add methods for accessing the k=v attrs and the filenames

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't want to break encapsulation. Either way works for me. I changed to use common.ConfigFlag

if fields[1] == "" {
value = ""
} else {
if err := yaml.Unmarshal([]byte(fields[1]), &value); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we should be parsing the value as YAML for application config. Can we make that bit configurable please, and disable it for the "juju config" command?

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@wallyworld wallyworld force-pushed the deploy-config branch 4 times, most recently from 635365a to b972898 Compare December 13, 2017 00:38
preserveType bool
}

// SetPreserveType sets whether name values should be
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on how preserveType is used, I don't understand this at all. Is it meant to be preserving the string type? Or inferring the type based on the value's contents (i.e. decoding as YAML)?

Perhaps be a bit more literal, and make this

// SetDecodeYAMLValues controls whether or not config values
// are decoded as YAML into their default types, or to store the
// original string values. The default is to decode as YAML.
func (*ConfigFlag) SetDecodeYAMLValues(bool)

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to "SetPreserveStringValue" and expanded the comment to hopefully clarify.

}
appConfig := make(map[string]string)
for k, v := range attr {
appConfig[k] = fmt.Sprintf("%v", v)
Copy link
Contributor

Choose a reason for hiding this comment

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

should be safe to just v.(string), since you've said to preserve string values

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

@wallyworld
Copy link
Member Author

$$merge$$

@jujubot
Copy link
Collaborator

jujubot commented Dec 13, 2017

Status: merge request accepted. Url: http://ci.jujucharms.com/job/github-merge-juju

@jujubot
Copy link
Collaborator

jujubot commented Dec 13, 2017

Build failed: Tests failed
build url: http://ci.jujucharms.com/job/github-merge-juju/670

@wallyworld
Copy link
Member Author

$$merge$$

@jujubot
Copy link
Collaborator

jujubot commented Dec 13, 2017

Status: merge request accepted. Url: http://ci.jujucharms.com/job/github-merge-juju

@jujubot jujubot merged commit fdcd718 into juju:develop Dec 13, 2017
wallyworld pushed a commit to wallyworld/juju that referenced this pull request Dec 15, 2017
Add support for --config key=value for juju deploy

juju deploy help claims that it supports
$ juju deploy mysql --config foo=bar

But it didn't. It only supported --config path/to/yaml
(where the yaml file wasn't a key values but a map kyed on charm name).

Add support for --config key=value along with a yaml file.
If more than one yaml file is specified, that's an error.
If both config name values and a yaml file are specified, the config name values take precedence over the values in the yaml file.

bootstrap
deploy a charm and specify key=value and ensure these are used

None because juju didn't behave like the doc said it should.
@wallyworld wallyworld mentioned this pull request Dec 15, 2017
jujubot added a commit that referenced this pull request Dec 15, 2017
Backport 2.4 fixes

## Description of change

Backport 2 fixes:
#8206 which adds support for juju deploy --config name=value
#8227 which adds relation status on import if they are missing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants