...

Source file src/k8s.io/kubernetes/cmd/kubeadm/app/util/initsystem/initsystem_windows.go

Documentation: k8s.io/kubernetes/cmd/kubeadm/app/util/initsystem

     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  }
   248  

View as plain text