feat: add basic ntp implementation (#459)
Signed-off-by: Brad Beam <brad.beam@b-rad.info>
This commit is contained in:
parent
b585b3f896
commit
3693cff14f
12
Dockerfile
12
Dockerfile
@ -343,3 +343,15 @@ RUN GOOS=linux GOARCH=amd64 go build -a -ldflags "-s -w -X ${VERSION_PKG}.Name=C
|
||||
RUN chmod +x /osinstall-linux-amd64
|
||||
FROM scratch AS osinstall-linux-amd64
|
||||
COPY --from=osinstall-linux-amd64-build /osinstall-linux-amd64 /osinstall-linux-amd64
|
||||
|
||||
# The ntpd target builds the ntpd binary
|
||||
FROM base AS ntpd-build
|
||||
ARG SHA
|
||||
ARG TAG
|
||||
ARG VERSION_PKG="github.com/autonomy/talos/internal/pkg/version"
|
||||
WORKDIR /src/internal/app/ntpd
|
||||
RUN go build -a -ldflags "-s -w -X ${VERSION_PKG}.Name=Server -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG}" -o /ntpd
|
||||
RUN chmod +x /ntpd
|
||||
FROM scratch AS ntpd
|
||||
COPY --from=ntpd-build /ntpd /ntpd
|
||||
ENTRYPOINT ["/ntpd"]
|
||||
|
11
Makefile
11
Makefile
@ -99,7 +99,7 @@ initramfs: buildkitd
|
||||
--frontend-opt target=$@ \
|
||||
$(COMMON_ARGS)
|
||||
|
||||
rootfs: buildkitd hyperkube etcd coredns pause osd trustd proxyd blockd
|
||||
rootfs: buildkitd hyperkube etcd coredns pause osd trustd proxyd blockd ntpd
|
||||
@buildctl --addr $(BUILDKIT_HOST) \
|
||||
build \
|
||||
--exporter=local \
|
||||
@ -227,6 +227,15 @@ blockd: buildkitd
|
||||
--frontend-opt target=$@ \
|
||||
$(COMMON_ARGS)
|
||||
|
||||
ntpd: buildkitd
|
||||
@buildctl --addr $(BUILDKIT_HOST) \
|
||||
build \
|
||||
--exporter=docker \
|
||||
--exporter-opt output=images/$@.tar \
|
||||
--exporter-opt name=docker.io/autonomy/$@:$(TAG) \
|
||||
--frontend-opt target=$@ \
|
||||
$(COMMON_ARGS)
|
||||
|
||||
hyperkube:
|
||||
@docker pull k8s.gcr.io/$@:v1.13.3
|
||||
@docker save k8s.gcr.io/$@:v1.13.3 -o ./images/$@.tar
|
||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ require (
|
||||
github.com/Microsoft/go-winio v0.4.9 // indirect
|
||||
github.com/Microsoft/hcsshim v0.7.0 // indirect
|
||||
github.com/autonomy/dhcp v0.0.0-20190227141242-cedea8519f96
|
||||
github.com/beevik/ntp v0.2.0
|
||||
github.com/containerd/cgroups v0.0.0-20180905221500-58556f5ad844
|
||||
github.com/containerd/containerd v1.2.4
|
||||
github.com/containerd/continuity v0.0.0-20181003075958-be9bd761db19 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -7,6 +7,8 @@ github.com/Microsoft/hcsshim v0.7.0 h1:m1J6JDH52fG9Qjq8fznVe8PNX75RFge88bzQ8u/HF
|
||||
github.com/Microsoft/hcsshim v0.7.0/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/autonomy/dhcp v0.0.0-20190227141242-cedea8519f96 h1:le2YbRJwapQ4/vDjJX5EfKBMzdBKmTkxq2+7qIv/oPU=
|
||||
github.com/autonomy/dhcp v0.0.0-20190227141242-cedea8519f96/go.mod h1:geIPC0Of8gFT72dq3OwSOpqHWJaISvkU7XXqs8HF0+0=
|
||||
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/cgroups v0.0.0-20180905221500-58556f5ad844 h1:W0F6ErEE8B84VNA5yX3sqNm0z7tivzEtvI/3DMo4Mr4=
|
||||
github.com/containerd/cgroups v0.0.0-20180905221500-58556f5ad844/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
|
||||
|
@ -208,6 +208,12 @@ func startSystemServices(data *userdata.UserData) {
|
||||
containerd.WithIndexName("talos/trustd"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/usr/images/ntpd.tar",
|
||||
Options: []containerd.ImportOpt{
|
||||
containerd.WithIndexName("talos/ntpd"),
|
||||
},
|
||||
},
|
||||
}
|
||||
if err = ctrdrunner.Import(constants.SystemContainerdNamespace, reqs...); err != nil {
|
||||
panic(err)
|
||||
@ -219,6 +225,7 @@ func startSystemServices(data *userdata.UserData) {
|
||||
&services.Udevd{},
|
||||
&services.OSD{},
|
||||
&services.Blockd{},
|
||||
&services.NTPd{},
|
||||
)
|
||||
// Start the services common to all master nodes.
|
||||
if data.IsMaster() {
|
||||
|
@ -48,6 +48,7 @@ func Setup(platform string) (err error) {
|
||||
}
|
||||
|
||||
//dhcp request
|
||||
// TODO: Figure out how we want to pass around ntp servers
|
||||
modifiers := []dhcpv4.Modifier{
|
||||
dhcpv4.WithRequestedOptions(
|
||||
dhcpv4.OptionHostName,
|
||||
|
73
internal/app/init/pkg/system/services/ntpd.go
Normal file
73
internal/app/init/pkg/system/services/ntpd.go
Normal file
@ -0,0 +1,73 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// nolint: dupl,golint
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/autonomy/talos/internal/app/init/pkg/system/conditions"
|
||||
"github.com/autonomy/talos/internal/app/init/pkg/system/runner"
|
||||
"github.com/autonomy/talos/internal/app/init/pkg/system/runner/containerd"
|
||||
"github.com/autonomy/talos/internal/pkg/constants"
|
||||
"github.com/autonomy/talos/internal/pkg/userdata"
|
||||
"github.com/containerd/containerd/oci"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// NTPd implements the Service interface. It serves as the concrete type with
|
||||
// the required methods.
|
||||
type NTPd struct{}
|
||||
|
||||
// ID implements the Service interface.
|
||||
func (n *NTPd) ID(data *userdata.UserData) string {
|
||||
return "ntpd"
|
||||
}
|
||||
|
||||
// PreFunc implements the Service interface.
|
||||
func (n *NTPd) PreFunc(data *userdata.UserData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostFunc implements the Service interface.
|
||||
func (n *NTPd) PostFunc(data *userdata.UserData) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConditionFunc implements the Service interface.
|
||||
func (n *NTPd) ConditionFunc(data *userdata.UserData) conditions.ConditionFunc {
|
||||
return conditions.None()
|
||||
}
|
||||
|
||||
func (n *NTPd) Start(data *userdata.UserData) error {
|
||||
image := "talos/ntpd"
|
||||
|
||||
args := runner.Args{
|
||||
ID: n.ID(data),
|
||||
ProcessArgs: []string{"/ntpd", "--userdata=" + constants.UserDataPath},
|
||||
}
|
||||
|
||||
mounts := []specs.Mount{
|
||||
{Type: "bind", Destination: constants.UserDataPath, Source: constants.UserDataPath, Options: []string{"rbind", "ro"}},
|
||||
}
|
||||
|
||||
env := []string{}
|
||||
for key, val := range data.Env {
|
||||
env = append(env, fmt.Sprintf("%s=%s", key, val))
|
||||
}
|
||||
|
||||
r := containerd.Containerd{}
|
||||
|
||||
return r.Run(
|
||||
data,
|
||||
args,
|
||||
runner.WithContainerImage(image),
|
||||
runner.WithEnv(env),
|
||||
runner.WithOCISpecOpts(
|
||||
containerd.WithMemoryLimit(int64(1000000*32)),
|
||||
oci.WithMounts(mounts),
|
||||
),
|
||||
)
|
||||
}
|
129
internal/app/ntpd/main.go
Normal file
129
internal/app/ntpd/main.go
Normal file
@ -0,0 +1,129 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"math/rand"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/autonomy/talos/internal/pkg/userdata"
|
||||
"github.com/beevik/ntp"
|
||||
)
|
||||
|
||||
// https://access.redhat.com/solutions/39194
|
||||
// Using the above as reference for setting min/max
|
||||
const (
|
||||
MAXPOLL = 1000
|
||||
MINPOLL = 20
|
||||
// TODO: Once we get naming sorted we need to apply
|
||||
// for a project specific address
|
||||
// https://manage.ntppool.org/manage/vendor
|
||||
DEFAULTSERVER = "pool.ntp.org"
|
||||
)
|
||||
|
||||
var (
|
||||
dataPath *string
|
||||
)
|
||||
|
||||
func init() {
|
||||
log.SetFlags(log.Lshortfile | log.Ldate | log.Lmicroseconds | log.Ltime)
|
||||
dataPath = flag.String("userdata", "", "the path to the user data")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
// New instantiates a new ntp instance against a given server
|
||||
// If no servers are specified, the default will be used
|
||||
func main() {
|
||||
server := DEFAULTSERVER
|
||||
|
||||
data, err := userdata.Open(*dataPath)
|
||||
if err != nil {
|
||||
log.Fatalf("open user data: %v", err)
|
||||
}
|
||||
|
||||
// Check if ntp servers are defined
|
||||
if data.Services.NTPd != nil && data.Services.NTPd.Server != "" {
|
||||
server = data.Services.NTPd.Server
|
||||
}
|
||||
|
||||
log.Println("Starting ntpd")
|
||||
n := &NTP{Server: server}
|
||||
n.Daemon()
|
||||
}
|
||||
|
||||
// NTP contains a server address
|
||||
// and the most recent response from a query
|
||||
type NTP struct {
|
||||
Server string
|
||||
Response *ntp.Response
|
||||
}
|
||||
|
||||
// Daemon runs the control loop for query and set time
|
||||
// We dont ever want the daemon to stop, so we only log
|
||||
// errors
|
||||
func (n *NTP) Daemon() {
|
||||
var err error
|
||||
rando := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
ticker := time.NewTicker(time.Duration(rando.Intn(MAXPOLL)+MINPOLL) * time.Second)
|
||||
|
||||
log.Println("initial query")
|
||||
// Do an initial hard set of time to ensure clock skew isnt too far off
|
||||
if err = n.Query(); err != nil {
|
||||
log.Printf("error querying %s for time, %s", n.Server, err)
|
||||
}
|
||||
log.Printf("%+v\n", n.Response)
|
||||
log.Println("Current time")
|
||||
log.Println(time.Now())
|
||||
if err = n.SetTime(); err != nil {
|
||||
log.Printf("failed to set time, %s", err)
|
||||
}
|
||||
log.Println("Updated time")
|
||||
log.Println(time.Now())
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
// Set some variance with how frequently we poll ntp servers
|
||||
if err = n.Query(); err != nil {
|
||||
log.Printf("error querying %s for time, %s", n.Server, err)
|
||||
continue
|
||||
}
|
||||
log.Printf("%+v\n", n.Response)
|
||||
log.Println("Current time")
|
||||
log.Println(time.Now())
|
||||
if err = n.SetTime(); err != nil {
|
||||
log.Printf("failed to set time, %s", err)
|
||||
continue
|
||||
}
|
||||
log.Println("Updated time")
|
||||
log.Println(time.Now())
|
||||
}
|
||||
ticker = time.NewTicker(time.Duration(rando.Intn(MAXPOLL)+MINPOLL) * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// Query polls the ntp server to get back a response
|
||||
// and saves it for later use
|
||||
func (n *NTP) Query() error {
|
||||
resp, err := ntp.Query(n.Server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.Response = resp
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTime sets the system time based on the query response
|
||||
func (n *NTP) SetTime() error {
|
||||
// Not sure if this is the right thing to do
|
||||
if n.Response == nil {
|
||||
return nil
|
||||
}
|
||||
timeval := syscall.NsecToTimeval(n.Response.Time.UnixNano())
|
||||
return syscall.Settimeofday(&timeval)
|
||||
}
|
@ -80,6 +80,7 @@ type Services struct {
|
||||
Blockd *Blockd `yaml:"blockd"`
|
||||
OSD *OSD `yaml:"osd"`
|
||||
CRT *CRT `yaml:"crt"`
|
||||
NTPd *NTPd `yaml:"ntp"`
|
||||
}
|
||||
|
||||
// File represents a files to write to disk.
|
||||
@ -249,6 +250,13 @@ type CommonServiceOptions struct {
|
||||
Env Env `yaml:"env,omitempty"`
|
||||
}
|
||||
|
||||
// NTPd describes the configuration of the ntp service.
|
||||
type NTPd struct {
|
||||
CommonServiceOptions `yaml:",inline"`
|
||||
|
||||
Server string `yaml:"server,omitempty"`
|
||||
}
|
||||
|
||||
// WriteFiles writes the requested files to disk.
|
||||
func (data *UserData) WriteFiles() (err error) {
|
||||
for _, f := range data.Files {
|
||||
|
Loading…
x
Reference in New Issue
Block a user