Skip to content

Commit

Permalink
Merge pull request #7605 from wallyworld/cmr-controller-addr-lookup
Browse files Browse the repository at this point in the history
Look for offer model uuid in local controller first

## Description of change

When setting up a cross model relation, the api address of the host controller needs to be determined. This PR ensures that we first look for the model in the local controller before looking for any external controllers.

## QA steps

Deploy a cmr scenario with just one controller.
  • Loading branch information
jujubot committed Jul 10, 2017
2 parents 33cd928 + f25f66a commit 13f1c2a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 14 deletions.
29 changes: 24 additions & 5 deletions apiserver/common/controllerconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package common

import (
"github.com/juju/errors"
"gopkg.in/juju/names.v2"

"github.com/juju/juju/apiserver/params"
Expand Down Expand Up @@ -49,13 +50,13 @@ func (s *ControllerConfigAPI) ControllerAPIInfoForModels(args params.Entities) (
result.Results[i].Error = ServerError(err)
continue
}
ec, err := s.st.ControllerInfo(modelTag.Id())
addrs, CACert, err := s.st.ControllerInfo(modelTag.Id())
if err != nil {
result.Results[i].Error = ServerError(err)
continue
}
result.Results[i].Addresses = ec.ControllerInfo().Addrs
result.Results[i].CACert = ec.ControllerInfo().CACert
result.Results[i].Addresses = addrs
result.Results[i].CACert = CACert
}
return result, nil
}
Expand All @@ -65,7 +66,25 @@ type controllerStateShim struct {
}

