Merge lp:~ericsnowcurrently/fake-juju/juju-2.0-support into lp:~landscape/fake-juju/trunk-old
- juju-2.0-support
- Merge into trunk-old
Status: | Merged |
---|---|
Approved by: | Eric Snow |
Approved revision: | 86 |
Merged at revision: | 47 |
Proposed branch: | lp:~ericsnowcurrently/fake-juju/juju-2.0-support |
Merge into: | lp:~landscape/fake-juju/trunk-old |
Prerequisite: | lp:~ericsnowcurrently/fake-juju/testing-fixes |
Diff against target: |
1595 lines (+345/-735) 8 files modified
1.24.7/fake-juju.go (+0/-514) 1.25.6/fake-juju.go (+93/-57) 2.0.0/fake-juju.go (+239/-104) Makefile (+2/-2) patches/juju-core_1.24.7.patch (+0/-47) patches/juju-core_2.0.0.patch (+6/-6) python/fakejuju/testing.py (+2/-2) tests/test_fake.py (+3/-3) |
To merge this branch: | bzr merge lp:~ericsnowcurrently/fake-juju/juju-2.0-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
🤖 Landscape Builder | test results | Approve | |
Simon Poirier (community) | Approve | ||
Review via email: mp+309285@code.launchpad.net |
This proposal supersedes a proposal from 2016-10-25.
Commit message
Update to juju 2.0.0.
Also drop support for 1.24.x.
Description of the change
Update to juju 2.0.0.
Also drop support for 1.24.x.
Testing instructions:
Run make test
🤖 Landscape Builder (landscape-builder) : Posted in a previous version of this proposal | # |
🤖 Landscape Builder (landscape-builder) wrote : Posted in a previous version of this proposal | # |
🤖 Landscape Builder (landscape-builder) : | # |
🤖 Landscape Builder (landscape-builder) wrote : | # |
Command: make ci-test
Result: Success
Revno: 63
Branch: lp:~ericsnowcurrently/fake-juju/juju-2.0-support
Jenkins: https:/
Simon Poirier (simpoir) wrote : | # |
See inline question
Simon Poirier (simpoir) wrote : | # |
+1 Never mind. I just misread. Looks all good.
- 64. By Eric Snow
-
Add some comments about bootstrap.
- 65. By Eric Snow
-
Factor out waitForBootstra
pCompletion( ). - 66. By Eric Snow
-
Rename the command handler functions.
- 67. By Eric Snow
-
Factor out destroyControll
er(). - 68. By Eric Snow
-
Destroy the controller if bootstrap fails.
- 69. By Eric Snow
-
Factor out updateBootstrap
Result( ). - 70. By Eric Snow
-
Call copyConfig() before updating the bootstrap result.
- 71. By Eric Snow
-
Handle bootstrap error cleanup centrally.
- 72. By Eric Snow
-
Capture error output from the daemon.
- 73. By Eric Snow
-
Minor touch-ups to SetUpTest().
- 74. By Eric Snow
-
Use constants for the environment variable names.
- 75. By Eric Snow
-
Add a log file for jujud logs.
- 76. By Eric Snow
-
Factor out reportInfo().
- 77. By Eric Snow
-
Ensure that the daemon runs with FAKE_JUJU_DATA_DIR set.
- 78. By Eric Snow
-
Parse all the supported "juju bootstrap" args.
- 79. By Eric Snow
-
Always ensure that the Juju cfg dir exists.
- 80. By Eric Snow
-
Support a -v bootstrap arg.
- 81. By Eric Snow
-
Set up logging right *after* calling JujuConnSuite.
SetUpTest( ). - 82. By Eric Snow
-
Fix bootstrap arg order in a test.
- 83. By Eric Snow
-
Merge from trunk.
🤖 Landscape Builder (landscape-builder) : | # |
🤖 Landscape Builder (landscape-builder) wrote : | # |
Command: make ci-test
Result: Success
Revno: 83
Branch: lp:~ericsnowcurrently/fake-juju/juju-2.0-support
Jenkins: https:/
🤖 Landscape Builder (landscape-builder) : | # |
🤖 Landscape Builder (landscape-builder) wrote : | # |
Command: make ci-test
Result: Success
Revno: 85
Branch: lp:~ericsnowcurrently/fake-juju/juju-2.0-support
Jenkins: https:/
Preview Diff
1 | === removed directory '1.24.7' |
2 | === removed file '1.24.7/fake-juju.go' |
3 | --- 1.24.7/fake-juju.go 2016-06-10 17:08:28 +0000 |
4 | +++ 1.24.7/fake-juju.go 1970-01-01 00:00:00 +0000 |
5 | @@ -1,514 +0,0 @@ |
6 | -package main |
7 | - |
8 | -import ( |
9 | - "bufio" |
10 | - "encoding/json" |
11 | - "errors" |
12 | - "fmt" |
13 | - gc "gopkg.in/check.v1" |
14 | - "io" |
15 | - "io/ioutil" |
16 | - "log" |
17 | - "os" |
18 | - "os/exec" |
19 | - "path/filepath" |
20 | - "strings" |
21 | - "syscall" |
22 | - "testing" |
23 | - "time" |
24 | - |
25 | - "github.com/juju/juju/agent" |
26 | - "github.com/juju/juju/api" |
27 | - "github.com/juju/juju/environs" |
28 | - "github.com/juju/juju/environs/configstore" |
29 | - "github.com/juju/juju/instance" |
30 | - "github.com/juju/juju/juju/osenv" |
31 | - jujutesting "github.com/juju/juju/juju/testing" |
32 | - "github.com/juju/juju/network" |
33 | - _ "github.com/juju/juju/provider/maas" |
34 | - "github.com/juju/juju/state" |
35 | - coretesting "github.com/juju/juju/testing" |
36 | - "github.com/juju/juju/testing/factory" |
37 | - "github.com/juju/juju/version" |
38 | - "github.com/juju/names" |
39 | - corecharm "gopkg.in/juju/charm.v5/charmrepo" |
40 | - goyaml "gopkg.in/yaml.v1" |
41 | -) |
42 | - |
43 | -func main() { |
44 | - if len(os.Args) > 1 { |
45 | - code := 0 |
46 | - err := handleCommand(os.Args[1]) |
47 | - if err != nil { |
48 | - fmt.Println(err.Error()) |
49 | - code = 1 |
50 | - } |
51 | - os.Exit(code) |
52 | - } |
53 | - t := &testing.T{} |
54 | - coretesting.MgoTestPackage(t) |
55 | -} |
56 | - |
57 | -type processInfo struct { |
58 | - WorkDir string |
59 | - EndpointAddr string |
60 | - Uuid string |
61 | - CACert string |
62 | -} |
63 | - |
64 | -func handleCommand(command string) error { |
65 | - if command == "bootstrap" { |
66 | - return bootstrap() |
67 | - } |
68 | - if command == "api-endpoints" { |
69 | - return apiEndpoints() |
70 | - } |
71 | - if command == "api-info" { |
72 | - return apiInfo() |
73 | - } |
74 | - if command == "destroy-environment" { |
75 | - return destroyEnvironment() |
76 | - } |
77 | - return errors.New("command not found") |
78 | -} |
79 | - |
80 | -func bootstrap() error { |
81 | - envName, password, err := environmentNameAndPassword() |
82 | - if err != nil { |
83 | - return err |
84 | - } |
85 | - command := exec.Command(os.Args[0]) |
86 | - command.Env = os.Environ() |
87 | - command.Env = append(command.Env, "ADMIN_PASSWORD="+password) |
88 | - stdout, err := command.StdoutPipe() |
89 | - if err != nil { |
90 | - return err |
91 | - } |
92 | - command.Start() |
93 | - apiInfo, err := parseApiInfo(envName, stdout) |
94 | - if err != nil { |
95 | - return err |
96 | - } |
97 | - dialOpts := api.DialOpts{ |
98 | - DialAddressInterval: 50 * time.Millisecond, |
99 | - Timeout: 5 * time.Second, |
100 | - RetryDelay: 2 * time.Second, |
101 | - } |
102 | - state, err := api.Open(apiInfo, dialOpts) |
103 | - if err != nil { |
104 | - return err |
105 | - } |
106 | - client := state.Client() |
107 | - watcher, err := client.WatchAll() |
108 | - if err != nil { |
109 | - return err |
110 | - } |
111 | - deltas, err := watcher.Next() |
112 | - if err != nil { |
113 | - return err |
114 | - } |
115 | - for _, delta := range deltas { |
116 | - entityId := delta.Entity.EntityId() |
117 | - if entityId.Kind == "machine" { |
118 | - machineId, _ := entityId.Id.(string) |
119 | - if machineId == "0" { |
120 | - return nil |
121 | - } |
122 | - } |
123 | - } |
124 | - return errors.New("invalid delta") |
125 | -} |
126 | - |
127 | -func apiEndpoints() error { |
128 | - info, err := readProcessInfo() |
129 | - if err != nil { |
130 | - return err |
131 | - } |
132 | - fmt.Println(info.EndpointAddr) |
133 | - return nil |
134 | -} |
135 | - |
136 | -func apiInfo() error { |
137 | - info, err := readProcessInfo() |
138 | - if err != nil { |
139 | - return err |
140 | - } |
141 | - fmt.Printf("{\"environ-uuid\": \"%s\", \"state-servers\": [\"%s\"]}\n", info.Uuid, info.EndpointAddr) |
142 | - return nil |
143 | -} |
144 | - |
145 | -func destroyEnvironment() error { |
146 | - info, err := readProcessInfo() |
147 | - if err != nil { |
148 | - return err |
149 | - } |
150 | - fifoPath := filepath.Join(info.WorkDir, "fifo") |
151 | - fd, err := os.OpenFile(fifoPath, os.O_APPEND|os.O_WRONLY, 0600) |
152 | - if err != nil { |
153 | - return err |
154 | - } |
155 | - defer fd.Close() |
156 | - _, err = fd.WriteString("destroy\n") |
157 | - if err != nil { |
158 | - return err |
159 | - } |
160 | - return nil |
161 | -} |
162 | - |
163 | -func environmentNameAndPassword() (string, string, error) { |
164 | - jujuHome := os.Getenv("JUJU_HOME") |
165 | - osenv.SetJujuHome(jujuHome) |
166 | - environs, err := environs.ReadEnvirons( |
167 | - filepath.Join(jujuHome, "environments.yaml")) |
168 | - if err != nil { |
169 | - return "", "", err |
170 | - } |
171 | - envName := environs.Names()[0] |
172 | - config, err := environs.Config(envName) |
173 | - if err != nil { |
174 | - return "", "", err |
175 | - } |
176 | - return envName, config.AdminSecret(), nil |
177 | -} |
178 | - |
179 | -func parseApiInfo(envName string, stdout io.ReadCloser) (*api.Info, error) { |
180 | - buffer := bufio.NewReader(stdout) |
181 | - line, _, err := buffer.ReadLine() |
182 | - if err != nil { |
183 | - return nil, err |
184 | - } |
185 | - uuid := string(line) |
186 | - environTag := names.NewEnvironTag(uuid) |
187 | - line, _, err = buffer.ReadLine() |
188 | - if err != nil { |
189 | - return nil, err |
190 | - } |
191 | - workDir := string(line) |
192 | - store, err := configstore.NewDisk(workDir) |
193 | - if err != nil { |
194 | - return nil, err |
195 | - } |
196 | - info, err := store.ReadInfo("dummyenv") |
197 | - if err != nil { |
198 | - return nil, err |
199 | - } |
200 | - credentials := info.APICredentials() |
201 | - endpoint := info.APIEndpoint() |
202 | - addresses := endpoint.Addresses |
203 | - apiInfo := &api.Info{ |
204 | - Addrs: addresses, |
205 | - Tag: names.NewLocalUserTag(credentials.User), |
206 | - Password: credentials.Password, |
207 | - CACert: endpoint.CACert, |
208 | - EnvironTag: environTag, |
209 | - } |
210 | - err = writeProcessInfo(envName, &processInfo{ |
211 | - WorkDir: workDir, |
212 | - EndpointAddr: addresses[0], |
213 | - Uuid: uuid, |
214 | - CACert: endpoint.CACert, |
215 | - }) |
216 | - if err != nil { |
217 | - return nil, err |
218 | - } |
219 | - return apiInfo, nil |
220 | -} |
221 | - |
222 | -func readProcessInfo() (*processInfo, error) { |
223 | - infoPath := filepath.Join(os.Getenv("JUJU_HOME"), "fakejuju") |
224 | - data, err := ioutil.ReadFile(infoPath) |
225 | - if err != nil { |
226 | - return nil, err |
227 | - } |
228 | - info := &processInfo{} |
229 | - err = goyaml.Unmarshal(data, info) |
230 | - if err != nil { |
231 | - return nil, err |
232 | - } |
233 | - return info, nil |
234 | -} |
235 | - |
236 | -func writeProcessInfo(envName string, info *processInfo) error { |
237 | - jujuHome := os.Getenv("JUJU_HOME") |
238 | - infoPath := filepath.Join(jujuHome, "fakejuju") |
239 | - logPath := filepath.Join(jujuHome, "fake-juju.log") |
240 | - caCertPath := filepath.Join(jujuHome, "cert.ca") |
241 | - envPath := filepath.Join(jujuHome, "environments") |
242 | - os.Mkdir(envPath, 0755) |
243 | - jEnvPath := filepath.Join(envPath, envName+".jenv") |
244 | - data, _ := goyaml.Marshal(info) |
245 | - err := os.Symlink(filepath.Join(info.WorkDir, "fake-juju.log"), logPath) |
246 | - if err != nil { |
247 | - return err |
248 | - } |
249 | - err = os.Symlink(filepath.Join(info.WorkDir, "environments/dummyenv.jenv"), jEnvPath) |
250 | - if err != nil { |
251 | - return err |
252 | - } |
253 | - err = ioutil.WriteFile(infoPath, data, 0644) |
254 | - if err != nil { |
255 | - return err |
256 | - } |
257 | - return ioutil.WriteFile(caCertPath, []byte(info.CACert), 0644) |
258 | -} |
259 | - |
260 | -type FakeJujuSuite struct { |
261 | - jujutesting.JujuConnSuite |
262 | - |
263 | - instanceCount int |
264 | - machineStarted map[string]bool |
265 | - fifoPath string |
266 | - logFile *os.File |
267 | -} |
268 | - |
269 | -var _ = gc.Suite(&FakeJujuSuite{}) |
270 | - |
271 | -func (s *FakeJujuSuite) SetUpTest(c *gc.C) { |
272 | - var CommandOutput = (*exec.Cmd).CombinedOutput |
273 | - s.JujuConnSuite.SetUpTest(c) |
274 | - |
275 | - ports := s.APIState.APIHostPorts() |
276 | - ports[0][0].NetworkName = "dummy-provider-network" |
277 | - err := s.State.SetAPIHostPorts(ports) |
278 | - c.Assert(err, gc.IsNil) |
279 | - |
280 | - s.machineStarted = make(map[string]bool) |
281 | - s.PatchValue(&corecharm.CacheDir, c.MkDir()) |
282 | - password := "dummy-password" |
283 | - if os.Getenv("ADMIN_PASSWORD") != "" { |
284 | - password = os.Getenv("ADMIN_PASSWORD") |
285 | - } |
286 | - _, err = s.State.AddUser("admin", "Admin", password, "dummy-admin") |
287 | - c.Assert(err, gc.IsNil) |
288 | - _, err = s.State.AddEnvironmentUser( |
289 | - names.NewLocalUserTag("admin"), names.NewLocalUserTag("dummy-admin"), "Admin") |
290 | - c.Assert(err, gc.IsNil) |
291 | - |
292 | - // Create a machine to manage the environment. |
293 | - stateServer := s.Factory.MakeMachine(c, &factory.MachineParams{ |
294 | - InstanceId: s.newInstanceId(), |
295 | - Nonce: agent.BootstrapNonce, |
296 | - Jobs: []state.MachineJob{state.JobManageEnviron, state.JobHostUnits}, |
297 | - Series: "trusty", |
298 | - }) |
299 | - c.Assert(stateServer.SetAgentVersion(version.Current), gc.IsNil) |
300 | - address := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal) |
301 | - c.Assert(stateServer.SetProviderAddresses(address), gc.IsNil) |
302 | - c.Assert(stateServer.SetStatus(state.StatusStarted, "", nil), gc.IsNil) |
303 | - _, err = stateServer.SetAgentPresence() |
304 | - c.Assert(err, gc.IsNil) |
305 | - s.State.StartSync() |
306 | - err = stateServer.WaitAgentPresence(coretesting.LongWait) |
307 | - c.Assert(err, gc.IsNil) |
308 | - |
309 | - apiInfo := s.APIInfo(c) |
310 | - //fmt.Println(apiInfo.Addrs[0]) |
311 | - jujuHome := osenv.JujuHome() |
312 | - fmt.Println(apiInfo.EnvironTag.Id()) |
313 | - fmt.Println(jujuHome) |
314 | - |
315 | - binPath := filepath.Join(jujuHome, "bin") |
316 | - os.Mkdir(binPath, 0755) |
317 | - fakeSSHData := []byte("#!/bin/sh\nsleep 1\n") |
318 | - fakeSSHPath := filepath.Join(binPath, "ssh") |
319 | - err = ioutil.WriteFile(fakeSSHPath, fakeSSHData, 0755) |
320 | - c.Assert(err, gc.IsNil) |
321 | - os.Setenv("PATH", binPath+":"+os.Getenv("PATH")) |
322 | - |
323 | - s.fifoPath = filepath.Join(jujuHome, "fifo") |
324 | - syscall.Mknod(s.fifoPath, syscall.S_IFIFO|0666, 0) |
325 | - |
326 | - // Logging |
327 | - logPath := filepath.Join(jujuHome, "fake-juju.log") |
328 | - s.logFile, err = os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
329 | - c.Assert(err, gc.IsNil) |
330 | - |
331 | - log.SetOutput(s.logFile) |
332 | - dpkgCmd := exec.Command( |
333 | - "dpkg-query", "--showformat='${Version}'", "--show", "fake-juju") |
334 | - out, err := CommandOutput(dpkgCmd) |
335 | - fakeJujuDebVersion := strings.Trim(string(out), "'") |
336 | - log.Printf("Started fake-juju-%s for %s\nJUJU_HOME=%s", fakeJujuDebVersion, version.Current, jujuHome) |
337 | - |
338 | -} |
339 | - |
340 | -func (s *FakeJujuSuite) TearDownTest(c *gc.C) { |
341 | - s.JujuConnSuite.TearDownTest(c) |
342 | - s.logFile.Close() |
343 | -} |
344 | - |
345 | -func (s *FakeJujuSuite) TestStart(c *gc.C) { |
346 | - watcher := s.State.Watch() |
347 | - go func() { |
348 | - fd, err := os.Open(s.fifoPath) |
349 | - c.Assert(err, gc.IsNil) |
350 | - scanner := bufio.NewScanner(fd) |
351 | - scanner.Scan() |
352 | - watcher.Stop() |
353 | - }() |
354 | - for { |
355 | - deltas, err := watcher.Next() |
356 | - log.Println("Got deltas") |
357 | - if err != nil { |
358 | - if err.Error() == "watcher was stopped" { |
359 | - log.Println("Watcher stopped") |
360 | - break |
361 | - } |
362 | - log.Println("Unexpected error", err.Error()) |
363 | - } |
364 | - c.Assert(err, gc.IsNil) |
365 | - for _, d := range deltas { |
366 | - |
367 | - entity, err := json.MarshalIndent(d.Entity, "", " ") |
368 | - c.Assert(err, gc.IsNil) |
369 | - verb := "change" |
370 | - if d.Removed { |
371 | - verb = "remove" |
372 | - } |
373 | - log.Println("Processing delta", verb, d.Entity.EntityId().Kind, string(entity[:])) |
374 | - |
375 | - entityId := d.Entity.EntityId() |
376 | - if entityId.Kind == "machine" { |
377 | - machineId, ok := entityId.Id.(string) |
378 | - c.Assert(ok, gc.Equals, true) |
379 | - c.Assert(s.handleAddMachine(machineId), gc.IsNil) |
380 | - } |
381 | - if entityId.Kind == "unit" { |
382 | - unitId, ok := entityId.Id.(string) |
383 | - c.Assert(ok, gc.Equals, true) |
384 | - c.Assert(s.handleAddUnit(unitId), gc.IsNil) |
385 | - } |
386 | - log.Println("Done processing delta") |
387 | - } |
388 | - } |
389 | -} |
390 | - |
391 | -func (s *FakeJujuSuite) handleAddMachine(id string) error { |
392 | - machine, err := s.State.Machine(id) |
393 | - if err != nil { |
394 | - return err |
395 | - } |
396 | - if instanceId, _ := machine.InstanceId(); instanceId == "" { |
397 | - err = machine.SetProvisioned(s.newInstanceId(), agent.BootstrapNonce, nil) |
398 | - if err != nil { |
399 | - log.Println("Got error with SetProvisioned", err) |
400 | - return err |
401 | - } |
402 | - address := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal) |
403 | - err = machine.SetProviderAddresses(address) |
404 | - if err != nil { |
405 | - log.Println("Got error with SetProviderAddresses", err) |
406 | - return err |
407 | - } |
408 | - } |
409 | - status, _ := machine.Status() |
410 | - if status.Status == state.StatusPending { |
411 | - if err = s.startMachine(machine); err != nil { |
412 | - log.Println("Got error with startMachine:", err) |
413 | - return err |
414 | - } |
415 | - } else if status.Status == state.StatusStarted { |
416 | - if _, ok := s.machineStarted[id]; !ok { |
417 | - s.machineStarted[id] = true |
418 | - if err = s.startUnits(machine); err != nil { |
419 | - log.Println("Got error with startUnits", err) |
420 | - return err |
421 | - } |
422 | - } |
423 | - } |
424 | - return nil |
425 | -} |
426 | - |
427 | -func (s *FakeJujuSuite) handleAddUnit(id string) error { |
428 | - unit, err := s.State.Unit(id) |
429 | - if err != nil { |
430 | - log.Println("Got error with get unit", err) |
431 | - return err |
432 | - } |
433 | - machineId, err := unit.AssignedMachineId() |
434 | - if err != nil { |
435 | - return nil |
436 | - } |
437 | - log.Println("Got machineId", machineId) |
438 | - machine, err := s.State.Machine(machineId) |
439 | - if err != nil { |
440 | - log.Println("Got error with unit AssignedMachineId", err) |
441 | - return err |
442 | - } |
443 | - machineStatus, _ := machine.Status() |
444 | - if machineStatus.Status != state.StatusStarted { |
445 | - return nil |
446 | - } |
447 | - status, _ := unit.Status() |
448 | - if status.Status != state.StatusActive { |
449 | - if err = s.startUnit(unit); err != nil { |
450 | - return err |
451 | - } |
452 | - } |
453 | - return nil |
454 | -} |
455 | - |
456 | -func (s *FakeJujuSuite) startMachine(machine *state.Machine) error { |
457 | - time.Sleep(500 * time.Millisecond) |
458 | - err := machine.SetStatus(state.StatusStarted, "", nil) |
459 | - if err != nil { |
460 | - return err |
461 | - } |
462 | - err = machine.SetAgentVersion(version.Current) |
463 | - if err != nil { |
464 | - return err |
465 | - } |
466 | - _, err = machine.SetAgentPresence() |
467 | - if err != nil { |
468 | - return err |
469 | - } |
470 | - s.State.StartSync() |
471 | - err = machine.WaitAgentPresence(coretesting.LongWait) |
472 | - if err != nil { |
473 | - return err |
474 | - } |
475 | - return nil |
476 | -} |
477 | - |
478 | -func (s *FakeJujuSuite) startUnits(machine *state.Machine) error { |
479 | - units, err := machine.Units() |
480 | - if err != nil { |
481 | - return err |
482 | - } |
483 | - return nil |
484 | - for _, unit := range units { |
485 | - unitStatus, _ := unit.Status() |
486 | - if unitStatus.Status != state.StatusActive { |
487 | - if err = s.startUnit(unit); err != nil { |
488 | - return err |
489 | - } |
490 | - } |
491 | - } |
492 | - return nil |
493 | -} |
494 | - |
495 | -func (s *FakeJujuSuite) startUnit(unit *state.Unit) error { |
496 | - err := unit.SetStatus(state.StatusActive, "", nil) |
497 | - if err != nil { |
498 | - return err |
499 | - } |
500 | - _, err = unit.SetAgentPresence() |
501 | - if err != nil { |
502 | - return err |
503 | - } |
504 | - s.State.StartSync() |
505 | - err = unit.WaitAgentPresence(coretesting.LongWait) |
506 | - if err != nil { |
507 | - return err |
508 | - } |
509 | - err = unit.SetAgentStatus(state.StatusIdle, "", nil) |
510 | - if err != nil { |
511 | - return err |
512 | - } |
513 | - return nil |
514 | -} |
515 | - |
516 | -func (s *FakeJujuSuite) newInstanceId() instance.Id { |
517 | - s.instanceCount += 1 |
518 | - return instance.Id(fmt.Sprintf("id-%d", s.instanceCount)) |
519 | -} |
520 | |
521 | === modified file '1.25.6/fake-juju.go' |
522 | --- 1.25.6/fake-juju.go 2016-10-25 16:32:53 +0000 |
523 | +++ 1.25.6/fake-juju.go 2016-10-29 14:08:30 +0000 |
524 | @@ -31,11 +31,17 @@ |
525 | coretesting "github.com/juju/juju/testing" |
526 | "github.com/juju/juju/testing/factory" |
527 | "github.com/juju/juju/version" |
528 | + "github.com/juju/loggo" |
529 | "github.com/juju/names" |
530 | + "github.com/juju/utils" |
531 | corecharm "gopkg.in/juju/charm.v5/charmrepo" |
532 | goyaml "gopkg.in/yaml.v1" |
533 | ) |
534 | |
535 | +const ( |
536 | + envDataDir = "FAKE_JUJU_DATA_DIR" |
537 | +) |
538 | + |
539 | func main() { |
540 | code := 0 |
541 | if len(os.Args) > 1 { |
542 | @@ -69,7 +75,7 @@ |
543 | return errors.New("command not found") |
544 | } |
545 | |
546 | -func bootstrap(filenames fakejujuFilenames) error { |
547 | +func bootstrap(filenames fakejujuFilenames) (returnedErr error) { |
548 | if err := filenames.ensureDirsExist(); err != nil { |
549 | return err |
550 | } |
551 | @@ -84,14 +90,26 @@ |
552 | command.Env = append(command.Env, "ADMIN_PASSWORD="+password) |
553 | defaultSeries, _ := config.DefaultSeries() |
554 | command.Env = append(command.Env, "DEFAULT_SERIES="+defaultSeries) |
555 | + command.Env = append(command.Env, envDataDir+"="+filenames.datadir) |
556 | stdout, err := command.StdoutPipe() |
557 | if err != nil { |
558 | return err |
559 | } |
560 | command.Start() |
561 | |
562 | + var whence string |
563 | + defer func() { |
564 | + if returnedErr != nil { |
565 | + if err := destroyEnvironment(filenames); err != nil { |
566 | + fmt.Printf("could not destroy environment when %s failed: %v\n", whence, err) |
567 | + } |
568 | + returnedErr = fmt.Errorf("bootstrap failed while %s: %v", whence, returnedErr) |
569 | + } |
570 | + }() |
571 | + |
572 | result, err := parseApiInfo(stdout) |
573 | if err != nil { |
574 | + whence = "parsing bootstrap result" |
575 | return err |
576 | } |
577 | // Get the API info before changing it. The new values might |
578 | @@ -103,9 +121,11 @@ |
579 | result.password = password |
580 | } |
581 | if err := result.apply(filenames, envName); err != nil { |
582 | + whence = "setting up fake-juju files" |
583 | return err |
584 | } |
585 | |
586 | + whence = "waiting-for-ready" |
587 | dialOpts := api.DialOpts{ |
588 | DialAddressInterval: 50 * time.Millisecond, |
589 | Timeout: 5 * time.Second, |
590 | @@ -154,11 +174,6 @@ |
591 | } |
592 | |
593 | func destroyEnvironment(filenames fakejujuFilenames) error { |
594 | - info, err := readProcessInfo(filenames) |
595 | - if err != nil { |
596 | - return err |
597 | - } |
598 | - filenames = newFakeJujuFilenames("", "", info.WorkDir) |
599 | fd, err := os.OpenFile(filenames.fifoFile(), os.O_APPEND|os.O_WRONLY, 0600) |
600 | if err != nil { |
601 | return err |
602 | @@ -228,7 +243,7 @@ |
603 | |
604 | func newFakeJujuFilenames(datadir, logsdir, jujucfgdir string) fakejujuFilenames { |
605 | if datadir == "" { |
606 | - datadir = os.Getenv("FAKE_JUJU_DATA_DIR") |
607 | + datadir = os.Getenv(envDataDir) |
608 | if datadir == "" { |
609 | if jujucfgdir == "" { |
610 | jujucfgdir = os.Getenv("JUJU_HOME") |
611 | @@ -267,6 +282,12 @@ |
612 | return filepath.Join(fj.logsdir, "fake-juju.log") |
613 | } |
614 | |
615 | +// jujudLogsFile() returns the path to the file where fake-juju writes |
616 | +// the jujud logs. |
617 | +func (fj fakejujuFilenames) jujudLogsFile() string { |
618 | + return filepath.Join(fj.logsdir, "jujud.log") |
619 | +} |
620 | + |
621 | // fifoFile() returns the path to the FIFO file used by fake-juju. |
622 | // The FIFO is used by the fake-juju subcommands to interact with |
623 | // the daemon. |
624 | @@ -317,23 +338,6 @@ |
625 | } |
626 | } |
627 | |
628 | -// logsSymlinkFilenames() determines the source and target paths for |
629 | -// a symlink to the fake-juju logs file. Such a symlink is relevant |
630 | -// because the fake-juju daemon may not know where the log file is |
631 | -// meant to go. It defaults to putting the log file in the default Juju |
632 | -// config dir. In that case, a symlink should be created from there to |
633 | -// the user-defined Juju config dir ($JUJU_HOME). |
634 | -func (br bootstrapResult) logsSymlinkFilenames(targetLogsFile string) (source, target string) { |
635 | - if os.Getenv("FAKE_JUJU_LOGS_DIR") != "" || os.Getenv("FAKE_JUJU_DATA_DIR") != "" { |
636 | - return "", "" |
637 | - } |
638 | - |
639 | - filenames := newFakeJujuFilenames("", "", br.cfgdir) |
640 | - source = filenames.logsFile() |
641 | - target = targetLogsFile |
642 | - return source, target |
643 | -} |
644 | - |
645 | // jenvSymlinkFilenames() determines the source and target paths for |
646 | // a symlink to the .jenv file for the identified environment. |
647 | func (br bootstrapResult) jenvSymlinkFilenames(jujuHome, envName string) (source, target string) { |
648 | @@ -353,13 +357,6 @@ |
649 | return err |
650 | } |
651 | |
652 | - logsSource, logsTarget := br.logsSymlinkFilenames(filenames.logsFile()) |
653 | - if logsSource != "" && logsTarget != "" { |
654 | - if err := os.Symlink(logsSource, logsTarget); err != nil { |
655 | - return err |
656 | - } |
657 | - } |
658 | - |
659 | jenvSource, jenvTarget := br.jenvSymlinkFilenames(os.Getenv("JUJU_HOME"), envName) |
660 | if jenvSource != "" && jenvTarget != "" { |
661 | if err := os.MkdirAll(filepath.Dir(jenvTarget), 0755); err != nil { |
662 | @@ -388,6 +385,10 @@ |
663 | return nil, err |
664 | } |
665 | uuid := string(line) |
666 | + if !utils.IsValidUUIDString(uuid) { |
667 | + data, _ := ioutil.ReadAll(stdout) |
668 | + return nil, fmt.Errorf("%s\n%s", line, data) |
669 | + } |
670 | |
671 | line, _, err = buffer.ReadLine() |
672 | if err != nil { |
673 | @@ -395,6 +396,12 @@ |
674 | } |
675 | workDir := string(line) |
676 | |
677 | + result := &bootstrapResult{ |
678 | + dummyEnvName: dummyEnvName, |
679 | + cfgdir: workDir, |
680 | + uuid: uuid, |
681 | + } |
682 | + |
683 | store, err := configstore.NewDisk(workDir) |
684 | if err != nil { |
685 | return nil, err |
686 | @@ -403,18 +410,13 @@ |
687 | if err != nil { |
688 | return nil, err |
689 | } |
690 | - |
691 | credentials := info.APICredentials() |
692 | endpoint := info.APIEndpoint() |
693 | - result := &bootstrapResult{ |
694 | - dummyEnvName: dummyEnvName, |
695 | - cfgdir: workDir, |
696 | - uuid: uuid, |
697 | - username: credentials.User, |
698 | - password: credentials.Password, |
699 | - addresses: endpoint.Addresses, |
700 | - caCert: []byte(endpoint.CACert), |
701 | - } |
702 | + result.username = credentials.User |
703 | + result.password = credentials.Password |
704 | + result.addresses = endpoint.Addresses |
705 | + result.caCert = []byte(endpoint.CACert) |
706 | + |
707 | return result, nil |
708 | } |
709 | |
710 | @@ -462,10 +464,10 @@ |
711 | type FakeJujuSuite struct { |
712 | jujutesting.JujuConnSuite |
713 | |
714 | - instanceCount int |
715 | - machineStarted map[string]bool |
716 | - filenames fakejujuFilenames |
717 | - logFile *os.File |
718 | + instanceCount int |
719 | + machineStarted map[string]bool |
720 | + filenames fakejujuFilenames |
721 | + toCloseOnTearDown []io.Closer |
722 | } |
723 | |
724 | var _ = gc.Suite(&FakeJujuSuite{}) |
725 | @@ -474,6 +476,16 @@ |
726 | var CommandOutput = (*exec.Cmd).CombinedOutput |
727 | s.JujuConnSuite.SetUpTest(c) |
728 | |
729 | + c.Assert(os.Getenv(envDataDir), gc.Not(gc.Equals), "") |
730 | + s.filenames = newFakeJujuFilenames("", "", "") |
731 | + // Note that LoggingSuite.SetUpTest (github.com/juju/testing/log.go), |
732 | + // called via s.JujuConnSuite.SetUpTest(), calls loggo.ResetLogging(). |
733 | + // So we cannot set up logging before then, since any writer we |
734 | + // register will get removed. Consequently we lose any logs that get |
735 | + // generated in the SetUpTest() call. |
736 | + logFile, jujudLogFile := setUpLogging(c, s.filenames) |
737 | + s.toCloseOnTearDown = append(s.toCloseOnTearDown, logFile, jujudLogFile) |
738 | + |
739 | ports := s.APIState.APIHostPorts() |
740 | ports[0][0].NetworkName = "dummy-provider-network" |
741 | err := s.State.SetAPIHostPorts(ports) |
742 | @@ -517,10 +529,6 @@ |
743 | |
744 | apiInfo := s.APIInfo(c) |
745 | jujuHome := osenv.JujuHome() |
746 | - // IMPORTANT: don't remove this logging because it's used by the |
747 | - // bootstrap command. |
748 | - fmt.Println(apiInfo.EnvironTag.Id()) |
749 | - fmt.Println(jujuHome) |
750 | |
751 | binPath := filepath.Join(jujuHome, "bin") |
752 | os.Mkdir(binPath, 0755) |
753 | @@ -530,27 +538,55 @@ |
754 | c.Assert(err, gc.IsNil) |
755 | os.Setenv("PATH", binPath+":"+os.Getenv("PATH")) |
756 | |
757 | - s.filenames = newFakeJujuFilenames("", "", jujuHome) |
758 | + // Once this FIFO is created, users can start sending commands. |
759 | + // The actual handling doesn't start until TestStart() runs. |
760 | syscall.Mknod(s.filenames.fifoFile(), syscall.S_IFIFO|0666, 0) |
761 | |
762 | - // Logging |
763 | - logPath := s.filenames.logsFile() |
764 | - s.logFile, err = os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
765 | - c.Assert(err, gc.IsNil) |
766 | + // Send the info back to the bootstrap command. |
767 | + reportInfo(apiInfo.EnvironTag.Id(), jujuHome) |
768 | |
769 | dpkgCmd := exec.Command( |
770 | "dpkg-query", "--showformat='${Version}'", "--show", "fake-juju") |
771 | out, err := CommandOutput(dpkgCmd) |
772 | - log.SetOutput(s.logFile) |
773 | fakeJujuDebVersion := strings.Trim(string(out), "'") |
774 | log.Printf("Started fake-juju-%s for %s\nJUJU_HOME=%s", fakeJujuDebVersion, version.Current, jujuHome) |
775 | } |
776 | |
777 | +func setUpLogging(c *gc.C, filenames fakejujuFilenames) (*os.File, *os.File) { |
778 | + c.Assert(filenames.logsdir, gc.Not(gc.Equals), "") |
779 | + |
780 | + // fake-juju logging |
781 | + logPath := filenames.logsFile() |
782 | + logFile, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
783 | + c.Assert(err, gc.IsNil) |
784 | + log.SetOutput(logFile) |
785 | + |
786 | + // jujud logging |
787 | + logPath = filenames.jujudLogsFile() |
788 | + jujudLogFile, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
789 | + c.Assert(err, gc.IsNil) |
790 | + err = loggo.RegisterWriter("fake-juju-jujud-logs", loggo.NewSimpleWriter(jujudLogFile, &loggo.DefaultFormatter{}), loggo.TRACE) |
791 | + c.Assert(err, gc.IsNil) |
792 | + logger := loggo.GetLogger("fake-juju") |
793 | + logger.Infof("--- starting logging ---") |
794 | + |
795 | + return logFile, jujudLogFile |
796 | +} |
797 | + |
798 | +func reportInfo(uuid, jujuCfgDir string) { |
799 | + // IMPORTANT: don't remove this logging because it's used by the |
800 | + // bootstrap command. |
801 | + fmt.Println(uuid) |
802 | + fmt.Println(jujuCfgDir) |
803 | +} |
804 | + |
805 | func (s *FakeJujuSuite) TearDownTest(c *gc.C) { |
806 | log.Println("Tearing down processes") |
807 | s.JujuConnSuite.TearDownTest(c) |
808 | - log.Println("Closing log file") |
809 | - s.logFile.Close() |
810 | + log.Println("Closing log files") |
811 | + for _, closer := range s.toCloseOnTearDown { |
812 | + closer.Close() |
813 | + } |
814 | } |
815 | |
816 | func (s *FakeJujuSuite) TestStart(c *gc.C) { |
817 | |
818 | === renamed directory '2.0-beta17' => '2.0.0' |
819 | === modified file '2.0.0/fake-juju.go' |
820 | --- 2.0-beta17/fake-juju.go 2016-10-25 16:32:53 +0000 |
821 | +++ 2.0.0/fake-juju.go 2016-10-29 14:08:30 +0000 |
822 | @@ -4,6 +4,7 @@ |
823 | "bufio" |
824 | "encoding/json" |
825 | "errors" |
826 | + "flag" |
827 | "fmt" |
828 | gc "gopkg.in/check.v1" |
829 | "io" |
830 | @@ -19,6 +20,7 @@ |
831 | |
832 | "github.com/juju/juju/agent" |
833 | "github.com/juju/juju/api" |
834 | + jujucmdcommon "github.com/juju/juju/cmd/juju/common" |
835 | "github.com/juju/juju/cmd/juju/controller" |
836 | "github.com/juju/juju/instance" |
837 | "github.com/juju/juju/juju/osenv" |
838 | @@ -31,12 +33,20 @@ |
839 | coretesting "github.com/juju/juju/testing" |
840 | "github.com/juju/juju/testing/factory" |
841 | "github.com/juju/juju/version" |
842 | + "github.com/juju/loggo" |
843 | + "github.com/juju/utils" |
844 | semversion "github.com/juju/version" |
845 | corecharm "gopkg.in/juju/charmrepo.v2-unstable" |
846 | "gopkg.in/juju/names.v2" |
847 | goyaml "gopkg.in/yaml.v1" |
848 | ) |
849 | |
850 | +const ( |
851 | + envDataDir = "FAKE_JUJU_DATA_DIR" |
852 | + envLogsDir = "FAKE_JUJU_LOGS_DIR" |
853 | + envFailuresFile = "FAKE_JUJU_FAILURES" |
854 | +) |
855 | + |
856 | func main() { |
857 | code := 0 |
858 | if len(os.Args) > 1 { |
859 | @@ -56,49 +66,150 @@ |
860 | func handleCommand(command string) error { |
861 | filenames := newFakeJujuFilenames("", "", "") |
862 | if command == "bootstrap" { |
863 | - return bootstrap(filenames) |
864 | + return handleBootstrap(filenames) |
865 | } |
866 | if command == "show-controller" { |
867 | - return apiInfo(filenames) |
868 | + return handleAPIInfo(filenames) |
869 | } |
870 | if command == "destroy-controller" { |
871 | - return destroyController(filenames) |
872 | + return handleDestroyController(filenames) |
873 | } |
874 | return errors.New("command not found") |
875 | } |
876 | |
877 | -func bootstrap(filenames fakejujuFilenames) error { |
878 | - argc := len(os.Args) |
879 | - if argc < 4 { |
880 | - return errors.New( |
881 | - "error: controller name and cloud name are required") |
882 | +func handleBootstrap(filenames fakejujuFilenames) (returnedErr error) { |
883 | + var args bootstrapArgs |
884 | + if err := args.parse(); err != nil { |
885 | + return err |
886 | } |
887 | if err := filenames.ensureDirsExist(); err != nil { |
888 | return err |
889 | } |
890 | - // XXX Swap the 2 args for juju-2.0-final. |
891 | - controllerName := os.Args[argc-2] |
892 | + |
893 | + // Start the fake-juju daemon. |
894 | command := exec.Command(os.Args[0]) |
895 | command.Env = os.Environ() |
896 | command.Env = append( |
897 | command.Env, "ADMIN_PASSWORD="+"pwd") |
898 | defaultSeries := "trusty" |
899 | command.Env = append(command.Env, "DEFAULT_SERIES="+defaultSeries) |
900 | + command.Env = append(command.Env, envDataDir+"="+filenames.datadir) |
901 | stdout, err := command.StdoutPipe() |
902 | if err != nil { |
903 | return err |
904 | } |
905 | command.Start() |
906 | |
907 | + var whence string |
908 | + defer func() { |
909 | + if returnedErr != nil { |
910 | + if err := destroyController(filenames); err != nil { |
911 | + fmt.Printf("could not destroy controller when %s failed: %v\n", whence, err) |
912 | + } |
913 | + returnedErr = fmt.Errorf("bootstrap failed while %s: %v", whence, returnedErr) |
914 | + } |
915 | + }() |
916 | + |
917 | + // Get the internal info from the daemon and store it. |
918 | result, err := parseApiInfo(stdout) |
919 | if err != nil { |
920 | - return err |
921 | - } |
922 | - if err := result.apply(filenames, controllerName); err != nil { |
923 | - return err |
924 | - } |
925 | + whence = "parsing bootstrap result" |
926 | + return err |
927 | + } |
928 | + if err := result.copyConfig(os.Getenv("JUJU_DATA"), args.controllerName); err != nil { |
929 | + whence = "copying config" |
930 | + return err |
931 | + } |
932 | + if err := updateBootstrapResult(result); err != nil { |
933 | + whence = "updating bootstrap result" |
934 | + return err |
935 | + } |
936 | + if err := result.apply(filenames); err != nil { |
937 | + whence = "setting up fake-juju files" |
938 | + return err |
939 | + } |
940 | + |
941 | + // Wait for the daemon to finish starting up. |
942 | + if err := waitForBootstrapCompletion(result); err != nil { |
943 | + whence = "waiting-for-ready" |
944 | + return err |
945 | + } |
946 | + |
947 | + return nil |
948 | +} |
949 | + |
950 | +// bootstrapArgs is an adaptation of bootstrapCommand from |
951 | +// github.com/juju/juju/cmd/juju/commands/bootstrap.go. |
952 | +type bootstrapArgs struct { |
953 | + config jujucmdcommon.ConfigFlag |
954 | + hostedModelName string |
955 | + credentialName string |
956 | + |
957 | + controllerName string |
958 | + cloud string |
959 | + region string |
960 | +} |
961 | + |
962 | +func (bsargs *bootstrapArgs) parse() error { |
963 | + flags := flag.NewFlagSet("bootstrap", flag.ExitOnError) |
964 | + |
965 | + var ignoredStr string |
966 | + flags.StringVar(&ignoredStr, "constraints", "", "") |
967 | + flags.StringVar(&ignoredStr, "bootstrap-constraints", "", "") |
968 | + flags.StringVar(&ignoredStr, "bootstrap-series", "", "") |
969 | + flags.StringVar(&ignoredStr, "bootstrap-image", "", "") |
970 | + flags.StringVar(&ignoredStr, "metadata-source", "", "") |
971 | + flags.StringVar(&ignoredStr, "to", "", "") |
972 | + flags.StringVar(&ignoredStr, "agent-version", "", "") |
973 | + flags.StringVar(&ignoredStr, "regions", "", "") |
974 | + |
975 | + var ignoredBool bool |
976 | + flags.BoolVar(&ignoredBool, "v", false, "") |
977 | + flags.BoolVar(&ignoredBool, "build-agent", false, "") |
978 | + flags.BoolVar(&ignoredBool, "keep-broken", false, "") |
979 | + flags.BoolVar(&ignoredBool, "auto-upgrade", false, "") |
980 | + flags.BoolVar(&ignoredBool, "no-gui", false, "") |
981 | + flags.BoolVar(&ignoredBool, "clouds", false, "") |
982 | + |
983 | + flags.Var(&bsargs.config, "config", "") |
984 | + flags.StringVar(&bsargs.credentialName, "credential", "", "") |
985 | + flags.StringVar(&bsargs.hostedModelName, "d", "", "") |
986 | + flags.StringVar(&bsargs.hostedModelName, "default-model", "", "") |
987 | + |
988 | + flags.Parse(os.Args[2:]) |
989 | + |
990 | + args := flags.Args() |
991 | + switch len(args) { |
992 | + case 0: |
993 | + return fmt.Errorf("expected at least one positional arg, got none") |
994 | + case 1: |
995 | + bsargs.cloud = args[0] |
996 | + case 2: |
997 | + bsargs.cloud = args[0] |
998 | + bsargs.controllerName = args[1] |
999 | + default: |
1000 | + return fmt.Errorf("expected at most two positional args, got %v", args) |
1001 | + } |
1002 | + |
1003 | + if i := strings.IndexRune(bsargs.cloud, '/'); i > 0 { |
1004 | + bsargs.cloud, bsargs.region = bsargs.cloud[:i], bsargs.cloud[i+1:] |
1005 | + } |
1006 | + if bsargs.controllerName == "" { |
1007 | + bsargs.controllerName = bsargs.cloud |
1008 | + if bsargs.region == "" { |
1009 | + bsargs.controllerName += "-" + bsargs.region |
1010 | + } |
1011 | + } |
1012 | + |
1013 | + if bsargs.hostedModelName == "" { |
1014 | + bsargs.hostedModelName = "default" |
1015 | + } |
1016 | + |
1017 | + return nil |
1018 | +} |
1019 | + |
1020 | +func waitForBootstrapCompletion(result *bootstrapResult) error { |
1021 | apiInfo := result.apiInfo() |
1022 | - |
1023 | dialOpts := api.DialOpts{ |
1024 | DialAddressInterval: 50 * time.Millisecond, |
1025 | Timeout: 5 * time.Second, |
1026 | @@ -128,7 +239,7 @@ |
1027 | return errors.New("invalid delta") |
1028 | } |
1029 | |
1030 | -func apiInfo(filenames fakejujuFilenames) error { |
1031 | +func handleAPIInfo(filenames fakejujuFilenames) error { |
1032 | info, err := readProcessInfo(filenames) |
1033 | if err != nil { |
1034 | return err |
1035 | @@ -137,21 +248,22 @@ |
1036 | jujuHome := os.Getenv("JUJU_DATA") |
1037 | osenv.SetJujuXDGDataHome(jujuHome) |
1038 | cmd := controller.NewShowControllerCommand() |
1039 | - ctx, err := coretesting.RunCommandInDir( |
1040 | - nil, cmd, os.Args[2:], info.WorkDir) |
1041 | - if err != nil { |
1042 | + if err := coretesting.InitCommand(cmd, os.Args[2:]); err != nil { |
1043 | + return err |
1044 | + } |
1045 | + ctx := coretesting.ContextForDir(nil, info.WorkDir) |
1046 | + if err := cmd.Run(ctx); err != nil { |
1047 | return err |
1048 | } |
1049 | fmt.Print(ctx.Stdout) |
1050 | return nil |
1051 | } |
1052 | |
1053 | +func handleDestroyController(filenames fakejujuFilenames) error { |
1054 | + return destroyController(filenames) |
1055 | +} |
1056 | + |
1057 | func destroyController(filenames fakejujuFilenames) error { |
1058 | - info, err := readProcessInfo(filenames) |
1059 | - if err != nil { |
1060 | - return err |
1061 | - } |
1062 | - filenames = newFakeJujuFilenames("", "", info.WorkDir) |
1063 | fd, err := os.OpenFile(filenames.fifoFile(), os.O_APPEND|os.O_WRONLY, 0600) |
1064 | if err != nil { |
1065 | return err |
1066 | @@ -203,7 +315,7 @@ |
1067 | |
1068 | func newFakeJujuFilenames(datadir, logsdir, jujucfgdir string) fakejujuFilenames { |
1069 | if datadir == "" { |
1070 | - datadir = os.Getenv("FAKE_JUJU_DATA_DIR") |
1071 | + datadir = os.Getenv(envDataDir) |
1072 | if datadir == "" { |
1073 | if jujucfgdir == "" { |
1074 | jujucfgdir = os.Getenv("JUJU_DATA") |
1075 | @@ -212,7 +324,7 @@ |
1076 | } |
1077 | } |
1078 | if logsdir == "" { |
1079 | - logsdir = os.Getenv("FAKE_JUJU_LOGS_DIR") |
1080 | + logsdir = os.Getenv(envLogsDir) |
1081 | if logsdir == "" { |
1082 | logsdir = datadir |
1083 | } |
1084 | @@ -242,6 +354,12 @@ |
1085 | return filepath.Join(fj.logsdir, "fake-juju.log") |
1086 | } |
1087 | |
1088 | +// jujudLogsFile() returns the path to the file where fake-juju writes |
1089 | +// the jujud logs. |
1090 | +func (fj fakejujuFilenames) jujudLogsFile() string { |
1091 | + return filepath.Join(fj.logsdir, "jujud.log") |
1092 | +} |
1093 | + |
1094 | // fifoFile() returns the path to the FIFO file used by fake-juju. |
1095 | // The FIFO is used by the fake-juju subcommands to interact with |
1096 | // the daemon. |
1097 | @@ -290,41 +408,13 @@ |
1098 | } |
1099 | } |
1100 | |
1101 | -// logsSymlinkFilenames() determines the source and target paths for |
1102 | -// a symlink to the fake-juju logs file. Such a symlink is relevant |
1103 | -// because the fake-juju daemon may not know where the log file is |
1104 | -// meant to go. It defaults to putting the log file in the default Juju |
1105 | -// config dir. In that case, a symlink should be created from there to |
1106 | -// the user-defined Juju config dir ($JUJU_DATA). |
1107 | -func (br bootstrapResult) logsSymlinkFilenames(targetLogsFile string) (source, target string) { |
1108 | - if os.Getenv("FAKE_JUJU_LOGS_DIR") != "" { |
1109 | - return "", "" |
1110 | - } |
1111 | - |
1112 | - filenames := newFakeJujuFilenames("", "", br.cfgdir) |
1113 | - source = filenames.logsFile() |
1114 | - target = targetLogsFile |
1115 | - return source, target |
1116 | -} |
1117 | - |
1118 | // apply() writes out the information from the bootstrap result to the |
1119 | // various files identified by the provided filenames. |
1120 | -func (br bootstrapResult) apply(filenames fakejujuFilenames, controllerName string) error { |
1121 | +func (br bootstrapResult) apply(filenames fakejujuFilenames) error { |
1122 | if err := br.fakeJujuInfo().write(filenames.infoFile()); err != nil { |
1123 | return err |
1124 | } |
1125 | |
1126 | - logsSource, logsTarget := br.logsSymlinkFilenames(filenames.logsFile()) |
1127 | - if logsSource != "" && logsTarget != "" { |
1128 | - if err := os.Symlink(logsSource, logsTarget); err != nil { |
1129 | - return err |
1130 | - } |
1131 | - } |
1132 | - |
1133 | - if err := br.copyConfig(os.Getenv("JUJU_DATA"), controllerName); err != nil { |
1134 | - return err |
1135 | - } |
1136 | - |
1137 | if err := ioutil.WriteFile(filenames.caCertFile(), br.caCert, 0644); err != nil { |
1138 | return err |
1139 | } |
1140 | @@ -333,6 +423,9 @@ |
1141 | } |
1142 | |
1143 | func (br bootstrapResult) copyConfig(targetCfgDir, controllerName string) error { |
1144 | + if err := os.MkdirAll(targetCfgDir, 0755); err != nil { |
1145 | + return err |
1146 | + } |
1147 | for _, name := range []string{"controllers.yaml", "models.yaml", "accounts.yaml"} { |
1148 | source := filepath.Join(br.cfgdir, name) |
1149 | target := filepath.Join(targetCfgDir, name) |
1150 | @@ -360,8 +453,7 @@ |
1151 | return nil |
1152 | } |
1153 | |
1154 | -// See github.com/juju/juju/blob/juju/testing/conn.go. |
1155 | -const dummyControllerName = "kontroll" |
1156 | +const dummyControllerName = jujutesting.ControllerName |
1157 | |
1158 | func parseApiInfo(stdout io.ReadCloser) (*bootstrapResult, error) { |
1159 | buffer := bufio.NewReader(stdout) |
1160 | @@ -371,6 +463,10 @@ |
1161 | return nil, err |
1162 | } |
1163 | uuid := string(line) |
1164 | + if !utils.IsValidUUIDString(uuid) { |
1165 | + data, _ := ioutil.ReadAll(stdout) |
1166 | + return nil, fmt.Errorf("%s\n%s", line, data) |
1167 | + } |
1168 | |
1169 | line, _, err = buffer.ReadLine() |
1170 | if err != nil { |
1171 | @@ -378,31 +474,37 @@ |
1172 | } |
1173 | workDir := string(line) |
1174 | |
1175 | - osenv.SetJujuXDGDataHome(workDir) |
1176 | + result := &bootstrapResult{ |
1177 | + dummyControllerName: dummyControllerName, |
1178 | + cfgdir: workDir, |
1179 | + uuid: uuid, |
1180 | + } |
1181 | + return result, nil |
1182 | +} |
1183 | + |
1184 | +func updateBootstrapResult(result *bootstrapResult) error { |
1185 | + osenv.SetJujuXDGDataHome(result.cfgdir) |
1186 | store := jujuclient.NewFileClientStore() |
1187 | + |
1188 | // hard-coded value in juju testing |
1189 | // This will be replaced in JUJU_DATA copy of the juju client config. |
1190 | - currentController := dummyControllerName |
1191 | + currentController := result.dummyControllerName |
1192 | + |
1193 | one, err := store.ControllerByName(currentController) |
1194 | if err != nil { |
1195 | - return nil, err |
1196 | + return err |
1197 | } |
1198 | + result.addresses = one.APIEndpoints |
1199 | + result.caCert = []byte(one.CACert) |
1200 | |
1201 | accountDetails, err := store.AccountDetails(currentController) |
1202 | if err != nil { |
1203 | - return nil, err |
1204 | + return err |
1205 | } |
1206 | + result.username = accountDetails.User |
1207 | + result.password = accountDetails.Password |
1208 | |
1209 | - result := &bootstrapResult{ |
1210 | - dummyControllerName: dummyControllerName, |
1211 | - cfgdir: workDir, |
1212 | - uuid: uuid, |
1213 | - username: accountDetails.User, |
1214 | - password: accountDetails.Password, |
1215 | - addresses: one.APIEndpoints, |
1216 | - caCert: []byte(one.CACert), |
1217 | - } |
1218 | - return result, nil |
1219 | + return nil |
1220 | } |
1221 | |
1222 | // Read the failures info file pointed by the FAKE_JUJU_FAILURES environment |
1223 | @@ -411,9 +513,9 @@ |
1224 | // entity transition to an error state. |
1225 | func readFailuresInfo() (map[string]bool, error) { |
1226 | log.Println("Checking for forced failures") |
1227 | - failuresPath := os.Getenv("FAKE_JUJU_FAILURES") |
1228 | + failuresPath := os.Getenv(envFailuresFile) |
1229 | if failuresPath == "" { |
1230 | - log.Println("No FAKE_JUJU_FAILURES env variable set") |
1231 | + log.Printf("No %s env variable set\n", envFailuresFile) |
1232 | } |
1233 | log.Println("Reading failures file", failuresPath) |
1234 | failuresInfo := map[string]bool{} |
1235 | @@ -449,10 +551,10 @@ |
1236 | type FakeJujuSuite struct { |
1237 | jujutesting.JujuConnSuite |
1238 | |
1239 | - instanceCount int |
1240 | - machineStarted map[string]bool |
1241 | - filenames fakejujuFilenames |
1242 | - logFile *os.File |
1243 | + instanceCount int |
1244 | + machineStarted map[string]bool |
1245 | + filenames fakejujuFilenames |
1246 | + toCloseOnTearDown []io.Closer |
1247 | } |
1248 | |
1249 | var _ = gc.Suite(&FakeJujuSuite{}) |
1250 | @@ -460,6 +562,16 @@ |
1251 | func (s *FakeJujuSuite) SetUpTest(c *gc.C) { |
1252 | s.JujuConnSuite.SetUpTest(c) |
1253 | |
1254 | + c.Assert(os.Getenv(envDataDir), gc.Not(gc.Equals), "") |
1255 | + s.filenames = newFakeJujuFilenames("", "", "") |
1256 | + // Note that LoggingSuite.SetUpTest (github.com/juju/testing/log.go), |
1257 | + // called via s.JujuConnSuite.SetUpTest(), calls loggo.ResetLogging(). |
1258 | + // So we cannot set up logging before then, since any writer we |
1259 | + // register will get removed. Consequently we lose any logs that get |
1260 | + // generated in the SetUpTest() call. |
1261 | + logFile, jujudLogFile := setUpLogging(c, s.filenames) |
1262 | + s.toCloseOnTearDown = append(s.toCloseOnTearDown, logFile, jujudLogFile) |
1263 | + |
1264 | ports := s.APIState.APIHostPorts() |
1265 | err := s.State.SetAPIHostPorts(ports) |
1266 | c.Assert(err, gc.IsNil) |
1267 | @@ -491,7 +603,7 @@ |
1268 | c.Assert(stateServer.SetProviderAddresses(address), gc.IsNil) |
1269 | now := time.Now() |
1270 | sInfo := states.StatusInfo{ |
1271 | - Status: states.StatusStarted, |
1272 | + Status: states.Started, |
1273 | Message: "", |
1274 | Since: &now, |
1275 | } |
1276 | @@ -505,10 +617,6 @@ |
1277 | apiInfo := s.APIInfo(c) |
1278 | //fmt.Println(apiInfo.Addrs[0]) |
1279 | jujuHome := osenv.JujuXDGDataHome() |
1280 | - // IMPORTANT: don't remove this logging because it's used by the |
1281 | - // bootstrap command. |
1282 | - fmt.Println(apiInfo.ModelTag.Id()) |
1283 | - fmt.Println(jujuHome) |
1284 | |
1285 | binPath := filepath.Join(jujuHome, "bin") |
1286 | os.Mkdir(binPath, 0755) |
1287 | @@ -518,24 +626,51 @@ |
1288 | c.Assert(err, gc.IsNil) |
1289 | os.Setenv("PATH", binPath+":"+os.Getenv("PATH")) |
1290 | |
1291 | - s.filenames = newFakeJujuFilenames("", "", jujuHome) |
1292 | + // Once this FIFO is created, users can start sending commands. |
1293 | + // The actual handling doesn't start until TestStart() runs. |
1294 | syscall.Mknod(s.filenames.fifoFile(), syscall.S_IFIFO|0666, 0) |
1295 | |
1296 | - // Logging |
1297 | - logPath := s.filenames.logsFile() |
1298 | - s.logFile, err = os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
1299 | - c.Assert(err, gc.IsNil) |
1300 | + // Send the info back to the bootstrap command. |
1301 | + reportInfo(apiInfo.ModelTag.Id(), jujuHome) |
1302 | |
1303 | - log.SetOutput(s.logFile) |
1304 | log.Println("Started fake-juju at ", jujuHome) |
1305 | - |
1306 | +} |
1307 | + |
1308 | +func setUpLogging(c *gc.C, filenames fakejujuFilenames) (*os.File, *os.File) { |
1309 | + c.Assert(filenames.logsdir, gc.Not(gc.Equals), "") |
1310 | + |
1311 | + // fake-juju logging |
1312 | + logPath := filenames.logsFile() |
1313 | + logFile, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
1314 | + c.Assert(err, gc.IsNil) |
1315 | + log.SetOutput(logFile) |
1316 | + |
1317 | + // jujud logging |
1318 | + logPath = filenames.jujudLogsFile() |
1319 | + jujudLogFile, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
1320 | + c.Assert(err, gc.IsNil) |
1321 | + err = loggo.RegisterWriter("fake-juju-jujud-logs", loggo.NewSimpleWriter(jujudLogFile, nil)) |
1322 | + c.Assert(err, gc.IsNil) |
1323 | + logger := loggo.GetLogger("fake-juju") |
1324 | + logger.Infof("--- starting logging ---") |
1325 | + |
1326 | + return logFile, jujudLogFile |
1327 | +} |
1328 | + |
1329 | +func reportInfo(uuid, jujuCfgDir string) { |
1330 | + // IMPORTANT: don't remove this logging because it's used by the |
1331 | + // bootstrap command. |
1332 | + fmt.Println(uuid) |
1333 | + fmt.Println(jujuCfgDir) |
1334 | } |
1335 | |
1336 | func (s *FakeJujuSuite) TearDownTest(c *gc.C) { |
1337 | log.Println("Tearing down processes") |
1338 | s.JujuConnSuite.TearDownTest(c) |
1339 | - log.Println("Closing log file") |
1340 | - s.logFile.Close() |
1341 | + log.Println("Closing log files") |
1342 | + for _, closer := range s.toCloseOnTearDown { |
1343 | + closer.Close() |
1344 | + } |
1345 | } |
1346 | |
1347 | func (s *FakeJujuSuite) TestStart(c *gc.C) { |
1348 | @@ -625,12 +760,12 @@ |
1349 | } |
1350 | status, _ := machine.Status() |
1351 | log.Println("Machine has status:", string(status.Status), status.Message) |
1352 | - if status.Status == states.StatusPending { |
1353 | + if status.Status == states.Pending { |
1354 | if err = s.startMachine(machine); err != nil { |
1355 | log.Println("Got error with startMachine:", err) |
1356 | return err |
1357 | } |
1358 | - } else if status.Status == states.StatusStarted { |
1359 | + } else if status.Status == states.Started { |
1360 | log.Println("Starting units on machine", id) |
1361 | if _, ok := s.machineStarted[id]; !ok { |
1362 | s.machineStarted[id] = true |
1363 | @@ -661,19 +796,19 @@ |
1364 | return err |
1365 | } |
1366 | machineStatus, _ := machine.Status() |
1367 | - if machineStatus.Status != states.StatusStarted { |
1368 | + if machineStatus.Status != states.Started { |
1369 | return nil |
1370 | } |
1371 | status, _ := unit.Status() |
1372 | log.Println("Unit has status", string(status.Status), status.Message) |
1373 | - if status.Status != states.StatusActive && status.Status != states.StatusError { |
1374 | + if status.Status != states.Active && status.Status != states.Error { |
1375 | log.Println("Start unit", id) |
1376 | err = s.startUnit(unit) |
1377 | if err != nil { |
1378 | log.Println("Got error changing unit status", id, err) |
1379 | return err |
1380 | } |
1381 | - } else if status.Status != states.StatusError { |
1382 | + } else if status.Status != states.Error { |
1383 | failuresInfo, err := readFailuresInfo() |
1384 | if err != nil { |
1385 | return err |
1386 | @@ -684,7 +819,7 @@ |
1387 | log.Println("Got error checking agent status", id, err) |
1388 | return err |
1389 | } |
1390 | - if agentStatus.Status != states.StatusError { |
1391 | + if agentStatus.Status != states.Error { |
1392 | log.Println("Error unit", id) |
1393 | err = s.errorUnit(unit) |
1394 | if err != nil { |
1395 | @@ -701,7 +836,7 @@ |
1396 | time.Sleep(500 * time.Millisecond) |
1397 | now := time.Now() |
1398 | sInfo := states.StatusInfo{ |
1399 | - Status: states.StatusStarted, |
1400 | + Status: states.Started, |
1401 | Message: "", |
1402 | Since: &now, |
1403 | } |
1404 | @@ -734,7 +869,7 @@ |
1405 | time.Sleep(500 * time.Millisecond) |
1406 | now := time.Now() |
1407 | sInfo := states.StatusInfo{ |
1408 | - Status: states.StatusError, |
1409 | + Status: states.Error, |
1410 | Message: "machine errored", |
1411 | Since: &now, |
1412 | } |
1413 | @@ -753,7 +888,7 @@ |
1414 | return nil |
1415 | for _, unit := range units { |
1416 | unitStatus, _ := unit.Status() |
1417 | - if unitStatus.Status != states.StatusActive { |
1418 | + if unitStatus.Status != states.Active { |
1419 | if err = s.startUnit(unit); err != nil { |
1420 | return err |
1421 | } |
1422 | @@ -765,7 +900,7 @@ |
1423 | func (s *FakeJujuSuite) startUnit(unit *state.Unit) error { |
1424 | now := time.Now() |
1425 | sInfo := states.StatusInfo{ |
1426 | - Status: states.StatusStarted, |
1427 | + Status: states.Started, |
1428 | Message: "", |
1429 | Since: &now, |
1430 | } |
1431 | @@ -783,7 +918,7 @@ |
1432 | return err |
1433 | } |
1434 | idleInfo := states.StatusInfo{ |
1435 | - Status: states.StatusIdle, |
1436 | + Status: states.Idle, |
1437 | Message: "", |
1438 | Since: &now, |
1439 | } |
1440 | @@ -798,7 +933,7 @@ |
1441 | log.Println("Erroring unit", unit.Name()) |
1442 | now := time.Now() |
1443 | sInfo := states.StatusInfo{ |
1444 | - Status: states.StatusIdle, |
1445 | + Status: states.Idle, |
1446 | Message: "unit errored", |
1447 | Since: &now, |
1448 | } |
1449 | |
1450 | === modified file 'Makefile' |
1451 | --- Makefile 2016-10-27 16:36:28 +0000 |
1452 | +++ Makefile 2016-10-29 14:08:30 +0000 |
1453 | @@ -63,8 +63,8 @@ |
1454 | # for all versions |
1455 | |
1456 | ifndef JUJU_VERSIONS |
1457 | -JUJU1_VERSIONS = 1.24.7 1.25.6 |
1458 | -JUJU2_VERSIONS = 2.0-beta17 |
1459 | +JUJU1_VERSIONS = 1.25.6 |
1460 | +JUJU2_VERSIONS = 2.0.0 |
1461 | JUJU_VERSIONS = $(JUJU1_VERSIONS) $(JUJU2_VERSIONS) |
1462 | endif |
1463 | BUILT_VERSIONS = $(foreach version,$(JUJU_VERSIONS),$(version)/$(version)) |
1464 | |
1465 | === removed file 'patches/juju-core_1.24.7.patch' |
1466 | --- patches/juju-core_1.24.7.patch 2016-03-18 11:10:52 +0000 |
1467 | +++ patches/juju-core_1.24.7.patch 1970-01-01 00:00:00 +0000 |
1468 | @@ -1,47 +0,0 @@ |
1469 | ---- 1.24.7/src/github.com/juju/juju/testcharms/charm.go.orig 2015-06-24 12:02:02.746416146 +0200 |
1470 | -+++ 1.24.7/src/github.com/juju/juju/testcharms/charm.go 2015-06-24 12:03:49.810418650 +0200 |
1471 | -@@ -10,4 +10,6 @@ |
1472 | - ) |
1473 | - |
1474 | - // Repo provides access to the test charm repository. |
1475 | --var Repo = testing.NewRepo("charm-repo", "quantal") |
1476 | -+// XXX fake-juju: avoid crashing because the charm-repo dir is not there |
1477 | -+//var Repo = testing.NewRepo("charm-repo", "quantal") |
1478 | -+var Repo = &testing.Repo{} |
1479 | - |
1480 | ---- 1.24.7/src/github.com/juju/juju/provider/dummy/environs.go.orig 2015-07-06 15:01:14.200568258 +0200 |
1481 | -+++ 1.24.7/src/github.com/juju/juju/provider/dummy/environs.go 2015-07-06 15:18:32.648549661 +0200 |
1482 | -@@ -642,9 +642,9 @@ |
1483 | - |
1484 | - // PrecheckInstance is specified in the state.Prechecker interface. |
1485 | - func (*environ) PrecheckInstance(series string, cons constraints.Value, placement string) error { |
1486 | -- if placement != "" && placement != "valid" { |
1487 | -- return fmt.Errorf("%s placement is invalid", placement) |
1488 | -- } |
1489 | -+// if placement != "" && placement != "valid" { |
1490 | -+// return fmt.Errorf("%s placement is invalid", placement) |
1491 | -+// } |
1492 | - return nil |
1493 | - } |
1494 | - |
1495 | ---- 1.24.7/src/github.com/juju/juju/testing/cert.go 2016-03-18 09:25:34 +0000 |
1496 | -+++ 1.24.7/src/github.com/juju/juju/testing/cert.go 2016-03-18 09:26:04 +0000 |
1497 | -@@ -52,7 +52,7 @@ |
1498 | - } |
1499 | - |
1500 | - func mustNewCA() (string, string) { |
1501 | -- cert.KeyBits = 512 |
1502 | -+ cert.KeyBits = 1024 |
1503 | - caCert, caKey, err := cert.NewCA("juju testing", time.Now().AddDate(10, 0, 0)) |
1504 | - if err != nil { |
1505 | - panic(err) |
1506 | -@@ -61,7 +61,7 @@ |
1507 | - } |
1508 | - |
1509 | - func mustNewServer() (string, string) { |
1510 | -- cert.KeyBits = 512 |
1511 | -+ cert.KeyBits = 1024 |
1512 | - var hostnames []string |
1513 | - srvCert, srvKey, err := cert.NewServer(CACert, CAKey, time.Now().AddDate(10, 0, 0), hostnames) |
1514 | - if err != nil { |
1515 | - |
1516 | |
1517 | === renamed file 'patches/juju-core_2.0-beta17.patch' => 'patches/juju-core_2.0.0.patch' |
1518 | --- patches/juju-core_2.0-beta17.patch 2016-09-01 22:03:22 +0000 |
1519 | +++ patches/juju-core_2.0.0.patch 2016-10-29 14:08:30 +0000 |
1520 | @@ -1,5 +1,5 @@ |
1521 | ---- 2.0-beta17/src/github.com/juju/juju/testcharms/charm.go 2016-03-10 13:45:57.000000000 +0100 |
1522 | -+++ 2.0-beta17/src/github.com/juju/juju/testcharms/charm.go 2016-03-21 10:46:24.312966629 +0100 |
1523 | +--- 2.0.0/src/github.com/juju/juju/testcharms/charm.go 2016-03-10 13:45:57.000000000 +0100 |
1524 | ++++ 2.0.0/src/github.com/juju/juju/testcharms/charm.go 2016-03-21 10:46:24.312966629 +0100 |
1525 | @@ -17,7 +17,9 @@ |
1526 | ) |
1527 | |
1528 | @@ -11,8 +11,8 @@ |
1529 | |
1530 | // UploadCharm uploads a charm using the given charm store client, and returns |
1531 | // the resulting charm URL and charm. |
1532 | ---- 2.0-beta17/src/github.com/juju/juju/provider/dummy/environs.go 2015-07-06 15:01:14.200568258 +0200 |
1533 | -+++ 2.0-beta17/src/github.com/juju/juju/provider/dummy/environs.go 2015-07-06 15:18:32.648549661 +0200 |
1534 | +--- 2.0.0/src/github.com/juju/juju/provider/dummy/environs.go 2015-07-06 15:01:14.200568258 +0200 |
1535 | ++++ 2.0.0/src/github.com/juju/juju/provider/dummy/environs.go 2015-07-06 15:18:32.648549661 +0200 |
1536 | @@ -633,9 +633,9 @@ |
1537 | |
1538 | // PrecheckInstance is specified in the state.Prechecker interface. |
1539 | @@ -26,8 +26,8 @@ |
1540 | return nil |
1541 | } |
1542 | |
1543 | ---- 2.0-beta17/src/github.com/juju/juju/testing/cert.go 2016-03-18 09:25:34 +0000 |
1544 | -+++ 2.0-beta17/src/github.com/juju/juju/testing/cert.go 2016-03-18 09:26:04 +0000 |
1545 | +--- 2.0.0/src/github.com/juju/juju/testing/cert.go 2016-03-18 09:25:34 +0000 |
1546 | ++++ 2.0.0/src/github.com/juju/juju/testing/cert.go 2016-03-18 09:26:04 +0000 |
1547 | @@ -52,7 +52,7 @@ |
1548 | } |
1549 | |
1550 | |
1551 | === modified file 'python/fakejuju/testing.py' |
1552 | --- python/fakejuju/testing.py 2016-10-18 20:54:27 +0000 |
1553 | +++ python/fakejuju/testing.py 2016-10-29 14:08:30 +0000 |
1554 | @@ -7,8 +7,8 @@ |
1555 | |
1556 | |
1557 | JUJU1_VER = "1.25.6" |
1558 | -JUJU2_VER = "2.0-beta17" |
1559 | -JUJU_VER = JUJU1_VER |
1560 | +JUJU2_VER = "2.0.0" |
1561 | +JUJU_VER = JUJU2_VER |
1562 | |
1563 | |
1564 | class FakeJujuFixture(Fixture): |
1565 | |
1566 | === modified file 'tests/test_fake.py' |
1567 | --- tests/test_fake.py 2016-09-15 20:38:52 +0000 |
1568 | +++ tests/test_fake.py 2016-10-29 14:08:30 +0000 |
1569 | @@ -37,7 +37,7 @@ |
1570 | super(_JujuFakeTest, self).setUp() |
1571 | |
1572 | self.env = os.environ.copy() |
1573 | - self.juju_home = cfgdir = tempfile.mkdtemp() |
1574 | + self.juju_home = cfgdir = tempfile.mkdtemp(prefix="fake-juju-test-") |
1575 | _jujuclient.prepare("dummy", "dummy", cfgdir, self.env, JUJU_VERSION) |
1576 | |
1577 | endpoint, uuid, password = self.bootstrap("dummy", "dummy", self.env) |
1578 | @@ -100,7 +100,7 @@ |
1579 | |
1580 | def bootstrap(self, name, type, env): |
1581 | """Return the API endpoint after bootstrapping the controller.""" |
1582 | - args = [JUJU_FAKE, "bootstrap", "--no-gui", name, type] |
1583 | + args = [JUJU_FAKE, "bootstrap", "--no-gui", type, name] |
1584 | subprocess.check_call(args, env=env) |
1585 | |
1586 | args = [JUJU_FAKE, "show-controller", "--format", "json", |
1587 | @@ -108,7 +108,7 @@ |
1588 | output = subprocess.check_output(args, env=env) |
1589 | api_info = json.loads(output.decode()) |
1590 | endpoint = str(api_info[name]["details"]["api-endpoints"][0]) |
1591 | - model = api_info[name]["current-model"] |
1592 | + model = api_info[name]["current-model"].split("/", 1)[-1] |
1593 | uuid = api_info[name]["models"][model]["uuid"] |
1594 | password = api_info[name]["account"]["password"] |
1595 | return endpoint, uuid, password |
Command: make ci-test /ci.lscape. net/job/ latch-test- xenial/ 336/
Result: Success
Revno: 63
Branch: lp:~ericsnowcurrently/fake-juju/juju-2.0-support
Jenkins: https:/