Example #1
0
    def __init__(self, config, componentID, loggerName = '', *args, **kwargs):
        '''
        Initializes the ntp_config class.
        Creates dictionaries of key:value configurations, which are taken
        from the config dictionary.
        Passed to this class from runner.py.
        '''

        super(ntp_config, self).__init__(config, componentID, loggerName = '', *args, **kwargs)

        self.Zone = ConstDict(config, 'Zone')
        self.Ntp = ConstDict(config, 'Ntp_')
        self.Runlevels = ConstDict(config, 'Runlevels')
        self.OnBoot = ConstDict(config, 'OnBoot')
        self.NtpdRestart = ConstDict(config, 'NtpdRestart')
        self.Template = ConstDict(config, 'Template_')
        self.Role = ConstDict(config, 'Role')
        self.Net = ConstDict(config, 'Net_')
        self.Interface = ConstDict(config, 'Interface')
Example #2
0
class ntp_config(builder, HashParser):
    def __init__(self, config, componentID, loggerName = '', *args, **kwargs):
        '''
        Initializes the ntp_config class.
        Creates dictionaries of key:value configurations, which are taken
        from the config dictionary.
        Passed to this class from runner.py.
        '''

        super(ntp_config, self).__init__(config, componentID, loggerName = '', *args, **kwargs)

        self.Zone = ConstDict(config, 'Zone')
        self.Ntp = ConstDict(config, 'Ntp_')
        self.Runlevels = ConstDict(config, 'Runlevels')
        self.OnBoot = ConstDict(config, 'OnBoot')
        self.NtpdRestart = ConstDict(config, 'NtpdRestart')
        self.Template = ConstDict(config, 'Template_')
        self.Role = ConstDict(config, 'Role')
        self.Net = ConstDict(config, 'Net_')
        self.Interface = ConstDict(config, 'Interface')

    def __call__(self, editFiles):
        '''
        Main call function.
        '''
        self.NtpAdjuster(editFiles)

    def NtpAdjuster(self, editFiles):
        '''
        Runs functions related to the automatic configuration
        of ntpd.
        Gets: editFiles (list).
        Returns: N/A
        '''
        self.logger.error('[%s] Starting ntp configuration...' % Grn('i'))

        try:
            zone = self.Zone['Zone']
        except:
            zone = ''

        try:
            runlevels = self.Runlevels['Runlevels']
            onBoot = self.OnBoot['OnBoot'].lower()
            restart = self.NtpdRestart['NtpdRestart'].lower()
            role = self.Role['Role'].lower()
        except KeyError:
            runlevels, onBoot, restart, role = '', '', '', ''

        Files = self.ConstFilesDict(editFiles)
        if runlevels == '' and onBoot == '' and restart == '' and role == '':
            Appendix = {}
            Appendix['clk'] = 'ZONE="%s"\nUTC=false\nARC=false\n' % zone
        else:
            Templates = self.ConstTemplateDict(self.Template)
            Appendix = self.ConstAppendixDict(zone, Templates, role)
            Servers = self.ConstServersList(Appendix)

        if zone != '':
            self.ChangeEtcLocalTime(zone, Files)
            self.RewriteClock(Files, Appendix)

        if len(self.Ntp) != 0:
            system('systemctl stop chronyd')
            system('systemctl disable chronyd')
            self.AppendToNtpConf(Files, Appendix)
            self.SetOnBoot(runlevels, onBoot)
            NtpKeys = self.Ntp.keys()
            self.RestartService(restart, self.Ntp[NtpKeys[0]])

            self.logger.error(\
            '[%s] Ntp configured. Servers: %s, OnBoot: "%s", Runlevels: "%s", NtpdRestarted: "%s"' \
            % (Grn('i'), Servers, onBoot, runlevels, restart))
        elif zone != '':
            self.logger.error(\
            '[%s] Time zone configured. Zone: "%s"' \
            % (Grn('i'), zone))
        elif zone == '' and len(self.Ntp) == 0 and role == 'server':
            system('systemctl stop chronyd')
            system('systemctl disable chronyd')
            self.AppendToNtpConf(Files, Appendix)
            self.SetOnBoot(runlevels, onBoot)
            NtpKeys = self.Ntp.keys()
            if len(NtpKeys) != 0:
                self.RestartService(restart, self.Ntp[NtpKeys[0]])
            else:
                self.RestartService(restart)

        elif zone != '' and len(self.Ntp) != 0:
            raise Exception, '[%s] Mixed configuration of ntpd and time zone is not possible, please check the config file.' % Red('e')

        
    def FileReader(self, fileName):
        '''
        Read lines from a given file and return them.
        '''

        self.logger.debug('[%s] Accessing FileReader()' % Blu('i'))

        if exists(fileName):
            fh = open(fileName, 'r')
            Lines = fh.readlines()
            fh.close()
            return Lines

    def ConstFilesDict(self, EditFiles, Files = {}):
        '''
        Creates a dictionary of files and keys for calling those files.
        Gets: EditFiles (list)
        Returns: Files (dict)
        '''
        for editFile in EditFiles:
            if 'ntp.conf' in editFile:
                Files['ntp'] = editFile
            elif 'localtime' in editFile:
                Files['lt'] = editFile
            elif 'clock' in editFile:
                Files['clk'] = editFile
        Files['clk'] = '/etc/sysconfig/clock'
        self.logger.debug('[%s] Compiled Files dictionary: %s' % (Blu('i'), Files))
        return Files

    def ConstTemplateDict(self, Tmpl, Templates = {}):
        '''
        Creates a dictionary of template lines and keys for calling them.
        Gets: Tmpl (list)
        Returns: Templates (dict)
        '''
        rst_cli, rst_srv, srv = 0, 0, 0
        for tmpl in Tmpl:
            if 'restrict' in Tmpl[tmpl] and 'nomodify' in Tmpl[tmpl] and 'noquery' not in Tmpl[tmpl]:
                Templates['rst_srv'] = Tmpl[tmpl].strip('"') + '\n'
                rst_srv += 1
            elif 'restrict' in Tmpl[tmpl] and 'nomodify' in Tmpl[tmpl] and 'noquery' in Tmpl[tmpl]:
                Templates['rst_cli'] = Tmpl[tmpl].strip('"') + '\n'
                rst_cli += 1
            elif 'server' in Tmpl[tmpl]:
                Templates['srv'] = Tmpl[tmpl].strip('"') + '\n'
                srv += 1
            if rst_cli + rst_srv + srv == len(Tmpl):
                break
        return Templates

    def ConstAppendixDict(self, zone, Templates, role, Appendix = {}):
        '''
        Creates a dictionary of appendix lines and keys for calling those lines.
        Gets: zone (str)
        Returns: Appendix (dict)
        '''
        Appendix['clk'] = 'ZONE="%s"\nUTC=false\nARC=false\n' % zone
        if len(self.Interface) > 0:
            interface = self.Interface[self.Interface.keys()[0]]
        else:
            interface = 'bond0'
        subnet, netmask = self.GetNet(interface)
        if role == 'server':
            i = 0
            if len(self.Ntp.keys()) != 0:
                for key in self.Ntp.keys():
                    try:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % eval(self.Ntp[key])
                    except TypeError:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % eval(self.Ntp[key])
                    except SyntaxError:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % self.Ntp[key]
                    except NameError:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % self.Ntp[key]
                    try:
                        Appendix['srv_%s' % str(i + 1)] = Templates['srv'] % eval(self.Ntp[key])
                    except SyntaxError:
                        Appendix['srv_%s' % str(i + 1)] = Templates['srv'] % self.Ntp[key]
                    except NameError:
                        Appendix['srv_%s' % str(i + 1)] = Templates['srv'] % self.Ntp[key]
                    Appendix['rst_%s' % str(i + 2)] = Templates['rst_srv'] % (subnet, netmask)
                    i += 1
            else:
                if zone == '':
                    self.logger.error('[%s] No ntp servers given, synchronizing locally...' % Grn('i'))
                Appendix['rst_%s' % str(i + 1)] = Templates['rst_srv'] % (subnet, netmask)
            for key in self.Net.keys():
                i += 1
                subnet, netmask = self.Net[key].split()[0], self.Net[key].split()[1]
                if subnet.endswith('.0'):
                    Appendix['rst_%s' % str(i + 1)] = Templates['rst_srv'] % (subnet, netmask)
                else:
                    subnet, netmask = self.GetNet('', subnet, netmask)
                    Appendix['rst_%s' % str(i + 1)] = Templates['rst_srv'] % (subnet, netmask)
        if role == 'client':
            i = 0
            if len(self.Ntp.keys()) != 0:    
                for key in self.Ntp.keys():
                    try:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % eval(self.Ntp[key])
                    except TypeError:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % (eval(self.Ntp[key]), netmask)
                    except SyntaxError:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % self.Ntp[key]
                    except NameError:
                        Appendix['rst_%s' % str(i + 1)] = Templates['rst_cli'] % self.Ntp[key]
                    try:
                        Appendix['srv_%s' % str(i + 1)] = Templates['srv'] % eval(self.Ntp[key])
                    except SyntaxError:
                        Appendix['srv_%s' % str(i + 1)] = Templates['srv'] % self.Ntp[key]
                    except NameError:
                        Appendix['srv_%s' % str(i + 1)] = Templates['srv'] % self.Ntp[key]
                    i += 1
            else:
                raise Exception, '[%s] Cannot configure ntp client without ntp servers, exiting...' % Red('e')
        self.logger.debug('[%s] Compiled Appendix dictionary: %s' % (Blu('i'), Appendix))
        return Appendix

    def ConstServersList(self, Appendix):
        '''
        Creates a list of servers.
        Gets: Appendix (dict)
        Returns: Servers (list)
        '''
        Servers = []
        for value in Appendix.values():
            if 'server' in value:
                try:
                    Servers.append(search('(server )(.*)(\n)', value).group(2))
                except AttributeError:
                    pass
        return Servers

    def AppendToNtpConf(self, Files, Appendix):
        '''
        Modifies ntp.conf.
        Gets: Files (dict), Appendix (dict).
        Returns: N/A
        '''
        if exists(Files['ntp']):
            Lines = self.FileReader(Files['ntp'])
        
            fh = open(Files['ntp'], 'w')
            for line in Lines:
                if (line.startswith('server') or line.startswith('restrict')) \
                and '127.127.1.0' not in line and 'default' not in line \
                and '127.0.0.1' not in line and '-6 ::1' not in line \
                and line not in Appendix.values():
                    self.logger.debug('[%s] Found colliding line, commenting out: %s' % (Blu('i'), line))
                    fh.write('#%s' % line)
                elif match('(server[\t\s]+127.127.1.0)|(fudge[\t\s]+127.127.1.0)', line) and \
                        (len(self.Ntp.keys()) > 0 or self.Role == 'client'):
                    self.logger.error('[%s] Found local NTP line, commenting out: %s' % (Blu('i'), line))
                    fh.write('#%s' % line)
                else:
                    fh.write(line)
            fh.close()

            fh = open(Files['ntp'], 'a')
            for key in ConstDict(Appendix, 'srv'):
                if Appendix[key] not in Lines:
                    fh.write(Appendix[key])
                    self.logger.error('[%s] Writing to %s: %s' % (Grn('i'), Files['ntp'], Appendix[key]))
            for key in ConstDict(Appendix, 'rst'):
                if Appendix[key] not in Lines:
                    fh.write(Appendix[key])
                    self.logger.error('[%s] Writing to %s: %s' % (Grn('i'), Files['ntp'], Appendix[key]))
            fh.close()
        else:
            raise Exception, '[%s] File not found: %s' % (Red('e'), Files['lt'])

    def ChangeEtcLocalTime(self, zone, Files):
        '''
        Replaces the localtime.
        Gets: zone (str), Files (dict)
        Returns: N/A
        '''
        if exists(Files['lt']):
            remove(Files['lt'])
            self.logger.debug('[%s] Removing file: %s' % (Grn('i'), Files['lt']))
        else:
            raise Exception, '[%s] File not found: %s' % (Red('e'), Files['lt'])

        self.logger.debug('[%s] Copying new zone file: %s' % (Grn('i'), Files['lt']))
        system('cp -pr %s %s' % (join('/usr/share/zoneinfo', zone), Files['lt']))
        system('timedatectl set-timezone  %s' % zone)

    def RewriteClock(self, Files, Appendix):
        '''
        Modifies the clock file.
        Gets: Files (dict), Appendix (dict).
        Returns: N/A
        '''
        if 'clk' in Files.keys():
            self.logger.debug('[%s] Writing to %s: %s' % (Grn('i'), Files['clk'], Appendix['clk']))
            fh = open(Files['clk'], 'w')
            fh.write(Appendix['clk'])
            fh.close()
        else:
            raise Exception, '[%s] File not found: %s' % (Red('e'), Files['lt'])

    def SetOnBoot(self, runlevels, onBoot):
        '''
        Sets or unsets ntpd to start on boot for required runlevels.
        Gets: runlevels (str), onBoot (str).
        Returns: N/A
        '''
        if onBoot.startswith('ena'):
            self.logger.debug('[%s] Setting ntpd to start on runlevels %s' % (Blu('i'), runlevels))
            system('chkconfig --level %s ntpd on' % runlevels)
        elif onBoot.startswith('dis'):
            self.logger.debug('[%s] Setting ntpd not to start on runlevels %s' % (Blu('i'), runlevels))
            system('chkconfig --level %s ntpd off' % runlevels)

    def RestartService(self, restart, server = ''):
        '''
        Restarts the ntpd service if requested in ntp_adj.conf.
        Gets: restart (str)
        Returns: N/A
        '''
        if restart.startswith('y'):
            self.logger.debug('[%s] Restarting ntpd...' % Blu('i'))
            #output = go('/etc/init.d/ntpd stop')
            #self.logger.error('[%s] %s' % (Grn('i'), output))
            system('systemctl stop ntpd')
            
            if server != '':
                try:
                    server = eval(server)
                except NameError:
                    pass
                except SyntaxError:
                    pass
                except TypeError:
                    pass
                output = go('/usr/sbin/ntpdate %s' % server)
                self.logger.error('[%s] %s' % (Grn('i'), output))
            else:
                self.logger.debug('[%s] Skipping ntpdate for local syncs' % Blu('i'))
            #output = go('/etc/init.d/ntpd start')
            system('systemctl enable ntpd')
            system('systemctl start ntpd')
            system('timedatectl set-ntp yes')
            #self.logger.error('[%s] %s' % (Grn('i'), output))
        elif restart.startswith('n'):
            self.logger.debug('[%s] Skipping ntpd restart...' % Blu('i'))
     
    def GetNet(self, eth = 'bond0', ip = '', netmask = ''):
        '''
        Finds the subnet and netmask of an ethernet device or, if given, finds a subnet
            and netmask of an ip and netmask couple.
        Gets: eth (optional str), ip (optional str), netmask (optional netmask)
        Returns: subnet, netmask (str, str)
        '''
        try:
            if ip == '':
                output = go('ifconfig %s' % eth)
                ip = search('(inet .*)(netmask.*)(broadcast.*)', output).group(1).lstrip('inet').strip() 
                netmask = search('(inet .*)(netmask.*)(broadcast.*)', output).group(2).lstrip('netmask').strip()
                subnet = go('ipcalc -n %s %s' % (ip, netmask)).lstrip('NETWORK=')
            elif ip != '' and netmask != '':
                subnet = go('ipcalc -n %s %s' % (ip, netmask)).lstrip('NETWORK=')
        except AttributeError:
            raise Exception, '[%s] The interface "%s" is not configured...' % (Red('e'), eth)
        return subnet, netmask