Permalink
Browse files

Merge pull request #1962 from natefinch/ha3

WIP: implement targeting existing machines for ensure-availability

This change allows you to target machines that already exist in the environment with ensure-availability. Thus you can do `juju ensure-availability --to 1,2` and convert machines 1 and 2 to be state servers.  This works exactly like the existing --to, where it uses as many of the machines specified as it needs, and if it needs more machines, it'll create new ones.  e.g. if you have just one state server and do `juju ensure-availability -n 5 --to 1,2` then it'll convert 1 and 2 into state servers and start two new machines to fill in the other 2 machines it needs.

(Review request: http://reviews.vapour.ws/r/1299/)
  • Loading branch information...
2 parents 1dd387a + b59c254 commit b228e89dd3ef9a3fe0f14b958db123e87a68bc48 @jujubot jujubot committed Apr 10, 2015
View
@@ -4,6 +4,7 @@
package machiner
import (
+ "github.com/juju/errors"
"github.com/juju/names"
"github.com/juju/juju/api/common"
@@ -87,3 +88,23 @@ func (m *Machine) EnsureDead() error {
func (m *Machine) Watch() (watcher.NotifyWatcher, error) {
return common.Watch(m.st.facade, m.tag)
}
+
+// Jobs returns a list of jobs for the machine.
+func (m *Machine) Jobs() (*params.JobsResult, error) {
+ var results params.JobsResults
+ args := params.Entities{
+ Entities: []params.Entity{{Tag: m.Tag().String()}},
+ }
+ err := m.st.facade.FacadeCall("Jobs", args, &results)
+ if err != nil {
+ return nil, errors.Annotate(err, "error from FacadeCall")
+ }
+ if len(results.Results) != 1 {
+ return nil, errors.Errorf("expected 1 result, got %d", len(results.Results))
+ }
+ result := results.Results[0]
+ if result.Error != nil {
+ return nil, result.Error
+ }
+ return &result, nil
+}
View
@@ -4,6 +4,7 @@
package machiner
import (
+ "github.com/juju/errors"
"github.com/juju/names"
"github.com/juju/juju/api/base"
@@ -38,7 +39,7 @@ func (st *State) machineLife(tag names.MachineTag) (params.Life, error) {
func (st *State) Machine(tag names.MachineTag) (*Machine, error) {
life, err := st.machineLife(tag)
if err != nil {
- return nil, err
+ return nil, errors.Annotate(err, "can't get life for machine")
}
return &Machine{
tag: tag,
@@ -54,7 +54,7 @@ func (s *machinerSuite) SetUpTest(c *gc.C) {
func (s *machinerSuite) TestMachineAndMachineTag(c *gc.C) {
machine, err := s.machiner.Machine(names.NewMachineTag("42"))
- c.Assert(err, gc.ErrorMatches, "permission denied")
+ c.Assert(err, gc.ErrorMatches, ".*permission denied")
c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
c.Assert(machine, gc.IsNil)
@@ -5,6 +5,7 @@ package networker_test
import (
"runtime"
+ "sort"
"github.com/juju/names"
jc "github.com/juju/testing/checkers"
@@ -201,6 +202,38 @@ func (s *networkerSuite) TestMachineNetworkConfigNameChange(c *gc.C) {
c.Assert(info, gc.IsNil)
}
+type orderedIfc []network.InterfaceInfo
+
+func (o orderedIfc) Len() int {
+ return len(o)
+}
+
+func (o orderedIfc) Less(i, j int) bool {
+ if o[i].MACAddress < o[j].MACAddress {
+ return true
+ }
+ if o[i].MACAddress > o[j].MACAddress {
+ return false
+ }
+ if o[i].CIDR < o[j].CIDR {
+ return true
+ }
+ if o[i].CIDR > o[j].CIDR {
+ return false
+ }
+ if o[i].NetworkName < o[j].NetworkName {
+ return true
+ }
+ if o[i].NetworkName > o[j].NetworkName {
+ return false
+ }
+ return o[i].VLANTag < o[j].VLANTag
+}
+
+func (o orderedIfc) Swap(i, j int) {
+ o[i], o[j] = o[j], o[i]
+}
+
func (s *networkerSuite) TestMachineNetworkConfig(c *gc.C) {
// TODO(bogdanteleaga): Find out what's the problem with this test
// It seems to work on some machines
@@ -245,6 +278,8 @@ func (s *networkerSuite) TestMachineNetworkConfig(c *gc.C) {
InterfaceName: "eth2",
Disabled: true,
}}
+ sort.Sort(orderedIfc(expectedMachineInfo))
+
expectedContainerInfo := []network.InterfaceInfo{{
MACAddress: "aa:bb:cc:dd:ee:e0",
CIDR: "0.1.2.0/24",
@@ -267,6 +302,8 @@ func (s *networkerSuite) TestMachineNetworkConfig(c *gc.C) {
VLANTag: 42,
InterfaceName: "eth1",
}}
+ sort.Sort(orderedIfc(expectedContainerInfo))
+
expectedNestedContainerInfo := []network.InterfaceInfo{{
MACAddress: "aa:bb:cc:dd:ee:d0",
CIDR: "0.1.2.0/24",
@@ -275,17 +312,21 @@ func (s *networkerSuite) TestMachineNetworkConfig(c *gc.C) {
VLANTag: 0,
InterfaceName: "eth0",
}}
+ sort.Sort(orderedIfc(expectedNestedContainerInfo))
results, err := s.networker.MachineNetworkConfig(names.NewMachineTag("0"))
c.Assert(err, jc.ErrorIsNil)
+ sort.Sort(orderedIfc(results))
c.Assert(results, gc.DeepEquals, expectedMachineInfo)
results, err = s.networker.MachineNetworkConfig(names.NewMachineTag("0/lxc/0"))
c.Assert(err, jc.ErrorIsNil)
+ sort.Sort(orderedIfc(results))
c.Assert(results, gc.DeepEquals, expectedContainerInfo)
results, err = s.networker.MachineNetworkConfig(names.NewMachineTag("0/lxc/0/lxc/0"))
c.Assert(err, jc.ErrorIsNil)
+ sort.Sort(orderedIfc(results))
c.Assert(results, gc.DeepEquals, expectedNestedContainerInfo)
}
View
@@ -155,15 +155,15 @@ func (s *loginSuite) TestBadLogin(c *gc.C) {
defer st.Close()
_, err = st.Machiner().Machine(names.NewMachineTag("0"))
- c.Assert(err, gc.ErrorMatches, `unknown object type "Machiner"`)
+ c.Assert(err, gc.ErrorMatches, `.*unknown object type "Machiner"`)
// Since these are user login tests, the nonce is empty.
err = st.Login(t.tag, t.password, "")
c.Assert(err, gc.ErrorMatches, t.err)
c.Assert(params.ErrCode(err), gc.Equals, t.code)
_, err = st.Machiner().Machine(names.NewMachineTag("0"))
- c.Assert(err, gc.ErrorMatches, `unknown object type "Machiner"`)
+ c.Assert(err, gc.ErrorMatches, `.*unknown object type "Machiner"`)
}()
}
}
@@ -181,14 +181,14 @@ func (s *loginSuite) TestLoginAsDeactivatedUser(c *gc.C) {
u := s.Factory.MakeUser(c, &factory.UserParams{Password: password, Disabled: true})
_, err = st.Client().Status([]string{})
- c.Assert(err, gc.ErrorMatches, `unknown object type "Client"`)
+ c.Assert(err, gc.ErrorMatches, `.*unknown object type "Client"`)
// Since these are user login tests, the nonce is empty.
err = st.Login(u.Tag().String(), password, "")
c.Assert(err, gc.ErrorMatches, "invalid entity name or password")
_, err = st.Client().Status([]string{})
- c.Assert(err, gc.ErrorMatches, `unknown object type "Client"`)
+ c.Assert(err, gc.ErrorMatches, `.*unknown object type "Client"`)
}
func (s *loginV0Suite) TestLoginSetsLogIdentifier(c *gc.C) {
@@ -635,7 +635,7 @@ func (s *baseLoginSuite) checkLoginWithValidator(c *gc.C, validator apiserver.Lo
// Ensure not already logged in.
_, err := st.Machiner().Machine(names.NewMachineTag("0"))
- c.Assert(err, gc.ErrorMatches, `unknown object type "Machiner"`)
+ c.Assert(err, gc.ErrorMatches, `*.unknown object type "Machiner"`)
adminUser := s.AdminUserTag(c)
// Since these are user login tests, the nonce is empty.
@@ -73,6 +73,7 @@ func stateServersChanges(change state.StateServersChanges) params.StateServersCh
Removed: machineIdsToTags(change.Removed...),
Promoted: machineIdsToTags(change.Promoted...),
Demoted: machineIdsToTags(change.Demoted...),
+ Converted: machineIdsToTags(change.Converted...),
}
}
@@ -33,7 +33,7 @@ type clientSuite struct {
resources *common.Resources
authoriser apiservertesting.FakeAuthorizer
haServer *highavailability.HighAvailabilityAPI
- pinger *presence.Pinger
+ pingers []*presence.Pinger
commontesting.BlockHelper
}
@@ -71,13 +71,15 @@ func (s *clientSuite) SetUpTest(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
// We have to ensure the agents are alive, or EnsureAvailability will
// create more to replace them.
- s.pinger = s.setAgentPresence(c, "0")
+ s.pingers = []*presence.Pinger{s.setAgentPresence(c, "0")}
s.BlockHelper = commontesting.NewBlockHelper(s.APIState)
s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() })
}
func (s *clientSuite) TearDownTest(c *gc.C) {
- assertKill(c, s.pinger)
+ for _, pinger := range s.pingers {
+ assertKill(c, pinger)
+ }
s.JujuConnSuite.TearDownTest(c)
}
@@ -132,6 +134,7 @@ func (s *clientSuite) TestEnsureAvailabilitySeries(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err = s.State.AllMachines()
c.Assert(err, jc.ErrorIsNil)
@@ -151,6 +154,7 @@ func (s *clientSuite) TestEnsureAvailabilitySeries(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0", "machine-1", "machine-2"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-3", "machine-4"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
c.Assert(err, jc.ErrorIsNil)
machines, err = s.State.AllMachines()
@@ -169,6 +173,7 @@ func (s *clientSuite) TestEnsureAvailabilityConstraints(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err := s.State.AllMachines()
c.Assert(err, jc.ErrorIsNil)
@@ -195,6 +200,7 @@ func (s *clientSuite) TestBlockEnsureAvailability(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.HasLen, 0)
c.Assert(ensureAvailabilityResult.Added, gc.HasLen, 0)
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err := s.State.AllMachines()
c.Assert(err, jc.ErrorIsNil)
@@ -208,6 +214,7 @@ func (s *clientSuite) TestEnsureAvailabilityPlacement(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err := s.State.AllMachines()
c.Assert(err, jc.ErrorIsNil)
@@ -226,6 +233,36 @@ func (s *clientSuite) TestEnsureAvailabilityPlacement(c *gc.C) {
}
}
+func (s *clientSuite) TestEnsureAvailabilityPlacementTo(c *gc.C) {
+ _, err := s.State.AddMachine("quantal", state.JobHostUnits)
+ c.Assert(err, jc.ErrorIsNil)
+ s.pingers = append(s.pingers, s.setAgentPresence(c, "1"))
+
+ _, err = s.State.AddMachine("quantal", state.JobHostUnits)
+ c.Assert(err, jc.ErrorIsNil)
+ s.pingers = append(s.pingers, s.setAgentPresence(c, "2"))
+
+ placement := []string{"1", "2"}
+ ensureAvailabilityResult, err := s.ensureAvailability(c, 3, emptyCons, defaultSeries, placement)
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
+ c.Assert(ensureAvailabilityResult.Added, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.DeepEquals, []string{"machine-1", "machine-2"})
+
+ machines, err := s.State.AllMachines()
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(machines, gc.HasLen, 3)
+ expectedCons := []constraints.Value{{}, {}, {}}
+ expectedPlacement := []string{"", "", ""}
+ for i, m := range machines {
+ cons, err := m.Constraints()
+ c.Assert(err, jc.ErrorIsNil)
+ c.Check(cons, gc.DeepEquals, expectedCons[i])
+ c.Check(m.Placement(), gc.Equals, expectedPlacement[i])
+ }
+}
+
func (s *clientSuite) TestEnsureAvailability0Preserves(c *gc.C) {
// A value of 0 says either "if I'm not HA, make me HA" or "preserve my
// current HA settings".
@@ -234,6 +271,7 @@ func (s *clientSuite) TestEnsureAvailability0Preserves(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err := s.State.AllMachines()
c.Assert(machines, gc.HasLen, 3)
@@ -248,6 +286,7 @@ func (s *clientSuite) TestEnsureAvailability0Preserves(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0", "machine-1"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-3"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err = s.State.AllMachines()
c.Assert(machines, gc.HasLen, 4)
@@ -260,6 +299,7 @@ func (s *clientSuite) TestEnsureAvailability0Preserves5(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2", "machine-3", "machine-4"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err := s.State.AllMachines()
c.Assert(machines, gc.HasLen, 5)
@@ -278,6 +318,7 @@ func (s *clientSuite) TestEnsureAvailability0Preserves5(c *gc.C) {
"machine-2", "machine-3"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-5"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err = s.State.AllMachines()
c.Assert(machines, gc.HasLen, 6)
@@ -293,6 +334,7 @@ func (s *clientSuite) TestEnsureAvailabilityErrors(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.DeepEquals, []string{"machine-0"})
c.Assert(ensureAvailabilityResult.Added, gc.DeepEquals, []string{"machine-1", "machine-2"})
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
_, err = s.ensureAvailability(c, 1, emptyCons, defaultSeries, nil)
c.Assert(err, gc.ErrorMatches, "failed to create new state server machines: cannot reduce state server count")
@@ -311,6 +353,7 @@ func (s *clientSuite) TestEnsureAvailabilityHostedEnvErrors(c *gc.C) {
c.Assert(ensureAvailabilityResult.Maintained, gc.HasLen, 0)
c.Assert(ensureAvailabilityResult.Added, gc.HasLen, 0)
c.Assert(ensureAvailabilityResult.Removed, gc.HasLen, 0)
+ c.Assert(ensureAvailabilityResult.Converted, gc.HasLen, 0)
machines, err := st2.AllMachines()
c.Assert(err, jc.ErrorIsNil)
Oops, something went wrong.

0 comments on commit b228e89

Please sign in to comment.