• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

journald/H25-May-2021-2111

notify/H25-May-2021-187132

resolved/H25-May-2021-1,4131,143

.gitignoreH A D25-May-202117 32

LICENSEH A D25-May-20211 KiB2117

README.mdH A D25-May-20217.2 KiB300241

go.modH A D25-May-2021187 107

go.sumH A D25-May-20211.7 KiB1918

sysd.goH A D25-May-2021318 115

README.md

1# go-systemd
2
3[![Go Report Card](https://goreportcard.com/badge/github.com/iguanesolutions/go-systemd)](https://goreportcard.com/report/github.com/iguanesolutions/go-systemd) [![PkgGoDev](https://pkg.go.dev/badge/github.com/iguanesolutions/go-systemd/v5)](https://pkg.go.dev/github.com/iguanesolutions/go-systemd/v5)
4
5Easily communicate with systemd when run as daemon within a service unit.
6
7## Notifier
8
9[![PkgGoDev](https://pkg.go.dev/badge/github.com/iguanesolutions/go-systemd/v5/notify)](https://pkg.go.dev/github.com/iguanesolutions/go-systemd/v5/notify)
10
11With notifier you can notify to systemd that your program is starting, stopping, reloading...
12
13For example, if your daemon needs some time for initializing its controllers before really being considered as ready, you can specify to systemd that this is a "notify" service and send it a notification when ready.
14
15It is safe to use it even if systemd notify support is disabled (noop call).
16
17```systemdunit
18[Service]
19Type=notify
20```
21
22```go
23import (
24    sysdnotify "github.com/iguanesolutions/go-systemd/v5/notify"
25)
26
27// Init http server
28server := &http.Server{
29    Addr:    "host:port",
30    Handler: myHTTPHandler,
31}
32
33/*
34    Do some more inits
35*/
36
37// Notify ready to systemd
38if err = sysdnotify.Ready(); err != nil {
39    log.Printf("failed to notify ready to systemd: %v\n", err)
40}
41
42// Start the server
43if err = server.ListenAndServe(); err != nil {
44    log.Printf("failed to start http server: %v\n", err)
45}
46```
47
48When stopping, you can notify systemd that you have indeed received the SIGTERM and you have launched the stop procedure
49
50```go
51import (
52    sysdnotify "github.com/iguanesolutions/go-systemd/v5/notify"
53)
54
55// Notify to systemd that we are stopping
56var err error
57if err = sysdnotify.Stopping(); err != nil {
58    log.Printf("failed to notify stopping to systemd: %v\n", err)
59}
60
61/*
62    Stop others things
63*/
64
65// Stop the server (with timeout)
66ctx, cancelCtx := context.WithTimeout(context.Background(), 5*time.Second)
67defer cancelCtx()
68if err = server.Shutdown(ctx); err != nil {
69    log.Printf("failed to shutdown http server: %v\n", err)
70}
71```
72
73You can also notify status to systemd
74
75```go
76import (
77    sysdnotify "github.com/iguanesolutions/go-systemd/v5/notify"
78)
79
80if err := sysdnotify.Status(fmt.Sprintf("There is currently %d active connections", activeConns)); err != nil {
81    log.Printf("failed to notify status to systemd: %v\n", err)
82}
83
84```
85
86systemctl status output example:
87
88```systemctlstatus
89user@host:~$ systemctl status superapp.service
90superapp.service - superapp
91   Loaded: loaded (/lib/systemd/system/superapp.service; enabled)
92   Active: active (running) since Mon 2018-06-25 08:54:35 UTC; 3 days ago
93 Main PID: 2604 (superapp)
94   Status: "There is currently 1506 active connections"
95   ...
96```
97
98### Watchdog
99
100[![PkgGoDev](https://pkg.go.dev/badge/github.com/iguanesolutions/go-systemd/v5/notify/watchdog)](https://pkg.go.dev/github.com/iguanesolutions/go-systemd/v5/notify/watchdog)
101
102```systemdunit
103[Service]
104Type=notify
105WatchdogSec=30s
106```
107
108```go
109import (
110    sysdwatchdog "github.com/iguanesolutions/go-systemd/v5/notify/watchdog"
111)
112
113// Init systemd watchdog, same as the notifier, it can be nil if your os does not support it
114watchdog, err := sysdwatchdog.New()
115if err != nil {
116    log.Printf("failed to initialize systemd watchdog controller: %v\n", err)
117}
118
119if watchdog != nil {
120    // Then start a watcher worker
121    go func() {
122        ticker := watchdog.NewTicker()
123        defer ticker.Stop()
124        for {
125            select {
126            // Ticker chan
127            case <-ticker.C:
128                // Check if something wrong, if not send heartbeat
129                if allGood {
130                    if err = watchdog.SendHeartbeat(); err != nil {
131                        log.Printf("failed to send systemd watchdog heartbeat: %v\n", err)
132                    }
133                }
134            // Some stop signal chan
135            case <-stopSig:
136                return
137            }
138        }
139    }()
140}
141```
142
143## Resolved
144
145[![PkgGoDev](https://pkg.go.dev/badge/github.com/iguanesolutions/go-systemd/resolved/resolved)](https://pkg.go.dev/github.com/iguanesolutions/go-systemd/v5/resolved)
146
147This package is still under development and very experimental, do not use it in production.
148We started this package in order to go deep into the DNS world. So we are opened to any suggestions/contributions on this.
149DNS is not trivial at all so there can be some stuff that are not rfc compliant (like sorting addresses etc...).
150
151The resolved package features:
152 * Pure Go implementation of `org.freedesktop.resolve1` dbus interface
153 * Resolver type (which uses the underlying dbus interface) that tries to implement the same methods as `net.Resolver` from Go standard library
154 * Unit tests (make sure Go resolver and systemd-resolved query the same dns server)
155
156### Dbus
157
158The following example shows how to use the resolve1 dbus connection to resolve an host:
159
160```go
161package main
162
163import (
164	"context"
165	"fmt"
166	"log"
167	"syscall"
168
169	"github.com/iguanesolutions/go-systemd/v5/resolved"
170)
171
172func main() {
173	c, err := resolved.NewConn()
174	if err != nil {
175		log.Fatal("ERROR: ", err)
176	}
177	ctx := context.Background()
178	addrs, canonical, flags, err := c.ResolveHostname(ctx, 0, "google.com", syscall.AF_UNSPEC, 0)
179	if err != nil {
180		log.Println("ERROR: ", err)
181	} else {
182		fmt.Println("Addresses: ", addrs)
183		fmt.Println("Canonical: ", canonical)
184		fmt.Println("OutputFlags: ", flags)
185	}
186	err = c.Close()
187	if err != nil {
188		log.Println("ERROR: ", err)
189	}
190}
191```
192
193Output:
194
195```output
196Addresses:  [{
197        IfIndex: 2,
198        Family:  2,
199        IP:      142.250.74.238,
200} {
201        IfIndex: 2,
202        Family:  10,
203        IP:      2a00:1450:4007:80b::200e,
204}]
205Canonical:  google.com
206Flags:  1
207```
208
209### Resolver
210
211The following example shows how to use the resolved Resolver to resolve an host:
212
213```go
214package main
215
216import (
217	"context"
218	"fmt"
219	"log"
220
221	"github.com/iguanesolutions/go-systemd/v5/resolved"
222)
223
224func main() {
225	r, err := resolved.NewResolver()
226	if err != nil {
227		log.Fatal("ERROR: ", err)
228	}
229	ctx := context.Background()
230	addrs, err := r.LookupHost(ctx, "google.com")
231	if err != nil {
232		log.Println("ERROR: ", err)
233	} else {
234		fmt.Println("Addresses: ", addrs)
235	}
236	err = r.Close()
237	if err != nil {
238		log.Println("ERROR: ", err)
239	}
240}
241```
242
243Output:
244
245```output
246Addresses:  [2a00:1450:4007:80b::200e 142.250.74.238]
247```
248
249### HTTP Client
250
251The following example shows how to use the systemd-resolved Resolver with the Go http client from the standard library:
252
253```go
254package main
255
256import (
257	"fmt"
258	"log"
259	"net/http"
260
261	"github.com/iguanesolutions/go-systemd/v5/resolved"
262)
263
264func main() {
265	r, err := resolved.NewResolver()
266	if err != nil {
267		log.Fatal("ERROR: ", err)
268	}
269	// if you want to make a custom http client using systemd-resolved as resolver
270	httpCli := &http.Client{
271		Transport: &http.Transport{
272			DialContext: r.DialContext,
273		},
274	}
275	// or if you don't have an http client you can call HTTPClient method on resolver
276	// it comes with some nice default values.
277	httpCli = r.HTTPClient()
278	resp, err := httpCli.Get("https://google.com")
279	if err != nil {
280		log.Println("ERROR: ", err)
281	} else {
282		fmt.Println("Status: ", resp.Status)
283		err = resp.Body.Close()
284		if err != nil {
285			log.Println("ERROR: ", err)
286		}
287	}
288	err = r.Close()
289	if err != nil {
290		log.Println("ERROR: ", err)
291	}
292}
293```
294
295Output:
296
297```output
298Status:  200 OK
299```
300