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