service.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // Copyright 2015 Daniel Theophanes.
  2. // Use of this source code is governed by a zlib-style
  3. // license that can be found in the LICENSE file.
  4. // Package service provides a simple way to create a system service.
  5. // Currently supports Windows, Linux/(systemd | Upstart | SysV), and OSX/Launchd.
  6. //
  7. // Windows controls services by setting up callbacks that is non-trivial. This
  8. // is very different then other systems. This package provides the same API
  9. // despite the substantial differences.
  10. // It also can be used to detect how a program is called, from an interactive
  11. // terminal or from a service manager.
  12. //
  13. // Examples in the example/ folder.
  14. //
  15. // package main
  16. //
  17. // import (
  18. // "log"
  19. //
  20. // "github.com/kardianos/service"
  21. // )
  22. //
  23. // var logger service.Logger
  24. //
  25. // type program struct{}
  26. //
  27. // func (p *program) Start(s service.Service) error {
  28. // // Start should not block. Do the actual work async.
  29. // go p.run()
  30. // return nil
  31. // }
  32. // func (p *program) run() {
  33. // // Do work here
  34. // }
  35. // func (p *program) Stop(s service.Service) error {
  36. // // Stop should not block. Return with a few seconds.
  37. // return nil
  38. // }
  39. //
  40. // func main() {
  41. // svcConfig := &service.Config{
  42. // Name: "GoServiceTest",
  43. // DisplayName: "Go Service Test",
  44. // Description: "This is a test Go service.",
  45. // }
  46. //
  47. // prg := &program{}
  48. // s, err := service.New(prg, svcConfig)
  49. // if err != nil {
  50. // log.Fatal(err)
  51. // }
  52. // logger, err = s.Logger(nil)
  53. // if err != nil {
  54. // log.Fatal(err)
  55. // }
  56. // err = s.Run()
  57. // if err != nil {
  58. // logger.Error(err)
  59. // }
  60. // }
  61. package service // import "github.com/kardianos/service"
  62. import (
  63. "errors"
  64. "fmt"
  65. )
  66. const (
  67. optionKeepAlive = "KeepAlive"
  68. optionKeepAliveDefault = true
  69. optionRunAtLoad = "RunAtLoad"
  70. optionRunAtLoadDefault = false
  71. optionUserService = "UserService"
  72. optionUserServiceDefault = false
  73. optionSessionCreate = "SessionCreate"
  74. optionSessionCreateDefault = false
  75. optionLogOutput = "LogOutput"
  76. optionLogOutputDefault = false
  77. optionPrefix = "Prefix"
  78. optionPrefixDefault = "application"
  79. optionRunWait = "RunWait"
  80. optionReloadSignal = "ReloadSignal"
  81. optionPIDFile = "PIDFile"
  82. optionLimitNOFILE = "LimitNOFILE"
  83. optionLimitNOFILEDefault = -1 // -1 = don't set in configuration
  84. optionRestart = "Restart"
  85. optionSuccessExitStatus = "SuccessExitStatus"
  86. optionSystemdScript = "SystemdScript"
  87. optionSysvScript = "SysvScript"
  88. optionUpstartScript = "UpstartScript"
  89. optionLaunchdConfig = "LaunchdConfig"
  90. )
  91. // Status represents service status as an byte value
  92. type Status byte
  93. // Status of service represented as an byte
  94. const (
  95. StatusUnknown Status = iota // Status is unable to be determined due to an error or it was not installed.
  96. StatusRunning
  97. StatusStopped
  98. )
  99. // Config provides the setup for a Service. The Name field is required.
  100. type Config struct {
  101. Name string // Required name of the service. No spaces suggested.
  102. DisplayName string // Display name, spaces allowed.
  103. Description string // Long description of service.
  104. UserName string // Run as username.
  105. Arguments []string // Run with arguments.
  106. // Optional field to specify the executable for service.
  107. // If empty the current executable is used.
  108. Executable string
  109. // Array of service dependencies.
  110. // Not yet fully implemented on Linux or OS X:
  111. // 1. Support linux-systemd dependencies, just put each full line as the
  112. // element of the string array, such as
  113. // "After=network.target syslog.target"
  114. // "Requires=syslog.target"
  115. // Note, such lines will be directly appended into the [Unit] of
  116. // the generated service config file, will not check their correctness.
  117. Dependencies []string
  118. // The following fields are not supported on Windows.
  119. WorkingDirectory string // Initial working directory.
  120. ChRoot string
  121. // System specific options.
  122. // * OS X
  123. // - LaunchdConfig string () - Use custom launchd config
  124. // - KeepAlive bool (true)
  125. // - RunAtLoad bool (false)
  126. // - UserService bool (false) - Install as a current user service.
  127. // - SessionCreate bool (false) - Create a full user session.
  128. // * POSIX
  129. // - SystemdScript string () - Use custom systemd script
  130. // - UpstartScript string () - Use custom upstart script
  131. // - SysvScript string () - Use custom sysv script
  132. // - RunWait func() (wait for SIGNAL) - Do not install signal but wait for this function to return.
  133. // - ReloadSignal string () [USR1, ...] - Signal to send on reaload.
  134. // - PIDFile string () [/run/prog.pid] - Location of the PID file.
  135. // - LogOutput bool (false) - Redirect StdErr & StandardOutPath to files.
  136. // - Restart string (always) - How shall service be restarted.
  137. // - SuccessExitStatus string () - The list of exit status that shall be considered as successful,
  138. // in addition to the default ones.
  139. // * Linux (systemd)
  140. // - LimitNOFILE int - Maximum open files (ulimit -n) (https://serverfault.com/questions/628610/increasing-nproc-for-processes-launched-by-systemd-on-centos-7)
  141. // * Windows
  142. // - DelayedAutoStart bool (false) - after booting start this service after some delay
  143. Option KeyValue
  144. }
  145. var (
  146. system System
  147. systemRegistry []System
  148. )
  149. var (
  150. // ErrNameFieldRequired is returned when Config.Name is empty.
  151. ErrNameFieldRequired = errors.New("Config.Name field is required.")
  152. // ErrNoServiceSystemDetected is returned when no system was detected.
  153. ErrNoServiceSystemDetected = errors.New("No service system detected.")
  154. // ErrNotInstalled is returned when the service is not installed
  155. ErrNotInstalled = errors.New("the service is not installed")
  156. )
  157. // New creates a new service based on a service interface and configuration.
  158. func New(i Interface, c *Config) (Service, error) {
  159. if len(c.Name) == 0 {
  160. return nil, ErrNameFieldRequired
  161. }
  162. if system == nil {
  163. return nil, ErrNoServiceSystemDetected
  164. }
  165. return system.New(i, c)
  166. }
  167. // KeyValue provides a list of platform specific options. See platform docs for
  168. // more details.
  169. type KeyValue map[string]interface{}
  170. // bool returns the value of the given name, assuming the value is a boolean.
  171. // If the value isn't found or is not of the type, the defaultValue is returned.
  172. func (kv KeyValue) bool(name string, defaultValue bool) bool {
  173. if v, found := kv[name]; found {
  174. if castValue, is := v.(bool); is {
  175. return castValue
  176. }
  177. }
  178. return defaultValue
  179. }
  180. // int returns the value of the given name, assuming the value is an int.
  181. // If the value isn't found or is not of the type, the defaultValue is returned.
  182. func (kv KeyValue) int(name string, defaultValue int) int {
  183. if v, found := kv[name]; found {
  184. if castValue, is := v.(int); is {
  185. return castValue
  186. }
  187. }
  188. return defaultValue
  189. }
  190. // string returns the value of the given name, assuming the value is a string.
  191. // If the value isn't found or is not of the type, the defaultValue is returned.
  192. func (kv KeyValue) string(name string, defaultValue string) string {
  193. if v, found := kv[name]; found {
  194. if castValue, is := v.(string); is {
  195. return castValue
  196. }
  197. }
  198. return defaultValue
  199. }
  200. // float64 returns the value of the given name, assuming the value is a float64.
  201. // If the value isn't found or is not of the type, the defaultValue is returned.
  202. func (kv KeyValue) float64(name string, defaultValue float64) float64 {
  203. if v, found := kv[name]; found {
  204. if castValue, is := v.(float64); is {
  205. return castValue
  206. }
  207. }
  208. return defaultValue
  209. }
  210. // funcSingle returns the value of the given name, assuming the value is a func().
  211. // If the value isn't found or is not of the type, the defaultValue is returned.
  212. func (kv KeyValue) funcSingle(name string, defaultValue func()) func() {
  213. if v, found := kv[name]; found {
  214. if castValue, is := v.(func()); is {
  215. return castValue
  216. }
  217. }
  218. return defaultValue
  219. }
  220. // Platform returns a description of the system service.
  221. func Platform() string {
  222. if system == nil {
  223. return ""
  224. }
  225. return system.String()
  226. }
  227. // Interactive returns false if running under the OS service manager
  228. // and true otherwise.
  229. func Interactive() bool {
  230. if system == nil {
  231. return true
  232. }
  233. return system.Interactive()
  234. }
  235. func newSystem() System {
  236. for _, choice := range systemRegistry {
  237. if choice.Detect() == false {
  238. continue
  239. }
  240. return choice
  241. }
  242. return nil
  243. }
  244. // ChooseSystem chooses a system from the given system services.
  245. // SystemServices are considered in the order they are suggested.
  246. // Calling this may change what Interactive and Platform return.
  247. func ChooseSystem(a ...System) {
  248. systemRegistry = a
  249. system = newSystem()
  250. }
  251. // ChosenSystem returns the system that service will use.
  252. func ChosenSystem() System {
  253. return system
  254. }
  255. // AvailableSystems returns the list of system services considered
  256. // when choosing the system service.
  257. func AvailableSystems() []System {
  258. return systemRegistry
  259. }
  260. // System represents the service manager that is available.
  261. type System interface {
  262. // String returns a description of the system.
  263. String() string
  264. // Detect returns true if the system is available to use.
  265. Detect() bool
  266. // Interactive returns false if running under the system service manager
  267. // and true otherwise.
  268. Interactive() bool
  269. // New creates a new service for this system.
  270. New(i Interface, c *Config) (Service, error)
  271. }
  272. // Interface represents the service interface for a program. Start runs before
  273. // the hosting process is granted control and Stop runs when control is returned.
  274. //
  275. // 1. OS service manager executes user program.
  276. // 2. User program sees it is executed from a service manager (IsInteractive is false).
  277. // 3. User program calls Service.Run() which blocks.
  278. // 4. Interface.Start() is called and quickly returns.
  279. // 5. User program runs.
  280. // 6. OS service manager signals the user program to stop.
  281. // 7. Interface.Stop() is called and quickly returns.
  282. // - For a successful exit, os.Exit should not be called in Interface.Stop().
  283. // 8. Service.Run returns.
  284. // 9. User program should quickly exit.
  285. type Interface interface {
  286. // Start provides a place to initiate the service. The service doesn't
  287. // signal a completed start until after this function returns, so the
  288. // Start function must not take more then a few seconds at most.
  289. Start(s Service) error
  290. // Stop provides a place to clean up program execution before it is terminated.
  291. // It should not take more then a few seconds to execute.
  292. // Stop should not call os.Exit directly in the function.
  293. Stop(s Service) error
  294. }
  295. // Shutdowner represents a service interface for a program that differentiates between "stop" and
  296. // "shutdown". A shutdown is triggered when the whole box (not just the service) is stopped.
  297. type Shutdowner interface {
  298. Interface
  299. // Shutdown provides a place to clean up program execution when the system is being shutdown.
  300. // It is essentially the same as Stop but for the case where machine is being shutdown/restarted
  301. // instead of just normally stopping the service. Stop won't be called when Shutdown is.
  302. Shutdown(s Service) error
  303. }
  304. // TODO: Add Configure to Service interface.
  305. // Service represents a service that can be run or controlled.
  306. type Service interface {
  307. // Run should be called shortly after the program entry point.
  308. // After Interface.Stop has finished running, Run will stop blocking.
  309. // After Run stops blocking, the program must exit shortly after.
  310. Run() error
  311. // Start signals to the OS service manager the given service should start.
  312. Start() error
  313. // Stop signals to the OS service manager the given service should stop.
  314. Stop() error
  315. // Restart signals to the OS service manager the given service should stop then start.
  316. Restart() error
  317. // Install setups up the given service in the OS service manager. This may require
  318. // greater rights. Will return an error if it is already installed.
  319. Install() error
  320. // Uninstall removes the given service from the OS service manager. This may require
  321. // greater rights. Will return an error if the service is not present.
  322. Uninstall() error
  323. // Opens and returns a system logger. If the user program is running
  324. // interactively rather then as a service, the returned logger will write to
  325. // os.Stderr. If errs is non-nil errors will be sent on errs as well as
  326. // returned from Logger's functions.
  327. Logger(errs chan<- error) (Logger, error)
  328. // SystemLogger opens and returns a system logger. If errs is non-nil errors
  329. // will be sent on errs as well as returned from Logger's functions.
  330. SystemLogger(errs chan<- error) (Logger, error)
  331. // String displays the name of the service. The display name if present,
  332. // otherwise the name.
  333. String() string
  334. // Platform displays the name of the system that manages the service.
  335. // In most cases this will be the same as service.Platform().
  336. Platform() string
  337. // Status returns the current service status.
  338. Status() (Status, error)
  339. }
  340. // ControlAction list valid string texts to use in Control.
  341. var ControlAction = [5]string{"start", "stop", "restart", "install", "uninstall"}
  342. // Control issues control functions to the service from a given action string.
  343. func Control(s Service, action string) error {
  344. var err error
  345. switch action {
  346. case ControlAction[0]:
  347. err = s.Start()
  348. case ControlAction[1]:
  349. err = s.Stop()
  350. case ControlAction[2]:
  351. err = s.Restart()
  352. case ControlAction[3]:
  353. err = s.Install()
  354. case ControlAction[4]:
  355. err = s.Uninstall()
  356. default:
  357. err = fmt.Errorf("Unknown action %s", action)
  358. }
  359. if err != nil {
  360. return fmt.Errorf("Failed to %s %v: %v", action, s, err)
  361. }
  362. return nil
  363. }
  364. // Logger writes to the system log.
  365. type Logger interface {
  366. Error(v ...interface{}) error
  367. Warning(v ...interface{}) error
  368. Info(v ...interface{}) error
  369. Errorf(format string, a ...interface{}) error
  370. Warningf(format string, a ...interface{}) error
  371. Infof(format string, a ...interface{}) error
  372. }