github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/service/discovery_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package service_test 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "runtime" 11 "strings" 12 13 "github.com/juju/errors" 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils/exec" 16 "github.com/juju/utils/featureflag" 17 jujuos "github.com/juju/utils/os" 18 "github.com/juju/utils/series" 19 "github.com/juju/version" 20 gc "gopkg.in/check.v1" 21 22 "github.com/juju/juju/feature" 23 "github.com/juju/juju/juju/osenv" 24 "github.com/juju/juju/service" 25 "github.com/juju/juju/service/common" 26 "github.com/juju/juju/service/systemd" 27 "github.com/juju/juju/service/upstart" 28 "github.com/juju/juju/service/windows" 29 ) 30 31 var maybeSystemd = service.InitSystemSystemd 32 33 func init() { 34 if featureflag.Enabled(feature.LegacyUpstart) { 35 maybeSystemd = service.InitSystemUpstart 36 } 37 } 38 39 const unknownExecutable = "/sbin/unknown/init/system" 40 41 type discoveryTest struct { 42 os jujuos.OSType 43 series string 44 expected string 45 } 46 47 func (dt discoveryTest) version() version.Binary { 48 return version.Binary{ 49 Series: dt.series, 50 } 51 } 52 53 func (dt discoveryTest) log(c *gc.C) { 54 c.Logf(" - testing {%q, %q}...", dt.os, dt.series) 55 } 56 57 func (dt discoveryTest) disableLocalDiscovery(c *gc.C, s *discoverySuite) { 58 s.PatchLocalDiscoveryDisable() 59 } 60 61 func (dt discoveryTest) disableVersionDiscovery(s *discoverySuite) { 62 dt.os = jujuos.Unknown 63 dt.setVersion(s) 64 } 65 66 func (dt discoveryTest) setLocal(c *gc.C, s *discoverySuite) { 67 s.PatchLocalDiscoveryNoMatch(dt.expected) 68 } 69 70 func (dt discoveryTest) setVersion(s *discoverySuite) version.Binary { 71 vers := dt.version() 72 s.PatchSeries(vers.Series) 73 return vers 74 } 75 76 func (dt discoveryTest) checkService(c *gc.C, svc service.Service, err error, name string, conf common.Conf) { 77 if dt.expected == "" { 78 c.Check(err, jc.Satisfies, errors.IsNotFound) 79 return 80 } 81 82 // Check the success case. 83 if !c.Check(err, jc.ErrorIsNil) { 84 return 85 } 86 switch dt.expected { 87 case service.InitSystemUpstart: 88 c.Check(svc, gc.FitsTypeOf, &upstart.Service{}) 89 case service.InitSystemSystemd: 90 c.Check(svc, gc.FitsTypeOf, &systemd.Service{}) 91 case service.InitSystemWindows: 92 c.Check(svc, gc.FitsTypeOf, &windows.Service{}) 93 default: 94 c.Errorf("unknown expected init system %q", dt.expected) 95 return 96 } 97 if svc == nil { 98 return 99 } 100 101 c.Check(svc.Name(), gc.Equals, name) 102 c.Check(svc.Conf(), jc.DeepEquals, conf) 103 } 104 105 func (dt discoveryTest) checkInitSystem(c *gc.C, name string, err error) { 106 if dt.expected == "" { 107 if !c.Check(err, jc.Satisfies, errors.IsNotFound) { 108 c.Logf("found init system %q", name) 109 } 110 } else { 111 c.Check(err, jc.ErrorIsNil) 112 c.Check(name, gc.Equals, dt.expected) 113 } 114 } 115 116 var discoveryTests = []discoveryTest{{ 117 os: jujuos.Windows, 118 series: "win2012", 119 expected: service.InitSystemWindows, 120 }, { 121 os: jujuos.Ubuntu, 122 series: "oneiric", 123 expected: "", 124 }, { 125 os: jujuos.Ubuntu, 126 series: "precise", 127 expected: service.InitSystemUpstart, 128 }, { 129 os: jujuos.Ubuntu, 130 series: "utopic", 131 expected: service.InitSystemUpstart, 132 }, { 133 os: jujuos.Ubuntu, 134 series: "vivid", 135 expected: maybeSystemd, 136 }, { 137 os: jujuos.CentOS, 138 series: "centos7", 139 expected: service.InitSystemSystemd, 140 }, { 141 os: jujuos.Unknown, 142 expected: "", 143 }} 144 145 type discoverySuite struct { 146 service.BaseSuite 147 148 name string 149 conf common.Conf 150 } 151 152 var _ = gc.Suite(&discoverySuite{}) 153 154 func (s *discoverySuite) SetUpTest(c *gc.C) { 155 s.BaseSuite.SetUpTest(c) 156 157 s.name = "a-service" 158 s.conf = common.Conf{ 159 Desc: "some service", 160 ExecStart: "/path/to/some-command", 161 } 162 } 163 164 func (s *discoverySuite) unsetLegacyUpstart(c *gc.C) { 165 err := os.Setenv(osenv.JujuFeatureFlagEnvKey, "") 166 c.Assert(err, jc.ErrorIsNil) 167 featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey) 168 } 169 170 func (s *discoverySuite) setLegacyUpstart(c *gc.C) { 171 err := os.Setenv(osenv.JujuFeatureFlagEnvKey, feature.LegacyUpstart) 172 c.Assert(err, jc.ErrorIsNil) 173 featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey) 174 } 175 176 func (s *discoverySuite) TestDiscoverServiceLocalHost(c *gc.C) { 177 var localInitSystem string 178 var err error 179 switch runtime.GOOS { 180 case "windows": 181 localInitSystem = service.InitSystemWindows 182 case "linux": 183 localInitSystem, err = service.VersionInitSystem(series.HostSeries()) 184 } 185 c.Assert(err, gc.IsNil) 186 187 test := discoveryTest{ 188 os: jujuos.HostOS(), 189 series: series.HostSeries(), 190 expected: localInitSystem, 191 } 192 test.disableVersionDiscovery(s) 193 194 svc, err := service.DiscoverService(s.name, s.conf) 195 c.Assert(err, jc.ErrorIsNil) 196 197 test.checkService(c, svc, err, s.name, s.conf) 198 } 199 200 func (s *discoverySuite) TestDiscoverServiceVersionFallback(c *gc.C) { 201 for _, test := range discoveryTests { 202 test.log(c) 203 204 test.disableLocalDiscovery(c, s) 205 test.setVersion(s) 206 207 svc, err := service.DiscoverService(s.name, s.conf) 208 209 test.checkService(c, svc, err, s.name, s.conf) 210 } 211 } 212 213 func (s *discoverySuite) TestVersionInitSystem(c *gc.C) { 214 for _, test := range discoveryTests { 215 test.log(c) 216 initSystem, err := service.VersionInitSystem(test.series) 217 test.checkInitSystem(c, initSystem, err) 218 } 219 } 220 221 func (s *discoverySuite) TestVersionInitSystemLegacyUpstart(c *gc.C) { 222 s.setLegacyUpstart(c) 223 test := discoveryTest{ 224 os: jujuos.Ubuntu, 225 series: "vivid", 226 expected: service.InitSystemUpstart, 227 } 228 vers := test.setVersion(s) 229 230 initSystem, err := service.VersionInitSystem(vers.Series) 231 232 test.checkInitSystem(c, initSystem, err) 233 } 234 235 func (s *discoverySuite) TestVersionInitSystemNoLegacyUpstart(c *gc.C) { 236 s.unsetLegacyUpstart(c) 237 test := discoveryTest{ 238 os: jujuos.Ubuntu, 239 series: "vivid", 240 expected: service.InitSystemSystemd, 241 } 242 vers := test.setVersion(s) 243 244 initSystem, err := service.VersionInitSystem(vers.Series) 245 246 test.checkInitSystem(c, initSystem, err) 247 } 248 249 func (s *discoverySuite) TestDiscoverLocalInitSystemMatchFirst(c *gc.C) { 250 s.PatchLocalDiscovery( 251 service.NewDiscoveryCheck("initA", true, nil), 252 service.NewDiscoveryCheck("initB", false, nil), 253 ) 254 255 name, err := service.DiscoverLocalInitSystem() 256 c.Assert(err, jc.ErrorIsNil) 257 258 c.Check(name, gc.Equals, "initA") 259 } 260 261 func (s *discoverySuite) TestDiscoverLocalInitSystemErrorFirst(c *gc.C) { 262 failure := errors.New("<failed>") 263 s.PatchLocalDiscovery( 264 service.NewDiscoveryCheck("initA", false, failure), 265 service.NewDiscoveryCheck("initB", true, nil), 266 ) 267 268 name, err := service.DiscoverLocalInitSystem() 269 c.Assert(err, jc.ErrorIsNil) 270 271 c.Check(name, gc.Equals, "initB") 272 } 273 274 func (s *discoverySuite) TestDiscoverLocalInitSystemMatchFirstError(c *gc.C) { 275 failure := errors.New("<failed>") 276 s.PatchLocalDiscovery( 277 service.NewDiscoveryCheck("initA", true, failure), 278 service.NewDiscoveryCheck("initB", false, nil), 279 ) 280 281 name, err := service.DiscoverLocalInitSystem() 282 c.Assert(err, jc.ErrorIsNil) 283 284 c.Check(name, gc.Equals, "initA") 285 } 286 287 func (s *discoverySuite) TestDiscoverLocalInitSystemMatchSecond(c *gc.C) { 288 s.PatchLocalDiscovery( 289 service.NewDiscoveryCheck("initA", false, nil), 290 service.NewDiscoveryCheck("initB", true, nil), 291 ) 292 293 name, err := service.DiscoverLocalInitSystem() 294 c.Assert(err, jc.ErrorIsNil) 295 296 c.Check(name, gc.Equals, "initB") 297 } 298 299 func (s *discoverySuite) TestDiscoverLocalInitSystemMatchNone(c *gc.C) { 300 s.PatchLocalDiscovery( 301 service.NewDiscoveryCheck("initA", false, nil), 302 service.NewDiscoveryCheck("initB", false, nil), 303 ) 304 305 _, err := service.DiscoverLocalInitSystem() 306 307 c.Check(err, jc.Satisfies, errors.IsNotFound) 308 } 309 310 func (s *discoverySuite) TestDiscoverLocalInitSystemErrorMixed(c *gc.C) { 311 failure := errors.New("<failed>") 312 s.PatchLocalDiscovery( 313 service.NewDiscoveryCheck("initA", false, failure), 314 service.NewDiscoveryCheck("initB", false, nil), 315 ) 316 317 _, err := service.DiscoverLocalInitSystem() 318 319 c.Check(err, jc.Satisfies, errors.IsNotFound) 320 } 321 322 func (s *discoverySuite) TestDiscoverLocalInitSystemErrorAll(c *gc.C) { 323 failureA := errors.New("<failed A>") 324 failureB := errors.New("<failed B>") 325 s.PatchLocalDiscovery( 326 service.NewDiscoveryCheck("initA", false, failureA), 327 service.NewDiscoveryCheck("initB", false, failureB), 328 ) 329 330 _, err := service.DiscoverLocalInitSystem() 331 332 c.Check(err, jc.Satisfies, errors.IsNotFound) 333 } 334 335 func (s *discoverySuite) TestDiscoverInitSystemScriptBash(c *gc.C) { 336 if runtime.GOOS == "windows" { 337 c.Skip("not supported on windows") 338 } 339 340 script, filename := s.newDiscoverInitSystemScript(c) 341 script += filename 342 response, err := exec.RunCommands(exec.RunParams{ 343 Commands: script, 344 }) 345 c.Assert(err, jc.ErrorIsNil) 346 347 initSystem, err := service.DiscoverInitSystem() 348 c.Assert(err, jc.ErrorIsNil) 349 c.Check(response.Code, gc.Equals, 0) 350 c.Check(string(response.Stdout), gc.Equals, initSystem) 351 c.Check(string(response.Stderr), gc.Equals, "") 352 } 353 354 func (s *discoverySuite) TestDiscoverInitSystemScriptPosix(c *gc.C) { 355 if runtime.GOOS == "windows" { 356 c.Skip("not supported on windows") 357 } 358 359 script, filename := s.newDiscoverInitSystemScript(c) 360 script += "sh " + filename 361 response, err := exec.RunCommands(exec.RunParams{ 362 Commands: script, 363 }) 364 c.Assert(err, jc.ErrorIsNil) 365 366 initSystem, err := service.DiscoverInitSystem() 367 c.Assert(err, jc.ErrorIsNil) 368 c.Check(response.Code, gc.Equals, 0) 369 c.Check(string(response.Stdout), gc.Equals, initSystem) 370 c.Check(string(response.Stderr), gc.Equals, "") 371 } 372 373 func (s *discoverySuite) writeScript(c *gc.C, name, script string) (string, string) { 374 filename := filepath.Join(c.MkDir(), name) 375 commands := []string{ 376 fmt.Sprintf(` 377 cat > %s << 'EOF' 378 %s 379 EOF`[1:], filename, script), 380 "chmod 0755 " + filename, 381 } 382 writeScript := strings.Join(commands, "\n") + "\n" 383 return writeScript, filename 384 } 385 386 func (s *discoverySuite) newDiscoverInitSystemScript(c *gc.C) (string, string) { 387 script := service.DiscoverInitSystemScript() 388 return s.writeScript(c, "discover_init_system.sh", script) 389 } 390 391 func (s *discoverySuite) TestNewShellSelectCommandBash(c *gc.C) { 392 if runtime.GOOS == "windows" { 393 c.Skip("not supported on windows") 394 } 395 396 discoveryScript := service.DiscoverInitSystemScript() 397 handler := func(initSystem string) (string, bool) { 398 return "echo -n " + initSystem, true 399 } 400 script := "init_system=$(" + discoveryScript + ")\n" 401 // The script will fail with exit 1 if it cannot match in init system. 402 script += service.NewShellSelectCommand("init_system", "exit 1", handler) 403 response, err := exec.RunCommands(exec.RunParams{ 404 Commands: script, 405 }) 406 c.Assert(err, jc.ErrorIsNil) 407 408 initSystem, err := service.DiscoverInitSystem() 409 c.Assert(err, jc.ErrorIsNil) 410 c.Check(response.Code, gc.Equals, 0) 411 c.Check(string(response.Stdout), gc.Equals, initSystem) 412 c.Check(string(response.Stderr), gc.Equals, "") 413 } 414 415 func (s *discoverySuite) TestNewShellSelectCommandPosix(c *gc.C) { 416 if runtime.GOOS == "windows" { 417 c.Skip("not supported on windows") 418 } 419 420 discoveryScript := service.DiscoverInitSystemScript() 421 handler := func(initSystem string) (string, bool) { 422 return "echo -n " + initSystem, true 423 } 424 script := "init_system=$(" + discoveryScript + ")\n" 425 // The script will fail with exit 1 if it cannot match in init system. 426 script += service.NewShellSelectCommand("init_system", "exit 1", handler) 427 commands, filename := s.writeScript(c, "test_shell_select.sh", script) 428 commands += "sh " + filename 429 response, err := exec.RunCommands(exec.RunParams{ 430 Commands: script, 431 }) 432 c.Assert(err, jc.ErrorIsNil) 433 434 initSystem, err := service.DiscoverInitSystem() 435 c.Assert(err, jc.ErrorIsNil) 436 c.Check(response.Code, gc.Equals, 0) 437 c.Check(string(response.Stdout), gc.Equals, initSystem) 438 c.Check(string(response.Stderr), gc.Equals, "") 439 }