Merge lp:~axwalk/juju-core/cmdapi-ensureavailability into lp:~go-bot/juju-core/trunk
- cmdapi-ensureavailability
- Merge into trunk
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 |
Related bugs: |
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.
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.
Andrew Wilkins (axwalk) wrote : | # |
Roger Peppe (rogpeppe) wrote : | # |
LGTM modulo the below, thanks!
https:/
File cmd/juju/
https:/
cmd/juju/
environment default-series
use this series for newly started instances ?
https:/
cmd/juju/
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:/
cmd/juju/
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:/
File state/api/client.go (right):
https:/
state/api/
There's no point in having an Error in the result as well as an error
return.
https:/
File state/api/
https:/
state/api/
d
https:/
File state/apiserver
https:/
state/apiserver
c.api.state.
series); err != nil {
err := c.api.state.
args.Constraints, series)
return params.
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
https:/
File cmd/juju/
https:/
cmd/juju/
environment default-series
On 2014/03/28 07:54:23, rog wrote:
> use this series for newly started instances ?
Done.
https:/
cmd/juju/
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:/
cmd/juju/
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:/
File state/api/client.go (right):
https:/
state/api/
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:/
File state/api/
https:/
state/api/
On 2014/03/28 07:54:23, rog wrote:
> d
Done.
https:/
File state/apiserver
https:/
state/apiserver
c.api.state.
series); err != nil {
On 2014/03/28 07:54:23, rog wrote:
> err := c.api.state.
args.Constraints,
> series)
> return params.
Done, except the result is no longer necessary so I've dropped it.
Roger Peppe (rogpeppe) wrote : | # |
On 2014/03/28 10:03:41, axw wrote:
> Please take a look.
> https:/
> File cmd/juju/
https:/
> cmd/juju/
the
> environment default-series
> On 2014/03/28 07:54:23, rog wrote:
> > use this series for newly started instances ?
> Done.
https:/
> cmd/juju/
> 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:/
> cmd/juju/
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:/
> File state/api/client.go (right):
https:/
> state/api/
> 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:/
> File state/api/
https:/
> state/api/
> On 2014/03/28 07:54:23, rog wrote:
> > d
> Done.
https:/
> File state/apiserver
https:/
> state/apiserver
> c.api.state.
series);
> err != nil {
> On 2014/03/28 07:54:23, rog wrote:
> > err := c.api.state.
args.Constraints,
> > series)
> > return params.
> Done, except the result is no longer necessary so I've dropped it.
LGTM, thanks!
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/
text conflict in state/apiserver
text conflict in state/apiserver
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
Go Bot (go-bot) wrote : | # |
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.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
Preview Diff
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) |
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- ensureavailabil ity/+merge/ 213190
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/81700043/
Affected files (+301, -0 lines): ensureha. go ensureha_ test.go params/ params. go /client/ client. go /client/ client_ test.go
A [revision details]
A cmd/juju/
A cmd/juju/
M cmd/juju/main.go
M state/api/client.go
M state/api/
M state/apiserver
M state/apiserver