github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/environs/jujutest/livetests.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujutest
     5  
     6  import (
     7  	"fmt"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/os/series"
    13  	gitjujutesting "github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	"github.com/juju/utils"
    16  	"github.com/juju/utils/arch"
    17  	"github.com/juju/version"
    18  	gc "gopkg.in/check.v1"
    19  	"gopkg.in/juju/charmrepo.v3"
    20  
    21  	"github.com/juju/juju/api"
    22  	"github.com/juju/juju/cloud"
    23  	"github.com/juju/juju/cloudconfig/instancecfg"
    24  	"github.com/juju/juju/core/constraints"
    25  	"github.com/juju/juju/core/instance"
    26  	"github.com/juju/juju/core/status"
    27  	"github.com/juju/juju/environs"
    28  	"github.com/juju/juju/environs/bootstrap"
    29  	"github.com/juju/juju/environs/config"
    30  	"github.com/juju/juju/environs/context"
    31  	"github.com/juju/juju/environs/filestorage"
    32  	"github.com/juju/juju/environs/instances"
    33  	sstesting "github.com/juju/juju/environs/simplestreams/testing"
    34  	"github.com/juju/juju/environs/storage"
    35  	"github.com/juju/juju/environs/sync"
    36  	envtesting "github.com/juju/juju/environs/testing"
    37  	envtools "github.com/juju/juju/environs/tools"
    38  	envtoolstesting "github.com/juju/juju/environs/tools/testing"
    39  	"github.com/juju/juju/juju/keys"
    40  	jujutesting "github.com/juju/juju/juju/testing"
    41  	supportedversion "github.com/juju/juju/juju/version"
    42  	"github.com/juju/juju/jujuclient"
    43  	"github.com/juju/juju/network"
    44  	"github.com/juju/juju/provider/dummy"
    45  	"github.com/juju/juju/state"
    46  	statetesting "github.com/juju/juju/state/testing"
    47  	"github.com/juju/juju/testcharms"
    48  	coretesting "github.com/juju/juju/testing"
    49  	coretools "github.com/juju/juju/tools"
    50  	jujuversion "github.com/juju/juju/version"
    51  )
    52  
    53  const (
    54  	AdminSecret = "admin-secret"
    55  )
    56  
    57  // LiveTests contains tests that are designed to run against a live server
    58  // (e.g. Amazon EC2).  The Environ is opened once only for all the tests
    59  // in the suite, stored in Env, and Destroyed after the suite has completed.
    60  type LiveTests struct {
    61  	gitjujutesting.CleanupSuite
    62  
    63  	envtesting.ToolsFixture
    64  	sstesting.TestDataSuite
    65  
    66  	// TestConfig contains the configuration attributes for opening an environment.
    67  	TestConfig coretesting.Attrs
    68  
    69  	// Credential contains the credential for preparing an environment for
    70  	// bootstrapping. If this is unset, empty credentials will be used.
    71  	Credential cloud.Credential
    72  
    73  	// CloudRegion contains the cloud region name to create resources in.
    74  	CloudRegion string
    75  
    76  	// CloudEndpoint contains the cloud API endpoint to communicate with.
    77  	CloudEndpoint string
    78  
    79  	// Attempt holds a strategy for waiting until the environment
    80  	// becomes logically consistent.
    81  	//
    82  	// TODO(katco): 2016-08-09: lp:1611427
    83  	Attempt utils.AttemptStrategy
    84  
    85  	// CanOpenState should be true if the testing environment allows
    86  	// the state to be opened after bootstrapping.
    87  	CanOpenState bool
    88  
    89  	// HasProvisioner should be true if the environment has
    90  	// a provisioning agent.
    91  	HasProvisioner bool
    92  
    93  	// Env holds the currently opened environment.
    94  	// This is set by PrepareOnce and BootstrapOnce.
    95  	Env environs.Environ
    96  
    97  	// ControllerStore holds the controller related information
    98  	// such as controllers, accounts, etc., used when preparing
    99  	// the environment. This is initialized by SetUpSuite.
   100  	ControllerStore jujuclient.ClientStore
   101  
   102  	// ControllerUUID is the uuid of the bootstrapped controller.
   103  	ControllerUUID string
   104  
   105  	// ProviderCallContext holds the context to be used to make
   106  	// calls to a cloud provider.
   107  	ProviderCallContext context.ProviderCallContext
   108  
   109  	prepared     bool
   110  	bootstrapped bool
   111  	toolsStorage storage.Storage
   112  }
   113  
   114  func (t *LiveTests) SetUpSuite(c *gc.C) {
   115  	t.CleanupSuite.SetUpSuite(c)
   116  	t.TestDataSuite.SetUpSuite(c)
   117  	t.ControllerStore = jujuclient.NewMemStore()
   118  	t.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey)
   119  }
   120  
   121  func (t *LiveTests) SetUpTest(c *gc.C) {
   122  	t.CleanupSuite.SetUpTest(c)
   123  	t.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber)
   124  	storageDir := c.MkDir()
   125  	baseURLPath := filepath.Join(storageDir, "tools")
   126  	t.DefaultBaseURL = utils.MakeFileURL(baseURLPath)
   127  	t.ToolsFixture.SetUpTest(c)
   128  	stor, err := filestorage.NewFileStorageWriter(storageDir)
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	t.UploadFakeTools(c, stor, "released", "released")
   131  	t.toolsStorage = stor
   132  	t.CleanupSuite.PatchValue(&envtools.BundleTools, envtoolstesting.GetMockBundleTools(c, nil))
   133  	t.ProviderCallContext = context.NewCloudCallContext()
   134  }
   135  
   136  func (t *LiveTests) TearDownSuite(c *gc.C) {
   137  	t.Destroy(c)
   138  	t.TestDataSuite.TearDownSuite(c)
   139  	t.CleanupSuite.TearDownSuite(c)
   140  }
   141  
   142  func (t *LiveTests) TearDownTest(c *gc.C) {
   143  	t.ToolsFixture.TearDownTest(c)
   144  	t.CleanupSuite.TearDownTest(c)
   145  }
   146  
   147  // PrepareOnce ensures that the environment is
   148  // available and prepared. It sets t.Env appropriately.
   149  func (t *LiveTests) PrepareOnce(c *gc.C) {
   150  	if t.prepared {
   151  		return
   152  	}
   153  	args := t.prepareForBootstrapParams(c)
   154  	e, err := bootstrap.PrepareController(false, envtesting.BootstrapContext(c), t.ControllerStore, args)
   155  	c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", t.TestConfig))
   156  	c.Assert(e, gc.NotNil)
   157  	t.Env = e.(environs.Environ)
   158  	t.prepared = true
   159  	t.ControllerUUID = coretesting.FakeControllerConfig().ControllerUUID()
   160  }
   161  
   162  func (t *LiveTests) prepareForBootstrapParams(c *gc.C) bootstrap.PrepareParams {
   163  	credential := t.Credential
   164  	if credential.AuthType() == "" {
   165  		credential = cloud.NewEmptyCredential()
   166  	}
   167  	return bootstrap.PrepareParams{
   168  		ControllerConfig: coretesting.FakeControllerConfig(),
   169  		ModelConfig:      t.TestConfig,
   170  		Cloud: environs.CloudSpec{
   171  			Type:       t.TestConfig["type"].(string),
   172  			Name:       t.TestConfig["type"].(string),
   173  			Region:     t.CloudRegion,
   174  			Endpoint:   t.CloudEndpoint,
   175  			Credential: &credential,
   176  		},
   177  		ControllerName: t.TestConfig["name"].(string),
   178  		AdminSecret:    AdminSecret,
   179  	}
   180  }
   181  
   182  func (t *LiveTests) bootstrapParams() bootstrap.BootstrapParams {
   183  	credential := t.Credential
   184  	if credential.AuthType() == "" {
   185  		credential = cloud.NewEmptyCredential()
   186  	}
   187  	var regions []cloud.Region
   188  	if t.CloudRegion != "" {
   189  		regions = []cloud.Region{{
   190  			Name:     t.CloudRegion,
   191  			Endpoint: t.CloudEndpoint,
   192  		}}
   193  	}
   194  	return bootstrap.BootstrapParams{
   195  		ControllerConfig: coretesting.FakeControllerConfig(),
   196  		Cloud: cloud.Cloud{
   197  			Name:      t.TestConfig["type"].(string),
   198  			Type:      t.TestConfig["type"].(string),
   199  			AuthTypes: []cloud.AuthType{credential.AuthType()},
   200  			Regions:   regions,
   201  			Endpoint:  t.CloudEndpoint,
   202  		},
   203  		CloudRegion:         t.CloudRegion,
   204  		CloudCredential:     &credential,
   205  		CloudCredentialName: "credential",
   206  		AdminSecret:         AdminSecret,
   207  		CAPrivateKey:        coretesting.CAKey,
   208  	}
   209  }
   210  
   211  func (t *LiveTests) BootstrapOnce(c *gc.C) {
   212  	if t.bootstrapped {
   213  		return
   214  	}
   215  	t.PrepareOnce(c)
   216  	// We only build and upload tools if there will be a state agent that
   217  	// we could connect to (actual live tests, rather than local-only)
   218  	cons := constraints.MustParse("mem=2G")
   219  	if t.CanOpenState {
   220  		_, err := sync.Upload(t.toolsStorage, "released", nil, supportedversion.SupportedLTS())
   221  		c.Assert(err, jc.ErrorIsNil)
   222  	}
   223  	args := t.bootstrapParams()
   224  	args.BootstrapConstraints = cons
   225  	args.ModelConstraints = cons
   226  	err := bootstrap.Bootstrap(envtesting.BootstrapContext(c), t.Env, t.ProviderCallContext, args)
   227  	c.Assert(err, jc.ErrorIsNil)
   228  	t.bootstrapped = true
   229  }
   230  
   231  func (t *LiveTests) Destroy(c *gc.C) {
   232  	if t.Env == nil {
   233  		return
   234  	}
   235  	err := environs.Destroy(t.Env.Config().Name(), t.Env, t.ProviderCallContext, t.ControllerStore)
   236  	c.Assert(err, jc.ErrorIsNil)
   237  	t.bootstrapped = false
   238  	t.prepared = false
   239  	t.ControllerUUID = ""
   240  	t.Env = nil
   241  }
   242  
   243  func (t *LiveTests) TestPrechecker(c *gc.C) {
   244  	// All implementations of InstancePrechecker should
   245  	// return nil for empty constraints (excluding the
   246  	// manual provider).
   247  	t.PrepareOnce(c)
   248  	err := t.Env.PrecheckInstance(t.ProviderCallContext,
   249  		environs.PrecheckInstanceParams{
   250  			Series: "precise",
   251  		})
   252  	c.Assert(err, jc.ErrorIsNil)
   253  }
   254  
   255  // TestStartStop is similar to Tests.TestStartStop except
   256  // that it does not assume a pristine environment.
   257  func (t *LiveTests) TestStartStop(c *gc.C) {
   258  	t.BootstrapOnce(c)
   259  
   260  	inst, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "0")
   261  	c.Assert(inst, gc.NotNil)
   262  	id0 := inst.Id()
   263  
   264  	insts, err := t.Env.Instances(t.ProviderCallContext, []instance.Id{id0, id0})
   265  	c.Assert(err, jc.ErrorIsNil)
   266  	c.Assert(insts, gc.HasLen, 2)
   267  	c.Assert(insts[0].Id(), gc.Equals, id0)
   268  	c.Assert(insts[1].Id(), gc.Equals, id0)
   269  
   270  	// Asserting on the return of AllInstances makes the test fragile,
   271  	// as even comparing the before and after start values can be thrown
   272  	// off if other instances have been created or destroyed in the same
   273  	// time frame. Instead, just check the instance we created exists.
   274  	insts, err = t.Env.AllInstances(t.ProviderCallContext)
   275  	c.Assert(err, jc.ErrorIsNil)
   276  	found := false
   277  	for _, inst := range insts {
   278  		if inst.Id() == id0 {
   279  			c.Assert(found, gc.Equals, false, gc.Commentf("%v", insts))
   280  			found = true
   281  		}
   282  	}
   283  	c.Assert(found, gc.Equals, true, gc.Commentf("expected %v in %v", inst, insts))
   284  
   285  	addresses, err := jujutesting.WaitInstanceAddresses(t.Env, t.ProviderCallContext, inst.Id())
   286  	c.Assert(err, jc.ErrorIsNil)
   287  	c.Assert(addresses, gc.Not(gc.HasLen), 0)
   288  
   289  	insts, err = t.Env.Instances(t.ProviderCallContext, []instance.Id{id0, ""})
   290  	c.Assert(err, gc.Equals, environs.ErrPartialInstances)
   291  	c.Assert(insts, gc.HasLen, 2)
   292  	c.Check(insts[0].Id(), gc.Equals, id0)
   293  	c.Check(insts[1], gc.IsNil)
   294  
   295  	err = t.Env.StopInstances(t.ProviderCallContext, inst.Id())
   296  	c.Assert(err, jc.ErrorIsNil)
   297  
   298  	// The machine may not be marked as shutting down
   299  	// immediately. Repeat a few times to ensure we get the error.
   300  	for a := t.Attempt.Start(); a.Next(); {
   301  		insts, err = t.Env.Instances(t.ProviderCallContext, []instance.Id{id0})
   302  		if err != nil {
   303  			break
   304  		}
   305  	}
   306  	c.Assert(err, gc.Equals, environs.ErrNoInstances)
   307  	c.Assert(insts, gc.HasLen, 0)
   308  }
   309  
   310  func (t *LiveTests) TestPorts(c *gc.C) {
   311  	t.BootstrapOnce(c)
   312  
   313  	inst1, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "1")
   314  	c.Assert(inst1, gc.NotNil)
   315  	defer t.Env.StopInstances(t.ProviderCallContext, inst1.Id())
   316  	fwInst1, ok := inst1.(instances.InstanceFirewaller)
   317  	c.Assert(ok, gc.Equals, true)
   318  
   319  	rules, err := fwInst1.IngressRules(t.ProviderCallContext, "1")
   320  	c.Assert(err, jc.ErrorIsNil)
   321  	c.Assert(rules, gc.HasLen, 0)
   322  
   323  	inst2, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "2")
   324  	c.Assert(inst2, gc.NotNil)
   325  	fwInst2, ok := inst2.(instances.InstanceFirewaller)
   326  	c.Assert(ok, gc.Equals, true)
   327  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   328  	c.Assert(err, jc.ErrorIsNil)
   329  	c.Assert(rules, gc.HasLen, 0)
   330  	defer t.Env.StopInstances(t.ProviderCallContext, inst2.Id())
   331  
   332  	// Open some ports and check they're there.
   333  	err = fwInst1.OpenPorts(t.ProviderCallContext,
   334  		"1", []network.IngressRule{
   335  			network.MustNewIngressRule("udp", 67, 67),
   336  			network.MustNewIngressRule("tcp", 45, 45),
   337  			network.MustNewIngressRule("tcp", 80, 100),
   338  		})
   339  
   340  	c.Assert(err, jc.ErrorIsNil)
   341  	rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1")
   342  	c.Assert(err, jc.ErrorIsNil)
   343  	c.Assert(
   344  		rules, jc.DeepEquals,
   345  		[]network.IngressRule{
   346  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   347  			network.MustNewIngressRule("tcp", 80, 100, "0.0.0.0/0"),
   348  			network.MustNewIngressRule("udp", 67, 67, "0.0.0.0/0"),
   349  		},
   350  	)
   351  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   352  	c.Assert(err, jc.ErrorIsNil)
   353  	c.Assert(rules, gc.HasLen, 0)
   354  
   355  	err = fwInst2.OpenPorts(t.ProviderCallContext,
   356  		"2", []network.IngressRule{
   357  			network.MustNewIngressRule("tcp", 89, 89),
   358  			network.MustNewIngressRule("tcp", 45, 45),
   359  			network.MustNewIngressRule("tcp", 20, 30),
   360  		})
   361  	c.Assert(err, jc.ErrorIsNil)
   362  
   363  	// Check there's no crosstalk to another machine
   364  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   365  	c.Assert(err, jc.ErrorIsNil)
   366  	c.Assert(
   367  		rules, jc.DeepEquals,
   368  		[]network.IngressRule{
   369  			network.MustNewIngressRule("tcp", 20, 30, "0.0.0.0/0"),
   370  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   371  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   372  		},
   373  	)
   374  	rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1")
   375  	c.Assert(err, jc.ErrorIsNil)
   376  	c.Assert(
   377  		rules, jc.DeepEquals,
   378  		[]network.IngressRule{
   379  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   380  			network.MustNewIngressRule("tcp", 80, 100, "0.0.0.0/0"),
   381  			network.MustNewIngressRule("udp", 67, 67, "0.0.0.0/0"),
   382  		},
   383  	)
   384  
   385  	// Check that opening the same port again is ok.
   386  	oldRules, err := fwInst2.IngressRules(t.ProviderCallContext, "2")
   387  	c.Assert(err, jc.ErrorIsNil)
   388  	err = fwInst2.OpenPorts(t.ProviderCallContext,
   389  		"2", []network.IngressRule{
   390  			network.MustNewIngressRule("tcp", 45, 45),
   391  		})
   392  	c.Assert(err, jc.ErrorIsNil)
   393  	err = fwInst2.OpenPorts(t.ProviderCallContext,
   394  		"2", []network.IngressRule{
   395  			network.MustNewIngressRule("tcp", 20, 30),
   396  		})
   397  	c.Assert(err, jc.ErrorIsNil)
   398  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   399  	c.Assert(err, jc.ErrorIsNil)
   400  	c.Assert(rules, jc.DeepEquals, oldRules)
   401  
   402  	// Check that opening the same port again and another port is ok.
   403  	err = fwInst2.OpenPorts(t.ProviderCallContext,
   404  		"2", []network.IngressRule{
   405  			network.MustNewIngressRule("tcp", 45, 45),
   406  			network.MustNewIngressRule("tcp", 99, 99),
   407  		})
   408  	c.Assert(err, jc.ErrorIsNil)
   409  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   410  	c.Assert(err, jc.ErrorIsNil)
   411  	c.Assert(
   412  		rules, jc.DeepEquals,
   413  		[]network.IngressRule{
   414  			network.MustNewIngressRule("tcp", 20, 30, "0.0.0.0/0"),
   415  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   416  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   417  			network.MustNewIngressRule("tcp", 99, 99, "0.0.0.0/0"),
   418  		},
   419  	)
   420  	err = fwInst2.ClosePorts(t.ProviderCallContext,
   421  		"2", []network.IngressRule{
   422  			network.MustNewIngressRule("tcp", 45, 45),
   423  			network.MustNewIngressRule("tcp", 99, 99),
   424  			network.MustNewIngressRule("tcp", 20, 30),
   425  		})
   426  	c.Assert(err, jc.ErrorIsNil)
   427  
   428  	// Check that we can close ports and that there's no crosstalk.
   429  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   430  	c.Assert(err, jc.ErrorIsNil)
   431  	c.Assert(
   432  		rules, jc.DeepEquals,
   433  		[]network.IngressRule{
   434  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   435  		},
   436  	)
   437  	rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1")
   438  	c.Assert(err, jc.ErrorIsNil)
   439  	c.Assert(
   440  		rules, jc.DeepEquals,
   441  		[]network.IngressRule{
   442  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   443  			network.MustNewIngressRule("tcp", 80, 100, "0.0.0.0/0"),
   444  			network.MustNewIngressRule("udp", 67, 67, "0.0.0.0/0"),
   445  		},
   446  	)
   447  
   448  	// Check that we can close multiple ports.
   449  	err = fwInst1.ClosePorts(t.ProviderCallContext,
   450  		"1", []network.IngressRule{
   451  			network.MustNewIngressRule("tcp", 45, 45),
   452  			network.MustNewIngressRule("udp", 67, 67),
   453  			network.MustNewIngressRule("tcp", 80, 100),
   454  		})
   455  	c.Assert(err, jc.ErrorIsNil)
   456  	rules, err = fwInst1.IngressRules(t.ProviderCallContext, "1")
   457  	c.Assert(rules, gc.HasLen, 0)
   458  
   459  	// Check that we can close ports that aren't there.
   460  	err = fwInst2.ClosePorts(t.ProviderCallContext,
   461  		"2", []network.IngressRule{
   462  			network.MustNewIngressRule("tcp", 111, 111),
   463  			network.MustNewIngressRule("udp", 222, 222),
   464  			network.MustNewIngressRule("tcp", 600, 700),
   465  		})
   466  	c.Assert(err, jc.ErrorIsNil)
   467  	rules, err = fwInst2.IngressRules(t.ProviderCallContext, "2")
   468  	c.Assert(
   469  		rules, jc.DeepEquals,
   470  		[]network.IngressRule{
   471  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   472  		},
   473  	)
   474  
   475  	// Check errors when acting on environment.
   476  	fwEnv, ok := t.Env.(environs.Firewaller)
   477  	c.Assert(ok, gc.Equals, true)
   478  	err = fwEnv.OpenPorts(t.ProviderCallContext, []network.IngressRule{network.MustNewIngressRule("tcp", 80, 80)})
   479  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for opening ports on model`)
   480  
   481  	err = fwEnv.ClosePorts(t.ProviderCallContext, []network.IngressRule{network.MustNewIngressRule("tcp", 80, 80)})
   482  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for closing ports on model`)
   483  
   484  	_, err = fwEnv.IngressRules(t.ProviderCallContext)
   485  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for retrieving ingress rules from model`)
   486  }
   487  
   488  func (t *LiveTests) TestGlobalPorts(c *gc.C) {
   489  	t.BootstrapOnce(c)
   490  
   491  	// Change configuration.
   492  	oldConfig := t.Env.Config()
   493  	defer func() {
   494  		err := t.Env.SetConfig(oldConfig)
   495  		c.Assert(err, jc.ErrorIsNil)
   496  	}()
   497  
   498  	attrs := t.Env.Config().AllAttrs()
   499  	attrs["firewall-mode"] = config.FwGlobal
   500  	newConfig, err := t.Env.Config().Apply(attrs)
   501  	c.Assert(err, jc.ErrorIsNil)
   502  	err = t.Env.SetConfig(newConfig)
   503  	c.Assert(err, jc.ErrorIsNil)
   504  
   505  	// Create instances and check open ports on both instances.
   506  	inst1, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "1")
   507  	defer t.Env.StopInstances(t.ProviderCallContext, inst1.Id())
   508  
   509  	fwEnv, ok := t.Env.(environs.Firewaller)
   510  	c.Assert(ok, gc.Equals, true)
   511  
   512  	rules, err := fwEnv.IngressRules(t.ProviderCallContext)
   513  	c.Assert(err, jc.ErrorIsNil)
   514  	c.Assert(rules, gc.HasLen, 0)
   515  
   516  	inst2, _ := jujutesting.AssertStartInstance(c, t.Env, t.ProviderCallContext, t.ControllerUUID, "2")
   517  	rules, err = fwEnv.IngressRules(t.ProviderCallContext)
   518  	c.Assert(err, jc.ErrorIsNil)
   519  	c.Assert(rules, gc.HasLen, 0)
   520  	defer t.Env.StopInstances(t.ProviderCallContext, inst2.Id())
   521  
   522  	err = fwEnv.OpenPorts(t.ProviderCallContext,
   523  		[]network.IngressRule{
   524  			network.MustNewIngressRule("udp", 67, 67),
   525  			network.MustNewIngressRule("tcp", 45, 45),
   526  			network.MustNewIngressRule("tcp", 89, 89),
   527  			network.MustNewIngressRule("tcp", 99, 99),
   528  			network.MustNewIngressRule("tcp", 100, 110),
   529  		})
   530  	c.Assert(err, jc.ErrorIsNil)
   531  
   532  	rules, err = fwEnv.IngressRules(t.ProviderCallContext)
   533  	c.Assert(err, jc.ErrorIsNil)
   534  	c.Assert(
   535  		rules, jc.DeepEquals,
   536  		[]network.IngressRule{
   537  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   538  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   539  			network.MustNewIngressRule("tcp", 99, 99, "0.0.0.0/0"),
   540  			network.MustNewIngressRule("tcp", 100, 110, "0.0.0.0/0"),
   541  			network.MustNewIngressRule("udp", 67, 67, "0.0.0.0/0"),
   542  		},
   543  	)
   544  
   545  	// Check closing some ports.
   546  	err = fwEnv.ClosePorts(t.ProviderCallContext,
   547  		[]network.IngressRule{
   548  			network.MustNewIngressRule("tcp", 99, 99),
   549  			network.MustNewIngressRule("udp", 67, 67),
   550  		})
   551  	c.Assert(err, jc.ErrorIsNil)
   552  
   553  	rules, err = fwEnv.IngressRules(t.ProviderCallContext)
   554  	c.Assert(err, jc.ErrorIsNil)
   555  	c.Assert(
   556  		rules, jc.DeepEquals,
   557  		[]network.IngressRule{
   558  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   559  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   560  			network.MustNewIngressRule("tcp", 100, 110, "0.0.0.0/0"),
   561  		},
   562  	)
   563  
   564  	// Check that we can close ports that aren't there.
   565  	err = fwEnv.ClosePorts(t.ProviderCallContext,
   566  		[]network.IngressRule{
   567  			network.MustNewIngressRule("tcp", 111, 111),
   568  			network.MustNewIngressRule("udp", 222, 222),
   569  			network.MustNewIngressRule("tcp", 2000, 2500),
   570  		})
   571  	c.Assert(err, jc.ErrorIsNil)
   572  
   573  	rules, err = fwEnv.IngressRules(t.ProviderCallContext)
   574  	c.Assert(err, jc.ErrorIsNil)
   575  	c.Assert(
   576  		rules, jc.DeepEquals,
   577  		[]network.IngressRule{
   578  			network.MustNewIngressRule("tcp", 45, 45, "0.0.0.0/0"),
   579  			network.MustNewIngressRule("tcp", 89, 89, "0.0.0.0/0"),
   580  			network.MustNewIngressRule("tcp", 100, 110, "0.0.0.0/0"),
   581  		},
   582  	)
   583  
   584  	fwInst1, ok := inst1.(instances.InstanceFirewaller)
   585  	c.Assert(ok, gc.Equals, true)
   586  	// Check errors when acting on instances.
   587  	err = fwInst1.OpenPorts(t.ProviderCallContext,
   588  		"1", []network.IngressRule{network.MustNewIngressRule("tcp", 80, 80)})
   589  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for opening ports on instance`)
   590  
   591  	err = fwInst1.ClosePorts(t.ProviderCallContext,
   592  		"1", []network.IngressRule{network.MustNewIngressRule("tcp", 80, 80)})
   593  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for closing ports on instance`)
   594  
   595  	_, err = fwInst1.IngressRules(t.ProviderCallContext, "1")
   596  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for retrieving ingress rules from instance`)
   597  }
   598  
   599  func (t *LiveTests) TestBootstrapMultiple(c *gc.C) {
   600  	// bootstrap.Bootstrap no longer raises errors if the environment is
   601  	// already up, this has been moved into the bootstrap command.
   602  	t.BootstrapOnce(c)
   603  
   604  	c.Logf("destroy env")
   605  	env := t.Env
   606  	t.Destroy(c)
   607  	err := env.Destroy(t.ProviderCallContext) // Again, should work fine and do nothing.
   608  	c.Assert(err, jc.ErrorIsNil)
   609  
   610  	// check that we can bootstrap after destroy
   611  	t.BootstrapOnce(c)
   612  }
   613  
   614  func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) {
   615  	if !t.CanOpenState || !t.HasProvisioner {
   616  		c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner))
   617  	}
   618  	t.BootstrapOnce(c)
   619  
   620  	// TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts.
   621  
   622  	c.Logf("opening state")
   623  	st := t.Env.(jujutesting.GetStater).GetStateInAPIServer()
   624  
   625  	model, err := st.Model()
   626  	c.Assert(err, jc.ErrorIsNil)
   627  	owner := model.Owner()
   628  
   629  	c.Logf("opening API connection")
   630  	controllerCfg, err := st.ControllerConfig()
   631  	c.Assert(err, jc.ErrorIsNil)
   632  	caCert, _ := controllerCfg.CACert()
   633  	apiInfo, err := environs.APIInfo(t.ProviderCallContext, model.Tag().Id(), model.Tag().Id(), caCert, controllerCfg.APIPort(), t.Env)
   634  	c.Assert(err, jc.ErrorIsNil)
   635  	apiInfo.Tag = owner
   636  	apiInfo.Password = AdminSecret
   637  	apiState, err := api.Open(apiInfo, api.DefaultDialOpts())
   638  	c.Assert(err, jc.ErrorIsNil)
   639  	defer apiState.Close()
   640  
   641  	// Check that the agent version has made it through the
   642  	// bootstrap process (it's optional in the config.Config)
   643  	cfg, err := model.ModelConfig()
   644  	c.Assert(err, jc.ErrorIsNil)
   645  	agentVersion, ok := cfg.AgentVersion()
   646  	c.Check(ok, jc.IsTrue)
   647  	c.Check(agentVersion, gc.Equals, jujuversion.Current)
   648  
   649  	// Check that the constraints have been set in the environment.
   650  	cons, err := st.ModelConstraints()
   651  	c.Assert(err, jc.ErrorIsNil)
   652  	c.Assert(cons.String(), gc.Equals, "mem=2048M")
   653  
   654  	// Wait for machine agent to come up on the bootstrap
   655  	// machine and find the deployed series from that.
   656  	m0, err := st.Machine("0")
   657  	c.Assert(err, jc.ErrorIsNil)
   658  
   659  	instId0, err := m0.InstanceId()
   660  	c.Assert(err, jc.ErrorIsNil)
   661  
   662  	// Check that the API connection is working.
   663  	status, err := apiState.Client().Status(nil)
   664  	c.Assert(err, jc.ErrorIsNil)
   665  	c.Assert(status.Machines["0"].InstanceId, gc.Equals, string(instId0))
   666  
   667  	mw0 := newMachineToolWaiter(m0)
   668  	defer mw0.Stop()
   669  
   670  	// If the series has not been specified, we expect the most recent Ubuntu LTS release to be used.
   671  	expectedVersion := version.Binary{
   672  		Number: jujuversion.Current,
   673  		Arch:   arch.HostArch(),
   674  		Series: supportedversion.SupportedLTS(),
   675  	}
   676  
   677  	mtools0 := waitAgentTools(c, mw0, expectedVersion)
   678  
   679  	// Create a new application and deploy a unit of it.
   680  	c.Logf("deploying application")
   681  	repoDir := c.MkDir()
   682  	url := testcharms.Repo.ClonedURL(repoDir, mtools0.Version.Series, "dummy")
   683  	sch, err := jujutesting.PutCharm(st, url, &charmrepo.LocalRepository{Path: repoDir}, false, false)
   684  	c.Assert(err, jc.ErrorIsNil)
   685  	svc, err := st.AddApplication(state.AddApplicationArgs{Name: "dummy", Charm: sch})
   686  	c.Assert(err, jc.ErrorIsNil)
   687  	unit, err := svc.AddUnit(state.AddUnitParams{})
   688  	c.Assert(err, jc.ErrorIsNil)
   689  	err = st.AssignUnit(unit, state.AssignCleanEmpty)
   690  	c.Assert(err, jc.ErrorIsNil)
   691  
   692  	// Wait for the unit's machine and associated agent to come up
   693  	// and announce itself.
   694  	mid1, err := unit.AssignedMachineId()
   695  	c.Assert(err, jc.ErrorIsNil)
   696  	m1, err := st.Machine(mid1)
   697  	c.Assert(err, jc.ErrorIsNil)
   698  	mw1 := newMachineToolWaiter(m1)
   699  	defer mw1.Stop()
   700  	waitAgentTools(c, mw1, mtools0.Version)
   701  
   702  	err = m1.Refresh()
   703  	c.Assert(err, jc.ErrorIsNil)
   704  	instId1, err := m1.InstanceId()
   705  	c.Assert(err, jc.ErrorIsNil)
   706  	uw := newUnitToolWaiter(unit)
   707  	defer uw.Stop()
   708  	utools := waitAgentTools(c, uw, expectedVersion)
   709  
   710  	// Check that we can upgrade the environment.
   711  	newVersion := utools.Version
   712  	newVersion.Patch++
   713  	t.checkUpgrade(c, st, newVersion, mw0, mw1, uw)
   714  
   715  	// BUG(niemeyer): Logic below is very much wrong. Must be:
   716  	//
   717  	// 1. EnsureDying on the unit and EnsureDying on the machine
   718  	// 2. Unit dies by itself
   719  	// 3. Machine removes dead unit
   720  	// 4. Machine dies by itself
   721  	// 5. Provisioner removes dead machine
   722  	//
   723  
   724  	// Now remove the unit and its assigned machine and
   725  	// check that the PA removes it.
   726  	c.Logf("removing unit")
   727  	err = unit.Destroy()
   728  	c.Assert(err, jc.ErrorIsNil)
   729  
   730  	// Wait until unit is dead
   731  	uwatch := unit.Watch()
   732  	defer uwatch.Stop()
   733  	for unit.Life() != state.Dead {
   734  		c.Logf("waiting for unit change")
   735  		<-uwatch.Changes()
   736  		err := unit.Refresh()
   737  		c.Logf("refreshed; err %v", err)
   738  		if errors.IsNotFound(err) {
   739  			c.Logf("unit has been removed")
   740  			break
   741  		}
   742  		c.Assert(err, jc.ErrorIsNil)
   743  	}
   744  	for {
   745  		c.Logf("destroying machine")
   746  		err := m1.Destroy()
   747  		if err == nil {
   748  			break
   749  		}
   750  		c.Assert(err, gc.FitsTypeOf, &state.HasAssignedUnitsError{})
   751  		time.Sleep(5 * time.Second)
   752  		err = m1.Refresh()
   753  		if errors.IsNotFound(err) {
   754  			break
   755  		}
   756  		c.Assert(err, jc.ErrorIsNil)
   757  	}
   758  	c.Logf("waiting for instance to be removed")
   759  	t.assertStopInstance(c, t.Env, instId1)
   760  }
   761  
   762  type tooler interface {
   763  	Life() state.Life
   764  	AgentTools() (*coretools.Tools, error)
   765  	Refresh() error
   766  	String() string
   767  }
   768  
   769  type watcher interface {
   770  	Stop() error
   771  	Err() error
   772  }
   773  
   774  type toolsWaiter struct {
   775  	lastTools *coretools.Tools
   776  	// changes is a chan of struct{} so that it can
   777  	// be used with different kinds of entity watcher.
   778  	changes chan struct{}
   779  	watcher watcher
   780  	tooler  tooler
   781  }
   782  
   783  func newMachineToolWaiter(m *state.Machine) *toolsWaiter {
   784  	w := m.Watch()
   785  	waiter := &toolsWaiter{
   786  		changes: make(chan struct{}, 1),
   787  		watcher: w,
   788  		tooler:  m,
   789  	}
   790  	go func() {
   791  		for range w.Changes() {
   792  			waiter.changes <- struct{}{}
   793  		}
   794  		close(waiter.changes)
   795  	}()
   796  	return waiter
   797  }
   798  
   799  func newUnitToolWaiter(u *state.Unit) *toolsWaiter {
   800  	w := u.Watch()
   801  	waiter := &toolsWaiter{
   802  		changes: make(chan struct{}, 1),
   803  		watcher: w,
   804  		tooler:  u,
   805  	}
   806  	go func() {
   807  		for range w.Changes() {
   808  			waiter.changes <- struct{}{}
   809  		}
   810  		close(waiter.changes)
   811  	}()
   812  	return waiter
   813  }
   814  
   815  func (w *toolsWaiter) Stop() error {
   816  	return w.watcher.Stop()
   817  }
   818  
   819  // NextTools returns the next changed tools, waiting
   820  // until the tools are actually set.
   821  func (w *toolsWaiter) NextTools(c *gc.C) (*coretools.Tools, error) {
   822  	for range w.changes {
   823  		err := w.tooler.Refresh()
   824  		if err != nil {
   825  			return nil, fmt.Errorf("cannot refresh: %v", err)
   826  		}
   827  		if w.tooler.Life() == state.Dead {
   828  			return nil, fmt.Errorf("object is dead")
   829  		}
   830  		tools, err := w.tooler.AgentTools()
   831  		if errors.IsNotFound(err) {
   832  			c.Logf("tools not yet set")
   833  			continue
   834  		}
   835  		if err != nil {
   836  			return nil, err
   837  		}
   838  		changed := w.lastTools == nil || *tools != *w.lastTools
   839  		w.lastTools = tools
   840  		if changed {
   841  			return tools, nil
   842  		}
   843  		c.Logf("found same tools")
   844  	}
   845  	return nil, fmt.Errorf("watcher closed prematurely: %v", w.watcher.Err())
   846  }
   847  
   848  // waitAgentTools waits for the given agent
   849  // to start and returns the tools that it is running.
   850  func waitAgentTools(c *gc.C, w *toolsWaiter, expect version.Binary) *coretools.Tools {
   851  	c.Logf("waiting for %v to signal agent version", w.tooler.String())
   852  	tools, err := w.NextTools(c)
   853  	c.Assert(err, jc.ErrorIsNil)
   854  	c.Check(tools.Version, gc.Equals, expect)
   855  	return tools
   856  }
   857  
   858  // checkUpgrade sets the environment agent version and checks that
   859  // all the provided watchers upgrade to the requested version.
   860  func (t *LiveTests) checkUpgrade(c *gc.C, st *state.State, newVersion version.Binary, waiters ...*toolsWaiter) {
   861  	c.Logf("putting testing version of juju tools")
   862  	upgradeTools, err := sync.Upload(t.toolsStorage, "released", &newVersion.Number, newVersion.Series)
   863  	c.Assert(err, jc.ErrorIsNil)
   864  	// sync.Upload always returns tools for the series on which the tests are running.
   865  	// We are only interested in checking the version.Number below so need to fake the
   866  	// upgraded tools series to match that of newVersion.
   867  	upgradeTools.Version.Series = newVersion.Series
   868  
   869  	// Check that the put version really is the version we expect.
   870  	c.Assert(upgradeTools.Version, gc.Equals, newVersion)
   871  	err = statetesting.SetAgentVersion(st, newVersion.Number)
   872  	c.Assert(err, jc.ErrorIsNil)
   873  
   874  	for i, w := range waiters {
   875  		c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String())
   876  
   877  		waitAgentTools(c, w, newVersion)
   878  		c.Logf("upgrade %d successful", i)
   879  	}
   880  }
   881  
   882  // TODO(katco): 2016-08-09: lp:1611427
   883  var waitAgent = utils.AttemptStrategy{
   884  	Total: 30 * time.Second,
   885  	Delay: 1 * time.Second,
   886  }
   887  
   888  func (t *LiveTests) assertStopInstance(c *gc.C, env environs.Environ, instId instance.Id) {
   889  	var err error
   890  	for a := waitAgent.Start(); a.Next(); {
   891  		_, err = t.Env.Instances(t.ProviderCallContext, []instance.Id{instId})
   892  		if err == nil {
   893  			continue
   894  		}
   895  		if err == environs.ErrNoInstances {
   896  			return
   897  		}
   898  		c.Logf("error from Instances: %v", err)
   899  	}
   900  	c.Fatalf("provisioner failed to stop machine after %v", waitAgent.Total)
   901  }
   902  
   903  // Check that we get a consistent error when asking for an instance without
   904  // a valid machine config.
   905  func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *gc.C) {
   906  	machineId := "4"
   907  	apiInfo := jujutesting.FakeAPIInfo(machineId)
   908  	instanceConfig, err := instancecfg.NewInstanceConfig(coretesting.ControllerTag, machineId, "", "released", "quantal", apiInfo)
   909  	c.Assert(err, jc.ErrorIsNil)
   910  
   911  	t.PrepareOnce(c)
   912  	possibleTools := coretools.List(envtesting.AssertUploadFakeToolsVersions(
   913  		c, t.toolsStorage, "released", "released", version.MustParseBinary("5.4.5-trusty-amd64"),
   914  	))
   915  	fakeCallback := func(_ status.Status, _ string, _ map[string]interface{}) error {
   916  		return nil
   917  	}
   918  	params := environs.StartInstanceParams{
   919  		ControllerUUID: coretesting.ControllerTag.Id(),
   920  		Tools:          possibleTools,
   921  		InstanceConfig: instanceConfig,
   922  		StatusCallback: fakeCallback,
   923  	}
   924  	err = jujutesting.SetImageMetadata(
   925  		t.Env,
   926  		possibleTools.AllSeries(),
   927  		possibleTools.Arches(),
   928  		&params.ImageMetadata,
   929  	)
   930  	c.Check(err, jc.ErrorIsNil)
   931  	result, err := t.Env.StartInstance(t.ProviderCallContext, params)
   932  	if result != nil && result.Instance != nil {
   933  		err := t.Env.StopInstances(t.ProviderCallContext, result.Instance.Id())
   934  		c.Check(err, jc.ErrorIsNil)
   935  	}
   936  	c.Assert(result, gc.IsNil)
   937  	c.Assert(err, gc.ErrorMatches, ".*missing machine nonce")
   938  }
   939  
   940  func (t *LiveTests) TestBootstrapWithDefaultSeries(c *gc.C) {
   941  	if !t.HasProvisioner {
   942  		c.Skip("HasProvisioner is false; cannot test deployment")
   943  	}
   944  
   945  	current := version.Binary{
   946  		Number: jujuversion.Current,
   947  		Arch:   arch.HostArch(),
   948  		Series: series.MustHostSeries(),
   949  	}
   950  	other := current
   951  	other.Series = "quantal"
   952  	if current == other {
   953  		other.Series = "precise"
   954  	}
   955  
   956  	dummyCfg := dummy.SampleConfig().Merge(coretesting.Attrs{
   957  		"controller": false,
   958  		"name":       "dummy storage",
   959  	})
   960  	args := t.prepareForBootstrapParams(c)
   961  	args.ModelConfig = dummyCfg
   962  	e, err := bootstrap.PrepareController(false, envtesting.BootstrapContext(c),
   963  		jujuclient.NewMemStore(),
   964  		args,
   965  	)
   966  	c.Assert(err, jc.ErrorIsNil)
   967  	defer e.(environs.Environ).Destroy(t.ProviderCallContext)
   968  
   969  	t.Destroy(c)
   970  
   971  	attrs := t.TestConfig.Merge(coretesting.Attrs{
   972  		"name":           "livetests",
   973  		"default-series": other.Series,
   974  	})
   975  	args.ModelConfig = attrs
   976  	env, err := bootstrap.PrepareController(false, envtesting.BootstrapContext(c),
   977  		t.ControllerStore,
   978  		args)
   979  	c.Assert(err, jc.ErrorIsNil)
   980  	defer environs.Destroy("livetests", env, t.ProviderCallContext, t.ControllerStore)
   981  
   982  	err = bootstrap.Bootstrap(envtesting.BootstrapContext(c), env, t.ProviderCallContext, t.bootstrapParams())
   983  	c.Assert(err, jc.ErrorIsNil)
   984  
   985  	st := t.Env.(jujutesting.GetStater).GetStateInAPIServer()
   986  	// Wait for machine agent to come up on the bootstrap
   987  	// machine and ensure it deployed the proper series.
   988  	m0, err := st.Machine("0")
   989  	c.Assert(err, jc.ErrorIsNil)
   990  	mw0 := newMachineToolWaiter(m0)
   991  	defer mw0.Stop()
   992  
   993  	waitAgentTools(c, mw0, other)
   994  }