Merge master onto maas-spaces #4139

Closed
wants to merge 211 commits into
from
Commits
Jump to file or symbol
Failed to load files and symbols.
+9,399 −3,072
Split
View
@@ -596,7 +596,15 @@ func (c *configInternal) SetAPIHostPorts(servers [][]network.HostPort) {
}
var addrs []string
for _, serverHostPorts := range servers {
- addrs = append(addrs, network.SelectInternalHostPorts(serverHostPorts, false)...)
+ // Try the preferred approach first.
+ serverHP, ok := network.SelectHostPortBySpace(serverHostPorts, network.DefaultSpace)
+ if ok {
+ addrs = append(addrs, serverHP.NetAddr())
+ } else {
+ // Fallback to the legacy approach.
+ hps := network.SelectInternalHostPorts(serverHostPorts, false)
+ addrs = append(addrs, hps...)
+ }
}
c.apiDetails.addresses = addrs
logger.Infof("API server address details %q written to agent config as %q", servers, addrs)
View
@@ -211,7 +211,18 @@ func initBootstrapMachine(c ConfigSetter, st *state.State, cfg BootstrapMachineC
// initAPIHostPorts sets the initial API host/port addresses in state.
func initAPIHostPorts(c ConfigSetter, st *state.State, addrs []network.Address, apiPort int) error {
- hostPorts := network.AddressesWithPort(addrs, apiPort)
+ var hostPorts []network.HostPort
+ // First try to select the correct address using the default space where all
+ // API servers should be accessible on.
+ spaceAddr, ok := network.SelectAddressBySpace(addrs, network.DefaultSpace)
+ if ok {
+ logger.Debugf("selected %q as API address, using space %q", spaceAddr.Value, network.DefaultSpace)
+ hostPorts = network.AddressesWithPort([]network.Address{spaceAddr}, apiPort)
+ } else {
+ // Fallback to using all instead.
+ hostPorts = network.AddressesWithPort(addrs, apiPort)
+ }
+
return st.SetAPIHostPorts([][]network.HostPort{hostPorts})
}
@@ -0,0 +1,81 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package discoverspaces
+
+import (
+ "github.com/juju/errors"
+ "github.com/juju/loggo"
+
+ "github.com/juju/juju/api/base"
+ "github.com/juju/juju/apiserver/params"
+ "github.com/juju/juju/environs/config"
+)
+
+var logger = loggo.GetLogger("juju.api.discoverspaces")
+
+const discoverspacesFacade = "DiscoverSpaces"
+
+// API provides access to the DiscoverSpaces API facade.
+type API struct {
+ facade base.FacadeCaller
+}
+
+// NewAPI creates a new facade.
+func NewAPI(caller base.APICaller) *API {
+ if caller == nil {
+ panic("caller is nil")
+ }
+ facadeCaller := base.NewFacadeCaller(caller, discoverspacesFacade)
+ return &API{
+ facade: facadeCaller,
+ }
+}
+
+func (api *API) ListSpaces() (params.DiscoverSpacesResults, error) {
+ var result params.DiscoverSpacesResults
+ if err := api.facade.FacadeCall("ListSpaces", nil, &result); err != nil {
+ return result, errors.Trace(err)
+ }
+ return result, nil
+}
+
+func (api *API) AddSubnets(args params.AddSubnetsParams) (params.ErrorResults, error) {
+ var result params.ErrorResults
+ err := api.facade.FacadeCall("AddSubnets", args, &result)
+ if err != nil {
+ return result, errors.Trace(err)
+ }
+ return result, nil
+}
+
+func (api *API) CreateSpaces(args params.CreateSpacesParams) (results params.ErrorResults, err error) {
+ var result params.ErrorResults
+ err = api.facade.FacadeCall("CreateSpaces", args, &result)
+ if err != nil {
+ return result, errors.Trace(err)
+ }
+ return result, nil
+}
+
+func (api *API) ListSubnets(args params.SubnetsFilters) (params.ListSubnetsResults, error) {
+ var result params.ListSubnetsResults
+ if err := api.facade.FacadeCall("ListSubnets", args, &result); err != nil {
+ return result, errors.Trace(err)
+ }
+ return result, nil
+}
+
+// EnvironConfig returns the current environment configuration.
+func (api *API) EnvironConfig() (*config.Config, error) {
+ var result params.EnvironConfigResult
+ err := api.facade.FacadeCall("EnvironConfig", nil, &result)
+ if err != nil {
+ return nil, err
+ }
+ conf, err := config.New(config.NoDefaults, result.Config)
+ if err != nil {
+ return nil, err
+ }
+ return conf, nil
+}
@@ -0,0 +1,129 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package discoverspaces_test
+
+import (
+ "errors"
+
+ jc "github.com/juju/testing/checkers"
+ gc "gopkg.in/check.v1"
+
+ "github.com/juju/juju/api/base"
+ apitesting "github.com/juju/juju/api/base/testing"
+ "github.com/juju/juju/api/discoverspaces"
+ "github.com/juju/juju/apiserver/params"
+ "github.com/juju/juju/environs/config"
+ coretesting "github.com/juju/juju/testing"
+)
+
+type DiscoverSpacesSuite struct {
+ coretesting.BaseSuite
+}
+
+var _ = gc.Suite(&DiscoverSpacesSuite{})
+
+func (s *DiscoverSpacesSuite) TestNewAPI(c *gc.C) {
+ var called int
+ apiCaller := clientErrorAPICaller(c, "ListSpaces", nil, &called)
+ api := discoverspaces.NewAPI(apiCaller)
+ c.Check(api, gc.NotNil)
+ c.Check(called, gc.Equals, 0)
+
+ // Make a call so that an error will be returned.
+ _, err := api.ListSpaces()
+ c.Assert(err, gc.ErrorMatches, "client error!")
+ c.Assert(called, gc.Equals, 1)
+}
+
+func clientErrorAPICaller(c *gc.C, method string, expectArgs interface{}, numCalls *int) base.APICaller {
+ args := &apitesting.CheckArgs{
+ Facade: "DiscoverSpaces",
+ VersionIsZero: true,
+ IdIsEmpty: true,
+ Method: method,
+ Args: expectArgs,
+ }
+ return apitesting.CheckingAPICaller(c, args, numCalls, errors.New("client error!"))
+}
+
+func successAPICaller(c *gc.C, method string, expectArgs, useResults interface{}, numCalls *int) base.APICaller {
+ args := &apitesting.CheckArgs{
+ Facade: "DiscoverSpaces",
+ VersionIsZero: true,
+ IdIsEmpty: true,
+ Method: method,
+ Args: expectArgs,
+ Results: useResults,
+ }
+ return apitesting.CheckingAPICaller(c, args, numCalls, nil)
+}
+
+func (s *DiscoverSpacesSuite) TestNewAPIWithNilCaller(c *gc.C) {
+ panicFunc := func() { discoverspaces.NewAPI(nil) }
+ c.Assert(panicFunc, gc.PanicMatches, "caller is nil")
+}
+
+func (s *DiscoverSpacesSuite) TestListSpaces(c *gc.C) {
+ var called int
+ expectedResult := params.DiscoverSpacesResults{
+ Results: []params.ProviderSpace{{Name: "foobar"}},
+ }
+ apiCaller := successAPICaller(c, "ListSpaces", nil, expectedResult, &called)
+ api := discoverspaces.NewAPI(apiCaller)
+
+ result, err := api.ListSpaces()
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(result, jc.DeepEquals, expectedResult)
+ c.Assert(called, gc.Equals, 1)
+}
+
+func (s *DiscoverSpacesSuite) TestAddSubnets(c *gc.C) {
+ var called int
+ expectedResult := params.ErrorResults{
+ Results: []params.ErrorResult{{}},
+ }
+ expectedArgs := params.AddSubnetsParams{
+ Subnets: []params.AddSubnetParams{{SubnetTag: "foo"}},
+ }
+ apiCaller := successAPICaller(c, "AddSubnets", expectedArgs, expectedResult, &called)
+ api := discoverspaces.NewAPI(apiCaller)
+
+ result, err := api.AddSubnets(expectedArgs)
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(result, jc.DeepEquals, expectedResult)
+ c.Assert(called, gc.Equals, 1)
+}
+
+func (s *DiscoverSpacesSuite) TestCreateSpaces(c *gc.C) {
+ var called int
+ expectedResult := params.ErrorResults{
+ Results: []params.ErrorResult{{}},
+ }
+ expectedArgs := params.CreateSpacesParams{
+ Spaces: []params.CreateSpaceParams{{SpaceTag: "foo"}},
+ }
+ apiCaller := successAPICaller(c, "CreateSpaces", expectedArgs, expectedResult, &called)
+ api := discoverspaces.NewAPI(apiCaller)
+
+ result, err := api.CreateSpaces(expectedArgs)
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(result, jc.DeepEquals, expectedResult)
+ c.Assert(called, gc.Equals, 1)
+}
+
+func (s *DiscoverSpacesSuite) TestEnvironConfig(c *gc.C) {
+ var called int
+ cfg, err := config.New(config.UseDefaults, coretesting.FakeConfig())
+ c.Assert(err, jc.ErrorIsNil)
+ expectedResult := params.EnvironConfigResult{
+ Config: cfg.AllAttrs(),
+ }
+ apiCaller := successAPICaller(c, "EnvironConfig", nil, expectedResult, &called)
+ api := discoverspaces.NewAPI(apiCaller)
+
+ result, err := api.EnvironConfig()
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(result, jc.DeepEquals, cfg)
+ c.Assert(called, gc.Equals, 1)
+}
@@ -0,0 +1,14 @@
+// Copyright 2015 Canonical Ltd.
+// Licensed under the AGPLv3, see LICENCE file for details.
+
+package discoverspaces_test
+
+import (
+ stdtesting "testing"
+
+ "github.com/juju/juju/testing"
+)
+
+func TestAll(t *stdtesting.T) {
+ testing.MgoTestPackage(t)
+}
View
@@ -24,6 +24,7 @@ var facadeVersions = map[string]int{
"Client": 0,
"Cleaner": 1,
"Deployer": 0,
+ "DiscoverSpaces": 1,
"DiskManager": 1,
"EntityWatcher": 1,
"Environment": 0,
View
@@ -15,6 +15,7 @@ import (
"github.com/juju/juju/api/charmrevisionupdater"
"github.com/juju/juju/api/cleaner"
"github.com/juju/juju/api/deployer"
+ "github.com/juju/juju/api/discoverspaces"
"github.com/juju/juju/api/diskmanager"
"github.com/juju/juju/api/environment"
"github.com/juju/juju/api/firewaller"
@@ -178,6 +179,7 @@ type Connection interface {
Logger() *apilogger.State
KeyUpdater() *keyupdater.State
Addresser() *addresser.API
+ DiscoverSpaces() *discoverspaces.API
InstancePoller() *instancepoller.API
CharmRevisionUpdater() *charmrevisionupdater.State
Cleaner() *cleaner.API
@@ -477,9 +477,9 @@ func (s *provisionerSuite) TestDistributionGroupMachineNotFound(c *gc.C) {
func (s *provisionerSuite) TestProvisioningInfo(c *gc.C) {
// Add a couple of spaces.
- _, err := s.State.AddSpace("space1", nil, true)
+ _, err := s.State.AddSpace("space1", "", nil, true)
c.Assert(err, jc.ErrorIsNil)
- _, err = s.State.AddSpace("space2", nil, false)
+ _, err = s.State.AddSpace("space2", "", nil, false)
c.Assert(err, jc.ErrorIsNil)
// Add 2 subnets into each space.
// Only the first subnet of space2 has AllocatableIPLow|High set.
View
@@ -72,24 +72,34 @@ func (c *Client) ServiceDeploy(
placement []*instance.Placement,
networks []string,
storage map[string]storage.Constraints,
+ bindings map[string]string,
) error {
args := params.ServicesDeploy{
Services: []params.ServiceDeploy{{
- ServiceName: serviceName,
- Series: series,
- CharmUrl: charmURL,
- NumUnits: numUnits,
- ConfigYAML: configYAML,
- Constraints: cons,
- ToMachineSpec: toMachineSpec,
- Placement: placement,
- Networks: networks,
- Storage: storage,
+ ServiceName: serviceName,
+ Series: series,
+ CharmUrl: charmURL,
+ NumUnits: numUnits,
+ ConfigYAML: configYAML,
+ Constraints: cons,
+ ToMachineSpec: toMachineSpec,
+ Placement: placement,
+ Networks: networks,
+ Storage: storage,
+ EndpointBindings: bindings,
}},
}
var results params.ErrorResults
var err error
- if len(placement) > 0 {
+ if len(bindings) > 0 {
+ err = c.FacadeCall("ServicesDeployWithBindings", args, &results)
+ if err != nil {
+ if params.IsCodeNotImplemented(err) {
+ return errors.Errorf("unsupported --bind parameter")
+ }
+ return err
+ }
+ } else if len(placement) > 0 {
err = c.FacadeCall("ServicesDeployWithPlacement", args, &results)
if err != nil {
if params.IsCodeNotImplemented(err) {
@@ -97,7 +97,45 @@ func (s *serviceSuite) TestSetServiceDeploy(c *gc.C) {
return nil
})
err := s.client.ServiceDeploy("charmURL", "serviceA", "series", 2, "configYAML", constraints.MustParse("mem=4G"),
- "machineSpec", nil, []string{"neta"}, map[string]storage.Constraints{"data": storage.Constraints{Pool: "pool"}})
+ "machineSpec", nil, []string{"neta"}, map[string]storage.Constraints{"data": storage.Constraints{Pool: "pool"}}, nil)
+ c.Assert(err, jc.ErrorIsNil)
+ c.Assert(called, jc.IsTrue)
+}
+
+func (s *serviceSuite) TestSetServiceDeployWithBindings(c *gc.C) {
+ var called bool
+ service.PatchFacadeCall(s, s.client, func(request string, a, response interface{}) error {
+ called = true
+ c.Assert(request, gc.Equals, "ServicesDeployWithBindings")
+ args, ok := a.(params.ServicesDeploy)
+ c.Assert(ok, jc.IsTrue)
+ c.Assert(args.Services, gc.HasLen, 1)
+ c.Assert(args.Services[0].CharmUrl, gc.Equals, "charmURL")
+ c.Assert(args.Services[0].ServiceName, gc.Equals, "serviceA")
+ c.Assert(args.Services[0].NumUnits, gc.Equals, 2)
+ c.Assert(args.Services[0].ConfigYAML, gc.Equals, "configYAML")
+ c.Assert(args.Services[0].Constraints, gc.DeepEquals, constraints.MustParse("mem=4G"))
+ c.Assert(args.Services[0].ToMachineSpec, gc.Equals, "machineSpec")
+ c.Assert(args.Services[0].Storage, gc.DeepEquals, map[string]storage.Constraints{"data": storage.Constraints{Pool: "pool"}})
+ c.Assert(args.Services[0].EndpointBindings, gc.DeepEquals, map[string]string{"foo": "bar"})
+
+ result := response.(*params.ErrorResults)
+ result.Results = make([]params.ErrorResult, 1)
+ return nil
+ })
+ err := s.client.ServiceDeploy(
+ "charmURL",
+ "serviceA",
+ "series",
+ 2,
+ "configYAML",
+ constraints.MustParse("mem=4G"),
+ "machineSpec",
+ nil,
+ nil, // networks shouldn't be used anymore
+ map[string]storage.Constraints{"data": storage.Constraints{Pool: "pool"}},
+ map[string]string{"foo": "bar"},
+ )
c.Assert(err, jc.ErrorIsNil)
c.Assert(called, jc.IsTrue)
}
Oops, something went wrong.