Compare commits

...

15 Commits

Author SHA1 Message Date
c0dfb9b628 fix date formatting 2025-03-11 10:33:24 +01:00
57c04685a1 changes 2025-03-10 20:25:38 +01:00
e3b9e11533 peer variables 2025-03-10 14:48:00 +01:00
9d8aa63bed initial in new branch 2025-03-10 10:59:27 +01:00
af30d5ec57 error handling 2025-03-07 22:37:46 +01:00
e5d167dcda service file 2025-03-04 18:40:27 +01:00
613c2be109 arg parsing int 2025-03-02 22:34:11 +01:00
b371796690 adjust logging, 2 2025-03-02 22:31:54 +01:00
8b29d8808c adjust logging 2025-03-02 22:29:10 +01:00
30da4ed974 verbose switch 2025-03-02 22:19:15 +01:00
b5e8a63013 period for update too 2025-03-02 22:14:20 +01:00
679b9492d7 period fix 2025-03-01 23:50:09 +01:00
1e97ef3b2e changes 2025-02-25 14:00:28 +01:00
bfbaf70430 Merge branch 'main' of gitea.hottis.de:wn/snmp-agentx-ntpsec 2025-02-25 11:24:52 +01:00
d3b8114b0b mib adjusted 2025-02-25 11:24:49 +01:00
5 changed files with 296 additions and 180 deletions

14
snippets/ntp/test02.py Normal file
View File

@ -0,0 +1,14 @@
import ntp.packet
import json
session = ntp.packet.ControlSession()
session.openhost('localhost')
peers = session.readstat()
for p in peers:
vars = session.readvar(p.associd, ['srchost', 'srcadr', 'refid', 'stratum', 'hmode', 'rec', 'reach', 'hpoll', 'ppoll', 'delay', 'offset', 'jitter'])
peerSelectStatus = " x.-+#*o"[(session.rstatus >>8) & 0x07]
print(f"{p.associd}, {peerSelectStatus}, {session.rstatus:04x}: {dict(vars)}")

View File

