Merge lp:~menno.smits/juju-core/1302005-bootstrap_series into lp:~go-bot/juju-core/trunk

Proposed by Menno Finlay-Smits
Status: Merged
Approved by: Menno Finlay-Smits
Approved revision: no longer in the source branch.
Merged at revision: 2706
Proposed branch: lp:~menno.smits/juju-core/1302005-bootstrap_series
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 193 lines (+104/-5)
2 files modified
cmd/juju/bootstrap.go (+47/-4)
cmd/juju/bootstrap_test.go (+57/-1)
To merge this branch: bzr merge lp:~menno.smits/juju-core/1302005-bootstrap_series
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+218152@code.launchpad.net

Commit message

cmd/juju: deprecate --series, added --upload-series

Emit a deprecation warning to stderr when --series is used

To make testing easier an interface is now used to allow the calls
made by BootstrapCommand.Run to environs/bootstrap to be mocked out.

https://codereview.appspot.com/94060044/

R=thumper

Description of the change

cmd/juju: refactor --series to use StringsValue

seriesVar is now called seriesValue and is implemented using
StringsValue. This reuses StringValue while preserving the series
validation logic.

https://codereview.appspot.com/94060044/

To post a comment you must log in.
Revision history for this message
Menno Finlay-Smits (menno.smits) wrote :
Download full text (3.8 KiB)

Reviewers: mp+218152_code.launchpad.net,

Message:
Please take a look.

Description:
cmd/juju: refactor --series to use StringsValue

seriesVar is now called seriesValue and is implemented using
StringsValue. This reuses StringValue while preserving the series
validation logic.

https://code.launchpad.net/~menno.smits/juju-core/1302005-bootstrap_series/+merge/218152

(do not edit description out of merge proposal)

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

Affected files (+28, -22 lines):
   A [revision details]
   M cmd/juju/bootstrap.go
   M cmd/juju/upgradejuju.go

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-20140501192736-36p3425ohtpy4np7
+New revision: <email address hidden>

