github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/service/systemd/service_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package systemd_test 5 6 import ( 7 "bytes" 8 "fmt" 9 "os" 10 "strings" 11 12 "github.com/coreos/go-systemd/unit" 13 "github.com/juju/errors" 14 "github.com/juju/names" 15 "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/utils/exec" 18 "github.com/juju/utils/shell" 19 gc "gopkg.in/check.v1" 20 21 "github.com/juju/juju/juju/paths" 22 "github.com/juju/juju/service" 23 "github.com/juju/juju/service/common" 24 "github.com/juju/juju/service/systemd" 25 systemdtesting "github.com/juju/juju/service/systemd/testing" 26 coretesting "github.com/juju/juju/testing" 27 ) 28 29 var renderer = &shell.BashRenderer{} 30 31 const confStr = ` 32 [Unit] 33 Description=juju agent for %s 34 After=syslog.target 35 After=network.target 36 After=systemd-user-sessions.service 37 38 [Service] 39 ExecStart=%s 40 Restart=on-failure 41 42 [Install] 43 WantedBy=multi-user.target 44 45 ` 46 47 const jujud = "/var/lib/juju/bin/jujud" 48 49 var listCmdArg = exec.RunParams{ 50 Commands: `/bin/systemctl list-unit-files --no-legend --no-page -t service | grep -o -P '^\w[\S]*(?=\.service)'`, 51 } 52 53 type initSystemSuite struct { 54 coretesting.BaseSuite 55 56 dataDir string 57 ch chan string 58 stub *testing.Stub 59 conn *systemd.StubDbusAPI 60 fops *systemd.StubFileOps 61 exec *systemd.StubExec 62 63 name string 64 tag names.Tag 65 conf common.Conf 66 confStr string 67 service *systemd.Service 68 } 69 70 var _ = gc.Suite(&initSystemSuite{}) 71 72 func (s *initSystemSuite) SetUpTest(c *gc.C) { 73 s.BaseSuite.SetUpTest(c) 74 75 dataDir, err := paths.DataDir("vivid") 76 c.Assert(err, jc.ErrorIsNil) 77 s.dataDir = dataDir 78 // Patch things out. 79 s.ch = systemd.PatchNewChan(s) 80 81 s.stub = &testing.Stub{} 82 s.conn = systemd.PatchNewConn(s, s.stub) 83 s.fops = systemd.PatchFileOps(s, s.stub) 84 s.exec = systemd.PatchExec(s, s.stub) 85 86 // Set up the service. 87 tagStr := "machine-0" 88 tag, err := names.ParseTag(tagStr) 89 c.Assert(err, jc.ErrorIsNil) 90 s.tag = tag 91 s.name = "jujud-" + tagStr 92 s.conf = common.Conf{ 93 Desc: "juju agent for " + tagStr, 94 ExecStart: jujud + " " + tagStr, 95 } 96 s.service = s.newService(c) 97 98 // Reset any incidental calls. 99 s.stub.ResetCalls() 100 } 101 102 func (s *initSystemSuite) newService(c *gc.C) *systemd.Service { 103 service, err := systemd.NewService(s.name, s.conf, s.dataDir) 104 c.Assert(err, jc.ErrorIsNil) 105 return service 106 } 107 108 func (s *initSystemSuite) newConfStr(name string) string { 109 return s.newConfStrCmd(name, "") 110 } 111 112 func (s *initSystemSuite) newConfStrCmd(name, cmd string) string { 113 tag := name[len("jujud-"):] 114 if cmd == "" { 115 cmd = jujud + " " + tag 116 } 117 return fmt.Sprintf(confStr[1:], tag, cmd) 118 } 119 120 func (s *initSystemSuite) newConfStrEnv(name, env string) string { 121 const replace = "[Service]\n" 122 result := s.newConfStr(name) 123 result = strings.Replace( 124 result, replace, 125 fmt.Sprintf("%sEnvironment=%s\n", replace, env), 126 1, 127 ) 128 return result 129 } 130 131 func (s *initSystemSuite) addService(name, status string) { 132 tag := name[len("jujud-"):] 133 desc := "juju agent for " + tag 134 s.conn.AddService(name, desc, status) 135 } 136 137 func (s *initSystemSuite) addListResponse() { 138 var lines []string 139 for _, unit := range s.conn.Units { 140 lines = append(lines, strings.TrimSuffix(unit.Name, ".service")) 141 } 142 143 s.exec.Responses = append(s.exec.Responses, exec.ExecResponse{ 144 Code: 0, 145 Stdout: []byte(strings.Join(lines, "\n")), 146 Stderr: nil, 147 }) 148 } 149 150 func (s *initSystemSuite) setConf(c *gc.C, conf common.Conf) { 151 data, err := systemd.Serialize(s.name, conf, renderer) 152 c.Assert(err, jc.ErrorIsNil) 153 s.exec.Responses = append(s.exec.Responses, exec.ExecResponse{ 154 Code: 0, 155 Stdout: data, 156 Stderr: nil, 157 }) 158 } 159 160 func (s *initSystemSuite) checkCreateFileCall(c *gc.C, index int, filename, content string, perm os.FileMode) { 161 if content == "" { 162 name := filename 163 filename = fmt.Sprintf("%s/init/%s/%s.service", s.dataDir, name, name) 164 content = s.newConfStr(name) 165 } 166 167 call := s.stub.Calls()[index] 168 if !c.Check(call.FuncName, gc.Equals, "CreateFile") { 169 return 170 } 171 if !c.Check(call.Args, gc.HasLen, 3) { 172 return 173 } 174 175 callFilename, callData, callPerm := call.Args[0], call.Args[1], call.Args[2] 176 c.Check(callFilename, gc.Equals, filename) 177 178 // Some tests don't generate valid ini files, instead including placeholder 179 // strings (e.g. "a\nb\nc\n"). To avoid parsing errors, we only try and 180 // parse actual and expected file content if they don't exactly match. 181 if content != string(callData.([]byte)) { 182 // Parse the ini configurations and compare those. 183 expected, err := unit.Deserialize(bytes.NewReader(callData.([]byte))) 184 c.Assert(err, jc.ErrorIsNil) 185 cfg, err := unit.Deserialize(strings.NewReader(content)) 186 c.Assert(err, jc.ErrorIsNil) 187 c.Check(cfg, jc.SameContents, expected) 188 } 189 190 c.Check(callPerm, gc.Equals, perm) 191 } 192 193 func (s *initSystemSuite) TestListServices(c *gc.C) { 194 s.addService("jujud-machine-0", "active") 195 s.addService("something-else", "error") 196 s.addService("jujud-unit-wordpress-0", "active") 197 s.addService("another", "inactive") 198 s.addListResponse() 199 200 names, err := systemd.ListServices() 201 c.Assert(err, jc.ErrorIsNil) 202 203 c.Check(names, jc.SameContents, []string{ 204 "jujud-machine-0", 205 "something-else", 206 "jujud-unit-wordpress-0", 207 "another", 208 }) 209 s.stub.CheckCallNames(c, "RunCommand") 210 } 211 212 func (s *initSystemSuite) TestListServicesEmpty(c *gc.C) { 213 s.addListResponse() 214 215 names, err := systemd.ListServices() 216 c.Assert(err, jc.ErrorIsNil) 217 218 c.Check(names, gc.HasLen, 0) 219 s.stub.CheckCallNames(c, "RunCommand") 220 } 221 222 func (s *initSystemSuite) TestNewService(c *gc.C) { 223 service := s.newService(c) 224 c.Check(service, jc.DeepEquals, &systemd.Service{ 225 Service: common.Service{ 226 Name: s.name, 227 Conf: s.conf, 228 }, 229 ConfName: s.name + ".service", 230 UnitName: s.name + ".service", 231 Dirname: fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 232 }) 233 s.stub.CheckCalls(c, nil) 234 } 235 236 func (s *initSystemSuite) TestNewServiceLogfile(c *gc.C) { 237 s.conf.Logfile = "/var/log/juju/machine-0.log" 238 service := s.newService(c) 239 240 user, group := systemd.SyslogUserGroup() 241 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 242 script := ` 243 #!/usr/bin/env bash 244 245 # Set up logging. 246 touch '/var/log/juju/machine-0.log' 247 chown `[1:] + user + `:` + group + ` '/var/log/juju/machine-0.log' 248 chmod 0600 '/var/log/juju/machine-0.log' 249 exec >> '/var/log/juju/machine-0.log' 250 exec 2>&1 251 252 # Run the script. 253 ` + jujud + " machine-0" 254 c.Check(service, jc.DeepEquals, &systemd.Service{ 255 Service: common.Service{ 256 Name: s.name, 257 Conf: common.Conf{ 258 Desc: s.conf.Desc, 259 ExecStart: dirname + "/exec-start.sh", 260 Logfile: "/var/log/juju/machine-0.log", 261 }, 262 }, 263 UnitName: s.name + ".service", 264 ConfName: s.name + ".service", 265 Dirname: dirname, 266 Script: []byte(script), 267 }) 268 // This gives us a more readable output if they aren't equal. 269 c.Check(string(service.Script), gc.Equals, script) 270 c.Check(strings.Split(string(service.Script), "\n"), jc.DeepEquals, strings.Split(script, "\n")) 271 } 272 273 func (s *initSystemSuite) TestNewServiceEmptyConf(c *gc.C) { 274 service, err := systemd.NewService(s.name, common.Conf{}, s.dataDir) 275 c.Assert(err, jc.ErrorIsNil) 276 277 c.Check(service, jc.DeepEquals, &systemd.Service{ 278 Service: common.Service{ 279 Name: s.name, 280 }, 281 ConfName: s.name + ".service", 282 UnitName: s.name + ".service", 283 Dirname: fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 284 }) 285 s.stub.CheckCalls(c, nil) 286 } 287 288 func (s *initSystemSuite) TestNewServiceBasic(c *gc.C) { 289 s.conf.ExecStart = "/path/to/some/other/command" 290 svc := s.newService(c) 291 292 c.Check(svc, jc.DeepEquals, &systemd.Service{ 293 Service: common.Service{ 294 Name: s.name, 295 Conf: s.conf, 296 }, 297 ConfName: s.name + ".service", 298 UnitName: s.name + ".service", 299 Dirname: fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 300 }) 301 s.stub.CheckCalls(c, nil) 302 } 303 304 func (s *initSystemSuite) TestNewServiceExtraScript(c *gc.C) { 305 s.conf.ExtraScript = "'/path/to/another/command'" 306 svc := s.newService(c) 307 308 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 309 script := ` 310 #!/usr/bin/env bash 311 312 '/path/to/another/command' 313 `[1:] + jujud + " machine-0" 314 c.Check(svc, jc.DeepEquals, &systemd.Service{ 315 Service: common.Service{ 316 Name: s.name, 317 Conf: common.Conf{ 318 Desc: s.conf.Desc, 319 ExecStart: dirname + "/exec-start.sh", 320 }, 321 }, 322 UnitName: s.name + ".service", 323 ConfName: s.name + ".service", 324 Dirname: dirname, 325 Script: []byte(script), 326 }) 327 // This gives us a more readable output if they aren't equal. 328 c.Check(string(svc.Script), gc.Equals, script) 329 s.stub.CheckCalls(c, nil) 330 } 331 332 func (s *initSystemSuite) TestNewServiceMultiline(c *gc.C) { 333 s.conf.ExecStart = "a\nb\nc" 334 svc := s.newService(c) 335 336 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 337 script := ` 338 #!/usr/bin/env bash 339 340 a 341 b 342 c`[1:] 343 c.Check(svc, jc.DeepEquals, &systemd.Service{ 344 Service: common.Service{ 345 Name: s.name, 346 Conf: common.Conf{ 347 Desc: s.conf.Desc, 348 ExecStart: dirname + "/exec-start.sh", 349 }, 350 }, 351 UnitName: s.name + ".service", 352 ConfName: s.name + ".service", 353 Dirname: dirname, 354 Script: []byte(script), 355 }) 356 // This gives us a more readable output if they aren't equal. 357 c.Check(string(svc.Script), gc.Equals, script) 358 s.stub.CheckCalls(c, nil) 359 } 360 361 func (s *initSystemSuite) TestInstalledTrue(c *gc.C) { 362 s.addService("jujud-machine-0", "active") 363 s.addService("something-else", "error") 364 s.addService("juju-mongod", "active") 365 s.addListResponse() 366 367 installed, err := s.service.Installed() 368 c.Assert(err, jc.ErrorIsNil) 369 370 c.Check(installed, jc.IsTrue) 371 s.stub.CheckCallNames(c, "RunCommand") 372 } 373 374 func (s *initSystemSuite) TestInstalledFalse(c *gc.C) { 375 s.addService("something-else", "error") 376 s.addListResponse() 377 378 installed, err := s.service.Installed() 379 c.Assert(err, jc.ErrorIsNil) 380 381 c.Check(installed, jc.IsFalse) 382 s.stub.CheckCallNames(c, "RunCommand") 383 } 384 385 func (s *initSystemSuite) TestInstalledError(c *gc.C) { 386 s.addService("jujud-machine-0", "active") 387 s.addService("something-else", "error") 388 s.addService("juju-mongod", "active") 389 s.addListResponse() 390 failure := errors.New("<failed>") 391 s.stub.SetErrors(failure) 392 393 installed, err := s.service.Installed() 394 c.Assert(errors.Cause(err), gc.Equals, failure) 395 396 c.Check(installed, jc.IsFalse) 397 s.stub.CheckCallNames(c, "RunCommand") 398 } 399 400 func (s *initSystemSuite) TestExistsTrue(c *gc.C) { 401 s.setConf(c, s.conf) 402 403 exists, err := s.service.Exists() 404 c.Assert(err, jc.ErrorIsNil) 405 406 c.Check(exists, jc.IsTrue) 407 s.stub.CheckCallNames(c, "RunCommand") 408 } 409 410 func (s *initSystemSuite) TestExistsFalse(c *gc.C) { 411 // We force the systemd API to return a slightly different conf. 412 // In this case we simply set Conf.Env, which s.conf does not set. 413 // This causes Service.Exists to return false. 414 s.setConf(c, common.Conf{ 415 Desc: s.conf.Desc, 416 ExecStart: s.conf.ExecStart, 417 Env: map[string]string{"a": "b"}, 418 }) 419 420 exists, err := s.service.Exists() 421 c.Assert(err, jc.ErrorIsNil) 422 423 c.Check(exists, jc.IsFalse) 424 s.stub.CheckCallNames(c, "RunCommand") 425 } 426 427 func (s *initSystemSuite) TestExistsError(c *gc.C) { 428 failure := errors.New("<failed>") 429 s.stub.SetErrors(failure) 430 431 exists, err := s.service.Exists() 432 c.Assert(errors.Cause(err), gc.Equals, failure) 433 434 c.Check(exists, jc.IsFalse) 435 s.stub.CheckCallNames(c, "RunCommand") 436 } 437 438 func (s *initSystemSuite) TestExistsEmptyConf(c *gc.C) { 439 s.service.Service.Conf = common.Conf{} 440 441 _, err := s.service.Exists() 442 443 c.Check(err, gc.ErrorMatches, `.*no conf expected.*`) 444 s.stub.CheckCalls(c, nil) 445 } 446 447 func (s *initSystemSuite) TestRunningTrue(c *gc.C) { 448 s.addService("jujud-machine-0", "active") 449 s.addService("something-else", "error") 450 s.addService("juju-mongod", "active") 451 452 running, err := s.service.Running() 453 c.Assert(err, jc.ErrorIsNil) 454 455 c.Check(running, jc.IsTrue) 456 s.stub.CheckCallNames(c, "ListUnits", "Close") 457 } 458 459 func (s *initSystemSuite) TestRunningFalse(c *gc.C) { 460 s.addService("jujud-machine-0", "inactive") 461 s.addService("something-else", "error") 462 s.addService("juju-mongod", "active") 463 464 running, err := s.service.Running() 465 c.Assert(err, jc.ErrorIsNil) 466 467 c.Check(running, jc.IsFalse) 468 s.stub.CheckCallNames(c, "ListUnits", "Close") 469 } 470 471 func (s *initSystemSuite) TestRunningNotEnabled(c *gc.C) { 472 s.addService("something-else", "active") 473 474 running, err := s.service.Running() 475 c.Assert(err, jc.ErrorIsNil) 476 477 c.Check(running, jc.IsFalse) 478 s.stub.CheckCallNames(c, "ListUnits", "Close") 479 } 480 481 func (s *initSystemSuite) TestRunningError(c *gc.C) { 482 s.addService("jujud-machine-0", "active") 483 s.addService("something-else", "error") 484 s.addService("juju-mongod", "active") 485 failure := errors.New("<failed>") 486 s.stub.SetErrors(failure) 487 488 running, err := s.service.Running() 489 c.Assert(errors.Cause(err), gc.Equals, failure) 490 491 c.Check(running, jc.IsFalse) 492 s.stub.CheckCallNames(c, "ListUnits", "Close") 493 } 494 495 func (s *initSystemSuite) TestStart(c *gc.C) { 496 s.addService("jujud-machine-0", "inactive") 497 s.ch <- "done" 498 s.addListResponse() 499 500 err := s.service.Start() 501 c.Assert(err, jc.ErrorIsNil) 502 503 s.stub.CheckCalls(c, []testing.StubCall{{ 504 FuncName: "RunCommand", 505 Args: []interface{}{ 506 listCmdArg, 507 }, 508 }, { 509 FuncName: "ListUnits", 510 }, { 511 FuncName: "Close", 512 }, { 513 FuncName: "StartUnit", 514 Args: []interface{}{ 515 s.name + ".service", 516 "fail", 517 (chan<- string)(s.ch), 518 }, 519 }, { 520 FuncName: "Close", 521 }}) 522 } 523 524 func (s *initSystemSuite) TestStartAlreadyRunning(c *gc.C) { 525 s.addService("jujud-machine-0", "active") 526 s.ch <- "done" // just in case 527 s.addListResponse() 528 529 err := s.service.Start() 530 c.Assert(err, jc.ErrorIsNil) 531 532 s.stub.CheckCallNames(c, 533 "RunCommand", 534 "ListUnits", 535 "Close", 536 ) 537 } 538 539 func (s *initSystemSuite) TestStartNotInstalled(c *gc.C) { 540 s.ch <- "done" // just in case 541 542 err := s.service.Start() 543 544 c.Check(err, jc.Satisfies, errors.IsNotFound) 545 s.stub.CheckCallNames(c, "RunCommand") 546 } 547 548 func (s *initSystemSuite) TestStop(c *gc.C) { 549 s.addService("jujud-machine-0", "active") 550 s.ch <- "done" 551 552 err := s.service.Stop() 553 c.Assert(err, jc.ErrorIsNil) 554 555 s.stub.CheckCalls(c, []testing.StubCall{{ 556 FuncName: "ListUnits", 557 }, { 558 FuncName: "Close", 559 }, { 560 FuncName: "StopUnit", 561 Args: []interface{}{ 562 s.name + ".service", 563 "fail", 564 (chan<- string)(s.ch), 565 }, 566 }, { 567 FuncName: "Close", 568 }}) 569 } 570 571 func (s *initSystemSuite) TestStopNotRunning(c *gc.C) { 572 s.addService("jujud-machine-0", "inactive") 573 s.ch <- "done" // just in case 574 575 err := s.service.Stop() 576 c.Assert(err, jc.ErrorIsNil) 577 578 s.stub.CheckCallNames(c, "ListUnits", "Close") 579 } 580 581 func (s *initSystemSuite) TestStopNotInstalled(c *gc.C) { 582 s.ch <- "done" // just in case 583 584 err := s.service.Stop() 585 c.Assert(err, jc.ErrorIsNil) 586 587 s.stub.CheckCallNames(c, "ListUnits", "Close") 588 } 589 590 func (s *initSystemSuite) TestRemove(c *gc.C) { 591 s.addService("jujud-machine-0", "inactive") 592 s.addListResponse() 593 594 err := s.service.Remove() 595 c.Assert(err, jc.ErrorIsNil) 596 597 s.stub.CheckCalls(c, []testing.StubCall{{ 598 FuncName: "RunCommand", 599 Args: []interface{}{ 600 listCmdArg, 601 }, 602 }, { 603 FuncName: "DisableUnitFiles", 604 Args: []interface{}{ 605 []string{s.name + ".service"}, 606 false, 607 }, 608 }, { 609 FuncName: "Reload", 610 }, { 611 FuncName: "RemoveAll", 612 Args: []interface{}{ 613 fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 614 }, 615 }, { 616 FuncName: "Close", 617 }}) 618 } 619 620 func (s *initSystemSuite) TestRemoveNotInstalled(c *gc.C) { 621 err := s.service.Remove() 622 c.Assert(err, jc.ErrorIsNil) 623 624 s.stub.CheckCallNames(c, "RunCommand") 625 } 626 627 func (s *initSystemSuite) TestInstall(c *gc.C) { 628 err := s.service.Install() 629 c.Assert(err, jc.ErrorIsNil) 630 631 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 632 filename := fmt.Sprintf("%s/%s.service", dirname, s.name) 633 createFileOutput := s.stub.Calls()[2].Args[1] // gross 634 s.stub.CheckCalls(c, []testing.StubCall{{ 635 FuncName: "RunCommand", 636 Args: []interface{}{ 637 listCmdArg, 638 }, 639 }, { 640 FuncName: "MkdirAll", 641 Args: []interface{}{ 642 dirname, 643 }, 644 }, { 645 FuncName: "CreateFile", 646 Args: []interface{}{ 647 filename, 648 // The contents of the file will always pass this test. We are 649 // testing the sequence of commands. The output of CreateFile 650 // is tested by tests that call checkCreateFileCall. 651 createFileOutput, 652 os.FileMode(0644), 653 }, 654 }, { 655 FuncName: "LinkUnitFiles", 656 Args: []interface{}{ 657 []string{filename}, 658 false, 659 true, 660 }, 661 }, { 662 FuncName: "Reload", 663 }, { 664 FuncName: "EnableUnitFiles", 665 Args: []interface{}{ 666 []string{filename}, 667 false, 668 true, 669 }, 670 }, { 671 FuncName: "Close", 672 }}) 673 s.checkCreateFileCall(c, 2, filename, s.newConfStr(s.name), 0644) 674 } 675 676 func (s *initSystemSuite) TestInstallAlreadyInstalled(c *gc.C) { 677 s.addService("jujud-machine-0", "inactive") 678 s.addListResponse() 679 s.setConf(c, s.conf) 680 681 err := s.service.Install() 682 c.Assert(err, jc.ErrorIsNil) 683 684 s.stub.CheckCallNames(c, 685 "RunCommand", 686 "RunCommand", 687 ) 688 } 689 690 func (s *initSystemSuite) TestInstallZombie(c *gc.C) { 691 s.addService("jujud-machine-0", "active") 692 s.addListResponse() 693 // We force the systemd API to return a slightly different conf. 694 // In this case we simply set a different Env value between the 695 // conf we are installing and the conf returned by the systemd API. 696 // This causes Service.Exists to return false. 697 conf := common.Conf{ 698 Desc: s.conf.Desc, 699 ExecStart: s.conf.ExecStart, 700 Env: map[string]string{"a": "b"}, 701 } 702 s.setConf(c, conf) 703 s.addListResponse() 704 s.ch <- "done" 705 706 conf.Env["a"] = "c" 707 service, err := systemd.NewService(s.name, conf, s.dataDir) 708 c.Assert(err, jc.ErrorIsNil) 709 err = service.Install() 710 c.Assert(err, jc.ErrorIsNil) 711 712 s.stub.CheckCallNames(c, 713 "RunCommand", 714 "RunCommand", 715 "ListUnits", 716 "Close", 717 "StopUnit", 718 "Close", 719 "RunCommand", 720 "DisableUnitFiles", 721 "Reload", 722 "RemoveAll", 723 "Close", 724 "MkdirAll", 725 "CreateFile", 726 "LinkUnitFiles", 727 "Reload", 728 "EnableUnitFiles", 729 "Close", 730 ) 731 filename := fmt.Sprintf("%s/init/%s/%s.service", s.dataDir, s.name, s.name) 732 content := s.newConfStrEnv(s.name, `"a=c"`) 733 s.checkCreateFileCall(c, 12, filename, content, 0644) 734 } 735 736 func (s *initSystemSuite) TestInstallMultiline(c *gc.C) { 737 scriptPath := fmt.Sprintf("%s/init/%s/exec-start.sh", s.dataDir, s.name) 738 cmd := "a\nb\nc" 739 s.service.Service.Conf.ExecStart = scriptPath 740 s.service.Script = []byte(cmd) 741 742 err := s.service.Install() 743 c.Assert(err, jc.ErrorIsNil) 744 745 s.stub.CheckCallNames(c, 746 "RunCommand", 747 "MkdirAll", 748 "CreateFile", 749 "CreateFile", 750 "LinkUnitFiles", 751 "Reload", 752 "EnableUnitFiles", 753 "Close", 754 ) 755 s.checkCreateFileCall(c, 2, scriptPath, cmd, 0755) 756 filename := fmt.Sprintf("%s/init/%s/%s.service", s.dataDir, s.name, s.name) 757 content := s.newConfStrCmd(s.name, scriptPath) 758 s.checkCreateFileCall(c, 3, filename, content, 0644) 759 } 760 761 func (s *initSystemSuite) TestInstallEmptyConf(c *gc.C) { 762 s.service.Service.Conf = common.Conf{} 763 764 err := s.service.Install() 765 766 c.Check(err, gc.ErrorMatches, `.*missing conf.*`) 767 s.stub.CheckCalls(c, nil) 768 } 769 770 func (s *initSystemSuite) TestInstallCommands(c *gc.C) { 771 name := "jujud-machine-0" 772 commands, err := s.service.InstallCommands() 773 c.Assert(err, jc.ErrorIsNil) 774 775 test := systemdtesting.WriteConfTest{ 776 Service: name, 777 DataDir: s.dataDir, 778 Expected: s.newConfStr(name), 779 } 780 test.CheckCommands(c, commands) 781 } 782 783 func (s *initSystemSuite) TestInstallCommandsLogfile(c *gc.C) { 784 name := "jujud-machine-0" 785 s.conf.Logfile = "/var/log/juju/machine-0.log" 786 service := s.newService(c) 787 commands, err := service.InstallCommands() 788 c.Assert(err, jc.ErrorIsNil) 789 790 user, group := systemd.SyslogUserGroup() 791 test := systemdtesting.WriteConfTest{ 792 Service: name, 793 DataDir: s.dataDir, 794 Expected: strings.Replace( 795 s.newConfStr(name), 796 "ExecStart=/var/lib/juju/bin/jujud machine-0", 797 "ExecStart=/var/lib/juju/init/jujud-machine-0/exec-start.sh", 798 -1), 799 Script: ` 800 # Set up logging. 801 touch '/var/log/juju/machine-0.log' 802 chown `[1:] + user + `:` + group + ` '/var/log/juju/machine-0.log' 803 chmod 0600 '/var/log/juju/machine-0.log' 804 exec >> '/var/log/juju/machine-0.log' 805 exec 2>&1 806 807 # Run the script. 808 ` + jujud + " machine-0", 809 } 810 test.CheckCommands(c, commands) 811 } 812 813 func (s *initSystemSuite) TestInstallCommandsShutdown(c *gc.C) { 814 name := "juju-shutdown-job" 815 conf, err := service.ShutdownAfterConf("cloud-final") 816 c.Assert(err, jc.ErrorIsNil) 817 svc, err := systemd.NewService(name, conf, s.dataDir) 818 c.Assert(err, jc.ErrorIsNil) 819 commands, err := svc.InstallCommands() 820 c.Assert(err, jc.ErrorIsNil) 821 822 test := systemdtesting.WriteConfTest{ 823 Service: name, 824 DataDir: s.dataDir, 825 Expected: ` 826 [Unit] 827 Description=juju shutdown job 828 After=syslog.target 829 After=network.target 830 After=systemd-user-sessions.service 831 After=cloud-final 832 833 [Service] 834 ExecStart=/sbin/shutdown -h now 835 ExecStopPost=/bin/systemctl disable juju-shutdown-job.service 836 837 [Install] 838 WantedBy=multi-user.target 839 `[1:], 840 } 841 test.CheckCommands(c, commands) 842 } 843 844 func (s *initSystemSuite) TestInstallCommandsEmptyConf(c *gc.C) { 845 s.service.Service.Conf = common.Conf{} 846 847 _, err := s.service.InstallCommands() 848 849 c.Check(err, gc.ErrorMatches, `.*missing conf.*`) 850 s.stub.CheckCalls(c, nil) 851 } 852 853 func (s *initSystemSuite) TestStartCommands(c *gc.C) { 854 commands, err := s.service.StartCommands() 855 c.Assert(err, jc.ErrorIsNil) 856 857 c.Check(commands, jc.DeepEquals, []string{ 858 "/bin/systemctl start jujud-machine-0.service", 859 }) 860 }