Ubuntu: start on install
This commit is contained in:
		
							parent
							
								
									2b7148c3ae
								
							
						
					
					
						commit
						04e162b20f
					
				| @ -172,6 +172,7 @@ move serviceman.exe %userprofile%\bin\serviceman.exe | ||||
| **All Others** | ||||
| 
 | ||||
| ``` | ||||
| chmod a+x ./serviceman | ||||
| sudo mv ./serviceman /usr/local/bin/ | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
| @ -12,18 +12,20 @@ | ||||
| # sudo journalctl {{ if not .System -}} --user {{ end -}} -xefu {{ .Name }} | ||||
| 
 | ||||
| [Unit] | ||||
| Description={{ .Title }} - {{ .Desc }} | ||||
| Description={{ .Title }} {{ if .Desc }}- {{ .Desc }}{{ end }} | ||||
| {{ if .URL -}} | ||||
| Documentation={{ .URL }} | ||||
| {{ end -}} | ||||
| {{ if .System -}} | ||||
| After=network-online.target | ||||
| Wants=network-online.target systemd-networkd-wait-online.service | ||||
| {{- end }} | ||||
| 
 | ||||
| {{ end -}} | ||||
| [Service] | ||||
| # Restart on crash (bad signal), but not on 'clean' failure (error exit code) | ||||
| # Allow up to 3 restarts within 10 seconds | ||||
| # (it's unlikely that a user or properly-running script will do this) | ||||
| Restart=on-abnormal | ||||
| Restart=always | ||||
| StartLimitInterval=10 | ||||
| StartLimitBurst=3 | ||||
| 
 | ||||
| @ -36,7 +38,7 @@ Group={{ .Group }} | ||||
| {{ if .Workdir -}} | ||||
| WorkingDirectory={{ .Workdir }} | ||||
| {{ end -}} | ||||
| ExecStart={{if .Interpreter }}{{ .Interpreter }} {{ end }}{{ .Exec }} {{- range $arg := .Argv }}{{ $arg }} {{- end }} | ||||
| ExecStart={{if .Interpreter }}{{ .Interpreter }} {{ end }}{{ .Exec }}{{ range $arg := .Argv }} {{ $arg }}{{ end }} | ||||
| ExecReload=/bin/kill -USR1 $MAINPID | ||||
| 
 | ||||
| {{if .Production -}} | ||||
|  | ||||
| @ -58,6 +58,8 @@ func start(system bool, home string, name string) error { | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	cmds = adjustPrivs(system, cmds) | ||||
| 
 | ||||
| 	fmt.Println() | ||||
| 	for i := range cmds { | ||||
| 		exe := cmds[i] | ||||
| @ -112,8 +114,7 @@ func install(c *service.Service) error { | ||||
| 	plistName := c.ReverseDNS + ".plist" | ||||
| 	plistPath := filepath.Join(plistDir, plistName) | ||||
| 	if err := ioutil.WriteFile(plistPath, rw.Bytes(), 0644); err != nil { | ||||
| 
 | ||||
| 		return fmt.Errorf("ioutil.WriteFile error: %v", err) | ||||
| 		return fmt.Errorf("Error writing %s: %v", plistPath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO --no-start | ||||
| @ -127,20 +128,4 @@ func install(c *service.Service) error { | ||||
| 
 | ||||
| 	fmt.Printf("Added and started '%s' as a launchctl service.\n", c.Name) | ||||
| 	return nil | ||||
| 
 | ||||
| 	/* | ||||
| 		fmt.Printf("Installed. To start '%s' run the following:\n", c.Name) | ||||
| 		// TODO template config file | ||||
| 		if "" != c.Home { | ||||
| 			plistPath = strings.Replace(plistPath, c.Home, "~", 1) | ||||
| 		} | ||||
| 		sudo := "" | ||||
| 		if c.System { | ||||
| 			sudo = "sudo " | ||||
| 		} | ||||
| 		fmt.Printf("\t%slaunchctl load -w %s\n", sudo, plistPath) | ||||
| 
 | ||||
| 
 | ||||
| 		return nil | ||||
| 	*/ | ||||
| } | ||||
|  | ||||
| @ -16,13 +16,97 @@ var ( | ||||
| 	srvLen     int | ||||
| 	srvExt     = ".service" | ||||
| 	srvSysPath = "/etc/systemd/system" | ||||
| 	srvUserPath = ".local/share/systemd/user" | ||||
| 
 | ||||
| 	// Not sure which of these it's supposed to be... | ||||
| 	// * ~/.local/share/systemd/user/watchdog.service | ||||
| 	// * ~/.config/systemd/user/watchdog.service | ||||
| 	// https://wiki.archlinux.org/index.php/Systemd/User | ||||
| 	// This seems to work on Ubuntu | ||||
| 	srvUserPath = ".config/systemd/user" | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	srvLen = len(srvExt) | ||||
| } | ||||
| 
 | ||||
| func start(system bool, home string, name string) error { | ||||
| 	sys, user, err := getMatchingSrvs(home, name) | ||||
| 	if nil != err { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var service string | ||||
| 	if system { | ||||
| 		service, err = getOneSysSrv(sys, user, name) | ||||
| 		if nil != err { | ||||
| 			return err | ||||
| 		} | ||||
| 		service = filepath.Join(srvSysPath, service) | ||||
| 	} else { | ||||
| 		service, err = getOneUserSrv(home, sys, user, name) | ||||
| 		if nil != err { | ||||
| 			return err | ||||
| 		} | ||||
| 		service = filepath.Join(home, srvUserPath, service) | ||||
| 	} | ||||
| 
 | ||||
| 	var cmds []Runnable | ||||
| 	if system { | ||||
| 		cmds = []Runnable{ | ||||
| 			Runnable{ | ||||
| 				Exec: "systemctl", | ||||
| 				Args: []string{"daemon-reload"}, | ||||
| 				Must: false, | ||||
| 			}, | ||||
| 			Runnable{ | ||||
| 				Exec: "systemctl", | ||||
| 				Args: []string{"stop", name + ".service"}, | ||||
| 				Must: false, | ||||
| 			}, | ||||
| 			Runnable{ | ||||
| 				Exec:     "systemctl", | ||||
| 				Args:     []string{"start", name + ".service"}, | ||||
| 				Badwords: []string{"not found", "failed"}, | ||||
| 				Must:     true, | ||||
| 			}, | ||||
| 		} | ||||
| 	} else { | ||||
| 		cmds = []Runnable{ | ||||
| 			Runnable{ | ||||
| 				Exec: "systemctl", | ||||
| 				Args: []string{"--user", "daemon-reload"}, | ||||
| 				Must: false, | ||||
| 			}, | ||||
| 			Runnable{ | ||||
| 				Exec: "systemctl", | ||||
| 				Args: []string{"stop", "--user", name + ".service"}, | ||||
| 				Must: false, | ||||
| 			}, | ||||
| 			Runnable{ | ||||
| 				Exec:     "systemctl", | ||||
| 				Args:     []string{"start", "--user", name + ".service"}, | ||||
| 				Badwords: []string{"not found", "failed"}, | ||||
| 				Must:     true, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	cmds = adjustPrivs(system, cmds) | ||||
| 
 | ||||
| 	fmt.Println() | ||||
| 	for i := range cmds { | ||||
| 		exe := cmds[i] | ||||
| 		fmt.Println(exe.String()) | ||||
| 		err := exe.Run() | ||||
| 		if nil != err { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Println() | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func install(c *service.Service) error { | ||||
| 	// Linux-specific config options | ||||
| 	if c.System { | ||||
| @ -33,17 +117,12 @@ func install(c *service.Service) error { | ||||
| 	if "" == c.Group { | ||||
| 		c.Group = c.User | ||||
| 	} | ||||
| 	serviceDir := srvSysPath | ||||
| 
 | ||||
| 	// Check paths first | ||||
| 	serviceName := c.Name + ".service" | ||||
| 	serviceDir := srvSysPath | ||||
| 	if !c.System { | ||||
| 		// Not sure which of these it's supposed to be... | ||||
| 		// * ~/.local/share/systemd/user/watchdog.service | ||||
| 		// * ~/.config/systemd/user/watchdog.service | ||||
| 		// https://wiki.archlinux.org/index.php/Systemd/User | ||||
| 		serviceDir = filepath.Join(c.Home, srvUserPath) | ||||
| 		err := os.MkdirAll(filepath.Dir(serviceDir), 0755) | ||||
| 		err := os.MkdirAll(serviceDir, 0755) | ||||
| 		if nil != err { | ||||
| 			return err | ||||
| 		} | ||||
| @ -67,22 +146,27 @@ func install(c *service.Service) error { | ||||
| 	} | ||||
| 
 | ||||
| 	// Write the file out | ||||
| 	serviceName := c.Name + ".service" | ||||
| 	servicePath := filepath.Join(serviceDir, serviceName) | ||||
| 	if err := ioutil.WriteFile(servicePath, rw.Bytes(), 0644); err != nil { | ||||
| 		return fmt.Errorf("ioutil.WriteFile error: %v", err) | ||||
| 		return fmt.Errorf("Error writing %s: %v", servicePath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO template this as well? | ||||
| 	userspace := "" | ||||
| 	sudo := "sudo " | ||||
| 	if !c.System { | ||||
| 		userspace = "--user " | ||||
| 		sudo = "" | ||||
| 	// TODO --no-start | ||||
| 	err = start(c.System, c.Home, c.Name) | ||||
| 	if nil != err { | ||||
| 		sudo := "" | ||||
| 		// --user-unit rather than --user --unit for older systemd | ||||
| 		unit := "--user-unit" | ||||
| 		if c.System { | ||||
| 			sudo = "sudo " | ||||
| 			unit = "--unit" | ||||
| 		} | ||||
| 	fmt.Printf("System service installed as '%s'.\n", servicePath) | ||||
| 	fmt.Printf("Run the following to start '%s':\n", c.Name) | ||||
| 	fmt.Printf("\t" + sudo + "systemctl " + userspace + "daemon-reload\n") | ||||
| 	fmt.Printf("\t"+sudo+"systemctl "+userspace+"restart %s.service\n", c.Name) | ||||
| 	fmt.Printf("\t"+sudo+"journalctl "+userspace+"-xefu %s\n", c.Name) | ||||
| 		fmt.Printf("If things don't go well you should be able to get additional logging from journalctl:\n") | ||||
| 		fmt.Printf("\t%sjournalctl -xe %s %s.service\n", sudo, unit, c.Name) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("Added and started '%s' as a systemd service.\n", c.Name) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -45,34 +45,33 @@ func (x Runnable) Run() error { | ||||
| 		} | ||||
| 	} | ||||
| 	if nil != err { | ||||
| 		return fmt.Errorf("Failed to run %s %s\n%s\n", x.Exec, strings.Join(x.Args, " "), str) | ||||
| 		var comment string | ||||
| 		if len(x.Keywords) > 0 { | ||||
| 			comment += "# output must match all of:\n" | ||||
| 			comment += "# \t" + strings.Join(x.Keywords, "\n#\t") + "\n" | ||||
| 		} | ||||
| 		if len(x.Badwords) > 0 { | ||||
| 			comment += "# output must not match any of:\n" | ||||
| 			comment += "# \t" + strings.Join(x.Badwords, "\n#\t") + "\n" | ||||
| 		} | ||||
| 		return fmt.Errorf("Failed to run %s %s\n%s\n%s\n", x.Exec, strings.Join(x.Args, " "), str, comment) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (x Runnable) String() string { | ||||
| 	var comment string | ||||
| 	var must = "true" | ||||
| 
 | ||||
| 	if x.Must { | ||||
| 		must = "exit" | ||||
| 		if len(x.Keywords) > 0 { | ||||
| 			comment += "# output must match all of:\n" | ||||
| 			comment += "\t" + strings.Join(x.Keywords, "#\t \n") + "\n" | ||||
| 		} | ||||
| 		if len(x.Badwords) > 0 { | ||||
| 			comment += "# output must not match any of:\n" | ||||
| 			comment += "\t" + strings.Join(x.Keywords, "#\t \n") + "\n" | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return strings.TrimSpace(fmt.Sprintf( | ||||
| 		"%s %s || %s\n%s", | ||||
| 		"%s %s || %s\n", | ||||
| 		x.Exec, | ||||
| 		strings.Join(x.Args, " "), | ||||
| 		must, | ||||
| 		comment, | ||||
| 	)) | ||||
| } | ||||
| 
 | ||||
| @ -203,3 +202,20 @@ func getOneUserSrv(home string, sys []string, user []string, name string) (strin | ||||
| 
 | ||||
| 	return service, nil | ||||
| } | ||||
| 
 | ||||
| func adjustPrivs(system bool, cmds []Runnable) []Runnable { | ||||
| 	if !system || isPrivileged() { | ||||
| 		return cmds | ||||
| 	} | ||||
| 
 | ||||
| 	sudos := cmds | ||||
| 	cmds = []Runnable{} | ||||
| 	for i := range sudos { | ||||
| 		exe := sudos[i] | ||||
| 		exe.Args = append([]string{exe.Exec}, exe.Args...) | ||||
| 		exe.Exec = "sudo" | ||||
| 		cmds = append(cmds, exe) | ||||
| 	} | ||||
| 
 | ||||
| 	return cmds | ||||
| } | ||||
|  | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -126,15 +126,16 @@ func add() { | ||||
| 	conf.Normalize(force) | ||||
| 
 | ||||
| 	//fmt.Printf("\n%#v\n\n", conf) | ||||
| 	if conf.System && !manager.IsPrivileged() { | ||||
| 		fmt.Fprintf(os.Stderr, "Warning: You may need to use 'sudo' to add %q as a privileged system service.\n", conf.Name) | ||||
| 	} | ||||
| 
 | ||||
| 	err = manager.Install(conf) | ||||
| 	if nil != err { | ||||
| 		fmt.Fprintf(os.Stderr, "%s\n", err) | ||||
| 		fmt.Fprintf(os.Stderr, "Use 'sudo' to add service as a privileged system service.\n") | ||||
| 		fmt.Fprintf(os.Stderr, "Use '--user' to add service as an user service.\n") | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("If all went well the logs should have been created at:\n\t%s\n", conf.Logdir) | ||||
| 	printLogMessage(conf) | ||||
| 	fmt.Println() | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										11
									
								
								serviceman_darwin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								serviceman_darwin.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| ) | ||||
| 
 | ||||
| func printLogMessage(conf *service.Service) { | ||||
| 	fmt.Printf("If all went well the logs should have been created at:\n\t%s\n", conf.Logdir) | ||||
| } | ||||
							
								
								
									
										26
									
								
								serviceman_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								serviceman_linux.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"git.rootprojects.org/root/go-serviceman/manager" | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| ) | ||||
| 
 | ||||
| func printLogMessage(conf *service.Service) { | ||||
| 	sudo := "" | ||||
| 	unit := "--unit" | ||||
| 	if conf.System { | ||||
| 		if !manager.IsPrivileged() { | ||||
| 			sudo = "sudo" | ||||
| 		} | ||||
| 	} else { | ||||
| 		unit = "--user-unit" | ||||
| 	} | ||||
| 	fmt.Println("If all went well you should be able to see some goodies in the logs:") | ||||
| 	fmt.Printf("\t%sjournalctl -xe %s %s.service\n", sudo, unit, conf.Name) | ||||
| 	if !conf.System { | ||||
| 		fmt.Println("\nIf that's not the case, see https://unix.stackexchange.com/a/486566/45554.") | ||||
| 		fmt.Println("(you may need to run `systemctl restart systemd-journald`)") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										11
									
								
								serviceman_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								serviceman_windows.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"git.rootprojects.org/root/go-serviceman/service" | ||||
| ) | ||||
| 
 | ||||
| func printLogMessage(conf *service.Service) { | ||||
| 	fmt.Printf("If all went well the logs should have been created at:\n\t%s\n", conf.Logdir) | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user