Merge lp:~axwalk/juju-core/cmd-juju-unset-env into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2484
Proposed branch: lp:~axwalk/juju-core/cmd-juju-unset-env
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 295 lines (+198/-2)
8 files modified
cmd/juju/environment.go (+62/-0)
cmd/juju/environment_test.go (+72/-0)
cmd/juju/main.go (+1/-0)
cmd/juju/main_test.go (+2/-0)
state/api/client.go (+6/-0)
state/api/params/params.go (+6/-0)
state/apiserver/client/client.go (+8/-2)
state/apiserver/client/client_test.go (+41/-0)
To merge this branch: bzr merge lp:~axwalk/juju-core/cmd-juju-unset-env
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+212771@code.launchpad.net

Commit message

Introduce unset-environment subcommand

A new juju subcommand, unset-environment (with unset-env alias)
is introduced. This subcommand will take the existing environment
config, remove the specified keys, and update it in state. If
the specified keys have associated defaults, then they will be
assigned.

This is necessary for removing configuration for which an empty
value is not permitted, e.g. for string attributes which are
omitted by default, such as http-proxy.

Fixes lp:1295372

https://codereview.appspot.com/80380043/

Description of the change

Introduce unset-environment subcommand

A new juju subcommand, unset-environment (with unset-env alias)
is introduced. This subcommand will take the existing environment
config, remove the specified keys, and update it in state. If
the specified keys have associated defaults, then they will be
assigned.

This is necessary for removing configuration for which an empty
value is not permitted, e.g. for string attributes which are
omitted by default, such as http-proxy.

Fixes lp:1295372

https://codereview.appspot.com/80380043/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Reviewers: mp+212771_code.launchpad.net,

Message:
Please take a look.

Description:
Introduce unset-environment subcommand

A new juju subcommand, unset-environment (with unset-env alias)
is introduced. This subcommand will take the existing environment
config, remove the specified keys, and update it in state. If
the specified keys have associated defaults, then they will be
assigned.

This is necessary for removing configuration for which an empty
value is not permitted, e.g. for string attributes which are
omitted by default, such as http-proxy.

Fixes lp:1295372

https://code.launchpad.net/~axwalk/juju-core/cmd-juju-unset-env/+merge/212771

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/80380043/

Affected files (+196, -2 lines):
   A [revision details]
   M cmd/juju/environment.go
   M cmd/juju/environment_test.go
   M cmd/juju/main.go
   M cmd/juju/main_test.go
   M state/api/client.go
   M state/api/params/params.go
   M state/apiserver/client/client.go
   M state/apiserver/client/client_test.go

Revision history for this message
Ian Booth (wallyworld) wrote :

LGTM but I'd rather see more useful error message if an unset fails

https://codereview.appspot.com/80380043/diff/1/cmd/juju/environment.go
File cmd/juju/environment.go (right):

https://codereview.appspot.com/80380043/diff/1/cmd/juju/environment.go#newcode192
cmd/juju/environment.go:192: Set one or more the environment
configuration attributes to its default value
s/Set/Reset ?

https://codereview.appspot.com/80380043/diff/1/cmd/juju/environment.go#newcode193
cmd/juju/environment.go:193: in a running Juju instance. Attributes
without defaults are removed.
Perhaps include an example to show they are space separated? Or mention
that in the help?

https://codereview.appspot.com/80380043/diff/1/state/api/params/params.go
File state/api/params/params.go (right):

