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 }