Skip to content

Commit

Permalink
CA-369899: DHCP|Default|Manual|None NTP config
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerald Elder-Vass committed Mar 13, 2024
1 parent c202279 commit a992e30
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 114 deletions.
120 changes: 109 additions & 11 deletions XSConsoleData.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

import XenAPI
import datetime
import subprocess, re, shutil, sys, tempfile, socket, os
import time
import subprocess, re, shutil, sys, tempfile, socket, os, stat
from pprint import pprint
from simpleconfig import SimpleConfigFile

Expand Down Expand Up @@ -486,10 +487,26 @@ def UpdateFromHostname(self):
self.ScanHostname(output.split("\n"))

def UpdateFromNTPConf(self):
if not 'ntp' in self.data:
self.data['ntp'] = {}

(status, output) = getstatusoutput("/bin/cat /etc/chrony.conf")
if status == 0:
self.ScanNTPConf(output.split("\n"))

self.data['ntp']['method'] = ""
chronyPerm = os.stat("/etc/dhcp/dhclient.d/chrony.sh").st_mode
if chronyPerm & stat.S_IXUSR and chronyPerm & stat.S_IXGRP and chronyPerm & stat.S_IXOTH:
self.data['ntp']['method'] = "DHCP"
elif self.data['ntp']['servers']:
self.data['ntp']['method'] = "Manual"

servers = self.data['ntp']['servers']
if len(servers) == 4 and all("centos.pool.ntp.org" in server for server in self.data['ntp']['servers']):
self.data['ntp']['method'] = "Default"
else:
self.data['ntp']['method'] = "Disabled"

def StringToBool(self, inString):
return inString.lower().startswith('true')

Expand Down Expand Up @@ -528,17 +545,95 @@ def SaveToNTPConf(self):
# Double-check authentication
Auth.Inst().AssertAuthenticated()

file = None
try:
file = open("/etc/chrony.conf", "w")
for other in self.ntp.othercontents([]):
file.write(other+"\n")
for server in self.ntp.servers([]):
file.write("server "+server+" iburst\n")
with open("/etc/chrony.conf", "w") as confFile:
for other in self.ntp.othercontents([]):
confFile.write(other + "\n")
for server in self.ntp.servers([]):
confFile.write("server " + server + " iburst\n")
finally:
if file is not None: file.close()
self.UpdateFromNTPConf()

# Force chronyd to update the time
if self.data['ntp']['method'] != "Disabled":
servers = self.data['ntp']['servers']
if self.data['ntp']['method'] == "DHCP":
servers = self.GetDHClientInterfaces()

if servers:
self.StopService("chronyd")
getoutput("chronyd -q 'server %s iburst'" % servers[0]) # Update the clock and exit
getoutput("hwclock -w") # Sync hwclock with date set by chronyd
self.StartService("chronyd")

def AddDHCPNTP(self):
# Double-check authentication
Auth.Inst().AssertAuthenticated()

