github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/wrappers/services_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package wrappers_test 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "regexp" 28 "sort" 29 "strings" 30 "time" 31 32 . "gopkg.in/check.v1" 33 34 "github.com/snapcore/snapd/dirs" 35 "github.com/snapcore/snapd/logger" 36 "github.com/snapcore/snapd/osutil" 37 "github.com/snapcore/snapd/progress" 38 "github.com/snapcore/snapd/snap" 39 "github.com/snapcore/snapd/snap/snaptest" 40 "github.com/snapcore/snapd/strutil" 41 "github.com/snapcore/snapd/systemd" 42 "github.com/snapcore/snapd/testutil" 43 "github.com/snapcore/snapd/timings" 44 "github.com/snapcore/snapd/usersession/agent" 45 "github.com/snapcore/snapd/wrappers" 46 ) 47 48 type servicesTestSuite struct { 49 tempdir string 50 51 sysdLog [][]string 52 53 systemctlRestorer, delaysRestorer func() 54 55 perfTimings timings.Measurer 56 57 agent *agent.SessionAgent 58 } 59 60 var _ = Suite(&servicesTestSuite{}) 61 62 func (s *servicesTestSuite) SetUpTest(c *C) { 63 s.tempdir = c.MkDir() 64 s.sysdLog = nil 65 dirs.SetRootDir(s.tempdir) 66 67 s.systemctlRestorer = systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 68 s.sysdLog = append(s.sysdLog, cmd) 69 return []byte("ActiveState=inactive\n"), nil 70 }) 71 s.delaysRestorer = systemd.MockStopDelays(time.Millisecond, 25*time.Second) 72 s.perfTimings = timings.New(nil) 73 74 xdgRuntimeDir := fmt.Sprintf("%s/%d", dirs.XdgRuntimeDirBase, os.Getuid()) 75 err := os.MkdirAll(xdgRuntimeDir, 0700) 76 c.Assert(err, IsNil) 77 s.agent, err = agent.New() 78 c.Assert(err, IsNil) 79 s.agent.Start() 80 } 81 82 func (s *servicesTestSuite) TearDownTest(c *C) { 83 if s.agent != nil { 84 err := s.agent.Stop() 85 c.Check(err, IsNil) 86 } 87 s.systemctlRestorer() 88 s.delaysRestorer() 89 dirs.SetRootDir("") 90 } 91 92 func (s *servicesTestSuite) TestAddSnapServicesAndRemove(c *C) { 93 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 94 svcFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.service") 95 96 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 97 c.Assert(err, IsNil) 98 c.Check(s.sysdLog, DeepEquals, [][]string{ 99 {"--root", dirs.GlobalRootDir, "enable", filepath.Base(svcFile)}, 100 {"daemon-reload"}, 101 }) 102 103 content, err := ioutil.ReadFile(svcFile) 104 c.Assert(err, IsNil) 105 106 verbs := []string{"Start", "Stop", "StopPost"} 107 cmds := []string{"", " --command=stop", " --command=post-stop"} 108 for i := range verbs { 109 expected := fmt.Sprintf("Exec%s=/usr/bin/snap run%s hello-snap.svc1", verbs[i], cmds[i]) 110 c.Check(string(content), Matches, "(?ms).*^"+regexp.QuoteMeta(expected)) // check.v1 adds ^ and $ around the regexp provided 111 } 112 113 s.sysdLog = nil 114 err = wrappers.StopServices(info.Services(), nil, "", progress.Null, s.perfTimings) 115 c.Assert(err, IsNil) 116 c.Assert(s.sysdLog, HasLen, 2) 117 c.Check(s.sysdLog, DeepEquals, [][]string{ 118 {"stop", filepath.Base(svcFile)}, 119 {"show", "--property=ActiveState", "snap.hello-snap.svc1.service"}, 120 }) 121 122 s.sysdLog = nil 123 err = wrappers.RemoveSnapServices(info, progress.Null) 124 c.Assert(err, IsNil) 125 c.Check(osutil.FileExists(svcFile), Equals, false) 126 c.Assert(s.sysdLog, HasLen, 2) 127 c.Check(s.sysdLog[0], DeepEquals, []string{"--root", dirs.GlobalRootDir, "disable", filepath.Base(svcFile)}) 128 c.Check(s.sysdLog[1], DeepEquals, []string{"daemon-reload"}) 129 } 130 131 func (s *servicesTestSuite) TestAddSnapServicesAndRemoveUserDaemons(c *C) { 132 info := snaptest.MockSnap(c, packageHello+` 133 svc1: 134 daemon: simple 135 daemon-scope: user 136 `, &snap.SideInfo{Revision: snap.R(12)}) 137 svcFile := filepath.Join(s.tempdir, "/etc/systemd/user/snap.hello-snap.svc1.service") 138 139 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 140 c.Assert(err, IsNil) 141 c.Check(s.sysdLog, DeepEquals, [][]string{ 142 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", filepath.Base(svcFile)}, 143 {"--user", "daemon-reload"}, 144 }) 145 146 content, err := ioutil.ReadFile(svcFile) 147 c.Assert(err, IsNil) 148 149 expected := "ExecStart=/usr/bin/snap run hello-snap.svc1" 150 c.Check(string(content), Matches, "(?ms).*^"+regexp.QuoteMeta(expected)) // check.v1 adds ^ and $ around the regexp provided 151 152 s.sysdLog = nil 153 err = wrappers.StopServices(info.Services(), nil, "", progress.Null, s.perfTimings) 154 c.Assert(err, IsNil) 155 c.Assert(s.sysdLog, HasLen, 2) 156 c.Check(s.sysdLog, DeepEquals, [][]string{ 157 {"--user", "stop", filepath.Base(svcFile)}, 158 {"--user", "show", "--property=ActiveState", "snap.hello-snap.svc1.service"}, 159 }) 160 161 s.sysdLog = nil 162 err = wrappers.RemoveSnapServices(info, progress.Null) 163 c.Assert(err, IsNil) 164 c.Check(osutil.FileExists(svcFile), Equals, false) 165 c.Assert(s.sysdLog, HasLen, 2) 166 c.Check(s.sysdLog, DeepEquals, [][]string{ 167 {"--user", "--global", "--root", dirs.GlobalRootDir, "disable", filepath.Base(svcFile)}, 168 {"--user", "daemon-reload"}, 169 }) 170 } 171 172 var snapdYaml = `name: snapd 173 version: 1.0 174 type: snapd 175 ` 176 177 func (s *servicesTestSuite) TestRemoveSnapWithSocketsRemovesSocketsService(c *C) { 178 info := snaptest.MockSnap(c, packageHello+` 179 svc1: 180 daemon: simple 181 plugs: [network-bind] 182 sockets: 183 sock1: 184 listen-stream: $SNAP_DATA/sock1.socket 185 socket-mode: 0666 186 sock2: 187 listen-stream: $SNAP_COMMON/sock2.socket 188 `, &snap.SideInfo{Revision: snap.R(12)}) 189 190 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 191 c.Assert(err, IsNil) 192 193 err = wrappers.StopServices(info.Services(), nil, "", &progress.Null, s.perfTimings) 194 c.Assert(err, IsNil) 195 196 err = wrappers.RemoveSnapServices(info, &progress.Null) 197 c.Assert(err, IsNil) 198 199 app := info.Apps["svc1"] 200 c.Assert(app.Sockets, HasLen, 2) 201 for _, socket := range app.Sockets { 202 c.Check(osutil.FileExists(socket.File()), Equals, false) 203 } 204 } 205 206 func (s *servicesTestSuite) TestRemoveSnapPackageFallbackToKill(c *C) { 207 restore := wrappers.MockKillWait(time.Millisecond) 208 defer restore() 209 210 var sysdLog [][]string 211 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 212 // filter out the "systemctl show" that 213 // StopServices generates 214 if cmd[0] != "show" { 215 sysdLog = append(sysdLog, cmd) 216 } 217 return []byte("ActiveState=active\n"), nil 218 }) 219 defer r() 220 221 info := snaptest.MockSnap(c, `name: wat 222 version: 42 223 apps: 224 wat: 225 command: wat 226 stop-timeout: 20ms 227 daemon: forking 228 `, &snap.SideInfo{Revision: snap.R(11)}) 229 230 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 231 c.Assert(err, IsNil) 232 233 sysdLog = nil 234 235 svcFName := "snap.wat.wat.service" 236 237 err = wrappers.StopServices(info.Services(), nil, "", progress.Null, s.perfTimings) 238 c.Assert(err, IsNil) 239 240 c.Check(sysdLog, DeepEquals, [][]string{ 241 {"stop", svcFName}, 242 // check kill invocations 243 {"kill", svcFName, "-s", "TERM", "--kill-who=all"}, 244 {"kill", svcFName, "-s", "KILL", "--kill-who=all"}, 245 }) 246 } 247 248 func (s *servicesTestSuite) TestRemoveSnapPackageUserDaemonStopFailure(c *C) { 249 var sysdLog [][]string 250 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 251 // filter out the "systemctl --user show" that 252 // StopServices generates 253 if cmd[0] == "--user" && cmd[1] != "show" { 254 sysdLog = append(sysdLog, cmd) 255 } 256 if cmd[0] == "--user" && cmd[1] == "stop" { 257 return nil, fmt.Errorf("user unit stop failed") 258 } 259 return []byte("ActiveState=active\n"), nil 260 }) 261 defer r() 262 263 info := snaptest.MockSnap(c, `name: wat 264 version: 42 265 apps: 266 wat: 267 command: wat 268 stop-timeout: 20ms 269 daemon: forking 270 daemon-scope: user 271 `, &snap.SideInfo{Revision: snap.R(11)}) 272 273 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 274 c.Assert(err, IsNil) 275 276 sysdLog = nil 277 278 svcFName := "snap.wat.wat.service" 279 280 err = wrappers.StopServices(info.Services(), nil, "", progress.Null, s.perfTimings) 281 c.Check(err, ErrorMatches, "some user services failed to stop") 282 c.Check(sysdLog, DeepEquals, [][]string{ 283 {"--user", "stop", svcFName}, 284 }) 285 } 286 287 func (s *servicesTestSuite) TestServicesEnableState(c *C) { 288 info := snaptest.MockSnap(c, packageHello+` 289 svc2: 290 command: bin/hello 291 daemon: forking 292 svc3: 293 command: bin/hello 294 daemon: simple 295 daemon-scope: user 296 `, &snap.SideInfo{Revision: snap.R(12)}) 297 svc1File := "snap.hello-snap.svc1.service" 298 svc2File := "snap.hello-snap.svc2.service" 299 300 s.systemctlRestorer() 301 r := testutil.MockCommand(c, "systemctl", `#!/bin/sh 302 if [ "$1" = "--root" ]; then 303 # shifting by 2 also drops the temp dir arg to --root 304 shift 2 305 fi 306 307 case "$1" in 308 is-enabled) 309 case "$2" in 310 "snap.hello-snap.svc1.service") 311 echo "disabled" 312 exit 1 313 ;; 314 "snap.hello-snap.svc2.service") 315 echo "enabled" 316 exit 0 317 ;; 318 *) 319 echo "unexpected is-enabled of service $2" 320 exit 2 321 ;; 322 esac 323 ;; 324 *) 325 echo "unexpected op $*" 326 exit 2 327 esac 328 329 exit 1 330 `) 331 defer r.Restore() 332 333 states, err := wrappers.ServicesEnableState(info, progress.Null) 334 c.Assert(err, IsNil) 335 336 c.Assert(states, DeepEquals, map[string]bool{ 337 "svc1": false, 338 "svc2": true, 339 }) 340 341 // the calls could be out of order in the list, since iterating over a map 342 // is non-deterministic, so manually check each call 343 c.Assert(r.Calls(), HasLen, 2) 344 for _, call := range r.Calls() { 345 c.Assert(call, HasLen, 5) 346 c.Assert(call[:4], DeepEquals, []string{"systemctl", "--root", s.tempdir, "is-enabled"}) 347 switch call[4] { 348 case svc1File, svc2File: 349 default: 350 c.Errorf("unknown service for systemctl call: %s", call[4]) 351 } 352 } 353 } 354 355 func (s *servicesTestSuite) TestServicesEnableStateFail(c *C) { 356 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 357 svc1File := "snap.hello-snap.svc1.service" 358 359 s.systemctlRestorer() 360 r := testutil.MockCommand(c, "systemctl", `#!/bin/sh 361 if [ "$1" = "--root" ]; then 362 # shifting by 2 also drops the temp dir arg to --root 363 shift 2 364 fi 365 366 case "$1" in 367 is-enabled) 368 case "$2" in 369 "snap.hello-snap.svc1.service") 370 echo "whoops" 371 exit 1 372 ;; 373 *) 374 echo "unexpected is-enabled of service $2" 375 exit 2 376 ;; 377 esac 378 ;; 379 *) 380 echo "unexpected op $*" 381 exit 2 382 esac 383 384 exit 1 385 `) 386 defer r.Restore() 387 388 _, err := wrappers.ServicesEnableState(info, progress.Null) 389 c.Assert(err, ErrorMatches, ".*is-enabled snap.hello-snap.svc1.service\\] failed with exit status 1: whoops\n.*") 390 391 c.Assert(r.Calls(), DeepEquals, [][]string{ 392 {"systemctl", "--root", s.tempdir, "is-enabled", svc1File}, 393 }) 394 } 395 396 func (s *servicesTestSuite) TestAddSnapServicesWithDisabledServices(c *C) { 397 info := snaptest.MockSnap(c, packageHello+` 398 svc2: 399 command: bin/hello 400 daemon: forking 401 `, &snap.SideInfo{Revision: snap.R(12)}) 402 403 s.systemctlRestorer() 404 r := testutil.MockCommand(c, "systemctl", `#!/bin/sh 405 if [ "$1" = "--root" ]; then 406 shift 2 407 fi 408 409 case "$1" in 410 enable) 411 case "$2" in 412 "snap.hello-snap.svc1.service") 413 echo "unexpected enable of disabled service $2" 414 exit 1 415 ;; 416 "snap.hello-snap.svc2.service") 417 exit 0 418 ;; 419 *) 420 echo "unexpected enable of service $2" 421 exit 1 422 ;; 423 esac 424 ;; 425 daemon-reload) 426 exit 0 427 ;; 428 *) 429 echo "unexpected op $*" 430 exit 2 431 esac 432 exit 2 433 `) 434 defer r.Restore() 435 436 // svc1 will be disabled 437 disabledSvcs := []string{"svc1"} 438 439 err := wrappers.AddSnapServices(info, disabledSvcs, nil, progress.Null) 440 c.Assert(err, IsNil) 441 442 // only svc2 should be enabled 443 c.Assert(r.Calls(), DeepEquals, [][]string{ 444 {"systemctl", "--root", s.tempdir, "enable", "snap.hello-snap.svc2.service"}, 445 {"systemctl", "daemon-reload"}, 446 }) 447 } 448 449 func (s *servicesTestSuite) TestAddSnapServicesWithDisabledServicesNowApp(c *C) { 450 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 451 452 // mock the logger 453 buf, loggerRestore := logger.MockLogger() 454 defer loggerRestore() 455 456 s.systemctlRestorer() 457 r := testutil.MockCommand(c, "systemctl", `#!/bin/sh 458 if [ "$1" = "--root" ]; then 459 shift 2 460 fi 461 462 case "$1" in 463 enable) 464 case "$2" in 465 "snap.hello-snap.svc1.service") 466 exit 0 467 ;; 468 *) 469 echo "unexpected enable of service $2" 470 exit 1 471 ;; 472 esac 473 ;; 474 daemon-reload) 475 exit 0 476 ;; 477 *) 478 echo "unexpected op $*" 479 exit 2 480 esac 481 exit 2 482 `) 483 defer r.Restore() 484 485 svcs := []string{"hello"} 486 487 err := wrappers.AddSnapServices(info, svcs, nil, progress.Null) 488 c.Assert(err, IsNil) 489 490 // check the log for the notice 491 c.Assert(buf.String(), Matches, `.*previously disabled service hello is now an app and not a service\n.*`) 492 493 // the cleanup of AddSnapServices will remove written service files and then 494 // call reload, but note that we should catch any non-svc apps before 495 // actually enabling them, so we just see a daemon-reload call and not any 496 // enable calls 497 c.Assert(r.Calls(), DeepEquals, [][]string{ 498 {"systemctl", "--root", s.tempdir, "enable", "snap.hello-snap.svc1.service"}, 499 {"systemctl", "daemon-reload"}, 500 }) 501 } 502 503 func (s *servicesTestSuite) TestAddSnapServicesWithDisabledServicesMissing(c *C) { 504 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 505 506 // mock the logger 507 buf, loggerRestore := logger.MockLogger() 508 defer loggerRestore() 509 510 s.systemctlRestorer() 511 r := testutil.MockCommand(c, "systemctl", `#!/bin/sh 512 if [ "$1" = "--root" ]; then 513 shift 2 514 fi 515 516 case "$1" in 517 enable) 518 case "$2" in 519 "snap.hello-snap.svc1.service") 520 exit 0 521 ;; 522 *) 523 echo "unexpected enable of service $2" 524 exit 1 525 ;; 526 esac 527 ;; 528 daemon-reload) 529 exit 0 530 ;; 531 *) 532 echo "unexpected op $*" 533 exit 2 534 esac 535 exit 2 536 `) 537 defer r.Restore() 538 539 svcs := []string{"old-disabled-svc"} 540 541 err := wrappers.AddSnapServices(info, svcs, nil, progress.Null) 542 c.Assert(err, IsNil) 543 544 // check the log for the notice 545 c.Assert(buf.String(), Matches, `.*previously disabled service old-disabled-svc no longer exists\n.*`) 546 547 // the cleanup of AddSnapServices will remove written service files and then 548 // call reload, but note that we should catch any non-svc apps before 549 // actually enabling them, so we just see a daemon-reload call and not any 550 // enable calls 551 c.Assert(r.Calls(), DeepEquals, [][]string{ 552 {"systemctl", "--root", s.tempdir, "enable", "snap.hello-snap.svc1.service"}, 553 {"systemctl", "daemon-reload"}, 554 }) 555 } 556 557 func (s *servicesTestSuite) TestAddSnapServicesWithPreseed(c *C) { 558 opts := &wrappers.AddSnapServicesOptions{Preseeding: true} 559 560 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 561 562 s.systemctlRestorer() 563 r := testutil.MockCommand(c, "systemctl", "exit 1") 564 defer r.Restore() 565 566 err := wrappers.AddSnapServices(info, nil, opts, progress.Null) 567 c.Assert(err, IsNil) 568 569 // file was created 570 svcFiles, _ := filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.*.service")) 571 c.Check(svcFiles, HasLen, 1) 572 573 // but systemctl was not called 574 c.Assert(r.Calls(), HasLen, 0) 575 } 576 577 func (s *servicesTestSuite) TestStopServicesWithSockets(c *C) { 578 var sysServices, userServices []string 579 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 580 if cmd[0] == "stop" { 581 sysServices = append(sysServices, cmd[1]) 582 } else if cmd[0] == "--user" && cmd[1] == "stop" { 583 userServices = append(userServices, cmd[2]) 584 } 585 return []byte("ActiveState=inactive\n"), nil 586 }) 587 defer r() 588 589 info := snaptest.MockSnap(c, packageHello+` 590 svc1: 591 daemon: simple 592 plugs: [network-bind] 593 sockets: 594 sock1: 595 listen-stream: $SNAP_COMMON/sock1.socket 596 socket-mode: 0666 597 sock2: 598 listen-stream: $SNAP_DATA/sock2.socket 599 svc2: 600 daemon: simple 601 daemon-scope: user 602 plugs: [network-bind] 603 sockets: 604 sock1: 605 listen-stream: $SNAP_USER_COMMON/sock1.socket 606 socket-mode: 0666 607 sock2: 608 listen-stream: $SNAP_USER_DATA/sock2.socket 609 `, &snap.SideInfo{Revision: snap.R(12)}) 610 611 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 612 c.Assert(err, IsNil) 613 614 sysServices = nil 615 userServices = nil 616 617 err = wrappers.StopServices(info.Services(), nil, "", &progress.Null, s.perfTimings) 618 c.Assert(err, IsNil) 619 620 sort.Strings(sysServices) 621 c.Check(sysServices, DeepEquals, []string{ 622 "snap.hello-snap.svc1.service", "snap.hello-snap.svc1.sock1.socket", "snap.hello-snap.svc1.sock2.socket"}) 623 sort.Strings(userServices) 624 c.Check(userServices, DeepEquals, []string{ 625 "snap.hello-snap.svc2.service", "snap.hello-snap.svc2.sock1.socket", "snap.hello-snap.svc2.sock2.socket"}) 626 } 627 628 func (s *servicesTestSuite) TestStartServices(c *C) { 629 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 630 svcFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.service") 631 632 err := wrappers.StartServices(info.Services(), nil, nil, &progress.Null, s.perfTimings) 633 c.Assert(err, IsNil) 634 635 c.Assert(s.sysdLog, DeepEquals, [][]string{ 636 {"--root", s.tempdir, "is-enabled", filepath.Base(svcFile)}, 637 {"start", filepath.Base(svcFile)}, 638 }) 639 } 640 641 func (s *servicesTestSuite) TestStartServicesUserDaemons(c *C) { 642 info := snaptest.MockSnap(c, packageHello+` 643 svc1: 644 daemon: simple 645 daemon-scope: user 646 `, &snap.SideInfo{Revision: snap.R(12)}) 647 svcFile := filepath.Join(s.tempdir, "/etc/systemd/user/snap.hello-snap.svc1.service") 648 649 err := wrappers.StartServices(info.Services(), nil, nil, &progress.Null, s.perfTimings) 650 c.Assert(err, IsNil) 651 652 c.Assert(s.sysdLog, DeepEquals, [][]string{ 653 {"--user", "--global", "--root", s.tempdir, "is-enabled", filepath.Base(svcFile)}, 654 {"--user", "start", filepath.Base(svcFile)}, 655 }) 656 } 657 658 func (s *servicesTestSuite) TestEnableServices(c *C) { 659 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 660 svcFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.service") 661 662 err := wrappers.EnableSnapServices(info, nil) 663 c.Assert(err, IsNil) 664 665 c.Assert(s.sysdLog, DeepEquals, [][]string{ 666 {"--root", s.tempdir, "enable", filepath.Base(svcFile)}, 667 }) 668 } 669 670 func (s *servicesTestSuite) TestNoStartDisabledServices(c *C) { 671 info := snaptest.MockSnap(c, packageHello, &snap.SideInfo{Revision: snap.R(12)}) 672 svcFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.service") 673 674 s.systemctlRestorer() 675 r := testutil.MockCommand(c, "systemctl", `#!/bin/sh 676 if [ "$1" = "--root" ]; then 677 shift 2 678 fi 679 680 case "$1" in 681 is-enabled) 682 if [ "$2" = "snap.hello-snap.svc1.service" ]; then 683 echo "disabled" 684 exit 1 685 else 686 echo "unexpected call $*" 687 exit 2 688 fi 689 ;; 690 *) 691 echo "unexpected call $*" 692 exit 2 693 esac 694 `) 695 defer r.Restore() 696 697 err := wrappers.StartServices(info.Services(), nil, nil, &progress.Null, s.perfTimings) 698 c.Assert(err, IsNil) 699 700 c.Assert(r.Calls(), DeepEquals, [][]string{ 701 {"systemctl", "--root", s.tempdir, "is-enabled", filepath.Base(svcFile)}, 702 }) 703 } 704 705 func (s *servicesTestSuite) TestAddSnapMultiServicesFailCreateCleanup(c *C) { 706 // sanity check: there are no service files 707 svcFiles, _ := filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.hello-snap.*.service")) 708 c.Check(svcFiles, HasLen, 0) 709 710 info := snaptest.MockSnap(c, packageHello+` 711 svc2: 712 daemon: potato 713 `, &snap.SideInfo{Revision: snap.R(12)}) 714 715 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 716 c.Assert(err, ErrorMatches, ".*potato.*") 717 718 // the services are cleaned up 719 svcFiles, _ = filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.hello-snap.*.service")) 720 c.Check(svcFiles, HasLen, 0) 721 722 // *either* the first service failed validation, and nothing 723 // was done, *or* the second one failed, and the first one was 724 // enabled before the second failed, and disabled after. 725 if len(s.sysdLog) > 0 { 726 // the second service failed validation 727 c.Check(s.sysdLog, DeepEquals, [][]string{ 728 {"daemon-reload"}, 729 }) 730 } 731 } 732 733 func (s *servicesTestSuite) TestAddSnapMultiServicesFailEnableCleanup(c *C) { 734 var sysdLog [][]string 735 svc1Name := "snap.hello-snap.svc1.service" 736 svc2Name := "snap.hello-snap.svc2.service" 737 numEnables := 0 738 739 // sanity check: there are no service files 740 svcFiles, _ := filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.hello-snap.*.service")) 741 c.Check(svcFiles, HasLen, 0) 742 743 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 744 sysdLog = append(sysdLog, cmd) 745 sdcmd := cmd[0] 746 if len(cmd) >= 2 { 747 sdcmd = cmd[len(cmd)-2] 748 } 749 switch sdcmd { 750 case "enable": 751 numEnables++ 752 switch numEnables { 753 case 1: 754 if cmd[len(cmd)-1] == svc2Name { 755 // the services are being iterated in the "wrong" order 756 svc1Name, svc2Name = svc2Name, svc1Name 757 } 758 return nil, nil 759 case 2: 760 return nil, fmt.Errorf("failed") 761 default: 762 panic("expected no more than 2 enables") 763 } 764 case "disable", "daemon-reload": 765 return nil, nil 766 default: 767 panic("unexpected systemctl command " + sdcmd) 768 } 769 }) 770 defer r() 771 772 info := snaptest.MockSnap(c, packageHello+` 773 svc2: 774 command: bin/hello 775 daemon: simple 776 `, &snap.SideInfo{Revision: snap.R(12)}) 777 778 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 779 c.Assert(err, ErrorMatches, "failed") 780 781 // the services are cleaned up 782 svcFiles, _ = filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.hello-snap.*.service")) 783 c.Check(svcFiles, HasLen, 0) 784 c.Check(sysdLog, DeepEquals, [][]string{ 785 {"--root", dirs.GlobalRootDir, "enable", svc1Name}, 786 {"--root", dirs.GlobalRootDir, "enable", svc2Name}, // this one fails 787 {"--root", dirs.GlobalRootDir, "disable", svc1Name}, 788 {"daemon-reload"}, 789 }) 790 } 791 792 func (s *servicesTestSuite) TestAddSnapMultiServicesStartFailOnSystemdReloadCleanup(c *C) { 793 // this test might be overdoing it (it's mostly covering the same ground as the previous one), but ... :-) 794 var sysdLog [][]string 795 svc1Name := "snap.hello-snap.svc1.service" 796 svc2Name := "snap.hello-snap.svc2.service" 797 798 // sanity check: there are no service files 799 svcFiles, _ := filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.hello-snap.*.service")) 800 c.Check(svcFiles, HasLen, 0) 801 802 first := true 803 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 804 sysdLog = append(sysdLog, cmd) 805 if len(cmd) < 2 { 806 return nil, fmt.Errorf("failed") 807 } 808 if first { 809 first = false 810 if cmd[len(cmd)-1] == svc2Name { 811 // the services are being iterated in the "wrong" order 812 svc1Name, svc2Name = svc2Name, svc1Name 813 } 814 } 815 return nil, nil 816 817 }) 818 defer r() 819 820 info := snaptest.MockSnap(c, packageHello+` 821 svc2: 822 command: bin/hello 823 daemon: simple 824 `, &snap.SideInfo{Revision: snap.R(12)}) 825 826 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 827 c.Assert(err, ErrorMatches, "failed") 828 829 // the services are cleaned up 830 svcFiles, _ = filepath.Glob(filepath.Join(dirs.SnapServicesDir, "snap.hello-snap.*.service")) 831 c.Check(svcFiles, HasLen, 0) 832 c.Check(sysdLog, DeepEquals, [][]string{ 833 {"--root", dirs.GlobalRootDir, "enable", svc1Name}, 834 {"--root", dirs.GlobalRootDir, "enable", svc2Name}, 835 {"daemon-reload"}, // this one fails 836 {"--root", dirs.GlobalRootDir, "disable", svc1Name}, 837 {"--root", dirs.GlobalRootDir, "disable", svc2Name}, 838 {"daemon-reload"}, // so does this one :-) 839 }) 840 } 841 842 func (s *servicesTestSuite) TestAddSnapMultiUserServicesFailEnableCleanup(c *C) { 843 var sysdLog [][]string 844 svc1Name := "snap.hello-snap.svc1.service" 845 svc2Name := "snap.hello-snap.svc2.service" 846 numEnables := 0 847 848 // sanity check: there are no service files 849 svcFiles, _ := filepath.Glob(filepath.Join(dirs.SnapUserServicesDir, "snap.hello-snap.*.service")) 850 c.Check(svcFiles, HasLen, 0) 851 852 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 853 sysdLog = append(sysdLog, cmd) 854 if len(cmd) >= 1 && cmd[0] == "--user" { 855 cmd = cmd[1:] 856 } 857 if len(cmd) >= 1 && cmd[0] == "--global" { 858 cmd = cmd[1:] 859 } 860 sdcmd := cmd[0] 861 if len(cmd) >= 2 { 862 sdcmd = cmd[len(cmd)-2] 863 } 864 switch sdcmd { 865 case "enable": 866 numEnables++ 867 switch numEnables { 868 case 1: 869 if cmd[len(cmd)-1] == svc2Name { 870 // the services are being iterated in the "wrong" order 871 svc1Name, svc2Name = svc2Name, svc1Name 872 } 873 return nil, nil 874 case 2: 875 return nil, fmt.Errorf("failed") 876 default: 877 panic("expected no more than 2 enables") 878 } 879 case "disable", "daemon-reload": 880 return nil, nil 881 default: 882 panic("unexpected systemctl command " + sdcmd) 883 } 884 }) 885 defer r() 886 887 info := snaptest.MockSnap(c, packageHello+` 888 svc1: 889 command: bin/hello 890 daemon: simple 891 daemon-scope: user 892 svc2: 893 command: bin/hello 894 daemon: simple 895 daemon-scope: user 896 `, &snap.SideInfo{Revision: snap.R(12)}) 897 898 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 899 c.Assert(err, ErrorMatches, "failed") 900 901 // the services are cleaned up 902 svcFiles, _ = filepath.Glob(filepath.Join(dirs.SnapUserServicesDir, "snap.hello-snap.*.service")) 903 c.Check(svcFiles, HasLen, 0) 904 c.Check(sysdLog, DeepEquals, [][]string{ 905 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", svc1Name}, 906 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", svc2Name}, // this one fails 907 {"--user", "--global", "--root", dirs.GlobalRootDir, "disable", svc1Name}, 908 {"--user", "daemon-reload"}, 909 }) 910 } 911 912 func (s *servicesTestSuite) TestAddSnapMultiUserServicesStartFailOnSystemdReloadCleanup(c *C) { 913 // this test might be overdoing it (it's mostly covering the same ground as the previous one), but ... :-) 914 var sysdLog [][]string 915 svc1Name := "snap.hello-snap.svc1.service" 916 svc2Name := "snap.hello-snap.svc2.service" 917 918 // sanity check: there are no service files 919 svcFiles, _ := filepath.Glob(filepath.Join(dirs.SnapUserServicesDir, "snap.hello-snap.*.service")) 920 c.Check(svcFiles, HasLen, 0) 921 922 first := true 923 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 924 sysdLog = append(sysdLog, cmd) 925 if len(cmd) < 3 { 926 return nil, fmt.Errorf("failed") 927 } 928 if first { 929 first = false 930 if cmd[len(cmd)-1] == svc2Name { 931 // the services are being iterated in the "wrong" order 932 svc1Name, svc2Name = svc2Name, svc1Name 933 } 934 } 935 return nil, nil 936 937 }) 938 defer r() 939 940 info := snaptest.MockSnap(c, packageHello+` 941 svc1: 942 command: bin/hello 943 daemon: simple 944 daemon-scope: user 945 svc2: 946 command: bin/hello 947 daemon: simple 948 daemon-scope: user 949 `, &snap.SideInfo{Revision: snap.R(12)}) 950 951 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 952 c.Assert(err, ErrorMatches, "cannot reload daemon: failed") 953 954 // the services are cleaned up 955 svcFiles, _ = filepath.Glob(filepath.Join(dirs.SnapUserServicesDir, "snap.hello-snap.*.service")) 956 c.Check(svcFiles, HasLen, 0) 957 c.Check(sysdLog, DeepEquals, [][]string{ 958 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", svc1Name}, 959 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", svc2Name}, 960 {"--user", "daemon-reload"}, // this one fails 961 {"--user", "--global", "--root", dirs.GlobalRootDir, "disable", svc1Name}, 962 {"--user", "--global", "--root", dirs.GlobalRootDir, "disable", svc2Name}, 963 {"--user", "daemon-reload"}, // so does this one :-) 964 }) 965 } 966 967 func (s *servicesTestSuite) TestAddSnapSocketFiles(c *C) { 968 info := snaptest.MockSnap(c, packageHello+` 969 svc1: 970 daemon: simple 971 plugs: [network-bind] 972 sockets: 973 sock1: 974 listen-stream: $SNAP_COMMON/sock1.socket 975 socket-mode: 0666 976 sock2: 977 listen-stream: $SNAP_DATA/sock2.socket 978 sock3: 979 listen-stream: $XDG_RUNTIME_DIR/sock3.socket 980 981 `, &snap.SideInfo{Revision: snap.R(12)}) 982 983 sock1File := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.sock1.socket") 984 sock2File := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.sock2.socket") 985 sock3File := filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc1.sock3.socket") 986 987 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 988 c.Assert(err, IsNil) 989 990 expected := fmt.Sprintf( 991 `[Socket] 992 Service=snap.hello-snap.svc1.service 993 FileDescriptorName=sock1 994 ListenStream=%s 995 SocketMode=0666 996 997 `, filepath.Join(s.tempdir, "/var/snap/hello-snap/common/sock1.socket")) 998 c.Check(sock1File, testutil.FileContains, expected) 999 1000 expected = fmt.Sprintf( 1001 `[Socket] 1002 Service=snap.hello-snap.svc1.service 1003 FileDescriptorName=sock2 1004 ListenStream=%s 1005 1006 `, filepath.Join(s.tempdir, "/var/snap/hello-snap/12/sock2.socket")) 1007 c.Check(sock2File, testutil.FileContains, expected) 1008 1009 expected = fmt.Sprintf( 1010 `[Socket] 1011 Service=snap.hello-snap.svc1.service 1012 FileDescriptorName=sock3 1013 ListenStream=%s 1014 1015 `, filepath.Join(s.tempdir, "/run/user/0/snap.hello-snap/sock3.socket")) 1016 c.Check(sock3File, testutil.FileContains, expected) 1017 } 1018 1019 func (s *servicesTestSuite) TestAddSnapUserSocketFiles(c *C) { 1020 info := snaptest.MockSnap(c, packageHello+` 1021 svc1: 1022 daemon: simple 1023 daemon-scope: user 1024 plugs: [network-bind] 1025 sockets: 1026 sock1: 1027 listen-stream: $SNAP_USER_COMMON/sock1.socket 1028 socket-mode: 0666 1029 sock2: 1030 listen-stream: $SNAP_USER_DATA/sock2.socket 1031 sock3: 1032 listen-stream: $XDG_RUNTIME_DIR/sock3.socket 1033 `, &snap.SideInfo{Revision: snap.R(12)}) 1034 1035 sock1File := filepath.Join(s.tempdir, "/etc/systemd/user/snap.hello-snap.svc1.sock1.socket") 1036 sock2File := filepath.Join(s.tempdir, "/etc/systemd/user/snap.hello-snap.svc1.sock2.socket") 1037 sock3File := filepath.Join(s.tempdir, "/etc/systemd/user/snap.hello-snap.svc1.sock3.socket") 1038 1039 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1040 c.Assert(err, IsNil) 1041 1042 expected := `[Socket] 1043 Service=snap.hello-snap.svc1.service 1044 FileDescriptorName=sock1 1045 ListenStream=%h/snap/hello-snap/common/sock1.socket 1046 SocketMode=0666 1047 1048 ` 1049 c.Check(sock1File, testutil.FileContains, expected) 1050 1051 expected = `[Socket] 1052 Service=snap.hello-snap.svc1.service 1053 FileDescriptorName=sock2 1054 ListenStream=%h/snap/hello-snap/12/sock2.socket 1055 1056 ` 1057 c.Check(sock2File, testutil.FileContains, expected) 1058 1059 expected = `[Socket] 1060 Service=snap.hello-snap.svc1.service 1061 FileDescriptorName=sock3 1062 ListenStream=%t/snap.hello-snap/sock3.socket 1063 1064 ` 1065 c.Check(sock3File, testutil.FileContains, expected) 1066 } 1067 1068 func (s *servicesTestSuite) TestStartSnapMultiServicesFailStartCleanup(c *C) { 1069 var sysdLog [][]string 1070 svc1Name := "snap.hello-snap.svc1.service" 1071 svc2Name := "snap.hello-snap.svc2.service" 1072 1073 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 1074 sysdLog = append(sysdLog, cmd) 1075 if len(cmd) >= 2 && cmd[0] == "start" { 1076 name := cmd[len(cmd)-1] 1077 if name == svc2Name { 1078 return nil, fmt.Errorf("failed") 1079 } 1080 } 1081 return []byte("ActiveState=inactive\n"), nil 1082 }) 1083 defer r() 1084 1085 info := snaptest.MockSnap(c, packageHello+` 1086 svc2: 1087 command: bin/hello 1088 daemon: simple 1089 `, &snap.SideInfo{Revision: snap.R(12)}) 1090 1091 svcs := info.Services() 1092 c.Assert(svcs, HasLen, 2) 1093 if svcs[0].Name == "svc2" { 1094 svcs[0], svcs[1] = svcs[1], svcs[0] 1095 } 1096 err := wrappers.StartServices(svcs, nil, nil, &progress.Null, s.perfTimings) 1097 c.Assert(err, ErrorMatches, "failed") 1098 c.Assert(sysdLog, HasLen, 8, Commentf("len: %v calls: %v", len(sysdLog), sysdLog)) 1099 c.Check(sysdLog, DeepEquals, [][]string{ 1100 {"--root", s.tempdir, "is-enabled", svc1Name}, 1101 {"--root", s.tempdir, "is-enabled", svc2Name}, 1102 {"start", svc1Name}, 1103 {"start", svc2Name}, // one of the services fails 1104 {"stop", svc2Name}, 1105 {"show", "--property=ActiveState", svc2Name}, 1106 {"stop", svc1Name}, 1107 {"show", "--property=ActiveState", svc1Name}, 1108 }, Commentf("calls: %v", sysdLog)) 1109 } 1110 1111 func (s *servicesTestSuite) TestStartSnapMultiServicesFailStartCleanupWithSockets(c *C) { 1112 var sysdLog [][]string 1113 svc1Name := "snap.hello-snap.svc1.service" 1114 svc2Name := "snap.hello-snap.svc2.service" 1115 svc2SocketName := "snap.hello-snap.svc2.sock1.socket" 1116 svc3Name := "snap.hello-snap.svc3.service" 1117 svc3SocketName := "snap.hello-snap.svc3.sock1.socket" 1118 1119 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 1120 sysdLog = append(sysdLog, cmd) 1121 c.Logf("call: %v", cmd) 1122 if len(cmd) >= 2 && cmd[0] == "start" && cmd[1] == svc3SocketName { 1123 // svc2 socket fails 1124 return nil, fmt.Errorf("failed") 1125 } 1126 return []byte("ActiveState=inactive\n"), nil 1127 }) 1128 defer r() 1129 1130 info := snaptest.MockSnap(c, packageHello+` 1131 svc2: 1132 command: bin/hello 1133 daemon: simple 1134 sockets: 1135 sock1: 1136 listen-stream: $SNAP_COMMON/sock1.socket 1137 socket-mode: 0666 1138 svc3: 1139 command: bin/hello 1140 daemon: simple 1141 sockets: 1142 sock1: 1143 listen-stream: $SNAP_COMMON/sock1.socket 1144 socket-mode: 0666 1145 `, &snap.SideInfo{Revision: snap.R(12)}) 1146 1147 // ensure desired order 1148 apps := []*snap.AppInfo{info.Apps["svc1"], info.Apps["svc2"], info.Apps["svc3"]} 1149 1150 err := wrappers.StartServices(apps, nil, nil, &progress.Null, s.perfTimings) 1151 c.Assert(err, ErrorMatches, "failed") 1152 c.Logf("sysdlog: %v", sysdLog) 1153 c.Assert(sysdLog, HasLen, 17, Commentf("len: %v calls: %v", len(sysdLog), sysdLog)) 1154 c.Check(sysdLog, DeepEquals, [][]string{ 1155 {"--root", s.tempdir, "is-enabled", svc1Name}, 1156 {"--root", s.tempdir, "enable", svc2SocketName}, 1157 {"start", svc2SocketName}, 1158 {"--root", s.tempdir, "enable", svc3SocketName}, 1159 {"start", svc3SocketName}, // start failed, what follows is the cleanup 1160 {"stop", svc3SocketName}, 1161 {"show", "--property=ActiveState", svc3SocketName}, 1162 {"stop", svc3Name}, 1163 {"show", "--property=ActiveState", svc3Name}, 1164 {"--root", s.tempdir, "disable", svc3SocketName}, 1165 {"stop", svc2SocketName}, 1166 {"show", "--property=ActiveState", svc2SocketName}, 1167 {"stop", svc2Name}, 1168 {"show", "--property=ActiveState", svc2Name}, 1169 {"--root", s.tempdir, "disable", svc2SocketName}, 1170 {"stop", svc1Name}, 1171 {"show", "--property=ActiveState", svc1Name}, 1172 }, Commentf("calls: %v", sysdLog)) 1173 } 1174 1175 func (s *servicesTestSuite) TestStartSnapMultiUserServicesFailStartCleanup(c *C) { 1176 var sysdLog [][]string 1177 svc1Name := "snap.hello-snap.svc1.service" 1178 svc2Name := "snap.hello-snap.svc2.service" 1179 1180 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 1181 sysdLog = append(sysdLog, cmd) 1182 if len(cmd) >= 3 && cmd[0] == "--user" && cmd[1] == "start" { 1183 name := cmd[len(cmd)-1] 1184 if name == svc2Name { 1185 return nil, fmt.Errorf("failed") 1186 } 1187 } 1188 return []byte("ActiveState=inactive\n"), nil 1189 }) 1190 defer r() 1191 1192 info := snaptest.MockSnap(c, packageHello+` 1193 svc1: 1194 command: bin/hello 1195 daemon: simple 1196 daemon-scope: user 1197 svc2: 1198 command: bin/hello 1199 daemon: simple 1200 daemon-scope: user 1201 `, &snap.SideInfo{Revision: snap.R(12)}) 1202 1203 svcs := info.Services() 1204 c.Assert(svcs, HasLen, 2) 1205 if svcs[0].Name == "svc2" { 1206 svcs[0], svcs[1] = svcs[1], svcs[0] 1207 } 1208 err := wrappers.StartServices(svcs, nil, nil, &progress.Null, s.perfTimings) 1209 c.Assert(err, ErrorMatches, "some user services failed to start") 1210 c.Assert(sysdLog, HasLen, 10, Commentf("len: %v calls: %v", len(sysdLog), sysdLog)) 1211 c.Check(sysdLog, DeepEquals, [][]string{ 1212 {"--user", "--global", "--root", s.tempdir, "is-enabled", svc1Name}, 1213 {"--user", "--global", "--root", s.tempdir, "is-enabled", svc2Name}, 1214 {"--user", "start", svc1Name}, 1215 {"--user", "start", svc2Name}, // one of the services fails 1216 // session agent attempts to stop the non-failed services 1217 {"--user", "stop", svc1Name}, 1218 {"--user", "show", "--property=ActiveState", svc1Name}, 1219 // StartServices ensures everything is stopped 1220 {"--user", "stop", svc2Name}, 1221 {"--user", "show", "--property=ActiveState", svc2Name}, 1222 {"--user", "stop", svc1Name}, 1223 {"--user", "show", "--property=ActiveState", svc1Name}, 1224 }, Commentf("calls: %v", sysdLog)) 1225 } 1226 1227 func (s *servicesTestSuite) TestStartSnapServicesKeepsOrder(c *C) { 1228 var sysdLog [][]string 1229 svc1Name := "snap.services-snap.svc1.service" 1230 svc2Name := "snap.services-snap.svc2.service" 1231 svc3Name := "snap.services-snap.svc3.service" 1232 1233 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 1234 sysdLog = append(sysdLog, cmd) 1235 return []byte("ActiveState=inactive\n"), nil 1236 }) 1237 defer r() 1238 1239 info := snaptest.MockSnap(c, `name: services-snap 1240 apps: 1241 svc1: 1242 daemon: simple 1243 before: [svc3] 1244 svc2: 1245 daemon: simple 1246 after: [svc1] 1247 svc3: 1248 daemon: simple 1249 before: [svc2] 1250 `, &snap.SideInfo{Revision: snap.R(12)}) 1251 1252 svcs := info.Services() 1253 c.Assert(svcs, HasLen, 3) 1254 1255 sorted, err := snap.SortServices(svcs) 1256 c.Assert(err, IsNil) 1257 1258 err = wrappers.StartServices(sorted, nil, nil, &progress.Null, s.perfTimings) 1259 c.Assert(err, IsNil) 1260 c.Assert(sysdLog, HasLen, 6, Commentf("len: %v calls: %v", len(sysdLog), sysdLog)) 1261 c.Check(sysdLog, DeepEquals, [][]string{ 1262 {"--root", s.tempdir, "is-enabled", svc1Name}, 1263 {"--root", s.tempdir, "is-enabled", svc3Name}, 1264 {"--root", s.tempdir, "is-enabled", svc2Name}, 1265 {"start", svc1Name}, 1266 {"start", svc3Name}, 1267 {"start", svc2Name}, 1268 }, Commentf("calls: %v", sysdLog)) 1269 1270 // change the order 1271 sorted[1], sorted[0] = sorted[0], sorted[1] 1272 1273 // we should observe the calls done in the same order as services 1274 err = wrappers.StartServices(sorted, nil, nil, &progress.Null, s.perfTimings) 1275 c.Assert(err, IsNil) 1276 c.Assert(sysdLog, HasLen, 12, Commentf("len: %v calls: %v", len(sysdLog), sysdLog)) 1277 c.Check(sysdLog[6:], DeepEquals, [][]string{ 1278 {"--root", s.tempdir, "is-enabled", svc3Name}, 1279 {"--root", s.tempdir, "is-enabled", svc1Name}, 1280 {"--root", s.tempdir, "is-enabled", svc2Name}, 1281 {"start", svc3Name}, 1282 {"start", svc1Name}, 1283 {"start", svc2Name}, 1284 }, Commentf("calls: %v", sysdLog)) 1285 } 1286 1287 func (s *servicesTestSuite) TestServiceAfterBefore(c *C) { 1288 snapYaml := packageHello + ` 1289 svc2: 1290 daemon: forking 1291 after: [svc1] 1292 svc3: 1293 daemon: forking 1294 before: [svc4] 1295 after: [svc2] 1296 svc4: 1297 daemon: forking 1298 after: 1299 - svc1 1300 - svc2 1301 - svc3 1302 ` 1303 info := snaptest.MockSnap(c, snapYaml, &snap.SideInfo{Revision: snap.R(12)}) 1304 1305 checks := []struct { 1306 file string 1307 kind string 1308 matches []string 1309 }{{ 1310 file: filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc2.service"), 1311 kind: "After", 1312 matches: []string{info.Apps["svc1"].ServiceName()}, 1313 }, { 1314 file: filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc3.service"), 1315 kind: "After", 1316 matches: []string{info.Apps["svc2"].ServiceName()}, 1317 }, { 1318 file: filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc3.service"), 1319 kind: "Before", 1320 matches: []string{info.Apps["svc4"].ServiceName()}, 1321 }, { 1322 file: filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc4.service"), 1323 kind: "After", 1324 matches: []string{ 1325 info.Apps["svc1"].ServiceName(), 1326 info.Apps["svc2"].ServiceName(), 1327 info.Apps["svc3"].ServiceName(), 1328 }, 1329 }} 1330 1331 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1332 c.Assert(err, IsNil) 1333 1334 for _, check := range checks { 1335 content, err := ioutil.ReadFile(check.file) 1336 c.Assert(err, IsNil) 1337 1338 for _, m := range check.matches { 1339 c.Check(string(content), Matches, 1340 // match: 1341 // ... 1342 // After=other.mount some.target foo.service bar.service 1343 // Before=foo.service bar.service 1344 // ... 1345 // but not: 1346 // Foo=something After=foo.service Bar=something else 1347 // or: 1348 // After=foo.service 1349 // bar.service 1350 // or: 1351 // After= foo.service bar.service 1352 "(?ms).*^(?U)"+check.kind+"=.*\\s?"+regexp.QuoteMeta(m)+"\\s?[^=]*$") 1353 } 1354 } 1355 1356 } 1357 1358 func (s *servicesTestSuite) TestServiceWatchdog(c *C) { 1359 snapYaml := packageHello + ` 1360 svc2: 1361 daemon: forking 1362 watchdog-timeout: 12s 1363 svc3: 1364 daemon: forking 1365 watchdog-timeout: 0s 1366 svc4: 1367 daemon: forking 1368 ` 1369 info := snaptest.MockSnap(c, snapYaml, &snap.SideInfo{Revision: snap.R(12)}) 1370 1371 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1372 c.Assert(err, IsNil) 1373 1374 content, err := ioutil.ReadFile(filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc2.service")) 1375 c.Assert(err, IsNil) 1376 c.Check(strings.Contains(string(content), "\nWatchdogSec=12\n"), Equals, true) 1377 1378 noWatchdog := []string{ 1379 filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc3.service"), 1380 filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc4.service"), 1381 } 1382 for _, svcPath := range noWatchdog { 1383 content, err := ioutil.ReadFile(svcPath) 1384 c.Assert(err, IsNil) 1385 c.Check(strings.Contains(string(content), "WatchdogSec="), Equals, false) 1386 } 1387 } 1388 1389 func (s *servicesTestSuite) TestStopServiceEndure(c *C) { 1390 const surviveYaml = `name: survive-snap 1391 version: 1.0 1392 apps: 1393 survivor: 1394 command: bin/survivor 1395 refresh-mode: endure 1396 daemon: simple 1397 ` 1398 info := snaptest.MockSnap(c, surviveYaml, &snap.SideInfo{Revision: snap.R(1)}) 1399 survivorFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.survive-snap.survivor.service") 1400 1401 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1402 c.Assert(err, IsNil) 1403 c.Check(s.sysdLog, DeepEquals, [][]string{ 1404 {"--root", dirs.GlobalRootDir, "enable", filepath.Base(survivorFile)}, 1405 {"daemon-reload"}, 1406 }) 1407 1408 s.sysdLog = nil 1409 err = wrappers.StopServices(info.Services(), nil, snap.StopReasonRefresh, progress.Null, s.perfTimings) 1410 c.Assert(err, IsNil) 1411 c.Assert(s.sysdLog, HasLen, 0) 1412 1413 s.sysdLog = nil 1414 err = wrappers.StopServices(info.Services(), nil, snap.StopReasonRemove, progress.Null, s.perfTimings) 1415 c.Assert(err, IsNil) 1416 c.Check(s.sysdLog, DeepEquals, [][]string{ 1417 {"stop", filepath.Base(survivorFile)}, 1418 {"show", "--property=ActiveState", "snap.survive-snap.survivor.service"}, 1419 }) 1420 1421 } 1422 1423 func (s *servicesTestSuite) TestStopServiceSigs(c *C) { 1424 r := wrappers.MockKillWait(1 * time.Millisecond) 1425 defer r() 1426 1427 survivorFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.survive-snap.srv.service") 1428 for _, t := range []struct { 1429 mode string 1430 expectedSig string 1431 expectedWho string 1432 }{ 1433 {mode: "sigterm", expectedSig: "TERM", expectedWho: "main"}, 1434 {mode: "sigterm-all", expectedSig: "TERM", expectedWho: "all"}, 1435 {mode: "sighup", expectedSig: "HUP", expectedWho: "main"}, 1436 {mode: "sighup-all", expectedSig: "HUP", expectedWho: "all"}, 1437 {mode: "sigusr1", expectedSig: "USR1", expectedWho: "main"}, 1438 {mode: "sigusr1-all", expectedSig: "USR1", expectedWho: "all"}, 1439 {mode: "sigusr2", expectedSig: "USR2", expectedWho: "main"}, 1440 {mode: "sigusr2-all", expectedSig: "USR2", expectedWho: "all"}, 1441 } { 1442 surviveYaml := fmt.Sprintf(`name: survive-snap 1443 version: 1.0 1444 apps: 1445 srv: 1446 command: bin/survivor 1447 stop-mode: %s 1448 daemon: simple 1449 `, t.mode) 1450 info := snaptest.MockSnap(c, surviveYaml, &snap.SideInfo{Revision: snap.R(1)}) 1451 1452 s.sysdLog = nil 1453 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1454 c.Assert(err, IsNil) 1455 c.Check(s.sysdLog, DeepEquals, [][]string{ 1456 {"--root", dirs.GlobalRootDir, "enable", filepath.Base(survivorFile)}, 1457 {"daemon-reload"}, 1458 }) 1459 1460 s.sysdLog = nil 1461 err = wrappers.StopServices(info.Services(), nil, snap.StopReasonRefresh, progress.Null, s.perfTimings) 1462 c.Assert(err, IsNil) 1463 c.Check(s.sysdLog, DeepEquals, [][]string{ 1464 {"stop", filepath.Base(survivorFile)}, 1465 {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, 1466 }, Commentf("failure in %s", t.mode)) 1467 1468 s.sysdLog = nil 1469 err = wrappers.StopServices(info.Services(), nil, snap.StopReasonRemove, progress.Null, s.perfTimings) 1470 c.Assert(err, IsNil) 1471 switch t.expectedWho { 1472 case "all": 1473 c.Check(s.sysdLog, DeepEquals, [][]string{ 1474 {"stop", filepath.Base(survivorFile)}, 1475 {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, 1476 }) 1477 case "main": 1478 c.Check(s.sysdLog, DeepEquals, [][]string{ 1479 {"stop", filepath.Base(survivorFile)}, 1480 {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, 1481 {"kill", filepath.Base(survivorFile), "-s", "TERM", "--kill-who=all"}, 1482 {"kill", filepath.Base(survivorFile), "-s", "KILL", "--kill-who=all"}, 1483 }) 1484 default: 1485 panic("not reached") 1486 } 1487 } 1488 1489 } 1490 1491 func (s *servicesTestSuite) TestStartSnapSocketEnableStart(c *C) { 1492 svc1Name := "snap.hello-snap.svc1.service" 1493 // svc2Name := "snap.hello-snap.svc2.service" 1494 svc2Sock := "snap.hello-snap.svc2.sock.socket" 1495 svc3Sock := "snap.hello-snap.svc3.sock.socket" 1496 1497 info := snaptest.MockSnap(c, packageHello+` 1498 svc2: 1499 command: bin/hello 1500 daemon: simple 1501 sockets: 1502 sock: 1503 listen-stream: $SNAP_COMMON/sock1.socket 1504 svc3: 1505 command: bin/hello 1506 daemon: simple 1507 daemon-scope: user 1508 sockets: 1509 sock: 1510 listen-stream: $SNAP_USER_COMMON/sock1.socket 1511 `, &snap.SideInfo{Revision: snap.R(12)}) 1512 1513 // fix the apps order to make the test stable 1514 apps := []*snap.AppInfo{info.Apps["svc1"], info.Apps["svc2"], info.Apps["svc3"]} 1515 err := wrappers.StartServices(apps, nil, nil, &progress.Null, s.perfTimings) 1516 c.Assert(err, IsNil) 1517 c.Assert(s.sysdLog, HasLen, 6, Commentf("len: %v calls: %v", len(s.sysdLog), s.sysdLog)) 1518 c.Check(s.sysdLog, DeepEquals, [][]string{ 1519 {"--root", dirs.GlobalRootDir, "is-enabled", svc1Name}, 1520 {"--root", dirs.GlobalRootDir, "enable", svc2Sock}, 1521 {"start", svc2Sock}, 1522 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", svc3Sock}, 1523 {"--user", "start", svc3Sock}, 1524 {"start", svc1Name}, 1525 }, Commentf("calls: %v", s.sysdLog)) 1526 } 1527 1528 func (s *servicesTestSuite) TestStartSnapTimerEnableStart(c *C) { 1529 svc1Name := "snap.hello-snap.svc1.service" 1530 // svc2Name := "snap.hello-snap.svc2.service" 1531 svc2Timer := "snap.hello-snap.svc2.timer" 1532 svc3Timer := "snap.hello-snap.svc3.timer" 1533 1534 info := snaptest.MockSnap(c, packageHello+` 1535 svc2: 1536 command: bin/hello 1537 daemon: simple 1538 timer: 10:00-12:00 1539 svc3: 1540 command: bin/hello 1541 daemon: simple 1542 daemon-scope: user 1543 timer: 10:00-12:00 1544 `, &snap.SideInfo{Revision: snap.R(12)}) 1545 1546 // fix the apps order to make the test stable 1547 apps := []*snap.AppInfo{info.Apps["svc1"], info.Apps["svc2"], info.Apps["svc3"]} 1548 err := wrappers.StartServices(apps, nil, nil, &progress.Null, s.perfTimings) 1549 c.Assert(err, IsNil) 1550 c.Assert(s.sysdLog, HasLen, 6, Commentf("len: %v calls: %v", len(s.sysdLog), s.sysdLog)) 1551 c.Check(s.sysdLog, DeepEquals, [][]string{ 1552 {"--root", dirs.GlobalRootDir, "is-enabled", svc1Name}, 1553 {"--root", dirs.GlobalRootDir, "enable", svc2Timer}, 1554 {"start", svc2Timer}, 1555 {"--user", "--global", "--root", dirs.GlobalRootDir, "enable", svc3Timer}, 1556 {"--user", "start", svc3Timer}, 1557 {"start", svc1Name}, 1558 }, Commentf("calls: %v", s.sysdLog)) 1559 } 1560 1561 func (s *servicesTestSuite) TestStartSnapTimerCleanup(c *C) { 1562 var sysdLog [][]string 1563 svc1Name := "snap.hello-snap.svc1.service" 1564 svc2Name := "snap.hello-snap.svc2.service" 1565 svc2Timer := "snap.hello-snap.svc2.timer" 1566 1567 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 1568 sysdLog = append(sysdLog, cmd) 1569 if len(cmd) >= 2 && cmd[0] == "start" && cmd[1] == svc2Timer { 1570 return nil, fmt.Errorf("failed") 1571 } 1572 return []byte("ActiveState=inactive\n"), nil 1573 }) 1574 defer r() 1575 1576 info := snaptest.MockSnap(c, packageHello+` 1577 svc2: 1578 command: bin/hello 1579 daemon: simple 1580 timer: 10:00-12:00 1581 `, &snap.SideInfo{Revision: snap.R(12)}) 1582 1583 // fix the apps order to make the test stable 1584 apps := []*snap.AppInfo{info.Apps["svc1"], info.Apps["svc2"]} 1585 err := wrappers.StartServices(apps, nil, nil, &progress.Null, s.perfTimings) 1586 c.Assert(err, ErrorMatches, "failed") 1587 c.Assert(sysdLog, HasLen, 10, Commentf("len: %v calls: %v", len(sysdLog), sysdLog)) 1588 c.Check(sysdLog, DeepEquals, [][]string{ 1589 {"--root", dirs.GlobalRootDir, "is-enabled", svc1Name}, 1590 {"--root", dirs.GlobalRootDir, "enable", svc2Timer}, 1591 {"start", svc2Timer}, // this call fails 1592 {"stop", svc2Timer}, 1593 {"show", "--property=ActiveState", svc2Timer}, 1594 {"stop", svc2Name}, 1595 {"show", "--property=ActiveState", svc2Name}, 1596 {"--root", dirs.GlobalRootDir, "disable", svc2Timer}, 1597 {"stop", svc1Name}, 1598 {"show", "--property=ActiveState", svc1Name}, 1599 }, Commentf("calls: %v", sysdLog)) 1600 } 1601 1602 func (s *servicesTestSuite) TestAddRemoveSnapWithTimersAddsRemovesTimerFiles(c *C) { 1603 info := snaptest.MockSnap(c, packageHello+` 1604 svc2: 1605 command: bin/hello 1606 daemon: simple 1607 timer: 10:00-12:00 1608 `, &snap.SideInfo{Revision: snap.R(12)}) 1609 1610 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1611 c.Assert(err, IsNil) 1612 1613 app := info.Apps["svc2"] 1614 c.Assert(app.Timer, NotNil) 1615 1616 c.Check(osutil.FileExists(app.Timer.File()), Equals, true) 1617 c.Check(osutil.FileExists(app.ServiceFile()), Equals, true) 1618 1619 err = wrappers.StopServices(info.Services(), nil, "", &progress.Null, s.perfTimings) 1620 c.Assert(err, IsNil) 1621 1622 err = wrappers.RemoveSnapServices(info, &progress.Null) 1623 c.Assert(err, IsNil) 1624 1625 c.Check(osutil.FileExists(app.Timer.File()), Equals, false) 1626 c.Check(osutil.FileExists(app.ServiceFile()), Equals, false) 1627 } 1628 1629 func (s *servicesTestSuite) TestFailedAddSnapCleansUp(c *C) { 1630 info := snaptest.MockSnap(c, packageHello+` 1631 svc2: 1632 command: bin/hello 1633 daemon: simple 1634 timer: 10:00-12:00 1635 svc3: 1636 command: bin/hello 1637 daemon: simple 1638 plugs: [network-bind] 1639 sockets: 1640 sock1: 1641 listen-stream: $SNAP_COMMON/sock1.socket 1642 socket-mode: 0666 1643 `, &snap.SideInfo{Revision: snap.R(12)}) 1644 1645 calls := 0 1646 r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) { 1647 if len(cmd) == 1 && cmd[0] == "daemon-reload" && calls == 0 { 1648 // only fail the first systemd daemon-reload call, the 1649 // second one is at the end of cleanup 1650 calls += 1 1651 return nil, fmt.Errorf("failed") 1652 } 1653 return []byte("ActiveState=inactive\n"), nil 1654 }) 1655 defer r() 1656 1657 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1658 c.Assert(err, NotNil) 1659 1660 c.Logf("services dir: %v", dirs.SnapServicesDir) 1661 matches, err := filepath.Glob(dirs.SnapServicesDir + "/*") 1662 c.Assert(err, IsNil) 1663 c.Assert(matches, HasLen, 0, Commentf("the following autogenerated files were left behind: %v", matches)) 1664 } 1665 1666 func (s *servicesTestSuite) TestAddServicesDidReload(c *C) { 1667 const base = `name: hello-snap 1668 version: 1.10 1669 summary: hello 1670 description: Hello... 1671 apps: 1672 ` 1673 onlyServices := snaptest.MockSnap(c, base+` 1674 svc1: 1675 command: bin/hello 1676 daemon: simple 1677 `, &snap.SideInfo{Revision: snap.R(12)}) 1678 1679 onlySockets := snaptest.MockSnap(c, base+` 1680 svc1: 1681 command: bin/hello 1682 daemon: simple 1683 plugs: [network-bind] 1684 sockets: 1685 sock1: 1686 listen-stream: $SNAP_COMMON/sock1.socket 1687 socket-mode: 0666 1688 `, &snap.SideInfo{Revision: snap.R(12)}) 1689 1690 onlyTimers := snaptest.MockSnap(c, base+` 1691 svc1: 1692 command: bin/hello 1693 daemon: oneshot 1694 timer: 10:00-12:00 1695 `, &snap.SideInfo{Revision: snap.R(12)}) 1696 1697 for i, info := range []*snap.Info{onlyServices, onlySockets, onlyTimers} { 1698 s.sysdLog = nil 1699 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1700 c.Assert(err, IsNil) 1701 reloads := 0 1702 c.Logf("calls: %v", s.sysdLog) 1703 for _, call := range s.sysdLog { 1704 if strutil.ListContains(call, "daemon-reload") { 1705 reloads += 1 1706 } 1707 } 1708 c.Check(reloads >= 1, Equals, true, Commentf("test-case %v did not reload services as expected", i)) 1709 } 1710 } 1711 1712 func (s *servicesTestSuite) TestSnapServicesActivation(c *C) { 1713 const snapYaml = `name: hello-snap 1714 version: 1.10 1715 summary: hello 1716 description: Hello... 1717 apps: 1718 svc1: 1719 command: bin/hello 1720 daemon: simple 1721 plugs: [network-bind] 1722 sockets: 1723 sock1: 1724 listen-stream: $SNAP_COMMON/sock1.socket 1725 socket-mode: 0666 1726 svc2: 1727 command: bin/hello 1728 daemon: oneshot 1729 timer: 10:00-12:00 1730 svc3: 1731 command: bin/hello 1732 daemon: simple 1733 ` 1734 1735 svc3Name := "snap.hello-snap.svc3.service" 1736 1737 info := snaptest.MockSnap(c, snapYaml, &snap.SideInfo{Revision: snap.R(12)}) 1738 1739 // fix the apps order to make the test stable 1740 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1741 c.Assert(err, IsNil) 1742 c.Assert(s.sysdLog, HasLen, 2, Commentf("len: %v calls: %v", len(s.sysdLog), s.sysdLog)) 1743 c.Check(s.sysdLog, DeepEquals, [][]string{ 1744 // only svc3 gets started during boot 1745 {"--root", dirs.GlobalRootDir, "enable", svc3Name}, 1746 {"daemon-reload"}, 1747 }, Commentf("calls: %v", s.sysdLog)) 1748 } 1749 1750 func (s *servicesTestSuite) TestServiceRestartDelay(c *C) { 1751 snapYaml := packageHello + ` 1752 svc2: 1753 daemon: forking 1754 restart-delay: 12s 1755 svc3: 1756 daemon: forking 1757 ` 1758 info := snaptest.MockSnap(c, snapYaml, &snap.SideInfo{Revision: snap.R(12)}) 1759 1760 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1761 c.Assert(err, IsNil) 1762 1763 content, err := ioutil.ReadFile(filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc2.service")) 1764 c.Assert(err, IsNil) 1765 c.Check(strings.Contains(string(content), "\nRestartSec=12\n"), Equals, true) 1766 1767 content, err = ioutil.ReadFile(filepath.Join(s.tempdir, "/etc/systemd/system/snap.hello-snap.svc3.service")) 1768 c.Assert(err, IsNil) 1769 c.Check(strings.Contains(string(content), "RestartSec="), Equals, false) 1770 } 1771 1772 func (s *servicesTestSuite) TestAddRemoveSnapServiceWithSnapd(c *C) { 1773 info := makeMockSnapdSnap(c) 1774 1775 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1776 c.Check(err, ErrorMatches, "internal error: adding explicit services for snapd snap is unexpected") 1777 1778 err = wrappers.RemoveSnapServices(info, progress.Null) 1779 c.Check(err, ErrorMatches, "internal error: removing explicit services for snapd snap is unexpected") 1780 } 1781 1782 func (s *servicesTestSuite) TestReloadOrRestart(c *C) { 1783 const surviveYaml = `name: test-snap 1784 version: 1.0 1785 apps: 1786 foo: 1787 command: bin/foo 1788 daemon: simple 1789 ` 1790 info := snaptest.MockSnap(c, surviveYaml, &snap.SideInfo{Revision: snap.R(1)}) 1791 srvFile := "snap.test-snap.foo.service" 1792 1793 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1794 c.Assert(err, IsNil) 1795 1796 s.sysdLog = nil 1797 flags := &wrappers.RestartServicesFlags{Reload: true} 1798 c.Assert(wrappers.RestartServices(info.Services(), flags, progress.Null, s.perfTimings), IsNil) 1799 c.Assert(err, IsNil) 1800 c.Check(s.sysdLog, DeepEquals, [][]string{ 1801 {"reload-or-restart", srvFile}, 1802 }) 1803 1804 s.sysdLog = nil 1805 flags.Reload = false 1806 c.Assert(wrappers.RestartServices(info.Services(), flags, progress.Null, s.perfTimings), IsNil) 1807 c.Check(s.sysdLog, DeepEquals, [][]string{ 1808 {"stop", srvFile}, 1809 {"show", "--property=ActiveState", srvFile}, 1810 {"start", srvFile}, 1811 }) 1812 1813 s.sysdLog = nil 1814 c.Assert(wrappers.RestartServices(info.Services(), nil, progress.Null, s.perfTimings), IsNil) 1815 c.Check(s.sysdLog, DeepEquals, [][]string{ 1816 {"stop", srvFile}, 1817 {"show", "--property=ActiveState", srvFile}, 1818 {"start", srvFile}, 1819 }) 1820 } 1821 1822 func (s *servicesTestSuite) TestStopAndDisableServices(c *C) { 1823 info := snaptest.MockSnap(c, packageHello+` 1824 svc1: 1825 daemon: simple 1826 `, &snap.SideInfo{Revision: snap.R(12)}) 1827 svcFile := "snap.hello-snap.svc1.service" 1828 1829 err := wrappers.AddSnapServices(info, nil, nil, progress.Null) 1830 c.Assert(err, IsNil) 1831 1832 s.sysdLog = nil 1833 flags := &wrappers.StopServicesFlags{Disable: true} 1834 err = wrappers.StopServices(info.Services(), flags, "", progress.Null, s.perfTimings) 1835 c.Assert(err, IsNil) 1836 c.Check(s.sysdLog, DeepEquals, [][]string{ 1837 {"stop", svcFile}, 1838 {"show", "--property=ActiveState", svcFile}, 1839 {"--root", s.tempdir, "disable", svcFile}, 1840 }) 1841 }