Index: cmd/juju/bootstrap.go
=== modified file 'cmd/juju/bootstrap.go'
--- cmd/juju/bootstrap.go 2014-04-30 22:05:31 +0000
+++ cmd/juju/bootstrap.go 2014-05-02 19:25:05 +0000
@@ -6,7 +6,6 @@
  import (
   "fmt"
   "os"
- "strings"

   "launchpad.net/gnuflag"

@@ -81,7 +80,7 @@
   c.EnvCommandBase.SetFlags(f)
   f.Var(constraints.ConstraintsValue{Target:
&c.Constraints}, "constraints", "set environment constraints")
   f.BoolVar(&c.UploadTools, "upload-tools", false, "upload local version of
tools before bootstrapping")
- f.Var(seriesVar{&c.Series}, "series", "upload tools for supplied
comma-separated series list")
+ f.Var(newSeriesValue(nil, &c.Series), "series", "upload tools for
supplied comma-separated series list")
   f.StringVar(&c.MetadataSource, "metadata-source", "", "local path to use
as tools and/or metadata source")
   f.StringVar(&c.Placement, "to", "", "a placement directive indicating an
instance to bootstrap")
  }
@@ -106,6 +105,30 @@
   return cmd.CheckEmpty(args)
  }

+type seriesValue struct {
+ *cmd.StringsValue
+}
+
+// newSeriesValue is used to create the type passed into the
gnuflag.FlagSet Var function.
+func newSeriesValue(defaultValue []string, target *[]string) *seriesValue {
+ v := seriesValue{(*cmd.StringsValue)(target)}
+ *(v.StringsValue) = defaultValue
+ return &v
+}
+
+// Implements gnuflag.Value Set.
+func (v *seriesValue) Set(s string) error {
+ if err := v.StringsValue.Set(s); err != nil {
+ return err
+ }
+ for _, name := range *(v.StringsValue) {
+ if !charm.IsValidSeries(name) {
+ return fmt.Errorf("invalid series name %q", name)
+ }
+ }
+ return nil
+}
+
  // Run connects to the environment specified on the command line and
bootstraps
  // a juju in that environment if none already exists. If there is as yet
no environments.yaml file,
  // the user is informed how to create one.
@@ -174,22 +197,3 @@
    Placement: c.Placement,
   })
  }
-
-type seriesVar struct {
- target *[]string
-}
-
-func (v seriesVar) Set(value string) error {
- names := strings.Split(value, ",")
- for _, name := range names {
- if !charm.IsValidSeries(name) {
- return fmt.Errorf("invalid series name %q", name)
- }
- }
- *v.target = names
- return nil
-}
-
-func (v seriesVar) String() string {
- return strings.Join(*v....

Read more...

Revision history for this message
John A Meinel (jameinel) wrote :

Is there a specific advantage to using StringValue ? It looks like just code reshuffling without actually adding much. I'm happy to have it if there is an actual improvement in common handling (say StringsValue provides better parsing, etc).

So LGTM, though I'd like to understand what this actually helps with.

Revision history for this message
William Reade (fwereade) wrote :

LGTM

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

https://codereview.appspot.com/94060044/diff/1/cmd/juju/bootstrap.go#newcode128
cmd/juju/bootstrap.go:128: }
Quibble quibble whine: I'd rather validate before setting on the
StringsValue.

https://codereview.appspot.com/94060044/

Revision history for this message
John A Meinel (jameinel) wrote :

Don't you have to do the set first so that it parses the values into a
slice? Otherwise you just have the raw string and you are reimplementing
all the parsing anyway.

On Tue, May 6, 2014 at 11:39 AM, William Reade
<email address hidden>wrote:

> LGTM
>
>
> https://codereview.appspot.com/94060044/diff/1/cmd/juju/bootstrap.go
> File cmd/juju/bootstrap.go (right):
>
>
> https://codereview.appspot.com/94060044/diff/1/cmd/juju/bootstrap.go#newcode128
> cmd/juju/bootstrap.go:128: }
> Quibble quibble whine: I'd rather validate before setting on the
> StringsValue.
>
> https://codereview.appspot.com/94060044/
>
> --
>
> https://code.launchpad.net/~menno.smits/juju-core/1302005-bootstrap_series/+merge/218152
> You are subscribed to branch lp:juju-core.
>

Revision history for this message
William Reade (fwereade) wrote :

Dammit, ofc. Nil out the value on error?

Revision history for this message
Menno Finlay-Smits (menno.smits) wrote :

> Dammit, ofc. Nil out the value on error?

Done!

Revision history for this message
Menno Finlay-Smits (menno.smits) wrote :
Revision history for this message
Menno Finlay-Smits (menno.smits) wrote :
Revision history for this message
Tim Penhey (thumper) wrote :

On 2014/05/08 01:35:18, menn0 wrote:
> Please take a look.

Firstly, please don't reuse branches. It confuses things somewhat.

For new pieces of work, even related pieces, use a different branch.

https://codereview.appspot.com/94060044/

Revision history for this message
Tim Penhey (thumper) wrote :

LGTM with a few minor comments.

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go
File cmd/juju/bootstrap.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode85
cmd/juju/bootstrap.go:85: f.Var(newSeriesValue(nil, &c.seriesOld),
"series", "upload tools for supplied comma-separated series list
(DEPRECATED, see --upload-series)")
Wondering if we should move the deprecated bit to the front of the help
string. Thoughts?

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode174
cmd/juju/bootstrap.go:174: _bootstrap := getBootstrapFuncs()
a small part of me recoils at this prefix, but I can't really think of a
better one that makes more sense, so ok with it.

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap_test.go
File cmd/juju/bootstrap_test.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap_test.go#newcode438
cmd/juju/bootstrap_test.go:438: code := cmd.Main(&bootstrapCommand, ctx,
[]string{"--upload-tools", argVariant, "foo,bar"})
A better call would be the testing.RunCommand:

   RunCommand(c *gc.C, com cmd.Command, args []string) (*cmd.Context,
error)

ctx, err := testing.RunCommand(c, &BootstrapCommand{},
[]string{"--upload-tools", argVariant, "foo,bar"})
c.Assert(err, gc.IsNil)

https://codereview.appspot.com/94060044/

Revision history for this message
Menno Finlay-Smits (menno.smits) wrote :

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go
File cmd/juju/bootstrap.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode85
cmd/juju/bootstrap.go:85: f.Var(newSeriesValue(nil, &c.seriesOld),
"series", "upload tools for supplied comma-separated series list
(DEPRECATED, see --upload-series)")
On 2014/05/08 01:53:05, thumper wrote:
> Wondering if we should move the deprecated bit to the front of the
help string.
> Thoughts?

I have no strong opinion on this. I was just following what was already
done for the -u flag on the juju deploy command.

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode174
cmd/juju/bootstrap.go:174: _bootstrap := getBootstrapFuncs()
On 2014/05/08 01:53:05, thumper wrote:
> a small part of me recoils at this prefix, but I can't really think of
a better
> one that makes more sense, so ok with it.

I didn't like this much either. Alternatives I also considered where:

* bootstrap (shadowing the module): potentially confusing for the casual
reader.
* bootstrapApi: but it's not really an official API of any sort
* bootstrapFuncs or similar: collides with the struct but could change
the struct name.

Do any of these appeal more than _bootstrap?

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap_test.go
File cmd/juju/bootstrap_test.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap_test.go#newcode438
cmd/juju/bootstrap_test.go:438: code := cmd.Main(&bootstrapCommand, ctx,
[]string{"--upload-tools", argVariant, "foo,bar"})
On 2014/05/08 01:53:05, thumper wrote:
> A better call would be the testing.RunCommand:

> RunCommand(c *gc.C, com cmd.Command, args []string) (*cmd.Context,
error)

> ctx, err := testing.RunCommand(c, &BootstrapCommand{},
> []string{"--upload-tools", argVariant, "foo,bar"})
> c.Assert(err, gc.IsNil)

I got cmd.Main pattern this from the other tests in the file. RunCommand
is much more sensible. I'll change the test.

Should I do the others in this file as well? (as a separate change)

https://codereview.appspot.com/94060044/

Revision history for this message
Tim Penhey (thumper) wrote :

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go
File cmd/juju/bootstrap.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode85
cmd/juju/bootstrap.go:85: f.Var(newSeriesValue(nil, &c.seriesOld),
"series", "upload tools for supplied comma-separated series list
(DEPRECATED, see --upload-series)")
On 2014/05/08 02:35:48, menn0 wrote:
> On 2014/05/08 01:53:05, thumper wrote:
> > Wondering if we should move the deprecated bit to the front of the
help
> string.
> > Thoughts?

> I have no strong opinion on this. I was just following what was
already done for
> the -u flag on the juju deploy command.

I think it'll be OK... since we are emitting a deprecation warning
anyway.

If it was the ONLY deprecation warning there was then I'd say this would
be different.

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode174
cmd/juju/bootstrap.go:174: _bootstrap := getBootstrapFuncs()
On 2014/05/08 02:35:48, menn0 wrote:
> On 2014/05/08 01:53:05, thumper wrote:
> > a small part of me recoils at this prefix, but I can't really think
of a
> better
> > one that makes more sense, so ok with it.

> I didn't like this much either. Alternatives I also considered where:

> * bootstrap (shadowing the module): potentially confusing for the
casual reader.
> * bootstrapApi: but it's not really an official API of any sort
> * bootstrapFuncs or similar: collides with the struct but could change
the
> struct name.

> Do any of these appeal more than _bootstrap?

Shadowing the outer struct shouldn't be a big issue. I think of those
options, I'd prefer
   bootstrapFuncs

I know others would prefer "bf" or similar, but not me.

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap_test.go
File cmd/juju/bootstrap_test.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap_test.go#newcode438
cmd/juju/bootstrap_test.go:438: code := cmd.Main(&bootstrapCommand, ctx,
[]string{"--upload-tools", argVariant, "foo,bar"})
On 2014/05/08 02:35:48, menn0 wrote:
> On 2014/05/08 01:53:05, thumper wrote:
> > A better call would be the testing.RunCommand:
> >
> > RunCommand(c *gc.C, com cmd.Command, args []string) (*cmd.Context,
error)
> >
> > ctx, err := testing.RunCommand(c, &BootstrapCommand{},
> > []string{"--upload-tools", argVariant, "foo,bar"})
> > c.Assert(err, gc.IsNil)

> I got cmd.Main pattern this from the other tests in the file.
RunCommand is much
> more sensible. I'll change the test.

> Should I do the others in this file as well? (as a separate change)

Sure, that would be good.

https://codereview.appspot.com/94060044/

Revision history for this message
Menno Finlay-Smits (menno.smits) wrote :

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go
File cmd/juju/bootstrap.go (right):

https://codereview.appspot.com/94060044/diff/40001/cmd/juju/bootstrap.go#newcode174
cmd/juju/bootstrap.go:174: _bootstrap := getBootstrapFuncs()
On 2014/05/08 04:53:52, thumper wrote:
> On 2014/05/08 02:35:48, menn0 wrote:
> > On 2014/05/08 01:53:05, thumper wrote:
> > > a small part of me recoils at this prefix, but I can't really
think of a
> > better
> > > one that makes more sense, so ok with it.
> >
> > I didn't like this much either. Alternatives I also considered
where:
> >
> > * bootstrap (shadowing the module): potentially confusing for the
casual
> reader.
> > * bootstrapApi: but it's not really an official API of any sort
> > * bootstrapFuncs or similar: collides with the struct but could
change the
> > struct name.
> >
> > Do any of these appeal more than _bootstrap?

> Shadowing the outer struct shouldn't be a big issue. I think of those
options,
> I'd prefer
> bootstrapFuncs

> I know others would prefer "bf" or similar, but not me.

The only (minor) I have with bootstrapFuncs is that it's a type in the
outer scope and an instance of the type inside. Changing it anyway...

https://codereview.appspot.com/94060044/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmd/juju/bootstrap.go'
2--- cmd/juju/bootstrap.go 2014-05-06 20:39:36 +0000
3+++ cmd/juju/bootstrap.go 2014-05-08 05:19:19 +0000
4@@ -64,6 +64,7 @@
5 Constraints constraints.Value
6 UploadTools bool
7 Series []string
8+ seriesOld []string
9 MetadataSource string
10 Placement string
11 }
12@@ -80,7 +81,8 @@
13 c.EnvCommandBase.SetFlags(f)
14 f.Var(constraints.ConstraintsValue{Target: &c.Constraints}, "constraints", "set environment constraints")
15 f.BoolVar(&c.UploadTools, "upload-tools", false, "upload local version of tools before bootstrapping")
16- f.Var(newSeriesValue(nil, &c.Series), "series", "upload tools for supplied comma-separated series list")
17+ f.Var(newSeriesValue(nil, &c.Series), "upload-series", "upload tools for supplied comma-separated series list")
18+ f.Var(newSeriesValue(nil, &c.seriesOld), "series", "upload tools for supplied comma-separated series list (DEPRECATED, see --upload-series)")
19 f.StringVar(&c.MetadataSource, "metadata-source", "", "local path to use as tools and/or metadata source")
20 f.StringVar(&c.Placement, "to", "", "a placement directive indicating an instance to bootstrap")
21 }
22@@ -91,8 +93,18 @@
23 return
24 }
25 if len(c.Series) > 0 && !c.UploadTools {
26+ return fmt.Errorf("--upload-series requires --upload-tools")
27+ }
28+ if len(c.seriesOld) > 0 && !c.UploadTools {
29 return fmt.Errorf("--series requires --upload-tools")
30 }
31+ if len(c.Series) > 0 && len(c.seriesOld) > 0 {
32+ return fmt.Errorf("--upload-series and --series can't be used together")
33+ }
34+ if len(c.seriesOld) > 0 {
35+ c.Series = c.seriesOld
36+ }
37+
38 // Parse the placement directive. Bootstrap currently only
39 // supports provider-specific placement directives.
40 if c.Placement != "" {
41@@ -130,10 +142,41 @@
42 return nil
43 }
44
45+// bootstrap functionality that Run calls to support cleaner testing
46+type BootstrapInterface interface {
47+ EnsureNotBootstrapped(env environs.Environ) error
48+ UploadTools(environs.BootstrapContext, environs.Environ, *string, bool, ...string) error
49+ Bootstrap(ctx environs.BootstrapContext, environ environs.Environ, args environs.BootstrapParams) error
50+}
51+
52+type bootstrapFuncs struct{}
53+
54+func (b bootstrapFuncs) EnsureNotBootstrapped(env environs.Environ) error {
55+ return bootstrap.EnsureNotBootstrapped(env)
56+}
57+
58+func (b bootstrapFuncs) UploadTools(ctx environs.BootstrapContext, env environs.Environ, toolsArch *string, forceVersion bool, bootstrapSeries ...string) error {
59+ return bootstrap.UploadTools(ctx, env, toolsArch, forceVersion, bootstrapSeries...)
60+}
61+
62+func (b bootstrapFuncs) Bootstrap(ctx environs.BootstrapContext, env environs.Environ, args environs.BootstrapParams) error {
63+ return bootstrap.Bootstrap(ctx, env, args)
64+}
65+
66+var getBootstrapFuncs = func() BootstrapInterface {
67+ return &bootstrapFuncs{}
68+}
69+
70 // Run connects to the environment specified on the command line and bootstraps
71 // a juju in that environment if none already exists. If there is as yet no environments.yaml file,
72 // the user is informed how to create one.
73 func (c *BootstrapCommand) Run(ctx *cmd.Context) (resultErr error) {
74+ bootstrapFuncs := getBootstrapFuncs()
75+
76+ if len(c.seriesOld) > 0 {
77+ fmt.Fprintln(ctx.Stderr, "Use of --series is deprecated. Please use --upload-series instead.")
78+ }
79+
80 environ, cleanup, err := environFromName(ctx, c.EnvName, &resultErr, "Bootstrap")
81 if err != nil {
82 return err
83@@ -150,7 +193,7 @@
84 }
85
86 defer cleanup()
87- if err := bootstrap.EnsureNotBootstrapped(environ); err != nil {
88+ if err := bootstrapFuncs.EnsureNotBootstrapped(environ); err != nil {
89 return err
90 }
91
92@@ -188,12 +231,12 @@
93 c.UploadTools = true
94 }
95 if c.UploadTools {
96- err = bootstrap.UploadTools(ctx, environ, c.Constraints.Arch, true, c.Series...)
97+ err = bootstrapFuncs.UploadTools(ctx, environ, c.Constraints.Arch, true, c.Series...)
98 if err != nil {
99 return err
100 }
101 }
102- return bootstrap.Bootstrap(ctx, environ, environs.BootstrapParams{
103+ return bootstrapFuncs.Bootstrap(ctx, environ, environs.BootstrapParams{
104 Constraints: c.Constraints,
105 Placement: c.Placement,
106 })
107
108=== modified file 'cmd/juju/bootstrap_test.go'
109--- cmd/juju/bootstrap_test.go 2014-04-30 22:05:31 +0000
110+++ cmd/juju/bootstrap_test.go 2014-05-08 05:19:19 +0000
111@@ -305,6 +305,14 @@
112 args: []string{"--series", "fine"},
113 err: `--series requires --upload-tools`,
114 }, {
115+ info: "lonely --upload-series",
116+ args: []string{"--upload-series", "fine"},
117+ err: `--upload-series requires --upload-tools`,
118+}, {
119+ info: "--upload-series with --series",
120+ args: []string{"--upload-tools", "--upload-series", "foo", "--series", "bar"},
121+ err: `--upload-series and --series can't be used together`,
122+}, {
123 info: "bad environment",
124 version: "1.2.3-%LTS%-amd64",
125 args: []string{"-e", "brokenenv"},
126@@ -351,7 +359,7 @@
127 }, {
128 info: "--upload-tools rejects invalid series",
129 version: "1.2.3-saucy-amd64",
130- args: []string{"--upload-tools", "--series", "ping,ping,pong"},
131+ args: []string{"--upload-tools", "--upload-series", "ping,ping,pong"},
132 err: `invalid series "ping"`,
133 }, {
134 info: "--upload-tools rejects mismatched arch",
135@@ -407,6 +415,33 @@
136 c.Check(coretesting.Stdout(ctx2), gc.Equals, "")
137 }
138
139+func (s *BootstrapSuite) TestSeriesDeprecation(c *gc.C) {
140+ ctx := s.checkSeriesArg(c, "--series")
141+ c.Check(coretesting.Stderr(ctx), gc.Equals,
142+ "Use of --series is deprecated. Please use --upload-series instead.\n")
143+}
144+
145+func (s *BootstrapSuite) TestNoDeprecationWithUploadSeries(c *gc.C) {
146+ ctx := s.checkSeriesArg(c, "--upload-series")
147+ c.Check(coretesting.Stderr(ctx), gc.Equals, "")
148+}
149+
150+func (s *BootstrapSuite) checkSeriesArg(c *gc.C, argVariant string) *cmd.Context {
151+ _bootstrap := &fakeBootstrapFuncs{}
152+ s.PatchValue(&getBootstrapFuncs, func() BootstrapInterface {
153+ return _bootstrap
154+ })
155+ _, fake := makeEmptyFakeHome(c)
156+ defer fake.Restore()
157+
158+ ctx, err := coretesting.RunCommand(c, &BootstrapCommand{},
159+ []string{"--upload-tools", argVariant, "foo,bar"})
160+
161+ c.Assert(err, gc.IsNil)
162+ c.Check(_bootstrap.uploadToolsSeries, gc.DeepEquals, []string{"foo", "bar"})
163+ return ctx
164+}
165+
166 func (s *BootstrapSuite) TestBootstrapJenvWarning(c *gc.C) {
167 env, fake := makeEmptyFakeHome(c)
168 defer fake.Restore()
169@@ -704,3 +739,24 @@
170 }
171 return all
172 }
173+
174+// TODO(menn0): This fake BootstrapInterface implementation is
175+// currently quite minimal but could be easily extended to cover more
176+// test scenarios. This could help improve some of the tests in this
177+// file which execute large amounts of external functionality.
178+type fakeBootstrapFuncs struct {
179+ uploadToolsSeries []string
180+}
181+
182+func (fake *fakeBootstrapFuncs) EnsureNotBootstrapped(env environs.Environ) error {
183+ return nil
184+}
185+
186+func (fake *fakeBootstrapFuncs) UploadTools(ctx environs.BootstrapContext, env environs.Environ, toolsArch *string, forceVersion bool, bootstrapSeries ...string) error {
187+ fake.uploadToolsSeries = bootstrapSeries
188+ return nil
189+}
190+
191+func (fake fakeBootstrapFuncs) Bootstrap(ctx environs.BootstrapContext, env environs.Environ, args environs.BootstrapParams) error {
192+ return nil
193+}

Subscribers

People subscribed via source and target branches

to status/vote changes: