github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 241 script := ` 242 #!/usr/bin/env bash 243 244 # Set up logging. 245 touch '/var/log/juju/machine-0.log' 246 chown syslog:syslog '/var/log/juju/machine-0.log' 247 chmod 0600 '/var/log/juju/machine-0.log' 248 exec >> '/var/log/juju/machine-0.log' 249 exec 2>&1 250 251 # Run the script. 252 `[1:] + jujud + " machine-0" 253 c.Check(service, jc.DeepEquals, &systemd.Service{ 254 Service: common.Service{ 255 Name: s.name, 256 Conf: common.Conf{ 257 Desc: s.conf.Desc, 258 ExecStart: dirname + "/exec-start.sh", 259 Logfile: "/var/log/juju/machine-0.log", 260 }, 261 }, 262 UnitName: s.name + ".service", 263 ConfName: s.name + ".service", 264 Dirname: dirname, 265 Script: []byte(script), 266 }) 267 // This gives us a more readable output if they aren't equal. 268 c.Check(string(service.Script), gc.Equals, script) 269 c.Check(strings.Split(string(service.Script), "\n"), jc.DeepEquals, strings.Split(script, "\n")) 270 } 271 272 func (s *initSystemSuite) TestNewServiceEmptyConf(c *gc.C) { 273 service, err := systemd.NewService(s.name, common.Conf{}, s.dataDir) 274 c.Assert(err, jc.ErrorIsNil) 275 276 c.Check(service, jc.DeepEquals, &systemd.Service{ 277 Service: common.Service{ 278 Name: s.name, 279 }, 280 ConfName: s.name + ".service", 281 UnitName: s.name + ".service", 282 Dirname: fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 283 }) 284 s.stub.CheckCalls(c, nil) 285 } 286 287 func (s *initSystemSuite) TestNewServiceBasic(c *gc.C) { 288 s.conf.ExecStart = "/path/to/some/other/command" 289 svc := s.newService(c) 290 291 c.Check(svc, jc.DeepEquals, &systemd.Service{ 292 Service: common.Service{ 293 Name: s.name, 294 Conf: s.conf, 295 }, 296 ConfName: s.name + ".service", 297 UnitName: s.name + ".service", 298 Dirname: fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 299 }) 300 s.stub.CheckCalls(c, nil) 301 } 302 303 func (s *initSystemSuite) TestNewServiceExtraScript(c *gc.C) { 304 s.conf.ExtraScript = "'/path/to/another/command'" 305 svc := s.newService(c) 306 307 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 308 script := ` 309 #!/usr/bin/env bash 310 311 '/path/to/another/command' 312 `[1:] + jujud + " machine-0" 313 c.Check(svc, jc.DeepEquals, &systemd.Service{ 314 Service: common.Service{ 315 Name: s.name, 316 Conf: common.Conf{ 317 Desc: s.conf.Desc, 318 ExecStart: dirname + "/exec-start.sh", 319 }, 320 }, 321 UnitName: s.name + ".service", 322 ConfName: s.name + ".service", 323 Dirname: dirname, 324 Script: []byte(script), 325 }) 326 // This gives us a more readable output if they aren't equal. 327 c.Check(string(svc.Script), gc.Equals, script) 328 s.stub.CheckCalls(c, nil) 329 } 330 331 func (s *initSystemSuite) TestNewServiceMultiline(c *gc.C) { 332 s.conf.ExecStart = "a\nb\nc" 333 svc := s.newService(c) 334 335 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 336 script := ` 337 #!/usr/bin/env bash 338 339 a 340 b 341 c`[1:] 342 c.Check(svc, jc.DeepEquals, &systemd.Service{ 343 Service: common.Service{ 344 Name: s.name, 345 Conf: common.Conf{ 346 Desc: s.conf.Desc, 347 ExecStart: dirname + "/exec-start.sh", 348 }, 349 }, 350 UnitName: s.name + ".service", 351 ConfName: s.name + ".service", 352 Dirname: dirname, 353 Script: []byte(script), 354 }) 355 // This gives us a more readable output if they aren't equal. 356 c.Check(string(svc.Script), gc.Equals, script) 357 s.stub.CheckCalls(c, nil) 358 } 359 360 func (s *initSystemSuite) TestInstalledTrue(c *gc.C) { 361 s.addService("jujud-machine-0", "active") 362 s.addService("something-else", "error") 363 s.addService("juju-mongod", "active") 364 s.addListResponse() 365 366 installed, err := s.service.Installed() 367 c.Assert(err, jc.ErrorIsNil) 368 369 c.Check(installed, jc.IsTrue) 370 s.stub.CheckCallNames(c, "RunCommand") 371 } 372 373 func (s *initSystemSuite) TestInstalledFalse(c *gc.C) { 374 s.addService("something-else", "error") 375 s.addListResponse() 376 377 installed, err := s.service.Installed() 378 c.Assert(err, jc.ErrorIsNil) 379 380 c.Check(installed, jc.IsFalse) 381 s.stub.CheckCallNames(c, "RunCommand") 382 } 383 384 func (s *initSystemSuite) TestInstalledError(c *gc.C) { 385 s.addService("jujud-machine-0", "active") 386 s.addService("something-else", "error") 387 s.addService("juju-mongod", "active") 388 s.addListResponse() 389 failure := errors.New("<failed>") 390 s.stub.SetErrors(failure) 391 392 installed, err := s.service.Installed() 393 c.Assert(errors.Cause(err), gc.Equals, failure) 394 395 c.Check(installed, jc.IsFalse) 396 s.stub.CheckCallNames(c, "RunCommand") 397 } 398 399 func (s *initSystemSuite) TestExistsTrue(c *gc.C) { 400 s.setConf(c, s.conf) 401 402 exists, err := s.service.Exists() 403 c.Assert(err, jc.ErrorIsNil) 404 405 c.Check(exists, jc.IsTrue) 406 s.stub.CheckCallNames(c, "RunCommand") 407 } 408 409 func (s *initSystemSuite) TestExistsFalse(c *gc.C) { 410 // We force the systemd API to return a slightly different conf. 411 // In this case we simply set Conf.Env, which s.conf does not set. 412 // This causes Service.Exists to return false. 413 s.setConf(c, common.Conf{ 414 Desc: s.conf.Desc, 415 ExecStart: s.conf.ExecStart, 416 Env: map[string]string{"a": "b"}, 417 }) 418 419 exists, err := s.service.Exists() 420 c.Assert(err, jc.ErrorIsNil) 421 422 c.Check(exists, jc.IsFalse) 423 s.stub.CheckCallNames(c, "RunCommand") 424 } 425 426 func (s *initSystemSuite) TestExistsError(c *gc.C) { 427 failure := errors.New("<failed>") 428 s.stub.SetErrors(failure) 429 430 exists, err := s.service.Exists() 431 c.Assert(errors.Cause(err), gc.Equals, failure) 432 433 c.Check(exists, jc.IsFalse) 434 s.stub.CheckCallNames(c, "RunCommand") 435 } 436 437 func (s *initSystemSuite) TestExistsEmptyConf(c *gc.C) { 438 s.service.Service.Conf = common.Conf{} 439 440 _, err := s.service.Exists() 441 442 c.Check(err, gc.ErrorMatches, `.*no conf expected.*`) 443 s.stub.CheckCalls(c, nil) 444 } 445 446 func (s *initSystemSuite) TestRunningTrue(c *gc.C) { 447 s.addService("jujud-machine-0", "active") 448 s.addService("something-else", "error") 449 s.addService("juju-mongod", "active") 450 451 running, err := s.service.Running() 452 c.Assert(err, jc.ErrorIsNil) 453 454 c.Check(running, jc.IsTrue) 455 s.stub.CheckCallNames(c, "ListUnits", "Close") 456 } 457 458 func (s *initSystemSuite) TestRunningFalse(c *gc.C) { 459 s.addService("jujud-machine-0", "inactive") 460 s.addService("something-else", "error") 461 s.addService("juju-mongod", "active") 462 463 running, err := s.service.Running() 464 c.Assert(err, jc.ErrorIsNil) 465 466 c.Check(running, jc.IsFalse) 467 s.stub.CheckCallNames(c, "ListUnits", "Close") 468 } 469 470 func (s *initSystemSuite) TestRunningNotEnabled(c *gc.C) { 471 s.addService("something-else", "active") 472 473 running, err := s.service.Running() 474 c.Assert(err, jc.ErrorIsNil) 475 476 c.Check(running, jc.IsFalse) 477 s.stub.CheckCallNames(c, "ListUnits", "Close") 478 } 479 480 func (s *initSystemSuite) TestRunningError(c *gc.C) { 481 s.addService("jujud-machine-0", "active") 482 s.addService("something-else", "error") 483 s.addService("juju-mongod", "active") 484 failure := errors.New("<failed>") 485 s.stub.SetErrors(failure) 486 487 running, err := s.service.Running() 488 c.Assert(errors.Cause(err), gc.Equals, failure) 489 490 c.Check(running, jc.IsFalse) 491 s.stub.CheckCallNames(c, "ListUnits", "Close") 492 } 493 494 func (s *initSystemSuite) TestStart(c *gc.C) { 495 s.addService("jujud-machine-0", "inactive") 496 s.ch <- "done" 497 s.addListResponse() 498 499 err := s.service.Start() 500 c.Assert(err, jc.ErrorIsNil) 501 502 s.stub.CheckCalls(c, []testing.StubCall{{ 503 FuncName: "RunCommand", 504 Args: []interface{}{ 505 listCmdArg, 506 }, 507 }, { 508 FuncName: "ListUnits", 509 }, { 510 FuncName: "Close", 511 }, { 512 FuncName: "StartUnit", 513 Args: []interface{}{ 514 s.name + ".service", 515 "fail", 516 (chan<- string)(s.ch), 517 }, 518 }, { 519 FuncName: "Close", 520 }}) 521 } 522 523 func (s *initSystemSuite) TestStartAlreadyRunning(c *gc.C) { 524 s.addService("jujud-machine-0", "active") 525 s.ch <- "done" // just in case 526 s.addListResponse() 527 528 err := s.service.Start() 529 c.Assert(err, jc.ErrorIsNil) 530 531 s.stub.CheckCallNames(c, 532 "RunCommand", 533 "ListUnits", 534 "Close", 535 ) 536 } 537 538 func (s *initSystemSuite) TestStartNotInstalled(c *gc.C) { 539 s.ch <- "done" // just in case 540 541 err := s.service.Start() 542 543 c.Check(err, jc.Satisfies, errors.IsNotFound) 544 s.stub.CheckCallNames(c, "RunCommand") 545 } 546 547 func (s *initSystemSuite) TestStop(c *gc.C) { 548 s.addService("jujud-machine-0", "active") 549 s.ch <- "done" 550 551 err := s.service.Stop() 552 c.Assert(err, jc.ErrorIsNil) 553 554 s.stub.CheckCalls(c, []testing.StubCall{{ 555 FuncName: "ListUnits", 556 }, { 557 FuncName: "Close", 558 }, { 559 FuncName: "StopUnit", 560 Args: []interface{}{ 561 s.name + ".service", 562 "fail", 563 (chan<- string)(s.ch), 564 }, 565 }, { 566 FuncName: "Close", 567 }}) 568 } 569 570 func (s *initSystemSuite) TestStopNotRunning(c *gc.C) { 571 s.addService("jujud-machine-0", "inactive") 572 s.ch <- "done" // just in case 573 574 err := s.service.Stop() 575 c.Assert(err, jc.ErrorIsNil) 576 577 s.stub.CheckCallNames(c, "ListUnits", "Close") 578 } 579 580 func (s *initSystemSuite) TestStopNotInstalled(c *gc.C) { 581 s.ch <- "done" // just in case 582 583 err := s.service.Stop() 584 c.Assert(err, jc.ErrorIsNil) 585 586 s.stub.CheckCallNames(c, "ListUnits", "Close") 587 } 588 589 func (s *initSystemSuite) TestRemove(c *gc.C) { 590 s.addService("jujud-machine-0", "inactive") 591 s.addListResponse() 592 593 err := s.service.Remove() 594 c.Assert(err, jc.ErrorIsNil) 595 596 s.stub.CheckCalls(c, []testing.StubCall{{ 597 FuncName: "RunCommand", 598 Args: []interface{}{ 599 listCmdArg, 600 }, 601 }, { 602 FuncName: "DisableUnitFiles", 603 Args: []interface{}{ 604 []string{s.name + ".service"}, 605 false, 606 }, 607 }, { 608 FuncName: "Reload", 609 }, { 610 FuncName: "RemoveAll", 611 Args: []interface{}{ 612 fmt.Sprintf("%s/init/%s", s.dataDir, s.name), 613 }, 614 }, { 615 FuncName: "Close", 616 }}) 617 } 618 619 func (s *initSystemSuite) TestRemoveNotInstalled(c *gc.C) { 620 err := s.service.Remove() 621 c.Assert(err, jc.ErrorIsNil) 622 623 s.stub.CheckCallNames(c, "RunCommand") 624 } 625 626 func (s *initSystemSuite) TestInstall(c *gc.C) { 627 err := s.service.Install() 628 c.Assert(err, jc.ErrorIsNil) 629 630 dirname := fmt.Sprintf("%s/init/%s", s.dataDir, s.name) 631 filename := fmt.Sprintf("%s/%s.service", dirname, s.name) 632 createFileOutput := s.stub.Calls()[2].Args[1] // gross 633 s.stub.CheckCalls(c, []testing.StubCall{{ 634 FuncName: "RunCommand", 635 Args: []interface{}{ 636 listCmdArg, 637 }, 638 }, { 639 FuncName: "MkdirAll", 640 Args: []interface{}{ 641 dirname, 642 }, 643 }, { 644 FuncName: "CreateFile", 645 Args: []interface{}{ 646 filename, 647 // The contents of the file will always pass this test. We are 648 // testing the sequence of commands. The output of CreateFile 649 // is tested by tests that call checkCreateFileCall. 650 createFileOutput, 651 os.FileMode(0644), 652 }, 653 }, { 654 FuncName: "LinkUnitFiles", 655 Args: []interface{}{ 656 []string{filename}, 657 false, 658 true, 659 }, 660 }, { 661 FuncName: "Reload", 662 }, { 663 FuncName: "EnableUnitFiles", 664 Args: []interface{}{ 665 []string{filename}, 666 false, 667 true, 668 }, 669 }, { 670 FuncName: "Close", 671 }}) 672 s.checkCreateFileCall(c, 2, filename, s.newConfStr(s.name), 0644) 673 } 674 675 func (s *initSystemSuite) TestInstallAlreadyInstalled(c *gc.C) { 676 s.addService("jujud-machine-0", "inactive") 677 s.addListResponse() 678 s.setConf(c, s.conf) 679 680 err := s.service.Install() 681 c.Assert(err, jc.ErrorIsNil) 682 683 s.stub.CheckCallNames(c, 684 "RunCommand", 685 "RunCommand", 686 ) 687 } 688 689 func (s *initSystemSuite) TestInstallZombie(c *gc.C) { 690 s.addService("jujud-machine-0", "active") 691 s.addListResponse() 692 // We force the systemd API to return a slightly different conf. 693 // In this case we simply set a different Env value between the 694 // conf we are installing and the conf returned by the systemd API. 695 // This causes Service.Exists to return false. 696 conf := common.Conf{ 697 Desc: s.conf.Desc, 698 ExecStart: s.conf.ExecStart, 699 Env: map[string]string{"a": "b"}, 700 } 701 s.setConf(c, conf) 702 s.addListResponse() 703 s.ch <- "done" 704 705 conf.Env["a"] = "c" 706 service, err := systemd.NewService(s.name, conf, s.dataDir) 707 c.Assert(err, jc.ErrorIsNil) 708 err = service.Install() 709 c.Assert(err, jc.ErrorIsNil) 710 711 s.stub.CheckCallNames(c, 712 "RunCommand", 713 "RunCommand", 714 "ListUnits", 715 "Close", 716 "StopUnit", 717 "Close", 718 "RunCommand", 719 "DisableUnitFiles", 720 "Reload", 721 "RemoveAll", 722 "Close", 723 "MkdirAll", 724 "CreateFile", 725 "LinkUnitFiles", 726 "Reload", 727 "EnableUnitFiles", 728 "Close", 729 ) 730 filename := fmt.Sprintf("%s/init/%s/%s.service", s.dataDir, s.name, s.name) 731 content := s.newConfStrEnv(s.name, `"a=c"`) 732 s.checkCreateFileCall(c, 12, filename, content, 0644) 733 } 734 735 func (s *initSystemSuite) TestInstallMultiline(c *gc.C) { 736 scriptPath := fmt.Sprintf("%s/init/%s/exec-start.sh", s.dataDir, s.name) 737 cmd := "a\nb\nc" 738 s.service.Service.Conf.ExecStart = scriptPath 739 s.service.Script = []byte(cmd) 740 741 err := s.service.Install() 742 c.Assert(err, jc.ErrorIsNil) 743 744 s.stub.CheckCallNames(c, 745 "RunCommand", 746 "MkdirAll", 747 "CreateFile", 748 "CreateFile", 749 "LinkUnitFiles", 750 "Reload", 751 "EnableUnitFiles", 752 "Close", 753 ) 754 s.checkCreateFileCall(c, 2, scriptPath, cmd, 0755) 755 filename := fmt.Sprintf("%s/init/%s/%s.service", s.dataDir, s.name, s.name) 756 content := s.newConfStrCmd(s.name, scriptPath) 757 s.checkCreateFileCall(c, 3, filename, content, 0644) 758 } 759 760 func (s *initSystemSuite) TestInstallEmptyConf(c *gc.C) { 761 s.service.Service.Conf = common.Conf{} 762 763 err := s.service.Install() 764 765 c.Check(err, gc.ErrorMatches, `.*missing conf.*`) 766 s.stub.CheckCalls(c, nil) 767 } 768 769 func (s *initSystemSuite) TestInstallCommands(c *gc.C) { 770 name := "jujud-machine-0" 771 commands, err := s.service.InstallCommands() 772 c.Assert(err, jc.ErrorIsNil) 773 774 test := systemdtesting.WriteConfTest{ 775 Service: name, 776 DataDir: s.dataDir, 777 Expected: s.newConfStr(name), 778 } 779 test.CheckCommands(c, commands) 780 } 781 782 func (s *initSystemSuite) TestInstallCommandsLogfile(c *gc.C) { 783 name := "jujud-machine-0" 784 s.conf.Logfile = "/var/log/juju/machine-0.log" 785 service := s.newService(c) 786 commands, err := service.InstallCommands() 787 c.Assert(err, jc.ErrorIsNil) 788 789 test := systemdtesting.WriteConfTest{ 790 Service: name, 791 DataDir: s.dataDir, 792 Expected: strings.Replace( 793 s.newConfStr(name), 794 "ExecStart=/var/lib/juju/bin/jujud machine-0", 795 "ExecStart=/var/lib/juju/init/jujud-machine-0/exec-start.sh", 796 -1), 797 Script: ` 798 # Set up logging. 799 touch '/var/log/juju/machine-0.log' 800 chown syslog:syslog '/var/log/juju/machine-0.log' 801 chmod 0600 '/var/log/juju/machine-0.log' 802 exec >> '/var/log/juju/machine-0.log' 803 exec 2>&1 804 805 # Run the script. 806 `[1:] + jujud + " machine-0", 807 } 808 test.CheckCommands(c, commands) 809 } 810 811 func (s *initSystemSuite) TestInstallCommandsShutdown(c *gc.C) { 812 name := "juju-shutdown-job" 813 conf, err := service.ShutdownAfterConf("cloud-final") 814 c.Assert(err, jc.ErrorIsNil) 815 svc, err := systemd.NewService(name, conf, s.dataDir) 816 c.Assert(err, jc.ErrorIsNil) 817 commands, err := svc.InstallCommands() 818 c.Assert(err, jc.ErrorIsNil) 819 820 test := systemdtesting.WriteConfTest{ 821 Service: name, 822 DataDir: s.dataDir, 823 Expected: ` 824 [Unit] 825 Description=juju shutdown job 826 After=syslog.target 827 After=network.target 828 After=systemd-user-sessions.service 829 After=cloud-final 830 831 [Service] 832 ExecStart=/sbin/shutdown -h now 833 ExecStopPost=/bin/systemctl disable juju-shutdown-job.service 834 835 [Install] 836 WantedBy=multi-user.target 837 `[1:], 838 } 839 test.CheckCommands(c, commands) 840 } 841 842 func (s *initSystemSuite) TestInstallCommandsEmptyConf(c *gc.C) { 843 s.service.Service.Conf = common.Conf{} 844 845 _, err := s.service.InstallCommands() 846 847 c.Check(err, gc.ErrorMatches, `.*missing conf.*`) 848 s.stub.CheckCalls(c, nil) 849 } 850 851 func (s *initSystemSuite) TestStartCommands(c *gc.C) { 852 commands, err := s.service.StartCommands() 853 c.Assert(err, jc.ErrorIsNil) 854 855 c.Check(commands, jc.DeepEquals, []string{ 856 "/bin/systemctl start jujud-machine-0.service", 857 }) 858 }