Merge lp:~axwalk/juju-core/cmdapi-ensureavailability into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2507
Proposed branch: lp:~axwalk/juju-core/cmdapi-ensureavailability
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 343 lines (+288/-0)
7 files modified
cmd/juju/ensureavailability.go (+81/-0)
cmd/juju/ensureavailability_test.go (+114/-0)
cmd/juju/main.go (+4/-0)
state/api/client.go (+10/-0)
state/api/params/params.go (+10/-0)
state/apiserver/client/client.go (+13/-0)
state/apiserver/client/client_test.go (+56/-0)
To merge this branch: bzr merge lp:~axwalk/juju-core/cmdapi-ensureavailability
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+213190@code.launchpad.net

Commit message

Add ensure-availability command, EnsureAvailability API

We introduce a new ensure-availability juju subcommand, which
calls the new EnsureAvailability client API. This
is the CLI for ensuring high availability of Juju
state servers.

Note: I have not exposed the ensure-availability command yet,
as there is still work to be done in the agents to
properly support HA state servers.

https://codereview.appspot.com/81700043/

Description of the change

ensure-availability command

We introduce a new ensure-availability juju subcommand,
which calls the new EnsureAvailability client API. This
is the CLI for ensuring high availability of Juju
state servers.

Note: I have not exposed the ensure-availability command yet,
as there is still work to be done in the agents to
properly support HA state servers.

https://codereview.appspot.com/81700043/

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

Reviewers: mp+213190_code.launchpad.net,

Message:
Please take a look.

Description:
Add ensure-ha command, EnsureAvailability API

We introduce a new ensure-ha juju subcommand, which
calls the new EnsureAvailability client API. This
is the CLI for ensuring high availability of Juju
state servers.

Note: I have not exposed the ensure-ha command yet,
as there is still work to be done in the agents to
properly support HA state servers.

https://code.launchpad.net/~axwalk/juju-core/cmdapi-ensureavailability/+merge/213190

(do not edit description out of merge proposal)

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

Affected files (+301, -0 lines):
   A [revision details]
   A cmd/juju/ensureha.go
   A cmd/juju/ensureha_test.go
   M cmd/juju/main.go
   M state/api/client.go
   M state/api/params/params.go
   M state/apiserver/client/client.go
   M state/apiserver/client/client_test.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :

