github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"strings"
    12  	"time"
    13  
    14  	gc "launchpad.net/gocheck"
    15  
    16  	"launchpad.net/juju-core/charm"
    17  	"launchpad.net/juju-core/constraints"
    18  	"launchpad.net/juju-core/environs"
    19  	"launchpad.net/juju-core/environs/bootstrap"
    20  	"launchpad.net/juju-core/environs/config"
    21  	"launchpad.net/juju-core/environs/configstore"
    22  	"launchpad.net/juju-core/environs/storage"
    23  	"launchpad.net/juju-core/environs/sync"
    24  	envtesting "launchpad.net/juju-core/environs/testing"
    25  	envtools "launchpad.net/juju-core/environs/tools"
    26  	"launchpad.net/juju-core/errors"
    27  	"launchpad.net/juju-core/instance"
    28  	"launchpad.net/juju-core/juju"
    29  	"launchpad.net/juju-core/juju/testing"
    30  	"launchpad.net/juju-core/provider/common"
    31  	"launchpad.net/juju-core/provider/dummy"
    32  	"launchpad.net/juju-core/state"
    33  	"launchpad.net/juju-core/state/api"
    34  	statetesting "launchpad.net/juju-core/state/testing"
    35  	coretesting "launchpad.net/juju-core/testing"
    36  	jc "launchpad.net/juju-core/testing/checkers"
    37  	"launchpad.net/juju-core/testing/testbase"
    38  	coretools "launchpad.net/juju-core/tools"
    39  	"launchpad.net/juju-core/utils"
    40  	"launchpad.net/juju-core/version"
    41  )
    42  
    43  // LiveTests contains tests that are designed to run against a live server
    44  // (e.g. Amazon EC2).  The Environ is opened once only for all the tests
    45  // in the suite, stored in Env, and Destroyed after the suite has completed.
    46  type LiveTests struct {
    47  	testbase.LoggingSuite
    48  	envtesting.ToolsFixture
    49  
    50  	// TestConfig contains the configuration attributes for opening an environment.
    51  	TestConfig coretesting.Attrs
    52  
    53  	// Attempt holds a strategy for waiting until the environment
    54  	// becomes logically consistent.
    55  	Attempt utils.AttemptStrategy
    56  
    57  	// CanOpenState should be true if the testing environment allows
    58  	// the state to be opened after bootstrapping.
    59  	CanOpenState bool
    60  
    61  	// HasProvisioner should be true if the environment has
    62  	// a provisioning agent.
    63  	HasProvisioner bool
    64  
    65  	// Env holds the currently opened environment.
    66  	// This is set by PrepareOnce and BootstrapOnce.
    67  	Env environs.Environ
    68  
    69  	// ConfigStore holds the configuration storage
    70  	// used when preparing the environment.
    71  	// This is initialized by SetUpSuite.
    72  	ConfigStore configstore.Storage
    73  
    74  	prepared     bool
    75  	bootstrapped bool
    76  }
    77  
    78  func (t *LiveTests) SetUpSuite(c *gc.C) {
    79  	t.LoggingSuite.SetUpSuite(c)
    80  	t.ConfigStore = configstore.NewMem()
    81  }
    82  
    83  func (t *LiveTests) SetUpTest(c *gc.C) {
    84  	t.LoggingSuite.SetUpTest(c)
    85  	t.ToolsFixture.SetUpTest(c)
    86  }
    87  
    88  func publicAttrs(e environs.Environ) map[string]interface{} {
    89  	cfg := e.Config()
    90  	secrets, err := e.Provider().SecretAttrs(cfg)
    91  	if err != nil {
    92  		panic(err)
    93  	}
    94  	attrs := cfg.AllAttrs()
    95  	for attr := range secrets {
    96  		delete(attrs, attr)
    97  	}
    98  	return attrs
    99  }
   100  
   101  func (t *LiveTests) TearDownSuite(c *gc.C) {
   102  	if t.Env != nil {
   103  		t.Destroy(c)
   104  	}
   105  	t.LoggingSuite.TearDownSuite(c)
   106  }
   107  
   108  func (t *LiveTests) TearDownTest(c *gc.C) {
   109  	t.ToolsFixture.TearDownTest(c)
   110  	t.LoggingSuite.TearDownTest(c)
   111  }
   112  
   113  // PrepareOnce ensures that the environment is
   114  // available and prepared. It sets t.Env appropriately.
   115  func (t *LiveTests) PrepareOnce(c *gc.C) {
   116  	if t.prepared {
   117  		return
   118  	}
   119  	cfg, err := config.New(config.NoDefaults, t.TestConfig)
   120  	c.Assert(err, gc.IsNil)
   121  	e, err := environs.Prepare(cfg, coretesting.Context(c), t.ConfigStore)
   122  	c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", t.TestConfig))
   123  	c.Assert(e, gc.NotNil)
   124  	t.Env = e
   125  	t.prepared = true
   126  }
   127  
   128  func (t *LiveTests) BootstrapOnce(c *gc.C) {
   129  	if t.bootstrapped {
   130  		return
   131  	}
   132  	t.PrepareOnce(c)
   133  	// We only build and upload tools if there will be a state agent that
   134  	// we could connect to (actual live tests, rather than local-only)
   135  	cons := constraints.MustParse("mem=2G")
   136  	if t.CanOpenState {
   137  		_, err := sync.Upload(t.Env.Storage(), nil, config.DefaultSeries)
   138  		c.Assert(err, gc.IsNil)
   139  	}
   140  	envtesting.UploadFakeTools(c, t.Env.Storage())
   141  	err := common.EnsureNotBootstrapped(t.Env)
   142  	c.Assert(err, gc.IsNil)
   143  	err = bootstrap.Bootstrap(coretesting.Context(c), t.Env, cons)
   144  	c.Assert(err, gc.IsNil)
   145  	t.bootstrapped = true
   146  }
   147  
   148  func (t *LiveTests) Destroy(c *gc.C) {
   149  	if t.Env == nil {
   150  		return
   151  	}
   152  	err := environs.Destroy(t.Env, t.ConfigStore)
   153  	c.Assert(err, gc.IsNil)
   154  	t.bootstrapped = false
   155  	t.prepared = false
   156  	t.Env = nil
   157  }
   158  
   159  func (t *LiveTests) TestPrechecker(c *gc.C) {
   160  	// Providers may implement Prechecker. If they do, then they should
   161  	// return nil for empty constraints (excluding the null provider).
   162  	prechecker, ok := t.Env.(state.Prechecker)
   163  	if !ok {
   164  		return
   165  	}
   166  	err := prechecker.PrecheckInstance("precise", constraints.Value{})
   167  	c.Assert(err, gc.IsNil)
   168  }
   169  
   170  // TestStartStop is similar to Tests.TestStartStop except
   171  // that it does not assume a pristine environment.
   172  func (t *LiveTests) TestStartStop(c *gc.C) {
   173  	t.PrepareOnce(c)
   174  	envtesting.UploadFakeTools(c, t.Env.Storage())
   175  
   176  	inst, _ := testing.AssertStartInstance(c, t.Env, "0")
   177  	c.Assert(inst, gc.NotNil)
   178  	id0 := inst.Id()
   179  
   180  	insts, err := t.Env.Instances([]instance.Id{id0, id0})
   181  	c.Assert(err, gc.IsNil)
   182  	c.Assert(insts, gc.HasLen, 2)
   183  	c.Assert(insts[0].Id(), gc.Equals, id0)
   184  	c.Assert(insts[1].Id(), gc.Equals, id0)
   185  
   186  	// Asserting on the return of AllInstances makes the test fragile,
   187  	// as even comparing the before and after start values can be thrown
   188  	// off if other instances have been created or destroyed in the same
   189  	// time frame. Instead, just check the instance we created exists.
   190  	insts, err = t.Env.AllInstances()
   191  	c.Assert(err, gc.IsNil)
   192  	found := false
   193  	for _, inst := range insts {
   194  		if inst.Id() == id0 {
   195  			c.Assert(found, gc.Equals, false, gc.Commentf("%v", insts))
   196  			found = true
   197  		}
   198  	}
   199  	c.Assert(found, gc.Equals, true, gc.Commentf("expected %v in %v", inst, insts))
   200  
   201  	dns, err := inst.WaitDNSName()
   202  	c.Assert(err, gc.IsNil)
   203  	c.Assert(dns, gc.Not(gc.Equals), "")
   204  
   205  	insts, err = t.Env.Instances([]instance.Id{id0, ""})
   206  	c.Assert(err, gc.Equals, environs.ErrPartialInstances)
   207  	c.Assert(insts, gc.HasLen, 2)
   208  	c.Check(insts[0].Id(), gc.Equals, id0)
   209  	c.Check(insts[1], gc.IsNil)
   210  
   211  	err = t.Env.StopInstances([]instance.Instance{inst})
   212  	c.Assert(err, gc.IsNil)
   213  
   214  	// The machine may not be marked as shutting down
   215  	// immediately. Repeat a few times to ensure we get the error.
   216  	for a := t.Attempt.Start(); a.Next(); {
   217  		insts, err = t.Env.Instances([]instance.Id{id0})
   218  		if err != nil {
   219  			break
   220  		}
   221  	}
   222  	c.Assert(err, gc.Equals, environs.ErrNoInstances)
   223  	c.Assert(insts, gc.HasLen, 0)
   224  }
   225  
   226  func (t *LiveTests) TestPorts(c *gc.C) {
   227  	t.PrepareOnce(c)
   228  	envtesting.UploadFakeTools(c, t.Env.Storage())
   229  
   230  	inst1, _ := testing.AssertStartInstance(c, t.Env, "1")
   231  	c.Assert(inst1, gc.NotNil)
   232  	defer t.Env.StopInstances([]instance.Instance{inst1})
   233  	ports, err := inst1.Ports("1")
   234  	c.Assert(err, gc.IsNil)
   235  	c.Assert(ports, gc.HasLen, 0)
   236  
   237  	inst2, _ := testing.AssertStartInstance(c, t.Env, "2")
   238  	c.Assert(inst2, gc.NotNil)
   239  	ports, err = inst2.Ports("2")
   240  	c.Assert(err, gc.IsNil)
   241  	c.Assert(ports, gc.HasLen, 0)
   242  	defer t.Env.StopInstances([]instance.Instance{inst2})
   243  
   244  	// Open some ports and check they're there.
   245  	err = inst1.OpenPorts("1", []instance.Port{{"udp", 67}, {"tcp", 45}})
   246  	c.Assert(err, gc.IsNil)
   247  	ports, err = inst1.Ports("1")
   248  	c.Assert(err, gc.IsNil)
   249  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}})
   250  	ports, err = inst2.Ports("2")
   251  	c.Assert(err, gc.IsNil)
   252  	c.Assert(ports, gc.HasLen, 0)
   253  
   254  	err = inst2.OpenPorts("2", []instance.Port{{"tcp", 89}, {"tcp", 45}})
   255  	c.Assert(err, gc.IsNil)
   256  
   257  	// Check there's no crosstalk to another machine
   258  	ports, err = inst2.Ports("2")
   259  	c.Assert(err, gc.IsNil)
   260  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}})
   261  	ports, err = inst1.Ports("1")
   262  	c.Assert(err, gc.IsNil)
   263  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}})
   264  
   265  	// Check that opening the same port again is ok.
   266  	oldPorts, err := inst2.Ports("2")
   267  	c.Assert(err, gc.IsNil)
   268  	err = inst2.OpenPorts("2", []instance.Port{{"tcp", 45}})
   269  	c.Assert(err, gc.IsNil)
   270  	ports, err = inst2.Ports("2")
   271  	c.Assert(err, gc.IsNil)
   272  	c.Assert(ports, gc.DeepEquals, oldPorts)
   273  
   274  	// Check that opening the same port again and another port is ok.
   275  	err = inst2.OpenPorts("2", []instance.Port{{"tcp", 45}, {"tcp", 99}})
   276  	c.Assert(err, gc.IsNil)
   277  	ports, err = inst2.Ports("2")
   278  	c.Assert(err, gc.IsNil)
   279  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}, {"tcp", 99}})
   280  
   281  	err = inst2.ClosePorts("2", []instance.Port{{"tcp", 45}, {"tcp", 99}})
   282  	c.Assert(err, gc.IsNil)
   283  
   284  	// Check that we can close ports and that there's no crosstalk.
   285  	ports, err = inst2.Ports("2")
   286  	c.Assert(err, gc.IsNil)
   287  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 89}})
   288  	ports, err = inst1.Ports("1")
   289  	c.Assert(err, gc.IsNil)
   290  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}})
   291  
   292  	// Check that we can close multiple ports.
   293  	err = inst1.ClosePorts("1", []instance.Port{{"tcp", 45}, {"udp", 67}})
   294  	c.Assert(err, gc.IsNil)
   295  	ports, err = inst1.Ports("1")
   296  	c.Assert(ports, gc.HasLen, 0)
   297  
   298  	// Check that we can close ports that aren't there.
   299  	err = inst2.ClosePorts("2", []instance.Port{{"tcp", 111}, {"udp", 222}})
   300  	c.Assert(err, gc.IsNil)
   301  	ports, err = inst2.Ports("2")
   302  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 89}})
   303  
   304  	// Check errors when acting on environment.
   305  	err = t.Env.OpenPorts([]instance.Port{{"tcp", 80}})
   306  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for opening ports on environment`)
   307  
   308  	err = t.Env.ClosePorts([]instance.Port{{"tcp", 80}})
   309  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for closing ports on environment`)
   310  
   311  	_, err = t.Env.Ports()
   312  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for retrieving ports from environment`)
   313  }
   314  
   315  func (t *LiveTests) TestGlobalPorts(c *gc.C) {
   316  	t.PrepareOnce(c)
   317  	envtesting.UploadFakeTools(c, t.Env.Storage())
   318  
   319  	// Change configuration.
   320  	oldConfig := t.Env.Config()
   321  	defer func() {
   322  		err := t.Env.SetConfig(oldConfig)
   323  		c.Assert(err, gc.IsNil)
   324  	}()
   325  
   326  	attrs := t.Env.Config().AllAttrs()
   327  	attrs["firewall-mode"] = "global"
   328  	newConfig, err := t.Env.Config().Apply(attrs)
   329  	c.Assert(err, gc.IsNil)
   330  	err = t.Env.SetConfig(newConfig)
   331  	c.Assert(err, gc.IsNil)
   332  
   333  	// Create instances and check open ports on both instances.
   334  	inst1, _ := testing.AssertStartInstance(c, t.Env, "1")
   335  	defer t.Env.StopInstances([]instance.Instance{inst1})
   336  	ports, err := t.Env.Ports()
   337  	c.Assert(err, gc.IsNil)
   338  	c.Assert(ports, gc.HasLen, 0)
   339  
   340  	inst2, _ := testing.AssertStartInstance(c, t.Env, "2")
   341  	ports, err = t.Env.Ports()
   342  	c.Assert(err, gc.IsNil)
   343  	c.Assert(ports, gc.HasLen, 0)
   344  	defer t.Env.StopInstances([]instance.Instance{inst2})
   345  
   346  	err = t.Env.OpenPorts([]instance.Port{{"udp", 67}, {"tcp", 45}, {"tcp", 89}, {"tcp", 99}})
   347  	c.Assert(err, gc.IsNil)
   348  
   349  	ports, err = t.Env.Ports()
   350  	c.Assert(err, gc.IsNil)
   351  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}, {"tcp", 99}, {"udp", 67}})
   352  
   353  	// Check closing some ports.
   354  	err = t.Env.ClosePorts([]instance.Port{{"tcp", 99}, {"udp", 67}})
   355  	c.Assert(err, gc.IsNil)
   356  
   357  	ports, err = t.Env.Ports()
   358  	c.Assert(err, gc.IsNil)
   359  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}})
   360  
   361  	// Check that we can close ports that aren't there.
   362  	err = t.Env.ClosePorts([]instance.Port{{"tcp", 111}, {"udp", 222}})
   363  	c.Assert(err, gc.IsNil)
   364  
   365  	ports, err = t.Env.Ports()
   366  	c.Assert(err, gc.IsNil)
   367  	c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}})
   368  
   369  	// Check errors when acting on instances.
   370  	err = inst1.OpenPorts("1", []instance.Port{{"tcp", 80}})
   371  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for opening ports on instance`)
   372  
   373  	err = inst1.ClosePorts("1", []instance.Port{{"tcp", 80}})
   374  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for closing ports on instance`)
   375  
   376  	_, err = inst1.Ports("1")
   377  	c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for retrieving ports from instance`)
   378  }
   379  
   380  func (t *LiveTests) TestBootstrapMultiple(c *gc.C) {
   381  	// bootstrap.Bootstrap no longer raises errors if the environment is
   382  	// already up, this has been moved into the bootstrap command.
   383  	t.BootstrapOnce(c)
   384  
   385  	err := common.EnsureNotBootstrapped(t.Env)
   386  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   387  
   388  	c.Logf("destroy env")
   389  	env := t.Env
   390  	t.Destroy(c)
   391  	env.Destroy() // Again, should work fine and do nothing.
   392  
   393  	// check that we can bootstrap after destroy
   394  	t.BootstrapOnce(c)
   395  }
   396  
   397  func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) {
   398  	if !t.CanOpenState || !t.HasProvisioner {
   399  		c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner))
   400  	}
   401  	t.BootstrapOnce(c)
   402  
   403  	// TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts.
   404  
   405  	c.Logf("opening connection")
   406  	conn, err := juju.NewConn(t.Env)
   407  	c.Assert(err, gc.IsNil)
   408  	defer conn.Close()
   409  
   410  	c.Logf("opening API connection")
   411  	apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts())
   412  	c.Assert(err, gc.IsNil)
   413  	defer conn.Close()
   414  
   415  	// Check that the agent version has made it through the
   416  	// bootstrap process (it's optional in the config.Config)
   417  	cfg, err := conn.State.EnvironConfig()
   418  	c.Assert(err, gc.IsNil)
   419  	agentVersion, ok := cfg.AgentVersion()
   420  	c.Check(ok, gc.Equals, true)
   421  	c.Check(agentVersion, gc.Equals, version.Current.Number)
   422  
   423  	// Check that the constraints have been set in the environment.
   424  	cons, err := conn.State.EnvironConstraints()
   425  	c.Assert(err, gc.IsNil)
   426  	c.Assert(cons.String(), gc.Equals, "mem=2048M")
   427  
   428  	// Wait for machine agent to come up on the bootstrap
   429  	// machine and find the deployed series from that.
   430  	m0, err := conn.State.Machine("0")
   431  	c.Assert(err, gc.IsNil)
   432  
   433  	instId0, err := m0.InstanceId()
   434  	c.Assert(err, gc.IsNil)
   435  
   436  	// Check that the API connection is working.
   437  	status, err := apiConn.State.Client().Status(nil)
   438  	c.Assert(err, gc.IsNil)
   439  	c.Assert(status.Machines["0"].InstanceId, gc.Equals, string(instId0))
   440  
   441  	mw0 := newMachineToolWaiter(m0)
   442  	defer mw0.Stop()
   443  
   444  	// If the series has not been specified, we expect the most recent Ubuntu LTS release to be used.
   445  	expectedVersion := version.Current
   446  	expectedVersion.Series = config.DefaultSeries
   447  
   448  	mtools0 := waitAgentTools(c, mw0, expectedVersion)
   449  
   450  	// Create a new service and deploy a unit of it.
   451  	c.Logf("deploying service")
   452  	repoDir := c.MkDir()
   453  	url := coretesting.Charms.ClonedURL(repoDir, mtools0.Version.Series, "dummy")
   454  	sch, err := conn.PutCharm(url, &charm.LocalRepository{repoDir}, false)
   455  	c.Assert(err, gc.IsNil)
   456  	svc, err := conn.State.AddService("dummy", "user-admin", sch)
   457  	c.Assert(err, gc.IsNil)
   458  	units, err := juju.AddUnits(conn.State, svc, 1, "")
   459  	c.Assert(err, gc.IsNil)
   460  	unit := units[0]
   461  
   462  	// Wait for the unit's machine and associated agent to come up
   463  	// and announce itself.
   464  	mid1, err := unit.AssignedMachineId()
   465  	c.Assert(err, gc.IsNil)
   466  	m1, err := conn.State.Machine(mid1)
   467  	c.Assert(err, gc.IsNil)
   468  	mw1 := newMachineToolWaiter(m1)
   469  	defer mw1.Stop()
   470  	waitAgentTools(c, mw1, mtools0.Version)
   471  
   472  	err = m1.Refresh()
   473  	c.Assert(err, gc.IsNil)
   474  	instId1, err := m1.InstanceId()
   475  	c.Assert(err, gc.IsNil)
   476  	uw := newUnitToolWaiter(unit)
   477  	defer uw.Stop()
   478  	utools := waitAgentTools(c, uw, expectedVersion)
   479  
   480  	// Check that we can upgrade the environment.
   481  	newVersion := utools.Version
   482  	newVersion.Patch++
   483  	t.checkUpgrade(c, conn, newVersion, mw0, mw1, uw)
   484  
   485  	// BUG(niemeyer): Logic below is very much wrong. Must be:
   486  	//
   487  	// 1. EnsureDying on the unit and EnsureDying on the machine
   488  	// 2. Unit dies by itself
   489  	// 3. Machine removes dead unit
   490  	// 4. Machine dies by itself
   491  	// 5. Provisioner removes dead machine
   492  	//
   493  
   494  	// Now remove the unit and its assigned machine and
   495  	// check that the PA removes it.
   496  	c.Logf("removing unit")
   497  	err = unit.Destroy()
   498  	c.Assert(err, gc.IsNil)
   499  
   500  	// Wait until unit is dead
   501  	uwatch := unit.Watch()
   502  	defer uwatch.Stop()
   503  	for unit.Life() != state.Dead {
   504  		c.Logf("waiting for unit change")
   505  		<-uwatch.Changes()
   506  		err := unit.Refresh()
   507  		c.Logf("refreshed; err %v", err)
   508  		if errors.IsNotFoundError(err) {
   509  			c.Logf("unit has been removed")
   510  			break
   511  		}
   512  		c.Assert(err, gc.IsNil)
   513  	}
   514  	for {
   515  		c.Logf("destroying machine")
   516  		err := m1.Destroy()
   517  		if err == nil {
   518  			break
   519  		}
   520  		c.Assert(err, gc.FitsTypeOf, &state.HasAssignedUnitsError{})
   521  		time.Sleep(5 * time.Second)
   522  		err = m1.Refresh()
   523  		if errors.IsNotFoundError(err) {
   524  			break
   525  		}
   526  		c.Assert(err, gc.IsNil)
   527  	}
   528  	c.Logf("waiting for instance to be removed")
   529  	t.assertStopInstance(c, conn.Environ, instId1)
   530  }
   531  
   532  func (t *LiveTests) TestBootstrapVerifyStorage(c *gc.C) {
   533  	// Bootstrap automatically verifies that storage is writable.
   534  	t.BootstrapOnce(c)
   535  	environ := t.Env
   536  	stor := environ.Storage()
   537  	reader, err := storage.Get(stor, "bootstrap-verify")
   538  	c.Assert(err, gc.IsNil)
   539  	defer reader.Close()
   540  	contents, err := ioutil.ReadAll(reader)
   541  	c.Assert(err, gc.IsNil)
   542  	c.Check(string(contents), gc.Equals,
   543  		"juju-core storage writing verified: ok\n")
   544  }
   545  
   546  func restoreBootstrapVerificationFile(c *gc.C, stor storage.Storage) {
   547  	content := "juju-core storage writing verified: ok\n"
   548  	contentReader := strings.NewReader(content)
   549  	err := stor.Put("bootstrap-verify", contentReader,
   550  		int64(len(content)))
   551  	c.Assert(err, gc.IsNil)
   552  }
   553  
   554  func (t *LiveTests) TestCheckEnvironmentOnConnect(c *gc.C) {
   555  	// When new connection is established to a bootstraped environment,
   556  	// it is checked that we are running against a juju-core environment.
   557  	if !t.CanOpenState {
   558  		c.Skip("CanOpenState is false; cannot open state connection")
   559  	}
   560  	t.BootstrapOnce(c)
   561  
   562  	conn, err := juju.NewConn(t.Env)
   563  	c.Assert(err, gc.IsNil)
   564  	conn.Close()
   565  
   566  	apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts())
   567  	c.Assert(err, gc.IsNil)
   568  	apiConn.Close()
   569  }
   570  
   571  func (t *LiveTests) TestCheckEnvironmentOnConnectNoVerificationFile(c *gc.C) {
   572  	// When new connection is established to a bootstraped environment,
   573  	// it is checked that we are running against a juju-core environment.
   574  	//
   575  	// Absence of a verification file means it is a juju-core environment
   576  	// with an older version, which is fine.
   577  	if !t.CanOpenState {
   578  		c.Skip("CanOpenState is false; cannot open state connection")
   579  	}
   580  	t.BootstrapOnce(c)
   581  	environ := t.Env
   582  	stor := environ.Storage()
   583  	err := stor.Remove("bootstrap-verify")
   584  	c.Assert(err, gc.IsNil)
   585  	defer restoreBootstrapVerificationFile(c, stor)
   586  
   587  	conn, err := juju.NewConn(t.Env)
   588  	c.Assert(err, gc.IsNil)
   589  	conn.Close()
   590  }
   591  
   592  func (t *LiveTests) TestCheckEnvironmentOnConnectBadVerificationFile(c *gc.C) {
   593  	// When new connection is established to a bootstraped environment,
   594  	// it is checked that we are running against a juju-core environment.
   595  	//
   596  	// If the verification file has unexpected content, it is not
   597  	// a juju-core environment (likely to a Python juju environment).
   598  	if !t.CanOpenState {
   599  		c.Skip("CanOpenState is false; cannot open state connection")
   600  	}
   601  	t.BootstrapOnce(c)
   602  	environ := t.Env
   603  	stor := environ.Storage()
   604  
   605  	// Finally, replace the content with an arbitrary string.
   606  	badVerificationContent := "bootstrap storage verification"
   607  	reader := strings.NewReader(badVerificationContent)
   608  	err := stor.Put(
   609  		"bootstrap-verify",
   610  		reader,
   611  		int64(len(badVerificationContent)))
   612  	c.Assert(err, gc.IsNil)
   613  	defer restoreBootstrapVerificationFile(c, stor)
   614  
   615  	// Running NewConn() should fail.
   616  	_, err = juju.NewConn(t.Env)
   617  	c.Assert(err, gc.Equals, environs.InvalidEnvironmentError)
   618  }
   619  
   620  type tooler interface {
   621  	Life() state.Life
   622  	AgentTools() (*coretools.Tools, error)
   623  	Refresh() error
   624  	String() string
   625  }
   626  
   627  type watcher interface {
   628  	Stop() error
   629  	Err() error
   630  }
   631  
   632  type toolsWaiter struct {
   633  	lastTools *coretools.Tools
   634  	// changes is a chan of struct{} so that it can
   635  	// be used with different kinds of entity watcher.
   636  	changes chan struct{}
   637  	watcher watcher
   638  	tooler  tooler
   639  }
   640  
   641  func newMachineToolWaiter(m *state.Machine) *toolsWaiter {
   642  	w := m.Watch()
   643  	waiter := &toolsWaiter{
   644  		changes: make(chan struct{}, 1),
   645  		watcher: w,
   646  		tooler:  m,
   647  	}
   648  	go func() {
   649  		for _ = range w.Changes() {
   650  			waiter.changes <- struct{}{}
   651  		}
   652  		close(waiter.changes)
   653  	}()
   654  	return waiter
   655  }
   656  
   657  func newUnitToolWaiter(u *state.Unit) *toolsWaiter {
   658  	w := u.Watch()
   659  	waiter := &toolsWaiter{
   660  		changes: make(chan struct{}, 1),
   661  		watcher: w,
   662  		tooler:  u,
   663  	}
   664  	go func() {
   665  		for _ = range w.Changes() {
   666  			waiter.changes <- struct{}{}
   667  		}
   668  		close(waiter.changes)
   669  	}()
   670  	return waiter
   671  }
   672  
   673  func (w *toolsWaiter) Stop() error {
   674  	return w.watcher.Stop()
   675  }
   676  
   677  // NextTools returns the next changed tools, waiting
   678  // until the tools are actually set.
   679  func (w *toolsWaiter) NextTools(c *gc.C) (*coretools.Tools, error) {
   680  	for _ = range w.changes {
   681  		err := w.tooler.Refresh()
   682  		if err != nil {
   683  			return nil, fmt.Errorf("cannot refresh: %v", err)
   684  		}
   685  		if w.tooler.Life() == state.Dead {
   686  			return nil, fmt.Errorf("object is dead")
   687  		}
   688  		tools, err := w.tooler.AgentTools()
   689  		if errors.IsNotFoundError(err) {
   690  			c.Logf("tools not yet set")
   691  			continue
   692  		}
   693  		if err != nil {
   694  			return nil, err
   695  		}
   696  		changed := w.lastTools == nil || *tools != *w.lastTools
   697  		w.lastTools = tools
   698  		if changed {
   699  			return tools, nil
   700  		}
   701  		c.Logf("found same tools")
   702  	}
   703  	return nil, fmt.Errorf("watcher closed prematurely: %v", w.watcher.Err())
   704  }
   705  
   706  // waitAgentTools waits for the given agent
   707  // to start and returns the tools that it is running.
   708  func waitAgentTools(c *gc.C, w *toolsWaiter, expect version.Binary) *coretools.Tools {
   709  	c.Logf("waiting for %v to signal agent version", w.tooler.String())
   710  	tools, err := w.NextTools(c)
   711  	c.Assert(err, gc.IsNil)
   712  	c.Check(tools.Version, gc.Equals, expect)
   713  	return tools
   714  }
   715  
   716  // checkUpgrade sets the environment agent version and checks that
   717  // all the provided watchers upgrade to the requested version.
   718  func (t *LiveTests) checkUpgrade(c *gc.C, conn *juju.Conn, newVersion version.Binary, waiters ...*toolsWaiter) {
   719  	c.Logf("putting testing version of juju tools")
   720  	upgradeTools, err := sync.Upload(t.Env.Storage(), &newVersion.Number, newVersion.Series)
   721  	c.Assert(err, gc.IsNil)
   722  	// sync.Upload always returns tools for the series on which the tests are running.
   723  	// We are only interested in checking the version.Number below so need to fake the
   724  	// upgraded tools series to match that of newVersion.
   725  	upgradeTools.Version.Series = newVersion.Series
   726  
   727  	// Check that the put version really is the version we expect.
   728  	c.Assert(upgradeTools.Version, gc.Equals, newVersion)
   729  	err = statetesting.SetAgentVersion(conn.State, newVersion.Number)
   730  	c.Assert(err, gc.IsNil)
   731  
   732  	for i, w := range waiters {
   733  		c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String())
   734  
   735  		waitAgentTools(c, w, newVersion)
   736  		c.Logf("upgrade %d successful", i)
   737  	}
   738  }
   739  
   740  var waitAgent = utils.AttemptStrategy{
   741  	Total: 30 * time.Second,
   742  	Delay: 1 * time.Second,
   743  }
   744  
   745  func (t *LiveTests) assertStartInstance(c *gc.C, m *state.Machine) {
   746  	// Wait for machine to get an instance id.
   747  	for a := waitAgent.Start(); a.Next(); {
   748  		err := m.Refresh()
   749  		c.Assert(err, gc.IsNil)
   750  		instId, err := m.InstanceId()
   751  		if err != nil {
   752  			c.Assert(err, jc.Satisfies, state.IsNotProvisionedError)
   753  			continue
   754  		}
   755  		_, err = t.Env.Instances([]instance.Id{instId})
   756  		c.Assert(err, gc.IsNil)
   757  		return
   758  	}
   759  	c.Fatalf("provisioner failed to start machine after %v", waitAgent.Total)
   760  }
   761  
   762  func (t *LiveTests) assertStopInstance(c *gc.C, env environs.Environ, instId instance.Id) {
   763  	var err error
   764  	for a := waitAgent.Start(); a.Next(); {
   765  		_, err = t.Env.Instances([]instance.Id{instId})
   766  		if err == nil {
   767  			continue
   768  		}
   769  		if err == environs.ErrNoInstances {
   770  			return
   771  		}
   772  		c.Logf("error from Instances: %v", err)
   773  	}
   774  	c.Fatalf("provisioner failed to stop machine after %v", waitAgent.Total)
   775  }
   776  
   777  // assertInstanceId asserts that the machine has an instance id
   778  // that matches that of the given instance. If the instance is nil,
   779  // It asserts that the instance id is unset.
   780  func assertInstanceId(c *gc.C, m *state.Machine, inst instance.Instance) {
   781  	var wantId, gotId instance.Id
   782  	var err error
   783  	if inst != nil {
   784  		wantId = inst.Id()
   785  	}
   786  	for a := waitAgent.Start(); a.Next(); {
   787  		err := m.Refresh()
   788  		c.Assert(err, gc.IsNil)
   789  		gotId, err = m.InstanceId()
   790  		if err != nil {
   791  			c.Assert(err, jc.Satisfies, state.IsNotProvisionedError)
   792  			if inst == nil {
   793  				return
   794  			}
   795  			continue
   796  		}
   797  		break
   798  	}
   799  	c.Assert(err, gc.IsNil)
   800  	c.Assert(gotId, gc.Equals, wantId)
   801  }
   802  
   803  // TODO check that binary data works ok?
   804  var contents = []byte("hello\n")
   805  var contents2 = []byte("goodbye\n\n")
   806  
   807  func (t *LiveTests) TestFile(c *gc.C) {
   808  	t.PrepareOnce(c)
   809  	name := fmt.Sprint("testfile", time.Now().UnixNano())
   810  	stor := t.Env.Storage()
   811  
   812  	checkFileDoesNotExist(c, stor, name, t.Attempt)
   813  	checkPutFile(c, stor, name, contents)
   814  	checkFileHasContents(c, stor, name, contents, t.Attempt)
   815  	checkPutFile(c, stor, name, contents2) // check that we can overwrite the file
   816  	checkFileHasContents(c, stor, name, contents2, t.Attempt)
   817  
   818  	// check that the listed contents include the
   819  	// expected name.
   820  	found := false
   821  	var names []string
   822  attempt:
   823  	for a := t.Attempt.Start(); a.Next(); {
   824  		var err error
   825  		names, err = stor.List("")
   826  		c.Assert(err, gc.IsNil)
   827  		for _, lname := range names {
   828  			if lname == name {
   829  				found = true
   830  				break attempt
   831  			}
   832  		}
   833  	}
   834  	if !found {
   835  		c.Errorf("file name %q not found in file list %q", name, names)
   836  	}
   837  	err := stor.Remove(name)
   838  	c.Check(err, gc.IsNil)
   839  	checkFileDoesNotExist(c, stor, name, t.Attempt)
   840  	// removing a file that does not exist should not be an error.
   841  	err = stor.Remove(name)
   842  	c.Check(err, gc.IsNil)
   843  
   844  	// RemoveAll deletes all files from storage.
   845  	checkPutFile(c, stor, "file-1.txt", contents)
   846  	checkPutFile(c, stor, "file-2.txt", contents)
   847  	err = stor.RemoveAll()
   848  	c.Check(err, gc.IsNil)
   849  	checkFileDoesNotExist(c, stor, "file-1.txt", t.Attempt)
   850  	checkFileDoesNotExist(c, stor, "file-2.txt", t.Attempt)
   851  }
   852  
   853  // Check that we get a consistent error when asking for an instance without
   854  // a valid machine config.
   855  func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *gc.C) {
   856  	machineId := "4"
   857  	stateInfo := testing.FakeStateInfo(machineId)
   858  	apiInfo := testing.FakeAPIInfo(machineId)
   859  	machineConfig := environs.NewMachineConfig(machineId, "", "", stateInfo, apiInfo)
   860  
   861  	t.PrepareOnce(c)
   862  	possibleTools := envtesting.AssertUploadFakeToolsVersions(c, t.Env.Storage(), version.MustParseBinary("5.4.5-precise-amd64"))
   863  	inst, _, err := t.Env.StartInstance(constraints.Value{}, possibleTools, machineConfig)
   864  	if inst != nil {
   865  		err := t.Env.StopInstances([]instance.Instance{inst})
   866  		c.Check(err, gc.IsNil)
   867  	}
   868  	c.Assert(inst, gc.IsNil)
   869  	c.Assert(err, gc.ErrorMatches, ".*missing machine nonce")
   870  }
   871  
   872  func (t *LiveTests) TestBootstrapWithDefaultSeries(c *gc.C) {
   873  	if !t.HasProvisioner {
   874  		c.Skip("HasProvisioner is false; cannot test deployment")
   875  	}
   876  
   877  	current := version.Current
   878  	other := current
   879  	other.Series = "quantal"
   880  	if current == other {
   881  		other.Series = "precise"
   882  	}
   883  
   884  	dummyCfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(coretesting.Attrs{
   885  		"state-server": false,
   886  		"name":         "dummy storage",
   887  	}))
   888  	dummyenv, err := environs.Prepare(dummyCfg, coretesting.Context(c), configstore.NewMem())
   889  	c.Assert(err, gc.IsNil)
   890  	defer dummyenv.Destroy()
   891  
   892  	t.Destroy(c)
   893  
   894  	attrs := t.TestConfig.Merge(coretesting.Attrs{"default-series": other.Series})
   895  	cfg, err := config.New(config.NoDefaults, attrs)
   896  	c.Assert(err, gc.IsNil)
   897  	env, err := environs.Prepare(cfg, coretesting.Context(c), t.ConfigStore)
   898  	c.Assert(err, gc.IsNil)
   899  	defer environs.Destroy(env, t.ConfigStore)
   900  
   901  	currentName := envtools.StorageName(current)
   902  	otherName := envtools.StorageName(other)
   903  	envStorage := env.Storage()
   904  	dummyStorage := dummyenv.Storage()
   905  
   906  	defer envStorage.Remove(otherName)
   907  
   908  	_, err = sync.Upload(dummyStorage, &current.Number)
   909  	c.Assert(err, gc.IsNil)
   910  
   911  	// This will only work while cross-compiling across releases is safe,
   912  	// which depends on external elements. Tends to be safe for the last
   913  	// few releases, but we may have to refactor some day.
   914  	err = storageCopy(dummyStorage, currentName, envStorage, otherName)
   915  	c.Assert(err, gc.IsNil)
   916  
   917  	err = bootstrap.Bootstrap(coretesting.Context(c), env, constraints.Value{})
   918  	c.Assert(err, gc.IsNil)
   919  
   920  	conn, err := juju.NewConn(env)
   921  	c.Assert(err, gc.IsNil)
   922  	defer conn.Close()
   923  
   924  	// Wait for machine agent to come up on the bootstrap
   925  	// machine and ensure it deployed the proper series.
   926  	m0, err := conn.State.Machine("0")
   927  	c.Assert(err, gc.IsNil)
   928  	mw0 := newMachineToolWaiter(m0)
   929  	defer mw0.Stop()
   930  
   931  	waitAgentTools(c, mw0, other)
   932  }
   933  
   934  func storageCopy(source storage.Storage, sourcePath string, target storage.Storage, targetPath string) error {
   935  	rc, err := storage.Get(source, sourcePath)
   936  	if err != nil {
   937  		return err
   938  	}
   939  	var buf bytes.Buffer
   940  	_, err = io.Copy(&buf, rc)
   941  	rc.Close()
   942  	if err != nil {
   943  		return err
   944  	}
   945  	return target.Put(targetPath, &buf, int64(buf.Len()))
   946  }