cmd/ntpcheck/checker/system.go (96 lines of code) (raw):

/* Copyright (c) Facebook, Inc. and its affiliates. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package checker import ( "strconv" "github.com/facebook/time/ntp/chrony" "github.com/facebook/time/ntp/control" "github.com/pkg/errors" ) // SystemVariables holds System Variables extracted from k=v pairs, as described in http://doc.ntp.org/current-stable/ntpq.html type SystemVariables struct { Version string Processor string System string Leap int Stratum int Precision int RootDelay float64 RootDisp float64 Peer int TC int MinTC int Clock string RefID string RefTime string Offset float64 SysJitter float64 Frequency float64 ClkWander float64 ClkJitter float64 Tai int } // sanityCheckSysVars checks if we parsed enough info from NTPD response func sanityCheckSysVars(sysVars *SystemVariables) error { if sysVars == nil { return errors.New("No system variables") } if sysVars.Stratum == 0 { return errors.New("Incomplete data, stratum 0 in system variables") } return nil } // NewSystemVariablesFromChrony returns initialized instance of SystemVariables func NewSystemVariablesFromChrony(p *chrony.ReplyTracking) *SystemVariables { return &SystemVariables{ Leap: int(p.LeapStatus), Stratum: int(p.Stratum), RootDelay: secToMS(p.RootDelay), RootDisp: secToMS(p.RootDispersion), RefID: chrony.RefidAsHEX(p.RefID), RefTime: p.RefTime.String(), Offset: secToMS(p.RMSOffset), Frequency: p.FreqPPM, } } // NewSystemVariablesFromNTP constructs System from NTPControlMsg packet func NewSystemVariablesFromNTP(p *control.NTPControlMsg) (*SystemVariables, error) { m, err := p.GetAssociationInfo() if err != nil { return nil, err } // data comes as k=v pairs in packet, and those kv pairs are parsed by GetAssociationInfo. // If data is severely corrupted GetAssociationInfo will return error. // It's ok to have some fields missing, thus we don't check for errors below. leap, _ := strconv.Atoi(m["leap"]) stratum, _ := strconv.Atoi(m["stratum"]) precision, _ := strconv.Atoi(m["precision"]) rootdelay, _ := strconv.ParseFloat(m["rootdelay"], 64) rootdisp, _ := strconv.ParseFloat(m["rootdisp"], 64) peer, _ := strconv.Atoi(m["peer"]) tc, _ := strconv.Atoi(m["tc"]) mintc, _ := strconv.Atoi(m["mintc"]) offset, _ := strconv.ParseFloat(m["offset"], 64) sysjitter, _ := strconv.ParseFloat(m["sys_jitter"], 64) frequency, _ := strconv.ParseFloat(m["frequency"], 64) clkwander, _ := strconv.ParseFloat(m["clk_wander"], 64) clkjitter, _ := strconv.ParseFloat(m["clk_jitter"], 64) tai, _ := strconv.Atoi(m["tai"]) system := SystemVariables{ // from variables Version: m["version"], Processor: m["processor"], System: m["system"], Leap: leap, Stratum: stratum, Precision: precision, RootDelay: rootdelay, RootDisp: rootdisp, Peer: peer, TC: tc, MinTC: mintc, Clock: m["clock"], RefID: m["refid"], RefTime: m["reftime"], Offset: offset, SysJitter: sysjitter, Frequency: frequency, ClkWander: clkwander, ClkJitter: clkjitter, Tai: tai, } // sometimes NTPD returns malformed k=v pairs and we can't parse important info if err := sanityCheckSysVars(&system); err != nil { return nil, err } return &system, nil }