LGTM modulo the below, thanks!

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go
File cmd/juju/ensureha.go (right):

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode19
cmd/juju/ensureha.go:19: // If specified, use this series, else use the
environment default-series
use this series for newly started instances ?

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode50
cmd/juju/ensureha.go:50: Name: "ensure-ha",
I'm not sure about "ha" in lower case - it looks too much like a word.
I'm thinking that either we make it into a proper word ("availability")
or we capitalise the ha - ensure-HA, thus making it clearer that it's an
acronym.

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode58
cmd/juju/ensureha.go:58: f.IntVar(&c.NumStateServers, "n", 1, "number of
state servers to make available")
Thought for the future - it would be good to be able to run "juju
ensure-HA" without any arguments at all, for when we just want to
maintain the current availability. Perhaps rather than defaulting to 1,
we should default to -1 and complain if it's not specified. That way we
leave that path open.

https://codereview.appspot.com/81700043/diff/1/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/81700043/diff/1/state/api/client.go#newcode680
state/api/client.go:680: } else if err := result.Error; err != nil {
There's no point in having an Error in the result as well as an error
return.

https://codereview.appspot.com/81700043/diff/1/state/api/params/params.go
File state/api/params/params.go (right):

https://codereview.appspot.com/81700043/diff/1/state/api/params/params.go#newcode649
state/api/params/params.go:649: Error *Error
d

https://codereview.appspot.com/81700043/diff/1/state/apiserver/client/client.go
File state/apiserver/client/client.go (right):

https://codereview.appspot.com/81700043/diff/1/state/apiserver/client/client.go#newcode990
state/apiserver/client/client.go:990: if err :=
c.api.state.EnsureAvailability(args.NumStateServers, args.Constraints,
series); err != nil {
err := c.api.state.EnsureAvailability(args.NumStateServers,
args.Constraints, series)
return params.EnsureAvailabilityResult{}, err

https://codereview.appspot.com/81700043/

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

Please take a look.

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go
File cmd/juju/ensureha.go (right):

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode19
cmd/juju/ensureha.go:19: // If specified, use this series, else use the
environment default-series
On 2014/03/28 07:54:23, rog wrote:
> use this series for newly started instances ?

Done.

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode50
cmd/juju/ensureha.go:50: Name: "ensure-ha",
On 2014/03/28 07:54:23, rog wrote:
> I'm not sure about "ha" in lower case - it looks too much like a word.
I'm
> thinking that either we make it into a proper word ("availability") or
we
> capitalise the ha - ensure-HA, thus making it clearer that it's an
acronym.

Yeah, it didn't look quite right to me, I was following what was in the
card. I've changed it to ensure-availability to be consistent with the
API.

If others disagree, it can be changed easily enough later -- this
command is not yet exposed.

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode58
cmd/juju/ensureha.go:58: f.IntVar(&c.NumStateServers, "n", 1, "number of
state servers to make available")
On 2014/03/28 07:54:23, rog wrote:
> Thought for the future - it would be good to be able to run "juju
ensure-HA"
> without any arguments at all, for when we just want to maintain the
current
> availability. Perhaps rather than defaulting to 1, we should default
to -1 and
> complain if it's not specified. That way we leave that path open.

Good point, will disallow for now.

https://codereview.appspot.com/81700043/diff/1/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/81700043/diff/1/state/api/client.go#newcode680
state/api/client.go:680: } else if err := result.Error; err != nil {
On 2014/03/28 07:54:23, rog wrote:
> There's no point in having an Error in the result as well as an error
return.

Done.

https://codereview.appspot.com/81700043/diff/1/state/api/params/params.go
File state/api/params/params.go (right):

https://codereview.appspot.com/81700043/diff/1/state/api/params/params.go#newcode649
state/api/params/params.go:649: Error *Error
On 2014/03/28 07:54:23, rog wrote:
> d

Done.

https://codereview.appspot.com/81700043/diff/1/state/apiserver/client/client.go
File state/apiserver/client/client.go (right):

https://codereview.appspot.com/81700043/diff/1/state/apiserver/client/client.go#newcode990
state/apiserver/client/client.go:990: if err :=
c.api.state.EnsureAvailability(args.NumStateServers, args.Constraints,
series); err != nil {
On 2014/03/28 07:54:23, rog wrote:
> err := c.api.state.EnsureAvailability(args.NumStateServers,
args.Constraints,
> series)
> return params.EnsureAvailabilityResult{}, err

Done, except the result is no longer necessary so I've dropped it.

https://codereview.appspot.com/81700043/

Revision history for this message
Roger Peppe (rogpeppe) wrote :

On 2014/03/28 10:03:41, axw wrote:
> Please take a look.

> https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go
> File cmd/juju/ensureha.go (right):

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode19
> cmd/juju/ensureha.go:19: // If specified, use this series, else use
the
> environment default-series
> On 2014/03/28 07:54:23, rog wrote:
> > use this series for newly started instances ?

> Done.

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode50
> cmd/juju/ensureha.go:50: Name: "ensure-ha",
> On 2014/03/28 07:54:23, rog wrote:
> > I'm not sure about "ha" in lower case - it looks too much like a
word. I'm
> > thinking that either we make it into a proper word ("availability")
or we
> > capitalise the ha - ensure-HA, thus making it clearer that it's an
acronym.

> Yeah, it didn't look quite right to me, I was following what was in
the card.
> I've changed it to ensure-availability to be consistent with the API.

> If others disagree, it can be changed easily enough later -- this
command is not
> yet exposed.

https://codereview.appspot.com/81700043/diff/1/cmd/juju/ensureha.go#newcode58
> cmd/juju/ensureha.go:58: f.IntVar(&c.NumStateServers, "n", 1, "number
of state
> servers to make available")
> On 2014/03/28 07:54:23, rog wrote:
> > Thought for the future - it would be good to be able to run "juju
ensure-HA"
> > without any arguments at all, for when we just want to maintain the
current
> > availability. Perhaps rather than defaulting to 1, we should default
to -1 and
> > complain if it's not specified. That way we leave that path open.

> Good point, will disallow for now.

> https://codereview.appspot.com/81700043/diff/1/state/api/client.go
> File state/api/client.go (right):

https://codereview.appspot.com/81700043/diff/1/state/api/client.go#newcode680
> state/api/client.go:680: } else if err := result.Error; err != nil {
> On 2014/03/28 07:54:23, rog wrote:
> > There's no point in having an Error in the result as well as an
error return.

> Done.

https://codereview.appspot.com/81700043/diff/1/state/api/params/params.go
> File state/api/params/params.go (right):

https://codereview.appspot.com/81700043/diff/1/state/api/params/params.go#newcode649
> state/api/params/params.go:649: Error *Error
> On 2014/03/28 07:54:23, rog wrote:
> > d

> Done.

https://codereview.appspot.com/81700043/diff/1/state/apiserver/client/client.go
> File state/apiserver/client/client.go (right):

https://codereview.appspot.com/81700043/diff/1/state/apiserver/client/client.go#newcode990
> state/apiserver/client/client.go:990: if err :=
> c.api.state.EnsureAvailability(args.NumStateServers, args.Constraints,
series);
> err != nil {
> On 2014/03/28 07:54:23, rog wrote:
> > err := c.api.state.EnsureAvailability(args.NumStateServers,
args.Constraints,
> > series)
> > return params.EnsureAvailabilityResult{}, err

> Done, except the result is no longer necessary so I've dropped it.

LGTM, thanks!

https://codereview.appspot.com/81700043/

Revision history for this message
Go Bot (go-bot) wrote :

Attempt to merge into lp:juju-core failed due to conflicts:

text conflict in state/api/client.go
text conflict in state/api/params/params.go
text conflict in state/apiserver/client/client.go
text conflict in state/apiserver/client/client_test.go

Revision history for this message
Andrew Wilkins (axwalk) wrote :
Revision history for this message
Go Bot (go-bot) wrote :
Download full text (16.3 KiB)

The attempt to merge lp:~axwalk/juju-core/cmdapi-ensureavailability into lp:juju-core failed. Below is the output from the failed tests.

ok launchpad.net/juju-core 0.014s
ok launchpad.net/juju-core/agent 1.123s
ok launchpad.net/juju-core/agent/mongo 0.529s
ok launchpad.net/juju-core/agent/tools 0.170s
ok launchpad.net/juju-core/bzr 5.544s
ok launchpad.net/juju-core/cert 2.478s
ok launchpad.net/juju-core/charm 0.448s
? launchpad.net/juju-core/charm/hooks [no test files]
? launchpad.net/juju-core/charm/testing [no test files]
ok launchpad.net/juju-core/cloudinit 0.026s
ok launchpad.net/juju-core/cloudinit/sshinit 0.822s
ok launchpad.net/juju-core/cmd 0.167s
ok launchpad.net/juju-core/cmd/charm-admin 0.766s
? launchpad.net/juju-core/cmd/charmd [no test files]
? launchpad.net/juju-core/cmd/charmload [no test files]
ok launchpad.net/juju-core/cmd/juju 204.103s
ok launchpad.net/juju-core/cmd/jujud 64.185s
ok launchpad.net/juju-core/cmd/plugins/juju-metadata 10.634s
? launchpad.net/juju-core/cmd/plugins/juju-restore [no test files]
ok launchpad.net/juju-core/cmd/plugins/local 0.181s
? launchpad.net/juju-core/cmd/plugins/local/juju-local [no test files]
ok launchpad.net/juju-core/constraints 0.022s
ok launchpad.net/juju-core/container 0.075s
ok launchpad.net/juju-core/container/factory 0.050s
ok launchpad.net/juju-core/container/kvm 0.224s
ok launchpad.net/juju-core/container/kvm/mock 0.043s
? launchpad.net/juju-core/container/kvm/testing [no test files]
ok launchpad.net/juju-core/container/lxc 4.382s
? launchpad.net/juju-core/container/lxc/mock [no test files]
? launchpad.net/juju-core/container/lxc/testing [no test files]
? launchpad.net/juju-core/container/testing [no test files]
ok launchpad.net/juju-core/downloader 5.221s
ok launchpad.net/juju-core/environs 2.256s
ok launchpad.net/juju-core/environs/bootstrap 10.068s
ok launchpad.net/juju-core/environs/cloudinit 0.448s
ok launchpad.net/juju-core/environs/config 2.850s
ok launchpad.net/juju-core/environs/configstore 0.032s
ok launchpad.net/juju-core/environs/filestorage 0.027s
ok launchpad.net/juju-core/environs/httpstorage 0.643s
ok launchpad.net/juju-core/environs/imagemetadata 0.427s
? launchpad.net/juju-core/environs/imagemetadata/testing [no test files]
ok launchpad.net/juju-core/environs/instances 0.046s
ok launchpad.net/juju-core/environs/jujutest 0.175s
ok launchpad.net/juju-core/environs/manual 13.882s
ok launchpad.net/juju-core/environs/simplestreams 0.230s
? launchpad.net/juju-core/environs/simplestreams/testing [no test files]
ok launchpad.net/juju-core/environs/sshstorage 0.995s
ok launchpad.net/juju-core/environs/storage 0.928s
ok launchpad.net/juju-core/environs/sync 43.136s
ok launchpad.net/juju-core/environs/testing 0.139s
ok launchpad.net/juju-core/environs/tools 4.837s
? launchpad.net/juju-core/environs/tools/testing [no test files]
ok launchpad.net/juju-core/errors 0.011s
ok launchpad.net/juju-core/instance 0.017s
? launchpad.net/juju-core/instance/testing [no test files]
ok launchpad.net/juju-core/juju 19.193s
ok launchpad.net/juju-core/juju/arch 0....

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'cmd/juju/ensureavailability.go'
2--- cmd/juju/ensureavailability.go 1970-01-01 00:00:00 +0000
3+++ cmd/juju/ensureavailability.go 2014-03-28 13:32:35 +0000
4@@ -0,0 +1,81 @@
5+// Copyright 2014 Canonical Ltd.
6+// Licensed under the AGPLv3, see LICENCE file for details.
7+
8+package main
9+
10+import (
11+ "fmt"
12+
13+ "launchpad.net/gnuflag"
14+
15+ "launchpad.net/juju-core/cmd"
16+ "launchpad.net/juju-core/constraints"
17+ "launchpad.net/juju-core/juju"
18+)
19+
20+type EnsureAvailabilityCommand struct {
21+ cmd.EnvCommandBase
22+ NumStateServers int
23+ // If specified, use this series for newly created machines,
24+ // else use the environment's default-series
25+ Series string
26+ // If specified, these constraints will be merged with those
27+ // already in the environment when creating new machines.
28+ Constraints constraints.Value
29+}
30+
31+const ensureAvailabilityDoc = `
32+To ensure availability of deployed services, the Juju infrastructure
33+must itself be highly available. Ensure-availability must be called
34+to ensure that the specified number of state servers are made available.
35+
36+An odd number of state servers is required.
37+
38+Examples:
39+ juju ensure-availability -n 3
40+ Ensure that 3 state servers are available,
41+ with newly created state server machines
42+ having the default series and constraints.
43+ juju ensure-availability -n 5 --series=trusty
44+ Ensure that 5 state servers are available,
45+ with newly created state server machines
46+ having the "trusty" series.
47+ juju ensure-availability -n 7 --constraints mem=8G
48+ Ensure that 7 state servers are available,
49+ with newly created state server machines
50+ having the default series, and at least
51+ 8GB RAM.
52+`
53+
54+func (c *EnsureAvailabilityCommand) Info() *cmd.Info {
55+ return &cmd.Info{
56+ Name: "ensure-availability",
57+ Purpose: "ensure the availability of Juju state servers",
58+ Doc: ensureAvailabilityDoc,
59+ }
60+}
61+
62+func (c *EnsureAvailabilityCommand) SetFlags(f *gnuflag.FlagSet) {
63+ c.EnvCommandBase.SetFlags(f)
64+ f.IntVar(&c.NumStateServers, "n", -1, "number of state servers to make available")
65+ f.StringVar(&c.Series, "series", "", "the charm series")
66+ f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "additional machine constraints")
67+}
68+
69+func (c *EnsureAvailabilityCommand) Init(args []string) error {
70+ if c.NumStateServers%2 != 1 || c.NumStateServers <= 0 {
71+ return fmt.Errorf("must specify a number of state servers odd and greater than zero")
72+ }
73+ return cmd.CheckEmpty(args)
74+}
75+
76+// Run connects to the environment specified on the command line
77+// and calls EnsureAvailability.
78+func (c *EnsureAvailabilityCommand) Run(_ *cmd.Context) error {
79+ client, err := juju.NewAPIClientFromName(c.EnvName)
80+ if err != nil {
81+ return err
82+ }
83+ defer client.Close()
84+ return client.EnsureAvailability(c.NumStateServers, c.Constraints, c.Series)
85+}
86
87=== added file 'cmd/juju/ensureavailability_test.go'
88--- cmd/juju/ensureavailability_test.go 1970-01-01 00:00:00 +0000
89+++ cmd/juju/ensureavailability_test.go 2014-03-28 13:32:35 +0000
90@@ -0,0 +1,114 @@
91+// Copyright 2013 Canonical Ltd.
92+// Licensed under the AGPLv3, see LICENCE file for details.
93+
94+package main
95+
96+import (
97+ "fmt"
98+
99+ jc "github.com/juju/testing/checkers"
100+ gc "launchpad.net/gocheck"
101+
102+ "launchpad.net/juju-core/constraints"
103+ jujutesting "launchpad.net/juju-core/juju/testing"
104+ "launchpad.net/juju-core/state"
105+ "launchpad.net/juju-core/testing"
106+)
107+
108+type EnsureAvailabilitySuite struct {
109+ jujutesting.RepoSuite
110+}
111+
112+var _ = gc.Suite(&EnsureAvailabilitySuite{})
113+
114+func runEnsureAvailability(c *gc.C, args ...string) error {
115+ _, err := testing.RunCommand(c, &EnsureAvailabilityCommand{}, args)
116+ return err
117+}
118+
119+func (s *EnsureAvailabilitySuite) TestEnsureAvailability(c *gc.C) {
120+ err := runEnsureAvailability(c, "-n", "1")
121+ c.Assert(err, gc.IsNil)
122+ m, err := s.State.Machine("0")
123+ c.Assert(err, gc.IsNil)
124+ c.Assert(m.Life(), gc.Equals, state.Alive)
125+ c.Assert(m.Series(), gc.DeepEquals, "precise")
126+ mcons, err := m.Constraints()
127+ c.Assert(err, gc.IsNil)
128+ c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
129+}
130+
131+func (s *EnsureAvailabilitySuite) TestEnsureAvailabilityWithSeries(c *gc.C) {
132+ err := runEnsureAvailability(c, "--series", "series", "-n", "1")
133+ c.Assert(err, gc.IsNil)
134+ m, err := s.State.Machine("0")
135+ c.Assert(err, gc.IsNil)
136+ c.Assert(m.Series(), gc.DeepEquals, "series")
137+}
138+
139+func (s *EnsureAvailabilitySuite) TestEnsureAvailabilityWithConstraints(c *gc.C) {
140+ err := runEnsureAvailability(c, "--constraints", "mem=4G", "-n", "1")
141+ c.Assert(err, gc.IsNil)
142+ m, err := s.State.Machine("0")
143+ c.Assert(err, gc.IsNil)
144+ mcons, err := m.Constraints()
145+ c.Assert(err, gc.IsNil)
146+ expectedCons := constraints.MustParse("mem=4G")
147+ c.Assert(mcons, gc.DeepEquals, expectedCons)
148+}
149+
150+func (s *EnsureAvailabilitySuite) TestEnsureAvailabilityIdempotent(c *gc.C) {
151+ for i := 0; i < 2; i++ {
152+ err := runEnsureAvailability(c, "-n", "1")
153+ c.Assert(err, gc.IsNil)
154+ }
155+ m, err := s.State.Machine("0")
156+ c.Assert(err, gc.IsNil)
157+ mcons, err := m.Constraints()
158+ c.Assert(err, gc.IsNil)
159+ c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
160+
161+ // Running ensure-availability with constraints or series
162+ // will have no effect unless new machines are
163+ // created.
164+ err = runEnsureAvailability(c, "-n", "1", "--constraints", "mem=4G")
165+ c.Assert(err, gc.IsNil)
166+ m, err = s.State.Machine("0")
167+ c.Assert(err, gc.IsNil)
168+ mcons, err = m.Constraints()
169+ c.Assert(err, gc.IsNil)
170+ c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
171+}
172+
173+func (s *EnsureAvailabilitySuite) TestEnsureAvailabilityMultiple(c *gc.C) {
174+ err := runEnsureAvailability(c, "-n", "1")
175+ c.Assert(err, gc.IsNil)
176+ err = runEnsureAvailability(c, "-n", "3", "--constraints", "mem=4G")
177+ c.Assert(err, gc.IsNil)
178+
179+ machines, err := s.State.AllMachines()
180+ c.Assert(err, gc.IsNil)
181+ c.Assert(machines, gc.HasLen, 3)
182+ mcons, err := machines[0].Constraints()
183+ c.Assert(err, gc.IsNil)
184+ c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty)
185+ for i := 1; i < 3; i++ {
186+ mcons, err := machines[i].Constraints()
187+ c.Assert(err, gc.IsNil)
188+ expectedCons := constraints.MustParse("mem=4G")
189+ c.Assert(mcons, gc.DeepEquals, expectedCons)
190+ }
191+}
192+
193+func (s *EnsureAvailabilitySuite) TestEnsureAvailabilityErrors(c *gc.C) {
194+ err := runEnsureAvailability(c)
195+ c.Assert(err, gc.ErrorMatches, "must specify a number of state servers odd and greater than zero")
196+ for _, n := range []int{-1, 0, 2} {
197+ err := runEnsureAvailability(c, "-n", fmt.Sprint(n))
198+ c.Assert(err, gc.ErrorMatches, "must specify a number of state servers odd and greater than zero")
199+ }
200+ err = runEnsureAvailability(c, "-n", "3")
201+ c.Assert(err, gc.IsNil)
202+ err = runEnsureAvailability(c, "-n", "1")
203+ c.Assert(err, gc.ErrorMatches, "cannot reduce state server count")
204+}
205
206=== modified file 'cmd/juju/main.go'
207--- cmd/juju/main.go 2014-03-26 13:40:28 +0000
208+++ cmd/juju/main.go 2014-03-28 13:32:35 +0000
209@@ -125,6 +125,10 @@
210 // Manage authorised ssh keys.
211 jujucmd.Register(wrap(NewAuthorisedKeysCommand()))
212
213+ // Manage state server availability.
214+ // TODO: enable once the backend is ready for it.
215+ //jujucmd.Register(wrap(&EnsureAvailabilityCommand{}))
216+
217 // Common commands.
218 jujucmd.Register(wrap(&cmd.VersionCommand{}))
219
220
221=== modified file 'state/api/client.go'
222--- state/api/client.go 2014-03-28 05:59:48 +0000
223+++ state/api/client.go 2014-03-28 13:32:35 +0000
224@@ -675,3 +675,13 @@
225 }
226 return result.Servers, nil
227 }
228+
229+// EnsureAvailability ensures the availability of Juju state servers.
230+func (c *Client) EnsureAvailability(numStateServers int, cons constraints.Value, series string) error {
231+ args := params.EnsureAvailability{
232+ NumStateServers: numStateServers,
233+ Constraints: cons,
234+ Series: series,
235+ }
236+ return c.call("EnsureAvailability", args, nil)
237+}
238
239=== modified file 'state/api/params/params.go'
240--- state/api/params/params.go 2014-03-28 05:59:48 +0000
241+++ state/api/params/params.go 2014-03-28 13:32:35 +0000
242@@ -639,3 +639,13 @@
243 type APIHostPortsResult struct {
244 Servers [][]instance.HostPort
245 }
246+
247+// EnsureAvailability contains arguments for
248+// the EnsureAvailability client API call.
249+type EnsureAvailability struct {
250+ NumStateServers int
251+ Constraints constraints.Value
252+ // Series is the series to associate with new state server machines.
253+ // If this is empty, then the environment's default series is used.
254+ Series string
255+}
256
257=== modified file 'state/apiserver/client/client.go'
258--- state/apiserver/client/client.go 2014-03-28 05:59:48 +0000
259+++ state/apiserver/client/client.go 2014-03-28 13:32:35 +0000
260@@ -984,3 +984,16 @@
261 }
262 return result, nil
263 }
264+
265+// EnsureAvailability ensures the availability of Juju state servers.
266+func (c *Client) EnsureAvailability(args params.EnsureAvailability) error {
267+ series := args.Series
268+ if series == "" {
269+ cfg, err := c.api.state.EnvironConfig()
270+ if err != nil {
271+ return err
272+ }
273+ series = cfg.DefaultSeries()
274+ }
275+ return c.api.state.EnsureAvailability(args.NumStateServers, args.Constraints, series)
276+}
277
278=== modified file 'state/apiserver/client/client_test.go'
279--- state/apiserver/client/client_test.go 2014-03-28 09:57:37 +0000
280+++ state/apiserver/client/client_test.go 2014-03-28 13:32:35 +0000
281@@ -2083,6 +2083,62 @@
282 c.Assert(data["transient"], gc.Equals, true)
283 }
284
285+func (s *clientSuite) TestClientEnsureAvailabilitySeries(c *gc.C) {
286+ apiParams := []params.EnsureAvailability{{
287+ NumStateServers: 1,
288+ }, {
289+ NumStateServers: 3,
290+ Series: "non-default",
291+ }}
292+ for _, p := range apiParams {
293+ err := s.APIState.Client().EnsureAvailability(p.NumStateServers, p.Constraints, p.Series)
294+ c.Assert(err, gc.IsNil)
295+ }
296+ machines, err := s.State.AllMachines()
297+ c.Assert(err, gc.IsNil)
298+ c.Assert(machines, gc.HasLen, 3)
299+ c.Assert(machines[0].Series(), gc.Equals, "precise")
300+ c.Assert(machines[1].Series(), gc.Equals, "non-default")
301+ c.Assert(machines[2].Series(), gc.Equals, "non-default")
302+}
303+
304+func (s *clientSuite) TestClientEnsureAvailabilityConstraints(c *gc.C) {
305+ apiParams := []params.EnsureAvailability{{
306+ NumStateServers: 1,
307+ }, {
308+ NumStateServers: 3,
309+ Constraints: constraints.MustParse("mem=4G"),
310+ }}
311+ for _, p := range apiParams {
312+ err := s.APIState.Client().EnsureAvailability(p.NumStateServers, p.Constraints, p.Series)
313+ c.Assert(err, gc.IsNil)
314+ }
315+ machines, err := s.State.AllMachines()
316+ c.Assert(err, gc.IsNil)
317+ c.Assert(machines, gc.HasLen, 3)
318+ expectedCons := []constraints.Value{
319+ constraints.Value{},
320+ constraints.MustParse("mem=4G"),
321+ constraints.MustParse("mem=4G"),
322+ }
323+ for i, m := range machines {
324+ cons, err := m.Constraints()
325+ c.Assert(err, gc.IsNil)
326+ c.Check(cons, gc.DeepEquals, expectedCons[i])
327+ }
328+}
329+
330+func (s *clientSuite) TestClientEnsureAvailabilityErrors(c *gc.C) {
331+ var emptyCons constraints.Value
332+ defaultSeries := ""
333+ err := s.APIState.Client().EnsureAvailability(0, emptyCons, defaultSeries)
334+ c.Assert(err, gc.ErrorMatches, "number of state servers must be odd and greater than zero")
335+ err = s.APIState.Client().EnsureAvailability(3, emptyCons, defaultSeries)
336+ c.Assert(err, gc.IsNil)
337+ err = s.APIState.Client().EnsureAvailability(1, emptyCons, defaultSeries)
338+ c.Assert(err, gc.ErrorMatches, "cannot reduce state server count")
339+}
340+
341 func (s *clientSuite) TestAPIHostPorts(c *gc.C) {
342 apiHostPorts, err := s.APIState.Client().APIHostPorts()
343 c.Assert(err, gc.IsNil)

Subscribers

People subscribed via source and target branches

to status/vote changes: