github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/common/setstatus_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/state"
    17  	"github.com/juju/juju/status"
    18  	"github.com/juju/juju/testing/factory"
    19  )
    20  
    21  type statusSetterSuite struct {
    22  	statusBaseSuite
    23  	setter *common.StatusSetter
    24  }
    25  
    26  var _ = gc.Suite(&statusSetterSuite{})
    27  
    28  func (s *statusSetterSuite) SetUpTest(c *gc.C) {
    29  	s.statusBaseSuite.SetUpTest(c)
    30  
    31  	s.setter = common.NewStatusSetter(s.State, func() (common.AuthFunc, error) {
    32  		return s.authFunc, nil
    33  	})
    34  }
    35  
    36  func (s *statusSetterSuite) TestUnauthorized(c *gc.C) {
    37  	tag := names.NewMachineTag("42")
    38  	s.badTag = tag
    39  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
    40  		Tag:    tag.String(),
    41  		Status: status.Executing.String(),
    42  	}}})
    43  	c.Assert(err, jc.ErrorIsNil)
    44  	c.Assert(result.Results, gc.HasLen, 1)
    45  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
    46  }
    47  
    48  func (s *statusSetterSuite) TestNotATag(c *gc.C) {
    49  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
    50  		Tag:    "not a tag",
    51  		Status: status.Executing.String(),
    52  	}}})
    53  	c.Assert(err, jc.ErrorIsNil)
    54  	c.Assert(result.Results, gc.HasLen, 1)
    55  	c.Assert(result.Results[0].Error, gc.ErrorMatches, `"not a tag" is not a valid tag`)
    56  }
    57  
    58  func (s *statusSetterSuite) TestNotFound(c *gc.C) {
    59  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
    60  		Tag:    names.NewMachineTag("42").String(),
    61  		Status: status.Down.String(),
    62  	}}})
    63  	c.Assert(err, jc.ErrorIsNil)
    64  	c.Assert(result.Results, gc.HasLen, 1)
    65  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeNotFound)
    66  }
    67  
    68  func (s *statusSetterSuite) TestSetMachineStatus(c *gc.C) {
    69  	machine := s.Factory.MakeMachine(c, nil)
    70  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
    71  		Tag:    machine.Tag().String(),
    72  		Status: status.Started.String(),
    73  	}}})
    74  	c.Assert(err, jc.ErrorIsNil)
    75  	c.Assert(result.Results, gc.HasLen, 1)
    76  	c.Assert(result.Results[0].Error, gc.IsNil)
    77  
    78  	err = machine.Refresh()
    79  	c.Assert(err, jc.ErrorIsNil)
    80  	machineStatus, err := machine.Status()
    81  	c.Assert(err, jc.ErrorIsNil)
    82  	c.Assert(machineStatus.Status, gc.Equals, status.Started)
    83  }
    84  
    85  func (s *statusSetterSuite) TestSetUnitStatus(c *gc.C) {
    86  	// The status has to be a valid workload status, because get status
    87  	// on the unit returns the workload status not the agent status as it
    88  	// does on a machine.
    89  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Status: &status.StatusInfo{
    90  		Status: status.Maintenance,
    91  	}})
    92  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
    93  		Tag:    unit.Tag().String(),
    94  		Status: status.Active.String(),
    95  	}}})
    96  	c.Assert(err, jc.ErrorIsNil)
    97  	c.Assert(result.Results, gc.HasLen, 1)
    98  	c.Assert(result.Results[0].Error, gc.IsNil)
    99  
   100  	err = unit.Refresh()
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	unitStatus, err := unit.Status()
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	c.Assert(unitStatus.Status, gc.Equals, status.Active)
   105  }
   106  
   107  func (s *statusSetterSuite) TestSetServiceStatus(c *gc.C) {
   108  	// Calls to set the status of a service should be going through the
   109  	// ServiceStatusSetter that checks for leadership, so permission denied
   110  	// here.
   111  	service := s.Factory.MakeApplication(c, &factory.ApplicationParams{Status: &status.StatusInfo{
   112  		Status: status.Maintenance,
   113  	}})
   114  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   115  		Tag:    service.Tag().String(),
   116  		Status: status.Active.String(),
   117  	}}})
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(result.Results, gc.HasLen, 1)
   120  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
   121  
   122  	err = service.Refresh()
   123  	c.Assert(err, jc.ErrorIsNil)
   124  	serviceStatus, err := service.Status()
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	c.Assert(serviceStatus.Status, gc.Equals, status.Maintenance)
   127  }
   128  
   129  func (s *statusSetterSuite) TestBulk(c *gc.C) {
   130  	s.badTag = names.NewMachineTag("42")
   131  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   132  		Tag:    s.badTag.String(),
   133  		Status: status.Active.String(),
   134  	}, {
   135  		Tag:    "bad-tag",
   136  		Status: status.Active.String(),
   137  	}}})
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	c.Assert(result.Results, gc.HasLen, 2)
   140  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
   141  	c.Assert(result.Results[1].Error, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
   142  }
   143  
   144  type serviceStatusSetterSuite struct {
   145  	statusBaseSuite
   146  	setter *common.ServiceStatusSetter
   147  }
   148  
   149  var _ = gc.Suite(&serviceStatusSetterSuite{})
   150  
   151  func (s *serviceStatusSetterSuite) SetUpTest(c *gc.C) {
   152  	s.statusBaseSuite.SetUpTest(c)
   153  
   154  	s.setter = common.NewServiceStatusSetter(s.State, func() (common.AuthFunc, error) {
   155  		return s.authFunc, nil
   156  	})
   157  }
   158  
   159  func (s *serviceStatusSetterSuite) TestUnauthorized(c *gc.C) {
   160  	// Machines are unauthorized since they are not units
   161  	tag := names.NewUnitTag("foo/0")
   162  	s.badTag = tag
   163  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   164  		Tag:    tag.String(),
   165  		Status: status.Active.String(),
   166  	}}})
   167  	c.Assert(err, jc.ErrorIsNil)
   168  	c.Assert(result.Results, gc.HasLen, 1)
   169  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
   170  }
   171  
   172  func (s *serviceStatusSetterSuite) TestNotATag(c *gc.C) {
   173  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   174  		Tag:    "not a tag",
   175  		Status: status.Active.String(),
   176  	}}})
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	c.Assert(result.Results, gc.HasLen, 1)
   179  	c.Assert(result.Results[0].Error, gc.ErrorMatches, `"not a tag" is not a valid tag`)
   180  }
   181  
   182  func (s *serviceStatusSetterSuite) TestNotFound(c *gc.C) {
   183  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   184  		Tag:    names.NewUnitTag("foo/0").String(),
   185  		Status: status.Active.String(),
   186  	}}})
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	c.Assert(result.Results, gc.HasLen, 1)
   189  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeNotFound)
   190  }
   191  
   192  func (s *serviceStatusSetterSuite) TestSetMachineStatus(c *gc.C) {
   193  	machine := s.Factory.MakeMachine(c, nil)
   194  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   195  		Tag:    machine.Tag().String(),
   196  		Status: status.Active.String(),
   197  	}}})
   198  	c.Assert(err, jc.ErrorIsNil)
   199  	c.Assert(result.Results, gc.HasLen, 1)
   200  	// Can't call set service status on a machine.
   201  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
   202  }
   203  
   204  func (s *serviceStatusSetterSuite) TestSetServiceStatus(c *gc.C) {
   205  	// TODO: the correct way to fix this is to have the authorizer on the
   206  	// simple status setter to check to see if the unit (authTag) is a leader
   207  	// and able to set the service status. However, that is for another day.
   208  	service := s.Factory.MakeApplication(c, &factory.ApplicationParams{Status: &status.StatusInfo{
   209  		Status: status.Maintenance,
   210  	}})
   211  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   212  		Tag:    service.Tag().String(),
   213  		Status: status.Active.String(),
   214  	}}})
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	c.Assert(result.Results, gc.HasLen, 1)
   217  	// Can't call set service status on a service. Weird I know, but the only
   218  	// way is to go through the unit leader.
   219  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
   220  }
   221  
   222  func (s *serviceStatusSetterSuite) TestSetUnitStatusNotLeader(c *gc.C) {
   223  	// If the unit isn't the leader, it can't set it.
   224  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Status: &status.StatusInfo{
   225  		Status: status.Maintenance,
   226  	}})
   227  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   228  		Tag:    unit.Tag().String(),
   229  		Status: status.Active.String(),
   230  	}}})
   231  	c.Assert(err, jc.ErrorIsNil)
   232  	c.Assert(result.Results, gc.HasLen, 1)
   233  	status := result.Results[0]
   234  	c.Assert(status.Error, gc.ErrorMatches, ".* is not leader of .*")
   235  }
   236  
   237  func (s *serviceStatusSetterSuite) TestSetUnitStatusIsLeader(c *gc.C) {
   238  	service := s.Factory.MakeApplication(c, &factory.ApplicationParams{Status: &status.StatusInfo{
   239  		Status: status.Maintenance,
   240  	}})
   241  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{
   242  		Application: service,
   243  		Status: &status.StatusInfo{
   244  			Status: status.Maintenance,
   245  		}})
   246  	s.State.LeadershipClaimer().ClaimLeadership(
   247  		service.Name(),
   248  		unit.Name(),
   249  		time.Minute)
   250  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   251  		Tag:    unit.Tag().String(),
   252  		Status: status.Active.String(),
   253  	}}})
   254  
   255  	c.Assert(err, jc.ErrorIsNil)
   256  	c.Assert(result.Results, gc.HasLen, 1)
   257  	c.Assert(result.Results[0].Error, gc.IsNil)
   258  
   259  	err = service.Refresh()
   260  	c.Assert(err, jc.ErrorIsNil)
   261  	unitStatus, err := service.Status()
   262  	c.Assert(err, jc.ErrorIsNil)
   263  	c.Assert(unitStatus.Status, gc.Equals, status.Active)
   264  }
   265  
   266  func (s *serviceStatusSetterSuite) TestBulk(c *gc.C) {
   267  	s.badTag = names.NewMachineTag("42")
   268  	machine := s.Factory.MakeMachine(c, nil)
   269  	result, err := s.setter.SetStatus(params.SetStatus{[]params.EntityStatusArgs{{
   270  		Tag:    s.badTag.String(),
   271  		Status: status.Active.String(),
   272  	}, {
   273  		Tag:    machine.Tag().String(),
   274  		Status: status.Active.String(),
   275  	}, {
   276  		Tag:    "bad-tag",
   277  		Status: status.Active.String(),
   278  	}}})
   279  	c.Assert(err, jc.ErrorIsNil)
   280  	c.Assert(result.Results, gc.HasLen, 3)
   281  	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
   282  	c.Assert(result.Results[1].Error, jc.Satisfies, params.IsCodeUnauthorized)
   283  	c.Assert(result.Results[2].Error, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
   284  }
   285  
   286  type unitAgentFinderSuite struct{}
   287  
   288  var _ = gc.Suite(&unitAgentFinderSuite{})
   289  
   290  func (unitAgentFinderSuite) TestFindEntity(c *gc.C) {
   291  	f := fakeEntityFinder{
   292  		unit: fakeUnit{
   293  			agent: &state.UnitAgent{},
   294  		},
   295  	}
   296  	ua := &common.UnitAgentFinder{f}
   297  	entity, err := ua.FindEntity(names.NewUnitTag("unit/0"))
   298  	c.Assert(err, jc.ErrorIsNil)
   299  	c.Assert(entity, gc.DeepEquals, f.unit.agent)
   300  }
   301  
   302  func (unitAgentFinderSuite) TestFindEntityBadTag(c *gc.C) {
   303  	ua := &common.UnitAgentFinder{fakeEntityFinder{}}
   304  	_, err := ua.FindEntity(names.NewApplicationTag("foo"))
   305  	c.Assert(err, gc.ErrorMatches, "unsupported tag.*")
   306  }
   307  
   308  func (unitAgentFinderSuite) TestFindEntityErr(c *gc.C) {
   309  	f := fakeEntityFinder{err: errors.Errorf("boo")}
   310  	ua := &common.UnitAgentFinder{f}
   311  	_, err := ua.FindEntity(names.NewUnitTag("unit/0"))
   312  	c.Assert(errors.Cause(err), gc.Equals, f.err)
   313  }
   314  
   315  type fakeEntityFinder struct {
   316  	unit fakeUnit
   317  	err  error
   318  }
   319  
   320  func (f fakeEntityFinder) FindEntity(tag names.Tag) (state.Entity, error) {
   321  	return f.unit, f.err
   322  }
   323  
   324  type fakeUnit struct {
   325  	state.Entity
   326  	agent *state.UnitAgent
   327  }
   328  
   329  func (f fakeUnit) Agent() *state.UnitAgent {
   330  	return f.agent
   331  }