зеркало из https://github.com/mozilla/mig.git
[minor] remove vendored service-go and just include this package in mig
service-go is being imported as a vendor package. It was originally more generic but over time has been tweaked in a few ways for its use within MIG. Rather then manage it as a separate package, just include it.
This commit is contained in:
Родитель
1f403c02ed
Коммит
dcb89d9ad6
1
Makefile
1
Makefile
|
@ -179,7 +179,6 @@ go_vendor_dependencies:
|
|||
$(GOGETTER) github.com/gorilla/mux
|
||||
$(GOGETTER) github.com/jvehent/cljs
|
||||
$(GOGETTER) github.com/jvehent/gozdef
|
||||
$(GOGETTER) github.com/jvehent/service-go
|
||||
$(GOGETTER) github.com/kardianos/osext
|
||||
$(GOGETTER) github.com/lib/pq
|
||||
$(GOGETTER) github.com/mozilla/masche/listlibs
|
||||
|
|
|
@ -19,11 +19,11 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jvehent/service-go"
|
||||
"github.com/streadway/amqp"
|
||||
"mig.ninja/mig"
|
||||
"mig.ninja/mig/mig-agent/agentcontext"
|
||||
"mig.ninja/mig/modules"
|
||||
"mig.ninja/mig/service"
|
||||
)
|
||||
|
||||
// publication lock is used to prevent publication when the channels are not
|
||||
|
|
|
@ -20,11 +20,11 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jvehent/service-go"
|
||||
"github.com/streadway/amqp"
|
||||
"mig.ninja/mig"
|
||||
"mig.ninja/mig/mig-agent/agentcontext"
|
||||
"mig.ninja/mig/modules"
|
||||
"mig.ninja/mig/service"
|
||||
)
|
||||
|
||||
// Context contains all configuration variables as well as handlers for
|
||||
|
|
|
@ -8,8 +8,8 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jvehent/service-go"
|
||||
"mig.ninja/mig"
|
||||
"mig.ninja/mig/service"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
service is a package used within MIG for service management. This includes
|
||||
tasks such as installing/removing MIG components as OS services, and starting
|
||||
and stopping services.
|
||||
|
||||
This code was originally forked from bitbucket.org/kardianos/service/ to
|
||||
github.com/jvehent/service-go. Since then the code has been modified for MIG,
|
||||
and as such now lives here.
|
|
@ -1,4 +1,4 @@
|
|||
package service
|
||||
package service /* import "mig.ninja/mig/service" */
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -1,6 +1,6 @@
|
|||
// Package service provides a simple way to create a system service.
|
||||
// Currently supports Windows, Linux/(systemd | Upstart | SysV), and OSX/Launchd.
|
||||
package service
|
||||
package service /* import "mig.ninja/mig/service" */
|
||||
|
||||
import "github.com/kardianos/osext"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package service
|
||||
package service /* import "mig.ninja/mig/service" */
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package service
|
||||
package service /* import "mig.ninja/mig/service" */
|
||||
|
||||
import (
|
||||
"bytes"
|
|
@ -1,4 +1,4 @@
|
|||
package service
|
||||
package service /* import "mig.ninja/mig/service" */
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +0,0 @@
|
|||
service will install / un-install, start / stop, and run a program as a service (daemon).
|
||||
Currently supports Windows XP+, Linux/(systemd | Upstart | SysV), and OSX/Launchd.
|
||||
|
||||
To start out follow "example/main.go".
|
|
@ -1,170 +0,0 @@
|
|||
// A simple and consistent method to extract a configuration from a file.
|
||||
// This doesn't contain any method to actually decode the file. The actual
|
||||
// decoding is done in an external function.
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/kardianos/osext"
|
||||
"gopkg.in/fsnotify.v1"
|
||||
)
|
||||
|
||||
const DefaultPostfix = "_config.json"
|
||||
|
||||
// Simple JSON based configuration decoder.
|
||||
func DecodeJsonConfig(r io.Reader, v interface{}) error {
|
||||
d := json.NewDecoder(r)
|
||||
return d.Decode(v)
|
||||
}
|
||||
|
||||
// Simple JSON based configuration encoder.
|
||||
func EncodeJsonConfig(w io.Writer, v interface{}) error {
|
||||
bb, err := json.MarshalIndent(v, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, tot := 0, 0
|
||||
for {
|
||||
n, err = w.Write(bb[tot:])
|
||||
tot += n
|
||||
if len(bb) == tot {
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Return a configuration file path. If baseName is empty,
|
||||
// then the current executable name without the extension
|
||||
// is used. If postfix is empty then DefaultPostfix is used.
|
||||
func GetConfigFilePath(baseName, postfix string) (string, error) {
|
||||
if len(postfix) == 0 {
|
||||
postfix = DefaultPostfix
|
||||
}
|
||||
path, err := osext.Executable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
path, exeName := filepath.Split(path)
|
||||
if len(baseName) == 0 {
|
||||
exeName = exeName[:len(exeName)-len(filepath.Ext(exeName))]
|
||||
} else {
|
||||
exeName = baseName
|
||||
}
|
||||
configPath := filepath.Join(path, exeName+postfix)
|
||||
return configPath, nil
|
||||
}
|
||||
|
||||
type DecodeConfig func(r io.Reader, v interface{}) error
|
||||
type EncodeConfig func(w io.Writer, v interface{}) error
|
||||
|
||||
type WatchConfig struct {
|
||||
// Notified here if the file changes.
|
||||
C chan *WatchConfig
|
||||
|
||||
filepath string
|
||||
watch *fsnotify.Watcher
|
||||
decode DecodeConfig
|
||||
|
||||
close chan struct{}
|
||||
}
|
||||
|
||||
// Create a new configuration watcher. Adds a notification if the configuration file changes
|
||||
// so it may be reloaded. If defaultConfig is not nil and encode is not nil, the
|
||||
// configuration file path is checked if a file exists or not. If it doesn't exist
|
||||
// the default configuration is written to the file.
|
||||
func NewWatchConfig(filepath string, decode DecodeConfig, defaultConfig interface{}, encode EncodeConfig) (*WatchConfig, error) {
|
||||
if defaultConfig != nil && encode != nil {
|
||||
f, err := os.Open(filepath)
|
||||
if f != nil {
|
||||
f.Close()
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
f, err = os.Create(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = encode(f, defaultConfig)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
watch, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = watch.Add(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wc := &WatchConfig{
|
||||
C: make(chan *WatchConfig),
|
||||
|
||||
filepath: filepath,
|
||||
watch: watch,
|
||||
decode: decode,
|
||||
|
||||
close: make(chan struct{}, 0),
|
||||
}
|
||||
go wc.run()
|
||||
|
||||
return wc, nil
|
||||
}
|
||||
|
||||
func (wc *WatchConfig) run() {
|
||||
// Work around watch events being sent more then once.
|
||||
ticker := time.NewTicker(time.Second)
|
||||
trigger := false
|
||||
waitOnce := false
|
||||
for {
|
||||
select {
|
||||
case <-wc.close:
|
||||
close(wc.C)
|
||||
return
|
||||
case <-wc.watch.Errors:
|
||||
// Nothing right now.
|
||||
case <-wc.watch.Events:
|
||||
trigger = true
|
||||
case <-ticker.C:
|
||||
// Think of this as a PLC state machine.
|
||||
if trigger && waitOnce {
|
||||
wc.C <- wc
|
||||
trigger = false
|
||||
waitOnce = false
|
||||
}
|
||||
if trigger && !waitOnce {
|
||||
waitOnce = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send a notification as if the configuration file has changed.
|
||||
func (wc *WatchConfig) TriggerC() {
|
||||
wc.C <- wc
|
||||
}
|
||||
|
||||
// Load the configuration from the file into the provided value.
|
||||
func (wc *WatchConfig) Load(v interface{}) error {
|
||||
f, err := os.Open(wc.filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return wc.decode(f, v)
|
||||
}
|
||||
|
||||
// Stop the watch and any loops that are running.
|
||||
func (wc *WatchConfig) Close() error {
|
||||
wc.close <- struct{}{}
|
||||
return wc.watch.Close()
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/jvehent/service-go"
|
||||
)
|
||||
|
||||
var log service.Logger
|
||||
|
||||
func main() {
|
||||
var name = "GoServiceTest"
|
||||
var displayName = "Go Service Test"
|
||||
var desc = "This is a test Go service. It is designed to run well."
|
||||
|
||||
var s, err = service.NewService(name, displayName, desc)
|
||||
log = s
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%s unable to start: %s", displayName, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
var err error
|
||||
verb := os.Args[1]
|
||||
switch verb {
|
||||
case "install":
|
||||
err = s.Install()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to install: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" installed.\n", displayName)
|
||||
case "remove":
|
||||
err = s.Remove()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to remove: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" removed.\n", displayName)
|
||||
case "run":
|
||||
doWork()
|
||||
case "start":
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to start: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" started.\n", displayName)
|
||||
case "stop":
|
||||
err = s.Stop()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to stop: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" stopped.\n", displayName)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = s.Run(func() error {
|
||||
// start
|
||||
go doWork()
|
||||
return nil
|
||||
}, func() error {
|
||||
// stop
|
||||
stopWork()
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
s.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
var exit = make(chan struct{})
|
||||
|
||||
func doWork() {
|
||||
log.Info("I'm Running!")
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
log.Info("Still running...")
|
||||
case <-exit:
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
func stopWork() {
|
||||
log.Info("I'm Stopping!")
|
||||
exit <- struct{}{}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package stdservice
|
||||
|
||||
import "fmt"
|
||||
|
||||
type ConsoleLogger struct{}
|
||||
|
||||
func (ConsoleLogger) Error(format string, a ...interface{}) error {
|
||||
fmt.Printf("E: "+format+"\n", a...)
|
||||
return nil
|
||||
}
|
||||
func (ConsoleLogger) Warning(format string, a ...interface{}) error {
|
||||
fmt.Printf("W: "+format+"\n", a...)
|
||||
return nil
|
||||
}
|
||||
func (ConsoleLogger) Info(format string, a ...interface{}) error {
|
||||
fmt.Printf("I: "+format+"\n", a...)
|
||||
return nil
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
Many services that run on different platforms cannot rely
|
||||
on flags to be passed for configuration. Some platforms
|
||||
require explicit install commands. This package handles the common
|
||||
boilerplate code. The following command may be passed to the
|
||||
executable as the first argument:
|
||||
install | remove | run | start | stop
|
||||
|
||||
These commands will do the following actions:
|
||||
install - Install the running executable as a service on the system.
|
||||
remove - Remove the running executable as a service on the system.
|
||||
run - Run the service as a command line application, output log to prompt.
|
||||
start - Starts the service via system controls.
|
||||
stop - Stops the service via system controls.
|
||||
*/
|
||||
package stdservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"bitbucket.org/kardianos/service"
|
||||
)
|
||||
|
||||
// Standard service configuration. Start MUST block.
|
||||
// Stop MUST NOT block for more then a second or two.
|
||||
type Config struct {
|
||||
// Used to register the service with the operating system.
|
||||
Name, DisplayName, LongDescription string
|
||||
|
||||
// Called when the service starts or stops.
|
||||
// Stop may be nil.
|
||||
Start, Stop func(c *Config)
|
||||
|
||||
// Called after logging may be setup but before the service is started.
|
||||
// Init is optional and may be nil.
|
||||
// If Init returns an error, that error is logged to the logger
|
||||
// and the service start is aborted.
|
||||
// Init should not block.
|
||||
Init func(c *Config) error
|
||||
|
||||
s service.Service
|
||||
l service.Logger
|
||||
}
|
||||
|
||||
// Get service after Run() has been called.
|
||||
func (c *Config) Service() service.Service {
|
||||
return c.s
|
||||
}
|
||||
|
||||
// Get logger after Run() has been called.
|
||||
func (c *Config) Logger() service.Logger {
|
||||
return c.l
|
||||
}
|
||||
|
||||
// Fill in configuration, then call Run() to setup basic handling.
|
||||
// Blocks until program completes. Is intended to handle the standard
|
||||
// simple cases for running a service.
|
||||
func (c *Config) Run() {
|
||||
run(c)
|
||||
}
|
||||
|
||||
// Depreciated. Same as *Config.Run().
|
||||
func Run(c *Config) {
|
||||
run(c)
|
||||
}
|
||||
|
||||
func run(c *Config) {
|
||||
var s, err = service.NewService(c.Name, c.DisplayName, c.LongDescription)
|
||||
c.s = s
|
||||
c.l = s
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%s unable to start: %s", c.DisplayName, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
var err error
|
||||
verb := os.Args[1]
|
||||
switch verb {
|
||||
case "install":
|
||||
err = s.Install()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to install: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" installed.\n", c.DisplayName)
|
||||
case "remove":
|
||||
err = s.Remove()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to remove: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" removed.\n", c.DisplayName)
|
||||
case "run":
|
||||
c.l = ConsoleLogger{}
|
||||
defer func() {
|
||||
if c.Stop != nil {
|
||||
c.Stop(c)
|
||||
}
|
||||
}()
|
||||
if c.Init != nil {
|
||||
err := c.Init(c)
|
||||
if err != nil {
|
||||
c.l.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
c.Start(c)
|
||||
case "start":
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to start: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" started.\n", c.DisplayName)
|
||||
case "stop":
|
||||
err = s.Stop()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to stop: %s\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Service \"%s\" stopped.\n", c.DisplayName)
|
||||
default:
|
||||
fmt.Printf("Options for \"%s\": (install | remove | run | start | stop)\n", os.Args[0])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if c.Init != nil {
|
||||
err := c.Init(c)
|
||||
if err != nil {
|
||||
c.l.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = s.Run(func() error {
|
||||
// start
|
||||
go c.Start(c)
|
||||
return nil
|
||||
}, func() error {
|
||||
// stop
|
||||
if c.Stop != nil {
|
||||
c.Stop(c)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
c.l.Error(err.Error())
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче