github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/apiserver/networker/networker_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package networker_test
     5  
     6  import (
     7  	"runtime"
     8  	"sort"
     9  
    10  	"github.com/juju/names"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/networker"
    16  	"github.com/juju/juju/apiserver/params"
    17  	apiservertesting "github.com/juju/juju/apiserver/testing"
    18  	"github.com/juju/juju/instance"
    19  	"github.com/juju/juju/juju/testing"
    20  	"github.com/juju/juju/state"
    21  	statetesting "github.com/juju/juju/state/testing"
    22  )
    23  
    24  type networkerSuite struct {
    25  	testing.JujuConnSuite
    26  
    27  	networks []state.NetworkInfo
    28  
    29  	machine         *state.Machine
    30  	container       *state.Machine
    31  	nestedContainer *state.Machine
    32  
    33  	machineIfaces         []state.NetworkInterfaceInfo
    34  	containerIfaces       []state.NetworkInterfaceInfo
    35  	nestedContainerIfaces []state.NetworkInterfaceInfo
    36  
    37  	authorizer apiservertesting.FakeAuthorizer
    38  	resources  *common.Resources
    39  	networker  *networker.NetworkerAPI
    40  }
    41  
    42  var _ = gc.Suite(&networkerSuite{})
    43  
    44  // Create several networks.
    45  func (s *networkerSuite) setUpNetworks(c *gc.C) {
    46  	s.networks = []state.NetworkInfo{{
    47  		Name:       "net1",
    48  		ProviderId: "net1",
    49  		CIDR:       "0.1.2.0/24",
    50  		VLANTag:    0,
    51  	}, {
    52  		Name:       "vlan42",
    53  		ProviderId: "vlan42",
    54  		CIDR:       "0.2.2.0/24",
    55  		VLANTag:    42,
    56  	}, {
    57  		Name:       "vlan69",
    58  		ProviderId: "vlan69",
    59  		CIDR:       "0.3.2.0/24",
    60  		VLANTag:    69,
    61  	}, {
    62  		Name:       "vlan123",
    63  		ProviderId: "vlan123",
    64  		CIDR:       "0.4.2.0/24",
    65  		VLANTag:    123,
    66  	}, {
    67  		Name:       "net2",
    68  		ProviderId: "net2",
    69  		CIDR:       "0.5.2.0/24",
    70  		VLANTag:    0,
    71  	}}
    72  }
    73  
    74  // Create a machine to use.
    75  func (s *networkerSuite) setUpMachine(c *gc.C) {
    76  	var err error
    77  	s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits)
    78  	c.Assert(err, jc.ErrorIsNil)
    79  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
    80  	s.machineIfaces = []state.NetworkInterfaceInfo{{
    81  		MACAddress:    "aa:bb:cc:dd:ee:f0",
    82  		InterfaceName: "eth0",
    83  		NetworkName:   "net1",
    84  		IsVirtual:     false,
    85  	}, {
    86  		MACAddress:    "aa:bb:cc:dd:ee:f1",
    87  		InterfaceName: "eth1",
    88  		NetworkName:   "net1",
    89  		IsVirtual:     false,
    90  	}, {
    91  		MACAddress:    "aa:bb:cc:dd:ee:f1",
    92  		InterfaceName: "eth1.42",
    93  		NetworkName:   "vlan42",
    94  		IsVirtual:     true,
    95  	}, {
    96  		MACAddress:    "aa:bb:cc:dd:ee:f0",
    97  		InterfaceName: "eth0.69",
    98  		NetworkName:   "vlan69",
    99  		IsVirtual:     true,
   100  	}, {
   101  		MACAddress:    "aa:bb:cc:dd:ee:f2",
   102  		InterfaceName: "eth2",
   103  		NetworkName:   "net2",
   104  		IsVirtual:     false,
   105  		Disabled:      true,
   106  	}}
   107  	err = s.machine.SetInstanceInfo("i-am", "fake_nonce", &hwChars, s.networks, s.machineIfaces, nil, nil)
   108  	c.Assert(err, jc.ErrorIsNil)
   109  }
   110  
   111  // Create and provision a container and a nested container.
   112  func (s *networkerSuite) setUpContainers(c *gc.C) {
   113  	template := state.MachineTemplate{
   114  		Series: "quantal",
   115  		Jobs:   []state.MachineJob{state.JobHostUnits},
   116  	}
   117  	var err error
   118  	s.container, err = s.State.AddMachineInsideMachine(template, s.machine.Id(), instance.LXC)
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	s.containerIfaces = []state.NetworkInterfaceInfo{{
   121  		MACAddress:    "aa:bb:cc:dd:ee:e0",
   122  		InterfaceName: "eth0",
   123  		NetworkName:   "net1",
   124  		IsVirtual:     false,
   125  	}, {
   126  		MACAddress:    "aa:bb:cc:dd:ee:e1",
   127  		InterfaceName: "eth1",
   128  		NetworkName:   "net1",
   129  		IsVirtual:     false,
   130  	}, {
   131  		MACAddress:    "aa:bb:cc:dd:ee:e1",
   132  		InterfaceName: "eth1.42",
   133  		NetworkName:   "vlan42",
   134  		IsVirtual:     true,
   135  	}}
   136  	hwChars := instance.MustParseHardware("arch=i386", "mem=4G")
   137  	err = s.container.SetInstanceInfo("i-container", "fake_nonce", &hwChars, s.networks[:2],
   138  		s.containerIfaces, nil, nil)
   139  	c.Assert(err, jc.ErrorIsNil)
   140  
   141  	s.nestedContainer, err = s.State.AddMachineInsideMachine(template, s.container.Id(), instance.LXC)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	s.nestedContainerIfaces = []state.NetworkInterfaceInfo{{
   144  		MACAddress:    "aa:bb:cc:dd:ee:d0",
   145  		InterfaceName: "eth0",
   146  		NetworkName:   "net1",
   147  	}}
   148  	err = s.nestedContainer.SetInstanceInfo("i-too", "fake_nonce", &hwChars, s.networks[:1],
   149  		s.nestedContainerIfaces, nil, nil)
   150  	c.Assert(err, jc.ErrorIsNil)
   151  }
   152  
   153  func (s *networkerSuite) SetUpTest(c *gc.C) {
   154  	s.JujuConnSuite.SetUpTest(c)
   155  
   156  	s.setUpNetworks(c)
   157  	s.setUpMachine(c)
   158  	s.setUpContainers(c)
   159  
   160  	// Create a FakeAuthorizer so we can check permissions,
   161  	// set up assuming we logged in as a machine agent.
   162  	s.authorizer = apiservertesting.FakeAuthorizer{
   163  		Tag: s.machine.Tag(),
   164  	}
   165  
   166  	// Create the resource registry separately to track invocations to
   167  	// Register.
   168  	s.resources = common.NewResources()
   169  
   170  	// Create a networker API for the machine.
   171  	var err error
   172  	s.networker, err = networker.NewNetworkerAPI(
   173  		s.State,
   174  		s.resources,
   175  		s.authorizer,
   176  	)
   177  	c.Assert(err, jc.ErrorIsNil)
   178  }
   179  
   180  func (s *networkerSuite) TestNetworkerNonMachineAgent(c *gc.C) {
   181  	// Fails with not a machine agent
   182  	anAuthorizer := s.authorizer
   183  	anAuthorizer.Tag = names.NewUnitTag("ubuntu/1")
   184  	aNetworker, err := networker.NewNetworkerAPI(s.State, s.resources, anAuthorizer)
   185  	c.Assert(err, gc.ErrorMatches, "permission denied")
   186  	c.Assert(aNetworker, gc.IsNil)
   187  }
   188  
   189  func (s *networkerSuite) TestMachineNetworkConfigPermissions(c *gc.C) {
   190  	args := params.Entities{Entities: []params.Entity{
   191  		{Tag: "service-bar"},
   192  		{Tag: "foo-42"},
   193  		{Tag: "unit-mysql-0"},
   194  		{Tag: "service-mysql"},
   195  		{Tag: "user-foo"},
   196  		{Tag: "machine-1"},
   197  		{Tag: "machine-0-lxc-42"},
   198  	}}
   199  	results, err := s.networker.MachineNetworkConfig(args)
   200  	c.Assert(err, jc.ErrorIsNil)
   201  	c.Assert(results, gc.DeepEquals, params.MachineNetworkConfigResults{
   202  		Results: []params.MachineNetworkConfigResult{
   203  			{Error: apiservertesting.ErrUnauthorized},
   204  			{Error: apiservertesting.ErrUnauthorized},
   205  			{Error: apiservertesting.ErrUnauthorized},
   206  			{Error: apiservertesting.ErrUnauthorized},
   207  			{Error: apiservertesting.ErrUnauthorized},
   208  			{Error: apiservertesting.ErrUnauthorized},
   209  			{Error: apiservertesting.NotFoundError("machine 0/lxc/42")},
   210  		},
   211  	})
   212  }
   213  
   214  type orderedNetwork []params.NetworkConfig
   215  
   216  func (o orderedNetwork) Len() int {
   217  	return len(o)
   218  }
   219  
   220  func (o orderedNetwork) Less(i, j int) bool {
   221  	if o[i].MACAddress < o[j].MACAddress {
   222  		return true
   223  	}
   224  	if o[i].MACAddress > o[j].MACAddress {
   225  		return false
   226  	}
   227  	if o[i].CIDR < o[j].CIDR {
   228  		return true
   229  	}
   230  	if o[i].CIDR > o[j].CIDR {
   231  		return false
   232  	}
   233  	if o[i].NetworkName < o[j].NetworkName {
   234  		return true
   235  	}
   236  	if o[i].NetworkName > o[j].NetworkName {
   237  		return false
   238  	}
   239  	return o[i].VLANTag < o[j].VLANTag
   240  }
   241  
   242  func (o orderedNetwork) Swap(i, j int) {
   243  	o[i], o[j] = o[j], o[i]
   244  }
   245  
   246  func (s *networkerSuite) TestMachineNetworkConfig(c *gc.C) {
   247  	// TODO(bogdanteleaga): Find out what's the problem with this test
   248  	// It seems to work on some machines
   249  	if runtime.GOOS == "windows" {
   250  		c.Skip("bug 1403084: currently does not work on windows")
   251  	}
   252  	// Expected results of MachineNetworkConfig for a machine and containers
   253  	expectedMachineConfig := []params.NetworkConfig{{
   254  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   255  		CIDR:          "0.1.2.0/24",
   256  		NetworkName:   "net1",
   257  		ProviderId:    "net1",
   258  		VLANTag:       0,
   259  		InterfaceName: "eth0",
   260  	}, {
   261  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   262  		CIDR:          "0.1.2.0/24",
   263  		NetworkName:   "net1",
   264  		ProviderId:    "net1",
   265  		VLANTag:       0,
   266  		InterfaceName: "eth1",
   267  	}, {
   268  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   269  		CIDR:          "0.2.2.0/24",
   270  		NetworkName:   "vlan42",
   271  		ProviderId:    "vlan42",
   272  		VLANTag:       42,
   273  		InterfaceName: "eth1",
   274  	}, {
   275  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   276  		CIDR:          "0.3.2.0/24",
   277  		NetworkName:   "vlan69",
   278  		ProviderId:    "vlan69",
   279  		VLANTag:       69,
   280  		InterfaceName: "eth0",
   281  	}, {
   282  		MACAddress:    "aa:bb:cc:dd:ee:f2",
   283  		CIDR:          "0.5.2.0/24",
   284  		NetworkName:   "net2",
   285  		ProviderId:    "net2",
   286  		VLANTag:       0,
   287  		InterfaceName: "eth2",
   288  		Disabled:      true,
   289  	}}
   290  	expectedContainerConfig := []params.NetworkConfig{{
   291  		MACAddress:    "aa:bb:cc:dd:ee:e0",
   292  		CIDR:          "0.1.2.0/24",
   293  		NetworkName:   "net1",
   294  		ProviderId:    "net1",
   295  		VLANTag:       0,
   296  		InterfaceName: "eth0",
   297  	}, {
   298  		MACAddress:    "aa:bb:cc:dd:ee:e1",
   299  		CIDR:          "0.1.2.0/24",
   300  		NetworkName:   "net1",
   301  		ProviderId:    "net1",
   302  		VLANTag:       0,
   303  		InterfaceName: "eth1",
   304  	}, {
   305  		MACAddress:    "aa:bb:cc:dd:ee:e1",
   306  		CIDR:          "0.2.2.0/24",
   307  		NetworkName:   "vlan42",
   308  		ProviderId:    "vlan42",
   309  		VLANTag:       42,
   310  		InterfaceName: "eth1",
   311  	}}
   312  	expectedNestedContainerConfig := []params.NetworkConfig{{
   313  		MACAddress:    "aa:bb:cc:dd:ee:d0",
   314  		CIDR:          "0.1.2.0/24",
   315  		NetworkName:   "net1",
   316  		ProviderId:    "net1",
   317  		VLANTag:       0,
   318  		InterfaceName: "eth0",
   319  	}}
   320  	args := params.Entities{Entities: []params.Entity{
   321  		{Tag: "machine-0"},
   322  		{Tag: "machine-0-lxc-0"},
   323  		{Tag: "machine-0-lxc-0-lxc-0"},
   324  	}}
   325  
   326  	sort.Sort(orderedNetwork(expectedMachineConfig))
   327  	sort.Sort(orderedNetwork(expectedContainerConfig))
   328  	sort.Sort(orderedNetwork(expectedNestedContainerConfig))
   329  
   330  	expected := [][]params.NetworkConfig{
   331  		expectedMachineConfig,
   332  		expectedContainerConfig,
   333  		expectedNestedContainerConfig,
   334  	}
   335  
   336  	assert := func(f func(params.Entities) (params.MachineNetworkConfigResults, error)) {
   337  		results, err := f(args)
   338  		c.Assert(err, jc.ErrorIsNil)
   339  		c.Assert(results.Results, gc.HasLen, 3)
   340  		for i, r := range results.Results {
   341  			c.Assert(r.Error, gc.IsNil)
   342  			sort.Sort(orderedNetwork(r.Config))
   343  			c.Assert(r.Config, jc.DeepEquals, expected[i])
   344  		}
   345  	}
   346  	assert(s.networker.MachineNetworkInfo)
   347  	assert(s.networker.MachineNetworkConfig)
   348  }
   349  
   350  func (s *networkerSuite) TestWatchInterfacesPermissions(c *gc.C) {
   351  	args := params.Entities{Entities: []params.Entity{
   352  		{Tag: "service-bar"},
   353  		{Tag: "foo-42"},
   354  		{Tag: "unit-mysql-0"},
   355  		{Tag: "service-mysql"},
   356  		{Tag: "user-foo"},
   357  		{Tag: "machine-1"},
   358  		{Tag: "machine-0-lxc-42"},
   359  	}}
   360  	results, err := s.networker.WatchInterfaces(args)
   361  	c.Assert(err, jc.ErrorIsNil)
   362  	c.Assert(results, gc.DeepEquals, params.NotifyWatchResults{
   363  		Results: []params.NotifyWatchResult{
   364  			{Error: apiservertesting.ErrUnauthorized},
   365  			{Error: apiservertesting.ErrUnauthorized},
   366  			{Error: apiservertesting.ErrUnauthorized},
   367  			{Error: apiservertesting.ErrUnauthorized},
   368  			{Error: apiservertesting.ErrUnauthorized},
   369  			{Error: apiservertesting.ErrUnauthorized},
   370  			{Error: apiservertesting.NotFoundError("machine 0/lxc/42")},
   371  		},
   372  	})
   373  }
   374  
   375  func (s *networkerSuite) TestWatchInterfaces(c *gc.C) {
   376  	c.Assert(s.resources.Count(), gc.Equals, 0)
   377  
   378  	args := params.Entities{Entities: []params.Entity{
   379  		{Tag: "machine-0"},
   380  		{Tag: "machine-0-lxc-0"},
   381  		{Tag: "machine-0-lxc-0-lxc-0"},
   382  	}}
   383  	result, err := s.networker.WatchInterfaces(args)
   384  	c.Assert(err, jc.ErrorIsNil)
   385  	c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{
   386  		Results: []params.NotifyWatchResult{
   387  			{NotifyWatcherId: "1"},
   388  			{NotifyWatcherId: "2"},
   389  			{NotifyWatcherId: "3"},
   390  		},
   391  	})
   392  
   393  	// Verify the resource was registered and stop when done
   394  	c.Assert(s.resources.Count(), gc.Equals, 3)
   395  	for _, watcherId := range []string{"1", "2", "3"} {
   396  		resource := s.resources.Get(watcherId)
   397  		defer statetesting.AssertStop(c, resource)
   398  
   399  		// Check that the WatchInterfaces has consumed the initial event ("returned" in
   400  		// the Watch call)
   401  		wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher))
   402  		wc.AssertNoChange()
   403  	}
   404  }