oldPermissions = os.stat("/etc/dhcp/dhclient.d/chrony.sh").st_mode
newPermissions = oldPermissions | (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
os.chmod("/etc/dhcp/dhclient.d/chrony.sh", newPermissions)

interfaces = self.GetDHClientInterfaces()
for interface in interfaces:
ntpServer = self.GetDHCPNTPServer(interface)

with open("/var/lib/dhclient/chrony.servers.%s" % interface, "w") as chronyFile:
chronyFile.write("%s iburst prefer\n" % ntpServer)

def ResetDefaultNTPServers(self):
# Double-check authentication
Auth.Inst().AssertAuthenticated()

Data.Inst().NTPServersSet(["0.centos.pool.ntp.org",
"1.centos.pool.ntp.org",
"2.centos.pool.ntp.org",
"3.centos.pool.ntp.org"])

def GetDHClientInterfaces(self):
(status, output) = getstatusoutput("ls /var/lib/xcp/ | grep leases")
if status != 0:
return []

dhclientFiles = output.splitlines()
pattern = "dhclient-(.*).leases"
interfaces = []
for dhclientFile in dhclientFiles:
match = re.match(pattern, dhclientFile)
if match:
interfaces.append(match.group(1))

return interfaces

def GetDHCPNTPServer(self, interface):
ntpServer = getoutput("grep ntp-servers /var/lib/xcp/dhclient-%s.leases | tail -1 | awk '{{ print ( $3 ) }}'" % interface).strip()[:-1]
return ntpServer

def RemoveDHCPNTP(self):
# Double-check authentication
Auth.Inst().AssertAuthenticated()

oldPermissions = os.stat("/etc/dhcp/dhclient.d/chrony.sh").st_mode
newPermissions = oldPermissions & ~(stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
os.chmod("/etc/dhcp/dhclient.d/chrony.sh", newPermissions)

getstatusoutput("rm -f /var/lib/dhclient/chrony.servers.*")

def SetTimeManually(self, date):
# Double-check authentication
Auth.Inst().AssertAuthenticated()

self.NTPServersSet([])
self.RemoveDHCPNTP()
self.SaveToNTPConf()

self.DisableService("chrony-wait")
self.DisableService("chronyd")

timestring = date.strftime("%Y-%m-%d %H:%M:00")
getstatusoutput("date --set='%s'" % timestring)
getstatusoutput("hwclock --utc --systohc")

def SaveToResolveConf(self):
# Double-check authentication
Auth.Inst().AssertAuthenticated()
Expand Down Expand Up @@ -724,9 +819,6 @@ def ScanHostname(self, inLines):
self.data['sysconfig']['network']['hostname'] = inLines[0]

def ScanNTPConf(self, inLines):
if not 'ntp' in self.data:
self.data['ntp'] = {}

self.data['ntp']['servers'] = []
self.data['ntp']['othercontents'] = []

Expand Down Expand Up @@ -953,6 +1045,12 @@ def DisableManagement(self):
# Network reconfigured so this link is potentially no longer valid
self.session = Auth.Inst().CloseSession(self.session)

def AdjustNTPForStaticNetwork(self):
self.RemoveDHCPNTP()
if not self.data['ntp']['servers']: # No NTP servers after removing DHCP
self.ResetDefaultNTPServers()
self.SaveToNTPConf()

def LocalHostEnable(self):
Auth.Inst().AssertAuthenticatedOrPasswordUnset()
self.RequireSession()
Expand Down
4 changes: 2 additions & 2 deletions XSConsoleDialoguePane.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,10 @@ def AddStatusField(self, inName, inValue):
self.AddBodyFieldObj(TextField(str(inName), self.brightColour, Field.FLOW_RIGHT))
self.AddBodyFieldObj(WrappedTextField(str(inValue), self.baseColour, Field.FLOW_RETURN))

def AddInputField(self, inName, inValue, inLabel, inLengthLimit = None):
def AddInputField(self, inName, inValue, inLabel, inLengthLimit = None, inputWidth=INPUT_FIELD_DEFAULT_WIDTH, flow=Field.FLOW_RETURN):
self.AddBodyFieldObj(TextField(str(inName), self.brightColour, Field.FLOW_RIGHT))
self.AddInputFieldObj(InputField(str(inValue), self.highlightColour, self.selectedColour,
Field.FLOW_RETURN, inLengthLimit), inLabel)
flow, inLengthLimit, width=inputWidth), inLabel)

def AddPasswordField(self, inName, inValue, inLabel, inLengthLimit = None):
self.AddBodyFieldObj(TextField(str(inName), self.brightColour, Field.FLOW_RIGHT))
Expand Down
7 changes: 4 additions & 3 deletions XSConsoleFields.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@ def Width(self):
def Height(self):
return 1

INPUT_FIELD_DEFAULT_WIDTH = 40 # Declared for use in constructor
class InputField(Field):
MIN_WIDTH = 40 # Minimum width for input fields
MIN_WIDTH = 5 # Minimum width for input fields

def __init__(self, text, colour, selectedColour, flow, lengthLimit):
def __init__(self, text, colour, selectedColour, flow, lengthLimit, width=INPUT_FIELD_DEFAULT_WIDTH):
ParamsToAttr()
self.activated = False
self.cursorPos = len(self.text)
self.hideText = False
self.selected = True
self.scrollPos = 0
self.width = self.MIN_WIDTH
self.UpdateWidth(width)
if self.lengthLimit is None:
self.lengthLimit = 4096

Expand Down
4 changes: 4 additions & 0 deletions plugins-base/XSFeatureInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,11 +423,15 @@ def Commit(self):
if self.nic is None:
self.mode = None
data.DisableManagement()
data.AdjustNTPForStaticNetwork()
Layout.Inst().PushDialogue(InfoDialogue(Lang("Removed DHCP NTP server")))
else:
pif = data.host.PIFs()[self.nic]
if self.mode.lower().startswith('static'):
# Comma-separated list of nameserver IPs
dns = ','.join(data.dns.nameservers([]))
data.AdjustNTPForStaticNetwork()
Layout.Inst().PushDialogue(InfoDialogue(Lang("Removed DHCP NTP server")))
else:
dns = ''

Expand Down
Loading

0 comments on commit a992e30

Please sign in to comment.