Merge lp:~axwalk/juju-core/lp1291292-jujud-bootstrap-nostateurl 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: 2464
Proposed branch: lp:~axwalk/juju-core/lp1291292-jujud-bootstrap-nostateurl
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 791 lines (+138/-188)
14 files modified
cloudinit/sshinit/configure_test.go (+2/-1)
cmd/jujud/bootstrap.go (+10/-25)
cmd/jujud/bootstrap_test.go (+72/-52)
cmd/jujud/main_test.go (+1/-0)
environs/bootstrap/state.go (+0/-20)
environs/bootstrap/state_test.go (+0/-27)
environs/cloudinit.go (+1/-3)
environs/cloudinit/cloudinit.go (+20/-10)
environs/cloudinit/cloudinit_test.go (+11/-8)
environs/manual/bootstrap.go (+3/-2)
instance/instance.go (+10/-0)
provider/common/bootstrap.go (+3/-9)
provider/common/bootstrap_test.go (+3/-26)
provider/local/environ.go (+2/-5)
To merge this branch: bzr merge lp:~axwalk/juju-core/lp1291292-jujud-bootstrap-nostateurl
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+212172@code.launchpad.net

Commit message

Pass instance-id/hardware directly to jujud

The bootstrap-state agent currently loads its
instance ID and hardware characteristics by
fetching a URL that is written to a file on
disk. This is no longer necessary with
synchronous bootstrap.

I have changed jujud and bootstrap script
generation to pass the instance-id and hardware
characteristics directly to jujud as command
line arguments.

Fixes part of lp:1291292

https://codereview.appspot.com/78840044/

Description of the change

Pass instance-id/hardware directly to jujud

The bootstrap-state agent currently loads its
instance ID and hardware characteristics by
fetching a URL that is written to a file on
disk. This is no longer necessary with
synchronous bootstrap.

I have changed jujud and bootstrap script
generation to pass the instance-id and hardware
characteristics directly to jujud as command
line arguments.

Fixes part of lp:1291292

https://codereview.appspot.com/78840044/

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

Reviewers: mp+212172_code.launchpad.net,

Message:
Please take a look.

Description:
Pass instance-id/hardware directly to jujud

The bootstrap-state agent currently loads its
instance ID and hardware characteristics by
fetching a URL that is written to a file on
disk. This is no longer necessary with
synchronous bootstrap.

I have changed jujud and bootstrap script
generation to pass the instance-id and hardware
characteristics directly to jujud as command
line arguments.

Fixes part of lp:1291292

https://code.launchpad.net/~axwalk/juju-core/lp1291292-jujud-bootstrap-nostateurl/+merge/212172

(do not edit description out of merge proposal)

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

Affected files (+140, -141 lines):
   A [revision details]
   M cloudinit/sshinit/configure_test.go
   M cmd/jujud/bootstrap.go
   M cmd/jujud/bootstrap_test.go
   M cmd/jujud/main_test.go
   M environs/cloudinit.go
   M environs/cloudinit/cloudinit.go
   M environs/cloudinit/cloudinit_test.go
   M environs/manual/bootstrap.go
   M instance/instance.go
   M provider/common/bootstrap.go
   M provider/common/bootstrap_test.go
   M provider/local/environ.go

Revision history for this message
Dimiter Naydenov (dimitern) wrote :

This is great, LGTM, assuming you tested it live.

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

