github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/openstack/provider_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package openstack 5 6 import ( 7 gitjujutesting "github.com/juju/testing" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 "gopkg.in/goose.v1/nova" 11 12 "github.com/juju/juju/cloud" 13 "github.com/juju/juju/environs" 14 "github.com/juju/juju/network" 15 ) 16 17 // localTests contains tests which do not require a live service or test double to run. 18 type localTests struct { 19 gitjujutesting.IsolationSuite 20 } 21 22 var _ = gc.Suite(&localTests{}) 23 24 // ported from lp:juju/juju/providers/openstack/tests/test_machine.py 25 var addressTests = []struct { 26 summary string 27 floatingIP string 28 private []nova.IPAddress 29 public []nova.IPAddress 30 networks []string 31 expected string 32 failure error 33 }{{ 34 summary: "missing", 35 expected: "", 36 }, { 37 summary: "empty", 38 private: []nova.IPAddress{}, 39 networks: []string{"private"}, 40 expected: "", 41 }, { 42 summary: "private IPv4 only", 43 private: []nova.IPAddress{{4, "192.168.0.1"}}, 44 networks: []string{"private"}, 45 expected: "192.168.0.1", 46 }, { 47 summary: "private IPv6 only", 48 private: []nova.IPAddress{{6, "fc00::1"}}, 49 networks: []string{"private"}, 50 expected: "fc00::1", 51 }, { 52 summary: "private only, both IPv4 and IPv6", 53 private: []nova.IPAddress{{4, "192.168.0.1"}, {6, "fc00::1"}}, 54 networks: []string{"private"}, 55 expected: "192.168.0.1", 56 }, { 57 summary: "private only, both IPv6 and IPv4", 58 private: []nova.IPAddress{{6, "fc00::1"}, {4, "192.168.0.1"}}, 59 networks: []string{"private"}, 60 expected: "fc00::1", 61 }, { 62 summary: "private IPv4 plus (HP cloud)", 63 private: []nova.IPAddress{{4, "10.0.0.1"}, {4, "8.8.4.4"}}, 64 networks: []string{"private"}, 65 expected: "8.8.4.4", 66 }, { 67 summary: "public IPv4 only", 68 public: []nova.IPAddress{{4, "8.8.8.8"}}, 69 networks: []string{"", "public"}, 70 expected: "8.8.8.8", 71 }, { 72 summary: "public IPv6 only", 73 public: []nova.IPAddress{{6, "2001:db8::1"}}, 74 networks: []string{"", "public"}, 75 expected: "2001:db8::1", 76 }, { 77 summary: "public only, both IPv4 and IPv6", 78 public: []nova.IPAddress{{4, "8.8.8.8"}, {6, "2001:db8::1"}}, 79 networks: []string{"", "public"}, 80 expected: "8.8.8.8", 81 }, { 82 summary: "public only, both IPv6 and IPv4", 83 public: []nova.IPAddress{{6, "2001:db8::1"}, {4, "8.8.8.8"}}, 84 networks: []string{"", "public"}, 85 expected: "2001:db8::1", 86 }, { 87 summary: "public and private both IPv4", 88 private: []nova.IPAddress{{4, "10.0.0.4"}}, 89 public: []nova.IPAddress{{4, "8.8.4.4"}}, 90 networks: []string{"private", "public"}, 91 expected: "8.8.4.4", 92 }, { 93 summary: "public and private both IPv6", 94 private: []nova.IPAddress{{6, "fc00::1"}}, 95 public: []nova.IPAddress{{6, "2001:db8::1"}}, 96 networks: []string{"private", "public"}, 97 expected: "2001:db8::1", 98 }, { 99 summary: "public, private, and localhost IPv4", 100 private: []nova.IPAddress{{4, "127.0.0.4"}, {4, "192.168.0.1"}}, 101 public: []nova.IPAddress{{4, "8.8.8.8"}}, 102 networks: []string{"private", "public"}, 103 expected: "8.8.8.8", 104 }, { 105 summary: "public, private, and localhost IPv6", 106 private: []nova.IPAddress{{6, "::1"}, {6, "fc00::1"}}, 107 public: []nova.IPAddress{{6, "2001:db8::1"}}, 108 networks: []string{"private", "public"}, 109 expected: "2001:db8::1", 110 }, { 111 summary: "public, private, and localhost - both IPv4 and IPv6", 112 private: []nova.IPAddress{{4, "127.0.0.4"}, {4, "192.168.0.1"}, {6, "::1"}, {6, "fc00::1"}}, 113 public: []nova.IPAddress{{4, "8.8.8.8"}, {6, "2001:db8::1"}}, 114 networks: []string{"private", "public"}, 115 expected: "8.8.8.8", 116 }, { 117 summary: "public, private, and localhost - both IPv6 and IPv4", 118 private: []nova.IPAddress{{6, "::1"}, {6, "fc00::1"}, {4, "127.0.0.4"}, {4, "192.168.0.1"}}, 119 public: []nova.IPAddress{{6, "2001:db8::1"}, {4, "8.8.8.8"}}, 120 networks: []string{"private", "public"}, 121 expected: "2001:db8::1", 122 }, { 123 summary: "custom only IPv4", 124 private: []nova.IPAddress{{4, "192.168.0.1"}}, 125 networks: []string{"special"}, 126 expected: "192.168.0.1", 127 }, { 128 summary: "custom only IPv6", 129 private: []nova.IPAddress{{6, "fc00::1"}}, 130 networks: []string{"special"}, 131 expected: "fc00::1", 132 }, { 133 summary: "custom only - both IPv4 and IPv6", 134 private: []nova.IPAddress{{4, "192.168.0.1"}, {6, "fc00::1"}}, 135 networks: []string{"special"}, 136 expected: "192.168.0.1", 137 }, { 138 summary: "custom only - both IPv6 and IPv4", 139 private: []nova.IPAddress{{6, "fc00::1"}, {4, "192.168.0.1"}}, 140 networks: []string{"special"}, 141 expected: "fc00::1", 142 }, { 143 summary: "custom and public IPv4", 144 private: []nova.IPAddress{{4, "172.16.0.1"}}, 145 public: []nova.IPAddress{{4, "8.8.8.8"}}, 146 networks: []string{"special", "public"}, 147 expected: "8.8.8.8", 148 }, { 149 summary: "custom and public IPv6", 150 private: []nova.IPAddress{{6, "fc00::1"}}, 151 public: []nova.IPAddress{{6, "2001:db8::1"}}, 152 networks: []string{"special", "public"}, 153 expected: "2001:db8::1", 154 }, { 155 summary: "custom and public - both IPv4 and IPv6", 156 private: []nova.IPAddress{{4, "172.16.0.1"}, {6, "fc00::1"}}, 157 public: []nova.IPAddress{{4, "8.8.8.8"}, {6, "2001:db8::1"}}, 158 networks: []string{"special", "public"}, 159 expected: "8.8.8.8", 160 }, { 161 summary: "custom and public - both IPv6 and IPv4", 162 private: []nova.IPAddress{{6, "fc00::1"}, {4, "172.16.0.1"}}, 163 public: []nova.IPAddress{{6, "2001:db8::1"}, {4, "8.8.8.8"}}, 164 networks: []string{"special", "public"}, 165 expected: "2001:db8::1", 166 }, { 167 summary: "floating and public, same address", 168 floatingIP: "8.8.8.8", 169 public: []nova.IPAddress{{4, "8.8.8.8"}}, 170 networks: []string{"", "public"}, 171 expected: "8.8.8.8", 172 }, { 173 summary: "floating and public, different address", 174 floatingIP: "8.8.4.4", 175 public: []nova.IPAddress{{4, "8.8.8.8"}}, 176 networks: []string{"", "public"}, 177 expected: "8.8.4.4", 178 }, { 179 summary: "floating and private", 180 floatingIP: "8.8.4.4", 181 private: []nova.IPAddress{{4, "10.0.0.1"}}, 182 networks: []string{"private"}, 183 expected: "8.8.4.4", 184 }, { 185 summary: "floating, custom and public", 186 floatingIP: "8.8.4.4", 187 private: []nova.IPAddress{{4, "172.16.0.1"}}, 188 public: []nova.IPAddress{{4, "8.8.8.8"}}, 189 networks: []string{"special", "public"}, 190 expected: "8.8.4.4", 191 }} 192 193 func (t *localTests) TestGetServerAddresses(c *gc.C) { 194 for i, t := range addressTests { 195 c.Logf("#%d. %s -> %s (%v)", i, t.summary, t.expected, t.failure) 196 addresses := make(map[string][]nova.IPAddress) 197 if t.private != nil { 198 if len(t.networks) < 1 { 199 addresses["private"] = t.private 200 } else { 201 addresses[t.networks[0]] = t.private 202 } 203 } 204 if t.public != nil { 205 if len(t.networks) < 2 { 206 addresses["public"] = t.public 207 } else { 208 addresses[t.networks[1]] = t.public 209 } 210 } 211 addr := InstanceAddress(t.floatingIP, addresses) 212 c.Assert(addr, gc.Equals, t.expected) 213 } 214 } 215 216 func (*localTests) TestPortsToRuleInfo(c *gc.C) { 217 groupId := "groupid" 218 testCases := []struct { 219 about string 220 ports []network.PortRange 221 expected []nova.RuleInfo 222 }{{ 223 about: "single port", 224 ports: []network.PortRange{{ 225 FromPort: 80, 226 ToPort: 80, 227 Protocol: "tcp", 228 }}, 229 expected: []nova.RuleInfo{{ 230 IPProtocol: "tcp", 231 FromPort: 80, 232 ToPort: 80, 233 Cidr: "0.0.0.0/0", 234 ParentGroupId: groupId, 235 }}, 236 }, { 237 about: "multiple ports", 238 ports: []network.PortRange{{ 239 FromPort: 80, 240 ToPort: 82, 241 Protocol: "tcp", 242 }}, 243 expected: []nova.RuleInfo{{ 244 IPProtocol: "tcp", 245 FromPort: 80, 246 ToPort: 82, 247 Cidr: "0.0.0.0/0", 248 ParentGroupId: groupId, 249 }}, 250 }, { 251 about: "multiple port ranges", 252 ports: []network.PortRange{{ 253 FromPort: 80, 254 ToPort: 82, 255 Protocol: "tcp", 256 }, { 257 FromPort: 100, 258 ToPort: 120, 259 Protocol: "tcp", 260 }}, 261 expected: []nova.RuleInfo{{ 262 IPProtocol: "tcp", 263 FromPort: 80, 264 ToPort: 82, 265 Cidr: "0.0.0.0/0", 266 ParentGroupId: groupId, 267 }, { 268 IPProtocol: "tcp", 269 FromPort: 100, 270 ToPort: 120, 271 Cidr: "0.0.0.0/0", 272 ParentGroupId: groupId, 273 }}, 274 }} 275 276 for i, t := range testCases { 277 c.Logf("test %d: %s", i, t.about) 278 rules := PortsToRuleInfo(groupId, t.ports) 279 c.Check(len(rules), gc.Equals, len(t.expected)) 280 c.Check(rules, gc.DeepEquals, t.expected) 281 } 282 } 283 284 func (*localTests) TestRuleMatchesPortRange(c *gc.C) { 285 proto_tcp := "tcp" 286 proto_udp := "udp" 287 port_80 := 80 288 port_85 := 85 289 290 testCases := []struct { 291 about string 292 ports network.PortRange 293 rule nova.SecurityGroupRule 294 expected bool 295 }{{ 296 about: "single port", 297 ports: network.PortRange{ 298 FromPort: 80, 299 ToPort: 80, 300 Protocol: "tcp", 301 }, 302 rule: nova.SecurityGroupRule{ 303 IPProtocol: &proto_tcp, 304 FromPort: &port_80, 305 ToPort: &port_80, 306 }, 307 expected: true, 308 }, { 309 about: "multiple port", 310 ports: network.PortRange{ 311 FromPort: port_80, 312 ToPort: port_85, 313 Protocol: proto_tcp, 314 }, 315 rule: nova.SecurityGroupRule{ 316 IPProtocol: &proto_tcp, 317 FromPort: &port_80, 318 ToPort: &port_85, 319 }, 320 expected: true, 321 }, { 322 about: "nil rule components", 323 ports: network.PortRange{ 324 FromPort: port_80, 325 ToPort: port_85, 326 Protocol: proto_tcp, 327 }, 328 rule: nova.SecurityGroupRule{ 329 IPProtocol: nil, 330 FromPort: nil, 331 ToPort: nil, 332 }, 333 expected: false, 334 }, { 335 about: "mismatched port range and rule", 336 ports: network.PortRange{ 337 FromPort: port_80, 338 ToPort: port_85, 339 Protocol: proto_tcp, 340 }, 341 rule: nova.SecurityGroupRule{ 342 IPProtocol: &proto_udp, 343 FromPort: &port_80, 344 ToPort: &port_80, 345 }, 346 expected: false, 347 }} 348 for i, t := range testCases { 349 c.Logf("test %d: %s", i, t.about) 350 c.Check(RuleMatchesPortRange(t.rule, t.ports), gc.Equals, t.expected) 351 } 352 } 353 354 func (s *localTests) TestDetectRegionsNoRegionName(c *gc.C) { 355 _, err := s.detectRegions(c) 356 c.Assert(err, gc.ErrorMatches, "OS_REGION_NAME environment variable not set") 357 } 358 359 func (s *localTests) TestDetectRegionsNoAuthURL(c *gc.C) { 360 s.PatchEnvironment("OS_REGION_NAME", "oceania") 361 _, err := s.detectRegions(c) 362 c.Assert(err, gc.ErrorMatches, "OS_AUTH_URL environment variable not set") 363 } 364 365 func (s *localTests) TestDetectRegions(c *gc.C) { 366 s.PatchEnvironment("OS_REGION_NAME", "oceania") 367 s.PatchEnvironment("OS_AUTH_URL", "http://keystone.internal") 368 regions, err := s.detectRegions(c) 369 c.Assert(err, jc.ErrorIsNil) 370 c.Assert(regions, jc.DeepEquals, []cloud.Region{ 371 {Name: "oceania", Endpoint: "http://keystone.internal"}, 372 }) 373 } 374 375 func (s *localTests) detectRegions(c *gc.C) ([]cloud.Region, error) { 376 provider, err := environs.Provider("openstack") 377 c.Assert(err, jc.ErrorIsNil) 378 c.Assert(provider, gc.Implements, new(environs.CloudRegionDetector)) 379 return provider.(environs.CloudRegionDetector).DetectRegions() 380 } 381 382 type providerUnitTests struct{} 383 384 var _ = gc.Suite(&providerUnitTests{}) 385 386 func (s *providerUnitTests) TestIdentityClientVersion_BadURLErrors(c *gc.C) { 387 _, err := identityClientVersion("abc123") 388 c.Check(err, gc.Not(jc.ErrorIsNil)) 389 } 390 391 func (s *providerUnitTests) TestIdentityClientVersion_ParsesGoodURL(c *gc.C) { 392 version, err := identityClientVersion("https://keystone.internal/v2.0") 393 c.Assert(err, jc.ErrorIsNil) 394 c.Check(version, gc.Equals, 2) 395 396 version, err = identityClientVersion("https://keystone.internal/v3.0/") 397 c.Assert(err, jc.ErrorIsNil) 398 c.Check(version, gc.Equals, 3) 399 400 version, err = identityClientVersion("https://keystone.internal/v2/") 401 c.Assert(err, jc.ErrorIsNil) 402 c.Check(version, gc.Equals, 2) 403 }