@ -16,186 +16,264 @@ hottis MODULE-IDENTITY
::= { enterprises 9676 }
hottisNtpsec OBJECT IDENTIFIER ::= { hottis 123 }
local OBJECT IDENTIFIER ::= { hottisNtpsec 1 }
peers OBJECT IDENTIFIER ::= { hottisNtpsec 2 }
local OBJECT IDENTIFIER ::= { hottisNtpsec 1 }
system OBJECT IDENTIFIER ::= { hottisNtpsec 2 }
peers OBJECT IDENTIFIER ::= { hottisNtpsec 3 }
leap OBJECT-TYPE
SYNTAX INTEGER (0..2)
ntpsecLocalLeap OBJECT-TYPE
SYNTAX INTEGER (0..3)
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Leap Indicator (0=none, 1=last minute 61s, 2=last minute 59s)"
DESCRIPTION "Leap Indicator (0=none, 1=last minute 61s, 2=last minute 59s, 3=invalid)"
::= { local 1 }
stratum OBJECT-TYPE
ntpsecLocalStratum OBJECT-TYPE
SYNTAX INTEGER (0..16)
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Stratum-Level des lokalen NTP-Servers."
DESCRIPTION "Stratum level of this NTP server"
::= { local 2 }
precision OBJECT-TYPE
ntpsecLocalPrecision OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Präzision des lokalen NTP-Servers."
DESCRIPTION "Precision of this NTP server (log2 s)"
::= { local 3 }
rootdelay OBJECT-TYPE
ntpsecLocalRootdelay OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Root Delay in Millisekunden."
DESCRIPTION "Total roundtrip delay to the primary reference clock (ns)"
::= { local 4 }
rootdisp OBJECT-TYPE
ntpsecLocalRootdisp OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Root Dispersion in Millisekunden."
DESCRIPTION "Root dispersion to the primary reference clock (us)"
::= { local 5 }
refid OBJECT-TYPE
ntpsecLocalRefid OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Referenz-ID des lokalen NTP-Servers."
DESCRIPTION "Reference ID of this NTP server"
::= { local 6 }
ntpsecLocalReftime OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Reference time"
::= { local 7 }
reftime OBJECT-TYPE
ntpsecLocalTc OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Letzte Referenzzeit des lokalen NTP-Servers."
DESCRIPTION "Time constant and poll exponent (log2 s, 3-17)"
::= { local 8 }
clock OBJECT-TYPE
ntpsecLocalPeer OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "System peer association id"
::= { local 9 }
ntpsecLocalOffset OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Combined offset relative to this host (ns)"
::= { local 10 }
ntpsecLocalFrequency OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Frequency offset (PPM*1000) relative to hardware clock"
::= { local 11 }
ntpsecLocalSysJitter OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Combined system jitter"
::= { local 12 }
ntpsecLocalClkJitter OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Clock jitter"
::= { local 13 }
ntpsecLocalClock OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Uhrzeit des lokalen Systems."
DESCRIPTION "Date and time of day"
::= { local 14 }
ntpsecLocalProcessor OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Processor of this NTP server"
::= { local 15 }
processor OBJECT-TYPE
ntpsecLocalSystem OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Prozessortyp des Systems."
DESCRIPTION "System of this NTP server"
::= { local 16 }
system OBJECT-TYPE
ntpsecLocalVersion OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Systemtyp."
DESCRIPTION "NTPsec version of this NTP server"
::= { local 17 }
version OBJECT-TYPE
ntpsecLocalClkWander OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Clock frequency wander (PPM*1000000)"
::= { local 18 }
ntpsecLocalTai OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "TAI-UTC offset (s)"
::= { local 19 }
ntpsecLocalLeapsec OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "NTPsec Version."
::= { local 19 }
DESCRIPTION "Timestamp when the last/next leap second was/will be inserted"
::= { local 20 }
ntpsecLocalExpire OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Timestamp when the NIST leapseconds file expieres"
::= { local 21 }
ntpsecLocalMintc OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Minimum time constant (log2 s, 3-17)"
::= { local 22 }
peerNumber OBJECT-TYPE
ntpsecPeerNumber OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Number of Peers."
::= { peers 1 }
peerTable OBJECT-TYPE
SYNTAX SEQUENCE OF PeerEntry
ntpsecPeerTable OBJECT-TYPE
SYNTAX SEQUENCE OF ntpsecPeerEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION "Tabelle mit NTP-Peers."
::= { peers 2 }
peerEntry OBJECT-TYPE
ntpsecPeerEntry OBJECT-TYPE
SYNTAX PeerEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION "Eintrag für einen einzelnen NTP-Peer."
INDEX { associd }
::= { peerTable 1 }
INDEX { ntpsecPeerIndex }
::= { ntpsecPeerTable 1 }
PeerEntry ::= SEQUENCE {
index INTEGER,
associd INTEGER,
srcadr IpAddress,
srcport INTEGER,
dstadr IpAddress,
dstport INTEGER,
leap INTEGER,
hmode INTEGER,
stratum INTEGER,
ppoll INTEGER,
hpoll INTEGER,
precision INTEGER,
rootdelay INTEGER,
rootdisp INTEGER,
refid DisplayString,
reftime DisplayString,
rec DisplayString,
xmt DisplayString,
reach INTEGER,
unreach INTEGER,
delay_s DisplayString,
delay INTEGER,
offset INTEGER,
jitter INTEGER,
dispersion INTEGER,
keyid INTEGER,
filtdelay DisplayString,
filtoffset DisplayString,
pmode INTEGER,
filtdisp DisplayString,
flash INTEGER,
headway INTEGER,
ntscookies INTEGER
ntpsecPeerEntry ::= SEQUENCE {
ntpsecPeerIndex INTEGER,
ntpsecPeerAssocid INTEGER,
ntpsecPeerSrcadr IpAddress,
ntpsecPeerSrcport INTEGER,
ntpsecPeerDstadr IpAddress,
ntpsecPeerDstport INTEGER,
ntpsecPeerLeap INTEGER,
ntpsecPeerHmode INTEGER,
ntpsecPeerStratum INTEGER,
ntpsecPeerPpoll INTEGER,
ntpsecPeerHpoll INTEGER,
ntpsecPeerPrecision INTEGER,
ntpsecPeerRootdelay INTEGER,
ntpsecPeerRootdisp INTEGER,
ntpsecPeerRefid DisplayString,
ntpsecPeerReftime DisplayString,
ntpsecPeerRec DisplayString,
ntpsecPeerXmt DisplayString,
ntpsecPeerReach INTEGER,
ntpsecPeerUnreach INTEGER,
ntpsecPeerDelay_s DisplayString,
ntpsecPeerDelay INTEGER,
ntpsecPeerOffset INTEGER,
ntpsecPeerJitter INTEGER,
ntpsecPeerDispersion INTEGER,
ntpsecPeerKeyid INTEGER,
ntpsecPeerFiltdelay DisplayString,
ntpsecPeerFiltoffset DisplayString,
ntpsecPeerPmode INTEGER,
ntpsecPeerFiltdisp DisplayString,
ntpsecPeerFlash INTEGER,
ntpsecPeerHeadway INTEGER,
ntpsecPeerNtscookies INTEGER
}
index OBJECT-TYPE
ntpsecPeerIndex OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Peer-Index."
::= { peerEntry 1 }
::= { ntpsecPeerEntry 1 }
associd OBJECT-TYPE
ntpsecPeerAssocId OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Peer-Identifikationsnummer."
::= { peerEntry 2 }
::= { ntpsecPeerEntry 2 }
srcadr OBJECT-TYPE
SYNTAX IpAddress
ntpsecPeerSrcAdr OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Quell-IP-Adresse des Peers."
::= { peerEntry 3 }
::= { ntpsecPeerEntry 3 }
srcport OBJECT-TYPE
ntpsecPeerSrcPort OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Quellport des Peers."
::= { peerEntry 4 }
::= { ntpsecPeerEntry 4 }
dstadr OBJECT-TYPE
SYNTAX IpAddress
ntpsecPeerDstAdr OBJECT-TYPE
SYNTAX DisplayString
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Ziel-IP-Adresse des Peers."
::= { peerEntry 5 }
::= { ntpsecPeerEntry 5 }
dstport OBJECT-TYPE
ntpsecPeerDstPort OBJECT-TYPE
SYNTAX INTEGER
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Zielport des Peers."
::= { peerEntry 6 }
::= { ntpsecPeerEntry 6 }
END

View File

@ -1,4 +1,5 @@
pass_valueimport ntp.packe0
import ntp.packet
import ntp.ntpc
import threading
from contextlib import AbstractContextManager
import time
@ -10,18 +11,17 @@ import grp
import logging
import logging.handlers
import pyagentx
import datetime
LOGGING_LEVEL=logging.DEBUG
BASE_OID_ENTERPRISE = '1.3.6.1.4.1'
BASE_OID_HOTTIS = BASE_OID_ENTERPRISE + '.9676'
BASE_OID_HOTTIS_NTPSEC = BASE_OID_HOTTIS + '.123'
# just the prefix where the objects are below
LOCAL_PREFIX = '1'
PEERS_PREFIX = '2'
SYSINFO_PREFIX = '1'
SYSSTATS_PREFIX = '2'
PEERS_PREFIX = '3'
NUMBER_OF_PEERS_PREFIX = PEERS_PREFIX + '.1'
# this is for a table
@ -40,63 +40,52 @@ def int_scale1M(x):
def pass_value(x):
return x
LOCAL_SERVER_KEYS = [
def string_ntp_seconds(x):
return ntp.ntpc.prettydate(x).split(' ')[1]
SYSINFO_KEYS = [
['peeradr', pyagentx.TYPE_OCTETSTRING, pass_value],
['peermode', pyagentx.TYPE_INTEGER, pass_value],
['leap', pyagentx.TYPE_INTEGER, pass_value],
['stratum', pyagentx.TYPE_INTEGER, pass_value],
['precision', pyagentx.TYPE_INTEGER, pass_value],
['precision', pyagentx.TYPE_INTEGER, pass_value],
['rootdelay', pyagentx.TYPE_INTEGER, int_scale1M],
['rootdisp', pyagentx.TYPE_INTEGER, int_scale1k],
['rootdisp', pyagentx.TYPE_INTEGER, int_scale1M],
['rootdist', pyagentx.TYPE_INTEGER, int_scale1M],
['refid', pyagentx.TYPE_OCTETSTRING, pass_value],
['reftime', pyagentx.TYPE_OCTETSTRING, pass_value],
['tc', pyagentx.TYPE_INTEGER, pass_value],
['peer', pyagentx.TYPE_INTEGER, pass_value],
['offset', pyagentx.TYPE_INTEGER, int_scale1M],
['frequency', pyagentx.TYPE_INTEGER, int_scale1k],
['reftime', pyagentx.TYPE_OCTETSTRING, string_ntp_seconds],
['sys_jitter', pyagentx.TYPE_INTEGER, int_scale1M],
['clk_jitter', pyagentx.TYPE_INTEGER, int_scale1M],
['clock', pyagentx.TYPE_OCTETSTRING, pass_value],
['processor', pyagentx.TYPE_OCTETSTRING, pass_value],
['system', pyagentx.TYPE_OCTETSTRING, pass_value],
['version', pyagentx.TYPE_OCTETSTRING, pass_value],
['clk_wander', pyagentx.TYPE_INTEGER, int_scale1M],
['tai', pyagentx.TYPE_INTEGER, pass_value],
['leapsec', pyagentx.TYPE_OCTETSTRING, pass_value],
['expire', pyagentx.TYPE_OCTETSTRING, pass_value],
['mintc', pyagentx.TYPE_INTEGER, pass_value]
]
SYSSTATS_KEYS = [
['ss_uptime', pyagentx.TYPE_INTEGER, pass_value ],
['ss_numctlreq', pyagentx.TYPE_INTEGER, pass_value ],
['ss_reset', pyagentx.TYPE_INTEGER, pass_value ],
['ss_received', pyagentx.TYPE_COUNTER64, pass_value ],
['ss_badformat', pyagentx.TYPE_COUNTER64, pass_value ],
['ss_declined', pyagentx.TYPE_COUNTER64, pass_value ],
['ss_restricted', pyagentx.TYPE_COUNTER64, pass_value ],
['ss_limited', pyagentx.TYPE_COUNTER64, pass_value ],
['ss_kodsent', pyagentx.TYPE_COUNTER64, pass_value ],
['ss_processed', pyagentx.TYPE_COUNTER64, pass_value ]
]
PEER_KEYS = [
['srchost', pyagentx.TYPE_OCTETSTRING, pass_value],
['srcadr', pyagentx.TYPE_OCTETSTRING, pass_value],
['srcport', pyagentx.TYPE_INTEGER, pass_value],
['dstadr', pyagentx.TYPE_OCTETSTRING, pass_value],
['dstport', pyagentx.TYPE_INTEGER, pass_value],
['leap', pyagentx.TYPE_INTEGER, pass_value],
['hmode', pyagentx.TYPE_INTEGER, pass_value],
['refid', pyagentx.TYPE_OCTETSTRING, pass_value],
['stratum', pyagentx.TYPE_INTEGER, pass_value],
['hmode', pyagentx.TYPE_INTEGER, pass_value],
['ppoll', pyagentx.TYPE_INTEGER, pass_value],
['hpoll', pyagentx.TYPE_INTEGER, pass_value],
['precision', pyagentx.TYPE_INTEGER, pass_value],
['rootdelay', pyagentx.TYPE_INTEGER, int_scale1k],
['rootdisp', pyagentx.TYPE_INTEGER, int_scale1k],
['refid', pyagentx.TYPE_OCTETSTRING, pass_value],
['reftime', pyagentx.TYPE_OCTETSTRING, pass_value],
['rec', pyagentx.TYPE_OCTETSTRING, pass_value],
['xmt', pyagentx.TYPE_OCTETSTRING, pass_value],
['rec', pyagentx.TYPE_OCTETSTRING, string_ntp_seconds],
['reach', pyagentx.TYPE_INTEGER, pass_value],
['unreach', pyagentx.TYPE_INTEGER, pass_value],
['delay-s', pyagentx.TYPE_OCTETSTRING, pass_value],
['delay', pyagentx.TYPE_INTEGER, int_scale1k],
['offset', pyagentx.TYPE_INTEGER, int_scale1M],
['jitter', pyagentx.TYPE_INTEGER, int_scale1M],
['dispersion', pyagentx.TYPE_INTEGER, int_scale1k],
['keyid', pyagentx.TYPE_INTEGER, pass_value],
['filtdelay', pyagentx.TYPE_OCTETSTRING, pass_value],
['filtoffset', pyagentx.TYPE_OCTETSTRING, pass_value],
['pmode', pyagentx.TYPE_INTEGER, pass_value],
['filtdisp', pyagentx.TYPE_OCTETSTRING, pass_value],
['flash', pyagentx.TYPE_INTEGER, pass_value],
['headway', pyagentx.TYPE_INTEGER, pass_value],
['ntscookies', pyagentx.TYPE_INTEGER, pass_value]
]
@ -125,32 +114,39 @@ class NtpDataCollector(threading.Thread):
self.period = period
self.stop_event = threading.Event()
self.session = ntp.packet.ControlSession()
self.session.openhost(self.ntpserver)
threading.Thread.__init__(self)
def run(self):
while not self.stop_event.is_set():
logger.debug('Query ntp server')
try:
logger.debug('Query ntp server')
tmp_data_store = {}
ntpserver_vars = self.session.readvar(0)
logger.debug(f"{ntpserver_vars=}")
session = ntp.packet.ControlSession()
session.openhost(self.ntpserver)
tmp_data_store = {}
tmp_data_store['local'] = dict(ntpserver_vars)
sysinfo_vars = session.readvar(0, [ x[0] for x in SYSINFO_KEYS ])
logger.debug(f"{sysinfo_vars=}")
tmp_data_store['sysinfo'] = dict(sysinfo_vars)
peers = self.session.readstat()
tmp_data_store['peers'] = {}
for peer in peers:
peer_vars = self.session.readvar(peer.associd)
tmp_data_store['peers'][peer.associd] = dict(peer_vars)
logger.debug(f"{peer.associd=}, {peer_vars=}")
sysstats_vars = session.readvar(0, [ x[0] for x in SYSSTATS_KEYS ])
logger.debug(f"{sysstats_vars=}")
tmp_data_store['sysstats'] = dict(sysstats_vars)
with globalDataStore as ds:
ds.update_data(tmp_data_store)
peers = session.readstat()
tmp_data_store['peers'] = {}
for peer in peers:
peer_vars = session.readvar(peer.associd, [ x[0] for x in PEER_KEYS ])
tmp_data_store['peers'][peer.associd] = dict(peer_vars)
logger.debug(f"{peer.associd=}, {peer_vars=}")
with globalDataStore as ds:
ds.update_data(tmp_data_store)
except ntp.packet.ControlException as e:
logger.error(f"ntp.packet.ControlException while querying NTP server: {str(e)}")
finally:
time.sleep(self.period)
time.sleep(self.period)
logger.info('NtpDataCollector terminating')
def stop(self):
@ -163,15 +159,31 @@ class NtpsecDataUpdater(pyagentx.Updater):
with globalDataStore as ds:
if ds.data:
try:
for index, data_spec in enumerate(LOCAL_SERVER_KEYS, start=1):
logger.debug("Updating data store")
for index, data_spec in enumerate(SYSINFO_KEYS, start=1):
# logger.debug(f"local: {index=} {data_spec=}")
oid_prefix = f"{LOCAL_PREFIX}.{index}"
self._data[oid_prefix] = {
'name': oid_prefix,
'type': data_spec[1],
'value': data_spec[2](ds.data['local'][data_spec[0]])
}
try:
oid_prefix = f"{SYSINFO_PREFIX}.{index}"
self._data[oid_prefix] = {
'name': oid_prefix,
'type': data_spec[1],
'value': data_spec[2](ds.data['sysinfo'][data_spec[0]])
}
except KeyError as e:
logger.error(f"key {data_spec[0]} missing in local, skip it: {str(e)}")
for index, data_spec in enumerate(SYSSTATS_KEYS, start=1):
# logger.debug(f"local: {index=} {data_spec=}")
try:
oid_prefix = f"{SYSSTATS_PREFIX}.{index}"
self._data[oid_prefix] = {
'name': oid_prefix,
'type': data_spec[1],
'value': data_spec[2](ds.data['sysstats'][data_spec[0]])
}
except KeyError as e:
logger.error(f"key {data_spec[0]} missing in local, skip it: {str(e)}")
number_of_peers = len(ds.data['peers'])
# logger.debug(f"number of peers: {number_of_peers}")
number_of_peers_oid_prefix = f"{NUMBER_OF_PEERS_PREFIX}"
@ -196,25 +208,29 @@ class NtpsecDataUpdater(pyagentx.Updater):
}
for key_index, data_spec in enumerate(PEER_KEYS, start=3):
# logger.debug(f"peer: {associd=} {key_index=} {data_spec=}")
oid_prefix = f"{TABLE_OF_PEERS_PREFIX}.{key_index}.{peer_index}"
self._data[oid_prefix] = {
'name': oid_prefix,
'type': data_spec[1],
'value': data_spec[2](peer[data_spec[0]])
}
try:
oid_prefix = f"{TABLE_OF_PEERS_PREFIX}.{key_index}.{peer_index}"
self._data[oid_prefix] = {
'name': oid_prefix,
'type': data_spec[1],
'value': data_spec[2](peer[data_spec[0]])
}
except KeyError as e:
logger.error(f"key {data_spec[0]} missing in peer {associd}, skip it: {str(e)}")
except Exception as e:
logger.error(f"Failed to update: {type(e)} {e}")
class NtpsecAgent(pyagentx.Agent):
def __init__(self, agent_id='NtpsecAgent', socket_path=None):
def __init__(self, period=1, agent_id='NtpsecAgent', socket_path=None):
logger.info('Agent created')
self.period = period
super().__init__()
def setup(self):
logger.info('Agent setup')
self.register(BASE_OID_HOTTIS_NTPSEC, NtpsecDataUpdater, freq=1)
self.register(BASE_OID_HOTTIS_NTPSEC, NtpsecDataUpdater, freq=self.period)
@ -239,8 +255,6 @@ def daemonize(pid_filename):
os.dup2(log.fileno(), sys.stdout.fileno())
os.dup2(log.fileno(), sys.stderr.fileno())
logger.removeHandler(stdout_handler)
pyagentx.setup_logging(debug=True)
def set_user_group(user, group):
if group:
@ -258,10 +272,10 @@ def set_user_group(user, group):
sys.exit(1)
os.setuid(uid)
if __name__ == '__main__':
def setup_logging(verbose):
log_level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=LOGGING_LEVEL,
level=log_level,
format="%(name)s - %(levelname)s - %(message)s",
handlers=[logging.handlers.SysLogHandler(address='/dev/log')]
)
@ -269,13 +283,18 @@ if __name__ == '__main__':
stdout_handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stdout_handler.setFormatter(formatter)
pyagentx.setup_logging(debug=verbose)
logger.addHandler(stdout_handler)
return logger
if __name__ == '__main__':
pid_filename = '/tmp/agentx-ntpsec.pid'
parser = argparse.ArgumentParser(description='snmpd agentx extension for ntpsec')
parser.add_argument('--period', '-p',
help='Period to query the NTP server, in seconds, default 60s',
type=int,
required=False,
default=60)
parser.add_argument('--ntpserver', '-n',
@ -299,39 +318,29 @@ if __name__ == '__main__':
help="Set gid of process",
required=False,
default='')
parser.add_argument('--verbose', '-v',
help='Enable debug output',
required=False,
action='store_true',
default=False)
args = parser.parse_args()
if args.daemonize:
daemonize(pid_filename)
set_user_group(args.user, args.group)
logger = setup_logging(args.verbose)
if args.group:
try:
gid = grp.getgrnam(args.group).gr_gid
except KeyError:
logger.error(f"Group {args.group} does not exist")
sys.exit(1)
os.setgid(gid)
if args.user:
try:
uid = pwd.getpwnam(args.user).pw_uid
except KeyError:
logger.error(f"user {args.user} does not exist")
sys.exit(1)
os.setuid(uid)
ntpserver = args.ntpserver
period = args.period
try:
globalDataStore = DataStore()
ndc = NtpDataCollector(ntpserver=ntpserver, period=period)
ndc.start()
nsax = NtpsecAgent()
nsax = NtpsecAgent(period=period)
nsax.start()
except Exception as e:
logger.error(f"Unhandled exception: {e}")

View File

@ -0,0 +1,15 @@
[Unit]
Description=AgentX NTPsec Service
After=network.target
[Service]
ExecStart=/usr/bin/python3 /usr/local/bin/agentx-ntpsec.py -u Debian-snmp -g Debian-snmp -p 30 --pid /run/agentx-ntpsec.pid
User=Debian-snmp
Group=Debian-snmp
PIDFile=/run/agentx-ntpsec.pid
Restart=always
[Install]
WantedBy=multi-user.target