github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/service/agentconf_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // The test cases in this file do not pertain to a specific command. 5 6 package service_test 7 8 import ( 9 "bytes" 10 "fmt" 11 "os" 12 "path" 13 14 "github.com/juju/errors" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/utils/arch" 17 "github.com/juju/version" 18 gc "gopkg.in/check.v1" 19 "gopkg.in/juju/names.v2" 20 21 "github.com/juju/juju/agent" 22 agenttools "github.com/juju/juju/agent/tools" 23 agentcmd "github.com/juju/juju/cmd/jujud/agent" 24 "github.com/juju/juju/mongo" 25 "github.com/juju/juju/service" 26 "github.com/juju/juju/service/common" 27 svctesting "github.com/juju/juju/service/common/testing" 28 "github.com/juju/juju/service/systemd" 29 "github.com/juju/juju/testing" 30 coretest "github.com/juju/juju/tools" 31 jujuversion "github.com/juju/juju/version" 32 ) 33 34 type agentConfSuite struct { 35 testing.BaseSuite 36 37 agentConf agent.Config 38 dataDir string 39 machineName string 40 unitNames []string 41 systemdDir string 42 systemdMultiUserDir string 43 systemdDataDir string // service.SystemdDataDir 44 manager service.SystemdServiceManager 45 46 services []*svctesting.FakeService 47 serviceData *svctesting.FakeServiceData 48 } 49 50 func (s *agentConfSuite) SetUpSuite(c *gc.C) { 51 s.BaseSuite.SetUpSuite(c) 52 } 53 54 func (s *agentConfSuite) SetUpTest(c *gc.C) { 55 s.BaseSuite.SetUpTest(c) 56 57 s.dataDir = c.MkDir() 58 s.systemdDir = path.Join(s.dataDir, "etc", "systemd", "system") 59 s.systemdMultiUserDir = path.Join(s.systemdDir, "multi-user.target.wants") 60 c.Assert(os.MkdirAll(s.systemdMultiUserDir, os.ModeDir|os.ModePerm), jc.ErrorIsNil) 61 s.systemdDataDir = path.Join(s.dataDir, "lib", "systemd", "system") 62 63 s.machineName = "machine-0" 64 s.unitNames = []string{"unit-ubuntu-0", "unit-mysql-0"} 65 66 s.manager = service.NewServiceManager( 67 func() bool { return true }, 68 s.newService, 69 ) 70 71 s.assertSetupAgentsForTest(c) 72 s.setUpAgentConf(c) 73 s.setUpServices(c) 74 s.services[0].ResetCalls() 75 s.setupTools(c, "trusty") 76 } 77 78 func (s *agentConfSuite) TearDownTest(c *gc.C) { 79 s.serviceData = nil 80 s.services = nil 81 s.BaseSuite.TearDownTest(c) 82 } 83 84 var _ = gc.Suite(&agentConfSuite{}) 85 86 func (s *agentConfSuite) setUpAgentConf(c *gc.C) { 87 // Required for CopyAgentBinaries to evaluate the version of the agent. 88 configParams := agent.AgentConfigParams{ 89 Paths: agent.Paths{DataDir: s.dataDir}, 90 Tag: names.NewMachineTag("0"), 91 UpgradedToVersion: jujuversion.Current, 92 APIAddresses: []string{"localhost:17070"}, 93 CACert: testing.CACert, 94 Password: "fake", 95 Controller: testing.ControllerTag, 96 Model: testing.ModelTag, 97 MongoVersion: mongo.Mongo32wt, 98 } 99 100 agentConf, err := agent.NewAgentConfig(configParams) 101 c.Assert(err, jc.ErrorIsNil) 102 103 err = agentConf.Write() 104 c.Assert(err, jc.ErrorIsNil) 105 106 s.agentConf = agentConf 107 } 108 109 func (s *agentConfSuite) setUpServices(c *gc.C) { 110 for _, fake := range append(s.unitNames, s.machineName) { 111 s.addService(c, "jujud-"+fake) 112 } 113 s.PatchValue(&service.ListServices, s.listServices) 114 } 115 116 func (s *agentConfSuite) addService(c *gc.C, name string) { 117 svc, err := s.newService(name, common.Conf{}) 118 c.Assert(err, jc.ErrorIsNil) 119 c.Assert(svc.Install(), jc.ErrorIsNil) 120 c.Assert(svc.Start(), jc.ErrorIsNil) 121 } 122 123 func (s *agentConfSuite) listServices() ([]string, error) { 124 return s.serviceData.InstalledNames(), nil 125 } 126 127 func (s *agentConfSuite) newService(name string, conf common.Conf) (service.Service, error) { 128 for _, svc := range s.services { 129 if svc.Name() == name { 130 return svc, nil 131 } 132 } 133 if s.serviceData == nil { 134 s.serviceData = svctesting.NewFakeServiceData() 135 } 136 svc := &svctesting.FakeService{ 137 FakeServiceData: s.serviceData, 138 Service: common.Service{ 139 Name: name, 140 Conf: common.Conf{}, 141 }, 142 DataDir: s.dataDir, 143 } 144 s.services = append(s.services, svc) 145 return svc, nil 146 } 147 148 func (s *agentConfSuite) setupTools(c *gc.C, series string) { 149 files := []*testing.TarFile{ 150 testing.NewTarFile("jujud", 0755, "jujuc executable"), 151 } 152 data, checksum := testing.TarGz(files...) 153 testTools := &coretest.Tools{ 154 URL: "http://foo/bar1", 155 Version: version.Binary{ 156 Number: jujuversion.Current, 157 Arch: arch.HostArch(), 158 Series: series, 159 }, 160 Size: int64(len(data)), 161 SHA256: checksum, 162 } 163 err := agenttools.UnpackTools(s.dataDir, testTools, bytes.NewReader(data)) 164 c.Assert(err, jc.ErrorIsNil) 165 } 166 167 func (s *agentConfSuite) assertSetupAgentsForTest(c *gc.C) { 168 agentsDir := path.Join(s.dataDir, "agents") 169 err := os.MkdirAll(path.Join(agentsDir, s.machineName), os.ModeDir|os.ModePerm) 170 c.Assert(err, jc.ErrorIsNil) 171 for _, unit := range s.unitNames { 172 err = os.Mkdir(path.Join(agentsDir, unit), os.ModeDir|os.ModePerm) 173 c.Assert(err, jc.ErrorIsNil) 174 } 175 } 176 177 func (s *agentConfSuite) TestFindAgents(c *gc.C) { 178 machineAgent, unitAgents, errAgents, err := s.manager.FindAgents(s.dataDir) 179 c.Assert(err, jc.ErrorIsNil) 180 181 c.Assert(machineAgent, gc.Equals, s.machineName) 182 c.Assert(unitAgents, jc.SameContents, s.unitNames) 183 c.Assert(errAgents, gc.HasLen, 0) 184 } 185 186 func (s *agentConfSuite) TestFindAgentsUnexpectedTagType(c *gc.C) { 187 unexpectedAgent := names.NewApplicationTag("failme").String() 188 unexpectedAgentDir := path.Join(s.dataDir, "agents", unexpectedAgent) 189 err := os.MkdirAll(unexpectedAgentDir, os.ModeDir|os.ModePerm) 190 c.Assert(err, jc.ErrorIsNil) 191 192 machineAgent, unitAgents, unexpectedAgents, err := s.manager.FindAgents(s.dataDir) 193 c.Assert(err, jc.ErrorIsNil) 194 c.Assert(machineAgent, gc.Equals, s.machineName) 195 c.Assert(unitAgents, jc.SameContents, s.unitNames) 196 c.Assert(unexpectedAgents, gc.DeepEquals, []string{unexpectedAgent}) 197 } 198 199 func (s *agentConfSuite) TestCreateAgentConfDesc(c *gc.C) { 200 conf, err := s.manager.CreateAgentConf("machine-2", s.dataDir) 201 c.Assert(err, jc.ErrorIsNil) 202 // Spot check Conf 203 c.Assert(conf.Desc, gc.Equals, "juju agent for machine-2") 204 } 205 206 func (s *agentConfSuite) TestCreateAgentConfLogPath(c *gc.C) { 207 conf, err := s.manager.CreateAgentConf("machine-2", s.dataDir) 208 c.Assert(err, jc.ErrorIsNil) 209 c.Assert(conf.Logfile, gc.Equals, "/var/log/juju/machine-2.log") 210 } 211 212 func (s *agentConfSuite) TestCreateAgentConfFailAgentKind(c *gc.C) { 213 _, err := s.manager.CreateAgentConf("application-fail", s.dataDir) 214 c.Assert(err, gc.ErrorMatches, `agent "application-fail" is neither a machine nor a unit`) 215 } 216 217 func (s *agentConfSuite) agentUnitNames() []string { 218 unitAgents := make([]string, len(s.unitNames)) 219 for i, name := range s.unitNames { 220 unitAgents[i] = "jujud-" + name 221 } 222 return unitAgents 223 } 224 225 func (s *agentConfSuite) TestStartAllAgents(c *gc.C) { 226 machineAgent, unitAgents, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir) 227 c.Assert(err, jc.ErrorIsNil) 228 c.Assert(machineAgent, gc.Equals, "jujud-"+s.machineName) 229 c.Assert(unitAgents, jc.SameContents, s.agentUnitNames()) 230 s.assertServicesCalls(c, "Start", len(s.services)) 231 } 232 233 func (s *agentConfSuite) TestStartAllAgentsFailSecondUnit(c *gc.C) { 234 s.services[0].SetErrors( 235 nil, 236 errors.New("fail me"), 237 ) 238 239 machineAgent, unitAgents, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir) 240 c.Assert(err, gc.ErrorMatches, "failed to start jujud-unit-.* service: fail me") 241 c.Assert(machineAgent, gc.Equals, "") 242 c.Assert(unitAgents, gc.HasLen, 1) 243 s.assertServicesCalls(c, "Start", 2) 244 } 245 246 func (s *agentConfSuite) TestStartAllAgentsFailMachine(c *gc.C) { 247 s.services[0].SetErrors( 248 nil, 249 nil, 250 errors.New("fail me"), 251 ) 252 253 machineAgent, unitAgents, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir) 254 c.Assert(err, gc.ErrorMatches, fmt.Sprintf("failed to start jujud-%s service: fail me", s.machineName)) 255 c.Assert(machineAgent, gc.Equals, "") 256 c.Assert(unitAgents, jc.SameContents, s.agentUnitNames()) 257 s.assertServicesCalls(c, "Start", len(s.services)) 258 } 259 260 func (s *agentConfSuite) TestStartAllAgentsSystemdNotRunning(c *gc.C) { 261 s.manager = service.NewServiceManager( 262 func() bool { return false }, 263 s.newService, 264 ) 265 266 _, _, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir) 267 c.Assert(err, gc.ErrorMatches, "cannot interact with systemd; reboot to start agents") 268 s.assertServicesCalls(c, "Start", 0) 269 } 270 271 func (s *agentConfSuite) TestCopyAgentBinaryIdempotent(c *gc.C) { 272 jujuVersion, err := agentcmd.GetJujuVersion(s.machineName, s.dataDir) 273 c.Assert(err, jc.ErrorIsNil) 274 275 err = s.manager.CopyAgentBinary(s.machineName, s.unitNames, s.dataDir, "xenial", "trusty", jujuVersion) 276 c.Assert(err, jc.ErrorIsNil) 277 s.assertToolsCopySymlink(c, "xenial") 278 279 err = s.manager.CopyAgentBinary(s.machineName, s.unitNames, s.dataDir, "xenial", "trusty", jujuVersion) 280 c.Assert(err, jc.ErrorIsNil) 281 s.assertToolsCopySymlink(c, "xenial") 282 } 283 284 func (s *agentConfSuite) TestCopyAgentBinaryOriginalAgentBinariesNotFound(c *gc.C) { 285 jujuVersion, err := agentcmd.GetJujuVersion(s.machineName, s.dataDir) 286 c.Assert(err, jc.ErrorIsNil) 287 288 err = s.manager.CopyAgentBinary(s.machineName, s.unitNames, s.dataDir, "xenial", "xenial", jujuVersion) 289 c.Assert(err, gc.ErrorMatches, "failed to copy tools: .* no such file or directory") 290 } 291 292 func (s *agentConfSuite) TestWriteSystemdAgents(c *gc.C) { 293 startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents( 294 s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir) 295 296 c.Assert(err, jc.ErrorIsNil) 297 c.Assert(startedSysServiceNames, gc.HasLen, 0) 298 c.Assert(startedSymLinkAgents, gc.DeepEquals, append(s.agentUnitNames(), "jujud-"+s.machineName)) 299 c.Assert(errAgents, gc.HasLen, 0) 300 s.assertServicesCalls(c, "WriteService", len(s.services)) 301 } 302 303 func (s *agentConfSuite) TestWriteSystemdAgentsSystemdNotRunning(c *gc.C) { 304 s.manager = service.NewServiceManager( 305 func() bool { return false }, 306 s.newService, 307 ) 308 309 startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents( 310 s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir) 311 312 c.Assert(err, jc.ErrorIsNil) 313 c.Assert(startedSymLinkAgents, gc.HasLen, 0) 314 c.Assert(startedSysServiceNames, gc.DeepEquals, append(s.agentUnitNames(), "jujud-"+s.machineName)) 315 c.Assert(errAgents, gc.HasLen, 0) 316 s.assertServicesCalls(c, "WriteService", len(s.services)) 317 s.assertServiceSymLinks(c) 318 } 319 320 func (s *agentConfSuite) TestWriteSystemdAgentsDBusErrManualLink(c *gc.C) { 321 s.services[0].SetErrors( 322 errors.New("No such method 'LinkUnitFiles'"), 323 errors.New("No such method 'LinkUnitFiles'"), 324 errors.New("No such method 'LinkUnitFiles'"), 325 ) 326 327 startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents( 328 s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir) 329 330 c.Assert(err, jc.ErrorIsNil) 331 332 // This exhibits the same characteristics as for Systemd not running (above). 333 c.Assert(startedSymLinkAgents, gc.HasLen, 0) 334 c.Assert(startedSysServiceNames, gc.DeepEquals, append(s.agentUnitNames(), "jujud-"+s.machineName)) 335 c.Assert(errAgents, gc.HasLen, 0) 336 s.assertServicesCalls(c, "WriteService", len(s.services)) 337 } 338 339 func (s *agentConfSuite) TestWriteSystemdAgentsWriteServiceFail(c *gc.C) { 340 s.services[0].SetErrors( 341 nil, 342 nil, 343 errors.New("fail me"), // fail the machine 344 ) 345 346 startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents( 347 s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir) 348 349 c.Assert(err, gc.ErrorMatches, "fail me") 350 c.Assert(startedSysServiceNames, gc.HasLen, 0) 351 c.Assert(startedSymLinkAgents, gc.DeepEquals, s.agentUnitNames()) 352 c.Assert(errAgents, gc.DeepEquals, []string{s.machineName}) 353 s.assertServicesCalls(c, "WriteService", len(s.services)) 354 } 355 356 func (s *agentConfSuite) assertToolsCopySymlink(c *gc.C, series string) { 357 // Check tools changes 358 ver := version.Binary{ 359 Number: jujuversion.Current, 360 Arch: arch.HostArch(), 361 Series: series, 362 } 363 jujuTools, err := agenttools.ReadTools(s.dataDir, ver) 364 c.Assert(err, jc.ErrorIsNil) 365 c.Assert(jujuTools.Version, gc.DeepEquals, ver) 366 367 for _, name := range append(s.unitNames, s.machineName) { 368 link := path.Join(s.dataDir, "tools", name) 369 linkResult, err := os.Readlink(link) 370 c.Assert(err, jc.ErrorIsNil) 371 c.Assert(linkResult, gc.Equals, path.Join(s.dataDir, "tools", ver.String())) 372 } 373 } 374 375 func (s *agentConfSuite) assertServiceSymLinks(c *gc.C) { 376 for _, name := range append(s.unitNames, s.machineName) { 377 svcName := "jujud-" + name 378 svcFileName := svcName + ".service" 379 result, err := os.Readlink(path.Join(s.systemdDir, svcFileName)) 380 c.Assert(err, jc.ErrorIsNil) 381 c.Assert(result, gc.Equals, path.Join(systemd.LibSystemdDir, svcName, svcFileName)) 382 } 383 } 384 385 func (s *agentConfSuite) assertServicesCalls(c *gc.C, svc string, expectedCnt int) { 386 // Call list shared by the services 387 calls := s.services[0].Calls() 388 serviceCount := 0 389 for _, call := range calls { 390 if call.FuncName == svc { 391 serviceCount += 1 392 } 393 } 394 c.Assert(serviceCount, gc.Equals, expectedCnt) 395 }