github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/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 "net" 8 "os" 9 "path/filepath" 10 "strings" 11 "time" 12 13 "github.com/juju/names" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils" 16 "github.com/juju/utils/set" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/agent" 20 "github.com/juju/juju/api" 21 apinetworker "github.com/juju/juju/api/networker" 22 "github.com/juju/juju/instance" 23 "github.com/juju/juju/juju/testing" 24 "github.com/juju/juju/state" 25 coretesting "github.com/juju/juju/testing" 26 "github.com/juju/juju/worker" 27 "github.com/juju/juju/worker/networker" 28 ) 29 30 type networkerSuite struct { 31 testing.JujuConnSuite 32 33 stateMachine *state.Machine 34 stateNetworks []state.NetworkInfo 35 stateInterfaces []state.NetworkInterfaceInfo 36 37 upInterfaces set.Strings 38 interfacesWithAddress set.Strings 39 machineInterfaces []net.Interface 40 vlanModuleLoaded bool 41 lastCommands chan []string 42 43 apiState api.Connection 44 apiFacade apinetworker.State 45 } 46 47 var _ = gc.Suite(&networkerSuite{}) 48 49 func (s *networkerSuite) SetUpTest(c *gc.C) { 50 s.JujuConnSuite.SetUpTest(c) 51 52 // Setup testing state. 53 s.setUpNetworks(c) 54 s.setUpMachine(c) 55 56 s.machineInterfaces = []net.Interface{ 57 {Index: 1, MTU: 65535, Name: "lo", Flags: net.FlagUp | net.FlagLoopback}, 58 {Index: 2, MTU: 1500, Name: "eth0", Flags: net.FlagUp}, 59 {Index: 3, MTU: 1500, Name: "eth1"}, 60 {Index: 4, MTU: 1500, Name: "eth2"}, 61 } 62 s.PatchValue(&networker.InterfaceIsUp, func(name string) bool { 63 return s.upInterfaces.Contains(name) 64 }) 65 s.PatchValue(&networker.InterfaceHasAddress, func(name string) bool { 66 return s.interfacesWithAddress.Contains(name) 67 }) 68 s.PatchValue(&networker.ExecuteCommands, func(commands []string) error { 69 return s.executeCommandsHook(c, commands) 70 }) 71 s.PatchValue(&networker.Interfaces, func() ([]net.Interface, error) { 72 return s.machineInterfaces, nil 73 }) 74 75 // Create the networker API facade. 76 s.apiFacade = s.apiState.Networker() 77 c.Assert(s.apiFacade, gc.NotNil) 78 } 79 80 func (s *networkerSuite) TestStartStop(c *gc.C) { 81 nw := s.newNetworker(c, true) 82 c.Assert(worker.Stop(nw), gc.IsNil) 83 } 84 85 func (s *networkerSuite) TestConfigPaths(c *gc.C) { 86 nw, configDir := s.newCustomNetworker(c, s.apiFacade, s.stateMachine.Id(), true, true) 87 defer worker.Stop(nw) 88 89 c.Assert(nw.ConfigBaseDir(), gc.Equals, configDir) 90 subdir := filepath.Join(configDir, "interfaces.d") 91 c.Assert(nw.ConfigSubDir(), gc.Equals, subdir) 92 c.Assert(nw.ConfigFile(""), gc.Equals, filepath.Join(configDir, "interfaces")) 93 c.Assert(nw.ConfigFile("ethX.42"), gc.Equals, filepath.Join(subdir, "ethX.42.cfg")) 94 } 95 96 func (s *networkerSuite) TestSafeNetworkerCannotWriteConfig(c *gc.C) { 97 c.Skip("enable once the networker is enabled again") 98 99 nw := s.newNetworker(c, false) 100 defer worker.Stop(nw) 101 c.Assert(nw.IntrusiveMode(), jc.IsFalse) 102 103 select { 104 case cmds := <-s.lastCommands: 105 c.Fatalf("no commands expected, got %v", cmds) 106 case <-time.After(coretesting.ShortWait): 107 s.assertNoConfig(c, nw, "", "lo", "eth0", "eth1", "eth1.42", "eth0.69") 108 } 109 } 110 111 func (s *networkerSuite) TestNormalNetworkerCanWriteConfigAndLoadsVLANModule(c *gc.C) { 112 c.Skip("enable once the networker is enabled again") 113 114 nw := s.newNetworker(c, true) 115 defer worker.Stop(nw) 116 c.Assert(nw.IntrusiveMode(), jc.IsTrue) 117 118 select { 119 case <-s.lastCommands: 120 // VLAN module loading commands is one of the first things the 121 // worker does, so if it happened, we can assume commands are 122 // executed. 123 c.Assert(s.vlanModuleLoaded, jc.IsTrue) 124 c.Assert(nw.IsVLANModuleLoaded(), jc.IsTrue) 125 case <-time.After(coretesting.ShortWait): 126 c.Fatalf("commands expected but not executed") 127 } 128 c.Assert(nw.IsPrimaryInterfaceOrLoopback("lo"), jc.IsTrue) 129 c.Assert(nw.IsPrimaryInterfaceOrLoopback("eth0"), jc.IsTrue) 130 s.assertHaveConfig(c, nw, "", "eth0", "eth1", "eth1.42", "eth0.69") 131 } 132 133 func (s *networkerSuite) TestPrimaryOrLoopbackInterfacesAreSkipped(c *gc.C) { 134 c.Skip("enable once the networker is enabled again") 135 136 // Reset what's considered up, so we can test eth0 and lo are not 137 // touched. 138 s.upInterfaces = make(set.Strings) 139 s.interfacesWithAddress = make(set.Strings) 140 141 nw, _ := s.newCustomNetworker(c, s.apiFacade, s.stateMachine.Id(), true, false) 142 defer worker.Stop(nw) 143 144 timeout := time.After(coretesting.LongWait) 145 for { 146 select { 147 case <-s.lastCommands: 148 if !s.vlanModuleLoaded { 149 // VLAN module loading commands is one of the first things 150 // the worker does, so if hasn't happened, we wait a bit more. 151 continue 152 } 153 c.Assert(s.upInterfaces.Contains("lo"), jc.IsFalse) 154 c.Assert(s.upInterfaces.Contains("eth0"), jc.IsFalse) 155 if s.upInterfaces.Contains("eth1") { 156 // If we run ifup eth1, we successfully skipped lo and 157 // eth0. 158 s.assertHaveConfig(c, nw, "", "eth0", "eth1", "eth1.42", "eth0.69") 159 return 160 } 161 case <-timeout: 162 c.Fatalf("commands expected but not executed") 163 } 164 } 165 } 166 167 func (s *networkerSuite) TestDisabledInterfacesAreBroughtDown(c *gc.C) { 168 c.Skip("enable once the networker is enabled again") 169 170 // Simulate eth1 is up and then disable it, so we can test it's 171 // brought down. Also test the VLAN interface eth1.42 is also 172 // brought down, as it's physical interface eth1 is disabled. 173 s.upInterfaces = set.NewStrings("lo", "eth0", "eth1") 174 s.interfacesWithAddress = set.NewStrings("lo", "eth0", "eth1") 175 s.machineInterfaces[2].Flags |= net.FlagUp 176 ifaces, err := s.stateMachine.NetworkInterfaces() 177 c.Assert(err, jc.ErrorIsNil) 178 err = ifaces[1].Disable() 179 c.Assert(err, jc.ErrorIsNil) 180 // We verify that setting the parent physical interface to 181 // disabled leads to setting any VLAN intefaces depending on it to 182 // get disabled as well. 183 err = ifaces[2].Refresh() 184 c.Assert(err, jc.ErrorIsNil) 185 c.Assert(ifaces[2].IsDisabled(), jc.IsTrue) 186 187 nw, _ := s.newCustomNetworker(c, s.apiFacade, s.stateMachine.Id(), true, false) 188 defer worker.Stop(nw) 189 190 timeout := time.After(coretesting.LongWait) 191 for { 192 select { 193 case cmds := <-s.lastCommands: 194 if !strings.Contains(strings.Join(cmds, " "), "ifdown") { 195 // No down commands yet, keep waiting. 196 continue 197 } 198 c.Assert(s.upInterfaces.Contains("eth1"), jc.IsFalse) 199 c.Assert(s.machineInterfaces[2].Flags&net.FlagUp, gc.Equals, net.Flags(0)) 200 c.Assert(s.upInterfaces.Contains("eth1.42"), jc.IsFalse) 201 s.assertNoConfig(c, nw, "eth1", "eth1.42") 202 s.assertHaveConfig(c, nw, "", "eth0", "eth0.69") 203 return 204 case <-timeout: 205 c.Fatalf("commands expected but not executed") 206 } 207 } 208 } 209 210 func (s *networkerSuite) TestIsRunningInLXC(c *gc.C) { 211 tests := []struct { 212 machineId string 213 result bool 214 }{ 215 {"0", false}, 216 {"1/lxc/0", true}, 217 {"2/kvm/1", false}, 218 {"3/lxc/0/lxc/1", true}, 219 {"4/lxc/0/kvm/1", false}, 220 {"5/lxc/1/kvm/1/lxc/3", true}, 221 } 222 for i, t := range tests { 223 c.Logf("test %d: %q -> %v", i, t.machineId, t.result) 224 c.Check(networker.IsRunningInLXC(t.machineId), gc.Equals, t.result) 225 } 226 } 227 228 func (s *networkerSuite) TestNoModprobeWhenRunningInLXC(c *gc.C) { 229 c.Skip("enable once the networker is enabled again") 230 231 // Create a new container. 232 template := state.MachineTemplate{ 233 Series: coretesting.FakeDefaultSeries, 234 Jobs: []state.MachineJob{state.JobHostUnits}, 235 } 236 lxcMachine, err := s.State.AddMachineInsideMachine(template, s.stateMachine.Id(), instance.LXC) 237 c.Assert(err, jc.ErrorIsNil) 238 password, err := utils.RandomPassword() 239 c.Assert(err, jc.ErrorIsNil) 240 err = lxcMachine.SetPassword(password) 241 c.Assert(err, jc.ErrorIsNil) 242 lxcInterfaces := []state.NetworkInterfaceInfo{{ 243 MACAddress: "aa:bb:cc:dd:02:f0", 244 InterfaceName: "eth0.123", 245 NetworkName: "vlan123", 246 IsVirtual: true, 247 Disabled: false, 248 }} 249 s.machineInterfaces = []net.Interface{ 250 {Index: 1, MTU: 65535, Name: "lo", Flags: net.FlagUp | net.FlagLoopback}, 251 {Index: 2, MTU: 1500, Name: "eth0", Flags: net.FlagUp}, 252 } 253 254 err = lxcMachine.SetInstanceInfo("i-am-lxc", "fake_nonce", nil, s.stateNetworks, lxcInterfaces, nil, nil) 255 c.Assert(err, jc.ErrorIsNil) 256 257 // Login to the API as the machine agent of lxcMachine. 258 lxcState := s.OpenAPIAsMachine(c, lxcMachine.Tag(), password, "fake_nonce") 259 c.Assert(lxcState, gc.NotNil) 260 lxcFacade := lxcState.Networker() 261 c.Assert(lxcFacade, gc.NotNil) 262 263 // Create and setup networker for the LXC machine. 264 nw, _ := s.newCustomNetworker(c, lxcFacade, lxcMachine.Id(), true, true) 265 defer worker.Stop(nw) 266 267 timeout := time.After(coretesting.LongWait) 268 for { 269 select { 270 case cmds := <-s.lastCommands: 271 if !s.upInterfaces.Contains("eth0.123") { 272 c.Fatalf("expected command ifup eth0.123, got %v", cmds) 273 } 274 c.Assert(s.vlanModuleLoaded, jc.IsFalse) 275 c.Assert(nw.IsVLANModuleLoaded(), jc.IsFalse) 276 s.assertHaveConfig(c, nw, "", "eth0.123") 277 s.assertNoConfig(c, nw, "lo", "eth0") 278 return 279 case <-timeout: 280 c.Fatalf("no commands executed!") 281 } 282 } 283 } 284 285 type mockConfig struct { 286 agent.Config 287 tag names.Tag 288 } 289 290 func (mock *mockConfig) Tag() names.Tag { 291 return mock.tag 292 } 293 294 func agentConfig(machineId string) agent.Config { 295 return &mockConfig{tag: names.NewMachineTag(machineId)} 296 } 297 298 // Create several networks. 299 func (s *networkerSuite) setUpNetworks(c *gc.C) { 300 s.stateNetworks = []state.NetworkInfo{{ 301 Name: "net1", 302 ProviderId: "net1", 303 CIDR: "0.1.2.0/24", 304 VLANTag: 0, 305 }, { 306 Name: "vlan42", 307 ProviderId: "vlan42", 308 CIDR: "0.2.2.0/24", 309 VLANTag: 42, 310 }, { 311 Name: "vlan69", 312 ProviderId: "vlan69", 313 CIDR: "0.3.2.0/24", 314 VLANTag: 69, 315 }, { 316 Name: "vlan123", 317 ProviderId: "vlan123", 318 CIDR: "0.4.2.0/24", 319 VLANTag: 123, 320 }, { 321 Name: "net2", 322 ProviderId: "net2", 323 CIDR: "0.5.2.0/24", 324 VLANTag: 0, 325 }} 326 } 327 328 func (s *networkerSuite) setUpMachine(c *gc.C) { 329 var err error 330 s.stateMachine, err = s.State.AddMachine("quantal", state.JobHostUnits) 331 c.Assert(err, jc.ErrorIsNil) 332 password, err := utils.RandomPassword() 333 c.Assert(err, jc.ErrorIsNil) 334 err = s.stateMachine.SetPassword(password) 335 c.Assert(err, jc.ErrorIsNil) 336 s.stateInterfaces = []state.NetworkInterfaceInfo{{ 337 MACAddress: "aa:bb:cc:dd:ee:f0", 338 InterfaceName: "eth0", 339 NetworkName: "net1", 340 IsVirtual: false, 341 }, { 342 MACAddress: "aa:bb:cc:dd:ee:f1", 343 InterfaceName: "eth1", 344 NetworkName: "net1", 345 IsVirtual: false, 346 }, { 347 MACAddress: "aa:bb:cc:dd:ee:f1", 348 InterfaceName: "eth1.42", 349 NetworkName: "vlan42", 350 IsVirtual: true, 351 }, { 352 MACAddress: "aa:bb:cc:dd:ee:f0", 353 InterfaceName: "eth0.69", 354 NetworkName: "vlan69", 355 IsVirtual: true, 356 }, { 357 MACAddress: "aa:bb:cc:dd:ee:f2", 358 InterfaceName: "eth2", 359 NetworkName: "net2", 360 IsVirtual: false, 361 }} 362 err = s.stateMachine.SetInstanceInfo("i-am", "fake_nonce", nil, s.stateNetworks, s.stateInterfaces, nil, nil) 363 c.Assert(err, jc.ErrorIsNil) 364 s.apiState = s.OpenAPIAsMachine(c, s.stateMachine.Tag(), password, "fake_nonce") 365 c.Assert(s.apiState, gc.NotNil) 366 } 367 368 func (s *networkerSuite) executeCommandsHook(c *gc.C, commands []string) error { 369 markUp := func(name string, isUp bool) { 370 for i, iface := range s.machineInterfaces { 371 if iface.Name == name { 372 if isUp { 373 iface.Flags |= net.FlagUp 374 } else { 375 iface.Flags &= ^net.FlagUp 376 } 377 s.machineInterfaces[i] = iface 378 return 379 } 380 } 381 } 382 for _, cmd := range commands { 383 args := strings.Split(cmd, " ") 384 if len(args) >= 2 { 385 what, name := args[0], args[1] 386 switch what { 387 case "ifup": 388 s.upInterfaces.Add(name) 389 s.interfacesWithAddress.Add(name) 390 markUp(name, true) 391 c.Logf("bringing %q up", name) 392 case "ifdown": 393 s.upInterfaces.Remove(name) 394 s.interfacesWithAddress.Remove(name) 395 markUp(name, false) 396 c.Logf("bringing %q down", name) 397 } 398 } 399 if strings.Contains(cmd, "modprobe 8021q") { 400 s.vlanModuleLoaded = true 401 c.Logf("VLAN module loaded") 402 } 403 } 404 // Send the commands without blocking. 405 select { 406 case s.lastCommands <- commands: 407 default: 408 } 409 return nil 410 } 411 412 func (s *networkerSuite) newCustomNetworker( 413 c *gc.C, 414 facade apinetworker.State, 415 machineId string, 416 intrusiveMode bool, 417 initInterfaces bool, 418 ) (*networker.Networker, string) { 419 if initInterfaces { 420 s.upInterfaces = set.NewStrings("lo", "eth0") 421 s.interfacesWithAddress = set.NewStrings("lo", "eth0") 422 } 423 s.lastCommands = make(chan []string) 424 s.vlanModuleLoaded = false 425 configDir := c.MkDir() 426 427 nw, err := networker.NewNetworker(facade, agentConfig(machineId), intrusiveMode, configDir) 428 c.Assert(err, jc.ErrorIsNil) 429 c.Assert(nw, gc.NotNil) 430 431 return nw, configDir 432 } 433 434 func (s *networkerSuite) newNetworker(c *gc.C, canWriteConfig bool) *networker.Networker { 435 nw, _ := s.newCustomNetworker(c, s.apiFacade, s.stateMachine.Id(), canWriteConfig, true) 436 return nw 437 } 438 439 func (s *networkerSuite) assertNoConfig(c *gc.C, nw *networker.Networker, interfaceNames ...string) { 440 for _, name := range interfaceNames { 441 fullPath := nw.ConfigFile(name) 442 _, err := os.Stat(fullPath) 443 c.Assert(err, jc.Satisfies, os.IsNotExist) 444 } 445 } 446 447 func (s *networkerSuite) assertHaveConfig(c *gc.C, nw *networker.Networker, interfaceNames ...string) { 448 for _, name := range interfaceNames { 449 fullPath := nw.ConfigFile(name) 450 _, err := os.Stat(fullPath) 451 c.Assert(err, jc.ErrorIsNil) 452 } 453 }