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