github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/instancemutater/mutater_test.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package instancemutater_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names/v5"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	"go.uber.org/mock/gomock"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	apiinstancemutater "github.com/juju/juju/api/agent/instancemutater"
    16  	"github.com/juju/juju/core/instance"
    17  	"github.com/juju/juju/core/life"
    18  	"github.com/juju/juju/core/lxdprofile"
    19  	"github.com/juju/juju/core/status"
    20  	"github.com/juju/juju/worker/instancemutater"
    21  	"github.com/juju/juju/worker/instancemutater/mocks"
    22  )
    23  
    24  type mutaterSuite struct {
    25  	testing.IsolationSuite
    26  
    27  	tag    names.MachineTag
    28  	instId string
    29  
    30  	facade  *mocks.MockInstanceMutaterAPI
    31  	machine *mocks.MockMutaterMachine
    32  	broker  *mocks.MockLXDProfiler
    33  
    34  	mutaterMachine *instancemutater.MutaterMachine
    35  }
    36  
    37  var _ = gc.Suite(&mutaterSuite{})
    38  
    39  func (s *mutaterSuite) SetUpTest(c *gc.C) {
    40  	s.tag = names.NewMachineTag("2")
    41  	s.instId = "juju-23413-2"
    42  	s.IsolationSuite.SetUpTest(c)
    43  }
    44  
    45  func (s *mutaterSuite) TestProcessMachineProfileChanges(c *gc.C) {
    46  	defer s.setUpMocks(c).Finish()
    47  
    48  	startingProfiles := []string{"default", "juju-testme"}
    49  	finishingProfiles := append(startingProfiles, "juju-testme-lxd-profile-1")
    50  
    51  	s.expectRefreshLifeAliveStatusIdle()
    52  	s.expectLXDProfileNames(startingProfiles, nil)
    53  	s.expectAssignLXDProfiles(finishingProfiles, nil)
    54  	s.expectSetCharmProfiles(finishingProfiles)
    55  	s.expectModificationStatusApplied()
    56  
    57  	info := s.info(startingProfiles, 1, true)
    58  	err := instancemutater.ProcessMachineProfileChanges(s.mutaterMachine, info)
    59  	c.Assert(err, jc.ErrorIsNil)
    60  }
    61  
    62  func (s *mutaterSuite) TestProcessMachineProfileChangesMachineDead(c *gc.C) {
    63  	defer s.setUpMocks(c).Finish()
    64  
    65  	startingProfiles := []string{"default", "juju-testme"}
    66  
    67  	s.expectRefreshLifeDead()
    68  
    69  	info := s.info(startingProfiles, 1, false)
    70  	err := instancemutater.ProcessMachineProfileChanges(s.mutaterMachine, info)
    71  	c.Assert(err, jc.Satisfies, errors.IsNotValid)
    72  }
    73  
    74  func (s *mutaterSuite) TestProcessMachineProfileChangesError(c *gc.C) {
    75  	defer s.setUpMocks(c).Finish()
    76  
    77  	startingProfiles := []string{"default", "juju-testme"}
    78  	finishingProfiles := append(startingProfiles, "juju-testme-lxd-profile-1")
    79  
    80  	s.expectRefreshLifeAliveStatusIdle()
    81  	s.expectLXDProfileNames(startingProfiles, nil)
    82  	s.expectAssignLXDProfiles(finishingProfiles, errors.New("fail me"))
    83  	s.expectModificationStatusError()
    84  
    85  	info := s.info(startingProfiles, 1, true)
    86  	err := instancemutater.ProcessMachineProfileChanges(s.mutaterMachine, info)
    87  	c.Assert(err, gc.ErrorMatches, "fail me")
    88  }
    89  
    90  func (s *mutaterSuite) TestProcessMachineProfileChangesNilInfo(c *gc.C) {
    91  	defer s.setUpMocks(c).Finish()
    92  
    93  	err := instancemutater.ProcessMachineProfileChanges(s.mutaterMachine, &apiinstancemutater.UnitProfileInfo{})
    94  	c.Assert(err, jc.ErrorIsNil)
    95  }
    96  
    97  func (s *mutaterSuite) TestGatherProfileDataReplace(c *gc.C) {
    98  	defer s.setUpMocks(c).Finish()
    99  
   100  	post, err := instancemutater.GatherProfileData(
   101  		s.mutaterMachine,
   102  		s.info([]string{"default", "juju-testme", "juju-testme-lxd-profile-0"}, 1, true),
   103  	)
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	c.Assert(post, gc.DeepEquals, []lxdprofile.ProfilePost{
   106  		{Name: "juju-testme-lxd-profile-0", Profile: nil},
   107  		{Name: "juju-testme-lxd-profile-1", Profile: &testProfile},
   108  	})
   109  }
   110  
   111  func (s *mutaterSuite) TestGatherProfileDataRemove(c *gc.C) {
   112  	defer s.setUpMocks(c).Finish()
   113  
   114  	post, err := instancemutater.GatherProfileData(
   115  		s.mutaterMachine,
   116  		s.info([]string{"default", "juju-testme", "juju-testme-lxd-profile-0"}, 0, false),
   117  	)
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(post, gc.DeepEquals, []lxdprofile.ProfilePost{
   120  		{Name: "juju-testme-lxd-profile-0", Profile: nil},
   121  	})
   122  }
   123  
   124  func (s *mutaterSuite) TestGatherProfileDataAdd(c *gc.C) {
   125  	defer s.setUpMocks(c).Finish()
   126  
   127  	post, err := instancemutater.GatherProfileData(
   128  		s.mutaterMachine,
   129  		s.info([]string{"default", "juju-testme"}, 1, true),
   130  	)
   131  	c.Assert(err, jc.ErrorIsNil)
   132  	c.Assert(post, gc.DeepEquals, []lxdprofile.ProfilePost{
   133  		{Name: "juju-testme-lxd-profile-1", Profile: &testProfile},
   134  	})
   135  }
   136  
   137  func (s *mutaterSuite) TestGatherProfileDataNoChange(c *gc.C) {
   138  	defer s.setUpMocks(c).Finish()
   139  
   140  	post, err := instancemutater.GatherProfileData(
   141  		s.mutaterMachine,
   142  		s.info([]string{"default", "juju-testme", "juju-testme-lxd-profile-0"}, 0, true),
   143  	)
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	c.Assert(post, gc.DeepEquals, []lxdprofile.ProfilePost{
   146  		{Name: "juju-testme-lxd-profile-0", Profile: &testProfile},
   147  	})
   148  }
   149  
   150  func (s *mutaterSuite) info(profiles []string, rev int, add bool) *apiinstancemutater.UnitProfileInfo {
   151  	info := &apiinstancemutater.UnitProfileInfo{
   152  		ModelName:       "testme",
   153  		InstanceId:      instance.Id(s.instId),
   154  		CurrentProfiles: profiles,
   155  		ProfileChanges: []apiinstancemutater.UnitProfileChanges{
   156  			{ApplicationName: "lxd-profile",
   157  				Revision: rev,
   158  			},
   159  			// app-no-profile tests the fix for lp:1904619,
   160  			// use a pointer to a copy of data in for loop,
   161  			// rather than a pointer to the data as the data
   162  			// will change in subsequent loop iterations, but
   163  			// the pointer's address will not.
   164  			{ApplicationName: "app-no-profile",
   165  				Revision: rev,
   166  			},
   167  		},
   168  	}
   169  	if add {
   170  		info.ProfileChanges[0].Profile = testProfile
   171  	}
   172  	return info
   173  }
   174  
   175  func (s *mutaterSuite) TestVerifyCurrentProfilesTrue(c *gc.C) {
   176  	defer s.setUpMocks(c).Finish()
   177  
   178  	profiles := []string{"default", "juju-testme", "juju-testme-lxd-profile-0"}
   179  	s.expectLXDProfileNames(profiles, nil)
   180  
   181  	ok, err := instancemutater.VerifyCurrentProfiles(s.mutaterMachine, s.instId, profiles)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  	c.Assert(ok, jc.IsTrue)
   184  }
   185  
   186  func (s *mutaterSuite) TestVerifyCurrentProfilesFalseLength(c *gc.C) {
   187  	defer s.setUpMocks(c).Finish()
   188  
   189  	profiles := []string{"default", "juju-testme", "juju-testme-lxd-profile-0"}
   190  	s.expectLXDProfileNames(profiles, nil)
   191  
   192  	ok, err := instancemutater.VerifyCurrentProfiles(s.mutaterMachine, s.instId, append(profiles, "juju-testme-next-1"))
   193  	c.Assert(err, jc.ErrorIsNil)
   194  	c.Assert(ok, jc.IsFalse)
   195  }
   196  
   197  func (s *mutaterSuite) TestVerifyCurrentProfilesFalseContents(c *gc.C) {
   198  	defer s.setUpMocks(c).Finish()
   199  
   200  	s.expectLXDProfileNames([]string{"default", "juju-testme", "juju-testme-lxd-profile-0"}, nil)
   201  
   202  	ok, err := instancemutater.VerifyCurrentProfiles(s.mutaterMachine, s.instId, []string{"default", "juju-testme", "juju-testme-lxd-profile-1"})
   203  	c.Assert(err, jc.ErrorIsNil)
   204  	c.Assert(ok, jc.IsFalse)
   205  }
   206  
   207  func (s *mutaterSuite) TestVerifyCurrentProfilesError(c *gc.C) {
   208  	defer s.setUpMocks(c).Finish()
   209  
   210  	s.expectLXDProfileNames([]string{}, errors.NotFoundf("instId"))
   211  
   212  	ok, err := instancemutater.VerifyCurrentProfiles(s.mutaterMachine, s.instId, []string{"default"})
   213  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   214  	c.Assert(ok, jc.IsFalse)
   215  }
   216  
   217  func (s *mutaterSuite) setUpMocks(c *gc.C) *gomock.Controller {
   218  	ctrl := gomock.NewController(c)
   219  
   220  	logger := loggo.GetLogger("mutaterSuite")
   221  
   222  	s.machine = mocks.NewMockMutaterMachine(ctrl)
   223  	s.machine.EXPECT().Tag().Return(s.tag).AnyTimes()
   224  
   225  	s.broker = mocks.NewMockLXDProfiler(ctrl)
   226  	s.facade = mocks.NewMockInstanceMutaterAPI(ctrl)
   227  
   228  	s.mutaterMachine = instancemutater.NewMachineContext(logger, s.broker, s.machine, s.getRequiredLXDProfiles, s.tag.Id())
   229  	return ctrl
   230  }
   231  
   232  func (s *mutaterSuite) expectLXDProfileNames(profiles []string, err error) {
   233  	s.broker.EXPECT().LXDProfileNames(s.instId).Return(profiles, err)
   234  }
   235  
   236  func (s *mutaterSuite) expectRefreshLifeAliveStatusIdle() {
   237  	mExp := s.machine.EXPECT()
   238  	mExp.Refresh().Return(nil)
   239  	mExp.Life().Return(life.Alive)
   240  	mExp.SetModificationStatus(status.Idle, "", nil).Return(nil)
   241  }
   242  
   243  func (s *mutaterSuite) expectRefreshLifeDead() {
   244  	mExp := s.machine.EXPECT()
   245  	mExp.Refresh().Return(nil)
   246  	mExp.Life().Return(life.Dead)
   247  }
   248  
   249  func (s *mutaterSuite) expectModificationStatusApplied() {
   250  	s.machine.EXPECT().SetModificationStatus(status.Applied, "", nil).Return(nil)
   251  }
   252  
   253  func (s *mutaterSuite) expectModificationStatusError() {
   254  	s.machine.EXPECT().SetModificationStatus(status.Error, gomock.Any(), gomock.Any()).Return(nil)
   255  }
   256  
   257  func (s *mutaterSuite) expectAssignLXDProfiles(profiles []string, err error) {
   258  	s.broker.EXPECT().AssignLXDProfiles(s.instId, profiles, gomock.Any()).Return(profiles, err)
   259  }
   260  
   261  func (s *mutaterSuite) expectSetCharmProfiles(profiles []string) {
   262  	s.machine.EXPECT().SetCharmProfiles(profiles)
   263  }
   264  
   265  func (s *mutaterSuite) getRequiredLXDProfiles(modelName string) []string {
   266  	return []string{"default", "juju-" + modelName}
   267  }
   268  
   269  var testProfile = lxdprofile.Profile{
   270  	Config: map[string]string{
   271  		"security.nesting": "true",
   272  	},
   273  	Description: "dummy profile description",
   274  	Devices: map[string]map[string]string{
   275  		"tun": {
   276  			"path": "/dev/net/tun",
   277  		},
   278  	},
   279  }