github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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 }