// ControllerInfo returns the external controller details for the specified model.
func (s *controllerStateShim) ControllerInfo(modelUUID string) (state.ExternalController, error) {
func (s *controllerStateShim) ControllerInfo(modelUUID string) (addrs []string, CACert string, _ error) {
// First see if the requested model UUID is hosted by this controller.
_, err := s.State.GetModel(names.NewModelTag(modelUUID))
if err != nil && !errors.IsNotFound(err) {
return nil, "", errors.Trace(err)
}
if err == nil {
addr, err := apiAddresses(s.State)
if err != nil {
return nil, "", errors.Trace(err)
}
return addr, s.State.CACert(), nil
}

// Now check any external controllers.
ec := state.NewExternalControllers(s.State)
return ec.ControllerForModel(modelUUID)
info, err := ec.ControllerForModel(modelUUID)
if err != nil {
return nil, "", errors.Trace(err)
}
return info.ControllerInfo().Addrs, info.ControllerInfo().CACert, nil
}
72 changes: 70 additions & 2 deletions apiserver/common/controllerconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import (
"fmt"

jc "github.com/juju/testing/checkers"
"github.com/juju/utils"
gc "gopkg.in/check.v1"
"gopkg.in/juju/names.v2"

"github.com/juju/errors"
"github.com/juju/juju/apiserver/common"
"github.com/juju/juju/apiserver/params"
"github.com/juju/juju/controller"
"github.com/juju/juju/core/crossmodel"
"github.com/juju/juju/environs/config"
jujutesting "github.com/juju/juju/juju/testing"
"github.com/juju/juju/provider/dummy"
"github.com/juju/juju/state"
"github.com/juju/juju/testing"
Expand Down Expand Up @@ -42,8 +47,11 @@ func (f *fakeControllerAccessor) ControllerConfig() (controller.Config, error) {
}, nil
}

func (f *fakeControllerAccessor) ControllerInfo(modelUUID string) (state.ExternalController, error) {
return nil, errors.NotImplementedf("ControllerInfo")
func (f *fakeControllerAccessor) ControllerInfo(modelUUID string) ([]string, string, error) {
if modelUUID != testing.ModelTag.Id() {
return nil, "", errors.New("wrong model")
}
return []string{"192.168.1.1:17070"}, testing.CACert, nil
}

func (s *controllerConfigSuite) TearDownTest(c *gc.C) {
Expand Down Expand Up @@ -74,3 +82,63 @@ func (*controllerConfigSuite) TestControllerConfigFetchError(c *gc.C) {
_, err := cc.ControllerConfig()
c.Assert(err, gc.ErrorMatches, "pow")
}

func (*controllerConfigSuite) TestControllerInfo(c *gc.C) {
cc := common.NewControllerConfig(
&fakeControllerAccessor{},
)
results, err := cc.ControllerAPIInfoForModels(params.Entities{
Entities: []params.Entity{{Tag: testing.ModelTag.String()}}})
c.Assert(err, jc.ErrorIsNil)
c.Assert(results.Results, gc.HasLen, 1)
c.Assert(results.Results[0].Addresses, gc.DeepEquals, []string{"192.168.1.1:17070"})
c.Assert(results.Results[0].CACert, gc.Equals, testing.CACert)
}

type controllerInfoSuite struct {
jujutesting.JujuConnSuite

localModel *state.State
}

var _ = gc.Suite(&controllerInfoSuite{})

func (s *controllerInfoSuite) SetUpTest(c *gc.C) {
s.JujuConnSuite.SetUpTest(c)
s.localModel = s.Factory.MakeModel(c, nil)
s.AddCleanup(func(*gc.C) {
s.localModel.Close()
})
}

func (s *controllerInfoSuite) TestControllerInfoLocalModel(c *gc.C) {
cc := common.NewStateControllerConfig(s.State)
results, err := cc.ControllerAPIInfoForModels(params.Entities{
Entities: []params.Entity{{Tag: s.localModel.ModelTag().String()}}})
c.Assert(err, jc.ErrorIsNil)
c.Assert(results.Results, gc.HasLen, 1)
apiAddr, err := s.State.APIHostPorts()
c.Assert(err, jc.ErrorIsNil)
c.Assert(results.Results[0].Addresses, gc.HasLen, 1)
c.Assert(results.Results[0].Addresses[0], gc.Equals, apiAddr[0][0].String())
c.Assert(results.Results[0].CACert, gc.Equals, s.State.CACert())
}

func (s *controllerInfoSuite) TestControllerInfoExternalModel(c *gc.C) {
ec := state.NewExternalControllers(s.State)
modelUUID := utils.MustNewUUID().String()
info := crossmodel.ControllerInfo{
ControllerTag: testing.ControllerTag,
Addrs: []string{"192.168.1.1:12345"},
CACert: testing.CACert,
}
_, err := ec.Save(info, modelUUID)
c.Assert(err, jc.ErrorIsNil)
cc := common.NewStateControllerConfig(s.State)
results, err := cc.ControllerAPIInfoForModels(params.Entities{
Entities: []params.Entity{{Tag: names.NewModelTag(modelUUID).String()}}})
c.Assert(err, jc.ErrorIsNil)
c.Assert(results.Results, gc.HasLen, 1)
c.Assert(results.Results[0].Addresses, gc.DeepEquals, info.Addrs)
c.Assert(results.Results[0].CACert, gc.Equals, info.CACert)
}
6 changes: 3 additions & 3 deletions apiserver/firewaller/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ func (st *mockState) ControllerConfig() (controller.Config, error) {
return nil, errors.NotImplementedf("ControllerConfig")
}

func (st *mockState) ControllerInfo(modelUUID string) (state.ExternalController, error) {
func (st *mockState) ControllerInfo(modelUUID string) ([]string, string, error) {
if info, ok := st.controllerInfo[modelUUID]; !ok {
return nil, errors.NotFoundf("controller info for %v", modelUUID)
return nil, "", errors.NotFoundf("controller info for %v", modelUUID)
} else {
return info, nil
return info.ControllerInfo().Addrs, info.ControllerInfo().CACert, nil
}
}

Expand Down
6 changes: 3 additions & 3 deletions apiserver/remoterelations/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ func (st *mockState) ControllerConfig() (controller.Config, error) {
return nil, errors.NotImplementedf("ControllerConfig")
}

func (st *mockState) ControllerInfo(modelUUID string) (state.ExternalController, error) {
func (st *mockState) ControllerInfo(modelUUID string) ([]string, string, error) {
if info, ok := st.controllerInfo[modelUUID]; !ok {
return nil, errors.NotFoundf("controller info for %v", modelUUID)
return nil, "", errors.NotFoundf("controller info for %v", modelUUID)
} else {
return info, nil
return info.ControllerInfo().Addrs, info.ControllerInfo().CACert, nil
}
}

Expand Down
2 changes: 1 addition & 1 deletion state/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ type ModelAccessor interface {
// access controller information.
type ControllerAccessor interface {
ControllerConfig() (controller.Config, error)
ControllerInfo(modelUUID string) (ExternalController, error)
ControllerInfo(modelUUID string) (addrs []string, CACert string, _ error)
}

// UnitsWatcher defines the methods needed to retrieve an entity (a
Expand Down

0 comments on commit 13f1c2a

Please sign in to comment.