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 }