github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/interfaces/systemd/backend_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2017 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 systemd_test 21 22 import ( 23 "os" 24 "path/filepath" 25 26 . "gopkg.in/check.v1" 27 28 "github.com/snapcore/snapd/dirs" 29 "github.com/snapcore/snapd/interfaces" 30 "github.com/snapcore/snapd/interfaces/ifacetest" 31 "github.com/snapcore/snapd/interfaces/systemd" 32 "github.com/snapcore/snapd/snap" 33 sysd "github.com/snapcore/snapd/systemd" 34 ) 35 36 type backendSuite struct { 37 ifacetest.BackendSuite 38 39 systemctlArgs [][]string 40 systemctlRestorer func() 41 } 42 43 var _ = Suite(&backendSuite{}) 44 45 var testedConfinementOpts = []interfaces.ConfinementOptions{ 46 {}, 47 {DevMode: true}, 48 {JailMode: true}, 49 {Classic: true}, 50 } 51 52 func (s *backendSuite) SetUpTest(c *C) { 53 s.Backend = &systemd.Backend{} 54 s.BackendSuite.SetUpTest(c) 55 c.Assert(s.Repo.AddBackend(s.Backend), IsNil) 56 s.systemctlRestorer = sysd.MockSystemctl(func(args ...string) ([]byte, error) { 57 s.systemctlArgs = append(s.systemctlArgs, append([]string{"systemctl"}, args...)) 58 return []byte("ActiveState=inactive"), nil 59 }) 60 } 61 62 func (s *backendSuite) TearDownTest(c *C) { 63 s.systemctlRestorer() 64 s.BackendSuite.TearDownTest(c) 65 } 66 67 func (s *backendSuite) TestName(c *C) { 68 c.Check(s.Backend.Name(), Equals, interfaces.SecuritySystemd) 69 } 70 71 func (s *backendSuite) TestInstallingSnapWritesStartsServices(c *C) { 72 var sysdLog [][]string 73 74 r := sysd.MockSystemctl(func(cmd ...string) ([]byte, error) { 75 sysdLog = append(sysdLog, cmd) 76 if cmd[0] == "show" { 77 return []byte("ActiveState=inactive\n"), nil 78 } 79 return []byte{}, nil 80 }) 81 defer r() 82 83 s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { 84 return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) 85 } 86 s.InstallSnap(c, interfaces.ConfinementOptions{}, "", ifacetest.SambaYamlV1, 1) 87 service := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") 88 // the service file was created 89 _, err := os.Stat(service) 90 c.Check(err, IsNil) 91 // the service was also started (whee) 92 c.Check(sysdLog, DeepEquals, [][]string{ 93 {"daemon-reload"}, 94 {"enable", "snap.samba.interface.foo.service"}, 95 {"stop", "snap.samba.interface.foo.service"}, 96 {"show", "--property=ActiveState", "snap.samba.interface.foo.service"}, 97 {"start", "snap.samba.interface.foo.service"}, 98 }) 99 } 100 101 func (s *backendSuite) TestRemovingSnapRemovesAndStopsServices(c *C) { 102 s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { 103 return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) 104 } 105 for _, opts := range testedConfinementOpts { 106 snapInfo := s.InstallSnap(c, opts, "", ifacetest.SambaYamlV1, 1) 107 s.systemctlArgs = nil 108 s.RemoveSnap(c, snapInfo) 109 service := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") 110 // the service file was removed 111 _, err := os.Stat(service) 112 c.Check(os.IsNotExist(err), Equals, true) 113 // the service was stopped 114 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 115 {"systemctl", "disable", "snap.samba.interface.foo.service"}, 116 {"systemctl", "stop", "snap.samba.interface.foo.service"}, 117 {"systemctl", "show", "--property=ActiveState", "snap.samba.interface.foo.service"}, 118 {"systemctl", "daemon-reload"}, 119 }) 120 } 121 } 122 123 func (s *backendSuite) TestSettingUpSecurityWithFewerServices(c *C) { 124 s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { 125 err := spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) 126 if err != nil { 127 return err 128 } 129 return spec.AddService("snap.samba.interface.bar.service", &systemd.Service{ExecStart: "/bin/false"}) 130 } 131 snapInfo := s.InstallSnap(c, interfaces.ConfinementOptions{}, "", ifacetest.SambaYamlV1, 1) 132 s.systemctlArgs = nil 133 serviceFoo := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") 134 serviceBar := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.bar.service") 135 // the services were created 136 _, err := os.Stat(serviceFoo) 137 c.Check(err, IsNil) 138 _, err = os.Stat(serviceBar) 139 c.Check(err, IsNil) 140 141 // Change what the interface returns to simulate some useful change 142 s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { 143 return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) 144 } 145 // Update over to the same snap to regenerate security 146 s.UpdateSnap(c, snapInfo, interfaces.ConfinementOptions{}, ifacetest.SambaYamlV1, 0) 147 // The bar service should have been stopped 148 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 149 {"systemctl", "disable", "snap.samba.interface.bar.service"}, 150 {"systemctl", "stop", "snap.samba.interface.bar.service"}, 151 {"systemctl", "show", "--property=ActiveState", "snap.samba.interface.bar.service"}, 152 {"systemctl", "daemon-reload"}, 153 }) 154 } 155 156 func (s *backendSuite) TestSandboxFeatures(c *C) { 157 c.Assert(s.Backend.SandboxFeatures(), IsNil) 158 } 159 160 func (s *backendSuite) TestInstallingSnapWhenPreseeding(c *C) { 161 s.Backend = &systemd.Backend{} 162 opts := &interfaces.SecurityBackendOptions{Preseed: true} 163 s.Backend.Initialize(opts) 164 165 var sysdLog [][]string 166 r := sysd.MockSystemctl(func(cmd ...string) ([]byte, error) { 167 sysdLog = append(sysdLog, cmd) 168 return []byte{}, nil 169 }) 170 defer r() 171 172 s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { 173 return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) 174 } 175 s.InstallSnap(c, interfaces.ConfinementOptions{}, "", ifacetest.SambaYamlV1, 1) 176 service := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") 177 // the service file was created 178 _, err := os.Stat(service) 179 c.Check(err, IsNil) 180 // the service was enabled but not started 181 c.Check(sysdLog, DeepEquals, [][]string{ 182 {"--root", dirs.GlobalRootDir, "enable", "snap.samba.interface.foo.service"}, 183 }) 184 } 185 186 // not a viable scenario, but tested for completness 187 func (s *backendSuite) TestRemovingSnapWhenPreseeding(c *C) { 188 s.Backend = &systemd.Backend{} 189 opts := &interfaces.SecurityBackendOptions{Preseed: true} 190 s.Backend.Initialize(opts) 191 192 s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { 193 return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) 194 } 195 for _, opts := range testedConfinementOpts { 196 snapInfo := s.InstallSnap(c, opts, "", ifacetest.SambaYamlV1, 1) 197 s.systemctlArgs = nil 198 s.RemoveSnap(c, snapInfo) 199 service := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") 200 // the service file was removed 201 _, err := os.Stat(service) 202 c.Check(os.IsNotExist(err), Equals, true) 203 // the service was disabled (but no other systemctl calls) 204 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 205 {"systemctl", "--root", dirs.GlobalRootDir, "disable", "snap.samba.interface.foo.service"}, 206 }) 207 } 208 }