package service import ( "fmt" "github.com/juju/errors" "github.com/juju/juju/service/common" "github.com/juju/juju/service/upstart" "github.com/juju/juju/service/windows" "github.com/juju/juju/version" ) var _ Service = (*upstart.Service)(nil) var _ Service = (*windows.Service)(nil) // Service represents a service running on the current system type Service interface { // Name returns the service's name. Name() string // Conf returns the service's conf data. Conf() common.Conf // Config adds a config to the service, overwritting the current one UpdateConfig(conf common.Conf) // Running returns a boolean value that denotes // whether or not the service is running Running() bool // Start will try to start the service Start() error // Stop will try to stop the service Stop() error // TODO(ericsnow) Eliminate StopAndRemove. // StopAndRemove will stop the service and remove it StopAndRemove() error // Exists returns whether the service configuration exists in the // init directory with the same content that this Service would have // if installed. Exists() bool // Installed will return a boolean value that denotes // whether or not the service is installed Installed() bool // Install installs a service Install() error // Remove will remove the service Remove() error // InstallCommands returns the list of commands to run on a // (remote) host to install the service. InstallCommands() ([]string, error) } // TODO(ericsnow) Eliminate the need to pass an empty conf here for // most service methods. // NewService returns a new Service based on the provided info. func NewService(name string, conf common.Conf, initSystem string) (Service, error) { switch initSystem { case "windows": return windows.NewService(name, conf), nil case "upstart": return upstart.NewService(name, conf), nil default: return nil, errors.NotFoundf("init system %q", initSystem) } } // DiscoverService returns an interface to a service apropriate // for the current system func DiscoverService(name string, conf common.Conf) (Service, error) { initName := VersionInitSystem(version.Current) if initName == "" { return nil, errors.NotFoundf("init system on local host") } service, err := NewService(name, conf, initName) return service, errors.Trace(err) } // VersionInitSystem returns an init system name based on the provided // version info. func VersionInitSystem(vers version.Binary) string { switch vers.OS { case version.Windows: return "windows" case version.Ubuntu: switch vers.Series { case "precise", "quantal", "raring", "saucy", "trusty", "utopic": return "upstart" default: // vivid and later return "systemd" } // TODO(ericsnow) Support other OSes, like version.CentOS. default: return "" } } // ListServices lists all installed services on the running system func ListServices(initDir string) ([]string, error) { initName := VersionInitSystem(version.Current) if initName == "" { return nil, errors.NotFoundf("init system on local host") } switch initName { case "windows": services, err := windows.ListServices() return services, errors.Trace(err) case "upstart": services, err := upstart.ListServices(initDir) return services, errors.Trace(err) default: return nil, errors.NotFoundf("init system %q", initName) } } var linuxExecutables = map[string]string{ "/sbin/init": "upstart", } // TODO(ericsnow) Is it too much to cat once for each executable? const initSystemTest = `[[ "$(cat /proc/1/cmdline)" == "%s" ]]` // ListServicesCommand returns the command that should be run to get // a list of service names on a host. func ListServicesCommand() string { // TODO(ericsnow) Allow passing in "initSystems ...string". executables := linuxExecutables // TODO(ericsnow) build the command in a better way? cmdAll := "" for executable, initSystem := range executables { cmd := listServicesCommand(initSystem) if cmd == "" { continue } test := fmt.Sprintf(initSystemTest, executable) cmd = fmt.Sprintf("if %s; then %s\n", test, cmd) if cmdAll != "" { cmd = "el" + cmd } cmdAll += cmd } if cmdAll != "" { cmdAll += "fi" } return cmdAll } func listServicesCommand(initSystem string) string { switch initSystem { case "windows": return windows.ListCommand() case "upstart": return upstart.ListCommand() default: return "" } }