github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/provider/openstack/live_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package openstack_test
     5  
     6  import (
     7  	"crypto/rand"
     8  	"fmt"
     9  	"io"
    10  	"sort"
    11  
    12  	gc "launchpad.net/gocheck"
    13  	"launchpad.net/goose/client"
    14  	"launchpad.net/goose/identity"
    15  	"launchpad.net/goose/nova"
    16  
    17  	"launchpad.net/juju-core/constraints"
    18  	"launchpad.net/juju-core/environs"
    19  	"launchpad.net/juju-core/environs/bootstrap"
    20  	"launchpad.net/juju-core/environs/config"
    21  	"launchpad.net/juju-core/environs/jujutest"
    22  	"launchpad.net/juju-core/environs/storage"
    23  	envtesting "launchpad.net/juju-core/environs/testing"
    24  	jujutesting "launchpad.net/juju-core/juju/testing"
    25  	"launchpad.net/juju-core/provider/openstack"
    26  	coretesting "launchpad.net/juju-core/testing"
    27  	"launchpad.net/juju-core/testing/testbase"
    28  )
    29  
    30  // generate a different bucket name for each config instance, so that
    31  // we are not polluted by previous test state.
    32  func randomName() string {
    33  	buf := make([]byte, 8)
    34  	_, err := io.ReadFull(rand.Reader, buf)
    35  	if err != nil {
    36  		panic(fmt.Sprintf("error from crypto rand: %v", err))
    37  	}
    38  	return fmt.Sprintf("%x", buf)
    39  }
    40  
    41  func makeTestConfig(cred *identity.Credentials) map[string]interface{} {
    42  	// The following attributes hold the environment configuration
    43  	// for running the OpenStack integration tests.
    44  	//
    45  	// This is missing keys for security reasons; set the following
    46  	// environment variables to make the OpenStack testing work:
    47  	//  access-key: $OS_USERNAME
    48  	//  secret-key: $OS_PASSWORD
    49  	//
    50  	attrs := coretesting.FakeConfig().Merge(coretesting.Attrs{
    51  		"name":           "sample-" + randomName(),
    52  		"type":           "openstack",
    53  		"auth-mode":      "userpass",
    54  		"control-bucket": "juju-test-" + randomName(),
    55  		"username":       cred.User,
    56  		"password":       cred.Secrets,
    57  		"region":         cred.Region,
    58  		"auth-url":       cred.URL,
    59  		"tenant-name":    cred.TenantName,
    60  	})
    61  	return attrs
    62  }
    63  
    64  // Register tests to run against a real Openstack instance.
    65  func registerLiveTests(cred *identity.Credentials) {
    66  	config := makeTestConfig(cred)
    67  	gc.Suite(&LiveTests{
    68  		cred: cred,
    69  		LiveTests: jujutest.LiveTests{
    70  			TestConfig:     config,
    71  			Attempt:        *openstack.ShortAttempt,
    72  			CanOpenState:   true,
    73  			HasProvisioner: true,
    74  		},
    75  	})
    76  }
    77  
    78  // LiveTests contains tests that can be run against OpenStack deployments.
    79  // The deployment can be a real live instance or service doubles.
    80  // Each test runs using the same connection.
    81  type LiveTests struct {
    82  	testbase.LoggingSuite
    83  	jujutest.LiveTests
    84  	cred            *identity.Credentials
    85  	metadataStorage storage.Storage
    86  }
    87  
    88  func (t *LiveTests) SetUpSuite(c *gc.C) {
    89  	t.LoggingSuite.SetUpSuite(c)
    90  	// Update some Config items now that we have services running.
    91  	// This is setting the simplestreams urls and auth-url because that
    92  	// information is set during startup of the localLiveSuite
    93  	cl := client.NewClient(t.cred, identity.AuthUserPass, nil)
    94  	err := cl.Authenticate()
    95  	c.Assert(err, gc.IsNil)
    96  	containerURL, err := cl.MakeServiceURL("object-store", nil)
    97  	c.Assert(err, gc.IsNil)
    98  	t.TestConfig = t.TestConfig.Merge(coretesting.Attrs{
    99  		"tools-metadata-url": containerURL + "/juju-dist-test/tools",
   100  		"image-metadata-url": containerURL + "/juju-dist-test",
   101  		"auth-url":           t.cred.URL,
   102  	})
   103  	t.LiveTests.SetUpSuite(c)
   104  	// For testing, we create a storage instance to which is uploaded tools and image metadata.
   105  	t.PrepareOnce(c)
   106  	t.metadataStorage = openstack.MetadataStorage(t.Env)
   107  	// Put some fake tools metadata in place so that tests that are simply
   108  	// starting instances without any need to check if those instances
   109  	// are running can find the metadata.
   110  	envtesting.UploadFakeTools(c, t.metadataStorage)
   111  }
   112  
   113  func (t *LiveTests) TearDownSuite(c *gc.C) {
   114  	if t.Env == nil {
   115  		// This can happen if SetUpSuite fails.
   116  		return
   117  	}
   118  	if t.metadataStorage != nil {
   119  		envtesting.RemoveFakeToolsMetadata(c, t.metadataStorage)
   120  	}
   121  	t.LiveTests.TearDownSuite(c)
   122  	t.LoggingSuite.TearDownSuite(c)
   123  }
   124  
   125  func (t *LiveTests) SetUpTest(c *gc.C) {
   126  	t.LoggingSuite.SetUpTest(c)
   127  	t.LiveTests.SetUpTest(c)
   128  }
   129  
   130  func (t *LiveTests) TearDownTest(c *gc.C) {
   131  	t.LiveTests.TearDownTest(c)
   132  	t.LoggingSuite.TearDownTest(c)
   133  }
   134  
   135  func (t *LiveTests) TestEnsureGroupSetsGroupId(c *gc.C) {
   136  	t.PrepareOnce(c)
   137  	rules := []nova.RuleInfo{
   138  		{ // First group explicitly asks for all services
   139  			IPProtocol: "tcp",
   140  			FromPort:   22,
   141  			ToPort:     22,
   142  			Cidr:       "0.0.0.0/0",
   143  		},
   144  		{ // Second group should only allow access from within the group
   145  			IPProtocol: "tcp",
   146  			FromPort:   1,
   147  			ToPort:     65535,
   148  		},
   149  	}
   150  	groupName := "juju-test-group-" + randomName()
   151  	// Make sure things are clean before we start, and clean when we are done
   152  	cleanup := func() {
   153  		c.Check(openstack.DiscardSecurityGroup(t.Env, groupName), gc.IsNil)
   154  	}
   155  	cleanup()
   156  	defer cleanup()
   157  	group, err := openstack.EnsureGroup(t.Env, groupName, rules)
   158  	c.Assert(err, gc.IsNil)
   159  	c.Check(group.Rules, gc.HasLen, 2)
   160  	c.Check(*group.Rules[0].IPProtocol, gc.Equals, "tcp")
   161  	c.Check(*group.Rules[0].FromPort, gc.Equals, 22)
   162  	c.Check(*group.Rules[0].ToPort, gc.Equals, 22)
   163  	c.Check(group.Rules[0].IPRange["cidr"], gc.Equals, "0.0.0.0/0")
   164  	c.Check(group.Rules[0].Group.Name, gc.Equals, "")
   165  	c.Check(group.Rules[0].Group.TenantId, gc.Equals, "")
   166  	c.Check(*group.Rules[1].IPProtocol, gc.Equals, "tcp")
   167  	c.Check(*group.Rules[1].FromPort, gc.Equals, 1)
   168  	c.Check(*group.Rules[1].ToPort, gc.Equals, 65535)
   169  	c.Check(group.Rules[1].IPRange, gc.HasLen, 0)
   170  	c.Check(group.Rules[1].Group.Name, gc.Equals, groupName)
   171  	c.Check(group.Rules[1].Group.TenantId, gc.Equals, group.TenantId)
   172  }
   173  
   174  func (t *LiveTests) TestSetupGlobalGroupExposesCorrectPorts(c *gc.C) {
   175  	t.PrepareOnce(c)
   176  	groupName := "juju-test-group-" + randomName()
   177  	// Make sure things are clean before we start, and will be clean when we finish
   178  	cleanup := func() {
   179  		c.Check(openstack.DiscardSecurityGroup(t.Env, groupName), gc.IsNil)
   180  	}
   181  	cleanup()
   182  	defer cleanup()
   183  	statePort := 12345 // Default 37017
   184  	apiPort := 34567   // Default 17070
   185  	group, err := openstack.SetUpGlobalGroup(t.Env, groupName, statePort, apiPort)
   186  	c.Assert(err, gc.IsNil)
   187  	c.Assert(err, gc.IsNil)
   188  	// We default to exporting 22, statePort, apiPort, and icmp/udp/tcp on
   189  	// all ports to other machines inside the same group
   190  	// TODO(jam): 2013-09-18 http://pad.lv/1227142
   191  	// We shouldn't be exposing the API and State ports on all the machines
   192  	// that *aren't* hosting the state server. (And once we finish
   193  	// client-via-API we can disable the State port as well.)
   194  	stringRules := make([]string, 0, len(group.Rules))
   195  	for _, rule := range group.Rules {
   196  		ruleStr := fmt.Sprintf("%s %d %d %q %q",
   197  			*rule.IPProtocol,
   198  			*rule.FromPort,
   199  			*rule.ToPort,
   200  			rule.IPRange["cidr"],
   201  			rule.Group.Name,
   202  		)
   203  		stringRules = append(stringRules, ruleStr)
   204  	}
   205  	// We don't care about the ordering, so we sort the result, and compare it.
   206  	expectedRules := []string{
   207  		`tcp 22 22 "0.0.0.0/0" ""`,
   208  		fmt.Sprintf(`tcp %d %d "0.0.0.0/0" ""`, statePort, statePort),
   209  		fmt.Sprintf(`tcp %d %d "0.0.0.0/0" ""`, apiPort, apiPort),
   210  		fmt.Sprintf(`tcp 1 65535 "" "%s"`, groupName),
   211  		fmt.Sprintf(`udp 1 65535 "" "%s"`, groupName),
   212  		fmt.Sprintf(`icmp -1 -1 "" "%s"`, groupName),
   213  	}
   214  	sort.Strings(stringRules)
   215  	sort.Strings(expectedRules)
   216  	c.Check(stringRules, gc.DeepEquals, expectedRules)
   217  }
   218  
   219  func (s *LiveTests) assertStartInstanceDefaultSecurityGroup(c *gc.C, useDefault bool) {
   220  	attrs := s.TestConfig.Merge(coretesting.Attrs{
   221  		"name":                 "sample-" + randomName(),
   222  		"control-bucket":       "juju-test-" + randomName(),
   223  		"use-default-secgroup": useDefault,
   224  	})
   225  	cfg, err := config.New(config.NoDefaults, attrs)
   226  	c.Assert(err, gc.IsNil)
   227  	// Set up a test environment.
   228  	env, err := environs.New(cfg)
   229  	c.Assert(err, gc.IsNil)
   230  	c.Assert(env, gc.NotNil)
   231  	defer env.Destroy()
   232  	// Bootstrap and start an instance.
   233  	err = bootstrap.Bootstrap(coretesting.Context(c), env, constraints.Value{})
   234  	c.Assert(err, gc.IsNil)
   235  	inst, _ := jujutesting.AssertStartInstance(c, env, "100")
   236  	// Check whether the instance has the default security group assigned.
   237  	novaClient := openstack.GetNovaClient(env)
   238  	groups, err := novaClient.GetServerSecurityGroups(string(inst.Id()))
   239  	c.Assert(err, gc.IsNil)
   240  	defaultGroupFound := false
   241  	for _, group := range groups {
   242  		if group.Name == "default" {
   243  			defaultGroupFound = true
   244  			break
   245  		}
   246  	}
   247  	c.Assert(defaultGroupFound, gc.Equals, useDefault)
   248  }
   249  
   250  func (s *LiveTests) TestStartInstanceWithDefaultSecurityGroup(c *gc.C) {
   251  	s.assertStartInstanceDefaultSecurityGroup(c, true)
   252  }
   253  
   254  func (s *LiveTests) TestStartInstanceWithoutDefaultSecurityGroup(c *gc.C) {
   255  	s.assertStartInstanceDefaultSecurityGroup(c, false)
   256  }