https://codereview.appspot.com/78840044/diff/1/cmd/jujud/bootstrap.go#newcode65
cmd/jujud/bootstrap.go:65: if err = c.Conf.read("machine-0"); err != nil
{
s/=/:=/

https://codereview.appspot.com/78840044/

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

Please take a look.

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

https://codereview.appspot.com/78840044/diff/1/cmd/jujud/bootstrap.go#newcode65
cmd/jujud/bootstrap.go:65: if err = c.Conf.read("machine-0"); err != nil
{
On 2014/03/21 15:03:24, dimitern wrote:
> s/=/:=/

Done.

https://codereview.appspot.com/78840044/

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

On 2014/03/21 15:03:23, dimitern wrote:
> This is great, LGTM, assuming you tested it live.

Thanks, yes I have tested with local, manual and openstack.
I realised I could remove LoadStateFromURL altogether, so I went ahead
and did that.

> https://codereview.appspot.com/78840044/diff/1/cmd/jujud/bootstrap.go
> File cmd/jujud/bootstrap.go (right):

https://codereview.appspot.com/78840044/diff/1/cmd/jujud/bootstrap.go#newcode65
> cmd/jujud/bootstrap.go:65: if err = c.Conf.read("machine-0"); err !=
nil {
> s/=/:=/

https://codereview.appspot.com/78840044/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cloudinit/sshinit/configure_test.go'
--- cloudinit/sshinit/configure_test.go 2014-03-06 12:14:26 +0000
+++ cloudinit/sshinit/configure_test.go 2014-03-24 01:53:33 +0000
@@ -55,7 +55,8 @@
55func (s *configureSuite) getCloudConfig(c *gc.C, stateServer bool, vers version.Binary) *cloudinit.Config {55func (s *configureSuite) getCloudConfig(c *gc.C, stateServer bool, vers version.Binary) *cloudinit.Config {
56 var mcfg *envcloudinit.MachineConfig56 var mcfg *envcloudinit.MachineConfig
57 if stateServer {57 if stateServer {
58 mcfg = environs.NewBootstrapMachineConfig("http://whatever/dotcom", "private-key")58 mcfg = environs.NewBootstrapMachineConfig("private-key")
59 mcfg.InstanceId = "instance-id"
59 mcfg.Jobs = []params.MachineJob{params.JobManageEnviron, params.JobHostUnits}60 mcfg.Jobs = []params.MachineJob{params.JobManageEnviron, params.JobHostUnits}
60 } else {61 } else {
61 mcfg = environs.NewMachineConfig("0", "ya", nil, nil)62 mcfg = environs.NewMachineConfig("0", "ya", nil, nil)
6263
=== modified file 'cmd/jujud/bootstrap.go'
--- cmd/jujud/bootstrap.go 2014-03-05 16:30:01 +0000
+++ cmd/jujud/bootstrap.go 2014-03-24 01:53:33 +0000
@@ -6,8 +6,6 @@
6import (6import (
7 "encoding/base64"7 "encoding/base64"
8 "fmt"8 "fmt"
9 "io/ioutil"
10 "strings"
119
12 "launchpad.net/gnuflag"10 "launchpad.net/gnuflag"
13 "launchpad.net/goyaml"11 "launchpad.net/goyaml"
@@ -16,23 +14,19 @@
16 "launchpad.net/juju-core/cmd"14 "launchpad.net/juju-core/cmd"
17 "launchpad.net/juju-core/constraints"15 "launchpad.net/juju-core/constraints"
18 "launchpad.net/juju-core/environs"16 "launchpad.net/juju-core/environs"
19 "launchpad.net/juju-core/environs/bootstrap"
20 "launchpad.net/juju-core/environs/cloudinit"
21 "launchpad.net/juju-core/environs/config"17 "launchpad.net/juju-core/environs/config"
22 "launchpad.net/juju-core/instance"18 "launchpad.net/juju-core/instance"
23 "launchpad.net/juju-core/state"19 "launchpad.net/juju-core/state"
24 "launchpad.net/juju-core/state/api/params"20 "launchpad.net/juju-core/state/api/params"
25)21)
2622
27// Cloud-init write the URL to be used to load the bootstrap state into this file.
28// A variable is used here to allow tests to override.
29var providerStateURLFile = cloudinit.BootstrapStateURLFile
30
31type BootstrapCommand struct {23type BootstrapCommand struct {
32 cmd.CommandBase24 cmd.CommandBase
33 Conf AgentConf25 Conf AgentConf
34 EnvConfig map[string]interface{}26 EnvConfig map[string]interface{}
35 Constraints constraints.Value27 Constraints constraints.Value
28 Hardware instance.HardwareCharacteristics
29 InstanceId string
36}30}
3731
38// Info returns a decription of the command.32// Info returns a decription of the command.
@@ -47,6 +41,8 @@
47 c.Conf.addFlags(f)41 c.Conf.addFlags(f)
48 yamlBase64Var(f, &c.EnvConfig, "env-config", "", "initial environment configuration (yaml, base64 encoded)")42 yamlBase64Var(f, &c.EnvConfig, "env-config", "", "initial environment configuration (yaml, base64 encoded)")
49 f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "initial environment constraints (space-separated strings)")43 f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "initial environment constraints (space-separated strings)")
44 f.Var(&c.Hardware, "hardware", "hardware characteristics (space-separated strings)")
45 f.StringVar(&c.InstanceId, "instance-id", "", "unique instance-id for bootstrap machine")
50}46}
5147
52// Init initializes the command for running.48// Init initializes the command for running.
@@ -54,26 +50,19 @@
54 if len(c.EnvConfig) == 0 {50 if len(c.EnvConfig) == 0 {
55 return requiredError("env-config")51 return requiredError("env-config")
56 }52 }
53 if c.InstanceId == "" {
54 return requiredError("instance-id")
55 }
57 return c.Conf.checkArgs(args)56 return c.Conf.checkArgs(args)
58}57}
5958
60// Run initializes state for an environment.59// Run initializes state for an environment.
61func (c *BootstrapCommand) Run(_ *cmd.Context) error {60func (c *BootstrapCommand) Run(_ *cmd.Context) error {
62 data, err := ioutil.ReadFile(providerStateURLFile)
63 if err != nil {
64 return fmt.Errorf("cannot read provider-state-url file: %v", err)
65 }
66 envCfg, err := config.New(config.NoDefaults, c.EnvConfig)61 envCfg, err := config.New(config.NoDefaults, c.EnvConfig)
67 if err != nil {62 if err != nil {
68 return err63 return err
69 }64 }
70 stateInfoURL := strings.Split(string(data), "\n")[0]65 if err := c.Conf.read("machine-0"); err != nil {
71 bsState, err := bootstrap.LoadStateFromURL(stateInfoURL, !envCfg.SSLHostnameVerification())
72 if err != nil {
73 return fmt.Errorf("cannot load state from URL %q (read from %q): %v", stateInfoURL, providerStateURLFile, err)
74 }
75 err = c.Conf.read("machine-0")
76 if err != nil {
77 return err66 return err
78 }67 }
79 // agent.Jobs is an optional field in the agent config, and was68 // agent.Jobs is an optional field in the agent config, and was
@@ -86,15 +75,11 @@
86 params.JobHostUnits,75 params.JobHostUnits,
87 }76 }
88 }77 }
89 var characteristics instance.HardwareCharacteristics
90 if len(bsState.Characteristics) > 0 {
91 characteristics = bsState.Characteristics[0]
92 }
93 st, _, err := c.Conf.config.InitializeState(envCfg, agent.BootstrapMachineConfig{78 st, _, err := c.Conf.config.InitializeState(envCfg, agent.BootstrapMachineConfig{
94 Constraints: c.Constraints,79 Constraints: c.Constraints,
95 Jobs: jobs,80 Jobs: jobs,
96 InstanceId: bsState.StateInstances[0],81 InstanceId: instance.Id(c.InstanceId),
97 Characteristics: characteristics,82 Characteristics: c.Hardware,
98 }, state.DefaultDialOpts(), environs.NewStatePolicy())83 }, state.DefaultDialOpts(), environs.NewStatePolicy())
99 if err != nil {84 if err != nil {
100 return err85 return err
10186
=== modified file 'cmd/jujud/bootstrap_test.go'
--- cmd/jujud/bootstrap_test.go 2014-03-13 07:54:56 +0000
+++ cmd/jujud/bootstrap_test.go 2014-03-24 01:53:33 +0000
@@ -5,8 +5,6 @@
55
6import (6import (
7 "encoding/base64"7 "encoding/base64"
8 "io/ioutil"
9 "path/filepath"
108
11 jc "github.com/juju/testing/checkers"9 jc "github.com/juju/testing/checkers"
12 gc "launchpad.net/gocheck"10 gc "launchpad.net/gocheck"
@@ -15,8 +13,6 @@
15 "launchpad.net/juju-core/agent"13 "launchpad.net/juju-core/agent"
16 "launchpad.net/juju-core/constraints"14 "launchpad.net/juju-core/constraints"
17 "launchpad.net/juju-core/environs"15 "launchpad.net/juju-core/environs"
18 "launchpad.net/juju-core/environs/bootstrap"
19 "launchpad.net/juju-core/environs/jujutest"
20 "launchpad.net/juju-core/errors"16 "launchpad.net/juju-core/errors"
21 "launchpad.net/juju-core/instance"17 "launchpad.net/juju-core/instance"
22 "launchpad.net/juju-core/provider/dummy"18 "launchpad.net/juju-core/provider/dummy"
@@ -33,32 +29,15 @@
33type BootstrapSuite struct {29type BootstrapSuite struct {
34 testbase.LoggingSuite30 testbase.LoggingSuite
35 testing.MgoSuite31 testing.MgoSuite
36 dataDir string32 dataDir string
37 logDir string33 logDir string
38 providerStateURLFile string
39}34}
4035
41var _ = gc.Suite(&BootstrapSuite{})36var _ = gc.Suite(&BootstrapSuite{})
4237
43var testRoundTripper = &jujutest.ProxyRoundTripper{}
44
45func init() {
46 // Prepare mock http transport for provider-state output in tests.
47 testRoundTripper.RegisterForScheme("test")
48}
49
50func (s *BootstrapSuite) SetUpSuite(c *gc.C) {38func (s *BootstrapSuite) SetUpSuite(c *gc.C) {
51 s.LoggingSuite.SetUpSuite(c)39 s.LoggingSuite.SetUpSuite(c)
52 s.MgoSuite.SetUpSuite(c)40 s.MgoSuite.SetUpSuite(c)
53 stateInfo := bootstrap.BootstrapState{
54 StateInstances: []instance.Id{instance.Id("dummy.instance.id")},
55 }
56 stateData, err := goyaml.Marshal(stateInfo)
57 c.Assert(err, gc.IsNil)
58 content := map[string]string{"/" + bootstrap.StateFile: string(stateData)}
59 testRoundTripper.Sub = jujutest.NewCannedRoundTripper(content, nil)
60 s.providerStateURLFile = filepath.Join(c.MkDir(), "provider-state-url")
61 providerStateURLFile = s.providerStateURLFile
62}41}
6342
64func (s *BootstrapSuite) TearDownSuite(c *gc.C) {43func (s *BootstrapSuite) TearDownSuite(c *gc.C) {
@@ -85,7 +64,6 @@
85}64}
8665
87func (s *BootstrapSuite) initBootstrapCommand(c *gc.C, jobs []params.MachineJob, args ...string) (machineConf agent.Config, cmd *BootstrapCommand, err error) {66func (s *BootstrapSuite) initBootstrapCommand(c *gc.C, jobs []params.MachineJob, args ...string) (machineConf agent.Config, cmd *BootstrapCommand, err error) {
88 ioutil.WriteFile(s.providerStateURLFile, []byte("test://localhost/provider-state\n"), 0600)
89 if len(jobs) == 0 {67 if len(jobs) == 0 {
90 // Add default jobs.68 // Add default jobs.
91 jobs = []params.MachineJob{69 jobs = []params.MachineJob{
@@ -123,7 +101,8 @@
123}101}
124102
125func (s *BootstrapSuite) TestInitializeEnvironment(c *gc.C) {103func (s *BootstrapSuite) TestInitializeEnvironment(c *gc.C) {
126 _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig)104 hw := instance.MustParseHardware("arch=amd64 mem=8G")
105 _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig, "--instance-id", "anything", "--hardware", hw.String())
127 c.Assert(err, gc.IsNil)106 c.Assert(err, gc.IsNil)
128 err = cmd.Run(nil)107 err = cmd.Run(nil)
129 c.Assert(err, gc.IsNil)108 c.Assert(err, gc.IsNil)
@@ -141,7 +120,12 @@
141120
142 instid, err := machines[0].InstanceId()121 instid, err := machines[0].InstanceId()
143 c.Assert(err, gc.IsNil)122 c.Assert(err, gc.IsNil)
144 c.Assert(instid, gc.Equals, instance.Id("dummy.instance.id"))123 c.Assert(instid, gc.Equals, instance.Id("anything"))
124
125 stateHw, err := machines[0].HardwareCharacteristics()
126 c.Assert(err, gc.IsNil)
127 c.Assert(stateHw, gc.NotNil)
128 c.Assert(*stateHw, gc.DeepEquals, hw)
145129
146 cons, err := st.EnvironConstraints()130 cons, err := st.EnvironConstraints()
147 c.Assert(err, gc.IsNil)131 c.Assert(err, gc.IsNil)
@@ -150,7 +134,11 @@
150134
151func (s *BootstrapSuite) TestSetConstraints(c *gc.C) {135func (s *BootstrapSuite) TestSetConstraints(c *gc.C) {
152 tcons := constraints.Value{Mem: uint64p(2048), CpuCores: uint64p(2)}136 tcons := constraints.Value{Mem: uint64p(2048), CpuCores: uint64p(2)}
153 _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig, "--constraints", tcons.String())137 _, cmd, err := s.initBootstrapCommand(c, nil,
138 "--env-config", testConfig,
139 "--instance-id", "anything",
140 "--constraints", tcons.String(),
141 )
154 c.Assert(err, gc.IsNil)142 c.Assert(err, gc.IsNil)
155 err = cmd.Run(nil)143 err = cmd.Run(nil)
156 c.Assert(err, gc.IsNil)144 c.Assert(err, gc.IsNil)
@@ -182,7 +170,7 @@
182 expectedJobs := []state.MachineJob{170 expectedJobs := []state.MachineJob{
183 state.JobManageEnviron, state.JobHostUnits,171 state.JobManageEnviron, state.JobHostUnits,
184 }172 }
185 _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig)173 _, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig, "--instance-id", "anything")
186 c.Assert(err, gc.IsNil)174 c.Assert(err, gc.IsNil)
187 err = cmd.Run(nil)175 err = cmd.Run(nil)
188 c.Assert(err, gc.IsNil)176 c.Assert(err, gc.IsNil)
@@ -201,7 +189,7 @@
201189
202func (s *BootstrapSuite) TestConfiguredMachineJobs(c *gc.C) {190func (s *BootstrapSuite) TestConfiguredMachineJobs(c *gc.C) {
203 jobs := []params.MachineJob{params.JobManageEnviron}191 jobs := []params.MachineJob{params.JobManageEnviron}
204 _, cmd, err := s.initBootstrapCommand(c, jobs, "--env-config", testConfig)192 _, cmd, err := s.initBootstrapCommand(c, jobs, "--env-config", testConfig, "--instance-id", "anything")
205 c.Assert(err, gc.IsNil)193 c.Assert(err, gc.IsNil)
206 err = cmd.Run(nil)194 err = cmd.Run(nil)
207 c.Assert(err, gc.IsNil)195 c.Assert(err, gc.IsNil)
@@ -231,7 +219,7 @@
231}219}
232220
233func (s *BootstrapSuite) TestInitialPassword(c *gc.C) {221func (s *BootstrapSuite) TestInitialPassword(c *gc.C) {
234 machineConf, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig)222 machineConf, cmd, err := s.initBootstrapCommand(c, nil, "--env-config", testConfig, "--instance-id", "anything")
235 c.Assert(err, gc.IsNil)223 c.Assert(err, gc.IsNil)
236224
237 err = cmd.Run(nil)225 err = cmd.Run(nil)
@@ -270,35 +258,65 @@
270 defer st.Close()258 defer st.Close()
271}259}
272260
273var base64ConfigTests = []struct {261var bootstrapArgTests = []struct {
274 input []string262 input []string
275 err string263 err string
276 expected map[string]interface{}264 expectedInstanceId string
265 expectedHardware instance.HardwareCharacteristics
266 expectedConfig map[string]interface{}
277}{267}{
278 {268 {
279 // no value supplied269 // no value supplied for env-config
280 nil,270 err: "--env-config option must be set",
281 "--env-config option must be set",
282 nil,
283 }, {271 }, {
284 // empty272 // empty env-config
285 []string{"--env-config", ""},273 input: []string{"--env-config", ""},
286 "--env-config option must be set",274 err: "--env-config option must be set",
287 nil,
288 }, {275 }, {
289 // wrong, should be base64276 // wrong, should be base64
290 []string{"--env-config", "name: banana\n"},277 input: []string{"--env-config", "name: banana\n"},
291 ".*illegal base64 data at input byte.*",278 err: ".*illegal base64 data at input byte.*",
292 nil,279 }, {
293 }, {280 // no value supplied for instance-id
294 []string{"--env-config", base64.StdEncoding.EncodeToString([]byte("name: banana\n"))},281 input: []string{
295 "",282 "--env-config", base64.StdEncoding.EncodeToString([]byte("name: banana\n")),
296 map[string]interface{}{"name": "banana"},283 },
284 err: "--instance-id option must be set",
285 }, {
286 // empty instance-id
287 input: []string{
288 "--env-config", base64.StdEncoding.EncodeToString([]byte("name: banana\n")),
289 "--instance-id", "",
290 },
291 err: "--instance-id option must be set",
292 }, {
293 input: []string{
294 "--env-config", base64.StdEncoding.EncodeToString([]byte("name: banana\n")),
295 "--instance-id", "anything",
296 },
297 expectedInstanceId: "anything",
298 expectedConfig: map[string]interface{}{"name": "banana"},
299 }, {
300 input: []string{
301 "--env-config", base64.StdEncoding.EncodeToString([]byte("name: banana\n")),
302 "--instance-id", "anything",
303 "--hardware", "nonsense",
304 },
305 err: `invalid value "nonsense" for flag --hardware: malformed characteristic "nonsense"`,
306 }, {
307 input: []string{
308 "--env-config", base64.StdEncoding.EncodeToString([]byte("name: banana\n")),
309 "--instance-id", "anything",
310 "--hardware", "arch=amd64 cpu-cores=4 root-disk=2T",
311 },
312 expectedInstanceId: "anything",
313 expectedHardware: instance.MustParseHardware("arch=amd64 cpu-cores=4 root-disk=2T"),
314 expectedConfig: map[string]interface{}{"name": "banana"},
297 },315 },
298}316}
299317
300func (s *BootstrapSuite) TestBase64Config(c *gc.C) {318func (s *BootstrapSuite) TestBootstrapArgs(c *gc.C) {
301 for i, t := range base64ConfigTests {319 for i, t := range bootstrapArgTests {
302 c.Logf("test %d", i)320 c.Logf("test %d", i)
303 var args []string321 var args []string
304 args = append(args, t.input...)322 args = append(args, t.input...)
@@ -306,7 +324,9 @@
306 if t.err == "" {324 if t.err == "" {
307 c.Assert(cmd, gc.NotNil)325 c.Assert(cmd, gc.NotNil)
308 c.Assert(err, gc.IsNil)326 c.Assert(err, gc.IsNil)
309 c.Assert(cmd.EnvConfig, gc.DeepEquals, t.expected)327 c.Assert(cmd.EnvConfig, gc.DeepEquals, t.expectedConfig)
328 c.Assert(cmd.InstanceId, gc.Equals, t.expectedInstanceId)
329 c.Assert(cmd.Hardware, gc.DeepEquals, t.expectedHardware)
310 } else {330 } else {
311 c.Assert(err, gc.ErrorMatches, t.err)331 c.Assert(err, gc.ErrorMatches, t.err)
312 }332 }
313333
=== modified file 'cmd/jujud/main_test.go'
--- cmd/jujud/main_test.go 2014-03-19 03:48:12 +0000
+++ cmd/jujud/main_test.go 2014-03-24 01:53:33 +0000
@@ -110,6 +110,7 @@
110 checkMessage(c, msga,110 checkMessage(c, msga,
111 "bootstrap-state",111 "bootstrap-state",
112 "--env-config", b64yaml{"blah": "blah"}.encode(),112 "--env-config", b64yaml{"blah": "blah"}.encode(),
113 "--instance-id", "inst",
113 "toastie")114 "toastie")
114 checkMessage(c, msga, "unit",115 checkMessage(c, msga, "unit",
115 "--unit-name", "un/0",116 "--unit-name", "un/0",
116117
=== modified file 'environs/bootstrap/state.go'
--- environs/bootstrap/state.go 2014-03-12 10:59:17 +0000
+++ environs/bootstrap/state.go 2014-03-24 01:53:33 +0000
@@ -8,7 +8,6 @@
8 "fmt"8 "fmt"
9 "io"9 "io"
10 "io/ioutil"10 "io/ioutil"
11 "net/http"
1211
13 "launchpad.net/goyaml"12 "launchpad.net/goyaml"
1413
@@ -16,7 +15,6 @@
16 "launchpad.net/juju-core/environs/storage"15 "launchpad.net/juju-core/environs/storage"
17 coreerrors "launchpad.net/juju-core/errors"16 coreerrors "launchpad.net/juju-core/errors"
18 "launchpad.net/juju-core/instance"17 "launchpad.net/juju-core/instance"
19 "launchpad.net/juju-core/utils"
20)18)
2119
22// StateFile is the name of the file where the provider's state is stored.20// StateFile is the name of the file where the provider's state is stored.
@@ -68,24 +66,6 @@
68 return putState(storage, data)66 return putState(storage, data)
69}67}
7068
71// LoadStateFromURL reads state from the given URL.
72func LoadStateFromURL(url string, disableSSLHostnameVerification bool) (*BootstrapState, error) {
73 logger.Debugf("loading %q from %q", StateFile, url)
74 client := http.DefaultClient
75 if disableSSLHostnameVerification {
76 logger.Infof("hostname SSL verification disabled")
77 client = utils.GetNonValidatingHTTPClient()
78 }
79 resp, err := client.Get(url)
80 if err != nil {
81 return nil, err
82 }
83 if resp.StatusCode != http.StatusOK {
84 return nil, fmt.Errorf("could not load state from url: %v %s", url, resp.Status)
85 }
86 return loadState(resp.Body)
87}
88
89// LoadState reads state from the given storage.69// LoadState reads state from the given storage.
90func LoadState(stor storage.StorageReader) (*BootstrapState, error) {70func LoadState(stor storage.StorageReader) (*BootstrapState, error) {
91 r, err := storage.Get(stor, StateFile)71 r, err := storage.Get(stor, StateFile)
9272
=== modified file 'environs/bootstrap/state_test.go'
--- environs/bootstrap/state_test.go 2014-03-13 07:54:56 +0000
+++ environs/bootstrap/state_test.go 2014-03-24 01:53:33 +0000
@@ -125,33 +125,6 @@
125 c.Check(*storedState, gc.DeepEquals, state)125 c.Check(*storedState, gc.DeepEquals, state)
126}126}
127127
128func (suite *StateSuite) TestLoadStateFromURLReadsStateFile(c *gc.C) {
129 storage, dataDir := suite.newStorageWithDataDir(c)
130 state := suite.setUpSavedState(c, dataDir)
131 url, err := storage.URL(bootstrap.StateFile)
132 c.Assert(err, gc.IsNil)
133 storedState, err := bootstrap.LoadStateFromURL(url, false)
134 c.Assert(err, gc.IsNil)
135 c.Check(*storedState, gc.DeepEquals, state)
136}
137
138func (suite *StateSuite) TestLoadStateFromURLBadCert(c *gc.C) {
139 baseURL, _ := suite.testingHTTPSServer(c)
140 url := baseURL + "/" + bootstrap.StateFile
141 storedState, err := bootstrap.LoadStateFromURL(url, false)
142 c.Assert(err, gc.ErrorMatches, ".*/provider-state:.* certificate signed by unknown authority")
143 c.Assert(storedState, gc.IsNil)
144}
145
146func (suite *StateSuite) TestLoadStateFromURLBadCertPermitted(c *gc.C) {
147 baseURL, dataDir := suite.testingHTTPSServer(c)
148 state := suite.setUpSavedState(c, dataDir)
149 url := baseURL + "/" + bootstrap.StateFile
150 storedState, err := bootstrap.LoadStateFromURL(url, true)
151 c.Assert(err, gc.IsNil)
152 c.Check(*storedState, gc.DeepEquals, state)
153}
154
155func (suite *StateSuite) TestLoadStateMissingFile(c *gc.C) {128func (suite *StateSuite) TestLoadStateMissingFile(c *gc.C) {
156 stor := suite.newStorage(c)129 stor := suite.newStorage(c)
157 _, err := bootstrap.LoadState(stor)130 _, err := bootstrap.LoadState(stor)
158131
=== modified file 'environs/cloudinit.go'
--- environs/cloudinit.go 2014-03-12 02:28:30 +0000
+++ environs/cloudinit.go 2014-03-24 01:53:33 +0000
@@ -57,13 +57,11 @@
57// NewBootstrapMachineConfig sets up a basic machine configuration for a57// NewBootstrapMachineConfig sets up a basic machine configuration for a
58// bootstrap node. You'll still need to supply more information, but this58// bootstrap node. You'll still need to supply more information, but this
59// takes care of the fixed entries and the ones that are always needed.59// takes care of the fixed entries and the ones that are always needed.
60// stateInfoURL is the storage URL for the environment's state file.60func NewBootstrapMachineConfig(privateSystemSSHKey string) *cloudinit.MachineConfig {
61func NewBootstrapMachineConfig(stateInfoURL string, privateSystemSSHKey string) *cloudinit.MachineConfig {
62 // For a bootstrap instance, FinishMachineConfig will provide the61 // For a bootstrap instance, FinishMachineConfig will provide the
63 // state.Info and the api.Info. The machine id must *always* be "0".62 // state.Info and the api.Info. The machine id must *always* be "0".
64 mcfg := NewMachineConfig("0", state.BootstrapNonce, nil, nil)63 mcfg := NewMachineConfig("0", state.BootstrapNonce, nil, nil)
65 mcfg.StateServer = true64 mcfg.StateServer = true
66 mcfg.StateInfoURL = stateInfoURL
67 mcfg.SystemPrivateSSHKey = privateSystemSSHKey65 mcfg.SystemPrivateSSHKey = privateSystemSSHKey
68 mcfg.Jobs = []params.MachineJob{params.JobManageEnviron, params.JobHostUnits}66 mcfg.Jobs = []params.MachineJob{params.JobManageEnviron, params.JobHostUnits}
69 return mcfg67 return mcfg
7068
=== modified file 'environs/cloudinit/cloudinit.go'
--- environs/cloudinit/cloudinit.go 2014-03-18 22:20:40 +0000
+++ environs/cloudinit/cloudinit.go 2014-03-24 01:53:33 +0000
@@ -31,12 +31,6 @@
31 "launchpad.net/juju-core/version"31 "launchpad.net/juju-core/version"
32)32)
3333
34// BootstrapStateURLFile is used to communicate to the first bootstrap node
35// the URL from which to obtain important state information (instance id and
36// hardware characteristics). It is a transient file, only used as the node
37// is bootstrapping.
38const BootstrapStateURLFile = "/tmp/provider-state-url"
39
40// SystemIdentity is the name of the file where the environment SSH key is kept.34// SystemIdentity is the name of the file where the environment SSH key is kept.
41const SystemIdentity = "system-identity"35const SystemIdentity = "system-identity"
4236
@@ -79,6 +73,15 @@
79 // or be empty when starting a state server.73 // or be empty when starting a state server.
80 APIInfo *api.Info74 APIInfo *api.Info
8175
76 // InstanceId is the instance ID of the machine being initialised.
77 // This is required when bootstrapping, and ignored otherwise.
78 InstanceId instance.Id
79
80 // HardwareCharacteristics contains the harrdware characteristics of
81 // the machine being initialised. This optional, and is only used by
82 // the bootstrap agent during state initialisation.
83 HardwareCharacteristics *instance.HardwareCharacteristics
84
82 // MachineNonce is set at provisioning/bootstrap time and used to85 // MachineNonce is set at provisioning/bootstrap time and used to
83 // ensure the agent is running on the correct instance.86 // ensure the agent is running on the correct instance.
84 MachineNonce string87 MachineNonce string
@@ -128,9 +131,6 @@
128 // Constraints holds the initial environment constraints.131 // Constraints holds the initial environment constraints.
129 Constraints constraints.Value132 Constraints constraints.Value
130133
131 // StateInfoURL is the URL of a file which contains information about the state server machines.
132 StateInfoURL string
133
134 // DisableSSLHostnameVerification can be set to true to tell cloud-init134 // DisableSSLHostnameVerification can be set to true to tell cloud-init
135 // that it shouldn't verify SSL certificates135 // that it shouldn't verify SSL certificates
136 DisableSSLHostnameVerification bool136 DisableSSLHostnameVerification bool
@@ -393,13 +393,20 @@
393 if cons != "" {393 if cons != "" {
394 cons = " --constraints " + shquote(cons)394 cons = " --constraints " + shquote(cons)
395 }395 }
396 var hardware string
397 if cfg.HardwareCharacteristics != nil {
398 if hardware = cfg.HardwareCharacteristics.String(); hardware != "" {
399 hardware = " --hardware " + shquote(hardware)
400 }
401 }
396 c.AddRunCmd(cloudinit.LogProgressCmd("Bootstrapping Juju machine agent"))402 c.AddRunCmd(cloudinit.LogProgressCmd("Bootstrapping Juju machine agent"))
397 c.AddScripts(403 c.AddScripts(
398 fmt.Sprintf("echo %s > %s", shquote(cfg.StateInfoURL), BootstrapStateURLFile),
399 // The bootstrapping is always run with debug on.404 // The bootstrapping is always run with debug on.
400 cfg.jujuTools()+"/jujud bootstrap-state"+405 cfg.jujuTools()+"/jujud bootstrap-state"+
401 " --data-dir "+shquote(cfg.DataDir)+406 " --data-dir "+shquote(cfg.DataDir)+
402 " --env-config "+shquote(base64yaml(cfg.Config))+407 " --env-config "+shquote(base64yaml(cfg.Config))+
408 " --instance-id "+shquote(string(cfg.InstanceId))+
409 hardware+
403 cons+410 cons+
404 " --debug",411 " --debug",
405 "rm -rf "+shquote(acfg.Dir()),412 "rm -rf "+shquote(acfg.Dir()),
@@ -701,6 +708,9 @@
701 if cfg.SystemPrivateSSHKey == "" {708 if cfg.SystemPrivateSSHKey == "" {
702 return fmt.Errorf("missing system ssh identity")709 return fmt.Errorf("missing system ssh identity")
703 }710 }
711 if cfg.InstanceId == "" {
712 return fmt.Errorf("missing instance-id")
713 }
704 } else {714 } else {
705 if len(cfg.StateInfo.Addrs) == 0 {715 if len(cfg.StateInfo.Addrs) == 0 {
706 return fmt.Errorf("missing state hosts")716 return fmt.Errorf("missing state hosts")
707717
=== modified file 'environs/cloudinit/cloudinit_test.go'
--- environs/cloudinit/cloudinit_test.go 2014-03-19 02:27:03 +0000
+++ environs/cloudinit/cloudinit_test.go 2014-03-24 01:53:33 +0000
@@ -101,7 +101,7 @@
101 LogDir: agent.DefaultLogDir,101 LogDir: agent.DefaultLogDir,
102 Jobs: allMachineJobs,102 Jobs: allMachineJobs,
103 CloudInitOutputLog: environs.CloudInitOutputLog,103 CloudInitOutputLog: environs.CloudInitOutputLog,
104 StateInfoURL: "some-url",104 InstanceId: "i-bootstrap",
105 SystemPrivateSSHKey: "private rsa key",105 SystemPrivateSSHKey: "private rsa key",
106 MachineAgentServiceName: "jujud-machine-0",106 MachineAgentServiceName: "jujud-machine-0",
107 MongoServiceName: "juju-db",107 MongoServiceName: "juju-db",
@@ -147,8 +147,7 @@
147install -m 600 /dev/null '/var/lib/juju/agents/bootstrap/agent\.conf'147install -m 600 /dev/null '/var/lib/juju/agents/bootstrap/agent\.conf'
148printf '%s\\n' '.*' > '/var/lib/juju/agents/bootstrap/agent\.conf'148printf '%s\\n' '.*' > '/var/lib/juju/agents/bootstrap/agent\.conf'
149echo 'Bootstrapping Juju machine agent'.*149echo 'Bootstrapping Juju machine agent'.*
150echo 'some-url' > /tmp/provider-state-url150/var/lib/juju/tools/1\.2\.3-precise-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --instance-id 'i-bootstrap' --constraints 'mem=2048M' --debug
151/var/lib/juju/tools/1\.2\.3-precise-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --constraints 'mem=2048M' --debug
152rm -rf '/var/lib/juju/agents/bootstrap'151rm -rf '/var/lib/juju/agents/bootstrap'
153ln -s 1\.2\.3-precise-amd64 '/var/lib/juju/tools/machine-0'152ln -s 1\.2\.3-precise-amd64 '/var/lib/juju/tools/machine-0'
154echo 'Starting Juju machine agent \(jujud-machine-0\)'.*153echo 'Starting Juju machine agent \(jujud-machine-0\)'.*
@@ -182,7 +181,7 @@
182 LogDir: agent.DefaultLogDir,181 LogDir: agent.DefaultLogDir,
183 Jobs: allMachineJobs,182 Jobs: allMachineJobs,
184 CloudInitOutputLog: environs.CloudInitOutputLog,183 CloudInitOutputLog: environs.CloudInitOutputLog,
185 StateInfoURL: "some-url",184 InstanceId: "i-bootstrap",
186 SystemPrivateSSHKey: "private rsa key",185 SystemPrivateSSHKey: "private rsa key",
187 MachineAgentServiceName: "jujud-machine-0",186 MachineAgentServiceName: "jujud-machine-0",
188 MongoServiceName: "juju-db",187 MongoServiceName: "juju-db",
@@ -196,7 +195,7 @@
196grep '1234' \$bin/juju1\.2\.3-raring-amd64.sha256 \|\| \(echo "Tools checksum mismatch"; exit 1\)195grep '1234' \$bin/juju1\.2\.3-raring-amd64.sha256 \|\| \(echo "Tools checksum mismatch"; exit 1\)
197rm \$bin/tools\.tar\.gz && rm \$bin/juju1\.2\.3-raring-amd64\.sha256196rm \$bin/tools\.tar\.gz && rm \$bin/juju1\.2\.3-raring-amd64\.sha256
198printf %s '{"version":"1\.2\.3-raring-amd64","url":"http://foo\.com/tools/releases/juju1\.2\.3-raring-amd64\.tgz","sha256":"1234","size":10}' > \$bin/downloaded-tools\.txt197printf %s '{"version":"1\.2\.3-raring-amd64","url":"http://foo\.com/tools/releases/juju1\.2\.3-raring-amd64\.tgz","sha256":"1234","size":10}' > \$bin/downloaded-tools\.txt
199/var/lib/juju/tools/1\.2\.3-raring-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --constraints 'mem=2048M' --debug198/var/lib/juju/tools/1\.2\.3-raring-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --instance-id 'i-bootstrap' --constraints 'mem=2048M' --debug
200rm -rf '/var/lib/juju/agents/bootstrap'199rm -rf '/var/lib/juju/agents/bootstrap'
201ln -s 1\.2\.3-raring-amd64 '/var/lib/juju/tools/machine-0'200ln -s 1\.2\.3-raring-amd64 '/var/lib/juju/tools/machine-0'
202`,201`,
@@ -227,7 +226,7 @@
227 LogDir: agent.DefaultLogDir,226 LogDir: agent.DefaultLogDir,
228 Jobs: allMachineJobs,227 Jobs: allMachineJobs,
229 CloudInitOutputLog: environs.CloudInitOutputLog,228 CloudInitOutputLog: environs.CloudInitOutputLog,
230 StateInfoURL: "some-url",229 InstanceId: "i-bootstrap",
231 SystemPrivateSSHKey: "private rsa key",230 SystemPrivateSSHKey: "private rsa key",
232 MachineAgentServiceName: "jujud-machine-0",231 MachineAgentServiceName: "jujud-machine-0",
233 MongoServiceName: "juju-db",232 MongoServiceName: "juju-db",
@@ -386,7 +385,7 @@
386 LogDir: agent.DefaultLogDir,385 LogDir: agent.DefaultLogDir,
387 Jobs: allMachineJobs,386 Jobs: allMachineJobs,
388 CloudInitOutputLog: environs.CloudInitOutputLog,387 CloudInitOutputLog: environs.CloudInitOutputLog,
389 StateInfoURL: "some-url",388 InstanceId: "i-bootstrap",
390 SystemPrivateSSHKey: "private rsa key",389 SystemPrivateSSHKey: "private rsa key",
391 MachineAgentServiceName: "jujud-machine-0",390 MachineAgentServiceName: "jujud-machine-0",
392 MongoServiceName: "juju-db",391 MongoServiceName: "juju-db",
@@ -394,7 +393,7 @@
394 setEnvConfig: true,393 setEnvConfig: true,
395 inexactMatch: true,394 inexactMatch: true,
396 expectScripts: `395 expectScripts: `
397/var/lib/juju/tools/1\.2\.3-precise-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --debug396/var/lib/juju/tools/1\.2\.3-precise-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --instance-id 'i-bootstrap' --debug
398`,397`,
399 },398 },
400}399}
@@ -783,6 +782,9 @@
783 {"missing mongo service name", func(cfg *cloudinit.MachineConfig) {782 {"missing mongo service name", func(cfg *cloudinit.MachineConfig) {
784 cfg.MongoServiceName = ""783 cfg.MongoServiceName = ""
785 }},784 }},
785 {"missing instance-id", func(cfg *cloudinit.MachineConfig) {
786 cfg.InstanceId = ""
787 }},
786}788}
787789
788// TestCloudInitVerify checks that required fields are appropriately790// TestCloudInitVerify checks that required fields are appropriately
@@ -812,6 +814,7 @@
812 LogDir: agent.DefaultLogDir,814 LogDir: agent.DefaultLogDir,
813 Jobs: normalMachineJobs,815 Jobs: normalMachineJobs,
814 CloudInitOutputLog: environs.CloudInitOutputLog,816 CloudInitOutputLog: environs.CloudInitOutputLog,
817 InstanceId: "i-bootstrap",
815 MachineNonce: "FAKE_NONCE",818 MachineNonce: "FAKE_NONCE",
816 SystemPrivateSSHKey: "private rsa key",819 SystemPrivateSSHKey: "private rsa key",
817 MachineAgentServiceName: "jujud-machine-99",820 MachineAgentServiceName: "jujud-machine-99",
818821
=== modified file 'environs/manual/bootstrap.go'
--- environs/manual/bootstrap.go 2014-02-20 02:24:46 +0000
+++ environs/manual/bootstrap.go 2014-03-24 01:53:33 +0000
@@ -124,8 +124,9 @@
124 }124 }
125125
126 // Finally, provision the machine agent.126 // Finally, provision the machine agent.
127 stateFileURL := fmt.Sprintf("file://%s/%s", storageDir, bootstrap.StateFile)127 mcfg := environs.NewBootstrapMachineConfig(privateKey)
128 mcfg := environs.NewBootstrapMachineConfig(stateFileURL, privateKey)128 mcfg.InstanceId = BootstrapInstanceId
129 mcfg.HardwareCharacteristics = args.HardwareCharacteristics
129 if args.DataDir != "" {130 if args.DataDir != "" {
130 mcfg.DataDir = args.DataDir131 mcfg.DataDir = args.DataDir
131 }132 }
132133
=== modified file 'instance/instance.go'
--- instance/instance.go 2014-03-21 11:00:41 +0000
+++ instance/instance.go 2014-03-24 01:53:33 +0000
@@ -112,6 +112,16 @@
112 return strings.Join(strs, " ")112 return strings.Join(strs, " ")
113}113}
114114
115// Implement gnuflag.Value
116func (hc *HardwareCharacteristics) Set(s string) error {
117 parsed, err := ParseHardware(s)
118 if err != nil {
119 return err
120 }
121 *hc = parsed
122 return nil
123}
124
115// MustParseHardware constructs a HardwareCharacteristics from the supplied arguments,125// MustParseHardware constructs a HardwareCharacteristics from the supplied arguments,
116// as Parse, but panics on failure.126// as Parse, but panics on failure.
117func MustParseHardware(args ...string) HardwareCharacteristics {127func MustParseHardware(args ...string) HardwareCharacteristics {
118128
=== modified file 'provider/common/bootstrap.go'
--- provider/common/bootstrap.go 2014-03-19 02:55:15 +0000
+++ provider/common/bootstrap.go 2014-03-24 01:53:33 +0000
@@ -56,19 +56,11 @@
56 return fmt.Errorf("no SSH client available")56 return fmt.Errorf("no SSH client available")
57 }57 }
5858
59 // Create an empty bootstrap state file so we can get its URL.
60 // It will be updated with the instance id and hardware characteristics
61 // after the bootstrap instance is started.
62 stateFileURL, err := bootstrap.CreateStateFile(env.Storage())
63 if err != nil {
64 return err
65 }
66
67 privateKey, err := GenerateSystemSSHKey(env)59 privateKey, err := GenerateSystemSSHKey(env)
68 if err != nil {60 if err != nil {
69 return err61 return err
70 }62 }
71 machineConfig := environs.NewBootstrapMachineConfig(stateFileURL, privateKey)63 machineConfig := environs.NewBootstrapMachineConfig(privateKey)
7264
73 fmt.Fprintln(ctx.GetStderr(), "Launching instance")65 fmt.Fprintln(ctx.GetStderr(), "Launching instance")
74 inst, hw, err := env.StartInstance(environs.StartInstanceParams{66 inst, hw, err := env.StartInstance(environs.StartInstanceParams{
@@ -80,6 +72,8 @@
80 return fmt.Errorf("cannot start bootstrap instance: %v", err)72 return fmt.Errorf("cannot start bootstrap instance: %v", err)
81 }73 }
82 fmt.Fprintf(ctx.GetStderr(), " - %s\n", inst.Id())74 fmt.Fprintf(ctx.GetStderr(), " - %s\n", inst.Id())
75 machineConfig.InstanceId = inst.Id()
76 machineConfig.HardwareCharacteristics = hw
8377
84 var characteristics []instance.HardwareCharacteristics78 var characteristics []instance.HardwareCharacteristics
85 if hw != nil {79 if hw != nil {
8680
=== modified file 'provider/common/bootstrap_test.go'
--- provider/common/bootstrap_test.go 2014-03-19 22:16:15 +0000
+++ provider/common/bootstrap_test.go 2014-03-24 01:53:33 +0000
@@ -15,7 +15,6 @@
1515
16 "launchpad.net/juju-core/constraints"16 "launchpad.net/juju-core/constraints"
17 "launchpad.net/juju-core/environs"17 "launchpad.net/juju-core/environs"
18 "launchpad.net/juju-core/environs/bootstrap"
19 "launchpad.net/juju-core/environs/cloudinit"18 "launchpad.net/juju-core/environs/cloudinit"
20 "launchpad.net/juju-core/environs/config"19 "launchpad.net/juju-core/environs/config"
21 "launchpad.net/juju-core/environs/storage"20 "launchpad.net/juju-core/environs/storage"
@@ -76,21 +75,7 @@
76 return func() *config.Config { return cfg }75 return func() *config.Config { return cfg }
77}76}
7877
79func (s *BootstrapSuite) TestCannotWriteStateFile(c *gc.C) {
80 brokenStorage := &mockStorage{
81 Storage: newStorage(s, c),
82 putErr: fmt.Errorf("noes!"),
83 }
84 env := &mockEnviron{storage: brokenStorage, config: configGetter(c)}
85 ctx := coretesting.Context(c)
86 err := common.Bootstrap(ctx, env, constraints.Value{})
87 c.Assert(err, gc.ErrorMatches, "cannot create initial state file: noes!")
88}
89
90func (s *BootstrapSuite) TestCannotStartInstance(c *gc.C) {78func (s *BootstrapSuite) TestCannotStartInstance(c *gc.C) {
91 stor := newStorage(s, c)
92 checkURL, err := stor.URL(bootstrap.StateFile)
93 c.Assert(err, gc.IsNil)
94 checkCons := constraints.MustParse("mem=8G")79 checkCons := constraints.MustParse("mem=8G")
9580
96 startInstance := func(81 startInstance := func(
@@ -99,18 +84,18 @@
99 instance.Instance, *instance.HardwareCharacteristics, error,84 instance.Instance, *instance.HardwareCharacteristics, error,
100 ) {85 ) {
101 c.Assert(cons, gc.DeepEquals, checkCons)86 c.Assert(cons, gc.DeepEquals, checkCons)
102 c.Assert(mcfg, gc.DeepEquals, environs.NewBootstrapMachineConfig(checkURL, mcfg.SystemPrivateSSHKey))87 c.Assert(mcfg, gc.DeepEquals, environs.NewBootstrapMachineConfig(mcfg.SystemPrivateSSHKey))
103 return nil, nil, fmt.Errorf("meh, not started")88 return nil, nil, fmt.Errorf("meh, not started")
104 }89 }
10590
106 env := &mockEnviron{91 env := &mockEnviron{
107 storage: stor,92 storage: newStorage(s, c),
108 startInstance: startInstance,93 startInstance: startInstance,
109 config: configGetter(c),94 config: configGetter(c),
110 }95 }
11196
112 ctx := coretesting.Context(c)97 ctx := coretesting.Context(c)
113 err = common.Bootstrap(ctx, env, checkCons)98 err := common.Bootstrap(ctx, env, checkCons)
114 c.Assert(err, gc.ErrorMatches, "cannot start bootstrap instance: meh, not started")99 c.Assert(err, gc.ErrorMatches, "cannot start bootstrap instance: meh, not started")
115}100}
116101
@@ -192,13 +177,11 @@
192 checkInstanceId := "i-success"177 checkInstanceId := "i-success"
193 checkHardware := instance.MustParseHardware("mem=2T")178 checkHardware := instance.MustParseHardware("mem=2T")
194179
195 checkURL := ""
196 startInstance := func(180 startInstance := func(
197 _ constraints.Value, _ environs.Networks, _ tools.List, mcfg *cloudinit.MachineConfig,181 _ constraints.Value, _ environs.Networks, _ tools.List, mcfg *cloudinit.MachineConfig,
198 ) (182 ) (
199 instance.Instance, *instance.HardwareCharacteristics, error,183 instance.Instance, *instance.HardwareCharacteristics, error,
200 ) {184 ) {
201 checkURL = mcfg.StateInfoURL
202 return &mockInstance{id: checkInstanceId}, &checkHardware, nil185 return &mockInstance{id: checkInstanceId}, &checkHardware, nil
203 }186 }
204 var mocksConfig = minimalConfig(c)187 var mocksConfig = minimalConfig(c)
@@ -226,12 +209,6 @@
226 err := common.Bootstrap(ctx, env, constraints.Value{})209 err := common.Bootstrap(ctx, env, constraints.Value{})
227 c.Assert(err, gc.IsNil)210 c.Assert(err, gc.IsNil)
228211
229 savedState, err := bootstrap.LoadStateFromURL(checkURL, false)
230 c.Assert(err, gc.IsNil)
231 c.Assert(savedState, gc.DeepEquals, &bootstrap.BootstrapState{
232 StateInstances: []instance.Id{instance.Id(checkInstanceId)},
233 Characteristics: []instance.HardwareCharacteristics{checkHardware},
234 })
235 authKeys := env.Config().AuthorizedKeys()212 authKeys := env.Config().AuthorizedKeys()
236 c.Assert(authKeys, gc.Not(gc.Equals), originalAuthKeys)213 c.Assert(authKeys, gc.Not(gc.Equals), originalAuthKeys)
237 c.Assert(authKeys, jc.HasSuffix, "juju-system-key\n")214 c.Assert(authKeys, jc.HasSuffix, "juju-system-key\n")
238215
=== modified file 'provider/local/environ.go'
--- provider/local/environ.go 2014-03-19 21:08:58 +0000
+++ provider/local/environ.go 2014-03-24 01:53:33 +0000
@@ -109,10 +109,6 @@
109109
110 // Before we write the agent config file, we need to make sure the110 // Before we write the agent config file, we need to make sure the
111 // instance is saved in the StateInfo.111 // instance is saved in the StateInfo.
112 stateFileURL, err := bootstrap.CreateStateFile(env.Storage())
113 if err != nil {
114 return err
115 }
116 if err := bootstrap.SaveState(env.Storage(), &bootstrap.BootstrapState{112 if err := bootstrap.SaveState(env.Storage(), &bootstrap.BootstrapState{
117 StateInstances: []instance.Id{bootstrapInstanceId},113 StateInstances: []instance.Id{bootstrapInstanceId},
118 }); err != nil {114 }); err != nil {
@@ -138,7 +134,8 @@
138 return err134 return err
139 }135 }
140136
141 mcfg := environs.NewBootstrapMachineConfig(stateFileURL, privateKey)137 mcfg := environs.NewBootstrapMachineConfig(privateKey)
138 mcfg.InstanceId = bootstrapInstanceId
142 mcfg.Tools = selectedTools[0]139 mcfg.Tools = selectedTools[0]
143 mcfg.DataDir = env.config.rootDir()140 mcfg.DataDir = env.config.rootDir()
144 mcfg.LogDir = fmt.Sprintf("/var/log/juju-%s", env.config.namespace())141 mcfg.LogDir = fmt.Sprintf("/var/log/juju-%s", env.config.namespace())

Subscribers

People subscribed via source and target branches

to status/vote changes: