github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/configstate/configcore/services_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 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 configcore_test 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 28 . "gopkg.in/check.v1" 29 30 "github.com/snapcore/snapd/dirs" 31 "github.com/snapcore/snapd/overlord/configstate/configcore" 32 "github.com/snapcore/snapd/release" 33 "github.com/snapcore/snapd/snap" 34 "github.com/snapcore/snapd/testutil" 35 ) 36 37 type servicesSuite struct { 38 configcoreSuite 39 } 40 41 var _ = Suite(&servicesSuite{}) 42 43 func (s *servicesSuite) SetUpTest(c *C) { 44 s.configcoreSuite.SetUpTest(c) 45 c.Assert(os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "etc"), 0755), IsNil) 46 s.systemctlArgs = nil 47 s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 48 } 49 50 func (s *servicesSuite) TestConfigureServiceInvalidValue(c *C) { 51 restore := release.MockOnClassic(false) 52 defer restore() 53 54 err := configcore.Run(&mockConf{ 55 state: s.state, 56 changes: map[string]interface{}{ 57 "service.ssh.disable": "xxx", 58 }, 59 }) 60 c.Check(err, ErrorMatches, `option "service.ssh.disable" has invalid value "xxx"`) 61 } 62 63 func (s *servicesSuite) TestConfigureServiceNotDisabled(c *C) { 64 err := configcore.SwitchDisableService("sshd.service", false, nil) 65 c.Assert(err, IsNil) 66 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 67 {"--root", dirs.GlobalRootDir, "unmask", "sshd.service"}, 68 {"--root", dirs.GlobalRootDir, "enable", "sshd.service"}, 69 {"start", "sshd.service"}, 70 }) 71 } 72 73 func (s *servicesSuite) TestConfigureServiceDisabled(c *C) { 74 err := configcore.SwitchDisableService("sshd.service", true, nil) 75 c.Assert(err, IsNil) 76 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 77 {"--root", dirs.GlobalRootDir, "disable", "sshd.service"}, 78 {"--root", dirs.GlobalRootDir, "mask", "sshd.service"}, 79 {"stop", "sshd.service"}, 80 {"show", "--property=ActiveState", "sshd.service"}, 81 }) 82 } 83 84 func (s *servicesSuite) TestConfigureServiceDisabledIntegration(c *C) { 85 restore := release.MockOnClassic(false) 86 defer restore() 87 88 err := os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "/etc/ssh"), 0755) 89 c.Assert(err, IsNil) 90 91 for _, service := range []struct { 92 cfgName string 93 systemdName string 94 }{ 95 {"ssh", "ssh.service"}, 96 {"rsyslog", "rsyslog.service"}, 97 } { 98 s.systemctlArgs = nil 99 100 err := configcore.Run(&mockConf{ 101 state: s.state, 102 conf: map[string]interface{}{ 103 fmt.Sprintf("service.%s.disable", service.cfgName): true, 104 }, 105 }) 106 c.Assert(err, IsNil) 107 srv := service.systemdName 108 switch service.cfgName { 109 case "ssh": 110 sshCanary := filepath.Join(dirs.GlobalRootDir, "/etc/ssh/sshd_not_to_be_run") 111 _, err := os.Stat(sshCanary) 112 c.Assert(err, IsNil) 113 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 114 {"stop", srv}, 115 {"show", "--property=ActiveState", srv}, 116 }) 117 default: 118 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 119 {"--root", dirs.GlobalRootDir, "disable", srv}, 120 {"--root", dirs.GlobalRootDir, "mask", srv}, 121 {"stop", srv}, 122 {"show", "--property=ActiveState", srv}, 123 }) 124 } 125 } 126 } 127 128 func (s *servicesSuite) TestConfigureConsoleConfDisableFSOnly(c *C) { 129 restore := release.MockOnClassic(false) 130 defer restore() 131 132 conf := configcore.PlainCoreConfig(map[string]interface{}{ 133 "service.console-conf.disable": true, 134 }) 135 136 tmpDir := c.MkDir() 137 c.Assert(configcore.FilesystemOnlyApply(tmpDir, conf, nil), IsNil) 138 139 consoleConfDisabled := filepath.Join(tmpDir, "/var/lib/console-conf/complete") 140 c.Check(consoleConfDisabled, testutil.FileEquals, "console-conf has been disabled by the snapd system configuration\n") 141 } 142 143 func (s *servicesSuite) TestConfigureConsoleConfEnabledFSOnly(c *C) { 144 restore := release.MockOnClassic(false) 145 defer restore() 146 147 conf := configcore.PlainCoreConfig(map[string]interface{}{ 148 "service.console-conf.disable": false, 149 }) 150 151 tmpDir := c.MkDir() 152 c.Assert(configcore.FilesystemOnlyApply(tmpDir, conf, nil), IsNil) 153 154 consoleConfDisabled := filepath.Join(tmpDir, "/var/lib/console-conf/complete") 155 c.Check(consoleConfDisabled, testutil.FileAbsent) 156 } 157 158 func (s *servicesSuite) TestConfigureConsoleConfEnableNotAtRuntime(c *C) { 159 restore := release.MockOnClassic(false) 160 defer restore() 161 162 // pretend that console-conf is disabled 163 canary := filepath.Join(dirs.GlobalRootDir, "/var/lib/console-conf/complete") 164 err := os.MkdirAll(filepath.Dir(canary), 0755) 165 c.Assert(err, IsNil) 166 err = ioutil.WriteFile(canary, nil, 0644) 167 c.Assert(err, IsNil) 168 169 // now enable it 170 err = configcore.Run(&mockConf{ 171 state: s.state, 172 conf: map[string]interface{}{ 173 "service.console-conf.disable": false, 174 }, 175 }) 176 c.Assert(err, ErrorMatches, "cannot toggle console-conf at runtime, but only initially via gadget defaults") 177 } 178 179 func (s *servicesSuite) TestConfigureConsoleConfDisableNotAtRuntime(c *C) { 180 restore := release.MockOnClassic(false) 181 defer restore() 182 183 // console-conf is not disabled, i.e. there is no 184 // "/var/lib/console-conf/complete" file 185 186 // now try to enable it 187 err := configcore.Run(&mockConf{ 188 state: s.state, 189 conf: map[string]interface{}{ 190 "service.console-conf.disable": true, 191 }, 192 }) 193 c.Assert(err, ErrorMatches, "cannot toggle console-conf at runtime, but only initially via gadget defaults") 194 } 195 196 func (s *servicesSuite) TestConfigureConsoleConfEnableAlreadyEnabledIsFine(c *C) { 197 restore := release.MockOnClassic(false) 198 defer restore() 199 200 // Note that we have no 201 // /var/lib/console-conf/complete 202 // file. So console-conf is already enabled 203 err := configcore.Run(&mockConf{ 204 state: s.state, 205 conf: map[string]interface{}{ 206 "service.console-conf.disable": false, 207 }, 208 }) 209 c.Assert(err, IsNil) 210 } 211 212 func (s *servicesSuite) TestConfigureConsoleConfDisableAlreadyDisabledIsFine(c *C) { 213 restore := release.MockOnClassic(false) 214 defer restore() 215 216 // pretend that console-conf is disabled 217 canary := filepath.Join(dirs.GlobalRootDir, "/var/lib/console-conf/complete") 218 err := os.MkdirAll(filepath.Dir(canary), 0755) 219 c.Assert(err, IsNil) 220 err = ioutil.WriteFile(canary, nil, 0644) 221 c.Assert(err, IsNil) 222 223 err = configcore.Run(&mockConf{ 224 state: s.state, 225 conf: map[string]interface{}{ 226 "service.console-conf.disable": true, 227 }, 228 }) 229 c.Assert(err, IsNil) 230 } 231 232 func (s *servicesSuite) TestConfigureServiceEnableIntegration(c *C) { 233 restore := release.MockOnClassic(false) 234 defer restore() 235 236 err := os.MkdirAll(filepath.Join(dirs.GlobalRootDir, "/etc/ssh"), 0755) 237 c.Assert(err, IsNil) 238 239 for _, service := range []struct { 240 cfgName string 241 systemdName string 242 }{ 243 {"ssh", "ssh.service"}, 244 {"rsyslog", "rsyslog.service"}, 245 } { 246 s.systemctlArgs = nil 247 err := configcore.Run(&mockConf{ 248 state: s.state, 249 conf: map[string]interface{}{ 250 fmt.Sprintf("service.%s.disable", service.cfgName): false, 251 }, 252 }) 253 254 c.Assert(err, IsNil) 255 srv := service.systemdName 256 switch service.cfgName { 257 case "ssh": 258 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 259 {"--root", dirs.GlobalRootDir, "unmask", "sshd.service"}, 260 {"--root", dirs.GlobalRootDir, "unmask", "ssh.service"}, 261 {"start", srv}, 262 }) 263 sshCanary := filepath.Join(dirs.GlobalRootDir, "/etc/ssh/sshd_not_to_be_run") 264 _, err := os.Stat(sshCanary) 265 c.Assert(err, ErrorMatches, ".* no such file or directory") 266 default: 267 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 268 {"--root", dirs.GlobalRootDir, "unmask", srv}, 269 {"--root", dirs.GlobalRootDir, "enable", srv}, 270 {"start", srv}, 271 }) 272 } 273 } 274 } 275 276 func (s *servicesSuite) TestConfigureServiceUnsupportedService(c *C) { 277 restore := release.MockOnClassic(false) 278 defer restore() 279 280 err := configcore.Run(&mockConf{ 281 state: s.state, 282 conf: map[string]interface{}{ 283 "service.snapd.disable": true, 284 }, 285 }) 286 c.Assert(err, IsNil) 287 288 // ensure nothing gets enabled/disabled when an unsupported 289 // service is set for disable 290 c.Check(s.systemctlArgs, IsNil) 291 } 292 293 func (s *servicesSuite) TestFilesystemOnlyApply(c *C) { 294 tmpDir := c.MkDir() 295 c.Assert(os.MkdirAll(filepath.Join(tmpDir, "etc", "ssh"), 0755), IsNil) 296 297 conf := configcore.PlainCoreConfig(map[string]interface{}{ 298 "service.ssh.disable": "true", 299 "service.rsyslog.disable": "true", 300 }) 301 c.Assert(configcore.FilesystemOnlyApply(tmpDir, conf, nil), IsNil) 302 c.Check(s.systemctlArgs, DeepEquals, [][]string{ 303 {"--root", tmpDir, "mask", "rsyslog.service"}, 304 }) 305 }