mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 04:33:26 +00:00
Merge pull request #78189 from ksubrmnn/initsystem
Use Service Control Manager as the Windows Initsystem
This commit is contained in:
commit
5d1409a4bf
@ -143,8 +143,8 @@ func (sc ServiceCheck) Check() (warnings, errorList []error) {
|
|||||||
|
|
||||||
if !initSystem.ServiceIsEnabled(sc.Service) {
|
if !initSystem.ServiceIsEnabled(sc.Service) {
|
||||||
warnings = append(warnings,
|
warnings = append(warnings,
|
||||||
errors.Errorf("%s service is not enabled, please run 'systemctl enable %s.service'",
|
errors.Errorf("%s service is not enabled, please run '%s'",
|
||||||
sc.Service, sc.Service))
|
sc.Service, initSystem.EnableCommand(sc.Service)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if sc.CheckIfActive && !initSystem.ServiceIsActive(sc.Service) {
|
if sc.CheckIfActive && !initSystem.ServiceIsActive(sc.Service) {
|
||||||
|
@ -7,8 +7,19 @@ load(
|
|||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["initsystem.go"],
|
srcs = [
|
||||||
|
"initsystem.go",
|
||||||
|
"initsystem_unix.go",
|
||||||
|
"initsystem_windows.go",
|
||||||
|
],
|
||||||
importpath = "k8s.io/kubernetes/pkg/util/initsystem",
|
importpath = "k8s.io/kubernetes/pkg/util/initsystem",
|
||||||
|
deps = select({
|
||||||
|
"@io_bazel_rules_go//go/platform:windows": [
|
||||||
|
"//vendor/golang.org/x/sys/windows/svc:go_default_library",
|
||||||
|
"//vendor/golang.org/x/sys/windows/svc/mgr:go_default_library",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
|
@ -16,12 +16,6 @@ limitations under the License.
|
|||||||
|
|
||||||
package initsystem
|
package initsystem
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InitSystem interface {
|
type InitSystem interface {
|
||||||
// return a string describing how to enable a service
|
// return a string describing how to enable a service
|
||||||
EnableCommand(service string) string
|
EnableCommand(service string) string
|
||||||
@ -44,202 +38,3 @@ type InitSystem interface {
|
|||||||
// ServiceIsActive ensures the service is running, or attempting to run. (crash looping in the case of kubelet)
|
// ServiceIsActive ensures the service is running, or attempting to run. (crash looping in the case of kubelet)
|
||||||
ServiceIsActive(service string) bool
|
ServiceIsActive(service string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenRCInitSystem struct{}
|
|
||||||
|
|
||||||
func (openrc OpenRCInitSystem) ServiceStart(service string) error {
|
|
||||||
args := []string{service, "start"}
|
|
||||||
return exec.Command("rc-service", args...).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (openrc OpenRCInitSystem) ServiceStop(service string) error {
|
|
||||||
args := []string{service, "stop"}
|
|
||||||
return exec.Command("rc-service", args...).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (openrc OpenRCInitSystem) ServiceRestart(service string) error {
|
|
||||||
args := []string{service, "restart"}
|
|
||||||
return exec.Command("rc-service", args...).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// openrc writes to stderr if a service is not found or not enabled
|
|
||||||
// this is in contrast to systemd which only writes to stdout.
|
|
||||||
// Hence, we use the Combinedoutput, and ignore the error.
|
|
||||||
func (openrc OpenRCInitSystem) ServiceExists(service string) bool {
|
|
||||||
args := []string{service, "status"}
|
|
||||||
outBytes, _ := exec.Command("rc-service", args...).CombinedOutput()
|
|
||||||
if strings.Contains(string(outBytes), "does not exist") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (openrc OpenRCInitSystem) ServiceIsEnabled(service string) bool {
|
|
||||||
args := []string{"show", "default"}
|
|
||||||
outBytes, _ := exec.Command("rc-update", args...).Output()
|
|
||||||
if strings.Contains(string(outBytes), service) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (openrc OpenRCInitSystem) ServiceIsActive(service string) bool {
|
|
||||||
args := []string{service, "status"}
|
|
||||||
outBytes, _ := exec.Command("rc-service", args...).Output()
|
|
||||||
if strings.Contains(string(outBytes), "stopped") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (openrc OpenRCInitSystem) EnableCommand(service string) string {
|
|
||||||
return fmt.Sprintf("rc-update add %s default", service)
|
|
||||||
}
|
|
||||||
|
|
||||||
type SystemdInitSystem struct{}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) EnableCommand(service string) string {
|
|
||||||
return fmt.Sprintf("systemctl enable %s.service", service)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) reloadSystemd() error {
|
|
||||||
if err := exec.Command("systemctl", "daemon-reload").Run(); err != nil {
|
|
||||||
return fmt.Errorf("failed to reload systemd: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) ServiceStart(service string) error {
|
|
||||||
// Before we try to start any service, make sure that systemd is ready
|
|
||||||
if err := sysd.reloadSystemd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
args := []string{"start", service}
|
|
||||||
return exec.Command("systemctl", args...).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) ServiceRestart(service string) error {
|
|
||||||
// Before we try to restart any service, make sure that systemd is ready
|
|
||||||
if err := sysd.reloadSystemd(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
args := []string{"restart", service}
|
|
||||||
return exec.Command("systemctl", args...).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) ServiceStop(service string) error {
|
|
||||||
args := []string{"stop", service}
|
|
||||||
return exec.Command("systemctl", args...).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) ServiceExists(service string) bool {
|
|
||||||
args := []string{"status", service}
|
|
||||||
outBytes, _ := exec.Command("systemctl", args...).Output()
|
|
||||||
output := string(outBytes)
|
|
||||||
if strings.Contains(output, "Loaded: not-found") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd SystemdInitSystem) ServiceIsEnabled(service string) bool {
|
|
||||||
args := []string{"is-enabled", service}
|
|
||||||
err := exec.Command("systemctl", args...).Run()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceIsActive will check is the service is "active". In the case of
|
|
||||||
// crash looping services (kubelet in our case) status will return as
|
|
||||||
// "activating", so we will consider this active as well.
|
|
||||||
func (sysd SystemdInitSystem) ServiceIsActive(service string) bool {
|
|
||||||
args := []string{"is-active", service}
|
|
||||||
// Ignoring error here, command returns non-0 if in "activating" status:
|
|
||||||
outBytes, _ := exec.Command("systemctl", args...).Output()
|
|
||||||
output := strings.TrimSpace(string(outBytes))
|
|
||||||
if output == "active" || output == "activating" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// WindowsInitSystem is the windows implementation of InitSystem
|
|
||||||
type WindowsInitSystem struct{}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) EnableCommand(service string) string {
|
|
||||||
return fmt.Sprintf("Set-Service '%s' -StartupType Automatic", service)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) ServiceStart(service string) error {
|
|
||||||
args := []string{"Start-Service", service}
|
|
||||||
err := exec.Command("powershell", args...).Run()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) ServiceRestart(service string) error {
|
|
||||||
if err := sysd.ServiceStop(service); err != nil {
|
|
||||||
return fmt.Errorf("couldn't stop service: %v", err)
|
|
||||||
}
|
|
||||||
if err := sysd.ServiceStart(service); err != nil {
|
|
||||||
return fmt.Errorf("couldn't start service: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) ServiceStop(service string) error {
|
|
||||||
args := []string{"Stop-Service", service}
|
|
||||||
err := exec.Command("powershell", args...).Run()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) ServiceExists(service string) bool {
|
|
||||||
args := []string{"Get-Service", service}
|
|
||||||
err := exec.Command("powershell", args...).Run()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) ServiceIsEnabled(service string) bool {
|
|
||||||
args := []string{"Get-Service", service + "| select -property starttype"}
|
|
||||||
outBytes, _ := exec.Command("powershell", args...).Output()
|
|
||||||
output := strings.TrimSpace(string(outBytes))
|
|
||||||
if strings.Contains(output, "Automatic") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sysd WindowsInitSystem) ServiceIsActive(service string) bool {
|
|
||||||
args := []string{"Get-Service", service + "| select -property status"}
|
|
||||||
outBytes, _ := exec.Command("powershell", args...).Output()
|
|
||||||
output := strings.TrimSpace(string(outBytes))
|
|
||||||
if strings.Contains(output, "Running") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInitSystem returns an InitSystem for the current system, or nil
|
|
||||||
// if we cannot detect a supported init system for pre-flight checks.
|
|
||||||
// This indicates we will skip init system checks, not an error.
|
|
||||||
func GetInitSystem() (InitSystem, error) {
|
|
||||||
// Assume existence of systemctl in path implies this is a systemd system:
|
|
||||||
_, err := exec.LookPath("systemctl")
|
|
||||||
if err == nil {
|
|
||||||
return &SystemdInitSystem{}, nil
|
|
||||||
}
|
|
||||||
_, err = exec.LookPath("openrc")
|
|
||||||
if err == nil {
|
|
||||||
return &OpenRCInitSystem{}, nil
|
|
||||||
}
|
|
||||||
_, err = exec.LookPath("wininit.exe")
|
|
||||||
if err == nil {
|
|
||||||
return &WindowsInitSystem{}, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("no supported init system detected, skipping checking for services")
|
|
||||||
}
|
|
||||||
|
162
pkg/util/initsystem/initsystem_unix.go
Normal file
162
pkg/util/initsystem/initsystem_unix.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package initsystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OpenRCInitSystem struct{}
|
||||||
|
|
||||||
|
func (openrc OpenRCInitSystem) ServiceStart(service string) error {
|
||||||
|
args := []string{service, "start"}
|
||||||
|
return exec.Command("rc-service", args...).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (openrc OpenRCInitSystem) ServiceStop(service string) error {
|
||||||
|
args := []string{service, "stop"}
|
||||||
|
return exec.Command("rc-service", args...).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (openrc OpenRCInitSystem) ServiceRestart(service string) error {
|
||||||
|
args := []string{service, "restart"}
|
||||||
|
return exec.Command("rc-service", args...).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// openrc writes to stderr if a service is not found or not enabled
|
||||||
|
// this is in contrast to systemd which only writes to stdout.
|
||||||
|
// Hence, we use the Combinedoutput, and ignore the error.
|
||||||
|
func (openrc OpenRCInitSystem) ServiceExists(service string) bool {
|
||||||
|
args := []string{service, "status"}
|
||||||
|
outBytes, _ := exec.Command("rc-service", args...).CombinedOutput()
|
||||||
|
if strings.Contains(string(outBytes), "does not exist") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (openrc OpenRCInitSystem) ServiceIsEnabled(service string) bool {
|
||||||
|
args := []string{"show", "default"}
|
||||||
|
outBytes, _ := exec.Command("rc-update", args...).Output()
|
||||||
|
if strings.Contains(string(outBytes), service) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (openrc OpenRCInitSystem) ServiceIsActive(service string) bool {
|
||||||
|
args := []string{service, "status"}
|
||||||
|
outBytes, _ := exec.Command("rc-service", args...).Output()
|
||||||
|
if strings.Contains(string(outBytes), "stopped") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (openrc OpenRCInitSystem) EnableCommand(service string) string {
|
||||||
|
return fmt.Sprintf("rc-update add %s default", service)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SystemdInitSystem struct{}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) EnableCommand(service string) string {
|
||||||
|
return fmt.Sprintf("systemctl enable %s.service", service)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) reloadSystemd() error {
|
||||||
|
if err := exec.Command("systemctl", "daemon-reload").Run(); err != nil {
|
||||||
|
return fmt.Errorf("failed to reload systemd: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) ServiceStart(service string) error {
|
||||||
|
// Before we try to start any service, make sure that systemd is ready
|
||||||
|
if err := sysd.reloadSystemd(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
args := []string{"start", service}
|
||||||
|
return exec.Command("systemctl", args...).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) ServiceRestart(service string) error {
|
||||||
|
// Before we try to restart any service, make sure that systemd is ready
|
||||||
|
if err := sysd.reloadSystemd(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
args := []string{"restart", service}
|
||||||
|
return exec.Command("systemctl", args...).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) ServiceStop(service string) error {
|
||||||
|
args := []string{"stop", service}
|
||||||
|
return exec.Command("systemctl", args...).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) ServiceExists(service string) bool {
|
||||||
|
args := []string{"status", service}
|
||||||
|
outBytes, _ := exec.Command("systemctl", args...).Output()
|
||||||
|
output := string(outBytes)
|
||||||
|
if strings.Contains(output, "Loaded: not-found") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd SystemdInitSystem) ServiceIsEnabled(service string) bool {
|
||||||
|
args := []string{"is-enabled", service}
|
||||||
|
err := exec.Command("systemctl", args...).Run()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceIsActive will check is the service is "active". In the case of
|
||||||
|
// crash looping services (kubelet in our case) status will return as
|
||||||
|
// "activating", so we will consider this active as well.
|
||||||
|
func (sysd SystemdInitSystem) ServiceIsActive(service string) bool {
|
||||||
|
args := []string{"is-active", service}
|
||||||
|
// Ignoring error here, command returns non-0 if in "activating" status:
|
||||||
|
outBytes, _ := exec.Command("systemctl", args...).Output()
|
||||||
|
output := strings.TrimSpace(string(outBytes))
|
||||||
|
if output == "active" || output == "activating" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInitSystem returns an InitSystem for the current system, or nil
|
||||||
|
// if we cannot detect a supported init system.
|
||||||
|
// This indicates we will skip init system checks, not an error.
|
||||||
|
func GetInitSystem() (InitSystem, error) {
|
||||||
|
// Assume existence of systemctl in path implies this is a systemd system:
|
||||||
|
_, err := exec.LookPath("systemctl")
|
||||||
|
if err == nil {
|
||||||
|
return &SystemdInitSystem{}, nil
|
||||||
|
}
|
||||||
|
_, err = exec.LookPath("openrc")
|
||||||
|
if err == nil {
|
||||||
|
return &OpenRCInitSystem{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("no supported init system detected, skipping checking for services")
|
||||||
|
}
|
238
pkg/util/initsystem/initsystem_windows.go
Normal file
238
pkg/util/initsystem/initsystem_windows.go
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package initsystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/svc"
|
||||||
|
"golang.org/x/sys/windows/svc/mgr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WindowsInitSystem is the windows implementation of InitSystem
|
||||||
|
type WindowsInitSystem struct{}
|
||||||
|
|
||||||
|
func (sysd WindowsInitSystem) EnableCommand(service string) string {
|
||||||
|
return fmt.Sprintf("Set-Service '%s' -StartupType Automatic", service)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following Windows documentation: https://docs.microsoft.com/en-us/windows/desktop/Services/starting-a-service
|
||||||
|
func (sysd WindowsInitSystem) ServiceStart(service string) error {
|
||||||
|
m, err := mgr.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer m.Disconnect()
|
||||||
|
|
||||||
|
s, err := m.OpenService(service)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not access service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
// Check if service is already started
|
||||||
|
status, err := s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not query service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.State != svc.Stopped && status.State != svc.StopPending {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := time.Now().Add(10 * time.Second)
|
||||||
|
for status.State != svc.Stopped {
|
||||||
|
if timeout.Before(time.Now()) {
|
||||||
|
return fmt.Errorf("timeout waiting for %s service to stop", service)
|
||||||
|
}
|
||||||
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
status, err = s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve %s service status: %v", service, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the service
|
||||||
|
err = s.Start("is", "manual-started")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not start service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the start was successful
|
||||||
|
status, err = s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not query service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
timeout = time.Now().Add(10 * time.Second)
|
||||||
|
for status.State != svc.Running {
|
||||||
|
if timeout.Before(time.Now()) {
|
||||||
|
return fmt.Errorf("timeout waiting for %s service to start", service)
|
||||||
|
}
|
||||||
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
status, err = s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve %s service status: %v", service, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd WindowsInitSystem) ServiceRestart(service string) error {
|
||||||
|
if err := sysd.ServiceStop(service); err != nil {
|
||||||
|
return fmt.Errorf("couldn't stop service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
if err := sysd.ServiceStart(service); err != nil {
|
||||||
|
return fmt.Errorf("couldn't start service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following Windows documentation: https://docs.microsoft.com/en-us/windows/desktop/Services/stopping-a-service
|
||||||
|
func (sysd WindowsInitSystem) ServiceStop(service string) error {
|
||||||
|
m, err := mgr.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer m.Disconnect()
|
||||||
|
|
||||||
|
s, err := m.OpenService(service)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not access service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
// Check if service is already stopped
|
||||||
|
status, err := s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not query service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.State == svc.Stopped {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If StopPending, check that service eventually stops
|
||||||
|
if status.State == svc.StopPending {
|
||||||
|
timeout := time.Now().Add(10 * time.Second)
|
||||||
|
for status.State != svc.Stopped {
|
||||||
|
if timeout.Before(time.Now()) {
|
||||||
|
return fmt.Errorf("timeout waiting for %s service to stop", service)
|
||||||
|
}
|
||||||
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
status, err = s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve %s service status: %v", service, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the service
|
||||||
|
status, err = s.Control(svc.Stop)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not stop service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the stop was successful
|
||||||
|
status, err = s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not query service %s: %v", service, err)
|
||||||
|
}
|
||||||
|
timeout := time.Now().Add(10 * time.Second)
|
||||||
|
for status.State != svc.Stopped {
|
||||||
|
if timeout.Before(time.Now()) {
|
||||||
|
return fmt.Errorf("timeout waiting for %s service to stop", service)
|
||||||
|
}
|
||||||
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
status, err = s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not retrieve %s service status: %v", service, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd WindowsInitSystem) ServiceExists(service string) bool {
|
||||||
|
m, err := mgr.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer m.Disconnect()
|
||||||
|
s, err := m.OpenService(service)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd WindowsInitSystem) ServiceIsEnabled(service string) bool {
|
||||||
|
m, err := mgr.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer m.Disconnect()
|
||||||
|
|
||||||
|
s, err := m.OpenService(service)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
c, err := s.Config()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.StartType != mgr.StartDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sysd WindowsInitSystem) ServiceIsActive(service string) bool {
|
||||||
|
m, err := mgr.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer m.Disconnect()
|
||||||
|
s, err := m.OpenService(service)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
status, err := s.Query()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return status.State == svc.Running
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInitSystem returns an InitSystem for the current system, or nil
|
||||||
|
// if we cannot detect a supported init system.
|
||||||
|
// This indicates we will skip init system checks, not an error.
|
||||||
|
func GetInitSystem() (InitSystem, error) {
|
||||||
|
m, err := mgr.Connect()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("no supported init system detected: %v", err)
|
||||||
|
}
|
||||||
|
defer m.Disconnect()
|
||||||
|
return &WindowsInitSystem{}, nil
|
||||||
|
}
|
5
vendor/golang.org/x/sys/windows/svc/BUILD
generated
vendored
5
vendor/golang.org/x/sys/windows/svc/BUILD
generated
vendored
@ -31,7 +31,10 @@ filegroup(
|
|||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [":package-srcs"],
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//vendor/golang.org/x/sys/windows/svc/mgr:all-srcs",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
35
vendor/golang.org/x/sys/windows/svc/mgr/BUILD
generated
vendored
Normal file
35
vendor/golang.org/x/sys/windows/svc/mgr/BUILD
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"config.go",
|
||||||
|
"mgr.go",
|
||||||
|
"recovery.go",
|
||||||
|
"service.go",
|
||||||
|
],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/golang.org/x/sys/windows/svc/mgr",
|
||||||
|
importpath = "golang.org/x/sys/windows/svc/mgr",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = select({
|
||||||
|
"@io_bazel_rules_go//go/platform:windows": [
|
||||||
|
"//vendor/golang.org/x/sys/windows:go_default_library",
|
||||||
|
"//vendor/golang.org/x/sys/windows/svc:go_default_library",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
145
vendor/golang.org/x/sys/windows/svc/mgr/config.go
generated
vendored
Normal file
145
vendor/golang.org/x/sys/windows/svc/mgr/config.go
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package mgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Service start types.
|
||||||
|
StartManual = windows.SERVICE_DEMAND_START // the service must be started manually
|
||||||
|
StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots
|
||||||
|
StartDisabled = windows.SERVICE_DISABLED // the service cannot be started
|
||||||
|
|
||||||
|
// The severity of the error, and action taken,
|
||||||
|
// if this service fails to start.
|
||||||
|
ErrorCritical = windows.SERVICE_ERROR_CRITICAL
|
||||||
|
ErrorIgnore = windows.SERVICE_ERROR_IGNORE
|
||||||
|
ErrorNormal = windows.SERVICE_ERROR_NORMAL
|
||||||
|
ErrorSevere = windows.SERVICE_ERROR_SEVERE
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it.
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
ServiceType uint32
|
||||||
|
StartType uint32
|
||||||
|
ErrorControl uint32
|
||||||
|
BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service
|
||||||
|
LoadOrderGroup string
|
||||||
|
TagId uint32
|
||||||
|
Dependencies []string
|
||||||
|
ServiceStartName string // name of the account under which the service should run
|
||||||
|
DisplayName string
|
||||||
|
Password string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
func toString(p *uint16) string {
|
||||||
|
if p == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func toStringSlice(ps *uint16) []string {
|
||||||
|
if ps == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := make([]string, 0)
|
||||||
|
for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
|
||||||
|
if p[i] == 0 {
|
||||||
|
// empty string marks the end
|
||||||
|
if i <= from {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r = append(r, string(utf16.Decode(p[from:i])))
|
||||||
|
from = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config retrieves service s configuration paramteres.
|
||||||
|
func (s *Service) Config() (Config, error) {
|
||||||
|
var p *windows.QUERY_SERVICE_CONFIG
|
||||||
|
n := uint32(1024)
|
||||||
|
for {
|
||||||
|
b := make([]byte, n)
|
||||||
|
p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
|
||||||
|
err := windows.QueryServiceConfig(s.Handle, p, n, &n)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_DESCRIPTION)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
|
||||||
|
|
||||||
|
return Config{
|
||||||
|
ServiceType: p.ServiceType,
|
||||||
|
StartType: p.StartType,
|
||||||
|
ErrorControl: p.ErrorControl,
|
||||||
|
BinaryPathName: toString(p.BinaryPathName),
|
||||||
|
LoadOrderGroup: toString(p.LoadOrderGroup),
|
||||||
|
TagId: p.TagId,
|
||||||
|
Dependencies: toStringSlice(p.Dependencies),
|
||||||
|
ServiceStartName: toString(p.ServiceStartName),
|
||||||
|
DisplayName: toString(p.DisplayName),
|
||||||
|
Description: toString(p2.Description),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateDescription(handle windows.Handle, desc string) error {
|
||||||
|
d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)}
|
||||||
|
return windows.ChangeServiceConfig2(handle,
|
||||||
|
windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateConfig updates service s configuration parameters.
|
||||||
|
func (s *Service) UpdateConfig(c Config) error {
|
||||||
|
err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
|
||||||
|
c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
|
||||||
|
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
|
||||||
|
toPtr(c.Password), toPtr(c.DisplayName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return updateDescription(s.Handle, c.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryServiceConfig2 calls Windows QueryServiceConfig2 with infoLevel parameter and returns retrieved service configuration information.
|
||||||
|
func (s *Service) queryServiceConfig2(infoLevel uint32) ([]byte, error) {
|
||||||
|
n := uint32(1024)
|
||||||
|
for {
|
||||||
|
b := make([]byte, n)
|
||||||
|
err := windows.QueryServiceConfig2(s.Handle, infoLevel, &b[0], n, &n)
|
||||||
|
if err == nil {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n <= uint32(len(b)) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
162
vendor/golang.org/x/sys/windows/svc/mgr/mgr.go
generated
vendored
Normal file
162
vendor/golang.org/x/sys/windows/svc/mgr/mgr.go
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
// Package mgr can be used to manage Windows service programs.
|
||||||
|
// It can be used to install and remove them. It can also start,
|
||||||
|
// stop and pause them. The package can query / change current
|
||||||
|
// service state and config parameters.
|
||||||
|
//
|
||||||
|
package mgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mgr is used to manage Windows service.
|
||||||
|
type Mgr struct {
|
||||||
|
Handle windows.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect establishes a connection to the service control manager.
|
||||||
|
func Connect() (*Mgr, error) {
|
||||||
|
return ConnectRemote("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectRemote establishes a connection to the
|
||||||
|
// service control manager on computer named host.
|
||||||
|
func ConnectRemote(host string) (*Mgr, error) {
|
||||||
|
var s *uint16
|
||||||
|
if host != "" {
|
||||||
|
s = syscall.StringToUTF16Ptr(host)
|
||||||
|
}
|
||||||
|
h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Mgr{Handle: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect closes connection to the service control manager m.
|
||||||
|
func (m *Mgr) Disconnect() error {
|
||||||
|
return windows.CloseServiceHandle(m.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPtr(s string) *uint16 {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return syscall.StringToUTF16Ptr(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toStringBlock terminates strings in ss with 0, and then
|
||||||
|
// concatenates them together. It also adds extra 0 at the end.
|
||||||
|
func toStringBlock(ss []string) *uint16 {
|
||||||
|
if len(ss) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
t := ""
|
||||||
|
for _, s := range ss {
|
||||||
|
if s != "" {
|
||||||
|
t += s + "\x00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
t += "\x00"
|
||||||
|
return &utf16.Encode([]rune(t))[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateService installs new service name on the system.
|
||||||
|
// The service will be executed by running exepath binary.
|
||||||
|
// Use config c to specify service parameters.
|
||||||
|
// Any args will be passed as command-line arguments when
|
||||||
|
// the service is started; these arguments are distinct from
|
||||||
|
// the arguments passed to Service.Start or via the "Start
|
||||||
|
// parameters" field in the service's Properties dialog box.
|
||||||
|
func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
|
||||||
|
if c.StartType == 0 {
|
||||||
|
c.StartType = StartManual
|
||||||
|
}
|
||||||
|
if c.ErrorControl == 0 {
|
||||||
|
c.ErrorControl = ErrorNormal
|
||||||
|
}
|
||||||
|
if c.ServiceType == 0 {
|
||||||
|
c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
|
||||||
|
}
|
||||||
|
s := syscall.EscapeArg(exepath)
|
||||||
|
for _, v := range args {
|
||||||
|
s += " " + syscall.EscapeArg(v)
|
||||||
|
}
|
||||||
|
h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
|
||||||
|
windows.SERVICE_ALL_ACCESS, c.ServiceType,
|
||||||
|
c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
|
||||||
|
nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.Description != "" {
|
||||||
|
err = updateDescription(h, c.Description)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Service{Name: name, Handle: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenService retrieves access to service name, so it can
|
||||||
|
// be interrogated and controlled.
|
||||||
|
func (m *Mgr) OpenService(name string) (*Service, error) {
|
||||||
|
h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Service{Name: name, Handle: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServices enumerates services in the specified
|
||||||
|
// service control manager database m.
|
||||||
|
// If the caller does not have the SERVICE_QUERY_STATUS
|
||||||
|
// access right to a service, the service is silently
|
||||||
|
// omitted from the list of services returned.
|
||||||
|
func (m *Mgr) ListServices() ([]string, error) {
|
||||||
|
var err error
|
||||||
|
var bytesNeeded, servicesReturned uint32
|
||||||
|
var buf []byte
|
||||||
|
for {
|
||||||
|
var p *byte
|
||||||
|
if len(buf) > 0 {
|
||||||
|
p = &buf[0]
|
||||||
|
}
|
||||||
|
err = windows.EnumServicesStatusEx(m.Handle, windows.SC_ENUM_PROCESS_INFO,
|
||||||
|
windows.SERVICE_WIN32, windows.SERVICE_STATE_ALL,
|
||||||
|
p, uint32(len(buf)), &bytesNeeded, &servicesReturned, nil, nil)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != syscall.ERROR_MORE_DATA {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if bytesNeeded <= uint32(len(buf)) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
buf = make([]byte, bytesNeeded)
|
||||||
|
}
|
||||||
|
if servicesReturned == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
services := (*[1 << 20]windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0]))[:servicesReturned]
|
||||||
|
var names []string
|
||||||
|
for _, s := range services {
|
||||||
|
name := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(s.ServiceName))[:])
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names, nil
|
||||||
|
}
|
135
vendor/golang.org/x/sys/windows/svc/mgr/recovery.go
generated
vendored
Normal file
135
vendor/golang.org/x/sys/windows/svc/mgr/recovery.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package mgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Possible recovery actions that the service control manager can perform.
|
||||||
|
NoAction = windows.SC_ACTION_NONE // no action
|
||||||
|
ComputerReboot = windows.SC_ACTION_REBOOT // reboot the computer
|
||||||
|
ServiceRestart = windows.SC_ACTION_RESTART // restart the service
|
||||||
|
RunCommand = windows.SC_ACTION_RUN_COMMAND // run a command
|
||||||
|
)
|
||||||
|
|
||||||
|
// RecoveryAction represents an action that the service control manager can perform when service fails.
|
||||||
|
// A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.
|
||||||
|
type RecoveryAction struct {
|
||||||
|
Type int // one of NoAction, ComputerReboot, ServiceRestart or RunCommand
|
||||||
|
Delay time.Duration // the time to wait before performing the specified action
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRecoveryActions sets actions that service controller performs when service fails and
|
||||||
|
// the time after which to reset the service failure count to zero if there are no failures, in seconds.
|
||||||
|
// Specify INFINITE to indicate that service failure count should never be reset.
|
||||||
|
func (s *Service) SetRecoveryActions(recoveryActions []RecoveryAction, resetPeriod uint32) error {
|
||||||
|
if recoveryActions == nil {
|
||||||
|
return errors.New("recoveryActions cannot be nil")
|
||||||
|
}
|
||||||
|
actions := []windows.SC_ACTION{}
|
||||||
|
for _, a := range recoveryActions {
|
||||||
|
action := windows.SC_ACTION{
|
||||||
|
Type: uint32(a.Type),
|
||||||
|
Delay: uint32(a.Delay.Nanoseconds() / 1000000),
|
||||||
|
}
|
||||||
|
actions = append(actions, action)
|
||||||
|
}
|
||||||
|
rActions := windows.SERVICE_FAILURE_ACTIONS{
|
||||||
|
ActionsCount: uint32(len(actions)),
|
||||||
|
Actions: &actions[0],
|
||||||
|
ResetPeriod: resetPeriod,
|
||||||
|
}
|
||||||
|
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoveryActions returns actions that service controller performs when service fails.
|
||||||
|
// The service control manager counts the number of times service s has failed since the system booted.
|
||||||
|
// The count is reset to 0 if the service has not failed for ResetPeriod seconds.
|
||||||
|
// When the service fails for the Nth time, the service controller performs the action specified in element [N-1] of returned slice.
|
||||||
|
// If N is greater than slice length, the service controller repeats the last action in the slice.
|
||||||
|
func (s *Service) RecoveryActions() ([]RecoveryAction, error) {
|
||||||
|
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||||
|
if p.Actions == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var recoveryActions []RecoveryAction
|
||||||
|
actions := (*[1024]windows.SC_ACTION)(unsafe.Pointer(p.Actions))[:p.ActionsCount]
|
||||||
|
for _, action := range actions {
|
||||||
|
recoveryActions = append(recoveryActions, RecoveryAction{Type: int(action.Type), Delay: time.Duration(action.Delay) * time.Millisecond})
|
||||||
|
}
|
||||||
|
return recoveryActions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetRecoveryActions deletes both reset period and array of failure actions.
|
||||||
|
func (s *Service) ResetRecoveryActions() error {
|
||||||
|
actions := make([]windows.SC_ACTION, 1)
|
||||||
|
rActions := windows.SERVICE_FAILURE_ACTIONS{
|
||||||
|
Actions: &actions[0],
|
||||||
|
}
|
||||||
|
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetPeriod is the time after which to reset the service failure
|
||||||
|
// count to zero if there are no failures, in seconds.
|
||||||
|
func (s *Service) ResetPeriod() (uint32, error) {
|
||||||
|
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||||
|
return p.ResetPeriod, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRebootMessage sets service s reboot message.
|
||||||
|
// If msg is "", the reboot message is deleted and no message is broadcast.
|
||||||
|
func (s *Service) SetRebootMessage(msg string) error {
|
||||||
|
rActions := windows.SERVICE_FAILURE_ACTIONS{
|
||||||
|
RebootMsg: syscall.StringToUTF16Ptr(msg),
|
||||||
|
}
|
||||||
|
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebootMessage is broadcast to server users before rebooting in response to the ComputerReboot service controller action.
|
||||||
|
func (s *Service) RebootMessage() (string, error) {
|
||||||
|
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||||
|
return toString(p.RebootMsg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRecoveryCommand sets the command line of the process to execute in response to the RunCommand service controller action.
|
||||||
|
// If cmd is "", the command is deleted and no program is run when the service fails.
|
||||||
|
func (s *Service) SetRecoveryCommand(cmd string) error {
|
||||||
|
rActions := windows.SERVICE_FAILURE_ACTIONS{
|
||||||
|
Command: syscall.StringToUTF16Ptr(cmd),
|
||||||
|
}
|
||||||
|
return windows.ChangeServiceConfig2(s.Handle, windows.SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&rActions)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoveryCommand is the command line of the process to execute in response to the RunCommand service controller action. This process runs under the same account as the service.
|
||||||
|
func (s *Service) RecoveryCommand() (string, error) {
|
||||||
|
b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_FAILURE_ACTIONS)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
p := (*windows.SERVICE_FAILURE_ACTIONS)(unsafe.Pointer(&b[0]))
|
||||||
|
return toString(p.Command), nil
|
||||||
|
}
|
72
vendor/golang.org/x/sys/windows/svc/mgr/service.go
generated
vendored
Normal file
72
vendor/golang.org/x/sys/windows/svc/mgr/service.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package mgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
"golang.org/x/sys/windows/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(brainman): Use EnumDependentServices to enumerate dependent services.
|
||||||
|
|
||||||
|
// Service is used to access Windows service.
|
||||||
|
type Service struct {
|
||||||
|
Name string
|
||||||
|
Handle windows.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete marks service s for deletion from the service control manager database.
|
||||||
|
func (s *Service) Delete() error {
|
||||||
|
return windows.DeleteService(s.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close relinquish access to the service s.
|
||||||
|
func (s *Service) Close() error {
|
||||||
|
return windows.CloseServiceHandle(s.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts service s.
|
||||||
|
// args will be passed to svc.Handler.Execute.
|
||||||
|
func (s *Service) Start(args ...string) error {
|
||||||
|
var p **uint16
|
||||||
|
if len(args) > 0 {
|
||||||
|
vs := make([]*uint16, len(args))
|
||||||
|
for i := range vs {
|
||||||
|
vs[i] = syscall.StringToUTF16Ptr(args[i])
|
||||||
|
}
|
||||||
|
p = &vs[0]
|
||||||
|
}
|
||||||
|
return windows.StartService(s.Handle, uint32(len(args)), p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control sends state change request c to the servce s.
|
||||||
|
func (s *Service) Control(c svc.Cmd) (svc.Status, error) {
|
||||||
|
var t windows.SERVICE_STATUS
|
||||||
|
err := windows.ControlService(s.Handle, uint32(c), &t)
|
||||||
|
if err != nil {
|
||||||
|
return svc.Status{}, err
|
||||||
|
}
|
||||||
|
return svc.Status{
|
||||||
|
State: svc.State(t.CurrentState),
|
||||||
|
Accepts: svc.Accepted(t.ControlsAccepted),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query returns current status of service s.
|
||||||
|
func (s *Service) Query() (svc.Status, error) {
|
||||||
|
var t windows.SERVICE_STATUS
|
||||||
|
err := windows.QueryServiceStatus(s.Handle, &t)
|
||||||
|
if err != nil {
|
||||||
|
return svc.Status{}, err
|
||||||
|
}
|
||||||
|
return svc.Status{
|
||||||
|
State: svc.State(t.CurrentState),
|
||||||
|
Accepts: svc.Accepted(t.ControlsAccepted),
|
||||||
|
}, nil
|
||||||
|
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -878,6 +878,7 @@ golang.org/x/sys/unix
|
|||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
golang.org/x/sys/windows/registry
|
golang.org/x/sys/windows/registry
|
||||||
golang.org/x/sys/windows/svc
|
golang.org/x/sys/windows/svc
|
||||||
|
golang.org/x/sys/windows/svc/mgr
|
||||||
# golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db => golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db
|
# golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db => golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db
|
||||||
golang.org/x/text/encoding
|
golang.org/x/text/encoding
|
||||||
golang.org/x/text/encoding/charmap
|
golang.org/x/text/encoding/charmap
|
||||||
|
Loading…
Reference in New Issue
Block a user