github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 IPv4 plus (what HP cloud used to do)",
    58  	private:  []nova.IPAddress{{4, "10.0.0.1"}, {4, "8.8.4.4"}},
    59  	networks: []string{"private"},
    60  	expected: "8.8.4.4",
    61  }, {
    62  	summary:  "public IPv4 only",
    63  	public:   []nova.IPAddress{{4, "8.8.8.8"}},
    64  	networks: []string{"", "public"},
    65  	expected: "8.8.8.8",
    66  }, {
    67  	summary:  "public IPv6 only",
    68  	public:   []nova.IPAddress{{6, "2001:db8::1"}},
    69  	networks: []string{"", "public"},
    70  	expected: "2001:db8::1",
    71  }, {
    72  	summary:  "public only, both IPv4 and IPv6",
    73  	public:   []nova.IPAddress{{4, "8.8.8.8"}, {6, "2001:db8::1"}},
    74  	networks: []string{"", "public"},
    75  	expected: "8.8.8.8",
    76  }, {
    77  	summary:  "public and private both IPv4",
    78  	private:  []nova.IPAddress{{4, "10.0.0.4"}},
    79  	public:   []nova.IPAddress{{4, "8.8.4.4"}},
    80  	networks: []string{"private", "public"},
    81  	expected: "8.8.4.4",
    82  }, {
    83  	summary:  "public and private both IPv6",
    84  	private:  []nova.IPAddress{{6, "fc00::1"}},
    85  	public:   []nova.IPAddress{{6, "2001:db8::1"}},
    86  	networks: []string{"private", "public"},
    87  	expected: "2001:db8::1",
    88  }, {
    89  	summary:  "public, private, and localhost IPv4",
    90  	private:  []nova.IPAddress{{4, "127.0.0.4"}, {4, "192.168.0.1"}},
    91  	public:   []nova.IPAddress{{4, "8.8.8.8"}},
    92  	networks: []string{"private", "public"},
    93  	expected: "8.8.8.8",
    94  }, {
    95  	summary:  "public, private, and localhost IPv6",
    96  	private:  []nova.IPAddress{{6, "::1"}, {6, "fc00::1"}},
    97  	public:   []nova.IPAddress{{6, "2001:db8::1"}},
    98  	networks: []string{"private", "public"},
    99  	expected: "2001:db8::1",
   100  }, {
   101  	summary:  "public, private, and localhost - both IPv4 and IPv6",
   102  	private:  []nova.IPAddress{{4, "127.0.0.4"}, {4, "192.168.0.1"}, {6, "::1"}, {6, "fc00::1"}},
   103  	public:   []nova.IPAddress{{4, "8.8.8.8"}, {6, "2001:db8::1"}},
   104  	networks: []string{"private", "public"},
   105  	expected: "8.8.8.8",
   106  }, {
   107  	summary:  "custom only IPv4",
   108  	private:  []nova.IPAddress{{4, "192.168.0.1"}},
   109  	networks: []string{"special"},
   110  	expected: "192.168.0.1",
   111  }, {
   112  	summary:  "custom only IPv6",
   113  	private:  []nova.IPAddress{{6, "fc00::1"}},
   114  	networks: []string{"special"},
   115  	expected: "fc00::1",
   116  }, {
   117  	summary:  "custom only - both IPv4 and IPv6",
   118  	private:  []nova.IPAddress{{4, "192.168.0.1"}, {6, "fc00::1"}},
   119  	networks: []string{"special"},
   120  	expected: "192.168.0.1",
   121  }, {
   122  	summary:  "custom and public IPv4",
   123  	private:  []nova.IPAddress{{4, "172.16.0.1"}},
   124  	public:   []nova.IPAddress{{4, "8.8.8.8"}},
   125  	networks: []string{"special", "public"},
   126  	expected: "8.8.8.8",
   127  }, {
   128  	summary:  "custom and public IPv6",
   129  	private:  []nova.IPAddress{{6, "fc00::1"}},
   130  	public:   []nova.IPAddress{{6, "2001:db8::1"}},
   131  	networks: []string{"special", "public"},
   132  	expected: "2001:db8::1",
   133  }, {
   134  	summary:  "custom and public - both IPv4 and IPv6",
   135  	private:  []nova.IPAddress{{4, "172.16.0.1"}, {6, "fc00::1"}},
   136  	public:   []nova.IPAddress{{4, "8.8.8.8"}, {6, "2001:db8::1"}},
   137  	networks: []string{"special", "public"},
   138  	expected: "8.8.8.8",
   139  }, {
   140  	summary:    "floating and public, same address",
   141  	floatingIP: "8.8.8.8",
   142  	public:     []nova.IPAddress{{4, "8.8.8.8"}},
   143  	networks:   []string{"", "public"},
   144  	expected:   "8.8.8.8",
   145  }, {
   146  	summary:    "floating and public, different address",
   147  	floatingIP: "8.8.4.4",
   148  	public:     []nova.IPAddress{{4, "8.8.8.8"}},
   149  	networks:   []string{"", "public"},
   150  	expected:   "8.8.4.4",
   151  }, {
   152  	summary:    "floating and private",
   153  	floatingIP: "8.8.4.4",
   154  	private:    []nova.IPAddress{{4, "10.0.0.1"}},
   155  	networks:   []string{"private"},
   156  	expected:   "8.8.4.4",
   157  }, {
   158  	summary:    "floating, custom and public",
   159  	floatingIP: "8.8.4.4",
   160  	private:    []nova.IPAddress{{4, "172.16.0.1"}},
   161  	public:     []nova.IPAddress{{4, "8.8.8.8"}},
   162  	networks:   []string{"special", "public"},
   163  	expected:   "8.8.4.4",
   164  }}
   165  
   166  func (t *localTests) TestGetServerAddresses(c *gc.C) {
   167  	for i, t := range addressTests {
   168  		c.Logf("#%d. %s -> %s (%v)", i, t.summary, t.expected, t.failure)
   169  		addresses := make(map[string][]nova.IPAddress)
   170  		if t.private != nil {
   171  			if len(t.networks) < 1 {
   172  				addresses["private"] = t.private
   173  			} else {
   174  				addresses[t.networks[0]] = t.private
   175  			}
   176  		}
   177  		if t.public != nil {
   178  			if len(t.networks) < 2 {
   179  				addresses["public"] = t.public
   180  			} else {
   181  				addresses[t.networks[1]] = t.public
   182  			}
   183  		}
   184  		addr := InstanceAddress(t.floatingIP, addresses)
   185  		c.Check(addr, gc.Equals, t.expected)
   186  	}
   187  }
   188  
   189  func (*localTests) TestPortsToRuleInfo(c *gc.C) {
   190  	groupId := "groupid"
   191  	testCases := []struct {
   192  		about    string
   193  		ports    []network.PortRange
   194  		expected []nova.RuleInfo
   195  	}{{
   196  		about: "single port",
   197  		ports: []network.PortRange{{
   198  			FromPort: 80,
   199  			ToPort:   80,
   200  			Protocol: "tcp",
   201  		}},
   202  		expected: []nova.RuleInfo{{
   203  			IPProtocol:    "tcp",
   204  			FromPort:      80,
   205  			ToPort:        80,
   206  			Cidr:          "0.0.0.0/0",
   207  			ParentGroupId: groupId,
   208  		}},
   209  	}, {
   210  		about: "multiple ports",
   211  		ports: []network.PortRange{{
   212  			FromPort: 80,
   213  			ToPort:   82,
   214  			Protocol: "tcp",
   215  		}},
   216  		expected: []nova.RuleInfo{{
   217  			IPProtocol:    "tcp",
   218  			FromPort:      80,
   219  			ToPort:        82,
   220  			Cidr:          "0.0.0.0/0",
   221  			ParentGroupId: groupId,
   222  		}},
   223  	}, {
   224  		about: "multiple port ranges",
   225  		ports: []network.PortRange{{
   226  			FromPort: 80,
   227  			ToPort:   82,
   228  			Protocol: "tcp",
   229  		}, {
   230  			FromPort: 100,
   231  			ToPort:   120,
   232  			Protocol: "tcp",
   233  		}},
   234  		expected: []nova.RuleInfo{{
   235  			IPProtocol:    "tcp",
   236  			FromPort:      80,
   237  			ToPort:        82,
   238  			Cidr:          "0.0.0.0/0",
   239  			ParentGroupId: groupId,
   240  		}, {
   241  			IPProtocol:    "tcp",
   242  			FromPort:      100,
   243  			ToPort:        120,
   244  			Cidr:          "0.0.0.0/0",
   245  			ParentGroupId: groupId,
   246  		}},
   247  	}}
   248  
   249  	for i, t := range testCases {
   250  		c.Logf("test %d: %s", i, t.about)
   251  		rules := PortsToRuleInfo(groupId, t.ports)
   252  		c.Check(len(rules), gc.Equals, len(t.expected))
   253  		c.Check(rules, gc.DeepEquals, t.expected)
   254  	}
   255  }
   256  
   257  func (*localTests) TestRuleMatchesPortRange(c *gc.C) {
   258  	proto_tcp := "tcp"
   259  	proto_udp := "udp"
   260  	port_80 := 80
   261  	port_85 := 85
   262  
   263  	testCases := []struct {
   264  		about    string
   265  		ports    network.PortRange
   266  		rule     nova.SecurityGroupRule
   267  		expected bool
   268  	}{{
   269  		about: "single port",
   270  		ports: network.PortRange{
   271  			FromPort: 80,
   272  			ToPort:   80,
   273  			Protocol: "tcp",
   274  		},
   275  		rule: nova.SecurityGroupRule{
   276  			IPProtocol: &proto_tcp,
   277  			FromPort:   &port_80,
   278  			ToPort:     &port_80,
   279  		},
   280  		expected: true,
   281  	}, {
   282  		about: "multiple port",
   283  		ports: network.PortRange{
   284  			FromPort: port_80,
   285  			ToPort:   port_85,
   286  			Protocol: proto_tcp,
   287  		},
   288  		rule: nova.SecurityGroupRule{
   289  			IPProtocol: &proto_tcp,
   290  			FromPort:   &port_80,
   291  			ToPort:     &port_85,
   292  		},
   293  		expected: true,
   294  	}, {
   295  		about: "nil rule components",
   296  		ports: network.PortRange{
   297  			FromPort: port_80,
   298  			ToPort:   port_85,
   299  			Protocol: proto_tcp,
   300  		},
   301  		rule: nova.SecurityGroupRule{
   302  			IPProtocol: nil,
   303  			FromPort:   nil,
   304  			ToPort:     nil,
   305  		},
   306  		expected: false,
   307  	}, {
   308  		about: "mismatched port range and rule",
   309  		ports: network.PortRange{
   310  			FromPort: port_80,
   311  			ToPort:   port_85,
   312  			Protocol: proto_tcp,
   313  		},
   314  		rule: nova.SecurityGroupRule{
   315  			IPProtocol: &proto_udp,
   316  			FromPort:   &port_80,
   317  			ToPort:     &port_80,
   318  		},
   319  		expected: false,
   320  	}}
   321  	for i, t := range testCases {
   322  		c.Logf("test %d: %s", i, t.about)
   323  		c.Check(RuleMatchesPortRange(t.rule, t.ports), gc.Equals, t.expected)
   324  	}
   325  }
   326  
   327  func (s *localTests) TestDetectRegionsNoRegionName(c *gc.C) {
   328  	_, err := s.detectRegions(c)
   329  	c.Assert(err, gc.ErrorMatches, "OS_REGION_NAME environment variable not set")
   330  }
   331  
   332  func (s *localTests) TestDetectRegionsNoAuthURL(c *gc.C) {
   333  	s.PatchEnvironment("OS_REGION_NAME", "oceania")
   334  	_, err := s.detectRegions(c)
   335  	c.Assert(err, gc.ErrorMatches, "OS_AUTH_URL environment variable not set")
   336  }
   337  
   338  func (s *localTests) TestDetectRegions(c *gc.C) {
   339  	s.PatchEnvironment("OS_REGION_NAME", "oceania")
   340  	s.PatchEnvironment("OS_AUTH_URL", "http://keystone.internal")
   341  	regions, err := s.detectRegions(c)
   342  	c.Assert(err, jc.ErrorIsNil)
   343  	c.Assert(regions, jc.DeepEquals, []cloud.Region{
   344  		{Name: "oceania", Endpoint: "http://keystone.internal"},
   345  	})
   346  }
   347  
   348  func (s *localTests) detectRegions(c *gc.C) ([]cloud.Region, error) {
   349  	provider, err := environs.Provider("openstack")
   350  	c.Assert(err, jc.ErrorIsNil)
   351  	c.Assert(provider, gc.Implements, new(environs.CloudRegionDetector))
   352  	return provider.(environs.CloudRegionDetector).DetectRegions()
   353  }
   354  
   355  type providerUnitTests struct{}
   356  
   357  var _ = gc.Suite(&providerUnitTests{})
   358  
   359  func (s *providerUnitTests) TestIdentityClientVersion_BadURLErrors(c *gc.C) {
   360  	_, err := identityClientVersion("abc123")
   361  	c.Check(err, gc.Not(jc.ErrorIsNil))
   362  }
   363  
   364  func (s *providerUnitTests) TestIdentityClientVersion_ParsesGoodURL(c *gc.C) {
   365  	version, err := identityClientVersion("https://keystone.internal/v2.0")
   366  	c.Assert(err, jc.ErrorIsNil)
   367  	c.Check(version, gc.Equals, 2)
   368  
   369  	version, err = identityClientVersion("https://keystone.internal/v3.0/")
   370  	c.Assert(err, jc.ErrorIsNil)
   371  	c.Check(version, gc.Equals, 3)
   372  
   373  	version, err = identityClientVersion("https://keystone.internal/v2/")
   374  	c.Assert(err, jc.ErrorIsNil)
   375  	c.Check(version, gc.Equals, 2)
   376  }