k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/util/initsystem/initsystem_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 Copyright 2017 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package initsystem 21 22 import ( 23 "fmt" 24 "time" 25 26 "github.com/pkg/errors" 27 "golang.org/x/sys/windows/svc" 28 "golang.org/x/sys/windows/svc/mgr" 29 ) 30 31 // WindowsInitSystem is the windows implementation of InitSystem 32 type WindowsInitSystem struct{} 33 34 // EnableCommand return a string describing how to enable a service 35 func (sysd WindowsInitSystem) EnableCommand(service string) string { 36 return fmt.Sprintf("Set-Service '%s' -StartupType Automatic", service) 37 } 38 39 // ServiceStart tries to start a specific service 40 // Following Windows documentation: https://docs.microsoft.com/en-us/windows/desktop/Services/starting-a-service 41 func (sysd WindowsInitSystem) ServiceStart(service string) error { 42 m, err := mgr.Connect() 43 if err != nil { 44 return err 45 } 46 defer m.Disconnect() 47 48 s, err := m.OpenService(service) 49 if err != nil { 50 return errors.Wrapf(err, "could not access service %s", service) 51 } 52 defer s.Close() 53 54 // Check if service is already started 55 status, err := s.Query() 56 if err != nil { 57 return errors.Wrapf(err, "could not query service %s", service) 58 } 59 60 if status.State != svc.Stopped && status.State != svc.StopPending { 61 return nil 62 } 63 64 timeout := time.Now().Add(10 * time.Second) 65 for status.State != svc.Stopped { 66 if timeout.Before(time.Now()) { 67 return errors.Errorf("timeout waiting for %s service to stop", service) 68 } 69 time.Sleep(300 * time.Millisecond) 70 status, err = s.Query() 71 if err != nil { 72 return errors.Wrapf(err, "could not retrieve %s service status", service) 73 } 74 } 75 76 // Start the service 77 err = s.Start("is", "manual-started") 78 if err != nil { 79 return errors.Wrapf(err, "could not start service %s", service) 80 } 81 82 // Check that the start was successful 83 status, err = s.Query() 84 if err != nil { 85 return errors.Wrapf(err, "could not query service %s", service) 86 } 87 timeout = time.Now().Add(10 * time.Second) 88 for status.State != svc.Running { 89 if timeout.Before(time.Now()) { 90 return errors.Errorf("timeout waiting for %s service to start", service) 91 } 92 time.Sleep(300 * time.Millisecond) 93 status, err = s.Query() 94 if err != nil { 95 return errors.Wrapf(err, "could not retrieve %s service status", service) 96 } 97 } 98 return nil 99 } 100 101 // ServiceRestart tries to reload the environment and restart the specific service 102 func (sysd WindowsInitSystem) ServiceRestart(service string) error { 103 if err := sysd.ServiceStop(service); err != nil { 104 return errors.Wrapf(err, "couldn't stop service %s", service) 105 } 106 if err := sysd.ServiceStart(service); err != nil { 107 return errors.Wrapf(err, "couldn't start service %s", service) 108 } 109 110 return nil 111 } 112 113 // ServiceStop tries to stop a specific service 114 // Following Windows documentation: https://docs.microsoft.com/en-us/windows/desktop/Services/stopping-a-service 115 func (sysd WindowsInitSystem) ServiceStop(service string) error { 116 m, err := mgr.Connect() 117 if err != nil { 118 return err 119 } 120 defer m.Disconnect() 121 122 s, err := m.OpenService(service) 123 if err != nil { 124 return errors.Wrapf(err, "could not access service %s", service) 125 } 126 defer s.Close() 127 128 // Check if service is already stopped 129 status, err := s.Query() 130 if err != nil { 131 return errors.Wrapf(err, "could not query service %s", service) 132 } 133 134 if status.State == svc.Stopped { 135 return nil 136 } 137 138 // If StopPending, check that service eventually stops 139 if status.State == svc.StopPending { 140 timeout := time.Now().Add(10 * time.Second) 141 for status.State != svc.Stopped { 142 if timeout.Before(time.Now()) { 143 return errors.Errorf("timeout waiting for %s service to stop", service) 144 } 145 time.Sleep(300 * time.Millisecond) 146 status, err = s.Query() 147 if err != nil { 148 return errors.Wrapf(err, "could not retrieve %s service status", service) 149 } 150 } 151 return nil 152 } 153 154 // Stop the service 155 status, err = s.Control(svc.Stop) 156 if err != nil { 157 return errors.Wrapf(err, "could not stop service %s", service) 158 } 159 160 // Check that the stop was successful 161 status, err = s.Query() 162 if err != nil { 163 return errors.Wrapf(err, "could not query service %s", service) 164 } 165 timeout := time.Now().Add(10 * time.Second) 166 for status.State != svc.Stopped { 167 if timeout.Before(time.Now()) { 168 return errors.Errorf("timeout waiting for %s service to stop", service) 169 } 170 time.Sleep(300 * time.Millisecond) 171 status, err = s.Query() 172 if err != nil { 173 return errors.Wrapf(err, "could not retrieve %s service status", service) 174 } 175 } 176 return nil 177 } 178 179 // ServiceExists ensures the service is defined for this init system. 180 func (sysd WindowsInitSystem) ServiceExists(service string) bool { 181 m, err := mgr.Connect() 182 if err != nil { 183 return false 184 } 185 defer m.Disconnect() 186 s, err := m.OpenService(service) 187 if err != nil { 188 return false 189 } 190 defer s.Close() 191 192 return true 193 } 194 195 // ServiceIsEnabled ensures the service is enabled to start on each boot. 196 func (sysd WindowsInitSystem) ServiceIsEnabled(service string) bool { 197 m, err := mgr.Connect() 198 if err != nil { 199 return false 200 } 201 defer m.Disconnect() 202 203 s, err := m.OpenService(service) 204 if err != nil { 205 return false 206 } 207 defer s.Close() 208 209 c, err := s.Config() 210 if err != nil { 211 return false 212 } 213 214 return c.StartType != mgr.StartDisabled 215 } 216 217 // ServiceIsActive ensures the service is running, or attempting to run. (crash looping in the case of kubelet) 218 func (sysd WindowsInitSystem) ServiceIsActive(service string) bool { 219 m, err := mgr.Connect() 220 if err != nil { 221 return false 222 } 223 defer m.Disconnect() 224 s, err := m.OpenService(service) 225 if err != nil { 226 return false 227 } 228 defer s.Close() 229 230 status, err := s.Query() 231 if err != nil { 232 return false 233 } 234 return status.State == svc.Running 235 } 236 237 // GetInitSystem returns an InitSystem for the current system, or nil 238 // if we cannot detect a supported init system. 239 // This indicates we will skip init system checks, not an error. 240 func GetInitSystem() (InitSystem, error) { 241 m, err := mgr.Connect() 242 if err != nil { 243 return nil, errors.Wrap(err, "no supported init system detected") 244 } 245 defer m.Disconnect() 246 return &WindowsInitSystem{}, nil 247 }