blob: 6c2e90648e731038d77445978434fc4a3b714afc [file] [log] [blame]
Lorenz Brune306d782021-09-01 13:01:06 +02001// Package time implements a supervisor runnable which is responsible for
2// keeping both the system clock and the RTC accurate.
3// Metropolis nodes need accurate time both for themselves (for log
4// timestamping, validating certain certificates, ...) as well as workloads
5// running on top of it expecting accurate time.
6// This initial implementation is very minimalistic, running just a stateless
7// NTP client per node for the whole lifecycle of it.
8// This implementation is simple, but is fairly unsafe as NTP by itself does
9// not offer any cryptography, so it's easy to tamper with the responses.
10// See #73 for further work in that direction.
11package time
12
13import (
14 "context"
15 "fmt"
16 "os/exec"
17 "strconv"
18 "strings"
19
20 "source.monogon.dev/metropolis/node"
21 "source.monogon.dev/metropolis/pkg/fileargs"
22 "source.monogon.dev/metropolis/pkg/supervisor"
23)
24
25// Service implements the time service. See package documentation for further
26// information.
27type Service struct{}
28
29func New() *Service {
30 return &Service{}
31}
32
33func (s *Service) Run(ctx context.Context) error {
34 // TODO(#72): Apply for a NTP pool vendor zone
35 config := strings.Join([]string{
36 "pool pool.ntp.org iburst",
37 "bindcmdaddress /",
38 "stratumweight 0.01",
39 "leapsecmode slew",
40 "maxslewrate 10000",
41 "makestep 2.0 3",
42 "rtconutc",
43 "rtcsync",
44 }, "\n")
45 args, err := fileargs.New()
46 if err != nil {
47 return fmt.Errorf("cannot create fileargs: %w", err)
48 }
49 defer args.Close()
50 cmd := exec.Command(
51 "/time/chrony",
52 "-d",
53 "-i", strconv.Itoa(node.TimeUid),
54 "-g", strconv.Itoa(node.TimeUid),
55 "-f", args.ArgPath("chrony.conf", []byte(config)),
56 )
57 cmd.Stdout = supervisor.RawLogger(ctx)
58 cmd.Stderr = supervisor.RawLogger(ctx)
59 return supervisor.RunCommand(ctx, cmd)
60}