github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/action/run_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package action_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  	commontesting "github.com/juju/juju/apiserver/common/testing"
    16  	"github.com/juju/juju/apiserver/facades/client/action"
    17  	"github.com/juju/juju/apiserver/params"
    18  	apiservertesting "github.com/juju/juju/apiserver/testing"
    19  	jujutesting "github.com/juju/juju/juju/testing"
    20  	"github.com/juju/juju/state"
    21  	"github.com/juju/juju/testing"
    22  )
    23  
    24  type runSuite struct {
    25  	jujutesting.JujuConnSuite
    26  	commontesting.BlockHelper
    27  
    28  	client *action.ActionAPI
    29  }
    30  
    31  var _ = gc.Suite(&runSuite{})
    32  
    33  func (s *runSuite) SetUpTest(c *gc.C) {
    34  	s.JujuConnSuite.SetUpTest(c)
    35  	s.BlockHelper = commontesting.NewBlockHelper(s.APIState)
    36  	s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() })
    37  
    38  	var err error
    39  	auth := apiservertesting.FakeAuthorizer{
    40  		Tag: s.AdminUserTag(c),
    41  	}
    42  	s.client, err = action.NewActionAPI(s.State, nil, auth)
    43  	c.Assert(err, jc.ErrorIsNil)
    44  }
    45  
    46  func (s *runSuite) addMachine(c *gc.C) *state.Machine {
    47  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
    48  	c.Assert(err, jc.ErrorIsNil)
    49  	return machine
    50  }
    51  
    52  func (s *runSuite) addUnit(c *gc.C, application *state.Application) *state.Unit {
    53  	unit, err := application.AddUnit(state.AddUnitParams{})
    54  	c.Assert(err, jc.ErrorIsNil)
    55  	err = unit.AssignToNewMachine()
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	return unit
    58  }
    59  
    60  func (s *runSuite) TestGetAllUnitNames(c *gc.C) {
    61  	charm := s.AddTestingCharm(c, "dummy")
    62  	magic, err := s.State.AddApplication(state.AddApplicationArgs{Name: "magic", Charm: charm})
    63  	s.addUnit(c, magic)
    64  	s.addUnit(c, magic)
    65  
    66  	// Ensure magic/1 is the leader.
    67  	claimer, err := s.LeaseManager.Claimer("application-leadership", s.State.ModelUUID())
    68  	c.Assert(err, jc.ErrorIsNil)
    69  	err = claimer.Claim("magic", "magic/1", time.Minute)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  
    72  	notAssigned, err := s.State.AddApplication(state.AddApplicationArgs{Name: "not-assigned", Charm: charm})
    73  	c.Assert(err, jc.ErrorIsNil)
    74  	_, err = notAssigned.AddUnit(state.AddUnitParams{})
    75  	c.Assert(err, jc.ErrorIsNil)
    76  
    77  	_, err = s.State.AddApplication(state.AddApplicationArgs{Name: "no-units", Charm: charm})
    78  	c.Assert(err, jc.ErrorIsNil)
    79  
    80  	wordpress, err := s.State.AddApplication(state.AddApplicationArgs{Name: "wordpress", Charm: s.AddTestingCharm(c, "wordpress")})
    81  	c.Assert(err, jc.ErrorIsNil)
    82  	wordpress0 := s.addUnit(c, wordpress)
    83  	_, err = s.State.AddApplication(state.AddApplicationArgs{Name: "logging", Charm: s.AddTestingCharm(c, "logging")})
    84  	c.Assert(err, jc.ErrorIsNil)
    85  
    86  	eps, err := s.State.InferEndpoints("logging", "wordpress")
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	rel, err := s.State.AddRelation(eps...)
    89  	c.Assert(err, jc.ErrorIsNil)
    90  	ru, err := rel.Unit(wordpress0)
    91  	c.Assert(err, jc.ErrorIsNil)
    92  	err = ru.EnterScope(nil)
    93  	c.Assert(err, jc.ErrorIsNil)
    94  
    95  	for i, test := range []struct {
    96  		message      string
    97  		expected     []string
    98  		units        []string
    99  		applications []string
   100  		error        string
   101  	}{{
   102  		message: "no units, expected nil slice",
   103  	}, {
   104  		message:      "asking for an empty string application",
   105  		applications: []string{""},
   106  		error:        `"" is not a valid application name`,
   107  	}, {
   108  		message: "asking for an empty string unit",
   109  		units:   []string{""},
   110  		error:   `invalid unit name ""`,
   111  	}, {
   112  		message:      "asking for a application that isn't there",
   113  		applications: []string{"foo"},
   114  		error:        `application "foo" not found`,
   115  	}, {
   116  		message:      "application with no units is not really an error",
   117  		applications: []string{"no-units"},
   118  	}, {
   119  		message:      "A application with units",
   120  		applications: []string{"magic"},
   121  		expected:     []string{"magic/0", "magic/1"},
   122  	}, {
   123  		message:  "Asking for just a unit",
   124  		units:    []string{"magic/0"},
   125  		expected: []string{"magic/0"},
   126  	}, {
   127  		message:  "Asking for just a subordinate unit",
   128  		units:    []string{"logging/0"},
   129  		expected: []string{"logging/0"},
   130  	}, {
   131  		message:      "Asking for a unit, and the application",
   132  		applications: []string{"magic"},
   133  		units:        []string{"magic/0"},
   134  		expected:     []string{"magic/0", "magic/1"},
   135  	}, {
   136  		message:  "Asking for an application leader unit",
   137  		units:    []string{"magic/leader"},
   138  		expected: []string{"magic/1"},
   139  	}, {
   140  		message: "Asking for an application leader unit of an unknown application",
   141  		units:   []string{"foo/leader"},
   142  		error:   `could not determine leader for "foo"`,
   143  	}} {
   144  		c.Logf("%v: %s", i, test.message)
   145  		result, err := action.GetAllUnitNames(s.State, test.units, test.applications)
   146  		if test.error == "" {
   147  			c.Check(err, jc.ErrorIsNil)
   148  			var units []string
   149  			for _, unit := range result {
   150  				units = append(units, unit.Id())
   151  			}
   152  			c.Check(units, jc.SameContents, test.expected)
   153  		} else {
   154  			c.Check(err, gc.ErrorMatches, test.error)
   155  		}
   156  	}
   157  }
   158  
   159  func (s *runSuite) AssertBlocked(c *gc.C, err error, msg string) {
   160  	c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err))
   161  	c.Assert(errors.Cause(err), gc.DeepEquals, &params.Error{
   162  		Message: msg,
   163  		Code:    "operation is blocked",
   164  	})
   165  }
   166  
   167  func (s *runSuite) TestBlockRunOnAllMachines(c *gc.C) {
   168  	// block all changes
   169  	s.BlockAllChanges(c, "TestBlockRunOnAllMachines")
   170  	_, err := s.client.RunOnAllMachines(
   171  		params.RunParams{
   172  			Commands: "hostname",
   173  			Timeout:  testing.LongWait,
   174  		})
   175  	s.AssertBlocked(c, err, "TestBlockRunOnAllMachines")
   176  }
   177  
   178  func (s *runSuite) TestBlockRunMachineAndApplication(c *gc.C) {
   179  	// block all changes
   180  	s.BlockAllChanges(c, "TestBlockRunMachineAndApplication")
   181  	_, err := s.client.Run(
   182  		params.RunParams{
   183  			Commands:     "hostname",
   184  			Timeout:      testing.LongWait,
   185  			Machines:     []string{"0"},
   186  			Applications: []string{"magic"},
   187  		})
   188  	s.AssertBlocked(c, err, "TestBlockRunMachineAndApplication")
   189  }
   190  
   191  func (s *runSuite) TestRunMachineAndApplication(c *gc.C) {
   192  	// We only test that we create the actions correctly
   193  	// There is no need to test anything else at this level.
   194  	expectedPayload := map[string]interface{}{
   195  		"command": "hostname",
   196  		"timeout": int64(0),
   197  	}
   198  	expectedArgs := params.Actions{
   199  		Actions: []params.Action{
   200  			{Receiver: "unit-magic-0", Name: "juju-run", Parameters: expectedPayload},
   201  			{Receiver: "unit-magic-1", Name: "juju-run", Parameters: expectedPayload},
   202  			{Receiver: "machine-0", Name: "juju-run", Parameters: expectedPayload},
   203  		},
   204  	}
   205  	called := false
   206  	s.PatchValue(action.QueueActions, func(client *action.ActionAPI, args params.Actions) (params.ActionResults, error) {
   207  		called = true
   208  		c.Assert(args, jc.DeepEquals, expectedArgs)
   209  		return params.ActionResults{}, nil
   210  	})
   211  
   212  	s.addMachine(c)
   213  
   214  	charm := s.AddTestingCharm(c, "dummy")
   215  	magic, err := s.State.AddApplication(state.AddApplicationArgs{Name: "magic", Charm: charm})
   216  	c.Assert(err, jc.ErrorIsNil)
   217  	s.addUnit(c, magic)
   218  	s.addUnit(c, magic)
   219  
   220  	s.client.Run(
   221  		params.RunParams{
   222  			Commands:     "hostname",
   223  			Machines:     []string{"0"},
   224  			Applications: []string{"magic"},
   225  		})
   226  	c.Assert(called, jc.IsTrue)
   227  }
   228  
   229  func (s *runSuite) TestRunOnAllMachines(c *gc.C) {
   230  	// We only test that we create the actions correctly
   231  	// There is no need to test anything else at this level.
   232  	expectedPayload := map[string]interface{}{
   233  		"command": "hostname",
   234  		"timeout": testing.LongWait.Nanoseconds(),
   235  	}
   236  	expectedArgs := params.Actions{
   237  		Actions: []params.Action{
   238  			{Receiver: "machine-0", Name: "juju-run", Parameters: expectedPayload},
   239  			{Receiver: "machine-1", Name: "juju-run", Parameters: expectedPayload},
   240  			{Receiver: "machine-2", Name: "juju-run", Parameters: expectedPayload},
   241  		},
   242  	}
   243  	called := false
   244  	s.PatchValue(action.QueueActions, func(client *action.ActionAPI, args params.Actions) (params.ActionResults, error) {
   245  		called = true
   246  		c.Assert(args, jc.DeepEquals, expectedArgs)
   247  		return params.ActionResults{}, nil
   248  	})
   249  	// Make three machines.
   250  	s.addMachine(c)
   251  	s.addMachine(c)
   252  	s.addMachine(c)
   253  
   254  	s.client.RunOnAllMachines(
   255  		params.RunParams{
   256  			Commands: "hostname",
   257  			Timeout:  testing.LongWait,
   258  		})
   259  	c.Assert(called, jc.IsTrue)
   260  }
   261  
   262  func (s *runSuite) TestRunRequiresAdmin(c *gc.C) {
   263  	alpha := names.NewUserTag("alpha@bravo")
   264  	auth := apiservertesting.FakeAuthorizer{
   265  		Tag:         alpha,
   266  		HasWriteTag: alpha,
   267  	}
   268  	client, err := action.NewActionAPI(s.State, nil, auth)
   269  	c.Assert(err, jc.ErrorIsNil)
   270  	_, err = client.Run(params.RunParams{})
   271  	c.Assert(errors.Cause(err), gc.Equals, common.ErrPerm)
   272  
   273  	auth.AdminTag = alpha
   274  	client, err = action.NewActionAPI(s.State, nil, auth)
   275  	c.Assert(err, jc.ErrorIsNil)
   276  	_, err = client.Run(params.RunParams{})
   277  	c.Assert(err, jc.ErrorIsNil)
   278  }
   279  
   280  func (s *runSuite) TestRunOnAllMachinesRequiresAdmin(c *gc.C) {
   281  	alpha := names.NewUserTag("alpha@bravo")
   282  	auth := apiservertesting.FakeAuthorizer{
   283  		Tag:         alpha,
   284  		HasWriteTag: alpha,
   285  	}
   286  	client, err := action.NewActionAPI(s.State, nil, auth)
   287  	c.Assert(err, jc.ErrorIsNil)
   288  	_, err = client.RunOnAllMachines(params.RunParams{})
   289  	c.Assert(errors.Cause(err), gc.Equals, common.ErrPerm)
   290  
   291  	auth.AdminTag = alpha
   292  	client, err = action.NewActionAPI(s.State, nil, auth)
   293  	c.Assert(err, jc.ErrorIsNil)
   294  	_, err = client.RunOnAllMachines(params.RunParams{})
   295  	c.Assert(err, jc.ErrorIsNil)
   296  }