github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/service/windows/service.go (about)

     1  // Copyright 2014 Cloudbase Solutions
     2  // Copyright 2014 Canonical Ltd.
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  package windows
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"strings"
    11  
    12  	"github.com/juju/loggo"
    13  	"github.com/juju/utils/exec"
    14  
    15  	"github.com/juju/juju/service/common"
    16  )
    17  
    18  var logger = loggo.GetLogger("juju.worker.deployer.service")
    19  
    20  var serviceInstallScript = `$data = Get-Content "C:\Juju\Jujud.pass"
    21  if($? -eq $false){Write-Error "Failed to read encrypted password"; exit 1}
    22  $serviceName = "%s"
    23  $secpasswd = $data | convertto-securestring
    24  if($? -eq $false){Write-Error "Failed decode password"; exit 1}
    25  $juju_user = whoami
    26  $jujuCreds = New-Object System.Management.Automation.PSCredential($juju_user, $secpasswd)
    27  if($? -eq $false){Write-Error "Failed to create secure credentials"; exit 1}
    28  New-Service -Credential $jujuCreds -Name "$serviceName" -DisplayName '%s' '%s'
    29  if($? -eq $false){Write-Error "Failed to install service $serviceName"; exit 1}
    30  cmd.exe /C call sc config $serviceName start=delayed-auto
    31  if($? -eq $false){Write-Error "Failed execute sc"; exit 1}
    32  `
    33  
    34  // Service represents a service running on the current system
    35  type Service struct {
    36  	Name string
    37  	Conf common.Conf
    38  }
    39  
    40  func runPsCommand(cmd string) (*exec.ExecResponse, error) {
    41  	com := exec.RunParams{
    42  		Commands: cmd,
    43  	}
    44  	out, err := exec.RunCommands(com)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	if out.Code != 0 {
    49  		return nil, fmt.Errorf("Error running %s: %s", cmd, string(out.Stderr))
    50  	}
    51  	return out, nil
    52  }
    53  
    54  func (s *Service) UpdateConfig(conf common.Conf) {
    55  	s.Conf = conf
    56  }
    57  
    58  // Status gets the service status
    59  func (s *Service) Status() (string, error) {
    60  	cmd := fmt.Sprintf(`$ErrorActionPreference="Stop"; (Get-Service "%s").Status`, s.Name)
    61  	out, err := runPsCommand(cmd)
    62  	if err != nil {
    63  		return "", err
    64  	}
    65  	return string(out.Stdout), nil
    66  }
    67  
    68  // Running returns true if the Service appears to be running.
    69  func (s *Service) Running() bool {
    70  	status, err := s.Status()
    71  	logger.Infof("Service %q Status %q", s.Name, status)
    72  	if err != nil {
    73  		return false
    74  	}
    75  	if strings.TrimSpace(status) == "Stopped" {
    76  		return false
    77  	}
    78  	return true
    79  }
    80  
    81  // Installed returns whether the service is installed
    82  func (s *Service) Installed() bool {
    83  	_, err := s.Status()
    84  	if err == nil {
    85  		return true
    86  	}
    87  	return false
    88  }
    89  
    90  // Exists returns whether the service configuration exists in the
    91  // init directory with the same content that this Service would have
    92  // if installed.
    93  // TODO (gabriel-samfira): 2014-07-30 bug 1350171
    94  // Needs a proper implementation when testing is improved
    95  func (s *Service) Exists() bool {
    96  	return false
    97  }
    98  
    99  // Start starts the service.
   100  func (s *Service) Start() error {
   101  	cmd := fmt.Sprintf(`$ErrorActionPreference="Stop"; Start-Service  "%s"`, s.Name)
   102  	logger.Infof("Starting service %q", s.Name)
   103  	if s.Running() {
   104  		logger.Infof("Service %q already running", s.Name)
   105  		return nil
   106  	}
   107  	_, err := runPsCommand(cmd)
   108  	return err
   109  }
   110  
   111  // Stop stops the service.
   112  func (s *Service) Stop() error {
   113  	if !s.Running() {
   114  		return nil
   115  	}
   116  	cmd := fmt.Sprintf(`$ErrorActionPreference="Stop"; Stop-Service  "%s"`, s.Name)
   117  	_, err := runPsCommand(cmd)
   118  	return err
   119  }
   120  
   121  // Remove deletes the service.
   122  func (s *Service) Remove() error {
   123  	_, err := s.Status()
   124  	if err != nil {
   125  		return err
   126  	}
   127  	cmd := fmt.Sprintf(`$ErrorActionPreference="Stop"; (gwmi win32_service -filter 'name="%s"').Delete()`, s.Name)
   128  	_, err = runPsCommand(cmd)
   129  	return err
   130  }
   131  
   132  // StopAndRemove stops the service and then deletes the service.
   133  func (s *Service) StopAndRemove() error {
   134  	err := s.Stop()
   135  	if err != nil {
   136  		return err
   137  	}
   138  	return s.Remove()
   139  }
   140  
   141  func (s *Service) validate() error {
   142  	if s.Conf.Cmd == "" {
   143  		return errors.New("missing Cmd")
   144  	}
   145  	if s.Conf.Desc == "" {
   146  		return errors.New("missing Description")
   147  	}
   148  	if s.Name == "" {
   149  		return errors.New("missing Name")
   150  	}
   151  	return nil
   152  }
   153  
   154  // Install installs and starts the service.
   155  func (s *Service) Install() error {
   156  	err := s.validate()
   157  	if err != nil {
   158  		return err
   159  	}
   160  	if s.Installed() {
   161  		return errors.New(fmt.Sprintf("Service %s already installed", s.Name))
   162  	}
   163  
   164  	logger.Infof("Installing Service %v", s.Name)
   165  	cmd := fmt.Sprintf(serviceInstallScript,
   166  		s.Name,
   167  		s.Conf.Desc,
   168  		s.Conf.Cmd)
   169  	outCmd, errCmd := runPsCommand(cmd)
   170  
   171  	if errCmd != nil {
   172  		logger.Infof("ERROR installing service %v --> %v", outCmd, errCmd)
   173  		return errCmd
   174  	}
   175  	return s.Start()
   176  }
   177  
   178  // NewService returns a new Service type
   179  func NewService(name string, conf common.Conf) *Service {
   180  	return &Service{
   181  		Name: name,
   182  		Conf: conf,
   183  	}
   184  }
   185  
   186  // InstallCommands returns shell commands to install and start the service.
   187  func (s *Service) InstallCommands() ([]string, error) {
   188  	cmd := fmt.Sprintf(serviceInstallScript,
   189  		s.Name,
   190  		s.Conf.Desc,
   191  		s.Conf.Cmd)
   192  	return strings.Split(cmd, "\n"), nil
   193  }