https://codereview.appspot.com/80380043/diff/1/state/api/params/params.go#newcode594
state/api/params/params.go:594: type EnvironmentUnset struct {
I wish there were a generic string args struct. Maybe there is, not
sure.

https://codereview.appspot.com/80380043/diff/1/state/apiserver/client/client_test.go
File state/apiserver/client/client_test.go (right):

https://codereview.appspot.com/80380043/diff/1/state/apiserver/client/client_test.go#newcode1579
state/apiserver/client/client_test.go:1579: c.Assert(err,
gc.ErrorMatches, "type: expected string, got nothing")
I don't like this error message. I realise it's the output of validate
but I'd expect to see "cannot unset blah" or something if i were a user.
Perhaps we could just wrap the error so it reads `cannot unset
environment attribute "type": blah blah`

https://codereview.appspot.com/80380043/

Revision history for this message
Andrew Wilkins (axwalk) wrote :

Please take a look.

https://codereview.appspot.com/80380043/diff/1/cmd/juju/environment.go
File cmd/juju/environment.go (right):

https://codereview.appspot.com/80380043/diff/1/cmd/juju/environment.go#newcode192
cmd/juju/environment.go:192: Set one or more the environment
configuration attributes to its default value
On 2014/03/26 06:13:43, wallyworld wrote:
> s/Set/Reset ?

Done.

https://codereview.appspot.com/80380043/diff/1/cmd/juju/environment.go#newcode193
cmd/juju/environment.go:193: in a running Juju instance. Attributes
without defaults are removed.
On 2014/03/26 06:13:43, wallyworld wrote:
> Perhaps include an example to show they are space separated? Or
mention that in
> the help?

Clarified in documentation.

https://codereview.appspot.com/80380043/diff/1/state/api/params/params.go
File state/api/params/params.go (right):

https://codereview.appspot.com/80380043/diff/1/state/api/params/params.go#newcode594
state/api/params/params.go:594: type EnvironmentUnset struct {
On 2014/03/26 06:13:43, wallyworld wrote:
> I wish there were a generic string args struct. Maybe there is, not
sure.

Nope, that I can see. Anyway, having API-specific ones means the struct
can be updated with additional fields if necessary.

https://codereview.appspot.com/80380043/diff/1/state/apiserver/client/client_test.go
File state/apiserver/client/client_test.go (right):

https://codereview.appspot.com/80380043/diff/1/state/apiserver/client/client_test.go#newcode1579
state/apiserver/client/client_test.go:1579: c.Assert(err,
gc.ErrorMatches, "type: expected string, got nothing")
On 2014/03/26 06:13:43, wallyworld wrote:
> I don't like this error message. I realise it's the output of validate
but I'd
> expect to see "cannot unset blah" or something if i were a user.
Perhaps we
> could just wrap the error so it reads `cannot unset environment
attribute
> "type": blah blah`

I agree the error sucks. The operaton isn't that granular, though. We're
saying "make all these changes to the config", and then checking if the
result is any good.

You can't necessarily remove them one at a time, either. It's feasible
that there are co-requisite attributes.

Perhaps the right thing to do is to have a method on EnvironProvider
that returns a config with defaults for all attributes that have
defaults. Then the attribute removal code can just reset them back to
those values, or error if there's no default and it's required. That's a
big change, though, and not something I want to drag into this.

https://codereview.appspot.com/80380043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cmd/juju/environment.go'
--- cmd/juju/environment.go 2014-03-12 22:33:09 +0000
+++ cmd/juju/environment.go 2014-03-26 06:33:09 +0000
@@ -181,3 +181,65 @@
181 }181 }
182 return err182 return err
183}183}
184
185// UnsetEnvironment
186type UnsetEnvironmentCommand struct {
187 cmd.EnvCommandBase
188 keys []string
189}
190
191const unsetEnvHelpDoc = `
192Reset one or more the environment configuration attributes to its default
193value in a running Juju instance. Attributes without defaults are removed,
194and attempting to remove a required attribute with no default will result
195in an error.
196
197Multiple attributes may be removed at once; keys are space-separated.
198`
199
200func (c *UnsetEnvironmentCommand) Info() *cmd.Info {
201 return &cmd.Info{
202 Name: "unset-environment",
203 Args: "<environment key> ...",
204 Purpose: "unset environment values",
205 Doc: strings.TrimSpace(unsetEnvHelpDoc),
206 Aliases: []string{"unset-env"},
207 }
208}
209
210func (c *UnsetEnvironmentCommand) Init(args []string) (err error) {
211 if len(args) == 0 {
212 return fmt.Errorf("No keys specified")
213 }
214 c.keys = args
215 return nil
216}
217
218// run1dot16 runs matches client.EnvironmentUnset using a direct DB
219// connection to maintain compatibility with an API server running 1.16 or
220// older (when EnvironmentUnset was not available). This fallback can be removed
221// when we no longer maintain 1.16 compatibility.
222func (c *UnsetEnvironmentCommand) run1dot16() error {
223 conn, err := juju.NewConnFromName(c.EnvName)
224 if err != nil {
225 return err
226 }
227 defer conn.Close()
228 return conn.State.UpdateEnvironConfig(nil, c.keys, nil)
229}
230
231func (c *UnsetEnvironmentCommand) Run(ctx *cmd.Context) error {
232 client, err := juju.NewAPIClientFromName(c.EnvName)
233 if err != nil {
234 return err
235 }
236 defer client.Close()
237
238 err = client.EnvironmentUnset(c.keys...)
239 if params.IsCodeNotImplemented(err) {
240 logger.Infof("EnvironmentUnset not supported by the API server, " +
241 "falling back to 1.16 compatibility mode (direct DB access)")
242 err = c.run1dot16()
243 }
244 return err
245}
184246
=== modified file 'cmd/juju/environment_test.go'
--- cmd/juju/environment_test.go 2014-03-17 06:03:51 +0000
+++ cmd/juju/environment_test.go 2014-03-26 06:33:09 +0000
@@ -7,8 +7,10 @@
7 "fmt"7 "fmt"
8 "strings"8 "strings"
99
10 jc "github.com/juju/testing/checkers"
10 gc "launchpad.net/gocheck"11 gc "launchpad.net/gocheck"
1112
13 "launchpad.net/juju-core/environs/config"
12 jujutesting "launchpad.net/juju-core/juju/testing"14 jujutesting "launchpad.net/juju-core/juju/testing"
13 "launchpad.net/juju-core/provider/dummy"15 "launchpad.net/juju-core/provider/dummy"
14 _ "launchpad.net/juju-core/provider/local"16 _ "launchpad.net/juju-core/provider/local"
@@ -178,3 +180,73 @@
178 c.Assert(err, gc.ErrorMatches, errorPattern)180 c.Assert(err, gc.ErrorMatches, errorPattern)
179 }181 }
180}182}
183
184type UnsetEnvironmentSuite struct {
185 jujutesting.RepoSuite
186}
187
188var _ = gc.Suite(&UnsetEnvironmentSuite{})
189
190var unsetEnvTests = []struct {
191 args []string
192 err string
193 expected attributes
194 unexpected []string
195}{
196 {
197 args: []string{},
198 err: "No keys specified",
199 }, {
200 args: []string{"xyz", "xyz"},
201 unexpected: []string{"xyz"},
202 }, {
203 args: []string{"type", "xyz"},
204 err: "type: expected string, got nothing",
205 expected: attributes{
206 "type": "dummy",
207 "xyz": 123,
208 },
209 }, {
210 args: []string{"syslog-port"},
211 expected: attributes{
212 "syslog-port": config.DefaultSyslogPort,
213 },
214 }, {
215 args: []string{"xyz2", "xyz"},
216 unexpected: []string{"xyz"},
217 },
218}
219
220func (s *UnsetEnvironmentSuite) initConfig(c *gc.C) {
221 err := s.State.UpdateEnvironConfig(map[string]interface{}{
222 "syslog-port": 1234,
223 "xyz": 123,
224 }, nil, nil)
225 c.Assert(err, gc.IsNil)
226}
227
228func (s *UnsetEnvironmentSuite) TestUnsetEnvironment(c *gc.C) {
229 for _, t := range unsetEnvTests {
230 c.Logf("testing unset-env %v", t.args)
231 s.initConfig(c)
232 _, err := testing.RunCommand(c, &UnsetEnvironmentCommand{}, t.args)
233 if t.err != "" {
234 c.Assert(err, gc.ErrorMatches, t.err)
235 } else {
236 c.Assert(err, gc.IsNil)
237 }
238 if len(t.expected)+len(t.unexpected) != 0 {
239 stateConfig, err := s.State.EnvironConfig()
240 c.Assert(err, gc.IsNil)
241 for k, v := range t.expected {
242 vstate, ok := stateConfig.AllAttrs()[k]
243 c.Assert(ok, jc.IsTrue)
244 c.Assert(vstate, gc.Equals, v)
245 }
246 for _, k := range t.unexpected {
247 _, ok := stateConfig.AllAttrs()[k]
248 c.Assert(ok, jc.IsFalse)
249 }
250 }
251 }
252}
181253
=== modified file 'cmd/juju/main.go'
--- cmd/juju/main.go 2014-03-21 14:28:36 +0000
+++ cmd/juju/main.go 2014-03-26 06:33:09 +0000
@@ -108,6 +108,7 @@
108 jujucmd.Register(wrap(&SetConstraintsCommand{}))108 jujucmd.Register(wrap(&SetConstraintsCommand{}))
109 jujucmd.Register(wrap(&GetEnvironmentCommand{}))109 jujucmd.Register(wrap(&GetEnvironmentCommand{}))
110 jujucmd.Register(wrap(&SetEnvironmentCommand{}))110 jujucmd.Register(wrap(&SetEnvironmentCommand{}))
111 jujucmd.Register(wrap(&UnsetEnvironmentCommand{}))
111 jujucmd.Register(wrap(&ExposeCommand{}))112 jujucmd.Register(wrap(&ExposeCommand{}))
112 jujucmd.Register(wrap(&SyncToolsCommand{}))113 jujucmd.Register(wrap(&SyncToolsCommand{}))
113 jujucmd.Register(wrap(&UnexposeCommand{}))114 jujucmd.Register(wrap(&UnexposeCommand{}))
114115
=== modified file 'cmd/juju/main_test.go'
--- cmd/juju/main_test.go 2014-03-26 01:22:46 +0000
+++ cmd/juju/main_test.go 2014-03-26 06:33:09 +0000
@@ -253,6 +253,8 @@
253 "terminate-machine", // alias for destroy-machine253 "terminate-machine", // alias for destroy-machine
254 "unexpose",254 "unexpose",
255 "unset",255 "unset",
256 "unset-env", // alias for unset-environment
257 "unset-environment",
256 "upgrade-charm",258 "upgrade-charm",
257 "upgrade-juju",259 "upgrade-juju",
258 "version",260 "version",
259261
=== modified file 'state/api/client.go'
--- state/api/client.go 2014-03-26 06:28:38 +0000
+++ state/api/client.go 2014-03-26 06:33:09 +0000
@@ -441,6 +441,12 @@
441 return c.call("EnvironmentSet", args, nil)441 return c.call("EnvironmentSet", args, nil)
442}442}
443443
444// EnvironmentUnset sets the given key-value pairs in the environment.
445func (c *Client) EnvironmentUnset(keys ...string) error {
446 args := params.EnvironmentUnset{Keys: keys}
447 return c.call("EnvironmentUnset", args, nil)
448}
449
444// SetEnvironAgentVersion sets the environment agent-version setting450// SetEnvironAgentVersion sets the environment agent-version setting
445// to the given value.451// to the given value.
446func (c *Client) SetEnvironAgentVersion(version version.Number) error {452func (c *Client) SetEnvironAgentVersion(version version.Number) error {
447453
=== modified file 'state/api/params/params.go'
--- state/api/params/params.go 2014-03-26 04:13:52 +0000
+++ state/api/params/params.go 2014-03-26 06:33:09 +0000
@@ -589,6 +589,12 @@
589 Config map[string]interface{}589 Config map[string]interface{}
590}590}
591591
592// EnvironmentUnset contains the arguments for EnvironmentUnset client API
593// call.
594type EnvironmentUnset struct {
595 Keys []string
596}
597
592// SetEnvironAgentVersion contains the arguments for598// SetEnvironAgentVersion contains the arguments for
593// SetEnvironAgentVersion client API call.599// SetEnvironAgentVersion client API call.
594type SetEnvironAgentVersion struct {600type SetEnvironAgentVersion struct {
595601
=== modified file 'state/apiserver/client/client.go'
--- state/apiserver/client/client.go 2014-03-26 04:13:52 +0000
+++ state/apiserver/client/client.go 2014-03-26 06:33:09 +0000
@@ -802,13 +802,19 @@
802 }802 }
803 return nil803 return nil
804 }804 }
805
806 // TODO(waigani) 2014-3-11 #1167616805 // TODO(waigani) 2014-3-11 #1167616
807 // Add a txn retry loop to ensure that the settings on disk have not806 // Add a txn retry loop to ensure that the settings on disk have not
808 // changed underneath us.807 // changed underneath us.
809
810 return c.api.state.UpdateEnvironConfig(args.Config, nil, checkAgentVersion)808 return c.api.state.UpdateEnvironConfig(args.Config, nil, checkAgentVersion)
809}
811810
811// EnvironmentUnset implements the server-side part of the
812// set-environment CLI command.
813func (c *Client) EnvironmentUnset(args params.EnvironmentUnset) error {
814 // TODO(waigani) 2014-3-11 #1167616
815 // Add a txn retry loop to ensure that the settings on disk have not
816 // changed underneath us.
817 return c.api.state.UpdateEnvironConfig(nil, args.Keys, nil)
812}818}
813819
814// SetEnvironAgentVersion sets the environment agent version.820// SetEnvironAgentVersion sets the environment agent version.
815821
=== modified file 'state/apiserver/client/client_test.go'
--- state/apiserver/client/client_test.go 2014-03-26 00:24:30 +0000
+++ state/apiserver/client/client_test.go 2014-03-26 06:33:09 +0000
@@ -1542,6 +1542,47 @@
1542 c.Assert(err, gc.IsNil)1542 c.Assert(err, gc.IsNil)
1543}1543}
15441544
1545func (s *clientSuite) TestClientEnvironmentUnset(c *gc.C) {
1546 err := s.State.UpdateEnvironConfig(map[string]interface{}{"abc": 123}, nil, nil)
1547 c.Assert(err, gc.IsNil)
1548 envConfig, err := s.State.EnvironConfig()
1549 c.Assert(err, gc.IsNil)
1550 _, found := envConfig.AllAttrs()["abc"]
1551 c.Assert(found, jc.IsTrue)
1552
1553 err = s.APIState.Client().EnvironmentUnset("abc")
1554 c.Assert(err, gc.IsNil)
1555 envConfig, err = s.State.EnvironConfig()
1556 c.Assert(err, gc.IsNil)
1557 _, found = envConfig.AllAttrs()["abc"]
1558 c.Assert(found, jc.IsFalse)
1559}
1560
1561func (s *clientSuite) TestClientEnvironmentUnsetMissing(c *gc.C) {
1562 // It's okay to unset a non-existent attribute.
1563 err := s.APIState.Client().EnvironmentUnset("not_there")
1564 c.Assert(err, gc.IsNil)
1565}
1566
1567func (s *clientSuite) TestClientEnvironmentUnsetError(c *gc.C) {
1568 err := s.State.UpdateEnvironConfig(map[string]interface{}{"abc": 123}, nil, nil)
1569 c.Assert(err, gc.IsNil)
1570 envConfig, err := s.State.EnvironConfig()
1571 c.Assert(err, gc.IsNil)
1572 _, found := envConfig.AllAttrs()["abc"]
1573 c.Assert(found, jc.IsTrue)
1574
1575 // "type" may not be removed, and this will cause an error.
1576 // If any one attribute's removal causes an error, there
1577 // should be no change.
1578 err = s.APIState.Client().EnvironmentUnset("abc", "type")
1579 c.Assert(err, gc.ErrorMatches, "type: expected string, got nothing")
1580 envConfig, err = s.State.EnvironConfig()
1581 c.Assert(err, gc.IsNil)
1582 _, found = envConfig.AllAttrs()["abc"]
1583 c.Assert(found, jc.IsTrue)
1584}
1585
1545func (s *clientSuite) TestClientFindTools(c *gc.C) {1586func (s *clientSuite) TestClientFindTools(c *gc.C) {
1546 result, err := s.APIState.Client().FindTools(2, -1, "", "")1587 result, err := s.APIState.Client().FindTools(2, -1, "", "")
1547 c.Assert(err, gc.IsNil)1588 c.Assert(err, gc.IsNil)

Subscribers

People subscribed via source and target branches

to status/vote changes: