Skip to content

Commit 8524bf4

Browse files
committed
Use single cerberus binary for multiple services
1 parent abfcbd1 commit 8524bf4

File tree

3 files changed

+38
-8
lines changed

3 files changed

+38
-8
lines changed

cerberus.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"os/exec"
99
"path/filepath"
1010
"strings"
11+
"time"
1112

1213
"github.com/go-sharp/windows/pkg/ps"
1314
"golang.org/x/sys/windows/registry"
@@ -67,6 +68,7 @@ func InstallService(config SvcConfig) error {
6768
}
6869

6970
// RemoveService removes the service with the given name.
71+
// Stops the service first, can return a timeout error if it can't stop the service.
7072
func RemoveService(name string) error {
7173
DebugLogger.Println("Open connection to service control manager...")
7274
manager, err := mgr.Connect()
@@ -88,6 +90,19 @@ func RemoveService(name string) error {
8890
}
8991
defer s.Close()
9092

93+
DebugLogger.Printf("Stopping service %v...\n", config.Name)
94+
s.Control(svc.Stop)
95+
timeout := time.Now().Add(30 * time.Second)
96+
state, _ := s.Query()
97+
for state.State != svc.Stopped {
98+
if time.Now().After(timeout) {
99+
return newError(ErrTimeout, "failed to stop service")
100+
}
101+
102+
time.Sleep(200 * time.Millisecond)
103+
state, _ = s.Query()
104+
}
105+
91106
Logger.Printf("Removing service %v...\n", config.Name)
92107
DebugLogger.Printf("Mark service %v for deletion...", config.Name)
93108
if err := s.Delete(); err != nil {
@@ -253,7 +268,7 @@ loop:
253268
return
254269
}
255270

256-
const swRegBaseKey = "SOFTWARE\\go-sharp\\cerberus"
271+
const swRegBaseKey = "SOFTWARE\\go-sharp\\cerberus\\services"
257272

258273
// RemoveServiceCfg removes the service configuration form the cerberus service db.
259274
// It returns a generic error if call fails.

cmd/main.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,18 @@ func (r *ListCommand) Execute(args []string) (err error) {
8686
cerberus.DebugLogger.Fatalln(err)
8787
}
8888

89+
fmt.Printf("\nCerberus installed services:\n")
90+
fmt.Println(strings.Repeat("-", 80))
8991
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
90-
fmt.Fprintf(w, "\nName\tDisplay Name\tDescription\tWorking Dir\tArgs\tEnvironment\n")
9192
for _, s := range svcs {
92-
fmt.Fprintf(w, "%v\t%v\t%v\t%v\t%v\t%v\n", s.Name, s.DisplayName, s.Desc, s.WorkDir, strings.Join(s.Args, " "), strings.Join(s.Env, " "))
93+
fmt.Fprintf(w, "Name:\t%v\n", s.Name)
94+
fmt.Fprintf(w, "Display Name:\t%v\n", s.DisplayName)
95+
fmt.Fprintf(w, "Description:\t%v\n", s.Desc)
96+
fmt.Fprintf(w, "Executable Path:\t%v\n", s.ExePath)
97+
fmt.Fprintf(w, "Working Directory:\t%v\n", s.WorkDir)
98+
fmt.Fprintf(w, "Arguments:\t%v\n", strings.Join(s.Args, " "))
99+
fmt.Fprintf(w, "Environment Variables:\t%v\n", strings.Join(s.Env, " "))
100+
fmt.Fprintf(w, "%v\n", strings.Repeat("-", 80))
93101
}
94102
w.Flush()
95103

@@ -135,7 +143,9 @@ func (i *InstallCommand) Execute(args []string) (err error) {
135143
// RemoveCommand used to remove a service.
136144
type RemoveCommand struct {
137145
RootCommand
138-
Name string `long:"name" short:"n" description:"Try to remove service by name" required:"yes"`
146+
Args struct {
147+
Name string `positional-arg-name:"SERVICE_NAME" description:"Name of the service to remove." required:"yes"`
148+
} `positional-args:"yes" required:"1"`
139149
}
140150

141151
// Execute will remove an installed service. The args parameter is not used
@@ -145,7 +155,7 @@ func (r *RemoveCommand) Execute(args []string) error {
145155
cerberus.Logger.Fatalln(err)
146156
}
147157

148-
if err := cerberus.RemoveService(r.Name); err != nil {
158+
if err := cerberus.RemoveService(r.Args.Name); err != nil {
149159
cerberus.Logger.Fatalln(err)
150160
}
151161

@@ -156,7 +166,7 @@ func (r *RemoveCommand) Execute(args []string) error {
156166
type RunCommand struct {
157167
RootCommand
158168
Args struct {
159-
Name string `positional-arg-name:"SERVICE_NAME" description:"Name of the service to remove."`
169+
Name string `positional-arg-name:"SERVICE_NAME" description:"Name of the service to run."`
160170
} `positional-args:"yes" required:"1"`
161171
}
162172

error.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ const (
2222
ErrRemoveService
2323
// ErrRunService indicates error while running a service.
2424
ErrRunService
25+
// ErrTimeout indicates an action run into a timeout.
26+
ErrTimeout
2527
)
2628

2729
var errorMap = map[ErrorCode]string{
28-
ErrGeneric: "",
2930
ErrSaveServiceCfg: "SaveServiceCfg",
3031
ErrLoadServiceCfg: "LoadServiceCfg",
3132
ErrInstallService: "InstallService",
@@ -61,7 +62,11 @@ func (e Error) Unwrap(err error) error {
6162

6263
// Error implements the error interface.
6364
func (e Error) Error() string {
64-
err := fmt.Sprintf("%v: %v", errorMap[e.Code], e.Message)
65+
err := e.Message
66+
if v, ok := errorMap[e.Code]; ok && v != "" {
67+
err = fmt.Sprintf("(%v) %v", v, e.Message)
68+
}
69+
6570
if e.nestedErr != nil {
6671
err = fmt.Sprintf("%v: %v", err, e.nestedErr)
6772
}

0 commit comments

Comments
 (0)