agent/install/service_linux.go (181 lines of code) (raw):

package install import ( "github.com/aliyun/aliyun_assist_client/thirdparty/service" "github.com/aliyun/aliyun_assist_client/agent/util/systemdutil" ) const ( systemdScript = `[Unit] Description={{.Description}} ConditionFileIsExecutable={{.Path|cmdEscape}} {{range $i, $dep := .Dependencies}} {{$dep}} {{end}} [Service] StandardOutput=journal+console StandardError=journal+console StartLimitInterval=3600 StartLimitBurst=10 ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}} {{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}} {{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}} {{if .UserName}}User={{.UserName}}{{end}} {{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}} {{if .PIDFile}}PIDFile={{.PIDFile|cmd}}{{end}} {{if and .LogOutput .HasOutputFileSupport -}} StandardOutput=file:/var/log/{{.Name}}.out StandardError=file:/var/log/{{.Name}}.err {{- end}} {{if gt .LimitNOFILE -1 }}LimitNOFILE={{.LimitNOFILE}}{{end}} {{if .Restart}}Restart={{.Restart}}{{end}} {{if .SuccessExitStatus}}SuccessExitStatus={{.SuccessExitStatus}}{{end}} RestartSec=120 EnvironmentFile=-/etc/sysconfig/{{.Name}} KillMode=process [Install] WantedBy=multi-user.target ` // NOTE: sysvinit script below is copied from https://github.com/kardianos/service/master/service_sysv_linux.go // with modification: // * In chkconfig configuration [default_runlevels start_priority stop_priority], // runlevels to be started by default is modified which should be consistent // with LSB init configuration below. And two priorities is also modified // to be consistent with installing code in library. // * "Required-Start" part of LSB init configuration is modified according to // https://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/facilname.html // for service dependency ordering, like what systemd provides. // See https://linux.die.net/man/8/chkconfig for more details sysvScript = `#!/bin/sh # For RedHat and cousins: # chkconfig: 2345 50 02 # description: {{.Description}} # processname: {{.Path}} ### BEGIN INIT INFO # Provides: {{.Path}} # Required-Start: $local_fs $network $named $remote_fs # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: {{.DisplayName}} # Description: {{.Description}} ### END INIT INFO cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}" name=$(basename $(readlink -f $0)) pid_file="/var/run/$name.pid" stdout_log="/var/log/$name.log" stderr_log="/var/log/$name.err" [ -e /etc/sysconfig/$name ] && . /etc/sysconfig/$name get_pid() { cat "$pid_file" } is_running() { [ -f "$pid_file" ] && ps $(get_pid) > /dev/null 2>&1 } case "$1" in start) if is_running; then echo "Already started" else echo "Starting $name" {{if .WorkingDirectory}}cd '{{.WorkingDirectory}}'{{end}} $cmd >> "$stdout_log" 2>> "$stderr_log" & echo $! > "$pid_file" if ! is_running; then echo "Unable to start, see $stdout_log and $stderr_log" exit 1 fi fi ;; stop) if is_running; then echo -n "Stopping $name.." kill $(get_pid) for i in $(seq 1 10) do if ! is_running; then break fi echo -n "." sleep 1 done echo if is_running; then echo "Not stopped; may still be shutting down or shutdown may have failed" exit 1 else echo "Stopped" if [ -f "$pid_file" ]; then rm "$pid_file" fi fi else echo "Not running" fi ;; restart) $0 stop if is_running; then echo "Unable to stop, will not attempt to start" exit 1 fi $0 start ;; status) if is_running; then echo "Running" else echo "Stopped" exit 1 fi ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 ` upstartScript = `# {{.Description}} {{if .DisplayName}}description "{{.DisplayName}}"{{end}} {{if .HasKillStanza}}kill signal INT{{end}} {{if .ChRoot}}chroot {{.ChRoot}}{{end}} {{if .WorkingDirectory}}chdir {{.WorkingDirectory}}{{end}} start on filesystem or runlevel [2345] stop on runlevel [!2345] {{if and .UserName .HasSetUIDStanza}}setuid {{.UserName}}{{end}} respawn respawn limit 3 120 normal exit 0 umask 022 console none pre-start script test -x {{.Path}} || { stop; exit 0; } end script # Start script {{if .LogOutput}} stdout_log="/var/log/{{.Name}}.out" stderr_log="/var/log/{{.Name}}.err" {{end}} if [ -f "/etc/sysconfig/{{.Name}}" ]; then set -a source /etc/sysconfig/{{.Name}} set +a fi exec {{if and .UserName (not .HasSetUIDStanza)}}sudo -E -u {{.UserName}} {{end}}{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}{{if .LogOutput}} >> $stdout_log 2>> $stderr_log{{end}} end script ` ) func ServiceConfig() *service.Config { ServiceName := "" depends := []string{} option := make(service.KeyValue) if systemdutil.IsRunningSystemd() { ServiceName = "aliyun" // Official doc https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/ // suggests both After= and Wants= configuration to delay a service after // network is up. Need validation on ALL distros and releases. depends = append(depends, "After=network-online.target") depends = append(depends, "Wants=network-online.target") option["SystemdScript"] = systemdScript option["Restart"] = "on-failure" // REMEMBER: Explicit disable LogOutput option of kardianos/service, and // use StandardOutput/StandardError settings manually written above. option["LogOutput"] = false } else { ServiceName = "aliyun-service" option["SysvScript"] = sysvScript option["UpstartScript"] = upstartScript option["LogOutput"] = true } return &service.Config{ // 服务显示名称 Name: ServiceName, // 服务名称 DisplayName: "Aliyun Assist Service", // 服务描述 Description: "Aliyun Assist", // TODO: Use symbolic link for shorter path needs more adaption // Executable: "/usr/sbin/aliyun-service", Dependencies: depends, //云助手依赖网络 Option: option, } }