Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2012, 2013 Canonical Ltd. | 1 // Copyright 2012, 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package main | 4 package main |
5 | 5 |
6 import ( | 6 import ( |
7 "fmt" | 7 "fmt" |
8 "os" | 8 "os" |
9 | 9 |
10 "launchpad.net/gnuflag" | 10 "launchpad.net/gnuflag" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
57 juju help set-constraints | 57 juju help set-constraints |
58 ` | 58 ` |
59 | 59 |
60 // BootstrapCommand is responsible for launching the first machine in a juju | 60 // BootstrapCommand is responsible for launching the first machine in a juju |
61 // environment, and setting up everything necessary to continue working. | 61 // environment, and setting up everything necessary to continue working. |
62 type BootstrapCommand struct { | 62 type BootstrapCommand struct { |
63 envcmd.EnvCommandBase | 63 envcmd.EnvCommandBase |
64 Constraints constraints.Value | 64 Constraints constraints.Value |
65 UploadTools bool | 65 UploadTools bool |
66 Series []string | 66 Series []string |
67 seriesOld []string | |
67 MetadataSource string | 68 MetadataSource string |
68 Placement string | 69 Placement string |
69 } | 70 } |
70 | 71 |
71 func (c *BootstrapCommand) Info() *cmd.Info { | 72 func (c *BootstrapCommand) Info() *cmd.Info { |
72 return &cmd.Info{ | 73 return &cmd.Info{ |
73 Name: "bootstrap", | 74 Name: "bootstrap", |
74 Purpose: "start up an environment from scratch", | 75 Purpose: "start up an environment from scratch", |
75 Doc: bootstrapDoc, | 76 Doc: bootstrapDoc, |
76 } | 77 } |
77 } | 78 } |
78 | 79 |
79 func (c *BootstrapCommand) SetFlags(f *gnuflag.FlagSet) { | 80 func (c *BootstrapCommand) SetFlags(f *gnuflag.FlagSet) { |
80 c.EnvCommandBase.SetFlags(f) | 81 c.EnvCommandBase.SetFlags(f) |
81 f.Var(constraints.ConstraintsValue{Target: &c.Constraints}, "constraints ", "set environment constraints") | 82 f.Var(constraints.ConstraintsValue{Target: &c.Constraints}, "constraints ", "set environment constraints") |
82 f.BoolVar(&c.UploadTools, "upload-tools", false, "upload local version o f tools before bootstrapping") | 83 f.BoolVar(&c.UploadTools, "upload-tools", false, "upload local version o f tools before bootstrapping") |
83 » f.Var(newSeriesValue(nil, &c.Series), "series", "upload tools for suppli ed comma-separated series list") | 84 » f.Var(newSeriesValue(nil, &c.Series), "upload-series", "upload tools for supplied comma-separated series list") |
85 » f.Var(newSeriesValue(nil, &c.seriesOld), "series", "upload tools for sup plied comma-separated series list (DEPRECATED, see --upload-series)") | |
thumper
2014/05/08 01:53:05
Wondering if we should move the deprecated bit to
menn0
2014/05/08 02:35:48
I have no strong opinion on this. I was just follo
thumper
2014/05/08 04:53:52
I think it'll be OK... since we are emitting a dep
| |
84 f.StringVar(&c.MetadataSource, "metadata-source", "", "local path to use as tools and/or metadata source") | 86 f.StringVar(&c.MetadataSource, "metadata-source", "", "local path to use as tools and/or metadata source") |
85 f.StringVar(&c.Placement, "to", "", "a placement directive indicating an instance to bootstrap") | 87 f.StringVar(&c.Placement, "to", "", "a placement directive indicating an instance to bootstrap") |
86 } | 88 } |
87 | 89 |
88 func (c *BootstrapCommand) Init(args []string) (err error) { | 90 func (c *BootstrapCommand) Init(args []string) (err error) { |
89 err = c.EnvCommandBase.Init() | 91 err = c.EnvCommandBase.Init() |
90 if err != nil { | 92 if err != nil { |
91 return | 93 return |
92 } | 94 } |
93 if len(c.Series) > 0 && !c.UploadTools { | 95 if len(c.Series) > 0 && !c.UploadTools { |
96 return fmt.Errorf("--upload-series requires --upload-tools") | |
97 } | |
98 if len(c.seriesOld) > 0 && !c.UploadTools { | |
94 return fmt.Errorf("--series requires --upload-tools") | 99 return fmt.Errorf("--series requires --upload-tools") |
95 } | 100 } |
101 if len(c.Series) > 0 && len(c.seriesOld) > 0 { | |
102 return fmt.Errorf("--upload-series and --series can't be used to gether") | |
103 } | |
104 if len(c.seriesOld) > 0 { | |
105 c.Series = c.seriesOld | |
106 } | |
107 | |
96 // Parse the placement directive. Bootstrap currently only | 108 // Parse the placement directive. Bootstrap currently only |
97 // supports provider-specific placement directives. | 109 // supports provider-specific placement directives. |
98 if c.Placement != "" { | 110 if c.Placement != "" { |
99 _, err = instance.ParsePlacement(c.Placement) | 111 _, err = instance.ParsePlacement(c.Placement) |
100 if err != instance.ErrPlacementScopeMissing { | 112 if err != instance.ErrPlacementScopeMissing { |
101 // We only support unscoped placement directives for boo tstrap. | 113 // We only support unscoped placement directives for boo tstrap. |
102 return fmt.Errorf("unsupported bootstrap placement direc tive %q", c.Placement) | 114 return fmt.Errorf("unsupported bootstrap placement direc tive %q", c.Placement) |
103 } | 115 } |
104 } | 116 } |
105 return cmd.CheckEmpty(args) | 117 return cmd.CheckEmpty(args) |
(...skipping 17 matching lines...) Expand all Loading... | |
123 } | 135 } |
124 for _, name := range *(v.StringsValue) { | 136 for _, name := range *(v.StringsValue) { |
125 if !charm.IsValidSeries(name) { | 137 if !charm.IsValidSeries(name) { |
126 v.StringsValue = nil | 138 v.StringsValue = nil |
127 return fmt.Errorf("invalid series name %q", name) | 139 return fmt.Errorf("invalid series name %q", name) |
128 } | 140 } |
129 } | 141 } |
130 return nil | 142 return nil |
131 } | 143 } |
132 | 144 |
145 // bootstrap functionality that Run calls to support cleaner testing | |
146 type BootstrapInterface interface { | |
147 EnsureNotBootstrapped(env environs.Environ) error | |
148 UploadTools(environs.BootstrapContext, environs.Environ, *string, bool, ...string) error | |
149 Bootstrap(ctx environs.BootstrapContext, environ environs.Environ, args environs.BootstrapParams) error | |
150 } | |
151 | |
152 type bootstrapFuncs struct{} | |
153 | |
154 func (b bootstrapFuncs) EnsureNotBootstrapped(env environs.Environ) error { | |
155 return bootstrap.EnsureNotBootstrapped(env) | |
156 } | |
157 | |
158 func (b bootstrapFuncs) UploadTools(ctx environs.BootstrapContext, env environs. Environ, toolsArch *string, forceVersion bool, bootstrapSeries ...string) error { | |
159 return bootstrap.UploadTools(ctx, env, toolsArch, forceVersion, bootstra pSeries...) | |
160 } | |
161 | |
162 func (b bootstrapFuncs) Bootstrap(ctx environs.BootstrapContext, env environs.En viron, args environs.BootstrapParams) error { | |
163 return bootstrap.Bootstrap(ctx, env, args) | |
164 } | |
165 | |
166 var getBootstrapFuncs = func() BootstrapInterface { | |
167 return &bootstrapFuncs{} | |
168 } | |
169 | |
133 // Run connects to the environment specified on the command line and bootstraps | 170 // Run connects to the environment specified on the command line and bootstraps |
134 // a juju in that environment if none already exists. If there is as yet no envi ronments.yaml file, | 171 // a juju in that environment if none already exists. If there is as yet no envi ronments.yaml file, |
135 // the user is informed how to create one. | 172 // the user is informed how to create one. |
136 func (c *BootstrapCommand) Run(ctx *cmd.Context) (resultErr error) { | 173 func (c *BootstrapCommand) Run(ctx *cmd.Context) (resultErr error) { |
174 _bootstrap := getBootstrapFuncs() | |
thumper
2014/05/08 01:53:05
a small part of me recoils at this prefix, but I c
menn0
2014/05/08 02:35:48
I didn't like this much either. Alternatives I als
thumper
2014/05/08 04:53:52
Shadowing the outer struct shouldn't be a big issu
menn0
2014/05/08 05:20:48
The only (minor) I have with bootstrapFuncs is tha
| |
175 | |
176 if len(c.seriesOld) > 0 { | |
177 fmt.Fprintln(ctx.Stderr, "Use of --series is deprecated. Please use --upload-series instead.") | |
178 } | |
179 | |
137 environ, cleanup, err := environFromName(ctx, c.EnvName, &resultErr, "Bo otstrap") | 180 environ, cleanup, err := environFromName(ctx, c.EnvName, &resultErr, "Bo otstrap") |
138 if err != nil { | 181 if err != nil { |
139 return err | 182 return err |
140 } | 183 } |
141 validator, err := environ.ConstraintsValidator() | 184 validator, err := environ.ConstraintsValidator() |
142 if err != nil { | 185 if err != nil { |
143 return err | 186 return err |
144 } | 187 } |
145 unsupported, err := validator.Validate(c.Constraints) | 188 unsupported, err := validator.Validate(c.Constraints) |
146 if len(unsupported) > 0 { | 189 if len(unsupported) > 0 { |
147 logger.Warningf("unsupported constraints: %v", err) | 190 logger.Warningf("unsupported constraints: %v", err) |
148 } else if err != nil { | 191 } else if err != nil { |
149 return err | 192 return err |
150 } | 193 } |
151 | 194 |
152 defer cleanup() | 195 defer cleanup() |
153 » if err := bootstrap.EnsureNotBootstrapped(environ); err != nil { | 196 » if err := _bootstrap.EnsureNotBootstrapped(environ); err != nil { |
154 return err | 197 return err |
155 } | 198 } |
156 | 199 |
157 // Block interruption during bootstrap. Providers may also | 200 // Block interruption during bootstrap. Providers may also |
158 // register for interrupt notification so they can exit early. | 201 // register for interrupt notification so they can exit early. |
159 interrupted := make(chan os.Signal, 1) | 202 interrupted := make(chan os.Signal, 1) |
160 defer close(interrupted) | 203 defer close(interrupted) |
161 ctx.InterruptNotify(interrupted) | 204 ctx.InterruptNotify(interrupted) |
162 defer ctx.StopInterruptNotify(interrupted) | 205 defer ctx.StopInterruptNotify(interrupted) |
163 go func() { | 206 go func() { |
(...skipping 17 matching lines...) Expand all Loading... | |
181 logger.Infof("custom image metadata uploaded") | 224 logger.Infof("custom image metadata uploaded") |
182 } | 225 } |
183 } | 226 } |
184 // TODO (wallyworld): 2013-09-20 bug 1227931 | 227 // TODO (wallyworld): 2013-09-20 bug 1227931 |
185 // We can set a custom tools data source instead of doing an | 228 // We can set a custom tools data source instead of doing an |
186 // unnecessary upload. | 229 // unnecessary upload. |
187 if environ.Config().Type() == provider.Local { | 230 if environ.Config().Type() == provider.Local { |
188 c.UploadTools = true | 231 c.UploadTools = true |
189 } | 232 } |
190 if c.UploadTools { | 233 if c.UploadTools { |
191 » » err = bootstrap.UploadTools(ctx, environ, c.Constraints.Arch, tr ue, c.Series...) | 234 » » err = _bootstrap.UploadTools(ctx, environ, c.Constraints.Arch, t rue, c.Series...) |
192 if err != nil { | 235 if err != nil { |
193 return err | 236 return err |
194 } | 237 } |
195 } | 238 } |
196 » return bootstrap.Bootstrap(ctx, environ, environs.BootstrapParams{ | 239 » return _bootstrap.Bootstrap(ctx, environ, environs.BootstrapParams{ |
197 Constraints: c.Constraints, | 240 Constraints: c.Constraints, |
198 Placement: c.Placement, | 241 Placement: c.Placement, |
199 }) | 242 }) |
200 } | 243 } |
LEFT | RIGHT |