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