github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmg/SubCommand/serviceCmd/Service.go (about) 1 package serviceCmd 2 3 import ( 4 "os" 5 "os/exec" 6 "strings" 7 8 "github.com/bronze1man/kmg/errors" 9 "github.com/bronze1man/kmg/kmgCmd" 10 "github.com/bronze1man/kmg/kmgFile" 11 "github.com/bronze1man/kmg/kmgTextTemplate" 12 ) 13 14 var ErrServiceExist = errors.New("Service already exist") 15 16 //这个是服务的定义数据结构,会序列化到具体实现的配置文件里面去 17 type Service struct { 18 Name string //Required 19 WorkingDirectory string 20 CommandLineSlice []string //Required 运行命令需要的slice数组.不要包含空格 21 } 22 23 func (s *Service) init() (err error) { 24 if s.Name == "" { 25 return errors.New("[Service] require Service.Name") 26 } 27 if s.WorkingDirectory == "" { 28 s.WorkingDirectory = "/" 29 } 30 if len(s.CommandLineSlice) == 0 { 31 return errors.New("[Service] require Service.CommandLineSlice") 32 } 33 s.CommandLineSlice[0], err = exec.LookPath(s.CommandLineSlice[0]) 34 return err 35 } 36 37 func (s *Service) GetCommandLineBashString() string { 38 return kmgCmd.BashEscape(strings.Join(s.CommandLineSlice, " ")) 39 } 40 41 func getConfigPath(name string) string { 42 return "/etc/init.d/" + name 43 } 44 45 func Install(s *Service) (err error) { 46 err = s.init() 47 if err != nil { 48 return err 49 } 50 confPath := getConfigPath(s.Name) 51 _, err = os.Stat(confPath) 52 if err != nil && !os.IsNotExist(err) { 53 return err 54 } 55 if err == nil { 56 return ErrServiceExist 57 } 58 out := kmgTextTemplate.MustRender(sysvScript, s) 59 err = kmgFile.WriteFile(confPath, out) 60 if err != nil { 61 return err 62 } 63 err = os.Chmod(confPath, 0755) 64 if err != nil { 65 return err 66 } 67 for _, i := range [...]string{"2", "3", "4", "5"} { 68 if err = os.Symlink(confPath, "/etc/rc"+i+".d/S50"+s.Name); err != nil { 69 continue 70 } 71 } 72 for _, i := range [...]string{"0", "1", "6"} { 73 if err = os.Symlink(confPath, "/etc/rc"+i+".d/K02"+s.Name); err != nil { 74 continue 75 } 76 } 77 return nil 78 } 79 80 func Uninstall(name string) (err error) { 81 Stop(name) 82 // TODO Stop 里面关闭不是错误. 83 confPath := getConfigPath(name) 84 pathList := []string{ 85 confPath, 86 } 87 for _, i := range [...]string{"2", "3", "4", "5"} { 88 pathList = append(pathList, "/etc/rc"+i+".d/S50"+name) 89 } 90 for _, i := range [...]string{"0", "1", "6"} { 91 pathList = append(pathList, "/etc/rc"+i+".d/K02"+name) 92 } 93 for _, path := range pathList { 94 kmgFile.MustDelete(path) 95 } 96 return nil 97 } 98 99 func Start(name string) (err error) { 100 c := waitRpcRespond() 101 err = kmgCmd.CmdSlice([]string{"service", name, "start"}).Run() 102 if err != nil { 103 return err 104 } 105 return <-c 106 } 107 108 //TODO 已经关闭不是错误 109 func Stop(name string) (err error) { 110 return kmgCmd.CmdSlice([]string{"service", name, "stop"}).Run() 111 } 112 113 func Restart(name string) (err error) { 114 c := waitRpcRespond() 115 err = kmgCmd.CmdSlice([]string{"service", name, "restart"}).Run() 116 if err != nil { 117 return err 118 } 119 return <-c 120 } 121 122 func RestartV1(name string) (err error) { 123 return kmgCmd.CmdSlice([]string{"service", name, "restart"}).Run() 124 } 125 126 const sysvScript = `#!/bin/bash 127 # For RedHat and cousins: 128 # chkconfig: - 99 01 129 130 ### BEGIN INIT INFO 131 # Required-Start: 132 # Required-Stop: 133 # Default-Start: 2 3 4 5 134 # Default-Stop: 0 1 6 135 ### END INIT INFO 136 137 ulimit -n 1048576 138 139 cmd={{.GetCommandLineBashString}} 140 141 name='{{.Name}}' 142 pid_file="/var/run/$name.pid" 143 stdout_log="/var/log/$name.log" 144 145 get_pid() { 146 cat "$pid_file" 147 } 148 149 is_running() { 150 [ -f "$pid_file" ] && ps $(get_pid) > /dev/null 2>&1 151 } 152 153 case "$1" in 154 start) 155 if is_running; then 156 echo "Already started" 157 else 158 echo "Starting $name" 159 cd '{{.WorkingDirectory}}' 160 $cmd &>> "$stdout_log" & 161 echo $! > "$pid_file" 162 if ! is_running; then 163 echo "Unable to start, see $stdout_log and $stderr_log" 164 exit 1 165 fi 166 fi 167 ;; 168 stop) 169 if is_running; then 170 echo -n "Stopping $name.." 171 kill $(get_pid) 172 for i in {1..10} 173 do 174 if ! is_running; then 175 break 176 fi 177 echo -n "." 178 sleep 1 179 done 180 echo 181 if is_running; then 182 echo "Not stopped; may still be shutting down or shutdown may have failed" 183 exit 1 184 else 185 echo "Stopped" 186 if [ -f "$pid_file" ]; then 187 rm "$pid_file" 188 fi 189 fi 190 else 191 echo "Not running" 192 fi 193 ;; 194 restart) 195 $0 stop 196 if is_running; then 197 echo "Unable to stop, will not attempt to start" 198 exit 1 199 fi 200 $0 start 201 ;; 202 status) 203 if is_running; then 204 echo "Running" 205 else 206 echo "Stopped" 207 exit 1 208 fi 209 ;; 210 *) 211 echo "Usage: $0 {start|stop|restart|status}" 212 exit 1 213 ;; 214 esac 215 exit 0 216 `