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  `