mirror of
https://github.com/rwinkhart/sys.git
synced 2026-09-01 06:46:44 -04:00
windows/svc/mgr: add Service.RecoveryActionsOnNonCrashFailures
Fixes golang/go#59016 Change-Id: I5e16f61ea2fc384052565342c6517687562260a1 GitHub-Last-Rev: 3626b01fcf35da32b67d11e8439e757de177bbaa GitHub-Pull-Request: golang/sys#157 Reviewed-on: https://go-review.googlesource.com/c/sys/+/484896 Run-TryBot: Bryan Mills <bcmills@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
committed by
Alex Brainman
parent
e0c3b6e6ae
commit
2b751ddc66
@@ -218,6 +218,10 @@ type SERVICE_FAILURE_ACTIONS struct {
|
|||||||
Actions *SC_ACTION
|
Actions *SC_ACTION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SERVICE_FAILURE_ACTIONS_FLAG struct {
|
||||||
|
FailureActionsOnNonCrashFailures int32
|
||||||
|
}
|
||||||
|
|
||||||
type SC_ACTION struct {
|
type SC_ACTION struct {
|
||||||
Type uint32
|
Type uint32
|
||||||
Delay uint32
|
Delay uint32
|
||||||
|
|||||||
@@ -209,6 +209,57 @@ func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testRecoveryActionsOnNonCrashFailures(t *testing.T, s *mgr.Service, should bool) {
|
||||||
|
err := s.SetRecoveryActionsOnNonCrashFailures(should)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetRecoveryActionsOnNonCrashFailures failed: %v", err)
|
||||||
|
}
|
||||||
|
is, err := s.RecoveryActionsOnNonCrashFailures()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("RecoveryActionsOnNonCrashFailures failed: %v", err)
|
||||||
|
}
|
||||||
|
if should != is {
|
||||||
|
t.Errorf("RecoveryActionsOnNonCrashFailures mismatch: flag is %v, but should have %v", is, should)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMultipleRecoverySettings(t *testing.T, s *mgr.Service, rebootMsgShould, recoveryCmdShould string, actionsFlagShould bool) {
|
||||||
|
err := s.SetRebootMessage(rebootMsgShould)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetRebootMessage failed: %v", err)
|
||||||
|
}
|
||||||
|
err = s.SetRecoveryActionsOnNonCrashFailures(actionsFlagShould)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetRecoveryActionsOnNonCrashFailures failed: %v", err)
|
||||||
|
}
|
||||||
|
err = s.SetRecoveryCommand(recoveryCmdShould)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetRecoveryCommand failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rebootMsgIs, err := s.RebootMessage()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("RebootMessage failed: %v", err)
|
||||||
|
}
|
||||||
|
if rebootMsgShould != rebootMsgIs {
|
||||||
|
t.Errorf("reboot message mismatch: message is %q, but should have %q", rebootMsgIs, rebootMsgShould)
|
||||||
|
}
|
||||||
|
recoveryCommandIs, err := s.RecoveryCommand()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("RecoveryCommand failed: %v", err)
|
||||||
|
}
|
||||||
|
if recoveryCmdShould != recoveryCommandIs {
|
||||||
|
t.Errorf("recovery command mismatch: command is %q, but should have %q", recoveryCommandIs, recoveryCmdShould)
|
||||||
|
}
|
||||||
|
actionsFlagIs, err := s.RecoveryActionsOnNonCrashFailures()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("RecoveryActionsOnNonCrashFailures failed: %v", err)
|
||||||
|
}
|
||||||
|
if actionsFlagShould != actionsFlagIs {
|
||||||
|
t.Errorf("RecoveryActionsOnNonCrashFailures mismatch: flag is %v, but should have %v", actionsFlagIs, actionsFlagShould)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testControl(t *testing.T, s *mgr.Service, c svc.Cmd, expectedErr error, expectedStatus svc.Status) {
|
func testControl(t *testing.T, s *mgr.Service, c svc.Cmd, expectedErr error, expectedStatus svc.Status) {
|
||||||
status, err := s.Control(c)
|
status, err := s.Control(c)
|
||||||
if err != expectedErr {
|
if err != expectedErr {
|
||||||
@@ -305,6 +356,9 @@ func TestMyService(t *testing.T) {
|
|||||||
testRebootMessage(t, s, "") // delete reboot message
|
testRebootMessage(t, s, "") // delete reboot message
|
||||||
testRecoveryCommand(t, s, fmt.Sprintf("sc query %s", name))
|
testRecoveryCommand(t, s, fmt.Sprintf("sc query %s", name))
|
||||||
testRecoveryCommand(t, s, "") // delete recovery command
|
testRecoveryCommand(t, s, "") // delete recovery command
|
||||||
|
testRecoveryActionsOnNonCrashFailures(t, s, true)
|
||||||
|
testRecoveryActionsOnNonCrashFailures(t, s, false)
|
||||||
|
testMultipleRecoverySettings(t, s, fmt.Sprintf("%s failed", name), fmt.Sprintf("sc query %s", name), true)
|
||||||
|
|
||||||
expectedStatus := svc.Status{
|
expectedStatus := svc.Status{
|
||||||
State: svc.Stopped,
|
State: svc.Stopped,
|
||||||
|
|||||||
@@ -140,3 +140,30 @@ func (s *Service) RecoveryCommand() (string, error) {
|
|||||||
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||||
return windows.UTF16PtrToString(p.Command), nil
|
return windows.UTF16PtrToString(p.Command), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetRecoveryActionsOnNonCrashFailures sets the failure actions flag. If the
|
||||||
|
// flag is set to false, recovery actions will only be performed if the service
|
||||||
|
// terminates without reporting a status of SERVICE_STOPPED. If the flag is set
|
||||||
|
// to true, recovery actions are also perfomed if the service stops with a
|
||||||
|
// nonzero exit code.
|
||||||
|
func (s *Service) SetRecoveryActionsOnNonCrashFailures(flag bool) error {
|
||||||
|
var setting windows.SERVICE_FAILURE_ACTIONS_FLAG
|
||||||
|
if flag {
|
||||||
|
setting.FailureActionsOnNonCrashFailures = 1
|
||||||
|
}
|
||||||
|
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, (*byte)(unsafe.Pointer(&setting)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoveryActionsOnNonCrashFailures returns the current value of the failure
|
||||||
|
// actions flag. If the flag is set to false, recovery actions will only be
|
||||||
|
// performed if the service terminates without reporting a status of
|
||||||
|
// SERVICE_STOPPED. If the flag is set to true, recovery actions are also
|
||||||
|
// perfomed if the service stops with a nonzero exit code.
|
||||||
|
func (s *Service) RecoveryActionsOnNonCrashFailures() (bool, error) {
|
||||||
|
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS_FLAG)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
p := (*windows.SERVICE_FAILURE_ACTIONS_FLAG)(unsafe.Pointer(&b[0]))
|
||||||
|
return p.FailureActionsOnNonCrashFailures != 0, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user