github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/unit_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	jc "github.com/juju/testing/checkers"
    12  	jujutxn "github.com/juju/txn"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/juju/charm.v6-unstable"
    15  
    16  	"github.com/juju/juju/instance"
    17  	"github.com/juju/juju/network"
    18  	"github.com/juju/juju/state"
    19  	"github.com/juju/juju/state/testing"
    20  	"github.com/juju/juju/status"
    21  	coretesting "github.com/juju/juju/testing"
    22  	"github.com/juju/juju/worker"
    23  )
    24  
    25  const (
    26  	contentionErr = ".*: state changing too quickly; try again soon"
    27  )
    28  
    29  type UnitSuite struct {
    30  	ConnSuite
    31  	charm   *state.Charm
    32  	service *state.Application
    33  	unit    *state.Unit
    34  }
    35  
    36  var _ = gc.Suite(&UnitSuite{})
    37  
    38  func (s *UnitSuite) SetUpTest(c *gc.C) {
    39  	s.ConnSuite.SetUpTest(c)
    40  	s.charm = s.AddTestingCharm(c, "wordpress")
    41  	var err error
    42  	s.service = s.AddTestingService(c, "wordpress", s.charm)
    43  	c.Assert(err, jc.ErrorIsNil)
    44  	s.unit, err = s.service.AddUnit()
    45  	c.Assert(err, jc.ErrorIsNil)
    46  	c.Assert(s.unit.Series(), gc.Equals, "quantal")
    47  }
    48  
    49  func (s *UnitSuite) TestUnitNotFound(c *gc.C) {
    50  	_, err := s.State.Unit("subway/0")
    51  	c.Assert(err, gc.ErrorMatches, `unit "subway/0" not found`)
    52  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
    53  }
    54  
    55  func (s *UnitSuite) TestService(c *gc.C) {
    56  	svc, err := s.unit.Application()
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	c.Assert(svc.Name(), gc.Equals, s.unit.ApplicationName())
    59  }
    60  
    61  func (s *UnitSuite) TestConfigSettingsNeedCharmURLSet(c *gc.C) {
    62  	_, err := s.unit.ConfigSettings()
    63  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
    64  }
    65  
    66  func (s *UnitSuite) TestConfigSettingsIncludeDefaults(c *gc.C) {
    67  	err := s.unit.SetCharmURL(s.charm.URL())
    68  	c.Assert(err, jc.ErrorIsNil)
    69  	settings, err := s.unit.ConfigSettings()
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"})
    72  }
    73  
    74  func (s *UnitSuite) TestConfigSettingsReflectService(c *gc.C) {
    75  	err := s.service.UpdateConfigSettings(charm.Settings{"blog-title": "no title"})
    76  	c.Assert(err, jc.ErrorIsNil)
    77  	err = s.unit.SetCharmURL(s.charm.URL())
    78  	c.Assert(err, jc.ErrorIsNil)
    79  	settings, err := s.unit.ConfigSettings()
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "no title"})
    82  
    83  	err = s.service.UpdateConfigSettings(charm.Settings{"blog-title": "ironic title"})
    84  	c.Assert(err, jc.ErrorIsNil)
    85  	settings, err = s.unit.ConfigSettings()
    86  	c.Assert(err, jc.ErrorIsNil)
    87  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "ironic title"})
    88  }
    89  
    90  func (s *UnitSuite) TestConfigSettingsReflectCharm(c *gc.C) {
    91  	err := s.unit.SetCharmURL(s.charm.URL())
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	newCharm := s.AddConfigCharm(c, "wordpress", "options: {}", 123)
    94  	cfg := state.SetCharmConfig{Charm: newCharm}
    95  	err = s.service.SetCharm(cfg)
    96  	c.Assert(err, jc.ErrorIsNil)
    97  
    98  	// Settings still reflect charm set on unit.
    99  	settings, err := s.unit.ConfigSettings()
   100  	c.Assert(err, jc.ErrorIsNil)
   101  	c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"})
   102  
   103  	// When the unit has the new charm set, it'll see the new config.
   104  	err = s.unit.SetCharmURL(newCharm.URL())
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	settings, err = s.unit.ConfigSettings()
   107  	c.Assert(err, jc.ErrorIsNil)
   108  	c.Assert(settings, gc.DeepEquals, charm.Settings{})
   109  }
   110  
   111  func (s *UnitSuite) TestWatchConfigSettingsNeedsCharmURL(c *gc.C) {
   112  	_, err := s.unit.WatchConfigSettings()
   113  	c.Assert(err, gc.ErrorMatches, "unit charm not set")
   114  }
   115  
   116  func (s *UnitSuite) TestWatchConfigSettings(c *gc.C) {
   117  	err := s.unit.SetCharmURL(s.charm.URL())
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	w, err := s.unit.WatchConfigSettings()
   120  	c.Assert(err, jc.ErrorIsNil)
   121  	defer testing.AssertStop(c, w)
   122  
   123  	// Initial event.
   124  	wc := testing.NewNotifyWatcherC(c, s.State, w)
   125  	wc.AssertOneChange()
   126  
   127  	// Update config a couple of times, check a single event.
   128  	err = s.service.UpdateConfigSettings(charm.Settings{
   129  		"blog-title": "superhero paparazzi",
   130  	})
   131  	c.Assert(err, jc.ErrorIsNil)
   132  	err = s.service.UpdateConfigSettings(charm.Settings{
   133  		"blog-title": "sauceror central",
   134  	})
   135  	c.Assert(err, jc.ErrorIsNil)
   136  	wc.AssertOneChange()
   137  
   138  	// Non-change is not reported.
   139  	err = s.service.UpdateConfigSettings(charm.Settings{
   140  		"blog-title": "sauceror central",
   141  	})
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	wc.AssertNoChange()
   144  
   145  	// Change service's charm; nothing detected.
   146  	newCharm := s.AddConfigCharm(c, "wordpress", floatConfig, 123)
   147  	cfg := state.SetCharmConfig{Charm: newCharm}
   148  	err = s.service.SetCharm(cfg)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	wc.AssertNoChange()
   151  
   152  	// Change service config for new charm; nothing detected.
   153  	err = s.service.UpdateConfigSettings(charm.Settings{
   154  		"key": 42.0,
   155  	})
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	wc.AssertNoChange()
   158  
   159  	// NOTE: if we were to change the unit to use the new charm, we'd see
   160  	// another event, because the originally-watched document will become
   161  	// unreferenced and be removed. But I'm not testing that behaviour
   162  	// because it's not very helpful and subject to change.
   163  }
   164  
   165  func (s *UnitSuite) addSubordinateUnit(c *gc.C) *state.Unit {
   166  	subCharm := s.AddTestingCharm(c, "logging")
   167  	s.AddTestingService(c, "logging", subCharm)
   168  	eps, err := s.State.InferEndpoints("wordpress", "logging")
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	rel, err := s.State.AddRelation(eps...)
   171  	c.Assert(err, jc.ErrorIsNil)
   172  	ru, err := rel.Unit(s.unit)
   173  	c.Assert(err, jc.ErrorIsNil)
   174  	err = ru.EnterScope(nil)
   175  	c.Assert(err, jc.ErrorIsNil)
   176  	subUnit, err := s.State.Unit("logging/0")
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	return subUnit
   179  }
   180  
   181  func (s *UnitSuite) setAssignedMachineAddresses(c *gc.C, u *state.Unit) {
   182  	err := u.AssignToNewMachine()
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	mid, err := u.AssignedMachineId()
   185  	c.Assert(err, jc.ErrorIsNil)
   186  	machine, err := s.State.Machine(mid)
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	err = machine.SetProvisioned("i-exist", "fake_nonce", nil)
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	err = machine.SetProviderAddresses(network.Address{
   191  		Type:  network.IPv4Address,
   192  		Scope: network.ScopeCloudLocal,
   193  		Value: "private.address.example.com",
   194  	}, network.Address{
   195  		Type:  network.IPv4Address,
   196  		Scope: network.ScopePublic,
   197  		Value: "public.address.example.com",
   198  	})
   199  	c.Assert(err, jc.ErrorIsNil)
   200  }
   201  
   202  func (s *UnitSuite) TestPublicAddressSubordinate(c *gc.C) {
   203  	subUnit := s.addSubordinateUnit(c)
   204  	address, err := subUnit.PublicAddress()
   205  	c.Assert(err, gc.Not(gc.IsNil))
   206  	c.Assert(address.Value, gc.Equals, "")
   207  
   208  	s.setAssignedMachineAddresses(c, s.unit)
   209  	address, err = subUnit.PublicAddress()
   210  	c.Assert(err, jc.ErrorIsNil)
   211  	c.Assert(address.Value, gc.Equals, "public.address.example.com")
   212  }
   213  
   214  func (s *UnitSuite) TestPublicAddress(c *gc.C) {
   215  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   216  	c.Assert(err, jc.ErrorIsNil)
   217  	err = s.unit.AssignToMachine(machine)
   218  	c.Assert(err, jc.ErrorIsNil)
   219  
   220  	_, err = s.unit.PublicAddress()
   221  	c.Assert(err, jc.Satisfies, network.IsNoAddressError)
   222  
   223  	public := network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   224  	private := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal)
   225  
   226  	err = machine.SetProviderAddresses(public, private)
   227  	c.Assert(err, jc.ErrorIsNil)
   228  
   229  	address, err := s.unit.PublicAddress()
   230  	c.Assert(err, jc.ErrorIsNil)
   231  	c.Check(address.Value, gc.Equals, "8.8.8.8")
   232  }
   233  
   234  func (s *UnitSuite) TestStablePrivateAddress(c *gc.C) {
   235  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   236  	c.Assert(err, jc.ErrorIsNil)
   237  	err = s.unit.AssignToMachine(machine)
   238  	c.Assert(err, jc.ErrorIsNil)
   239  
   240  	err = machine.SetMachineAddresses(network.NewAddress("10.0.0.2"))
   241  	c.Assert(err, jc.ErrorIsNil)
   242  
   243  	// Now add an address that would previously have sorted before the
   244  	// default.
   245  	err = machine.SetMachineAddresses(network.NewAddress("10.0.0.1"), network.NewAddress("10.0.0.2"))
   246  	c.Assert(err, jc.ErrorIsNil)
   247  
   248  	// Assert the address is unchanged.
   249  	addr, err := s.unit.PrivateAddress()
   250  	c.Assert(err, jc.ErrorIsNil)
   251  	c.Assert(addr.Value, gc.Equals, "10.0.0.2")
   252  }
   253  
   254  func (s *UnitSuite) TestStablePublicAddress(c *gc.C) {
   255  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   256  	c.Assert(err, jc.ErrorIsNil)
   257  	err = s.unit.AssignToMachine(machine)
   258  	c.Assert(err, jc.ErrorIsNil)
   259  
   260  	err = machine.SetProviderAddresses(network.NewAddress("8.8.8.8"))
   261  	c.Assert(err, jc.ErrorIsNil)
   262  
   263  	// Now add an address that would previously have sorted before the
   264  	// default.
   265  	err = machine.SetProviderAddresses(network.NewAddress("8.8.4.4"), network.NewAddress("8.8.8.8"))
   266  	c.Assert(err, jc.ErrorIsNil)
   267  
   268  	// Assert the address is unchanged.
   269  	addr, err := s.unit.PublicAddress()
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	c.Assert(addr.Value, gc.Equals, "8.8.8.8")
   272  }
   273  
   274  func (s *UnitSuite) TestPublicAddressMachineAddresses(c *gc.C) {
   275  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   276  	c.Assert(err, jc.ErrorIsNil)
   277  	err = s.unit.AssignToMachine(machine)
   278  	c.Assert(err, jc.ErrorIsNil)
   279  
   280  	publicProvider := network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   281  	privateProvider := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal)
   282  	privateMachine := network.NewAddress("127.0.0.2")
   283  
   284  	err = machine.SetProviderAddresses(privateProvider)
   285  	c.Assert(err, jc.ErrorIsNil)
   286  	err = machine.SetMachineAddresses(privateMachine)
   287  	c.Assert(err, jc.ErrorIsNil)
   288  	address, err := s.unit.PublicAddress()
   289  	c.Assert(err, jc.ErrorIsNil)
   290  	c.Check(address.Value, gc.Equals, "127.0.0.1")
   291  
   292  	err = machine.SetProviderAddresses(publicProvider, privateProvider)
   293  	c.Assert(err, jc.ErrorIsNil)
   294  	address, err = s.unit.PublicAddress()
   295  	c.Assert(err, jc.ErrorIsNil)
   296  	c.Check(address.Value, gc.Equals, "8.8.8.8")
   297  }
   298  
   299  func (s *UnitSuite) TestPrivateAddressSubordinate(c *gc.C) {
   300  	subUnit := s.addSubordinateUnit(c)
   301  	address, err := subUnit.PrivateAddress()
   302  	c.Assert(err, gc.Not(gc.IsNil))
   303  	c.Assert(address.Value, gc.Equals, "")
   304  
   305  	s.setAssignedMachineAddresses(c, s.unit)
   306  	address, err = subUnit.PrivateAddress()
   307  	c.Assert(err, jc.ErrorIsNil)
   308  	c.Assert(address.Value, gc.Equals, "private.address.example.com")
   309  }
   310  
   311  func (s *UnitSuite) TestPrivateAddress(c *gc.C) {
   312  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   313  	c.Assert(err, jc.ErrorIsNil)
   314  	err = s.unit.AssignToMachine(machine)
   315  	c.Assert(err, jc.ErrorIsNil)
   316  
   317  	_, err = s.unit.PrivateAddress()
   318  	c.Assert(err, jc.Satisfies, network.IsNoAddressError)
   319  
   320  	public := network.NewScopedAddress("8.8.8.8", network.ScopePublic)
   321  	private := network.NewScopedAddress("127.0.0.1", network.ScopeCloudLocal)
   322  
   323  	err = machine.SetProviderAddresses(public, private)
   324  	c.Assert(err, jc.ErrorIsNil)
   325  
   326  	address, err := s.unit.PrivateAddress()
   327  	c.Assert(err, jc.ErrorIsNil)
   328  	c.Check(address.Value, gc.Equals, "127.0.0.1")
   329  }
   330  
   331  type destroyMachineTestCase struct {
   332  	target    *state.Unit
   333  	host      *state.Machine
   334  	desc      string
   335  	flipHook  []jujutxn.TestHook
   336  	destroyed bool
   337  }
   338  
   339  func (s *UnitSuite) destroyMachineTestCases(c *gc.C) []destroyMachineTestCase {
   340  	var result []destroyMachineTestCase
   341  	var err error
   342  
   343  	{
   344  		tc := destroyMachineTestCase{desc: "standalone principal", destroyed: true}
   345  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   346  		c.Assert(err, jc.ErrorIsNil)
   347  		tc.target, err = s.service.AddUnit()
   348  		c.Assert(err, jc.ErrorIsNil)
   349  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   350  		result = append(result, tc)
   351  	}
   352  	{
   353  		tc := destroyMachineTestCase{desc: "co-located principals", destroyed: false}
   354  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   355  		c.Assert(err, jc.ErrorIsNil)
   356  		tc.target, err = s.service.AddUnit()
   357  		c.Assert(err, jc.ErrorIsNil)
   358  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   359  		colocated, err := s.service.AddUnit()
   360  		c.Assert(err, jc.ErrorIsNil)
   361  		c.Assert(colocated.AssignToMachine(tc.host), gc.IsNil)
   362  
   363  		result = append(result, tc)
   364  	}
   365  	{
   366  		tc := destroyMachineTestCase{desc: "host has container", destroyed: false}
   367  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   368  		c.Assert(err, jc.ErrorIsNil)
   369  		_, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
   370  			Series: "quantal",
   371  			Jobs:   []state.MachineJob{state.JobHostUnits},
   372  		}, tc.host.Id(), instance.LXD)
   373  		c.Assert(err, jc.ErrorIsNil)
   374  		tc.target, err = s.service.AddUnit()
   375  		c.Assert(err, jc.ErrorIsNil)
   376  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   377  
   378  		result = append(result, tc)
   379  	}
   380  	{
   381  		tc := destroyMachineTestCase{desc: "host has vote", destroyed: false}
   382  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   383  		c.Assert(err, jc.ErrorIsNil)
   384  		c.Assert(tc.host.SetHasVote(true), gc.IsNil)
   385  		tc.target, err = s.service.AddUnit()
   386  		c.Assert(err, jc.ErrorIsNil)
   387  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   388  
   389  		result = append(result, tc)
   390  	}
   391  	{
   392  		tc := destroyMachineTestCase{desc: "unassigned unit", destroyed: true}
   393  		tc.host, err = s.State.AddMachine("quantal", state.JobHostUnits)
   394  		c.Assert(err, jc.ErrorIsNil)
   395  		tc.target, err = s.service.AddUnit()
   396  		c.Assert(err, jc.ErrorIsNil)
   397  		c.Assert(tc.target.AssignToMachine(tc.host), gc.IsNil)
   398  		result = append(result, tc)
   399  	}
   400  
   401  	return result
   402  }
   403  
   404  func (s *UnitSuite) TestRemoveUnitMachineFastForwardDestroy(c *gc.C) {
   405  	for _, tc := range s.destroyMachineTestCases(c) {
   406  		c.Log(tc.desc)
   407  		c.Assert(tc.target.Destroy(), gc.IsNil)
   408  		if tc.destroyed {
   409  			assertLife(c, tc.host, state.Dying)
   410  			c.Assert(tc.host.EnsureDead(), gc.IsNil)
   411  		} else {
   412  			assertLife(c, tc.host, state.Alive)
   413  			c.Assert(tc.host.Destroy(), gc.NotNil)
   414  		}
   415  	}
   416  }
   417  
   418  func (s *UnitSuite) TestRemoveUnitMachineNoFastForwardDestroy(c *gc.C) {
   419  	for _, tc := range s.destroyMachineTestCases(c) {
   420  		c.Log(tc.desc)
   421  		preventUnitDestroyRemove(c, tc.target)
   422  		c.Assert(tc.target.Destroy(), gc.IsNil)
   423  		c.Assert(tc.target.EnsureDead(), gc.IsNil)
   424  		assertLife(c, tc.host, state.Alive)
   425  		c.Assert(tc.target.Remove(), gc.IsNil)
   426  		if tc.destroyed {
   427  			assertLife(c, tc.host, state.Dying)
   428  		} else {
   429  			assertLife(c, tc.host, state.Alive)
   430  			c.Assert(tc.host.Destroy(), gc.NotNil)
   431  		}
   432  	}
   433  }
   434  
   435  func (s *UnitSuite) setMachineVote(c *gc.C, id string, hasVote bool) {
   436  	m, err := s.State.Machine(id)
   437  	c.Assert(err, jc.ErrorIsNil)
   438  	c.Assert(m.SetHasVote(hasVote), gc.IsNil)
   439  }
   440  
   441  func (s *UnitSuite) TestRemoveUnitMachineThrashed(c *gc.C) {
   442  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   443  	c.Assert(err, jc.ErrorIsNil)
   444  	target, err := s.service.AddUnit()
   445  	c.Assert(err, jc.ErrorIsNil)
   446  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   447  	flip := jujutxn.TestHook{
   448  		Before: func() {
   449  			s.setMachineVote(c, host.Id(), true)
   450  		},
   451  	}
   452  	flop := jujutxn.TestHook{
   453  		Before: func() {
   454  			s.setMachineVote(c, host.Id(), false)
   455  		},
   456  	}
   457  	// You'll need to adjust the flip-flops to match the number of transaction
   458  	// retries.
   459  	defer state.SetTestHooks(c, s.State, flip, flop, flip).Check()
   460  
   461  	c.Assert(target.Destroy(), gc.ErrorMatches, "state changing too quickly; try again soon")
   462  }
   463  
   464  func (s *UnitSuite) TestRemoveUnitMachineRetryVoter(c *gc.C) {
   465  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   466  	c.Assert(err, jc.ErrorIsNil)
   467  	target, err := s.service.AddUnit()
   468  	c.Assert(err, jc.ErrorIsNil)
   469  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   470  
   471  	defer state.SetBeforeHooks(c, s.State, func() {
   472  		s.setMachineVote(c, host.Id(), true)
   473  	}, nil).Check()
   474  
   475  	c.Assert(target.Destroy(), gc.IsNil)
   476  	assertLife(c, host, state.Alive)
   477  }
   478  
   479  func (s *UnitSuite) TestRemoveUnitMachineRetryNoVoter(c *gc.C) {
   480  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   481  	c.Assert(err, jc.ErrorIsNil)
   482  	target, err := s.service.AddUnit()
   483  	c.Assert(err, jc.ErrorIsNil)
   484  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   485  	c.Assert(host.SetHasVote(true), gc.IsNil)
   486  
   487  	defer state.SetBeforeHooks(c, s.State, func() {
   488  		s.setMachineVote(c, host.Id(), false)
   489  	}, nil).Check()
   490  
   491  	c.Assert(target.Destroy(), gc.IsNil)
   492  	assertLife(c, host, state.Dying)
   493  }
   494  
   495  func (s *UnitSuite) TestRemoveUnitMachineRetryContainer(c *gc.C) {
   496  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   497  	c.Assert(err, jc.ErrorIsNil)
   498  	target, err := s.service.AddUnit()
   499  	c.Assert(err, jc.ErrorIsNil)
   500  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   501  	defer state.SetTestHooks(c, s.State, jujutxn.TestHook{
   502  		Before: func() {
   503  			machine, err := s.State.AddMachineInsideMachine(state.MachineTemplate{
   504  				Series: "quantal",
   505  				Jobs:   []state.MachineJob{state.JobHostUnits},
   506  			}, host.Id(), instance.LXD)
   507  			c.Assert(err, jc.ErrorIsNil)
   508  			assertLife(c, machine, state.Alive)
   509  
   510  			// test-setup verification for the disqualifying machine.
   511  			hostHandle, err := s.State.Machine(host.Id())
   512  			c.Assert(err, jc.ErrorIsNil)
   513  			containers, err := hostHandle.Containers()
   514  			c.Assert(err, jc.ErrorIsNil)
   515  			c.Assert(containers, gc.HasLen, 1)
   516  		},
   517  	}).Check()
   518  
   519  	c.Assert(target.Destroy(), gc.IsNil)
   520  	assertLife(c, host, state.Alive)
   521  }
   522  
   523  func (s *UnitSuite) TestRemoveUnitMachineRetryOrCond(c *gc.C) {
   524  	host, err := s.State.AddMachine("quantal", state.JobHostUnits)
   525  	c.Assert(err, jc.ErrorIsNil)
   526  	target, err := s.service.AddUnit()
   527  	c.Assert(err, jc.ErrorIsNil)
   528  	c.Assert(target.AssignToMachine(host), gc.IsNil)
   529  
   530  	// This unit will be colocated in the transaction hook to cause a retry.
   531  	colocated, err := s.service.AddUnit()
   532  	c.Assert(err, jc.ErrorIsNil)
   533  
   534  	c.Assert(host.SetHasVote(true), gc.IsNil)
   535  
   536  	defer state.SetTestHooks(c, s.State, jujutxn.TestHook{
   537  		Before: func() {
   538  			hostHandle, err := s.State.Machine(host.Id())
   539  			c.Assert(err, jc.ErrorIsNil)
   540  
   541  			// Original assertion preventing host removal is no longer valid
   542  			c.Assert(hostHandle.SetHasVote(false), gc.IsNil)
   543  
   544  			// But now the host gets a colocated unit, a different condition preventing removal
   545  			c.Assert(colocated.AssignToMachine(hostHandle), gc.IsNil)
   546  		},
   547  	}).Check()
   548  
   549  	c.Assert(target.Destroy(), gc.IsNil)
   550  	assertLife(c, host, state.Alive)
   551  }
   552  
   553  func (s *UnitSuite) TestRefresh(c *gc.C) {
   554  	unit1, err := s.State.Unit(s.unit.Name())
   555  	c.Assert(err, jc.ErrorIsNil)
   556  
   557  	err = s.unit.SetPassword("arble-farble-dying-yarble")
   558  	c.Assert(err, jc.ErrorIsNil)
   559  	valid := unit1.PasswordValid("arble-farble-dying-yarble")
   560  	c.Assert(valid, jc.IsFalse)
   561  	err = unit1.Refresh()
   562  	c.Assert(err, jc.ErrorIsNil)
   563  	valid = unit1.PasswordValid("arble-farble-dying-yarble")
   564  	c.Assert(valid, jc.IsTrue)
   565  
   566  	err = unit1.EnsureDead()
   567  	c.Assert(err, jc.ErrorIsNil)
   568  	err = unit1.Remove()
   569  	c.Assert(err, jc.ErrorIsNil)
   570  	err = unit1.Refresh()
   571  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   572  }
   573  
   574  func (s *UnitSuite) TestSetCharmURLSuccess(c *gc.C) {
   575  	preventUnitDestroyRemove(c, s.unit)
   576  	curl, ok := s.unit.CharmURL()
   577  	c.Assert(ok, jc.IsFalse)
   578  	c.Assert(curl, gc.IsNil)
   579  
   580  	err := s.unit.SetCharmURL(s.charm.URL())
   581  	c.Assert(err, jc.ErrorIsNil)
   582  
   583  	curl, ok = s.unit.CharmURL()
   584  	c.Assert(ok, jc.IsTrue)
   585  	c.Assert(curl, gc.DeepEquals, s.charm.URL())
   586  }
   587  
   588  func (s *UnitSuite) TestSetCharmURLFailures(c *gc.C) {
   589  	preventUnitDestroyRemove(c, s.unit)
   590  	curl, ok := s.unit.CharmURL()
   591  	c.Assert(ok, jc.IsFalse)
   592  	c.Assert(curl, gc.IsNil)
   593  
   594  	err := s.unit.SetCharmURL(nil)
   595  	c.Assert(err, gc.ErrorMatches, "cannot set nil charm url")
   596  
   597  	err = s.unit.SetCharmURL(charm.MustParseURL("cs:missing/one-1"))
   598  	c.Assert(err, gc.ErrorMatches, `unknown charm url "cs:missing/one-1"`)
   599  
   600  	err = s.unit.EnsureDead()
   601  	c.Assert(err, jc.ErrorIsNil)
   602  	err = s.unit.SetCharmURL(s.charm.URL())
   603  	c.Assert(err, gc.Equals, state.ErrDead)
   604  }
   605  
   606  func (s *UnitSuite) TestSetCharmURLWithRemovedUnit(c *gc.C) {
   607  	err := s.unit.Destroy()
   608  	c.Assert(err, jc.ErrorIsNil)
   609  	assertRemoved(c, s.unit)
   610  
   611  	err = s.unit.SetCharmURL(s.charm.URL())
   612  	c.Assert(err, gc.Equals, state.ErrDead)
   613  }
   614  
   615  func (s *UnitSuite) TestSetCharmURLWithDyingUnit(c *gc.C) {
   616  	preventUnitDestroyRemove(c, s.unit)
   617  	err := s.unit.Destroy()
   618  	c.Assert(err, jc.ErrorIsNil)
   619  	assertLife(c, s.unit, state.Dying)
   620  
   621  	err = s.unit.SetCharmURL(s.charm.URL())
   622  	c.Assert(err, jc.ErrorIsNil)
   623  
   624  	curl, ok := s.unit.CharmURL()
   625  	c.Assert(ok, jc.IsTrue)
   626  	c.Assert(curl, gc.DeepEquals, s.charm.URL())
   627  }
   628  
   629  func (s *UnitSuite) TestSetCharmURLRetriesWithDeadUnit(c *gc.C) {
   630  	preventUnitDestroyRemove(c, s.unit)
   631  
   632  	defer state.SetBeforeHooks(c, s.State, func() {
   633  		err := s.unit.Destroy()
   634  		c.Assert(err, jc.ErrorIsNil)
   635  		err = s.unit.EnsureDead()
   636  		c.Assert(err, jc.ErrorIsNil)
   637  		assertLife(c, s.unit, state.Dead)
   638  	}).Check()
   639  
   640  	err := s.unit.SetCharmURL(s.charm.URL())
   641  	c.Assert(err, gc.Equals, state.ErrDead)
   642  }
   643  
   644  func (s *UnitSuite) TestSetCharmURLRetriesWithDifferentURL(c *gc.C) {
   645  	sch := s.AddConfigCharm(c, "wordpress", emptyConfig, 2)
   646  
   647  	defer state.SetTestHooks(c, s.State,
   648  		jujutxn.TestHook{
   649  			Before: func() {
   650  				// Set a different charm to force a retry: first on
   651  				// the service, so the settings are created, then on
   652  				// the unit.
   653  				cfg := state.SetCharmConfig{Charm: sch}
   654  				err := s.service.SetCharm(cfg)
   655  				c.Assert(err, jc.ErrorIsNil)
   656  				err = s.unit.SetCharmURL(sch.URL())
   657  				c.Assert(err, jc.ErrorIsNil)
   658  			},
   659  			After: func() {
   660  				// Set back the same charm on the service, so the
   661  				// settings refcount is correct..
   662  				cfg := state.SetCharmConfig{Charm: s.charm}
   663  				err := s.service.SetCharm(cfg)
   664  				c.Assert(err, jc.ErrorIsNil)
   665  			},
   666  		},
   667  		jujutxn.TestHook{
   668  			Before: nil, // Ensure there will be a retry.
   669  			After: func() {
   670  				// Verify it worked after the second attempt.
   671  				err := s.unit.Refresh()
   672  				c.Assert(err, jc.ErrorIsNil)
   673  				currentURL, hasURL := s.unit.CharmURL()
   674  				c.Assert(currentURL, jc.DeepEquals, s.charm.URL())
   675  				c.Assert(hasURL, jc.IsTrue)
   676  			},
   677  		},
   678  	).Check()
   679  
   680  	err := s.unit.SetCharmURL(s.charm.URL())
   681  	c.Assert(err, jc.ErrorIsNil)
   682  }
   683  
   684  func (s *UnitSuite) TestDestroySetStatusRetry(c *gc.C) {
   685  	defer state.SetRetryHooks(c, s.State, func() {
   686  		now := time.Now()
   687  		sInfo := status.StatusInfo{
   688  			Status:  status.Idle,
   689  			Message: "",
   690  			Since:   &now,
   691  		}
   692  		err := s.unit.SetAgentStatus(sInfo)
   693  		c.Assert(err, jc.ErrorIsNil)
   694  	}, func() {
   695  		assertLife(c, s.unit, state.Dying)
   696  	}).Check()
   697  
   698  	err := s.unit.Destroy()
   699  	c.Assert(err, jc.ErrorIsNil)
   700  }
   701  
   702  func (s *UnitSuite) TestDestroySetCharmRetry(c *gc.C) {
   703  	defer state.SetRetryHooks(c, s.State, func() {
   704  		err := s.unit.SetCharmURL(s.charm.URL())
   705  		c.Assert(err, jc.ErrorIsNil)
   706  	}, func() {
   707  		assertRemoved(c, s.unit)
   708  	}).Check()
   709  
   710  	err := s.unit.Destroy()
   711  	c.Assert(err, jc.ErrorIsNil)
   712  }
   713  
   714  func (s *UnitSuite) TestDestroyChangeCharmRetry(c *gc.C) {
   715  	err := s.unit.SetCharmURL(s.charm.URL())
   716  	c.Assert(err, jc.ErrorIsNil)
   717  	newCharm := s.AddConfigCharm(c, "mysql", "options: {}", 99)
   718  	cfg := state.SetCharmConfig{Charm: newCharm}
   719  	err = s.service.SetCharm(cfg)
   720  	c.Assert(err, jc.ErrorIsNil)
   721  
   722  	defer state.SetRetryHooks(c, s.State, func() {
   723  		err := s.unit.SetCharmURL(newCharm.URL())
   724  		c.Assert(err, jc.ErrorIsNil)
   725  	}, func() {
   726  		assertRemoved(c, s.unit)
   727  	}).Check()
   728  
   729  	err = s.unit.Destroy()
   730  	c.Assert(err, jc.ErrorIsNil)
   731  }
   732  
   733  func (s *UnitSuite) TestDestroyAssignRetry(c *gc.C) {
   734  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   735  	c.Assert(err, jc.ErrorIsNil)
   736  
   737  	defer state.SetRetryHooks(c, s.State, func() {
   738  		err := s.unit.AssignToMachine(machine)
   739  		c.Assert(err, jc.ErrorIsNil)
   740  	}, func() {
   741  		assertRemoved(c, s.unit)
   742  		// Also check the unit ref was properly removed from the machine doc --
   743  		// if it weren't, we wouldn't be able to make the machine Dead.
   744  		err := machine.EnsureDead()
   745  		c.Assert(err, jc.ErrorIsNil)
   746  	}).Check()
   747  
   748  	err = s.unit.Destroy()
   749  	c.Assert(err, jc.ErrorIsNil)
   750  }
   751  
   752  func (s *UnitSuite) TestDestroyUnassignRetry(c *gc.C) {
   753  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   754  	c.Assert(err, jc.ErrorIsNil)
   755  	err = s.unit.AssignToMachine(machine)
   756  	c.Assert(err, jc.ErrorIsNil)
   757  
   758  	defer state.SetRetryHooks(c, s.State, func() {
   759  		err := s.unit.UnassignFromMachine()
   760  		c.Assert(err, jc.ErrorIsNil)
   761  	}, func() {
   762  		assertRemoved(c, s.unit)
   763  	}).Check()
   764  
   765  	err = s.unit.Destroy()
   766  	c.Assert(err, jc.ErrorIsNil)
   767  }
   768  
   769  func (s *UnitSuite) TestShortCircuitDestroyUnit(c *gc.C) {
   770  	// A unit that has not set any status is removed directly.
   771  	err := s.unit.Destroy()
   772  	c.Assert(err, jc.ErrorIsNil)
   773  	c.Assert(s.unit.Life(), gc.Equals, state.Dying)
   774  	assertRemoved(c, s.unit)
   775  }
   776  
   777  func (s *UnitSuite) TestCannotShortCircuitDestroyWithSubordinates(c *gc.C) {
   778  	// A unit with subordinates is just set to Dying.
   779  	s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
   780  	eps, err := s.State.InferEndpoints("logging", "wordpress")
   781  	c.Assert(err, jc.ErrorIsNil)
   782  	rel, err := s.State.AddRelation(eps...)
   783  	c.Assert(err, jc.ErrorIsNil)
   784  	ru, err := rel.Unit(s.unit)
   785  	c.Assert(err, jc.ErrorIsNil)
   786  	err = ru.EnterScope(nil)
   787  	c.Assert(err, jc.ErrorIsNil)
   788  	err = s.unit.Destroy()
   789  	c.Assert(err, jc.ErrorIsNil)
   790  	c.Assert(s.unit.Life(), gc.Equals, state.Dying)
   791  	assertLife(c, s.unit, state.Dying)
   792  }
   793  
   794  func (s *UnitSuite) TestCannotShortCircuitDestroyWithAgentStatus(c *gc.C) {
   795  	for i, test := range []struct {
   796  		status status.Status
   797  		info   string
   798  	}{{
   799  		status.Executing, "blah",
   800  	}, {
   801  		status.Idle, "blah",
   802  	}, {
   803  		status.Failed, "blah",
   804  	}, {
   805  		status.Rebooting, "blah",
   806  	}} {
   807  		c.Logf("test %d: %s", i, test.status)
   808  		unit, err := s.service.AddUnit()
   809  		c.Assert(err, jc.ErrorIsNil)
   810  		now := time.Now()
   811  		sInfo := status.StatusInfo{
   812  			Status:  test.status,
   813  			Message: test.info,
   814  			Since:   &now,
   815  		}
   816  		err = unit.SetAgentStatus(sInfo)
   817  		c.Assert(err, jc.ErrorIsNil)
   818  		err = unit.Destroy()
   819  		c.Assert(err, jc.ErrorIsNil)
   820  		c.Assert(unit.Life(), gc.Equals, state.Dying)
   821  		assertLife(c, unit, state.Dying)
   822  	}
   823  }
   824  
   825  func (s *UnitSuite) TestShortCircuitDestroyWithProvisionedMachine(c *gc.C) {
   826  	// A unit assigned to a provisioned machine is still removed directly so
   827  	// long as it has not set status.
   828  	err := s.unit.AssignToNewMachine()
   829  	c.Assert(err, jc.ErrorIsNil)
   830  	mid, err := s.unit.AssignedMachineId()
   831  	c.Assert(err, jc.ErrorIsNil)
   832  	machine, err := s.State.Machine(mid)
   833  	c.Assert(err, jc.ErrorIsNil)
   834  	err = machine.SetProvisioned("i-malive", "fake_nonce", nil)
   835  	c.Assert(err, jc.ErrorIsNil)
   836  	err = s.unit.Destroy()
   837  	c.Assert(err, jc.ErrorIsNil)
   838  	c.Assert(s.unit.Life(), gc.Equals, state.Dying)
   839  	assertRemoved(c, s.unit)
   840  }
   841  
   842  func assertLife(c *gc.C, entity state.Living, life state.Life) {
   843  	c.Assert(entity.Refresh(), gc.IsNil)
   844  	c.Assert(entity.Life(), gc.Equals, life)
   845  }
   846  
   847  func assertRemoved(c *gc.C, entity state.Living) {
   848  	err := entity.Refresh()
   849  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   850  	err = entity.Destroy()
   851  	c.Assert(err, jc.ErrorIsNil)
   852  	if entity, ok := entity.(state.AgentLiving); ok {
   853  		err = entity.EnsureDead()
   854  		c.Assert(err, jc.ErrorIsNil)
   855  		err = entity.Remove()
   856  		c.Assert(err, jc.ErrorIsNil)
   857  	}
   858  }
   859  
   860  func (s *UnitSuite) TestTag(c *gc.C) {
   861  	c.Assert(s.unit.Tag().String(), gc.Equals, "unit-wordpress-0")
   862  }
   863  
   864  func (s *UnitSuite) TestSetPassword(c *gc.C) {
   865  	preventUnitDestroyRemove(c, s.unit)
   866  	testSetPassword(c, func() (state.Authenticator, error) {
   867  		return s.State.Unit(s.unit.Name())
   868  	})
   869  }
   870  
   871  func (s *UnitSuite) TestUnitSetAgentPresence(c *gc.C) {
   872  	alive, err := s.unit.AgentPresence()
   873  	c.Assert(err, jc.ErrorIsNil)
   874  	c.Assert(alive, jc.IsFalse)
   875  
   876  	pinger, err := s.unit.SetAgentPresence()
   877  	c.Assert(err, jc.ErrorIsNil)
   878  	c.Assert(pinger, gc.NotNil)
   879  	defer func() {
   880  		c.Assert(worker.Stop(pinger), jc.ErrorIsNil)
   881  	}()
   882  	s.State.StartSync()
   883  	alive, err = s.unit.AgentPresence()
   884  	c.Assert(err, jc.ErrorIsNil)
   885  	c.Assert(alive, jc.IsTrue)
   886  }
   887  
   888  func (s *UnitSuite) TestUnitWaitAgentPresence(c *gc.C) {
   889  	alive, err := s.unit.AgentPresence()
   890  	c.Assert(err, jc.ErrorIsNil)
   891  	c.Assert(alive, jc.IsFalse)
   892  
   893  	err = s.unit.WaitAgentPresence(coretesting.ShortWait)
   894  	c.Assert(err, gc.ErrorMatches, `waiting for agent of unit "wordpress/0": still not alive after timeout`)
   895  
   896  	pinger, err := s.unit.SetAgentPresence()
   897  	c.Assert(err, jc.ErrorIsNil)
   898  
   899  	s.State.StartSync()
   900  	err = s.unit.WaitAgentPresence(coretesting.LongWait)
   901  	c.Assert(err, jc.ErrorIsNil)
   902  
   903  	alive, err = s.unit.AgentPresence()
   904  	c.Assert(err, jc.ErrorIsNil)
   905  	c.Assert(alive, jc.IsTrue)
   906  
   907  	err = pinger.KillForTesting()
   908  	c.Assert(err, jc.ErrorIsNil)
   909  
   910  	s.State.StartSync()
   911  
   912  	alive, err = s.unit.AgentPresence()
   913  	c.Assert(err, jc.ErrorIsNil)
   914  	c.Assert(alive, jc.IsFalse)
   915  }
   916  
   917  func (s *UnitSuite) TestResolve(c *gc.C) {
   918  	err := s.unit.Resolve(false)
   919  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" is not in an error state`)
   920  	err = s.unit.Resolve(true)
   921  	c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" is not in an error state`)
   922  
   923  	now := time.Now()
   924  	sInfo := status.StatusInfo{
   925  		Status:  status.Error,
   926  		Message: "gaaah",
   927  		Since:   &now,
   928  	}
   929  	err = s.unit.SetAgentStatus(sInfo)
   930  	c.Assert(err, jc.ErrorIsNil)
   931  	err = s.unit.Resolve(false)
   932  	c.Assert(err, jc.ErrorIsNil)
   933  	err = s.unit.Resolve(true)
   934  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": already resolved`)
   935  	c.Assert(s.unit.Resolved(), gc.Equals, state.ResolvedRetryHooks)
   936  
   937  	err = s.unit.ClearResolved()
   938  	c.Assert(err, jc.ErrorIsNil)
   939  	err = s.unit.Resolve(true)
   940  	c.Assert(err, jc.ErrorIsNil)
   941  	err = s.unit.Resolve(false)
   942  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": already resolved`)
   943  	c.Assert(s.unit.Resolved(), gc.Equals, state.ResolvedNoHooks)
   944  }
   945  
   946  func (s *UnitSuite) TestGetSetClearResolved(c *gc.C) {
   947  	mode := s.unit.Resolved()
   948  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   949  
   950  	err := s.unit.SetResolved(state.ResolvedNoHooks)
   951  	c.Assert(err, jc.ErrorIsNil)
   952  	err = s.unit.SetResolved(state.ResolvedNoHooks)
   953  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": already resolved`)
   954  
   955  	mode = s.unit.Resolved()
   956  	c.Assert(mode, gc.Equals, state.ResolvedNoHooks)
   957  	err = s.unit.Refresh()
   958  	c.Assert(err, jc.ErrorIsNil)
   959  	mode = s.unit.Resolved()
   960  	c.Assert(mode, gc.Equals, state.ResolvedNoHooks)
   961  
   962  	err = s.unit.ClearResolved()
   963  	c.Assert(err, jc.ErrorIsNil)
   964  	mode = s.unit.Resolved()
   965  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   966  	err = s.unit.Refresh()
   967  	c.Assert(err, jc.ErrorIsNil)
   968  	mode = s.unit.Resolved()
   969  	c.Assert(mode, gc.Equals, state.ResolvedNone)
   970  	err = s.unit.ClearResolved()
   971  	c.Assert(err, jc.ErrorIsNil)
   972  
   973  	err = s.unit.SetResolved(state.ResolvedNone)
   974  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": invalid error resolution mode: ""`)
   975  	err = s.unit.SetResolved(state.ResolvedMode("foo"))
   976  	c.Assert(err, gc.ErrorMatches, `cannot set resolved mode for unit "wordpress/0": invalid error resolution mode: "foo"`)
   977  }
   978  
   979  func (s *UnitSuite) TestOpenedPortsOnInvalidSubnet(c *gc.C) {
   980  	s.testOpenedPorts(c, "bad CIDR", `invalid subnet ID "bad CIDR"`)
   981  }
   982  
   983  func (s *UnitSuite) TestOpenedPortsOnUnknownSubnet(c *gc.C) {
   984  	// We're not adding the 127.0.0.0/8 subnet to test the "not found" case.
   985  	s.testOpenedPorts(c, "127.0.0.0/8", `subnet "127.0.0.0/8" not found or not alive`)
   986  }
   987  
   988  func (s *UnitSuite) TestOpenedPortsOnDeadSubnet(c *gc.C) {
   989  	// We're adding the 0.1.2.0/24 subnet first and then setting it to Dead to
   990  	// check the "not alive" case.
   991  	subnet, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "0.1.2.0/24"})
   992  	c.Assert(err, jc.ErrorIsNil)
   993  	err = subnet.EnsureDead()
   994  	c.Assert(err, jc.ErrorIsNil)
   995  
   996  	s.testOpenedPorts(c, "0.1.2.0/24", `subnet "0.1.2.0/24" not found or not alive`)
   997  }
   998  
   999  func (s *UnitSuite) TestOpenedPortsOnAliveIPv4Subnet(c *gc.C) {
  1000  	_, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "192.168.0.0/16"})
  1001  	c.Assert(err, jc.ErrorIsNil)
  1002  
  1003  	s.testOpenedPorts(c, "192.168.0.0/16", "")
  1004  }
  1005  
  1006  func (s *UnitSuite) TestOpenedPortsOnAliveIPv6Subnet(c *gc.C) {
  1007  	_, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "2001:db8::/64"})
  1008  	c.Assert(err, jc.ErrorIsNil)
  1009  
  1010  	s.testOpenedPorts(c, "2001:db8::/64", "")
  1011  }
  1012  
  1013  func (s *UnitSuite) TestOpenedPortsOnEmptySubnet(c *gc.C) {
  1014  	// TODO(dimitern): This should go away and become an error once we always
  1015  	// explicitly pass subnet IDs when handling unit ports.
  1016  	s.testOpenedPorts(c, "", "")
  1017  }
  1018  
  1019  func (s *UnitSuite) testOpenedPorts(c *gc.C, subnetID, expectedErrorCauseMatches string) {
  1020  
  1021  	checkExpectedError := func(err error) bool {
  1022  		if expectedErrorCauseMatches == "" {
  1023  			c.Check(err, jc.ErrorIsNil)
  1024  			return true
  1025  		}
  1026  		c.Check(errors.Cause(err), gc.ErrorMatches, expectedErrorCauseMatches)
  1027  		return false
  1028  	}
  1029  
  1030  	// Verify ports can be opened and closed only when the unit has
  1031  	// assigned machine.
  1032  	err := s.unit.OpenPortOnSubnet(subnetID, "tcp", 10)
  1033  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1034  	err = s.unit.OpenPortsOnSubnet(subnetID, "tcp", 10, 20)
  1035  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1036  	err = s.unit.ClosePortOnSubnet(subnetID, "tcp", 10)
  1037  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1038  	err = s.unit.ClosePortsOnSubnet(subnetID, "tcp", 10, 20)
  1039  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1040  	open, err := s.unit.OpenedPortsOnSubnet(subnetID)
  1041  	c.Check(errors.Cause(err), jc.Satisfies, errors.IsNotAssigned)
  1042  	c.Check(open, gc.HasLen, 0)
  1043  
  1044  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1045  	c.Check(err, jc.ErrorIsNil)
  1046  	err = s.unit.AssignToMachine(machine)
  1047  	c.Check(err, jc.ErrorIsNil)
  1048  
  1049  	// Verify no open ports before activity.
  1050  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1051  	if checkExpectedError(err) {
  1052  		c.Check(open, gc.HasLen, 0)
  1053  	}
  1054  
  1055  	// Now open and close ports and ranges and check.
  1056  
  1057  	err = s.unit.OpenPortOnSubnet(subnetID, "tcp", 80)
  1058  	checkExpectedError(err)
  1059  	err = s.unit.OpenPortsOnSubnet(subnetID, "udp", 100, 200)
  1060  	checkExpectedError(err)
  1061  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1062  	if checkExpectedError(err) {
  1063  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1064  			{80, 80, "tcp"},
  1065  			{100, 200, "udp"},
  1066  		})
  1067  	}
  1068  
  1069  	err = s.unit.OpenPortOnSubnet(subnetID, "udp", 53)
  1070  	checkExpectedError(err)
  1071  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1072  	if checkExpectedError(err) {
  1073  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1074  			{80, 80, "tcp"},
  1075  			{53, 53, "udp"},
  1076  			{100, 200, "udp"},
  1077  		})
  1078  	}
  1079  
  1080  	err = s.unit.OpenPortsOnSubnet(subnetID, "tcp", 53, 55)
  1081  	checkExpectedError(err)
  1082  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1083  	if checkExpectedError(err) {
  1084  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1085  			{53, 55, "tcp"},
  1086  			{80, 80, "tcp"},
  1087  			{53, 53, "udp"},
  1088  			{100, 200, "udp"},
  1089  		})
  1090  	}
  1091  
  1092  	err = s.unit.OpenPortOnSubnet(subnetID, "tcp", 443)
  1093  	checkExpectedError(err)
  1094  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1095  	if checkExpectedError(err) {
  1096  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1097  			{53, 55, "tcp"},
  1098  			{80, 80, "tcp"},
  1099  			{443, 443, "tcp"},
  1100  			{53, 53, "udp"},
  1101  			{100, 200, "udp"},
  1102  		})
  1103  	}
  1104  
  1105  	err = s.unit.ClosePortOnSubnet(subnetID, "tcp", 80)
  1106  	checkExpectedError(err)
  1107  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1108  	if checkExpectedError(err) {
  1109  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1110  			{53, 55, "tcp"},
  1111  			{443, 443, "tcp"},
  1112  			{53, 53, "udp"},
  1113  			{100, 200, "udp"},
  1114  		})
  1115  	}
  1116  
  1117  	err = s.unit.ClosePortsOnSubnet(subnetID, "udp", 100, 200)
  1118  	checkExpectedError(err)
  1119  	open, err = s.unit.OpenedPortsOnSubnet(subnetID)
  1120  	if checkExpectedError(err) {
  1121  		c.Check(open, gc.DeepEquals, []network.PortRange{
  1122  			{53, 55, "tcp"},
  1123  			{443, 443, "tcp"},
  1124  			{53, 53, "udp"},
  1125  		})
  1126  	}
  1127  }
  1128  
  1129  func (s *UnitSuite) TestOpenClosePortWhenDying(c *gc.C) {
  1130  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1131  	c.Assert(err, jc.ErrorIsNil)
  1132  	err = s.unit.AssignToMachine(machine)
  1133  	c.Assert(err, jc.ErrorIsNil)
  1134  
  1135  	preventUnitDestroyRemove(c, s.unit)
  1136  	testWhenDying(c, s.unit, noErr, contentionErr, func() error {
  1137  		err := s.unit.OpenPort("tcp", 20)
  1138  		if err != nil {
  1139  			return err
  1140  		}
  1141  		err = s.unit.OpenPorts("tcp", 10, 15)
  1142  		if err != nil {
  1143  			return err
  1144  		}
  1145  		err = s.unit.Refresh()
  1146  		if err != nil {
  1147  			return err
  1148  		}
  1149  		err = s.unit.ClosePort("tcp", 20)
  1150  		if err != nil {
  1151  			return err
  1152  		}
  1153  		return s.unit.ClosePorts("tcp", 10, 15)
  1154  	})
  1155  }
  1156  
  1157  func (s *UnitSuite) TestRemoveLastUnitOnMachineRemovesAllPorts(c *gc.C) {
  1158  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1159  	c.Assert(err, jc.ErrorIsNil)
  1160  	err = s.unit.AssignToMachine(machine)
  1161  	c.Assert(err, jc.ErrorIsNil)
  1162  
  1163  	ports, err := machine.AllPorts()
  1164  	c.Assert(err, jc.ErrorIsNil)
  1165  	c.Assert(ports, gc.HasLen, 0)
  1166  
  1167  	err = s.unit.OpenPorts("tcp", 100, 200)
  1168  	c.Assert(err, jc.ErrorIsNil)
  1169  
  1170  	ports, err = machine.AllPorts()
  1171  	c.Assert(err, jc.ErrorIsNil)
  1172  	c.Assert(ports, gc.HasLen, 1)
  1173  	c.Assert(ports[0].PortsForUnit(s.unit.Name()), jc.DeepEquals, []state.PortRange{
  1174  		{s.unit.Name(), 100, 200, "tcp"},
  1175  	})
  1176  
  1177  	// Now remove the unit and check again.
  1178  	err = s.unit.EnsureDead()
  1179  	c.Assert(err, jc.ErrorIsNil)
  1180  	err = s.unit.Remove()
  1181  	c.Assert(err, jc.ErrorIsNil)
  1182  	err = s.unit.Refresh()
  1183  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1184  
  1185  	// Because that was the only range open, the ports doc will be
  1186  	// removed as well.
  1187  	ports, err = machine.AllPorts()
  1188  	c.Assert(err, jc.ErrorIsNil)
  1189  	c.Assert(ports, gc.HasLen, 0)
  1190  }
  1191  
  1192  func (s *UnitSuite) TestRemoveUnitRemovesItsPortsOnly(c *gc.C) {
  1193  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
  1194  	c.Assert(err, jc.ErrorIsNil)
  1195  	err = s.unit.AssignToMachine(machine)
  1196  	c.Assert(err, jc.ErrorIsNil)
  1197  
  1198  	otherUnit, err := s.service.AddUnit()
  1199  	c.Assert(err, jc.ErrorIsNil)
  1200  	err = otherUnit.AssignToMachine(machine)
  1201  	c.Assert(err, jc.ErrorIsNil)
  1202  
  1203  	ports, err := machine.AllPorts()
  1204  	c.Assert(err, jc.ErrorIsNil)
  1205  	c.Assert(ports, gc.HasLen, 0)
  1206  
  1207  	err = s.unit.OpenPorts("tcp", 100, 200)
  1208  	c.Assert(err, jc.ErrorIsNil)
  1209  	err = otherUnit.OpenPorts("udp", 300, 400)
  1210  	c.Assert(err, jc.ErrorIsNil)
  1211  
  1212  	ports, err = machine.AllPorts()
  1213  	c.Assert(err, jc.ErrorIsNil)
  1214  	c.Assert(ports, gc.HasLen, 1)
  1215  	c.Assert(ports[0].PortsForUnit(s.unit.Name()), jc.DeepEquals, []state.PortRange{
  1216  		{s.unit.Name(), 100, 200, "tcp"},
  1217  	})
  1218  	c.Assert(ports[0].PortsForUnit(otherUnit.Name()), jc.DeepEquals, []state.PortRange{
  1219  		{otherUnit.Name(), 300, 400, "udp"},
  1220  	})
  1221  
  1222  	// Now remove the first unit and check again.
  1223  	err = s.unit.EnsureDead()
  1224  	c.Assert(err, jc.ErrorIsNil)
  1225  	err = s.unit.Remove()
  1226  	c.Assert(err, jc.ErrorIsNil)
  1227  	err = s.unit.Refresh()
  1228  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1229  
  1230  	// Verify only otherUnit still has open ports.
  1231  	ports, err = machine.AllPorts()
  1232  	c.Assert(err, jc.ErrorIsNil)
  1233  	c.Assert(ports, gc.HasLen, 1)
  1234  	c.Assert(ports[0].PortsForUnit(s.unit.Name()), gc.HasLen, 0)
  1235  	c.Assert(ports[0].PortsForUnit(otherUnit.Name()), jc.DeepEquals, []state.PortRange{
  1236  		{otherUnit.Name(), 300, 400, "udp"},
  1237  	})
  1238  }
  1239  
  1240  func (s *UnitSuite) TestSetClearResolvedWhenNotAlive(c *gc.C) {
  1241  	preventUnitDestroyRemove(c, s.unit)
  1242  	err := s.unit.Destroy()
  1243  	c.Assert(err, jc.ErrorIsNil)
  1244  	err = s.unit.SetResolved(state.ResolvedNoHooks)
  1245  	c.Assert(err, jc.ErrorIsNil)
  1246  	err = s.unit.Refresh()
  1247  	c.Assert(err, jc.ErrorIsNil)
  1248  	c.Assert(s.unit.Resolved(), gc.Equals, state.ResolvedNoHooks)
  1249  	err = s.unit.ClearResolved()
  1250  	c.Assert(err, jc.ErrorIsNil)
  1251  
  1252  	err = s.unit.EnsureDead()
  1253  	c.Assert(err, jc.ErrorIsNil)
  1254  	err = s.unit.SetResolved(state.ResolvedRetryHooks)
  1255  	c.Assert(err, gc.ErrorMatches, deadErr)
  1256  	err = s.unit.ClearResolved()
  1257  	c.Assert(err, jc.ErrorIsNil)
  1258  }
  1259  
  1260  func (s *UnitSuite) TestSubordinateChangeInPrincipal(c *gc.C) {
  1261  	subCharm := s.AddTestingCharm(c, "logging")
  1262  	for i := 0; i < 2; i++ {
  1263  		// Note: subordinate units can only be created as a side effect of a
  1264  		// principal entering scope; and a given principal can only have a
  1265  		// single subordinate unit of each service.
  1266  		name := "logging" + strconv.Itoa(i)
  1267  		s.AddTestingService(c, name, subCharm)
  1268  		eps, err := s.State.InferEndpoints(name, "wordpress")
  1269  		c.Assert(err, jc.ErrorIsNil)
  1270  		rel, err := s.State.AddRelation(eps...)
  1271  		c.Assert(err, jc.ErrorIsNil)
  1272  		ru, err := rel.Unit(s.unit)
  1273  		c.Assert(err, jc.ErrorIsNil)
  1274  		err = ru.EnterScope(nil)
  1275  		c.Assert(err, jc.ErrorIsNil)
  1276  	}
  1277  
  1278  	err := s.unit.Refresh()
  1279  	c.Assert(err, jc.ErrorIsNil)
  1280  	subordinates := s.unit.SubordinateNames()
  1281  	c.Assert(subordinates, gc.DeepEquals, []string{"logging0/0", "logging1/0"})
  1282  
  1283  	su1, err := s.State.Unit("logging1/0")
  1284  	c.Assert(err, jc.ErrorIsNil)
  1285  	err = su1.EnsureDead()
  1286  	c.Assert(err, jc.ErrorIsNil)
  1287  	err = su1.Remove()
  1288  	c.Assert(err, jc.ErrorIsNil)
  1289  	err = s.unit.Refresh()
  1290  	c.Assert(err, jc.ErrorIsNil)
  1291  	subordinates = s.unit.SubordinateNames()
  1292  	c.Assert(subordinates, gc.DeepEquals, []string{"logging0/0"})
  1293  }
  1294  
  1295  func (s *UnitSuite) TestDeathWithSubordinates(c *gc.C) {
  1296  	// Check that units can become dead when they've never had subordinates.
  1297  	u, err := s.service.AddUnit()
  1298  	c.Assert(err, jc.ErrorIsNil)
  1299  	err = u.EnsureDead()
  1300  	c.Assert(err, jc.ErrorIsNil)
  1301  
  1302  	// Create a new unit and add a subordinate.
  1303  	u, err = s.service.AddUnit()
  1304  	c.Assert(err, jc.ErrorIsNil)
  1305  	s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging"))
  1306  	c.Assert(err, jc.ErrorIsNil)
  1307  	eps, err := s.State.InferEndpoints("logging", "wordpress")
  1308  	c.Assert(err, jc.ErrorIsNil)
  1309  	rel, err := s.State.AddRelation(eps...)
  1310  	c.Assert(err, jc.ErrorIsNil)
  1311  	ru, err := rel.Unit(u)
  1312  	c.Assert(err, jc.ErrorIsNil)
  1313  	err = ru.EnterScope(nil)
  1314  	c.Assert(err, jc.ErrorIsNil)
  1315  
  1316  	// Check the unit cannot become Dead, but can become Dying...
  1317  	err = u.EnsureDead()
  1318  	c.Assert(err, gc.Equals, state.ErrUnitHasSubordinates)
  1319  	err = u.Destroy()
  1320  	c.Assert(err, jc.ErrorIsNil)
  1321  
  1322  	// ...and that it still can't become Dead now it's Dying.
  1323  	err = u.EnsureDead()
  1324  	c.Assert(err, gc.Equals, state.ErrUnitHasSubordinates)
  1325  
  1326  	// Make the subordinate Dead and check the principal still cannot be removed.
  1327  	sub, err := s.State.Unit("logging/0")
  1328  	c.Assert(err, jc.ErrorIsNil)
  1329  	err = sub.EnsureDead()
  1330  	c.Assert(err, jc.ErrorIsNil)
  1331  	err = u.EnsureDead()
  1332  	c.Assert(err, gc.Equals, state.ErrUnitHasSubordinates)
  1333  
  1334  	// remove the subordinate and check the principal can finally become Dead.
  1335  	err = sub.Remove()
  1336  	c.Assert(err, jc.ErrorIsNil)
  1337  	err = u.EnsureDead()
  1338  	c.Assert(err, jc.ErrorIsNil)
  1339  }
  1340  
  1341  func (s *UnitSuite) TestPrincipalName(c *gc.C) {
  1342  	subCharm := s.AddTestingCharm(c, "logging")
  1343  	s.AddTestingService(c, "logging", subCharm)
  1344  	eps, err := s.State.InferEndpoints("logging", "wordpress")
  1345  	c.Assert(err, jc.ErrorIsNil)
  1346  	rel, err := s.State.AddRelation(eps...)
  1347  	c.Assert(err, jc.ErrorIsNil)
  1348  	ru, err := rel.Unit(s.unit)
  1349  	c.Assert(err, jc.ErrorIsNil)
  1350  	err = ru.EnterScope(nil)
  1351  	c.Assert(err, jc.ErrorIsNil)
  1352  
  1353  	err = s.unit.Refresh()
  1354  	c.Assert(err, jc.ErrorIsNil)
  1355  	subordinates := s.unit.SubordinateNames()
  1356  	c.Assert(subordinates, gc.DeepEquals, []string{"logging/0"})
  1357  
  1358  	su, err := s.State.Unit("logging/0")
  1359  	c.Assert(err, jc.ErrorIsNil)
  1360  	principal, valid := su.PrincipalName()
  1361  	c.Assert(valid, jc.IsTrue)
  1362  	c.Assert(principal, gc.Equals, s.unit.Name())
  1363  
  1364  	// Calling PrincipalName on a principal unit yields "", false.
  1365  	principal, valid = s.unit.PrincipalName()
  1366  	c.Assert(valid, jc.IsFalse)
  1367  	c.Assert(principal, gc.Equals, "")
  1368  }
  1369  
  1370  func (s *UnitSuite) TestRelations(c *gc.C) {
  1371  	wordpress0 := s.unit
  1372  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1373  	mysql0, err := mysql.AddUnit()
  1374  	c.Assert(err, jc.ErrorIsNil)
  1375  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1376  	c.Assert(err, jc.ErrorIsNil)
  1377  	rel, err := s.State.AddRelation(eps...)
  1378  	c.Assert(err, jc.ErrorIsNil)
  1379  
  1380  	assertEquals := func(actual, expect []*state.Relation) {
  1381  		c.Assert(actual, gc.HasLen, len(expect))
  1382  		for i, a := range actual {
  1383  			c.Assert(a.Id(), gc.Equals, expect[i].Id())
  1384  		}
  1385  	}
  1386  	assertRelationsJoined := func(unit *state.Unit, expect ...*state.Relation) {
  1387  		actual, err := unit.RelationsJoined()
  1388  		c.Assert(err, jc.ErrorIsNil)
  1389  		assertEquals(actual, expect)
  1390  	}
  1391  	assertRelationsInScope := func(unit *state.Unit, expect ...*state.Relation) {
  1392  		actual, err := unit.RelationsInScope()
  1393  		c.Assert(err, jc.ErrorIsNil)
  1394  		assertEquals(actual, expect)
  1395  	}
  1396  	assertRelations := func(unit *state.Unit, expect ...*state.Relation) {
  1397  		assertRelationsInScope(unit, expect...)
  1398  		assertRelationsJoined(unit, expect...)
  1399  	}
  1400  	assertRelations(wordpress0)
  1401  	assertRelations(mysql0)
  1402  
  1403  	mysql0ru, err := rel.Unit(mysql0)
  1404  	c.Assert(err, jc.ErrorIsNil)
  1405  	err = mysql0ru.EnterScope(nil)
  1406  	c.Assert(err, jc.ErrorIsNil)
  1407  	assertRelations(wordpress0)
  1408  	assertRelations(mysql0, rel)
  1409  
  1410  	wordpress0ru, err := rel.Unit(wordpress0)
  1411  	c.Assert(err, jc.ErrorIsNil)
  1412  	err = wordpress0ru.EnterScope(nil)
  1413  	c.Assert(err, jc.ErrorIsNil)
  1414  	assertRelations(wordpress0, rel)
  1415  	assertRelations(mysql0, rel)
  1416  
  1417  	err = mysql0ru.PrepareLeaveScope()
  1418  	c.Assert(err, jc.ErrorIsNil)
  1419  	assertRelations(wordpress0, rel)
  1420  	assertRelationsInScope(mysql0, rel)
  1421  	assertRelationsJoined(mysql0)
  1422  }
  1423  
  1424  func (s *UnitSuite) TestRemove(c *gc.C) {
  1425  	err := s.unit.Remove()
  1426  	c.Assert(err, gc.ErrorMatches, `cannot remove unit "wordpress/0": unit is not dead`)
  1427  	err = s.unit.EnsureDead()
  1428  	c.Assert(err, jc.ErrorIsNil)
  1429  	err = s.unit.Remove()
  1430  	c.Assert(err, jc.ErrorIsNil)
  1431  	err = s.unit.Refresh()
  1432  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1433  	units, err := s.service.AllUnits()
  1434  	c.Assert(err, jc.ErrorIsNil)
  1435  	c.Assert(units, gc.HasLen, 0)
  1436  	err = s.unit.Remove()
  1437  	c.Assert(err, jc.ErrorIsNil)
  1438  }
  1439  
  1440  func (s *UnitSuite) TestRemovePathological(c *gc.C) {
  1441  	// Add a relation between wordpress and mysql...
  1442  	wordpress := s.service
  1443  	wordpress0 := s.unit
  1444  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1445  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1446  	c.Assert(err, jc.ErrorIsNil)
  1447  	rel, err := s.State.AddRelation(eps...)
  1448  	c.Assert(err, jc.ErrorIsNil)
  1449  
  1450  	// The relation holds a reference to wordpress, but that can't keep
  1451  	// wordpress from being removed -- because the relation will be removed
  1452  	// if we destroy wordpress.
  1453  	// However, if a unit of the *other* service joins the relation, that
  1454  	// will add an additional reference and prevent the relation -- and
  1455  	// thus wordpress itself -- from being removed when its last unit is.
  1456  	mysql0, err := mysql.AddUnit()
  1457  	c.Assert(err, jc.ErrorIsNil)
  1458  	mysql0ru, err := rel.Unit(mysql0)
  1459  	c.Assert(err, jc.ErrorIsNil)
  1460  	err = mysql0ru.EnterScope(nil)
  1461  	c.Assert(err, jc.ErrorIsNil)
  1462  
  1463  	// Destroy wordpress, and remove its last unit.
  1464  	err = wordpress.Destroy()
  1465  	c.Assert(err, jc.ErrorIsNil)
  1466  	err = wordpress0.EnsureDead()
  1467  	c.Assert(err, jc.ErrorIsNil)
  1468  	err = wordpress0.Remove()
  1469  	c.Assert(err, jc.ErrorIsNil)
  1470  
  1471  	// Check this didn't kill the service or relation yet...
  1472  	err = wordpress.Refresh()
  1473  	c.Assert(err, jc.ErrorIsNil)
  1474  	err = rel.Refresh()
  1475  	c.Assert(err, jc.ErrorIsNil)
  1476  
  1477  	// ...but when the unit on the other side departs the relation, the
  1478  	// relation and the other service are cleaned up.
  1479  	err = mysql0ru.LeaveScope()
  1480  	c.Assert(err, jc.ErrorIsNil)
  1481  	err = wordpress.Refresh()
  1482  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1483  	err = rel.Refresh()
  1484  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1485  }
  1486  
  1487  func (s *UnitSuite) TestRemovePathologicalWithBuggyUniter(c *gc.C) {
  1488  	// Add a relation between wordpress and mysql...
  1489  	wordpress := s.service
  1490  	wordpress0 := s.unit
  1491  	mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql"))
  1492  	eps, err := s.State.InferEndpoints("wordpress", "mysql")
  1493  	c.Assert(err, jc.ErrorIsNil)
  1494  	rel, err := s.State.AddRelation(eps...)
  1495  	c.Assert(err, jc.ErrorIsNil)
  1496  
  1497  	// The relation holds a reference to wordpress, but that can't keep
  1498  	// wordpress from being removed -- because the relation will be removed
  1499  	// if we destroy wordpress.
  1500  	// However, if a unit of the *other* service joins the relation, that
  1501  	// will add an additional reference and prevent the relation -- and
  1502  	// thus wordpress itself -- from being removed when its last unit is.
  1503  	mysql0, err := mysql.AddUnit()
  1504  	c.Assert(err, jc.ErrorIsNil)
  1505  	mysql0ru, err := rel.Unit(mysql0)
  1506  	c.Assert(err, jc.ErrorIsNil)
  1507  	err = mysql0ru.EnterScope(nil)
  1508  	c.Assert(err, jc.ErrorIsNil)
  1509  
  1510  	// Destroy wordpress, and remove its last unit.
  1511  	err = wordpress.Destroy()
  1512  	c.Assert(err, jc.ErrorIsNil)
  1513  	err = wordpress0.EnsureDead()
  1514  	c.Assert(err, jc.ErrorIsNil)
  1515  	err = wordpress0.Remove()
  1516  	c.Assert(err, jc.ErrorIsNil)
  1517  
  1518  	// Check this didn't kill the service or relation yet...
  1519  	err = wordpress.Refresh()
  1520  	c.Assert(err, jc.ErrorIsNil)
  1521  	err = rel.Refresh()
  1522  	c.Assert(err, jc.ErrorIsNil)
  1523  
  1524  	// ...and that when the malfunctioning unit agent on the other side
  1525  	// sets itself to dead *without* departing the relation, the unit's
  1526  	// removal causes the relation and the other service to be cleaned up.
  1527  	err = mysql0.EnsureDead()
  1528  	c.Assert(err, jc.ErrorIsNil)
  1529  	err = mysql0.Remove()
  1530  	c.Assert(err, jc.ErrorIsNil)
  1531  	err = wordpress.Refresh()
  1532  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1533  	err = rel.Refresh()
  1534  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
  1535  }
  1536  
  1537  func (s *UnitSuite) TestWatchSubordinates(c *gc.C) {
  1538  	// TODO(mjs) - ModelUUID - test with multiple models with
  1539  	// identically named units and ensure there's no leakage.
  1540  	w := s.unit.WatchSubordinateUnits()
  1541  	defer testing.AssertStop(c, w)
  1542  	wc := testing.NewStringsWatcherC(c, s.State, w)
  1543  	wc.AssertChange()
  1544  	wc.AssertNoChange()
  1545  
  1546  	// Add a couple of subordinates, check change.
  1547  	subCharm := s.AddTestingCharm(c, "logging")
  1548  	var subUnits []*state.Unit
  1549  	for i := 0; i < 2; i++ {
  1550  		// Note: subordinate units can only be created as a side effect of a
  1551  		// principal entering scope; and a given principal can only have a
  1552  		// single subordinate unit of each service.
  1553  		name := "logging" + strconv.Itoa(i)
  1554  		subSvc := s.AddTestingService(c, name, subCharm)
  1555  		eps, err := s.State.InferEndpoints(name, "wordpress")
  1556  		c.Assert(err, jc.ErrorIsNil)
  1557  		rel, err := s.State.AddRelation(eps...)
  1558  		c.Assert(err, jc.ErrorIsNil)
  1559  		ru, err := rel.Unit(s.unit)
  1560  		c.Assert(err, jc.ErrorIsNil)
  1561  		err = ru.EnterScope(nil)
  1562  		c.Assert(err, jc.ErrorIsNil)
  1563  		units, err := subSvc.AllUnits()
  1564  		c.Assert(err, jc.ErrorIsNil)
  1565  		c.Assert(units, gc.HasLen, 1)
  1566  		subUnits = append(subUnits, units[0])
  1567  	}
  1568  	wc.AssertChange(subUnits[0].Name(), subUnits[1].Name())
  1569  	wc.AssertNoChange()
  1570  
  1571  	// Set one to Dying, check change.
  1572  	err := subUnits[0].Destroy()
  1573  	c.Assert(err, jc.ErrorIsNil)
  1574  	wc.AssertChange(subUnits[0].Name())
  1575  	wc.AssertNoChange()
  1576  
  1577  	// Set both to Dead, and remove one; check change.
  1578  	err = subUnits[0].EnsureDead()
  1579  	c.Assert(err, jc.ErrorIsNil)
  1580  	err = subUnits[1].EnsureDead()
  1581  	c.Assert(err, jc.ErrorIsNil)
  1582  	err = subUnits[1].Remove()
  1583  	c.Assert(err, jc.ErrorIsNil)
  1584  	wc.AssertChange(subUnits[0].Name(), subUnits[1].Name())
  1585  	wc.AssertNoChange()
  1586  
  1587  	// Stop watcher, check closed.
  1588  	testing.AssertStop(c, w)
  1589  	wc.AssertClosed()
  1590  
  1591  	// Start a new watch, check Dead unit is reported.
  1592  	w = s.unit.WatchSubordinateUnits()
  1593  	defer testing.AssertStop(c, w)
  1594  	wc = testing.NewStringsWatcherC(c, s.State, w)
  1595  	wc.AssertChange(subUnits[0].Name())
  1596  	wc.AssertNoChange()
  1597  
  1598  	// Remove the leftover, check no change.
  1599  	err = subUnits[0].Remove()
  1600  	c.Assert(err, jc.ErrorIsNil)
  1601  	wc.AssertNoChange()
  1602  }
  1603  
  1604  func (s *UnitSuite) TestWatchUnit(c *gc.C) {
  1605  	preventUnitDestroyRemove(c, s.unit)
  1606  	w := s.unit.Watch()
  1607  	defer testing.AssertStop(c, w)
  1608  
  1609  	// Initial event.
  1610  	wc := testing.NewNotifyWatcherC(c, s.State, w)
  1611  	wc.AssertOneChange()
  1612  
  1613  	// Make one change (to a separate instance), check one event.
  1614  	unit, err := s.State.Unit(s.unit.Name())
  1615  	c.Assert(err, jc.ErrorIsNil)
  1616  	s.setAssignedMachineAddresses(c, unit)
  1617  	wc.AssertOneChange()
  1618  
  1619  	// Make two changes, check one event.
  1620  	err = unit.SetPassword("arble-farble-dying-yarble")
  1621  	c.Assert(err, jc.ErrorIsNil)
  1622  	err = unit.Destroy()
  1623  	c.Assert(err, jc.ErrorIsNil)
  1624  	wc.AssertOneChange()
  1625  
  1626  	// Stop, check closed.
  1627  	testing.AssertStop(c, w)
  1628  	wc.AssertClosed()
  1629  
  1630  	// Remove unit, start new watch, check single event.
  1631  	err = unit.EnsureDead()
  1632  	c.Assert(err, jc.ErrorIsNil)
  1633  	err = unit.Remove()
  1634  	c.Assert(err, jc.ErrorIsNil)
  1635  	w = s.unit.Watch()
  1636  	defer testing.AssertStop(c, w)
  1637  	testing.NewNotifyWatcherC(c, s.State, w).AssertOneChange()
  1638  }
  1639  
  1640  func (s *UnitSuite) TestUnitAgentTools(c *gc.C) {
  1641  	preventUnitDestroyRemove(c, s.unit)
  1642  	testAgentTools(c, s.unit, `unit "wordpress/0"`)
  1643  }
  1644  
  1645  func (s *UnitSuite) TestValidActionsAndSpecs(c *gc.C) {
  1646  	basicActions := `
  1647  snapshot:
  1648    params:
  1649      outfile:
  1650        type: string
  1651        default: "abcd"
  1652  `[1:]
  1653  
  1654  	wordpress := s.AddTestingService(c, "wordpress-actions", s.AddActionsCharm(c, "wordpress", basicActions, 1))
  1655  	unit1, err := wordpress.AddUnit()
  1656  	c.Assert(err, jc.ErrorIsNil)
  1657  	specs, err := unit1.ActionSpecs()
  1658  	c.Assert(err, jc.ErrorIsNil)
  1659  	c.Check(specs, jc.DeepEquals, state.ActionSpecsByName{
  1660  		"snapshot": charm.ActionSpec{
  1661  			Description: "No description",
  1662  			Params: map[string]interface{}{
  1663  				"type":        "object",
  1664  				"title":       "snapshot",
  1665  				"description": "No description",
  1666  				"properties": map[string]interface{}{
  1667  					"outfile": map[string]interface{}{
  1668  						"type":    "string",
  1669  						"default": "abcd",
  1670  					},
  1671  				},
  1672  			},
  1673  		},
  1674  	})
  1675  
  1676  	var tests = []struct {
  1677  		actionName      string
  1678  		errString       string
  1679  		givenPayload    map[string]interface{}
  1680  		expectedPayload map[string]interface{}
  1681  	}{
  1682  		{
  1683  			actionName:      "snapshot",
  1684  			expectedPayload: map[string]interface{}{"outfile": "abcd"},
  1685  		},
  1686  		{
  1687  			actionName: "juju-run",
  1688  			errString:  `validation failed: (root) : "command" property is missing and required, given {}; (root) : "timeout" property is missing and required, given {}`,
  1689  		},
  1690  		{
  1691  			actionName:   "juju-run",
  1692  			givenPayload: map[string]interface{}{"command": "allyourbasearebelongtous"},
  1693  			errString:    `validation failed: (root) : "timeout" property is missing and required, given {"command":"allyourbasearebelongtous"}`,
  1694  		},
  1695  		{
  1696  			actionName:   "juju-run",
  1697  			givenPayload: map[string]interface{}{"timeout": 5 * time.Second},
  1698  			errString:    `validation failed: (root) : "command" property is missing and required, given {"timeout":5e+09}`,
  1699  		},
  1700  		{
  1701  			actionName:      "juju-run",
  1702  			givenPayload:    map[string]interface{}{"command": "allyourbasearebelongtous", "timeout": 5.0},
  1703  			expectedPayload: map[string]interface{}{"command": "allyourbasearebelongtous", "timeout": 5.0},
  1704  		},
  1705  		{
  1706  			actionName: "baiku",
  1707  			errString:  `action "baiku" not defined on unit "wordpress-actions/0"`,
  1708  		},
  1709  	}
  1710  
  1711  	for i, t := range tests {
  1712  		c.Logf("running test %d", i)
  1713  		action, err := unit1.AddAction(t.actionName, t.givenPayload)
  1714  		if t.errString != "" {
  1715  			c.Assert(err.Error(), gc.Equals, t.errString)
  1716  			continue
  1717  		} else {
  1718  			c.Assert(err, jc.ErrorIsNil)
  1719  			c.Assert(action.Parameters(), jc.DeepEquals, t.expectedPayload)
  1720  		}
  1721  	}
  1722  }
  1723  
  1724  func (s *UnitSuite) TestUnitActionsFindsRightActions(c *gc.C) {
  1725  	// An actions.yaml which permits actions by the following names
  1726  	basicActions := `
  1727  action-a-a:
  1728  action-a-b:
  1729  action-a-c:
  1730  action-b-a:
  1731  action-b-b:
  1732  `[1:]
  1733  
  1734  	// Add simple service and two units
  1735  	dummy := s.AddTestingService(c, "dummy", s.AddActionsCharm(c, "dummy", basicActions, 1))
  1736  
  1737  	unit1, err := dummy.AddUnit()
  1738  	c.Assert(err, jc.ErrorIsNil)
  1739  
  1740  	unit2, err := dummy.AddUnit()
  1741  	c.Assert(err, jc.ErrorIsNil)
  1742  
  1743  	// Add 3 actions to first unit, and 2 to the second unit
  1744  	_, err = unit1.AddAction("action-a-a", nil)
  1745  	c.Assert(err, jc.ErrorIsNil)
  1746  	_, err = unit1.AddAction("action-a-b", nil)
  1747  	c.Assert(err, jc.ErrorIsNil)
  1748  	_, err = unit1.AddAction("action-a-c", nil)
  1749  	c.Assert(err, jc.ErrorIsNil)
  1750  
  1751  	_, err = unit2.AddAction("action-b-a", nil)
  1752  	c.Assert(err, jc.ErrorIsNil)
  1753  	_, err = unit2.AddAction("action-b-b", nil)
  1754  	c.Assert(err, jc.ErrorIsNil)
  1755  
  1756  	// Verify that calling Actions on unit1 returns only
  1757  	// the three actions added to unit1
  1758  	actions1, err := unit1.Actions()
  1759  	c.Assert(err, jc.ErrorIsNil)
  1760  	c.Assert(len(actions1), gc.Equals, 3)
  1761  	for _, action := range actions1 {
  1762  		c.Assert(action.Name(), gc.Matches, "^action-a-.")
  1763  	}
  1764  
  1765  	// Verify that calling Actions on unit2 returns only
  1766  	// the two actions added to unit2
  1767  	actions2, err := unit2.Actions()
  1768  	c.Assert(err, jc.ErrorIsNil)
  1769  	c.Assert(len(actions2), gc.Equals, 2)
  1770  	for _, action := range actions2 {
  1771  		c.Assert(action.Name(), gc.Matches, "^action-b-.")
  1772  	}
  1773  }
  1774  
  1775  func (s *UnitSuite) TestWorkloadVersion(c *gc.C) {
  1776  	ch := state.AddTestingCharm(c, s.State, "dummy")
  1777  	app := state.AddTestingService(c, s.State, "alexandrite", ch)
  1778  	unit, err := app.AddUnit()
  1779  	c.Assert(err, jc.ErrorIsNil)
  1780  
  1781  	version, err := unit.WorkloadVersion()
  1782  	c.Assert(err, jc.ErrorIsNil)
  1783  	c.Check(version, gc.Equals, "")
  1784  
  1785  	unit.SetWorkloadVersion("3.combined")
  1786  	version, err = unit.WorkloadVersion()
  1787  	c.Assert(err, jc.ErrorIsNil)
  1788  	c.Check(version, gc.Equals, "3.combined")
  1789  
  1790  	regotUnit, err := s.State.Unit("alexandrite/0")
  1791  	c.Assert(err, jc.ErrorIsNil)
  1792  	version, err = regotUnit.WorkloadVersion()
  1793  	c.Assert(err, jc.ErrorIsNil)
  1794  	c.Check(version, gc.Equals, "3.combined")
  1795  }