PageRenderTime 87ms CodeModel.GetById 58ms RepoModel.GetById 1ms app.codeStats 0ms

/cmd/juju/status_test.go

https://github.com/didrocks/juju
Go | 2038 lines | 1870 code | 136 blank | 32 comment | 10 complexity | aad3c68e2b613acc75c7306fe9313f98 MD5 | raw file
Possible License(s): AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright 2012, 2013 Canonical Ltd.
  2. // Licensed under the AGPLv3, see LICENCE file for details.
  3. package main
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "fmt"
  8. "net/url"
  9. "strings"
  10. "time"
  11. jc "github.com/juju/testing/checkers"
  12. gc "launchpad.net/gocheck"
  13. "launchpad.net/goyaml"
  14. "github.com/juju/juju/charm"
  15. charmtesting "github.com/juju/juju/charm/testing"
  16. "github.com/juju/juju/cmd"
  17. "github.com/juju/juju/cmd/envcmd"
  18. "github.com/juju/juju/constraints"
  19. "github.com/juju/juju/instance"
  20. "github.com/juju/juju/juju"
  21. "github.com/juju/juju/juju/testing"
  22. "github.com/juju/juju/network"
  23. "github.com/juju/juju/state"
  24. "github.com/juju/juju/state/api/params"
  25. "github.com/juju/juju/state/presence"
  26. coretesting "github.com/juju/juju/testing"
  27. "github.com/juju/juju/version"
  28. )
  29. func runStatus(c *gc.C, args ...string) (code int, stdout, stderr []byte) {
  30. ctx := coretesting.Context(c)
  31. code = cmd.Main(envcmd.Wrap(&StatusCommand{}), ctx, args)
  32. stdout = ctx.Stdout.(*bytes.Buffer).Bytes()
  33. stderr = ctx.Stderr.(*bytes.Buffer).Bytes()
  34. return
  35. }
  36. type StatusSuite struct {
  37. testing.JujuConnSuite
  38. }
  39. var _ = gc.Suite(&StatusSuite{})
  40. type M map[string]interface{}
  41. type L []interface{}
  42. type testCase struct {
  43. summary string
  44. steps []stepper
  45. }
  46. func test(summary string, steps ...stepper) testCase {
  47. return testCase{summary, steps}
  48. }
  49. type stepper interface {
  50. step(c *gc.C, ctx *context)
  51. }
  52. type context struct {
  53. st *state.State
  54. conn *juju.Conn
  55. charms map[string]*state.Charm
  56. pingers map[string]*presence.Pinger
  57. }
  58. func (s *StatusSuite) newContext() *context {
  59. st := s.Conn.Environ.(testing.GetStater).GetStateInAPIServer()
  60. // We make changes in the API server's state so that
  61. // our changes to presence are immediately noticed
  62. // in the status.
  63. return &context{
  64. st: st,
  65. conn: s.Conn,
  66. charms: make(map[string]*state.Charm),
  67. pingers: make(map[string]*presence.Pinger),
  68. }
  69. }
  70. func (s *StatusSuite) resetContext(c *gc.C, ctx *context) {
  71. for _, up := range ctx.pingers {
  72. err := up.Kill()
  73. c.Check(err, gc.IsNil)
  74. }
  75. s.JujuConnSuite.Reset(c)
  76. }
  77. func (ctx *context) run(c *gc.C, steps []stepper) {
  78. for i, s := range steps {
  79. c.Logf("step %d", i)
  80. c.Logf("%#v", s)
  81. s.step(c, ctx)
  82. }
  83. }
  84. type aliver interface {
  85. AgentAlive() (bool, error)
  86. SetAgentAlive() (*presence.Pinger, error)
  87. WaitAgentAlive(time.Duration) error
  88. }
  89. func (ctx *context) setAgentAlive(c *gc.C, a aliver) *presence.Pinger {
  90. pinger, err := a.SetAgentAlive()
  91. c.Assert(err, gc.IsNil)
  92. ctx.st.StartSync()
  93. err = a.WaitAgentAlive(coretesting.LongWait)
  94. c.Assert(err, gc.IsNil)
  95. agentAlive, err := a.AgentAlive()
  96. c.Assert(err, gc.IsNil)
  97. c.Assert(agentAlive, gc.Equals, true)
  98. return pinger
  99. }
  100. // shortcuts for expected output.
  101. var (
  102. machine0 = M{
  103. "agent-state": "started",
  104. "dns-name": "dummyenv-0.dns",
  105. "instance-id": "dummyenv-0",
  106. "series": "quantal",
  107. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  108. "state-server-member-status": "adding-vote",
  109. }
  110. machine1 = M{
  111. "agent-state": "started",
  112. "dns-name": "dummyenv-1.dns",
  113. "instance-id": "dummyenv-1",
  114. "series": "quantal",
  115. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  116. }
  117. machine2 = M{
  118. "agent-state": "started",
  119. "dns-name": "dummyenv-2.dns",
  120. "instance-id": "dummyenv-2",
  121. "series": "quantal",
  122. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  123. }
  124. machine3 = M{
  125. "agent-state": "started",
  126. "dns-name": "dummyenv-3.dns",
  127. "instance-id": "dummyenv-3",
  128. "series": "quantal",
  129. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  130. }
  131. machine4 = M{
  132. "agent-state": "started",
  133. "dns-name": "dummyenv-4.dns",
  134. "instance-id": "dummyenv-4",
  135. "series": "quantal",
  136. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  137. }
  138. machine1WithContainers = M{
  139. "agent-state": "started",
  140. "containers": M{
  141. "1/lxc/0": M{
  142. "agent-state": "started",
  143. "containers": M{
  144. "1/lxc/0/lxc/0": M{
  145. "agent-state": "started",
  146. "dns-name": "dummyenv-3.dns",
  147. "instance-id": "dummyenv-3",
  148. "series": "quantal",
  149. },
  150. },
  151. "dns-name": "dummyenv-2.dns",
  152. "instance-id": "dummyenv-2",
  153. "series": "quantal",
  154. },
  155. "1/lxc/1": M{
  156. "instance-id": "pending",
  157. "series": "quantal",
  158. },
  159. },
  160. "dns-name": "dummyenv-1.dns",
  161. "instance-id": "dummyenv-1",
  162. "series": "quantal",
  163. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  164. }
  165. machine1WithContainersScoped = M{
  166. "agent-state": "started",
  167. "containers": M{
  168. "1/lxc/0": M{
  169. "agent-state": "started",
  170. "dns-name": "dummyenv-2.dns",
  171. "instance-id": "dummyenv-2",
  172. "series": "quantal",
  173. },
  174. },
  175. "dns-name": "dummyenv-1.dns",
  176. "instance-id": "dummyenv-1",
  177. "series": "quantal",
  178. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  179. }
  180. unexposedService = M{
  181. "charm": "cs:quantal/dummy-1",
  182. "exposed": false,
  183. }
  184. exposedService = M{
  185. "charm": "cs:quantal/dummy-1",
  186. "exposed": true,
  187. }
  188. )
  189. type outputFormat struct {
  190. name string
  191. marshal func(v interface{}) ([]byte, error)
  192. unmarshal func(data []byte, v interface{}) error
  193. }
  194. // statusFormats list all output formats supported by status command.
  195. var statusFormats = []outputFormat{
  196. {"yaml", goyaml.Marshal, goyaml.Unmarshal},
  197. {"json", json.Marshal, json.Unmarshal},
  198. }
  199. var machineCons = constraints.MustParse("cpu-cores=2 mem=8G root-disk=8G")
  200. var statusTests = []testCase{
  201. // Status tests
  202. test(
  203. "bootstrap and starting a single instance",
  204. // unlikely, as you can't run juju status in real life without
  205. // machine/0 bootstrapped.
  206. expect{
  207. "empty state",
  208. M{
  209. "environment": "dummyenv",
  210. "machines": M{},
  211. "services": M{},
  212. },
  213. },
  214. addMachine{machineId: "0", job: state.JobManageEnviron},
  215. expect{
  216. "simulate juju bootstrap by adding machine/0 to the state",
  217. M{
  218. "environment": "dummyenv",
  219. "machines": M{
  220. "0": M{
  221. "instance-id": "pending",
  222. "series": "quantal",
  223. "state-server-member-status": "adding-vote",
  224. },
  225. },
  226. "services": M{},
  227. },
  228. },
  229. startAliveMachine{"0"},
  230. setAddresses{"0", []network.Address{
  231. network.NewAddress("10.0.0.1", network.ScopeUnknown),
  232. network.NewAddress("dummyenv-0.dns", network.ScopePublic),
  233. }},
  234. expect{
  235. "simulate the PA starting an instance in response to the state change",
  236. M{
  237. "environment": "dummyenv",
  238. "machines": M{
  239. "0": M{
  240. "agent-state": "pending",
  241. "dns-name": "dummyenv-0.dns",
  242. "instance-id": "dummyenv-0",
  243. "series": "quantal",
  244. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  245. "state-server-member-status": "adding-vote",
  246. },
  247. },
  248. "services": M{},
  249. },
  250. },
  251. setMachineStatus{"0", params.StatusStarted, ""},
  252. expect{
  253. "simulate the MA started and set the machine status",
  254. M{
  255. "environment": "dummyenv",
  256. "machines": M{
  257. "0": machine0,
  258. },
  259. "services": M{},
  260. },
  261. },
  262. setTools{"0", version.MustParseBinary("1.2.3-gutsy-ppc")},
  263. expect{
  264. "simulate the MA setting the version",
  265. M{
  266. "environment": "dummyenv",
  267. "machines": M{
  268. "0": M{
  269. "dns-name": "dummyenv-0.dns",
  270. "instance-id": "dummyenv-0",
  271. "agent-version": "1.2.3",
  272. "agent-state": "started",
  273. "series": "quantal",
  274. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  275. "state-server-member-status": "adding-vote",
  276. },
  277. },
  278. "services": M{},
  279. },
  280. },
  281. ), test(
  282. "deploy two services and two networks",
  283. addMachine{machineId: "0", job: state.JobManageEnviron},
  284. startAliveMachine{"0"},
  285. setMachineStatus{"0", params.StatusStarted, ""},
  286. setAddresses{"0", []network.Address{
  287. network.NewAddress("10.0.0.1", network.ScopeUnknown),
  288. network.NewAddress("dummyenv-0.dns", network.ScopePublic),
  289. }},
  290. addCharm{"dummy"},
  291. addService{
  292. name: "networks-service",
  293. charm: "dummy",
  294. networks: []string{"net1", "net2"},
  295. cons: constraints.MustParse("networks=foo,bar,^no,^good"),
  296. },
  297. addService{
  298. name: "no-networks-service",
  299. charm: "dummy",
  300. cons: constraints.MustParse("networks=^mynet"),
  301. },
  302. addNetwork{
  303. name: "net1",
  304. providerId: network.Id("provider-net1"),
  305. cidr: "0.1.2.0/24",
  306. vlanTag: 0,
  307. },
  308. addNetwork{
  309. name: "net2",
  310. providerId: network.Id("provider-vlan42"),
  311. cidr: "0.42.1.0/24",
  312. vlanTag: 42,
  313. },
  314. expect{
  315. "simulate just the two services and a bootstrap node",
  316. M{
  317. "environment": "dummyenv",
  318. "machines": M{
  319. "0": machine0,
  320. },
  321. "services": M{
  322. "networks-service": M{
  323. "charm": "cs:quantal/dummy-1",
  324. "exposed": false,
  325. "networks": M{
  326. "enabled": L{"net1", "net2"},
  327. "disabled": L{"foo", "bar", "no", "good"},
  328. },
  329. },
  330. "no-networks-service": M{
  331. "charm": "cs:quantal/dummy-1",
  332. "exposed": false,
  333. "networks": M{
  334. "disabled": L{"mynet"},
  335. },
  336. },
  337. },
  338. "networks": M{
  339. "net1": M{
  340. "provider-id": "provider-net1",
  341. "cidr": "0.1.2.0/24",
  342. },
  343. "net2": M{
  344. "provider-id": "provider-vlan42",
  345. "cidr": "0.42.1.0/24",
  346. "vlan-tag": 42,
  347. },
  348. },
  349. },
  350. },
  351. ), test(
  352. "instance with different hardware characteristics",
  353. addMachine{machineId: "0", cons: machineCons, job: state.JobManageEnviron},
  354. setAddresses{"0", []network.Address{
  355. network.NewAddress("10.0.0.1", network.ScopeUnknown),
  356. network.NewAddress("dummyenv-0.dns", network.ScopePublic),
  357. }},
  358. startAliveMachine{"0"},
  359. setMachineStatus{"0", params.StatusStarted, ""},
  360. expect{
  361. "machine 0 has specific hardware characteristics",
  362. M{
  363. "environment": "dummyenv",
  364. "machines": M{
  365. "0": M{
  366. "agent-state": "started",
  367. "dns-name": "dummyenv-0.dns",
  368. "instance-id": "dummyenv-0",
  369. "series": "quantal",
  370. "hardware": "arch=amd64 cpu-cores=2 mem=8192M root-disk=8192M",
  371. "state-server-member-status": "adding-vote",
  372. },
  373. },
  374. "services": M{},
  375. },
  376. },
  377. ), test(
  378. "instance without addresses",
  379. addMachine{machineId: "0", cons: machineCons, job: state.JobManageEnviron},
  380. startAliveMachine{"0"},
  381. setMachineStatus{"0", params.StatusStarted, ""},
  382. expect{
  383. "machine 0 has no dns-name",
  384. M{
  385. "environment": "dummyenv",
  386. "machines": M{
  387. "0": M{
  388. "agent-state": "started",
  389. "instance-id": "dummyenv-0",
  390. "series": "quantal",
  391. "hardware": "arch=amd64 cpu-cores=2 mem=8192M root-disk=8192M",
  392. "state-server-member-status": "adding-vote",
  393. },
  394. },
  395. "services": M{},
  396. },
  397. },
  398. ), test(
  399. "test pending and missing machines",
  400. addMachine{machineId: "0", job: state.JobManageEnviron},
  401. expect{
  402. "machine 0 reports pending",
  403. M{
  404. "environment": "dummyenv",
  405. "machines": M{
  406. "0": M{
  407. "instance-id": "pending",
  408. "series": "quantal",
  409. "state-server-member-status": "adding-vote",
  410. },
  411. },
  412. "services": M{},
  413. },
  414. },
  415. startMissingMachine{"0"},
  416. expect{
  417. "machine 0 reports missing",
  418. M{
  419. "environment": "dummyenv",
  420. "machines": M{
  421. "0": M{
  422. "instance-state": "missing",
  423. "instance-id": "i-missing",
  424. "agent-state": "pending",
  425. "series": "quantal",
  426. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  427. "state-server-member-status": "adding-vote",
  428. },
  429. },
  430. "services": M{},
  431. },
  432. },
  433. ), test(
  434. "add two services and expose one, then add 2 more machines and some units",
  435. addMachine{machineId: "0", job: state.JobManageEnviron},
  436. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  437. startAliveMachine{"0"},
  438. setMachineStatus{"0", params.StatusStarted, ""},
  439. addCharm{"dummy"},
  440. addService{name: "dummy-service", charm: "dummy"},
  441. addService{name: "exposed-service", charm: "dummy"},
  442. expect{
  443. "no services exposed yet",
  444. M{
  445. "environment": "dummyenv",
  446. "machines": M{
  447. "0": machine0,
  448. },
  449. "services": M{
  450. "dummy-service": unexposedService,
  451. "exposed-service": unexposedService,
  452. },
  453. },
  454. },
  455. setServiceExposed{"exposed-service", true},
  456. expect{
  457. "one exposed service",
  458. M{
  459. "environment": "dummyenv",
  460. "machines": M{
  461. "0": machine0,
  462. },
  463. "services": M{
  464. "dummy-service": unexposedService,
  465. "exposed-service": exposedService,
  466. },
  467. },
  468. },
  469. addMachine{machineId: "1", job: state.JobHostUnits},
  470. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  471. startAliveMachine{"1"},
  472. setMachineStatus{"1", params.StatusStarted, ""},
  473. addMachine{machineId: "2", job: state.JobHostUnits},
  474. setAddresses{"2", []network.Address{network.NewAddress("dummyenv-2.dns", network.ScopeUnknown)}},
  475. startAliveMachine{"2"},
  476. setMachineStatus{"2", params.StatusStarted, ""},
  477. expect{
  478. "two more machines added",
  479. M{
  480. "environment": "dummyenv",
  481. "machines": M{
  482. "0": machine0,
  483. "1": machine1,
  484. "2": machine2,
  485. },
  486. "services": M{
  487. "dummy-service": unexposedService,
  488. "exposed-service": exposedService,
  489. },
  490. },
  491. },
  492. addUnit{"dummy-service", "1"},
  493. addAliveUnit{"exposed-service", "2"},
  494. setUnitStatus{"exposed-service/0", params.StatusError, "You Require More Vespene Gas"},
  495. // Open multiple ports with different protocols,
  496. // ensure they're sorted on protocol, then number.
  497. openUnitPort{"exposed-service/0", "udp", 10},
  498. openUnitPort{"exposed-service/0", "udp", 2},
  499. openUnitPort{"exposed-service/0", "tcp", 3},
  500. openUnitPort{"exposed-service/0", "tcp", 2},
  501. // Simulate some status with no info, while the agent is down.
  502. setUnitStatus{"dummy-service/0", params.StatusStarted, ""},
  503. expect{
  504. "add two units, one alive (in error state), one down",
  505. M{
  506. "environment": "dummyenv",
  507. "machines": M{
  508. "0": machine0,
  509. "1": machine1,
  510. "2": machine2,
  511. },
  512. "services": M{
  513. "exposed-service": M{
  514. "charm": "cs:quantal/dummy-1",
  515. "exposed": true,
  516. "units": M{
  517. "exposed-service/0": M{
  518. "machine": "2",
  519. "agent-state": "error",
  520. "agent-state-info": "You Require More Vespene Gas",
  521. "open-ports": L{
  522. "2/tcp", "3/tcp", "2/udp", "10/udp",
  523. },
  524. "public-address": "dummyenv-2.dns",
  525. },
  526. },
  527. },
  528. "dummy-service": M{
  529. "charm": "cs:quantal/dummy-1",
  530. "exposed": false,
  531. "units": M{
  532. "dummy-service/0": M{
  533. "machine": "1",
  534. "agent-state": "down",
  535. "agent-state-info": "(started)",
  536. "public-address": "dummyenv-1.dns",
  537. },
  538. },
  539. },
  540. },
  541. },
  542. },
  543. addMachine{machineId: "3", job: state.JobHostUnits},
  544. startMachine{"3"},
  545. // Simulate some status with info, while the agent is down.
  546. setAddresses{"3", []network.Address{network.NewAddress("dummyenv-3.dns", network.ScopeUnknown)}},
  547. setMachineStatus{"3", params.StatusStopped, "Really?"},
  548. addMachine{machineId: "4", job: state.JobHostUnits},
  549. setAddresses{"4", []network.Address{network.NewAddress("dummyenv-4.dns", network.ScopeUnknown)}},
  550. startAliveMachine{"4"},
  551. setMachineStatus{"4", params.StatusError, "Beware the red toys"},
  552. ensureDyingUnit{"dummy-service/0"},
  553. addMachine{machineId: "5", job: state.JobHostUnits},
  554. ensureDeadMachine{"5"},
  555. expect{
  556. "add three more machine, one with a dead agent, one in error state and one dead itself; also one dying unit",
  557. M{
  558. "environment": "dummyenv",
  559. "machines": M{
  560. "0": machine0,
  561. "1": machine1,
  562. "2": machine2,
  563. "3": M{
  564. "dns-name": "dummyenv-3.dns",
  565. "instance-id": "dummyenv-3",
  566. "agent-state": "down",
  567. "agent-state-info": "(stopped: Really?)",
  568. "series": "quantal",
  569. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  570. },
  571. "4": M{
  572. "dns-name": "dummyenv-4.dns",
  573. "instance-id": "dummyenv-4",
  574. "agent-state": "error",
  575. "agent-state-info": "Beware the red toys",
  576. "series": "quantal",
  577. "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
  578. },
  579. "5": M{
  580. "life": "dead",
  581. "instance-id": "pending",
  582. "series": "quantal",
  583. },
  584. },
  585. "services": M{
  586. "exposed-service": M{
  587. "charm": "cs:quantal/dummy-1",
  588. "exposed": true,
  589. "units": M{
  590. "exposed-service/0": M{
  591. "machine": "2",
  592. "agent-state": "error",
  593. "agent-state-info": "You Require More Vespene Gas",
  594. "open-ports": L{
  595. "2/tcp", "3/tcp", "2/udp", "10/udp",
  596. },
  597. "public-address": "dummyenv-2.dns",
  598. },
  599. },
  600. },
  601. "dummy-service": M{
  602. "charm": "cs:quantal/dummy-1",
  603. "exposed": false,
  604. "units": M{
  605. "dummy-service/0": M{
  606. "machine": "1",
  607. "life": "dying",
  608. "agent-state": "down",
  609. "agent-state-info": "(started)",
  610. "public-address": "dummyenv-1.dns",
  611. },
  612. },
  613. },
  614. },
  615. },
  616. },
  617. scopedExpect{
  618. "scope status on dummy-service/0 unit",
  619. []string{"dummy-service/0"},
  620. M{
  621. "environment": "dummyenv",
  622. "machines": M{
  623. "1": machine1,
  624. },
  625. "services": M{
  626. "dummy-service": M{
  627. "charm": "cs:quantal/dummy-1",
  628. "exposed": false,
  629. "units": M{
  630. "dummy-service/0": M{
  631. "machine": "1",
  632. "life": "dying",
  633. "agent-state": "down",
  634. "agent-state-info": "(started)",
  635. "public-address": "dummyenv-1.dns",
  636. },
  637. },
  638. },
  639. },
  640. },
  641. },
  642. scopedExpect{
  643. "scope status on exposed-service service",
  644. []string{"exposed-service"},
  645. M{
  646. "environment": "dummyenv",
  647. "machines": M{
  648. "2": machine2,
  649. },
  650. "services": M{
  651. "exposed-service": M{
  652. "charm": "cs:quantal/dummy-1",
  653. "exposed": true,
  654. "units": M{
  655. "exposed-service/0": M{
  656. "machine": "2",
  657. "agent-state": "error",
  658. "agent-state-info": "You Require More Vespene Gas",
  659. "open-ports": L{
  660. "2/tcp", "3/tcp", "2/udp", "10/udp",
  661. },
  662. "public-address": "dummyenv-2.dns",
  663. },
  664. },
  665. },
  666. },
  667. },
  668. },
  669. scopedExpect{
  670. "scope status on service pattern",
  671. []string{"d*-service"},
  672. M{
  673. "environment": "dummyenv",
  674. "machines": M{
  675. "1": machine1,
  676. },
  677. "services": M{
  678. "dummy-service": M{
  679. "charm": "cs:quantal/dummy-1",
  680. "exposed": false,
  681. "units": M{
  682. "dummy-service/0": M{
  683. "machine": "1",
  684. "life": "dying",
  685. "agent-state": "down",
  686. "agent-state-info": "(started)",
  687. "public-address": "dummyenv-1.dns",
  688. },
  689. },
  690. },
  691. },
  692. },
  693. },
  694. scopedExpect{
  695. "scope status on unit pattern",
  696. []string{"e*posed-service/*"},
  697. M{
  698. "environment": "dummyenv",
  699. "machines": M{
  700. "2": machine2,
  701. },
  702. "services": M{
  703. "exposed-service": M{
  704. "charm": "cs:quantal/dummy-1",
  705. "exposed": true,
  706. "units": M{
  707. "exposed-service/0": M{
  708. "machine": "2",
  709. "agent-state": "error",
  710. "agent-state-info": "You Require More Vespene Gas",
  711. "open-ports": L{
  712. "2/tcp", "3/tcp", "2/udp", "10/udp",
  713. },
  714. "public-address": "dummyenv-2.dns",
  715. },
  716. },
  717. },
  718. },
  719. },
  720. },
  721. scopedExpect{
  722. "scope status on combination of service and unit patterns",
  723. []string{"exposed-service", "dummy-service", "e*posed-service/*", "dummy-service/*"},
  724. M{
  725. "environment": "dummyenv",
  726. "machines": M{
  727. "1": machine1,
  728. "2": machine2,
  729. },
  730. "services": M{
  731. "dummy-service": M{
  732. "charm": "cs:quantal/dummy-1",
  733. "exposed": false,
  734. "units": M{
  735. "dummy-service/0": M{
  736. "machine": "1",
  737. "life": "dying",
  738. "agent-state": "down",
  739. "agent-state-info": "(started)",
  740. "public-address": "dummyenv-1.dns",
  741. },
  742. },
  743. },
  744. "exposed-service": M{
  745. "charm": "cs:quantal/dummy-1",
  746. "exposed": true,
  747. "units": M{
  748. "exposed-service/0": M{
  749. "machine": "2",
  750. "agent-state": "error",
  751. "agent-state-info": "You Require More Vespene Gas",
  752. "open-ports": L{
  753. "2/tcp", "3/tcp", "2/udp", "10/udp",
  754. },
  755. "public-address": "dummyenv-2.dns",
  756. },
  757. },
  758. },
  759. },
  760. },
  761. },
  762. ), test(
  763. "add a dying service",
  764. addCharm{"dummy"},
  765. addService{name: "dummy-service", charm: "dummy"},
  766. addMachine{machineId: "0", job: state.JobHostUnits},
  767. addUnit{"dummy-service", "0"},
  768. ensureDyingService{"dummy-service"},
  769. expect{
  770. "service shows life==dying",
  771. M{
  772. "environment": "dummyenv",
  773. "machines": M{
  774. "0": M{
  775. "instance-id": "pending",
  776. "series": "quantal",
  777. },
  778. },
  779. "services": M{
  780. "dummy-service": M{
  781. "charm": "cs:quantal/dummy-1",
  782. "exposed": false,
  783. "life": "dying",
  784. "units": M{
  785. "dummy-service/0": M{
  786. "machine": "0",
  787. "agent-state": "pending",
  788. },
  789. },
  790. },
  791. },
  792. },
  793. },
  794. ),
  795. // Relation tests
  796. test(
  797. "complex scenario with multiple related services",
  798. addMachine{machineId: "0", job: state.JobManageEnviron},
  799. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  800. startAliveMachine{"0"},
  801. setMachineStatus{"0", params.StatusStarted, ""},
  802. addCharm{"wordpress"},
  803. addCharm{"mysql"},
  804. addCharm{"varnish"},
  805. addService{name: "project", charm: "wordpress"},
  806. setServiceExposed{"project", true},
  807. addMachine{machineId: "1", job: state.JobHostUnits},
  808. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  809. startAliveMachine{"1"},
  810. setMachineStatus{"1", params.StatusStarted, ""},
  811. addAliveUnit{"project", "1"},
  812. setUnitStatus{"project/0", params.StatusStarted, ""},
  813. addService{name: "mysql", charm: "mysql"},
  814. setServiceExposed{"mysql", true},
  815. addMachine{machineId: "2", job: state.JobHostUnits},
  816. setAddresses{"2", []network.Address{network.NewAddress("dummyenv-2.dns", network.ScopeUnknown)}},
  817. startAliveMachine{"2"},
  818. setMachineStatus{"2", params.StatusStarted, ""},
  819. addAliveUnit{"mysql", "2"},
  820. setUnitStatus{"mysql/0", params.StatusStarted, ""},
  821. addService{name: "varnish", charm: "varnish"},
  822. setServiceExposed{"varnish", true},
  823. addMachine{machineId: "3", job: state.JobHostUnits},
  824. setAddresses{"3", []network.Address{network.NewAddress("dummyenv-3.dns", network.ScopeUnknown)}},
  825. startAliveMachine{"3"},
  826. setMachineStatus{"3", params.StatusStarted, ""},
  827. addUnit{"varnish", "3"},
  828. addService{name: "private", charm: "wordpress"},
  829. setServiceExposed{"private", true},
  830. addMachine{machineId: "4", job: state.JobHostUnits},
  831. setAddresses{"4", []network.Address{network.NewAddress("dummyenv-4.dns", network.ScopeUnknown)}},
  832. startAliveMachine{"4"},
  833. setMachineStatus{"4", params.StatusStarted, ""},
  834. addUnit{"private", "4"},
  835. relateServices{"project", "mysql"},
  836. relateServices{"project", "varnish"},
  837. relateServices{"private", "mysql"},
  838. expect{
  839. "multiples services with relations between some of them",
  840. M{
  841. "environment": "dummyenv",
  842. "machines": M{
  843. "0": machine0,
  844. "1": machine1,
  845. "2": machine2,
  846. "3": machine3,
  847. "4": machine4,
  848. },
  849. "services": M{
  850. "project": M{
  851. "charm": "cs:quantal/wordpress-3",
  852. "exposed": true,
  853. "units": M{
  854. "project/0": M{
  855. "machine": "1",
  856. "agent-state": "started",
  857. "public-address": "dummyenv-1.dns",
  858. },
  859. },
  860. "relations": M{
  861. "db": L{"mysql"},
  862. "cache": L{"varnish"},
  863. },
  864. },
  865. "mysql": M{
  866. "charm": "cs:quantal/mysql-1",
  867. "exposed": true,
  868. "units": M{
  869. "mysql/0": M{
  870. "machine": "2",
  871. "agent-state": "started",
  872. "public-address": "dummyenv-2.dns",
  873. },
  874. },
  875. "relations": M{
  876. "server": L{"private", "project"},
  877. },
  878. },
  879. "varnish": M{
  880. "charm": "cs:quantal/varnish-1",
  881. "exposed": true,
  882. "units": M{
  883. "varnish/0": M{
  884. "machine": "3",
  885. "agent-state": "pending",
  886. "public-address": "dummyenv-3.dns",
  887. },
  888. },
  889. "relations": M{
  890. "webcache": L{"project"},
  891. },
  892. },
  893. "private": M{
  894. "charm": "cs:quantal/wordpress-3",
  895. "exposed": true,
  896. "units": M{
  897. "private/0": M{
  898. "machine": "4",
  899. "agent-state": "pending",
  900. "public-address": "dummyenv-4.dns",
  901. },
  902. },
  903. "relations": M{
  904. "db": L{"mysql"},
  905. },
  906. },
  907. },
  908. },
  909. },
  910. ), test(
  911. "simple peer scenario",
  912. addMachine{machineId: "0", job: state.JobManageEnviron},
  913. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  914. startAliveMachine{"0"},
  915. setMachineStatus{"0", params.StatusStarted, ""},
  916. addCharm{"riak"},
  917. addCharm{"wordpress"},
  918. addService{name: "riak", charm: "riak"},
  919. setServiceExposed{"riak", true},
  920. addMachine{machineId: "1", job: state.JobHostUnits},
  921. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  922. startAliveMachine{"1"},
  923. setMachineStatus{"1", params.StatusStarted, ""},
  924. addAliveUnit{"riak", "1"},
  925. setUnitStatus{"riak/0", params.StatusStarted, ""},
  926. addMachine{machineId: "2", job: state.JobHostUnits},
  927. setAddresses{"2", []network.Address{network.NewAddress("dummyenv-2.dns", network.ScopeUnknown)}},
  928. startAliveMachine{"2"},
  929. setMachineStatus{"2", params.StatusStarted, ""},
  930. addAliveUnit{"riak", "2"},
  931. setUnitStatus{"riak/1", params.StatusStarted, ""},
  932. addMachine{machineId: "3", job: state.JobHostUnits},
  933. setAddresses{"3", []network.Address{network.NewAddress("dummyenv-3.dns", network.ScopeUnknown)}},
  934. startAliveMachine{"3"},
  935. setMachineStatus{"3", params.StatusStarted, ""},
  936. addAliveUnit{"riak", "3"},
  937. setUnitStatus{"riak/2", params.StatusStarted, ""},
  938. expect{
  939. "multiples related peer units",
  940. M{
  941. "environment": "dummyenv",
  942. "machines": M{
  943. "0": machine0,
  944. "1": machine1,
  945. "2": machine2,
  946. "3": machine3,
  947. },
  948. "services": M{
  949. "riak": M{
  950. "charm": "cs:quantal/riak-7",
  951. "exposed": true,
  952. "units": M{
  953. "riak/0": M{
  954. "machine": "1",
  955. "agent-state": "started",
  956. "public-address": "dummyenv-1.dns",
  957. },
  958. "riak/1": M{
  959. "machine": "2",
  960. "agent-state": "started",
  961. "public-address": "dummyenv-2.dns",
  962. },
  963. "riak/2": M{
  964. "machine": "3",
  965. "agent-state": "started",
  966. "public-address": "dummyenv-3.dns",
  967. },
  968. },
  969. "relations": M{
  970. "ring": L{"riak"},
  971. },
  972. },
  973. },
  974. },
  975. },
  976. ),
  977. // Subordinate tests
  978. test(
  979. "one service with one subordinate service",
  980. addMachine{machineId: "0", job: state.JobManageEnviron},
  981. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  982. startAliveMachine{"0"},
  983. setMachineStatus{"0", params.StatusStarted, ""},
  984. addCharm{"wordpress"},
  985. addCharm{"mysql"},
  986. addCharm{"logging"},
  987. addService{name: "wordpress", charm: "wordpress"},
  988. setServiceExposed{"wordpress", true},
  989. addMachine{machineId: "1", job: state.JobHostUnits},
  990. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  991. startAliveMachine{"1"},
  992. setMachineStatus{"1", params.StatusStarted, ""},
  993. addAliveUnit{"wordpress", "1"},
  994. setUnitStatus{"wordpress/0", params.StatusStarted, ""},
  995. addService{name: "mysql", charm: "mysql"},
  996. setServiceExposed{"mysql", true},
  997. addMachine{machineId: "2", job: state.JobHostUnits},
  998. setAddresses{"2", []network.Address{network.NewAddress("dummyenv-2.dns", network.ScopeUnknown)}},
  999. startAliveMachine{"2"},
  1000. setMachineStatus{"2", params.StatusStarted, ""},
  1001. addAliveUnit{"mysql", "2"},
  1002. setUnitStatus{"mysql/0", params.StatusStarted, ""},
  1003. addService{name: "logging", charm: "logging"},
  1004. setServiceExposed{"logging", true},
  1005. relateServices{"wordpress", "mysql"},
  1006. relateServices{"wordpress", "logging"},
  1007. relateServices{"mysql", "logging"},
  1008. addSubordinate{"wordpress/0", "logging"},
  1009. addSubordinate{"mysql/0", "logging"},
  1010. setUnitsAlive{"logging"},
  1011. setUnitStatus{"logging/0", params.StatusStarted, ""},
  1012. setUnitStatus{"logging/1", params.StatusError, "somehow lost in all those logs"},
  1013. expect{
  1014. "multiples related peer units",
  1015. M{
  1016. "environment": "dummyenv",
  1017. "machines": M{
  1018. "0": machine0,
  1019. "1": machine1,
  1020. "2": machine2,
  1021. },
  1022. "services": M{
  1023. "wordpress": M{
  1024. "charm": "cs:quantal/wordpress-3",
  1025. "exposed": true,
  1026. "units": M{
  1027. "wordpress/0": M{
  1028. "machine": "1",
  1029. "agent-state": "started",
  1030. "subordinates": M{
  1031. "logging/0": M{
  1032. "agent-state": "started",
  1033. "public-address": "dummyenv-1.dns",
  1034. },
  1035. },
  1036. "public-address": "dummyenv-1.dns",
  1037. },
  1038. },
  1039. "relations": M{
  1040. "db": L{"mysql"},
  1041. "logging-dir": L{"logging"},
  1042. },
  1043. },
  1044. "mysql": M{
  1045. "charm": "cs:quantal/mysql-1",
  1046. "exposed": true,
  1047. "units": M{
  1048. "mysql/0": M{
  1049. "machine": "2",
  1050. "agent-state": "started",
  1051. "subordinates": M{
  1052. "logging/1": M{
  1053. "agent-state": "error",
  1054. "agent-state-info": "somehow lost in all those logs",
  1055. "public-address": "dummyenv-2.dns",
  1056. },
  1057. },
  1058. "public-address": "dummyenv-2.dns",
  1059. },
  1060. },
  1061. "relations": M{
  1062. "server": L{"wordpress"},
  1063. "juju-info": L{"logging"},
  1064. },
  1065. },
  1066. "logging": M{
  1067. "charm": "cs:quantal/logging-1",
  1068. "exposed": true,
  1069. "relations": M{
  1070. "logging-directory": L{"wordpress"},
  1071. "info": L{"mysql"},
  1072. },
  1073. "subordinate-to": L{"mysql", "wordpress"},
  1074. },
  1075. },
  1076. },
  1077. },
  1078. // scoped on 'logging'
  1079. scopedExpect{
  1080. "subordinates scoped on logging",
  1081. []string{"logging"},
  1082. M{
  1083. "environment": "dummyenv",
  1084. "machines": M{
  1085. "1": machine1,
  1086. "2": machine2,
  1087. },
  1088. "services": M{
  1089. "wordpress": M{
  1090. "charm": "cs:quantal/wordpress-3",
  1091. "exposed": true,
  1092. "units": M{
  1093. "wordpress/0": M{
  1094. "machine": "1",
  1095. "agent-state": "started",
  1096. "subordinates": M{
  1097. "logging/0": M{
  1098. "agent-state": "started",
  1099. "public-address": "dummyenv-1.dns",
  1100. },
  1101. },
  1102. "public-address": "dummyenv-1.dns",
  1103. },
  1104. },
  1105. "relations": M{
  1106. "db": L{"mysql"},
  1107. "logging-dir": L{"logging"},
  1108. },
  1109. },
  1110. "mysql": M{
  1111. "charm": "cs:quantal/mysql-1",
  1112. "exposed": true,
  1113. "units": M{
  1114. "mysql/0": M{
  1115. "machine": "2",
  1116. "agent-state": "started",
  1117. "subordinates": M{
  1118. "logging/1": M{
  1119. "agent-state": "error",
  1120. "agent-state-info": "somehow lost in all those logs",
  1121. "public-address": "dummyenv-2.dns",
  1122. },
  1123. },
  1124. "public-address": "dummyenv-2.dns",
  1125. },
  1126. },
  1127. "relations": M{
  1128. "server": L{"wordpress"},
  1129. "juju-info": L{"logging"},
  1130. },
  1131. },
  1132. "logging": M{
  1133. "charm": "cs:quantal/logging-1",
  1134. "exposed": true,
  1135. "relations": M{
  1136. "logging-directory": L{"wordpress"},
  1137. "info": L{"mysql"},
  1138. },
  1139. "subordinate-to": L{"mysql", "wordpress"},
  1140. },
  1141. },
  1142. },
  1143. },
  1144. // scoped on wordpress/0
  1145. scopedExpect{
  1146. "subordinates scoped on logging",
  1147. []string{"wordpress/0"},
  1148. M{
  1149. "environment": "dummyenv",
  1150. "machines": M{
  1151. "1": machine1,
  1152. },
  1153. "services": M{
  1154. "wordpress": M{
  1155. "charm": "cs:quantal/wordpress-3",
  1156. "exposed": true,
  1157. "units": M{
  1158. "wordpress/0": M{
  1159. "machine": "1",
  1160. "agent-state": "started",
  1161. "subordinates": M{
  1162. "logging/0": M{
  1163. "agent-state": "started",
  1164. "public-address": "dummyenv-1.dns",
  1165. },
  1166. },
  1167. "public-address": "dummyenv-1.dns",
  1168. },
  1169. },
  1170. "relations": M{
  1171. "db": L{"mysql"},
  1172. "logging-dir": L{"logging"},
  1173. },
  1174. },
  1175. "logging": M{
  1176. "charm": "cs:quantal/logging-1",
  1177. "exposed": true,
  1178. "relations": M{
  1179. "logging-directory": L{"wordpress"},
  1180. "info": L{"mysql"},
  1181. },
  1182. "subordinate-to": L{"mysql", "wordpress"},
  1183. },
  1184. },
  1185. },
  1186. },
  1187. ), test(
  1188. "one service with two subordinate services",
  1189. addMachine{machineId: "0", job: state.JobManageEnviron},
  1190. startAliveMachine{"0"},
  1191. setMachineStatus{"0", params.StatusStarted, ""},
  1192. addCharm{"wordpress"},
  1193. addCharm{"logging"},
  1194. addCharm{"monitoring"},
  1195. addService{name: "wordpress", charm: "wordpress"},
  1196. setServiceExposed{"wordpress", true},
  1197. addMachine{machineId: "1", job: state.JobHostUnits},
  1198. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  1199. startAliveMachine{"1"},
  1200. setMachineStatus{"1", params.StatusStarted, ""},
  1201. addAliveUnit{"wordpress", "1"},
  1202. setUnitStatus{"wordpress/0", params.StatusStarted, ""},
  1203. addService{name: "logging", charm: "logging"},
  1204. setServiceExposed{"logging", true},
  1205. addService{name: "monitoring", charm: "monitoring"},
  1206. setServiceExposed{"monitoring", true},
  1207. relateServices{"wordpress", "logging"},
  1208. relateServices{"wordpress", "monitoring"},
  1209. addSubordinate{"wordpress/0", "logging"},
  1210. addSubordinate{"wordpress/0", "monitoring"},
  1211. setUnitsAlive{"logging"},
  1212. setUnitStatus{"logging/0", params.StatusStarted, ""},
  1213. setUnitsAlive{"monitoring"},
  1214. setUnitStatus{"monitoring/0", params.StatusStarted, ""},
  1215. // scoped on monitoring; make sure logging doesn't show up.
  1216. scopedExpect{
  1217. "subordinates scoped on:",
  1218. []string{"monitoring"},
  1219. M{
  1220. "environment": "dummyenv",
  1221. "machines": M{
  1222. "1": machine1,
  1223. },
  1224. "services": M{
  1225. "wordpress": M{
  1226. "charm": "cs:quantal/wordpress-3",
  1227. "exposed": true,
  1228. "units": M{
  1229. "wordpress/0": M{
  1230. "machine": "1",
  1231. "agent-state": "started",
  1232. "subordinates": M{
  1233. "monitoring/0": M{
  1234. "agent-state": "started",
  1235. "public-address": "dummyenv-1.dns",
  1236. },
  1237. },
  1238. "public-address": "dummyenv-1.dns",
  1239. },
  1240. },
  1241. "relations": M{
  1242. "logging-dir": L{"logging"},
  1243. "monitoring-port": L{"monitoring"},
  1244. },
  1245. },
  1246. "monitoring": M{
  1247. "charm": "cs:quantal/monitoring-0",
  1248. "exposed": true,
  1249. "relations": M{
  1250. "monitoring-port": L{"wordpress"},
  1251. },
  1252. "subordinate-to": L{"wordpress"},
  1253. },
  1254. },
  1255. },
  1256. },
  1257. ), test(
  1258. "machines with containers",
  1259. addMachine{machineId: "0", job: state.JobManageEnviron},
  1260. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  1261. startAliveMachine{"0"},
  1262. setMachineStatus{"0", params.StatusStarted, ""},
  1263. addCharm{"mysql"},
  1264. addService{name: "mysql", charm: "mysql"},
  1265. setServiceExposed{"mysql", true},
  1266. addMachine{machineId: "1", job: state.JobHostUnits},
  1267. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  1268. startAliveMachine{"1"},
  1269. setMachineStatus{"1", params.StatusStarted, ""},
  1270. addAliveUnit{"mysql", "1"},
  1271. setUnitStatus{"mysql/0", params.StatusStarted, ""},
  1272. // A container on machine 1.
  1273. addContainer{"1", "1/lxc/0", state.JobHostUnits},
  1274. setAddresses{"1/lxc/0", []network.Address{network.NewAddress("dummyenv-2.dns", network.ScopeUnknown)}},
  1275. startAliveMachine{"1/lxc/0"},
  1276. setMachineStatus{"1/lxc/0", params.StatusStarted, ""},
  1277. addAliveUnit{"mysql", "1/lxc/0"},
  1278. setUnitStatus{"mysql/1", params.StatusStarted, ""},
  1279. addContainer{"1", "1/lxc/1", state.JobHostUnits},
  1280. // A nested container.
  1281. addContainer{"1/lxc/0", "1/lxc/0/lxc/0", state.JobHostUnits},
  1282. setAddresses{"1/lxc/0/lxc/0", []network.Address{network.NewAddress("dummyenv-3.dns", network.ScopeUnknown)}},
  1283. startAliveMachine{"1/lxc/0/lxc/0"},
  1284. setMachineStatus{"1/lxc/0/lxc/0", params.StatusStarted, ""},
  1285. expect{
  1286. "machines with nested containers",
  1287. M{
  1288. "environment": "dummyenv",
  1289. "machines": M{
  1290. "0": machine0,
  1291. "1": machine1WithContainers,
  1292. },
  1293. "services": M{
  1294. "mysql": M{
  1295. "charm": "cs:quantal/mysql-1",
  1296. "exposed": true,
  1297. "units": M{
  1298. "mysql/0": M{
  1299. "machine": "1",
  1300. "agent-state": "started",
  1301. "public-address": "dummyenv-1.dns",
  1302. },
  1303. "mysql/1": M{
  1304. "machine": "1/lxc/0",
  1305. "agent-state": "started",
  1306. "public-address": "dummyenv-2.dns",
  1307. },
  1308. },
  1309. },
  1310. },
  1311. },
  1312. },
  1313. // once again, with a scope on mysql/1
  1314. scopedExpect{
  1315. "machines with nested containers",
  1316. []string{"mysql/1"},
  1317. M{
  1318. "environment": "dummyenv",
  1319. "machines": M{
  1320. "1": machine1WithContainersScoped,
  1321. },
  1322. "services": M{
  1323. "mysql": M{
  1324. "charm": "cs:quantal/mysql-1",
  1325. "exposed": true,
  1326. "units": M{
  1327. "mysql/1": M{
  1328. "machine": "1/lxc/0",
  1329. "agent-state": "started",
  1330. "public-address": "dummyenv-2.dns",
  1331. },
  1332. },
  1333. },
  1334. },
  1335. },
  1336. },
  1337. ), test(
  1338. "service with out of date charm",
  1339. addMachine{machineId: "0", job: state.JobManageEnviron},
  1340. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  1341. startAliveMachine{"0"},
  1342. setMachineStatus{"0", params.StatusStarted, ""},
  1343. addMachine{machineId: "1", job: state.JobHostUnits},
  1344. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  1345. startAliveMachine{"1"},
  1346. setMachineStatus{"1", params.StatusStarted, ""},
  1347. addCharm{"mysql"},
  1348. addService{name: "mysql", charm: "mysql"},
  1349. setServiceExposed{"mysql", true},
  1350. addCharmPlaceholder{"mysql", 23},
  1351. addAliveUnit{"mysql", "1"},
  1352. expect{
  1353. "services and units with correct charm status",
  1354. M{
  1355. "environment": "dummyenv",
  1356. "machines": M{
  1357. "0": machine0,
  1358. "1": machine1,
  1359. },
  1360. "services": M{
  1361. "mysql": M{
  1362. "charm": "cs:quantal/mysql-1",
  1363. "can-upgrade-to": "cs:quantal/mysql-23",
  1364. "exposed": true,
  1365. "units": M{
  1366. "mysql/0": M{
  1367. "machine": "1",
  1368. "agent-state": "pending",
  1369. "public-address": "dummyenv-1.dns",
  1370. },
  1371. },
  1372. },
  1373. },
  1374. },
  1375. },
  1376. ), test(
  1377. "unit with out of date charm",
  1378. addMachine{machineId: "0", job: state.JobManageEnviron},
  1379. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  1380. startAliveMachine{"0"},
  1381. setMachineStatus{"0", params.StatusStarted, ""},
  1382. addMachine{machineId: "1", job: state.JobHostUnits},
  1383. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  1384. startAliveMachine{"1"},
  1385. setMachineStatus{"1", params.StatusStarted, ""},
  1386. addCharm{"mysql"},
  1387. addService{name: "mysql", charm: "mysql"},
  1388. setServiceExposed{"mysql", true},
  1389. addAliveUnit{"mysql", "1"},
  1390. setUnitCharmURL{"mysql/0", "cs:quantal/mysql-1"},
  1391. addCharmWithRevision{addCharm{"mysql"}, "local", 1},
  1392. setServiceCharm{"mysql", "local:quantal/mysql-1"},
  1393. expect{
  1394. "services and units with correct charm status",
  1395. M{
  1396. "environment": "dummyenv",
  1397. "machines": M{
  1398. "0": machine0,
  1399. "1": machine1,
  1400. },
  1401. "services": M{
  1402. "mysql": M{
  1403. "charm": "local:quantal/mysql-1",
  1404. "exposed": true,
  1405. "units": M{
  1406. "mysql/0": M{
  1407. "machine": "1",
  1408. "agent-state": "started",
  1409. "upgrading-from": "cs:quantal/mysql-1",
  1410. "public-address": "dummyenv-1.dns",
  1411. },
  1412. },
  1413. },
  1414. },
  1415. },
  1416. },
  1417. ), test(
  1418. "service and unit with out of date charms",
  1419. addMachine{machineId: "0", job: state.JobManageEnviron},
  1420. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  1421. startAliveMachine{"0"},
  1422. setMachineStatus{"0", params.StatusStarted, ""},
  1423. addMachine{machineId: "1", job: state.JobHostUnits},
  1424. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  1425. startAliveMachine{"1"},
  1426. setMachineStatus{"1", params.StatusStarted, ""},
  1427. addCharm{"mysql"},
  1428. addService{name: "mysql", charm: "mysql"},
  1429. setServiceExposed{"mysql", true},
  1430. addAliveUnit{"mysql", "1"},
  1431. setUnitCharmURL{"mysql/0", "cs:quantal/mysql-1"},
  1432. addCharmWithRevision{addCharm{"mysql"}, "cs", 2},
  1433. setServiceCharm{"mysql", "cs:quantal/mysql-2"},
  1434. addCharmPlaceholder{"mysql", 23},
  1435. expect{
  1436. "services and units with correct charm status",
  1437. M{
  1438. "environment": "dummyenv",
  1439. "machines": M{
  1440. "0": machine0,
  1441. "1": machine1,
  1442. },
  1443. "services": M{
  1444. "mysql": M{
  1445. "charm": "cs:quantal/mysql-2",
  1446. "can-upgrade-to": "cs:quantal/mysql-23",
  1447. "exposed": true,
  1448. "units": M{
  1449. "mysql/0": M{
  1450. "machine": "1",
  1451. "agent-state": "started",
  1452. "upgrading-from": "cs:quantal/mysql-1",
  1453. "public-address": "dummyenv-1.dns",
  1454. },
  1455. },
  1456. },
  1457. },
  1458. },
  1459. },
  1460. ), test(
  1461. "service with local charm not shown as out of date",
  1462. addMachine{machineId: "0", job: state.JobManageEnviron},
  1463. setAddresses{"0", []network.Address{network.NewAddress("dummyenv-0.dns", network.ScopeUnknown)}},
  1464. startAliveMachine{"0"},
  1465. setMachineStatus{"0", params.StatusStarted, ""},
  1466. addMachine{machineId: "1", job: state.JobHostUnits},
  1467. setAddresses{"1", []network.Address{network.NewAddress("dummyenv-1.dns", network.ScopeUnknown)}},
  1468. startAliveMachine{"1"},
  1469. setMachineStatus{"1", params.StatusStarted, ""},
  1470. addCharm{"mysql"},
  1471. addService{name: "mysql", charm: "mysql"},
  1472. setServiceExposed{"mysql", true},
  1473. addAliveUnit{"mysql", "1"},
  1474. setUnitCharmURL{"mysql/0", "cs:quantal/mysql-1"},
  1475. addCharmWithRevision{addCharm{"mysql"}, "local", 1},
  1476. setServiceCharm{"mysql", "local:quantal/mysql-1"},
  1477. addCharmPlaceholder{"mysql", 23},
  1478. expect{
  1479. "services and units with correct charm status",
  1480. M{
  1481. "environment": "dummyenv",
  1482. "machines": M{
  1483. "0": machine0,
  1484. "1": machine1,
  1485. },
  1486. "services": M{
  1487. "mysql": M{
  1488. "charm": "local:quantal/mysql-1",
  1489. "exposed": true,
  1490. "units": M{
  1491. "mysql/0": M{
  1492. "machine": "1",
  1493. "agent-state": "started",
  1494. "upgrading-from": "cs:quantal/mysql-1",
  1495. "public-address": "dummyenv-1.dns",
  1496. },
  1497. },
  1498. },
  1499. },
  1500. },
  1501. },
  1502. ),
  1503. }
  1504. // TODO(dfc) test failing components by destructively mutating the state under the hood
  1505. type addMachine struct {
  1506. machineId string
  1507. cons constraints.Value
  1508. job state.MachineJob
  1509. }
  1510. func (am addMachine) step(c *gc.C, ctx *context) {
  1511. m, err := ctx.st.AddOneMachine(state.MachineTemplate{
  1512. Series: "quantal",
  1513. Constraints: am.cons,
  1514. Jobs: []state.MachineJob{am.job},
  1515. })
  1516. c.Assert(err, gc.IsNil)
  1517. c.Assert(m.Id(), gc.Equals, am.machineId)
  1518. }
  1519. type addNetwork struct {
  1520. name string
  1521. providerId network.Id
  1522. cidr string
  1523. vlanTag int
  1524. }
  1525. func (an addNetwork) step(c *gc.C, ctx *context) {
  1526. n, err := ctx.st.AddNetwork(state.NetworkInfo{
  1527. Name: an.name,
  1528. ProviderId: an.providerId,
  1529. CIDR: an.cidr,
  1530. VLANTag: an.vlanTag,
  1531. })
  1532. c.Assert(err, gc.IsNil)
  1533. c.Assert(n.Name(), gc.Equals, an.name)
  1534. }
  1535. type addContainer struct {
  1536. parentId string
  1537. machineId string
  1538. job state.MachineJob
  1539. }
  1540. func (ac addContainer) step(c *gc.C, ctx *context) {
  1541. template := state.MachineTemplate{
  1542. Series: "quantal",
  1543. Jobs: []state.MachineJob{ac.job},
  1544. }
  1545. m, err := ctx.st.AddMachineInsideMachine(template, ac.parentId, instance.LXC)
  1546. c.Assert(err, gc.IsNil)
  1547. c.Assert(m.Id(), gc.Equals, ac.machineId)
  1548. }
  1549. type startMachine struct {
  1550. machineId string
  1551. }
  1552. func (sm startMachine) step(c *gc.C, ctx *context) {
  1553. m, err := ctx.st.Machine(sm.machineId)
  1554. c.Assert(err, gc.IsNil)
  1555. cons, err := m.Constraints()
  1556. c.Assert(err, gc.IsNil)
  1557. inst, hc := testing.AssertStartInstanceWithConstraints(c, ctx.conn.Environ, m.Id(), cons)
  1558. err = m.SetProvisioned(inst.Id(), "fake_nonce", hc)
  1559. c.Assert(err, gc.IsNil)
  1560. }
  1561. type startMissingMachine struct {
  1562. machineId string
  1563. }
  1564. func (sm startMissingMachine) step(c *gc.C, ctx *context) {
  1565. m, err := ctx.st.Machine(sm.machineId)
  1566. c.Assert(err, gc.IsNil)
  1567. cons, err := m.Constraints()
  1568. c.Assert(err, gc.IsNil)
  1569. _, hc := testing.AssertStartInstanceWithConstraints(c, ctx.conn.Environ, m.Id(), cons)
  1570. err = m.SetProvisioned("i-missing", "fake_nonce", hc)
  1571. c.Assert(err, gc.IsNil)
  1572. err = m.SetInstanceStatus("missing")
  1573. c.Assert(err, gc.IsNil)
  1574. }
  1575. type startAliveMachine struct {
  1576. machineId string
  1577. }
  1578. func (sam startAliveMachine) step(c *gc.C, ctx *context) {
  1579. m, err := ctx.st.Machine(sam.machineId)
  1580. c.Assert(err, gc.IsNil)
  1581. pinger := ctx.setAgentAlive(c, m)
  1582. cons, err := m.Constraints()
  1583. c.Assert(err, gc.IsNil)
  1584. inst, hc := testing.AssertStartInstanceWithConstraints(c, ctx.conn.Environ, m.Id(), cons)
  1585. err = m.SetProvisioned(inst.Id(), "fake_nonce", hc)
  1586. c.Assert(err, gc.IsNil)
  1587. ctx.pingers[m.Id()] = pinger
  1588. }
  1589. type setAddresses struct {
  1590. machineId string
  1591. addresses []network.Address
  1592. }
  1593. func (sa setAddresses) step(c *gc.C, ctx *context) {
  1594. m, err := ctx.st.Machine(sa.machineId)
  1595. c.Assert(err, gc.IsNil)
  1596. err = m.SetAddresses(sa.addresses...)
  1597. c.Assert(err, gc.IsNil)
  1598. }
  1599. type setTools struct {
  1600. machineId string
  1601. version version.Binary
  1602. }
  1603. func (st setTools) step(c *gc.C, ctx *context) {
  1604. m, err := ctx.st.Machine(st.machineId)
  1605. c.Assert(err, gc.IsNil)
  1606. err = m.SetAgentVersion(st.version)
  1607. c.Assert(err, gc.IsNil)
  1608. }
  1609. type addCharm struct {
  1610. name string
  1611. }
  1612. func (ac addCharm) addCharmStep(c *gc.C, ctx *context, scheme string, rev int) {
  1613. ch := charmtesting.Charms.Dir(ac.name)
  1614. name := ch.Meta().Name
  1615. curl := charm.MustParseURL(fmt.Sprintf("%s:quantal/%s-%d", scheme, name, rev))
  1616. bundleURL, err := url.Parse(fmt.Sprintf("http://bundles.testing.invalid/%s-%d", name, rev))
  1617. c.Assert(err, gc.IsNil)
  1618. dummy, err := ctx.st.AddCharm(ch, curl, bundleURL, fmt.Sprintf("%s-%d-sha256", name, rev))
  1619. c.Assert(err, gc.IsNil)
  1620. ctx.charms[ac.name] = dummy
  1621. }
  1622. func (ac addCharm) step(c *gc.C, ctx *context) {
  1623. ch := charmtesting.Charms.Dir(ac.name)
  1624. ac.addCharmStep(c, ctx, "cs", ch.Revision())
  1625. }
  1626. type addCharmWithRevision struct {
  1627. addCharm
  1628. scheme string
  1629. rev int
  1630. }
  1631. func (ac addCharmWithRevision) step(c *gc.C, ctx *context) {
  1632. ac.addCharmStep(c, ctx, ac.scheme, ac.rev)
  1633. }
  1634. type addService struct {
  1635. name string
  1636. charm string
  1637. networks []string
  1638. cons constraints.Value
  1639. }
  1640. func (as addService) step(c *gc.C, ctx *context) {
  1641. ch, ok := ctx.charms[as.charm]
  1642. c.Assert(ok, gc.Equals, true)
  1643. svc, err := ctx.st.AddService(as.name, "user-admin", ch, as.networks)
  1644. c.Assert(err, gc.IsNil)
  1645. if svc.IsPrincipal() {
  1646. err = svc.SetConstraints(as.cons)
  1647. c.Assert(err, gc.IsNil)
  1648. }
  1649. }
  1650. type setServiceExposed struct {
  1651. name string
  1652. exposed bool
  1653. }
  1654. func (sse setServiceExposed) step(c *gc.C, ctx *context) {
  1655. s, err := ctx.st.Service(sse.name)
  1656. c.Assert(err, gc.IsNil)
  1657. if sse.exposed {
  1658. err = s.SetExposed()
  1659. c.Assert(err, gc.IsNil)
  1660. }
  1661. }
  1662. type setServiceCharm struct {
  1663. name string
  1664. charm string
  1665. }
  1666. func (ssc setServiceCharm) step(c *gc.C, ctx *context) {
  1667. ch, err := ctx.st.Charm(charm.MustParseURL(ssc.charm))
  1668. c.Assert(err, gc.IsNil)
  1669. s, err := ctx.st.Service(ssc.name)
  1670. c.Assert(err, gc.IsNil)
  1671. err = s.SetCharm(ch, false)
  1672. c.Assert(err, gc.IsNil)
  1673. }
  1674. type addCharmPlaceholder struct {
  1675. name string
  1676. rev int
  1677. }
  1678. func (ac addCharmPlaceholder) step(c *gc.C, ctx *context) {
  1679. ch := charmtesting.Charms.Dir(ac.name)
  1680. name := ch.Meta().Name
  1681. curl := charm.MustParseURL(fmt.Sprintf("cs:quantal/%s-%d", name, ac.rev))
  1682. err := ctx.st.AddStoreCharmPlaceholder(curl)
  1683. c.Assert(err, gc.IsNil)
  1684. }
  1685. type addUnit struct {
  1686. serviceName string
  1687. machineId string
  1688. }
  1689. func (au addUnit) step(c *gc.C, ctx *context) {
  1690. s, err := ctx.st.Service(au.serviceName)
  1691. c.Assert(err, gc.IsNil)
  1692. u, err := s.AddUnit()
  1693. c.Assert(err, gc.IsNil)
  1694. m, err := ctx.st.Machine(au.machineId)
  1695. c.Assert(err, gc.IsNil)
  1696. err = u.AssignToMachine(m)
  1697. c.Assert(err, gc.IsNil)
  1698. }
  1699. type addAliveUnit struct {
  1700. serviceName string
  1701. machineId string
  1702. }
  1703. func (aau addAliveUnit) step(c *gc.C, ctx *context) {
  1704. s, err := ctx.st.Service(aau.serviceName)
  1705. c.Assert(err, gc.IsNil)
  1706. u, err := s.AddUnit()
  1707. c.Assert(err, gc.IsNil)
  1708. pinger := ctx.setAgentAlive(c, u)
  1709. m, err := ctx.st.Machine(aau.machineId)
  1710. c.Assert(err, gc.IsNil)
  1711. err = u.AssignToMachine(m)
  1712. c.Assert(err, gc.IsNil)
  1713. ctx.pingers[u.Name()] = pinger
  1714. }
  1715. type setUnitsAlive struct {
  1716. serviceName string
  1717. }
  1718. func (sua setUnitsAlive) step(c *gc.C, ctx *context) {
  1719. s, err := ctx.st.Service(sua.serviceName)
  1720. c.Assert(err, gc.IsNil)
  1721. us, err := s.AllUnits()
  1722. c.Assert(err, gc.IsNil)
  1723. for _, u := range us {
  1724. ctx.pingers[u.Name()] = ctx.se

Large files files are truncated, but you can click here to view the full file