Compare commits
	
		
			2 Commits
		
	
	
		
			1e9f95295d
			...
			fb4f0c5a69
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fb4f0c5a69 | |||
| ae809d5d5e | 
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,6 +1,4 @@ | |||||||
| installer | /cmd/watchdog/installer/static | ||||||
| watchdog.service |  | ||||||
| /cmd/install/static |  | ||||||
| /watchdog | /watchdog | ||||||
| /cmd/watchdog/watchdog | /cmd/watchdog/watchdog | ||||||
| xversion.go | xversion.go | ||||||
|  | |||||||
| @ -1,23 +0,0 @@ | |||||||
| //go:generate go run -mod=vendor github.com/UnnoTed/fileb0x b0x.toml |  | ||||||
| 
 |  | ||||||
| // I'm prototyping this out to be useful for more than just watchdog |  | ||||||
| // hence there are a few unnecessary things for the sake of the trying it out |  | ||||||
| package main |  | ||||||
| 
 |  | ||||||
| type Config struct { |  | ||||||
| 	Name                string `json:"name"` |  | ||||||
| 	Desc                string `json:"desc"` |  | ||||||
| 	URL                 string `json:"url"` |  | ||||||
| 	Exec                string `json:"exec"` |  | ||||||
| 	Args                string `json:"args"` |  | ||||||
| 	User                string `json:"user"` |  | ||||||
| 	Group               string `json:"group"` |  | ||||||
| 	Production          bool   `json:"production"` |  | ||||||
| 	PrivilegedPorts     bool   `json:"privileged_ports"` |  | ||||||
| 	MultiuserProtection bool   `json:"multiuser_protection"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
| 
 |  | ||||||
| 	install() |  | ||||||
| } |  | ||||||
| @ -1,7 +0,0 @@ | |||||||
| package main |  | ||||||
| 
 |  | ||||||
| import "log" |  | ||||||
| 
 |  | ||||||
| func install() { |  | ||||||
| 	log.Fatal("not yet implemented") |  | ||||||
| } |  | ||||||
| @ -1,60 +0,0 @@ | |||||||
| // +build !windows !darwin |  | ||||||
| package main |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" |  | ||||||
| 	"log" |  | ||||||
| 	"text/template" |  | ||||||
| 
 |  | ||||||
| 	"git.rootprojects.org/root/watchdog.go/cmd/install/static" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func install() { |  | ||||||
| 	b, err := static.ReadFile("dist/etc/systemd/system/watchdog.service.tmpl") |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	s := string(b) |  | ||||||
| 
 |  | ||||||
| 	j, err := static.ReadFile("dist/etc/systemd/system/watchdog.service.json") |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	//conf := map[string]string{} |  | ||||||
| 	conf := &Config{} |  | ||||||
| 	err = json.Unmarshal(j, &conf) |  | ||||||
| 	if nil != err { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if "" == conf.Group { |  | ||||||
| 		conf.Group = conf.User |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	serviceFile := conf.Exec + ".service" |  | ||||||
| 
 |  | ||||||
| 	rw := &bytes.Buffer{} |  | ||||||
| 	// not sure what the template name does, but whatever |  | ||||||
| 	tmpl, err := template.New("service").Parse(s) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = tmpl.Execute(rw, conf) |  | ||||||
| 	if nil != err { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if err := ioutil.WriteFile(serviceFile, rw.Bytes(), 0644); err != nil { |  | ||||||
| 		log.Fatalf("ioutil.WriteFile error: %v", err) |  | ||||||
| 	} |  | ||||||
| 	fmt.Printf("Wrote %q\n", serviceFile) |  | ||||||
| } |  | ||||||
							
								
								
									
										63
									
								
								cmd/watchdog/install.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								cmd/watchdog/install.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"git.rootprojects.org/root/watchdog.go/cmd/watchdog/installer" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func install(binpath string, args []string) { | ||||||
|  | 	system := true | ||||||
|  | 	production := false | ||||||
|  | 	config := "./config.json" | ||||||
|  | 	for i := range os.Args { | ||||||
|  | 		switch { | ||||||
|  | 		case strings.HasSuffix(os.Args[i], "userspace"): | ||||||
|  | 			system = false | ||||||
|  | 		case strings.HasSuffix(os.Args[i], "production"): | ||||||
|  | 			fmt.Println("Warning: production options don't work on all systems. If you have trouble, drop this first.") | ||||||
|  | 			production = false | ||||||
|  | 		case "-c" == os.Args[i]: | ||||||
|  | 			if len(os.Args) <= i+1 { | ||||||
|  | 				fmt.Println("-c requires a string path to the config file") | ||||||
|  | 				os.Exit(1) | ||||||
|  | 			} | ||||||
|  | 			config = os.Args[i+1] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	/* | ||||||
|  | 		j, err := static.ReadFile("dist/etc/systemd/system/watchdog.service.json") | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		//conf := map[string]string{} | ||||||
|  | 		conf := &Config{} | ||||||
|  | 		err = json.Unmarshal(j, &conf) | ||||||
|  | 		if nil != err { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	*/ | ||||||
|  | 	err := installer.Install(&installer.Config{ | ||||||
|  | 		Title:               "Watchdog", | ||||||
|  | 		Desc:                "Get notified when sites go down", | ||||||
|  | 		URL:                 "https://git.rootprojects.org/root/watchdog.go", | ||||||
|  | 		Name:                "watchdog", | ||||||
|  | 		Exec:                "watchdog", | ||||||
|  | 		Local:               "", | ||||||
|  | 		System:              system, | ||||||
|  | 		Restart:             true, | ||||||
|  | 		Argv:                []string{"-c", config}, | ||||||
|  | 		PrivilegedPorts:     false, | ||||||
|  | 		MultiuserProtection: false, | ||||||
|  | 		Production:          production, | ||||||
|  | 	}) | ||||||
|  | 	if nil != err { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										71
									
								
								cmd/watchdog/installer/dist/Library/LaunchDaemons/_rdns_.plist.tmpl
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								cmd/watchdog/installer/dist/Library/LaunchDaemons/_rdns_.plist.tmpl
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>Label</key> | ||||||
|  | 	<string>{{ .Title }}</string> | ||||||
|  | 	<key>ProgramArguments</key> | ||||||
|  | 	<array> | ||||||
|  | 		{{- if .Interpreter }} | ||||||
|  | 		<string>{{ .Interpreter }}</string> | ||||||
|  | 		{{- end }} | ||||||
|  | 		<string>{{ .Local }}/opt/{{ .Name }}/{{ .Exec }}</string> | ||||||
|  | 	  {{- if .Argv }} | ||||||
|  | 		{{- range $arg := .Argv }} | ||||||
|  | 		<string>{{ $arg }}</string> | ||||||
|  | 		{{- end }} | ||||||
|  | 	  {{- end }} | ||||||
|  | 	</array> | ||||||
|  | 	{{- if .Envs }} | ||||||
|  | 	<key>EnvironmentVariables</key> | ||||||
|  | 	<dict> | ||||||
|  | 		{{- range $key, $value := .Envs }} | ||||||
|  | 		<key>{{ $key }}</key> | ||||||
|  | 		<string>{{ $value }}</string> | ||||||
|  | 		{{- end }} | ||||||
|  | 	</dict> | ||||||
|  | 	{{- end }} | ||||||
|  | 
 | ||||||
|  | 	{{if .User -}} | ||||||
|  | 	<key>UserName</key> | ||||||
|  | 	<string>{{ .User }}</string> | ||||||
|  | 	<key>GroupName</key> | ||||||
|  | 	<string>{{ .Group }}</string> | ||||||
|  | 	<key>InitGroups</key> | ||||||
|  | 	<true/> | ||||||
|  | 
 | ||||||
|  | 	{{end -}} | ||||||
|  | 	<key>RunAtLoad</key> | ||||||
|  | 	<true/> | ||||||
|  | 	{{ if .Restart -}} | ||||||
|  | 	<key>KeepAlive</key> | ||||||
|  | 	<true/> | ||||||
|  | 	<!--dict> | ||||||
|  | 		<key>Crashed</key> | ||||||
|  | 		<true/> | ||||||
|  | 		<key>NetworkState</key> | ||||||
|  | 		<true/> | ||||||
|  | 		<key>SuccessfulExit</key> | ||||||
|  | 		<false/> | ||||||
|  | 	</dict--> | ||||||
|  | 
 | ||||||
|  | 	{{ end -}} | ||||||
|  | 	{{ if .Production -}} | ||||||
|  | 	<key>SoftResourceLimits</key> | ||||||
|  | 	<dict> | ||||||
|  | 		<key>NumberOfFiles</key> | ||||||
|  | 		<integer>8192</integer> | ||||||
|  | 	</dict> | ||||||
|  | 	<key>HardResourceLimits</key> | ||||||
|  | 	<dict/> | ||||||
|  | 
 | ||||||
|  | 	{{ end -}} | ||||||
|  | 	<key>WorkingDirectory</key> | ||||||
|  | 	<string>{{ .Local }}/opt/{{ .Name }}</string> | ||||||
|  | 
 | ||||||
|  | 	<key>StandardErrorPath</key> | ||||||
|  | 	<string>{{ .LogDir }}/{{ .Name }}.log</string> | ||||||
|  | 	<key>StandardOutPath</key> | ||||||
|  | 	<string>{{ .LogDir }}/{{ .Name }}.log</string> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -1,18 +1,24 @@ | |||||||
| # Pre-req | # Pre-req | ||||||
| # sudo adduser {{ .Exec }} --home /opt/{{ .Exec }} | # sudo mkdir -p {{ .Local }}/opt/{{ .Name }}/ {{ .Local }}/var/log/{{ .Name }} | ||||||
| # sudo mkdir -p /opt/{{ .Exec }}/ /var/log/{{ .Exec }} | {{ if not .Local -}} | ||||||
| # sudo chown -R {{ .Exec }}:{{ .Exec }} /opt/{{ .Exec }}/ /var/log/{{ .Exec }} | {{ if .User -}} | ||||||
|  | # sudo adduser {{ .User }} --home /opt/{{ .Name }} | ||||||
|  | # sudo chown -R {{ .User }}:{{ .Group }} /opt/{{ .Name }}/ /var/log/{{ .Name }} | ||||||
|  | {{- end }} | ||||||
|  | {{- end }} | ||||||
| 
 | 
 | ||||||
| # Post-install | # Post-install | ||||||
| # sudo systemctl daemon-reload | # sudo systemctl {{ if .Local -}} --user {{- end }} daemon-reload | ||||||
| # sudo systemctl restart {{ .Exec }}.service | # sudo systemctl {{ if .Local -}} --user {{- end }} restart {{ .Name }}.service | ||||||
| # sudo journalctl -xefu {{ .Exec }} | # sudo journalctl {{ if .Local -}} --user {{- end }} -xefu {{ .Name }} | ||||||
| 
 | 
 | ||||||
| [Unit] | [Unit] | ||||||
| Description={{ .Name }} - {{ .Desc }} | Description={{ .Title }} - {{ .Desc }} | ||||||
| Documentation={{ .URL }} | Documentation={{ .URL }} | ||||||
|  | {{ if not .Local -}} | ||||||
| After=network-online.target | After=network-online.target | ||||||
| Wants=network-online.target systemd-networkd-wait-online.service | Wants=network-online.target systemd-networkd-wait-online.service | ||||||
|  | {{- end }} | ||||||
| 
 | 
 | ||||||
| [Service] | [Service] | ||||||
| # Restart on crash (bad signal), but not on 'clean' failure (error exit code) | # Restart on crash (bad signal), but not on 'clean' failure (error exit code) | ||||||
| @ -28,8 +34,8 @@ User={{ .User }} | |||||||
| Group={{ .Group }} | Group={{ .Group }} | ||||||
| 
 | 
 | ||||||
| {{ end -}} | {{ end -}} | ||||||
| WorkingDirectory=/opt/{{ .Exec }} | WorkingDirectory={{ .Local }}/opt/{{ .Name }} | ||||||
| ExecStart=/opt/{{ .Exec }}/{{ .Exec }} {{ .Args }} | ExecStart={{if .Interpreter }}{{ .Interpreter }} {{ end }}{{ .Local }}/opt/{{ .Name }}/{{ .Name }} {{ .Args }} | ||||||
| ExecReload=/bin/kill -USR1 $MAINPID | ExecReload=/bin/kill -USR1 $MAINPID | ||||||
| 
 | 
 | ||||||
| {{if .Production -}} | {{if .Production -}} | ||||||
| @ -49,14 +55,14 @@ PrivateDevices=true | |||||||
| ProtectHome=true | ProtectHome=true | ||||||
| # Make /usr, /boot, /etc and possibly some more folders read-only. | # Make /usr, /boot, /etc and possibly some more folders read-only. | ||||||
| ProtectSystem=full | ProtectSystem=full | ||||||
| # ... except /opt/{{ .Exec }} because we want a place for the database | # ... except /opt/{{ .Name }} because we want a place for the database | ||||||
| # and /var/log/{{ .Exec }} because we want a place where logs can go. | # and /var/log/{{ .Name }} because we want a place where logs can go. | ||||||
| # This merely retains r/w access rights, it does not add any new. | # This merely retains r/w access rights, it does not add any new. | ||||||
| # Must still be writable on the host! | # Must still be writable on the host! | ||||||
| ReadWriteDirectories=/opt/{{ .Exec }} /var/log/{{ .Exec }} | ReadWriteDirectories=/opt/{{ .Name }} /var/log/{{ .Name }} | ||||||
| 
 | 
 | ||||||
| # Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories | # Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories | ||||||
| ; ReadWritePaths=/opt/{{ .Exec }} /var/log/{{ .Exec }} | ; ReadWritePaths=/opt/{{ .Name }} /var/log/{{ .Name }} | ||||||
| 
 | 
 | ||||||
| {{ end -}} | {{ end -}} | ||||||
| {{if .PrivilegedPorts -}} | {{if .PrivilegedPorts -}} | ||||||
| @ -75,4 +81,8 @@ NoNewPrivileges=true | |||||||
| 
 | 
 | ||||||
| {{ end -}} | {{ end -}} | ||||||
| [Install] | [Install] | ||||||
|  | {{ if not .Local -}} | ||||||
| WantedBy=multi-user.target | WantedBy=multi-user.target | ||||||
|  | {{- else -}} | ||||||
|  | WantedBy=default.target | ||||||
|  | {{- end }} | ||||||
							
								
								
									
										23
									
								
								cmd/watchdog/installer/filesystem.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								cmd/watchdog/installer/filesystem.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | // "A little copying is better than a little dependency" | ||||||
|  | // These are here so that we don't need a dependency on http.FileSystem and http.File | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Same as http.FileSystem | ||||||
|  | type FileSystem interface { | ||||||
|  | 	Open(name string) (File, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Same as http.File | ||||||
|  | type File interface { | ||||||
|  | 	io.Closer | ||||||
|  | 	io.Reader | ||||||
|  | 	io.Seeker | ||||||
|  | 	Readdir(count int) ([]os.FileInfo, error) | ||||||
|  | 	Stat() (os.FileInfo, error) | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								cmd/watchdog/installer/install.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								cmd/watchdog/installer/install.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | |||||||
|  | //go:generate go run -mod=vendor github.com/UnnoTed/fileb0x b0x.toml | ||||||
|  | 
 | ||||||
|  | // I'm prototyping this out to be useful for more than just watchdog | ||||||
|  | // hence there are a few unnecessary things for the sake of the trying it out | ||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type Config struct { | ||||||
|  | 	Title               string            `json:"title"` | ||||||
|  | 	Name                string            `json:"name"` | ||||||
|  | 	Desc                string            `json:"desc"` | ||||||
|  | 	URL                 string            `json:"url"` | ||||||
|  | 	Interpreter         string            `json:"interpreter"` // i.e. node, python | ||||||
|  | 	Exec                string            `json:"exec"` | ||||||
|  | 	Argv                []string          `json:"argv"` | ||||||
|  | 	Args                string            `json:"-"` | ||||||
|  | 	Envs                map[string]string `json:"envs"` | ||||||
|  | 	User                string            `json:"user"` | ||||||
|  | 	Group               string            `json:"group"` | ||||||
|  | 	home                string            `json:"-"` | ||||||
|  | 	Local               string            `json:"local"` | ||||||
|  | 	LogDir              string            `json:"-"` | ||||||
|  | 	System              bool              `json:"system"` | ||||||
|  | 	Restart             bool              `json:"restart"` | ||||||
|  | 	Production          bool              `json:"production"` | ||||||
|  | 	PrivilegedPorts     bool              `json:"privileged_ports"` | ||||||
|  | 	MultiuserProtection bool              `json:"multiuser_protection"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Install(c *Config) error { | ||||||
|  | 	if "" == c.Exec { | ||||||
|  | 		c.Exec = c.Name | ||||||
|  | 	} | ||||||
|  | 	c.Args = strings.Join(c.Argv, " ") | ||||||
|  | 
 | ||||||
|  | 	// TODO handle non-system installs | ||||||
|  | 	// * ~/.local/opt/watchdog/watchdog | ||||||
|  | 	// * ~/.local/share/watchdog/var/log/ | ||||||
|  | 	// * ~/.config/watchdog/watchdog.json | ||||||
|  | 	if !c.System { | ||||||
|  | 		home, err := os.UserHomeDir() | ||||||
|  | 		if nil != err { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		c.home = home | ||||||
|  | 		c.Local = filepath.Join(c.home, ".local") | ||||||
|  | 		c.LogDir = filepath.Join(c.home, ".local", "share", c.Name, "var", "log") | ||||||
|  | 	} else { | ||||||
|  | 		c.LogDir = "/var/log/" + c.Name | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err := install(c) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = os.MkdirAll(c.LogDir, 0750) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										64
									
								
								cmd/watchdog/installer/install_darwin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								cmd/watchdog/installer/install_darwin.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | |||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"strings" | ||||||
|  | 	"text/template" | ||||||
|  | 
 | ||||||
|  | 	"git.rootprojects.org/root/watchdog.go/cmd/watchdog/installer/static" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func install(c *Config) error { | ||||||
|  | 	// Darwin-specific config options | ||||||
|  | 	if c.PrivilegedPorts { | ||||||
|  | 		if !c.System { | ||||||
|  | 			return fmt.Errorf("You must use root-owned LaunchDaemons (not user-owned LaunchAgents) to use priveleged ports on OS X") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	plistDir := "/Library/LaunchDaemons/" | ||||||
|  | 	if !c.System { | ||||||
|  | 		plistDir = filepath.Join(c.home, "Library/LaunchAgents") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Check paths first | ||||||
|  | 	err := os.MkdirAll(filepath.Dir(plistDir), 0750) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Create service file from template | ||||||
|  | 	b, err := static.ReadFile("dist/Library/LaunchDaemons/_rdns_.plist.tmpl") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	s := string(b) | ||||||
|  | 	rw := &bytes.Buffer{} | ||||||
|  | 	// not sure what the template name does, but whatever | ||||||
|  | 	tmpl, err := template.New("service").Parse(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	err = tmpl.Execute(rw, c) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Write the file out | ||||||
|  | 	// TODO rdns | ||||||
|  | 	plistName := c.Name + ".plist" | ||||||
|  | 	plistPath := filepath.Join(plistDir, plistName) | ||||||
|  | 	if err := ioutil.WriteFile(plistPath, rw.Bytes(), 0644); err != nil { | ||||||
|  | 		fmt.Println("Use 'sudo' to install as a privileged system service.") | ||||||
|  | 		fmt.Println("Use '--userspace' to install as an user service.") | ||||||
|  | 		return fmt.Errorf("ioutil.WriteFile error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("Installed. To start '%s' run the following:\n", c.Name) | ||||||
|  | 	// TODO template config file | ||||||
|  | 	fmt.Printf("\tlaunchctl load -w %s\n", strings.Replace(plistPath, c.home, "~", 1)) | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								cmd/watchdog/installer/install_linux.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								cmd/watchdog/installer/install_linux.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"text/template" | ||||||
|  | 
 | ||||||
|  | 	"git.rootprojects.org/root/watchdog.go/cmd/watchdog/installer/static" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func install(c *Config) error { | ||||||
|  | 	// Linux-specific config options | ||||||
|  | 	if c.System { | ||||||
|  | 		if "" == c.User { | ||||||
|  | 			c.User = "root" | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if "" == c.Group { | ||||||
|  | 		c.Group = c.User | ||||||
|  | 	} | ||||||
|  | 	serviceDir := "/etc/systemd/system/" | ||||||
|  | 
 | ||||||
|  | 	// Check paths first | ||||||
|  | 	serviceName := c.Name + ".service" | ||||||
|  | 	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, ".local/share/systemd/user") | ||||||
|  | 	} | ||||||
|  | 	err = os.MkdirAll(filepath.Dir(serviceDir), 0750) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Create service file from template | ||||||
|  | 	b, err := static.ReadFile("dist/etc/systemd/system/_name_.service.tmpl") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	s := string(b) | ||||||
|  | 	rw := &bytes.Buffer{} | ||||||
|  | 	// not sure what the template name does, but whatever | ||||||
|  | 	tmpl, err := template.New("service").Parse(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	err = tmpl.Execute(rw, c) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Write the file out | ||||||
|  | 	servicePath := filepath.Join(serviceDir, serviceName) | ||||||
|  | 	if err := ioutil.WriteFile(servicePath, rw.Bytes(), 0644); err != nil { | ||||||
|  | 		return fmt.Errorf("ioutil.WriteFile error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("Wrote %q\n", servicePath) | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
| @ -1,7 +1,7 @@ | |||||||
| package main | package installer | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"log" | 	"fmt" | ||||||
| 	//"golang.org/x/sys/windows" | 	//"golang.org/x/sys/windows" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -11,7 +11,7 @@ import ( | |||||||
| // https://stackoverflow.com/questions/27366298/check-if-application-is-running-as-administrator-in-golang | // https://stackoverflow.com/questions/27366298/check-if-application-is-running-as-administrator-in-golang | ||||||
| // https://www.reddit.com/r/golang/comments/53dthc/way_to_detect_if_the_programs_running_with/ | // https://www.reddit.com/r/golang/comments/53dthc/way_to_detect_if_the_programs_running_with/ | ||||||
| // https://play.golang.org/p/bBtRZrk4_p | // https://play.golang.org/p/bBtRZrk4_p | ||||||
| func install() { | func install(c *Config) error { | ||||||
| 	//token := windows.Token(0) | 	//token := windows.Token(0) | ||||||
| 	log.Fatal("not yet implemented") | 	return fmt.Errorf("not yet implemented") | ||||||
| } | } | ||||||
							
								
								
									
										7
									
								
								cmd/watchdog/installer/unknownos.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								cmd/watchdog/installer/unknownos.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | // +build !windows,!linux,!darwin | ||||||
|  | 
 | ||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | func install(c *Config) error { | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								cmd/watchdog/installer/watchdog.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								cmd/watchdog/installer/watchdog.service
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | # Pre-req | ||||||
|  | # sudo adduser watchdog --home /opt/watchdog | ||||||
|  | # sudo mkdir -p /opt/watchdog/ /var/log/watchdog | ||||||
|  | # sudo chown -R watchdog:watchdog /opt/watchdog/ /var/log/watchdog | ||||||
|  | 
 | ||||||
|  | [Unit] | ||||||
|  | Description=Watchdog - Get notified when sites go down | ||||||
|  | Documentation=https://git.rootprojects.org/root/watchdog.go | ||||||
|  | After=network-online.target | ||||||
|  | Wants=network-online.target systemd-networkd-wait-online.service | ||||||
|  | 
 | ||||||
|  | [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 | ||||||
|  | StartLimitInterval=10 | ||||||
|  | StartLimitBurst=3 | ||||||
|  | 
 | ||||||
|  | # User and group the process will run as | ||||||
|  | User=root | ||||||
|  | Group=root | ||||||
|  | 
 | ||||||
|  | WorkingDirectory=/opt/watchdog | ||||||
|  | ExecStart=/opt/watchdog -c ./config.json | ||||||
|  | ExecReload=/bin/kill -USR1 $MAINPID | ||||||
|  | 
 | ||||||
|  | [Install] | ||||||
|  | WantedBy=multi-user.target | ||||||
							
								
								
									
										15
									
								
								cmd/watchdog/installer/whoami.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cmd/watchdog/installer/whoami.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | // +build !windows | ||||||
|  | 
 | ||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | import "os/user" | ||||||
|  | 
 | ||||||
|  | func IsAdmin() bool { | ||||||
|  | 	u, err := user.Current() | ||||||
|  | 	if nil != err { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// not quite, but close enough for now | ||||||
|  | 	return "0" == u.Uid | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								cmd/watchdog/installer/whoami_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								cmd/watchdog/installer/whoami_windows.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | package installer | ||||||
|  | 
 | ||||||
|  | import "os/user" | ||||||
|  | 
 | ||||||
|  | func IsAdmin() { | ||||||
|  | 	u, err := user.Current() | ||||||
|  | 	if nil != err { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems | ||||||
|  | 	// not quite, but close enough for now | ||||||
|  | 	// BUILTIN\ADMINISTRATORS | ||||||
|  | 	if "S-1-5-32-544" == u.Uid || "S-1-5-32-544" == u.Gid { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ids := u.GroupIds() | ||||||
|  | 	for i := range ids { | ||||||
|  | 		if "S-1-5-32-544" == ids[i] { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
| @ -11,7 +11,7 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	watchdog "git.rootprojects.org/root/watchdog.go" | 	"git.rootprojects.org/root/watchdog.go" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var GitRev, GitVersion, GitTimestamp string | var GitRev, GitVersion, GitTimestamp string | ||||||
| @ -21,6 +21,7 @@ func usage() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
|  | 	fmt.Println("Watchdog " + GitVersion) | ||||||
| 	for i := range os.Args { | 	for i := range os.Args { | ||||||
| 		switch { | 		switch { | ||||||
| 		case strings.HasSuffix(os.Args[i], "version"): | 		case strings.HasSuffix(os.Args[i], "version"): | ||||||
| @ -31,6 +32,13 @@ func main() { | |||||||
| 		case strings.HasSuffix(os.Args[i], "help"): | 		case strings.HasSuffix(os.Args[i], "help"): | ||||||
| 			usage() | 			usage() | ||||||
| 			os.Exit(0) | 			os.Exit(0) | ||||||
|  | 		case os.Args[i] == "install": | ||||||
|  | 			args := []string{} | ||||||
|  | 			if len(os.Args) > i+1 { | ||||||
|  | 				args = os.Args[i+1:] | ||||||
|  | 			} | ||||||
|  | 			install(os.Args[0], args) | ||||||
|  | 			os.Exit(0) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								cmd/watchdog/watchdog.service.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								cmd/watchdog/watchdog.service.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | { | ||||||
|  | 	"name": "Watchdog", | ||||||
|  | 	"desc": "Get notified when sites go down", | ||||||
|  | 	"url": "https://git.rootprojects.org/root/watchdog.go", | ||||||
|  | 	"exec": "watchdog", | ||||||
|  | 	"args": "-c ./config.json", | ||||||
|  | 	"user": "root", | ||||||
|  | 	"privileged_ports": false, | ||||||
|  | 	"multiuser_protection": false | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user