mirror of
https://github.com/siderolabs/talos.git
synced 2025-11-01 17:01:10 +01:00
This is a follow-up for #7567, which won't be backported to 1.5. This allows to get an output like: ``` $ talosctl -n 172.20.0.5 get adjtimestatus -w NODE * NAMESPACE TYPE ID VERSION OFFSET ESTERROR MAXERROR STATUS SYNC 172.20.0.5 + runtime AdjtimeStatus node 47 -18.14306ms 0s 191.5ms STA_PLL | STA_NANO true 172.20.0.5 runtime AdjtimeStatus node 48 -17.109555ms 0s 206.5ms STA_NANO | STA_PLL true 172.20.0.5 runtime AdjtimeStatus node 49 -16.134923ms 0s 221.5ms STA_NANO | STA_PLL true 172.20.0.5 runtime AdjtimeStatus node 50 -15.21581ms 0s 236.5ms STA_PLL | STA_NANO true ``` Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
98 lines
2.9 KiB
Go
98 lines
2.9 KiB
Go
// 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 time
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
stdtime "time"
|
|
|
|
"github.com/cosi-project/runtime/pkg/controller"
|
|
"github.com/cosi-project/runtime/pkg/safe"
|
|
"go.uber.org/zap"
|
|
"golang.org/x/sys/unix"
|
|
|
|
v1alpha1runtime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
|
|
"github.com/siderolabs/talos/internal/pkg/timex"
|
|
"github.com/siderolabs/talos/pkg/machinery/resources/time"
|
|
)
|
|
|
|
// AdjtimeStatusController manages time.AdjtimeStatus based on Linux kernel info.
|
|
type AdjtimeStatusController struct {
|
|
V1Alpha1Mode v1alpha1runtime.Mode
|
|
}
|
|
|
|
// Name implements controller.Controller interface.
|
|
func (ctrl *AdjtimeStatusController) Name() string {
|
|
return "time.AdjtimeStatusController"
|
|
}
|
|
|
|
// Inputs implements controller.Controller interface.
|
|
func (ctrl *AdjtimeStatusController) Inputs() []controller.Input {
|
|
return nil
|
|
}
|
|
|
|
// Outputs implements controller.Controller interface.
|
|
func (ctrl *AdjtimeStatusController) Outputs() []controller.Output {
|
|
return []controller.Output{
|
|
{
|
|
Type: time.AdjtimeStatusType,
|
|
Kind: controller.OutputExclusive,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Run implements controller.Controller interface.
|
|
func (ctrl *AdjtimeStatusController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error {
|
|
if ctrl.V1Alpha1Mode == v1alpha1runtime.ModeContainer {
|
|
// in container mode, clock is managed by the host
|
|
return nil
|
|
}
|
|
|
|
const pollInterval = 30 * stdtime.Second
|
|
|
|
pollTicker := stdtime.NewTicker(pollInterval)
|
|
defer pollTicker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil
|
|
case <-r.EventCh():
|
|
case <-pollTicker.C:
|
|
}
|
|
|
|
var timexBuf unix.Timex
|
|
|
|
state, err := timex.Adjtimex(&timexBuf)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get adjtimex state: %w", err)
|
|
}
|
|
|
|
scale := stdtime.Nanosecond
|
|
|
|
if timexBuf.Status&unix.STA_NANO == 0 {
|
|
scale = stdtime.Microsecond
|
|
}
|
|
|
|
if err := safe.WriterModify(ctx, r, time.NewAdjtimeStatus(), func(status *time.AdjtimeStatus) error {
|
|
status.TypedSpec().Offset = stdtime.Duration(timexBuf.Offset) * scale //nolint:durationcheck
|
|
status.TypedSpec().FrequencyAdjustmentRatio = 1 + float64(timexBuf.Freq)/65536.0/1000000.0
|
|
status.TypedSpec().MaxError = stdtime.Duration(timexBuf.Maxerror) * stdtime.Microsecond //nolint:durationcheck
|
|
status.TypedSpec().EstError = stdtime.Duration(timexBuf.Esterror) * stdtime.Microsecond //nolint:durationcheck
|
|
status.TypedSpec().Status = timex.Status(timexBuf.Status).String()
|
|
status.TypedSpec().State = state.String()
|
|
status.TypedSpec().Constant = int(timexBuf.Constant)
|
|
status.TypedSpec().SyncStatus = timexBuf.Status&unix.STA_UNSYNC == 0
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("failed to update adjtime status: %w", err)
|
|
}
|
|
|
|
r.ResetRestartBackoff()
|
|
}
|
|
}
|