Skip to content

Commit

Permalink
FAN: test for state/containernetworking
Browse files Browse the repository at this point in the history
  • Loading branch information
Witold Krecicki committed Oct 4, 2017
1 parent c3d5931 commit a409997
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 40 deletions.
13 changes: 8 additions & 5 deletions apiserver/facades/agent/fanconfigurer/fanconfigurer.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@ var _ FanConfigurer = (*FanConfigurerAPI)(nil)

// NewFanConfigurerAPI creates a new FanConfigurer API endpoint on server-side.
func NewFanConfigurerAPI(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*FanConfigurerAPI, error) {
// Only machine agents have access to the fanconfigurer service.
if !authorizer.AuthMachineAgent() {
return nil, common.ErrPerm
}

model, err := st.Model()
if err != nil {
return nil, err
}
return NewFanConfigurerAPIForModel(model, resources, authorizer)
}

func NewFanConfigurerAPIForModel(model state.ModelAccessor, resources facade.Resources, authorizer facade.Authorizer) (*FanConfigurerAPI, error) {
// Only machine agents have access to the fanconfigurer service.
if !authorizer.AuthMachineAgent() {
return nil, common.ErrPerm
}

return &FanConfigurerAPI{
model: model,
Expand Down
53 changes: 31 additions & 22 deletions apiserver/facades/agent/fanconfigurer/fanconfigurer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
package fanconfigurer_test

import (
"github.com/juju/cmd/cmdtesting"
jc "github.com/juju/testing/checkers"
gc "gopkg.in/check.v1"
"gopkg.in/juju/names.v2"

"fmt"
"github.com/juju/juju/apiserver/common"
"github.com/juju/juju/apiserver/facades/agent/fanconfigurer"
"github.com/juju/juju/apiserver/facades/agent/keyupdater"
"github.com/juju/juju/apiserver/params"
apiservertesting "github.com/juju/juju/apiserver/testing"
"github.com/juju/juju/cmd/modelcmd"
"github.com/juju/juju/environs/bootstrap"
"github.com/juju/juju/environs/config"
jujutesting "github.com/juju/juju/juju/testing"
"github.com/juju/juju/jujuclient"
"github.com/juju/juju/provider/dummy"
"github.com/juju/juju/state"
statetesting "github.com/juju/juju/state/testing"
"github.com/juju/juju/testing"
)

Expand Down Expand Up @@ -56,11 +57,12 @@ func (s *fanconfigurerSuite) TestWatchSuccess(c *gc.C) {
Tag: names.NewMachineTag("0"),
}
s.AddCleanup(func(_ *gc.C) { resources.StopAll() })
e, err := fanconfigurer.NewFanConfigurerAPI(
e, err := fanconfigurer.NewFanConfigurerAPIForModel(
&fakeModelAccessor{},
resources,
authorizer,
)
c.Assert(err, jc.ErrorIsNil)
result, err := e.WatchForFanConfigChanges()
c.Assert(err, jc.ErrorIsNil)
c.Assert(result, gc.DeepEquals, params.NotifyWatchResult{"1", nil})
Expand All @@ -70,51 +72,58 @@ func (s *fanconfigurerSuite) TestWatchSuccess(c *gc.C) {
func (s *fanconfigurerSuite) TestWatchAuthFailed(c *gc.C) {
resources := common.NewResources()
authorizer := apiservertesting.FakeAuthorizer{
Tag: names.NewMachineTag("0"),
Tag: names.NewUserTag("vito"),
}
s.AddCleanup(func(_ *gc.C) { resources.StopAll() })
e, err := fanconfigurer.NewFanConfigurerAPI(
_, err := fanconfigurer.NewFanConfigurerAPIForModel(
&fakeModelAccessor{},
resources,
authorizer,
)
result, err := e.WatchForFanConfigChanges()
c.Assert(err, jc.ErrorIsNil)
c.Assert(result, gc.DeepEquals, params.NotifyWatchResult{"1", nil})
c.Assert(resources.Count(), gc.Equals, 1)
c.Assert(err, gc.ErrorMatches, "permission denied")
}

func (*fanconfigurerSuite) TestModelConfigSuccess(c *gc.C) {
func (s *fanconfigurerSuite) TestFanConfigSuccess(c *gc.C) {
resources := common.NewResources()
authorizer := apiservertesting.FakeAuthorizer{
Tag: names.NewMachineTag("0"),
Controller: true,
}
s.AddCleanup(func(_ *gc.C) { resources.StopAll() })
testingEnvConfig := testingEnvConfig(c)
e := common.NewModelWatcher(
&fakeModelAccessor{modelConfig: testingEnvConfig},
nil,
e, err := fanconfigurer.NewFanConfigurerAPIForModel(
&fakeModelAccessor{
modelConfig: testingEnvConfig,
},
resources,
authorizer,
)
result, err := e.ModelConfig()
c.Assert(err, jc.ErrorIsNil)
// Make sure we can read the secret attribute (i.e. it's not masked).
c.Check(result.Config["secret"], gc.Equals, "pork")
c.Check(map[string]interface{}(result.Config), jc.DeepEquals, testingEnvConfig.AllAttrs())
result, err := e.FanConfig()
c.Assert(err, jc.ErrorIsNil)
c.Assert(result.Fans, gc.HasLen, 2)
c.Check(result.Fans[0].Underlay, gc.Equals, "10.100.0.0/16")
c.Check(result.Fans[0].Overlay, gc.Equals, "251.0.0.0/8")
c.Check(result.Fans[1].Underlay, gc.Equals, "192.168.0.0/16")
c.Check(result.Fans[1].Overlay, gc.Equals, "252.0.0.0/8")
}

func (*fanconfigurerSuite) TestFanConfigFetchError(c *gc.C) {
func (s *fanconfigurerSuite) TestFanConfigFetchError(c *gc.C) {
resources := common.NewResources()
authorizer := apiservertesting.FakeAuthorizer{
Tag: names.NewMachineTag("0"),
Controller: true,
}
e := common.NewModelWatcher(
s.AddCleanup(func(_ *gc.C) { resources.StopAll() })
e, err := fanconfigurer.NewFanConfigurerAPIForModel(
&fakeModelAccessor{
modelConfigError: fmt.Errorf("pow"),
},
nil,
authorizer,
)
_, err := e.ModelConfig()
c.Assert(err, jc.ErrorIsNil)
_, err = e.FanConfig()
c.Assert(err, gc.ErrorMatches, "pow")
}

Expand All @@ -125,7 +134,7 @@ func testingEnvConfig(c *gc.C) *config.Config {
bootstrap.PrepareParams{
ControllerConfig: testing.FakeControllerConfig(),
ControllerName: "dummycontroller",
ModelConfig: dummy.SampleConfig(),
ModelConfig: dummy.SampleConfig().Merge(testing.Attrs{"fan-config": "10.100.0.0/16=251.0.0.0/8 192.168.0.0/16=252.0.0.0/8"}),
Cloud: dummy.SampleCloudSpec(),
AdminSecret: "admin-secret",
},
Expand Down
5 changes: 5 additions & 0 deletions apiserver/facades/client/modelmanager/modelinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,11 @@ func (m *mockModel) LastModelConnection(user names.UserTag) (time.Time, error) {
return time.Time{}, m.NextErr()
}

func (m *mockModel) AutoConfigureContainerNetworking(environ environs.Environ) error {
m.MethodCall(m, "AutoConfigureContainerNetworking", environ)
return m.NextErr()
}

type mockModelUser struct {
gitjujutesting.Stub
userName string
Expand Down
1 change: 0 additions & 1 deletion environs/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,6 @@ func (s *ConfigSuite) TestConfigAttrs(c *gc.C) {

// These attributes are added if not set.
attrs["logging-config"] = "<root>=WARNING;unit=DEBUG"
attrs["container-networking-method"] = "local"

// Default firewall mode is instance
attrs["firewall-mode"] = string(config.FwInstance)
Expand Down
12 changes: 6 additions & 6 deletions network/containerizer/bridgepolicy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (s *bridgePolicyStateSuite) SetUpTest(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)

s.bridgePolicy = &containerizer.BridgePolicy{
NetBondReconfigureDelay: 13,
NetBondReconfigureDelay: 13,
ContainerNetworkingMethod: "provider",
}
}
Expand Down Expand Up @@ -601,7 +601,7 @@ func (s *bridgePolicyStateSuite) TestPopulateContainerLinkLayerDevicesNoLocal(c
s.assertNoDevicesOnMachine(c, s.containerMachine)

bridgePolicy := &containerizer.BridgePolicy{
NetBondReconfigureDelay: 13,
NetBondReconfigureDelay: 13,
ContainerNetworkingMethod: "provider",
}
err := bridgePolicy.PopulateContainerLinkLayerDevices(s.machine, s.containerMachine)
Expand All @@ -619,7 +619,7 @@ func (s *bridgePolicyStateSuite) TestPopulateContainerLinkLayerDevicesUseLocal(c
s.assertNoDevicesOnMachine(c, s.containerMachine)

bridgePolicy := &containerizer.BridgePolicy{
NetBondReconfigureDelay: 13,
NetBondReconfigureDelay: 13,
ContainerNetworkingMethod: "local",
}
err := bridgePolicy.PopulateContainerLinkLayerDevices(s.machine, s.containerMachine)
Expand Down Expand Up @@ -726,7 +726,7 @@ func (s *bridgePolicyStateSuite) TestFindMissingBridgesForContainerContainerNetw
s.createAllDefaultDevices(c, s.machine)
s.addContainerMachine(c)
bridgePolicy := &containerizer.BridgePolicy{
NetBondReconfigureDelay: 13,
NetBondReconfigureDelay: 13,
ContainerNetworkingMethod: "local",
}
// No defined spaces for the container, no *known* spaces for the host
Expand All @@ -747,7 +747,7 @@ func (s *bridgePolicyStateSuite) TestFindMissingBridgesForContainerContainerNetw
s.createAllDefaultDevices(c, s.machine)
s.addContainerMachine(c)
bridgePolicy := &containerizer.BridgePolicy{
NetBondReconfigureDelay: 13,
NetBondReconfigureDelay: 13,
ContainerNetworkingMethod: "local",
}
// No defined spaces for the container, host has spaces but we have
Expand Down Expand Up @@ -784,7 +784,7 @@ func (s *bridgePolicyStateSuite) TestFindMissingBridgesForContainerContainerNetw
c.Assert(err, jc.ErrorIsNil)
s.addContainerMachine(c)
bridgePolicy := &containerizer.BridgePolicy{
NetBondReconfigureDelay: 13,
NetBondReconfigureDelay: 13,
ContainerNetworkingMethod: "local",
}
// No defined spaces for the container, no *known* spaces for the host
Expand Down
6 changes: 6 additions & 0 deletions provider/openstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ type Environ struct {
}

var _ environs.Environ = (*Environ)(nil)
var _ environs.NetworkingEnviron = (*Environ)(nil)
var _ simplestreams.HasRegion = (*Environ)(nil)
var _ instance.Distributor = (*Environ)(nil)
var _ environs.InstanceTagger = (*Environ)(nil)
Expand Down Expand Up @@ -1774,6 +1775,11 @@ func (e *Environ) SupportsContainerAddresses() (bool, error) {
return false, errors.NotSupportedf("container address")
}

// SuperSubnets is specified on environs.Networking
func (*Environ) SuperSubnets() ([]string, error) {
return nil, errors.NotSupportedf("super subnets")
}

// AllocateContainerAddresses is specified on environs.Networking.
func (e *Environ) AllocateContainerAddresses(hostInstanceID instance.Id, containerTag names.MachineTag, preparedInfo []network.InterfaceInfo) ([]network.InterfaceInfo, error) {
return nil, errors.NotSupportedf("allocate container address")
Expand Down
22 changes: 18 additions & 4 deletions state/containernetworking.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package state

import (
"fmt"
"net"
"strings"

"github.com/juju/errors"
Expand Down Expand Up @@ -61,6 +62,23 @@ func (m *Model) discoverFan(netEnviron environs.NetworkingEnviron, modelConfig *
return false, err
}
var outputTable []string

fanOverlays := []string{"252.0.0.0/8", "253.0.0.0/8", "254.0.0.0/8", "250.0.0.0/8", "251.0.0.0/8"}
fanOverlayForUnderlay := func(underlay string) string {
_, ipNet, err := net.ParseCIDR(underlay)
if err != nil {
return ""
}
if ones, _ := ipNet.Mask.Size(); ones <= 8 {
return ""
}
if len(fanOverlays) == 0 {
return ""
}
var overlay string
overlay, fanOverlays = fanOverlays[0], fanOverlays[1:]
return overlay
}
for _, subnet := range subnets {
overlay := fanOverlayForUnderlay(subnet)
if overlay != "" {
Expand All @@ -73,7 +91,3 @@ func (m *Model) discoverFan(netEnviron environs.NetworkingEnviron, modelConfig *
}
return false, nil
}

func fanOverlayForUnderlay(overlay string) string {
return "253.0.0.0/8"
}
109 changes: 109 additions & 0 deletions state/containernetworking_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2017 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package state_test

import (
"github.com/juju/testing"
jc "github.com/juju/testing/checkers"
gc "gopkg.in/check.v1"

"github.com/juju/juju/environs"
)

type containerTestNetworkLessEnviron struct {
environs.Environ
}

type containerTestNetworkedEnviron struct {
environs.NetworkingEnviron

stub *testing.Stub
supportsContainerAddresses bool
superSubnets []string
}

type ContainerNetworkingSuite struct {
ConnSuite
}

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

func (e *containerTestNetworkedEnviron) SuperSubnets() ([]string, error) {
e.stub.AddCall("SuperSubnets")
return e.superSubnets, e.stub.NextErr()
}

func (e *containerTestNetworkedEnviron) SupportsContainerAddresses() (bool, error) {
e.stub.AddCall("SupportsContainerAddresses")
return e.supportsContainerAddresses, e.stub.NextErr()
}

var _ environs.NetworkingEnviron = (*containerTestNetworkedEnviron)(nil)

func (s *ContainerNetworkingSuite) TestAutoConfigureContainerNetworkingNetworkless(c *gc.C) {
err := s.Model.AutoConfigureContainerNetworking(containerTestNetworkLessEnviron{})
c.Check(err, gc.ErrorMatches, "fan configuration in a non-networking environ not supported")
}

func (s *ContainerNetworkingSuite) TestAutoConfigureContainerNetworkingAlreadyConfigured(c *gc.C) {
environ := containerTestNetworkedEnviron{
stub: &testing.Stub{},
superSubnets: []string{"172.31.0.0/16", "192.168.1.0/24", "10.0.0.0/8"},
}
err := s.State.UpdateModelConfig(map[string]interface{}{
"container-networking-method": "local",
"fan-config": "1.2.3.4/24=5.6.7.8/16",
}, nil)
c.Assert(err, jc.ErrorIsNil)
err = s.Model.AutoConfigureContainerNetworking(&environ)
c.Check(err, jc.ErrorIsNil)
config, err := s.Model.ModelConfig()
c.Assert(err, jc.ErrorIsNil)
attrs := config.AllAttrs()
c.Check(attrs["container-networking-method"], gc.Equals, "local")
c.Check(attrs["fan-config"], gc.Equals, "1.2.3.4/24=5.6.7.8/16")
}

func (s *ContainerNetworkingSuite) TestAutoConfigureContainerNetworkingNoSuperSubnets(c *gc.C) {
environ := containerTestNetworkedEnviron{
stub: &testing.Stub{},
}
err := s.Model.AutoConfigureContainerNetworking(&environ)
c.Check(err, jc.ErrorIsNil)
config, err := s.Model.ModelConfig()
c.Assert(err, jc.ErrorIsNil)
attrs := config.AllAttrs()
c.Check(attrs["container-networking-method"], gc.Equals, "local")
c.Check(attrs["fan-config"], gc.Equals, "")
}

func (s *ContainerNetworkingSuite) TestAutoConfigureContainerNetworkingSupportsContainerAddresses(c *gc.C) {
environ := containerTestNetworkedEnviron{
stub: &testing.Stub{},
supportsContainerAddresses: true,
superSubnets: []string{"172.31.0.0/16", "192.168.1.0/24", "10.0.0.0/8"},
}
err := s.Model.AutoConfigureContainerNetworking(&environ)
c.Check(err, jc.ErrorIsNil)
config, err := s.Model.ModelConfig()
c.Assert(err, jc.ErrorIsNil)
attrs := config.AllAttrs()
c.Check(attrs["container-networking-method"], gc.Equals, "provider")
c.Check(attrs["fan-config"], gc.Equals, "172.31.0.0/16=252.0.0.0/8 192.168.1.0/24=253.0.0.0/8")
}

func (s *ContainerNetworkingSuite) TestAutoConfigureContainerNetworkingDefault(c *gc.C) {
environ := containerTestNetworkedEnviron{
stub: &testing.Stub{},
supportsContainerAddresses: false,
superSubnets: []string{"172.31.0.0/16", "192.168.1.0/24", "10.0.0.0/8"},
}
err := s.Model.AutoConfigureContainerNetworking(&environ)
c.Check(err, jc.ErrorIsNil)
config, err := s.Model.ModelConfig()
c.Assert(err, jc.ErrorIsNil)
attrs := config.AllAttrs()
c.Check(attrs["container-networking-method"], gc.Equals, "fan")
c.Check(attrs["fan-config"], gc.Equals, "172.31.0.0/16=252.0.0.0/8 192.168.1.0/24=253.0.0.0/8")
}
Loading

0 comments on commit a409997

Please sign in to comment.