コード例 #1
0
ファイル: genloader.py プロジェクト: N2Github/Proje
class Loader(MySupport):

    def __init__(self,
        start = False,
        stop = False,
        hardstop = False,
        loglocation = ProgramDefaults.LogPath,
        log = None,
        localinit = False,
        ConfigFilePath = ProgramDefaults.ConfPath):

        self.Start = start
        self.Stop = stop
        self.HardStop = hardstop


        self.ConfigFilePath = ConfigFilePath

        self.ConfigFileName = "genloader.conf"
        # log errors in this module to a file
        if localinit == True:
            self.configfile = self.ConfigFileName
        else:
            self.configfile = self.ConfigFilePath + self.ConfigFileName

        self.ModulePath = os.path.dirname(os.path.realpath(__file__)) + "/"
        self.ConfPath = os.path.dirname(os.path.realpath(__file__)) + "/conf/"


        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("genloader", loglocation + "genloader.log")
        else:
            self.log = log

        self.console = SetupLogger("genloader_console", log_file = "", stream = True)

        try:
            if self.Start:
                if not self.CheckSystem():
                    self.LogInfo("Error check system readiness. Exiting")
                    sys.exit(2)

            self.CachedConfig = {}

            if not os.path.isdir(self.ConfigFilePath):
                try:
                    os.mkdir(self.ConfigFilePath)
                except Exception as e1:
                    self.LogInfo("Error creating target config directory: " + str(e1), LogLine = True)

            # check to see if genloader.conf is present, if not copy it from genmon directory
            if not os.path.isfile(self.configfile):
                self.LogInfo("Warning: unable to find config file: " + self.configfile + " Copying file to " + self.ConfigFilePath +  " directory.")
                if os.path.isfile(self.ConfPath + self.ConfigFileName):
                    copyfile(self.ConfPath + self.ConfigFileName , self.configfile)
                else:
                    self.LogInfo("Unable to find config file.")
                    sys.exit(2)

            self.config = MyConfig(filename = self.configfile, section = "genmon", log = self.log)
            if not self.GetConfig():
                self.LogInfo("Error reading config file. Exiting")
                sys.exit(2)

            if not self.ValidateConfig():
                self.LogInfo("Error validating config. Exiting")
                sys.exit(2)

            self.LoadOrder = self.GetLoadOrder()

            if self.Stop:
                self.StopModules()
                time.sleep(2)

            if self.Start:
                self.StartModules()
        except Exception as e1:
            self.LogErrorLine("Error in init: " + str(e1))

    #---------------------------------------------------------------------------
    def CheckSystem(self):

        # this function checks the system to see if the required libraries are
        # installed. If they are not then an attempt is made to install them.
        ModuleList = [
            # [import name , install name]
            ['flask','flask'],
            ['configparser','configparser'],
            ['serial','pyserial'],
            ['crcmod','crcmod'],
            ['pyowm','pyowm'],
            ['pytz','pytz'],
            ['pysnmp','pysnmp']
        ]
        try:
            ErrorOccured = False
            for Module in ModuleList:
                if not self.LibraryIsInstalled(Module[0]):
                    self.LogInfo("Warning: required library " + Module[1] + " not installed. Attempting to install....")
                    if not self.InstallLibrary(Module[1]):
                        self.LogInfo("Error: unable to install library " + Module[1])
                        ErrorOccured = True
            return not ErrorOccured
        except Exception as e1:
            self.LogInfo("Error in CheckSystem: " + str(e1), LogLine = True)
            return False

    #---------------------------------------------------------------------------
    @staticmethod
    def OneTimeMaint(ConfigFilePath, log):

        FileList = {
              "feedback.json" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "outage.txt" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "kwlog.txt" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "maintlog.json" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "Feedback_dat" : os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
              "Message_dat" : os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
              'genmon.conf' : "/etc/",
              'genserv.conf': "/etc/",
              'gengpio.conf' : "/etc/",
              'gengpioin.conf': "/etc/",
              'genlog.conf' : "/etc/",
              'gensms.conf' : "/etc/",
              'gensms_modem.conf': "/etc/",
              'genpushover.conf': "/etc/",
              'gensyslog.conf' : "/etc/",
              'genmqtt.conf' : "/etc/",
              'genslack.conf': "/etc/",
              'genexercise.conf' : "/etc/",
              'genemail2sms.conf' :  "/etc/",
              'genloader.conf' :  "/etc/",
              'mymail.conf' : "/etc/",
              'mymodem.conf' : "/etc/"
        }
        try:
            # Check to see if we have done this already by checking files in the genmon source directory
            if (not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/Message_dat") and
            not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/maintlog.json") and
            not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/outage.txt") and
            not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/kwlog.txt") and
            not os.path.isfile("/etc/genmon.conf")):
                return False
            # validate target directory
            if not os.path.isdir(ConfigFilePath):
                try:
                    os.mkdir(ConfigFilePath)
                    if not os.access(ConfigFilePath + File, os.R_OK):
                        pass
                except Exception as e1:
                    log.error("Error validating target directory: " + str(e1), LogLine = True)

            # move files
            for File, Path in FileList.items():
                try:
                    SourceFile = Path + File
                    if os.path.isfile(SourceFile):
                        log.error("Moving " + SourceFile + " to " + ConfigFilePath )
                        if not MySupport.CopyFile(SourceFile, ConfigFilePath + File, move = True, log = log):
                            log.error("Error: using alternate move method")
                            move(SourceFile , ConfigFilePath + File)
                        if not os.access(ConfigFilePath + File, os.R_OK):
                            pass
                except Exception as e1:
                    log.error("Error moving " + SourceFile)
        except Exception as e1:
            log.error("Error moving files: " + str(e1), LogLine = True)
        return True

    #---------------------------------------------------------------------------
    def LibraryIsInstalled(self, libraryname):

        try:
            import importlib
            my_module = importlib.import_module(libraryname)
            return True
        except Exception as e1:
            return False

    #---------------------------------------------------------------------------
    def InstallLibrary(self, libraryname):

        try:
            process = Popen(['pip','install', libraryname], stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallLibrary using pip : " + libraryname + " : " + str(_error))
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error installing module: " + libraryname + ": "+ str(e1), LogLine = True)
            return False
    #---------------------------------------------------------------------------
    def ValidateConfig(self):

        ErrorOccured = False
        if not len(self.CachedConfig):
            self.LogInfo("Error: Empty configruation found.")
            return False

        for Module, Settiings in self.CachedConfig.items():
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not os.path.isfile(self.ModulePath + self.CachedConfig[Module]["module"]):
                        self.LogInfo("Enable to find file " + self.ModulePath + self.CachedConfig[Module]["module"])
                        ErrorOccured = True

                # validate config file and if it is not there then copy it.
                if not self.CachedConfig[Module]["conffile"] == None and len(self.CachedConfig[Module]["conffile"]):
                    ConfFileList = self.CachedConfig[Module]["conffile"].split(",")
                    for ConfigFile in ConfFileList:
                        ConfigFile = ConfigFile.strip()
                        if not os.path.isfile(self.ConfigFilePath + ConfigFile):
                            if os.path.isfile(self.ConfPath + ConfigFile):
                                self.LogInfo("Copying " + ConfigFile + " to " + self.ConfigFilePath )
                                copyfile(self.ConfPath + ConfigFile , self.ConfigFilePath + ConfigFile)
                            else:
                                self.LogInfo("Enable to find config file " + self.ConfPath + ConfigFile)
                                ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error validating config for " + Module + " : " + str(e1), LogLine = True)
                return False

        return not ErrorOccured

    #---------------------------------------------------------------------------
    def AddEntry(self, section = None, module = None, conffile = "", args = "", priority = '2'):

        try:
            if section == None or module == None:
                return
            self.config.WriteSection(section)
            self.config.WriteValue('module', module, section = section)
            self.config.WriteValue('enable', 'False', section = section)
            self.config.WriteValue('hardstop', 'False', section = section)
            self.config.WriteValue('conffile', conffile, section = section)
            self.config.WriteValue('args', args, section = section)
            self.config.WriteValue('priority', priority, section = section)
        except Exception as e1:
            self.LogInfo("Error in AddEntry: " + str(e1), LogLine = True)
        return

    #---------------------------------------------------------------------------
    def UpdateIfNeeded(self):

        try:
            self.config.SetSection("gengpioin")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile', "gengpioin.conf", section = "gengpioin")
                self.LogError("Updated entry gengpioin.conf")
            else:
                defValue = self.config.ReadValue('conffile', default = "")
                if not len(defValue):
                    self.config.WriteValue('conffile', "gengpioin.conf", section = "gengpioin")
                    self.LogError("Updated entry gengpioin.conf")

        except Exception as e1:
            self.LogInfo("Error in UpdateIfNeeded: " + str(e1), LogLine = True)

    #---------------------------------------------------------------------------
    def GetConfig(self):

        try:

            Sections = self.config.GetSections()
            ValidSections = ['genmon', 'genserv', 'gengpio', 'gengpioin', 'genlog', 'gensms', 'gensms_modem', 'genpushover', 'gensyslog', 'genmqtt', 'genslack', 'genexercise', 'genemail2sms', 'gentankutil', 'genalexa', 'gensnmp']
            for entry in ValidSections:
                if not entry in Sections:
                    if entry == 'genslack':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genslack.py', conffile = 'genslack.conf')
                    if entry == 'genexercise':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genexercise.py', conffile = 'genexercise.conf')
                    if entry == 'genemail2sms':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genemail2sms.py', conffile = 'genemail2sms.conf')
                    if entry == 'gentankutil':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'gentankutil.py', conffile = 'gentankutil.conf')
                    if entry == 'genalexa':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genalexa.py', conffile = 'genalexa.conf')
                    if entry == 'gensnmp':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'gensnmp.py', conffile = 'gensnmp.conf')
                    else:
                        self.LogError("Warning: Missing entry: " + entry)

            self.UpdateIfNeeded()

            Sections = self.config.GetSections()
            for SectionName in Sections:
                TempDict = {}
                self.config.SetSection(SectionName)
                if self.config.HasOption('module'):
                    TempDict['module'] = self.config.ReadValue('module')
                else:
                    TempDict['module'] = None

                if self.config.HasOption('enable'):
                    TempDict['enable'] = self.config.ReadValue('enable', return_type = bool)
                else:
                    TempDict['enable'] = False

                if self.config.HasOption('hardstop'):
                    TempDict['hardstop'] = self.config.ReadValue('hardstop', return_type = bool)
                else:
                    TempDict['hardstop'] = False

                if self.config.HasOption('conffile'):
                    TempDict['conffile'] = self.config.ReadValue('conffile')
                else:
                    TempDict['conffile'] = None

                if self.config.HasOption('args'):
                    TempDict['args'] = self.config.ReadValue('args')
                else:
                    TempDict['args'] = None

                if self.config.HasOption('priority'):
                    TempDict['priority'] = self.config.ReadValue('priority', return_type = int, default = None)
                else:
                    TempDict['priority'] = None

                if self.config.HasOption('postloaddelay'):
                    TempDict['postloaddelay'] = self.config.ReadValue('postloaddelay', return_type = int, default = 0)
                else:
                    TempDict['postloaddelay'] = 0

                if self.config.HasOption('pid'):
                    TempDict['pid'] = self.config.ReadValue('pid', return_type = int, default = 0, NoLog = True)
                else:
                    TempDict['pid'] = 0

                self.CachedConfig[SectionName] = TempDict
            return True

        except Exception as e1:
            self.LogInfo("Error parsing config file: " + str(e1), LogLine = True)
            return False

    #---------------------------------------------------------------------------
    def ConvertToInt(self, value, default = None):

        try:
            return int(str(value))
        except:
            return default

    #---------------------------------------------------------------------------
    def GetLoadOrder(self):

        LoadOrder = []
        LoadDict = {}
        try:
            for Module, Settiings in self.CachedConfig.items():
                # get the load order of all modules, even if they are disabled
                # since we need to stop all modules (even disabled ones) if the
                # conf file changed
                try:
                    if self.CachedConfig[Module]["priority"] == None:
                        LoadDict[Module] = 99
                    elif self.CachedConfig[Module]["priority"] >= 0:
                        LoadDict[Module] = self.CachedConfig[Module]["priority"]
                    else:
                        LoadDict[Module] = 99
                except Exception as e1:
                    self.LogInfo("Error reading load order (retrying): " + str(e1), LogLine = True)
            #lambda kv: (-kv[1], kv[0])
            for key, value in sorted(LoadDict.items(), key=lambda kv: (-kv[1], kv[0])):
            #for key, value in sorted(LoadDict.iteritems(), key=lambda (k,v): (v,k)):
                LoadOrder.append(key)
        except Exception as e1:
            self.LogInfo("Error reading load order: " + str(e1), LogLine = True)

        return LoadOrder
    #---------------------------------------------------------------------------
    def StopModules(self):

        self.LogConsole("Stopping....")
        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to stop.")
            return False
        ErrorOccured = False
        for Module in self.LoadOrder:
            try:
                if not self.UnloadModule(self.ModulePath, self.CachedConfig[Module]["module"], pid = self.CachedConfig[Module]["pid"],HardStop = self.CachedConfig[Module]["hardstop"], UsePID = True):
                    self.LogInfo("Error stopping " + Module)
                    ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error stopping module " + Module + " : " + str(e1), LogLine = True)
                return False
        return not ErrorOccured
    #---------------------------------------------------------------------------
    def StartModules(self):

        self.LogConsole("Starting....")

        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to start.")
            return False
        ErrorOccured = False
        for Module in reversed(self.LoadOrder):
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not self.LoadModule(self.ModulePath, self.CachedConfig[Module]["module"], args = self.CachedConfig[Module]["args"]):
                        self.LogInfo("Error starting " + Module)
                        ErrorOccured = True
                    if not self.CachedConfig[Module]["postloaddelay"] == None and self.CachedConfig[Module]["postloaddelay"] > 0:
                        time.sleep(self.CachedConfig[Module]["postloaddelay"])
            except Exception as e1:
                self.LogInfo("Error starting module " + Module + " : " + str(e1), LogLine = True)
                return False
        return not ErrorOccured
    #---------------------------------------------------------------------------
    def LoadModuleAlt(self, modulename, args = None):
        try:
            self.LogConsole("Starting " + modulename)
            # to load as a background process we just use os.system since Popen
            # is problematic in doing this
            CommandString = sys.executable + " " + modulename
            if args != None and len(args):
                CommandString += " " + args
            CommandString += " &"
            os.system(CommandString)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine = True)
            return False

    #---------------------------------------------------------------------------
    def LoadModule(self, path, modulename, args = None):
        try:
            fullmodulename = path + modulename
            if args != None:
                self.LogConsole("Starting " + fullmodulename + " " + args)
            else:
                self.LogConsole("Starting " + fullmodulename)
            try:
                from subprocess import DEVNULL # py3k
            except ImportError:
                import os
                DEVNULL = open(os.devnull, 'wb')

            if not len(args):
                args = None

            if "genserv.py" in modulename:
                OutputStream = DEVNULL
            else:
                OutputStream = subprocess.PIPE

            executelist = [sys.executable, fullmodulename]
            if args != None:
                executelist.extend(args.split(" "))
            # This will make all the programs use the same config files
            executelist.extend(["-c", self.ConfigFilePath])
            # close_fds=True
            pid = subprocess.Popen(executelist, stdout=OutputStream, stderr=OutputStream, stdin=OutputStream)
            self.UpdatePID(modulename, pid.pid)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module " + modulename + ": " + str(e1), LogLine = True)
            return False
    #---------------------------------------------------------------------------
    def UnloadModule(self, path, modulename, pid = None, HardStop = False, UsePID = False):
        try:
            LoadInfo = []
            if UsePID:
                if pid == None or pid == "" or pid == 0:
                    return True
                LoadInfo.append("kill")
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append(str(pid))
            else:
                LoadInfo.append('pkill')
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append('-u')
                LoadInfo.append('root')
                LoadInfo.append('-f')
                LoadInfo.append(modulename)

            self.LogConsole("Stopping " + modulename)
            process = Popen(LoadInfo, stdout=PIPE)
            output, _error = process.communicate()
            rc = process.returncode
            self.UpdatePID(modulename, "")
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine = True)
            return False
    #---------------------------------------------------------------------------
    def UpdatePID(self, modulename, pid = None):

        try:
            filename = os.path.splitext(modulename)[0]    # remove extension
            self.config.SetSection(filename)
            self.config.WriteValue("pid", str(pid))
        except Exception as e1:
            self.LogInfo("Error writing PID for " + modulename + " : " + str(e1))
コード例 #2
0
class Loader(MySupport):
    def __init__(self,
                 start=False,
                 stop=False,
                 hardstop=False,
                 loglocation="/var/log/",
                 log=None,
                 localinit=False,
                 ConfigFilePath=None):

        self.Start = start
        self.Stop = stop
        self.HardStop = hardstop

        if ConfigFilePath == None:
            self.ConfigFilePath = "/etc/"
        else:
            self.ConfigFilePath = ConfigFilePath

        self.ConfigFileName = "genloader.conf"
        # log errors in this module to a file
        if localinit == True:
            self.configfile = self.ConfigFileName
        else:
            self.configfile = self.ConfigFilePath + self.ConfigFileName

        self.ModulePath = os.path.dirname(os.path.realpath(__file__)) + "/"
        self.ConfPath = os.path.dirname(os.path.realpath(__file__)) + "/conf/"

        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("genloader", loglocation + "genloader.log")
        else:
            self.log = log

        self.console = SetupLogger("genloader_console",
                                   log_file="",
                                   stream=True)

        try:
            if self.Start:
                if not self.CheckSystem():
                    self.LogInfo("Error check system readiness. Exiting")
                    sys.exit(2)

            self.CachedConfig = {}

            # check to see if genloader.conf is present, if not copy it from genmon directory
            if not os.path.isfile(self.configfile):
                self.LogInfo("Warning: unable to find config file: " +
                             self.configfile +
                             " Copying file to /etc/ directory.")
                if os.path.isfile(self.ConfPath + self.ConfigFileName):
                    copyfile(self.ConfPath + self.ConfigFileName,
                             self.configfile)
                else:
                    self.LogInfo("Unable to find config file.")
                    sys.exit(2)

            self.config = MyConfig(filename=self.configfile,
                                   section="genmon",
                                   log=self.log)
            if not self.GetConfig():
                self.LogInfo("Error reading config file. Exiting")
                sys.exit(2)

            if not self.ValidateConfig():
                self.LogInfo("Error validating config. Exiting")
                sys.exit(2)

            self.LoadOrder = self.GetLoadOrder()

            if self.Stop:
                self.StopModules()
                time.sleep(2)

            if self.Start:
                self.StartModules()
        except Exception as e1:
            self.LogErrorLine("Error in init: " + str(e1))

    #---------------------------------------------------------------------------
    def CheckSystem(self):

        # this function checks the system to see if the required libraries are
        # installed. If they are not then an attempt is made to install them.
        ModuleList = [
            # [import name , install name]
            ['flask', 'flask'],
            ['configparser', 'configparser'],
            ['serial', 'pyserial'],
            ['crcmod', 'crcmod'],
            ['pyowm', 'pyowm'],
            ['pytz', 'pytz']
        ]
        try:
            ErrorOccured = False
            for Module in ModuleList:
                if not self.LibraryIsInstalled(Module[0]):
                    self.LogInfo("Warning: required library " + Module[1] +
                                 " not installed. Attempting to install....")
                    if not self.InstallLibrary(Module[1]):
                        self.LogInfo("Error: unable to install library " +
                                     Module[1])
                        ErrorOccured = True
            return not ErrorOccured
        except Exception as e1:
            self.LogInfo("Error in CheckSystem: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def LibraryIsInstalled(self, libraryname):

        try:
            import importlib
            my_module = importlib.import_module(libraryname)
            return True
        except Exception as e1:
            return False

    #---------------------------------------------------------------------------
    def InstallLibrary(self, libraryname):

        try:
            process = Popen(['pip', 'install', libraryname],
                            stdout=PIPE,
                            stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallLibrary using pip : " +
                             libraryname + " : " + str(_error))
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error installing module: " + libraryname + ": " +
                         str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def ValidateConfig(self):

        ErrorOccured = False
        if not len(self.CachedConfig):
            self.LogInfo("Error: Empty configruation found.")
            return False

        for Module, Settiings in self.CachedConfig.items():
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not os.path.isfile(self.ModulePath +
                                          self.CachedConfig[Module]["module"]):
                        self.LogInfo("Enable to find file " + self.ModulePath +
                                     self.CachedConfig[Module]["module"])
                        ErrorOccured = True

                # validate config file and if it is not there then copy it.
                if not self.CachedConfig[Module]["conffile"] == None and len(
                        self.CachedConfig[Module]["conffile"]):
                    ConfFileList = self.CachedConfig[Module]["conffile"].split(
                        ",")
                    for ConfigFile in ConfFileList:
                        ConfigFile = ConfigFile.strip()
                        if not os.path.isfile(self.ConfigFilePath +
                                              ConfigFile):
                            if os.path.isfile(self.ConfPath + ConfigFile):
                                self.LogInfo("Copying " + ConfigFile + " to " +
                                             self.ConfigFilePath)
                                copyfile(self.ConfPath + ConfigFile,
                                         self.ConfigFilePath + ConfigFile)
                            else:
                                self.LogInfo("Enable to find config file " +
                                             self.ConfPath + ConfigFile)
                                ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error validating config for " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False

        return not ErrorOccured

    #---------------------------------------------------------------------------
    def AddEntry(self,
                 section=None,
                 module=None,
                 conffile="",
                 args="",
                 priority='2'):

        try:
            if section == None or module == None:
                return
            self.config.WriteSection(section)
            self.config.WriteValue('module', module, section=section)
            self.config.WriteValue('enable', 'False', section=section)
            self.config.WriteValue('hardstop', 'False', section=section)
            self.config.WriteValue('conffile', conffile, section=section)
            self.config.WriteValue('args', args, section=section)
            self.config.WriteValue('priority', priority, section=section)
        except Exception as e1:
            self.LogInfo("Error in AddEntry: " + str(e1), LogLine=True)
        return

    #---------------------------------------------------------------------------
    def UpdateIfNeeded(self):

        try:
            self.config.SetSection("gengpioin")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile',
                                       "gengpioin.conf",
                                       section="gengpioin")
                self.LogError("Updated entry gengpioin.conf")
            else:
                defValue = self.config.ReadValue('conffile', default="")
                if not len(defValue):
                    self.config.WriteValue('conffile',
                                           "gengpioin.conf",
                                           section="gengpioin")
                    self.LogError("Updated entry gengpioin.conf")

        except Exception as e1:
            self.LogInfo("Error in UpdateIfNeeded: " + str(e1), LogLine=True)

    #---------------------------------------------------------------------------
    def GetConfig(self):

        try:

            Sections = self.config.GetSections()
            ValidSections = [
                'genmon', 'genserv', 'gengpio', 'gengpioin', 'genlog',
                'gensms', 'gensms_modem', 'genpushover', 'gensyslog',
                'genmqtt', 'genslack', 'genexercise'
            ]
            for entry in ValidSections:
                if not entry in Sections:
                    if entry == 'genslack':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genslack.py',
                                      conffile='genslack.conf')
                    if entry == 'genexercise':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genexercise.py',
                                      conffile='genexercise.conf')
                    else:
                        self.LogError("Warning: Missing entry: " + entry)

            self.UpdateIfNeeded()

            Sections = self.config.GetSections()
            for SectionName in Sections:
                TempDict = {}
                self.config.SetSection(SectionName)
                if self.config.HasOption('module'):
                    TempDict['module'] = self.config.ReadValue('module')
                else:
                    TempDict['module'] = None

                if self.config.HasOption('enable'):
                    TempDict['enable'] = self.config.ReadValue(
                        'enable', return_type=bool)
                else:
                    TempDict['enable'] = False

                if self.config.HasOption('hardstop'):
                    TempDict['hardstop'] = self.config.ReadValue(
                        'hardstop', return_type=bool)
                else:
                    TempDict['hardstop'] = False

                if self.config.HasOption('conffile'):
                    TempDict['conffile'] = self.config.ReadValue('conffile')
                else:
                    TempDict['conffile'] = None

                if self.config.HasOption('args'):
                    TempDict['args'] = self.config.ReadValue('args')
                else:
                    TempDict['args'] = None

                if self.config.HasOption('priority'):
                    TempDict['priority'] = self.config.ReadValue(
                        'priority', return_type=int, default=None)
                else:
                    TempDict['priority'] = None

                if self.config.HasOption('postloaddelay'):
                    TempDict['postloaddelay'] = self.config.ReadValue(
                        'postloaddelay', return_type=int, default=0)
                else:
                    TempDict['postloaddelay'] = 0

                self.CachedConfig[SectionName] = TempDict
            return True

        except Exception as e1:
            self.LogInfo("Error parsing config file: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def ConvertToInt(self, value, default=None):

        try:
            return int(str(value))
        except:
            return default

    #---------------------------------------------------------------------------
    def GetLoadOrder(self):

        LoadOrder = []
        LoadDict = {}
        try:
            for Module, Settiings in self.CachedConfig.items():
                # get the load order of all modules, even if they are disabled
                # since we need to stop all modules (even disabled ones) if the
                # conf file changed
                try:
                    if self.CachedConfig[Module]["priority"] == None:
                        LoadDict[Module] = 99
                    elif self.CachedConfig[Module]["priority"] >= 0:
                        LoadDict[Module] = self.CachedConfig[Module][
                            "priority"]
                    else:
                        LoadDict[Module] = 99
                except Exception as e1:
                    self.LogInfo("Error reading load order (retrying): " +
                                 str(e1),
                                 LogLine=True)
            #lambda kv: (-kv[1], kv[0])
            for key, value in sorted(LoadDict.items(),
                                     key=lambda kv: (-kv[1], kv[0])):
                #for key, value in sorted(LoadDict.iteritems(), key=lambda (k,v): (v,k)):
                LoadOrder.append(key)
        except Exception as e1:
            self.LogInfo("Error reading load order: " + str(e1), LogLine=True)

        return LoadOrder

    #---------------------------------------------------------------------------
    def StopModules(self):

        self.LogConsole("Stopping....")
        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to stop.")
            return False
        ErrorOccured = False
        for Module in self.LoadOrder:
            try:
                if not self.UnloadModule(
                        self.CachedConfig[Module]["module"],
                        HardStop=self.CachedConfig[Module]["hardstop"]):
                    self.LogInfo("Error stopping " + Module)
                    ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error stopping module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def StartModules(self):

        self.LogConsole("Starting....")

        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to start.")
            return False
        ErrorOccured = False
        for Module in reversed(self.LoadOrder):
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not self.LoadModule(
                            self.ModulePath +
                            self.CachedConfig[Module]["module"],
                            args=self.CachedConfig[Module]["args"]):
                        self.LogInfo("Error starting " + Module)
                        ErrorOccured = True
                    if not self.CachedConfig[Module][
                            "postloaddelay"] == None and self.CachedConfig[
                                Module]["postloaddelay"] > 0:
                        time.sleep(self.CachedConfig[Module]["postloaddelay"])
            except Exception as e1:
                self.LogInfo("Error starting module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def LoadModuleAlt(self, modulename, args=None):
        try:
            self.LogConsole("Starting " + modulename)
            # to load as a background process we just use os.system since Popen
            # is problematic in doing this
            CommandString = sys.executable + " " + modulename
            if args != None and len(args):
                CommandString += " " + args
            CommandString += " &"
            os.system(CommandString)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def LoadModule(self, modulename, args=None):
        try:
            self.LogConsole("Starting " + modulename)

            try:
                from subprocess import DEVNULL  # py3k
            except ImportError:
                import os
                DEVNULL = open(os.devnull, 'wb')

            if not len(args):
                args = None

            if "genserv.py" in modulename:
                OutputStream = DEVNULL
            else:
                OutputStream = subprocess.PIPE
            if args == None:
                # close_fds=True
                pid = subprocess.Popen([sys.executable, modulename],
                                       stdout=OutputStream,
                                       stderr=OutputStream,
                                       stdin=OutputStream)
            else:
                pid = subprocess.Popen([sys.executable, modulename, args],
                                       stdout=OutputStream,
                                       stderr=OutputStream,
                                       stdin=OutputStream)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def UnloadModule(self, modulename, HardStop=False):
        try:
            self.LogConsole("Stopping " + modulename)
            LoadInfo = []
            LoadInfo.append('pkill')
            if HardStop or self.HardStop:
                LoadInfo.append('-9')
            LoadInfo.append('-u')
            LoadInfo.append('root')
            LoadInfo.append('-f')
            LoadInfo.append(modulename)

            process = Popen(LoadInfo, stdout=PIPE)
            output, _error = process.communicate()
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False
コード例 #3
0
class Loader(MySupport):
    def __init__(self,
                 start=False,
                 stop=False,
                 hardstop=False,
                 loglocation=ProgramDefaults.LogPath,
                 log=None,
                 localinit=False,
                 ConfigFilePath=ProgramDefaults.ConfPath):

        self.Start = start
        self.Stop = stop
        self.HardStop = hardstop
        self.PipChecked = False
        self.NewInstall = False
        self.Upgrade = False
        self.version = None

        self.ConfigFilePath = ConfigFilePath

        self.ConfigFileName = "genloader.conf"
        # log errors in this module to a file
        if localinit == True:
            self.configfile = self.ConfigFileName
        else:
            self.configfile = os.path.join(self.ConfigFilePath,
                                           self.ConfigFileName)

        self.ModulePath = os.path.dirname(os.path.realpath(__file__))
        self.ConfPath = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), "conf")

        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("genloader",
                                   os.path.join(loglocation, "genloader.log"))
        else:
            self.log = log

        self.console = SetupLogger("genloader_console",
                                   log_file="",
                                   stream=True)

        try:
            if self.Start:
                if not self.CheckSystem():
                    self.LogInfo("Error check system readiness. Exiting")
                    sys.exit(2)

            self.CachedConfig = {}

            if not os.path.isdir(self.ConfigFilePath):
                try:
                    os.mkdir(self.ConfigFilePath)
                except Exception as e1:
                    self.LogInfo("Error creating target config directory: " +
                                 str(e1),
                                 LogLine=True)

            # check to see if genloader.conf is present, if not copy it from genmon directory
            if not os.path.isfile(self.configfile):
                self.LogInfo("Warning: unable to find config file: " +
                             self.configfile + " Copying file to " +
                             self.ConfigFilePath + " directory.")
                if not self.CopyConfFile():
                    sys.exit(2)

            self.config = MyConfig(filename=self.configfile,
                                   section="genmon",
                                   log=self.log)

            if not self.GetConfig():
                self.CopyConfFile()
                self.LogInfo("Error validating config. Retrying..")
                self.config = MyConfig(filename=self.configfile,
                                       section="genmon",
                                       log=self.log)
                if not self.GetConfig():
                    self.LogInfo(
                        "Error reading config file, 2nd attempt (1), Exiting")
                    sys.exit(2)

            if not self.ValidateConfig():
                self.CopyConfFile()
                self.LogInfo("Error validating config. Retrying..")
                self.config = MyConfig(filename=self.configfile,
                                       section="genmon",
                                       log=self.log)
                if not self.GetConfig():
                    self.LogInfo(
                        "Error reading config file, 2nd attempt (2), Exiting")
                    sys.exit(2)
                if not self.ValidateConfig():
                    self.LogInfo("Error validating config file, Exiting")
                    sys.exit(2)

            self.LoadOrder = self.GetLoadOrder()

            if self.Stop:
                self.StopModules()
                time.sleep(2)

            if self.Start:
                self.StartModules()
        except Exception as e1:
            self.LogErrorLine("Error in init: " + str(e1))

    #---------------------------------------------------------------------------
    def CopyConfFile(self):

        if os.path.isfile(os.path.join(self.ConfPath, self.ConfigFileName)):
            copyfile(os.path.join(self.ConfPath, self.ConfigFileName),
                     self.configfile)
            return True
        else:
            self.LogInfo("Unable to find config file.")
            return False
            sys.exit(2)

    #---------------------------------------------------------------------------
    def CheckSystem(self):

        # this function checks the system to see if the required libraries are
        # installed. If they are not then an attempt is made to install them.
        ModuleList = [
            # [import name , install name, required version]
            ['flask', 'flask', None],  # Web server
            # we will not use the check for configparser as this look like it is in backports on 2.7
            # and our myconfig modules uses the default so this generates an error that is not warranted
            #['configparser','configparser',None],   # reading config files
            ['serial', 'pyserial', None],  # Serial
            ['crcmod', 'crcmod', None],  # Modbus CRC
            ['pyowm', 'pyowm', '2.10.0'],  # Open Weather API
            ['pytz', 'pytz', None],  # Time zone support
            ['pysnmp', 'pysnmp', None],  # SNMP
            ['ldap3', 'ldap3', None],  # LDAP
            ['smbus', 'smbus', None],  # SMBus reading of temp sensors
            ['pyotp', 'pyotp', '2.3.0'],  # 2FA support
            ['psutil', 'psutil', None],  # process utilities
            ['chump', 'chump', None],  # for genpushover
            ['twilio', 'twilio', None],  # for gensms
            ['paho.mqtt.client', 'paho-mqtt', None],  # for genmqtt
            ['OpenSSL', 'pyopenssl', None],  # SSL
            ['spidev', 'spidev', None]  # spidev
        ]
        try:
            ErrorOccured = False

            for Module in ModuleList:
                if not self.LibraryIsInstalled(Module[0]):
                    self.LogInfo("Warning: required library " + Module[1] +
                                 " not installed. Attempting to install....")
                    if not self.InstallLibrary(Module[1], version=Module[2]):
                        self.LogInfo("Error: unable to install library " +
                                     Module[1])
                        ErrorOccured = True
                    if Module[0] == "ldap3":
                        # This will correct and issue with the ldap3 modbule not being recogonized in LibrayIsInstalled
                        self.InstallLibrary("pyasn1", update=True)

            return not ErrorOccured
        except Exception as e1:
            self.LogInfo("Error in CheckSystem: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def CheckBaseSoftware(self):

        try:
            if self.PipChecked:
                return True

            if sys.version_info[0] < 3:
                pipProgram = "pip2"
            else:
                pipProgram = "pip3"

            install_list = [pipProgram, '-V']
            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in CheckBaseSoftware  : " + str(_error))
            rc = process.returncode

            self.PipChecked = True
            return True
        except Exception as e1:
            self.LogInfo("Error in CheckBaseSoftware: " + str(e1),
                         LogLine=True)
            self.InstallBaseSoftware()
            return False

    #---------------------------------------------------------------------------
    def InstallBaseSoftware(self):

        try:
            if sys.version_info[0] < 3:
                pipProgram = "python-pip"
            else:
                pipProgram = "python3-pip"

            self.LogInfo("Installing " + pipProgram)

            install_list = ["sudo", "apt-get", "-yqq", "update"]
            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallBaseSoftware  : " + str(_error))
            rc = process.returncode

            install_list = ["sudo", "apt-get", "-yqq", "install", pipProgram]
            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()
            return True
        except Exception as e1:
            self.LogInfo("Error in InstallBaseSoftware: " + str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    @staticmethod
    def OneTimeMaint(ConfigFilePath, log):

        FileList = {
            "feedback.json": os.path.dirname(os.path.realpath(__file__)) + "/",
            "outage.txt": os.path.dirname(os.path.realpath(__file__)) + "/",
            "kwlog.txt": os.path.dirname(os.path.realpath(__file__)) + "/",
            "maintlog.json": os.path.dirname(os.path.realpath(__file__)) + "/",
            "Feedback_dat":
            os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
            "Message_dat":
            os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
            'genmon.conf': "/etc/",
            'genserv.conf': "/etc/",
            'gengpio.conf': "/etc/",
            'gengpioin.conf': "/etc/",
            'genlog.conf': "/etc/",
            'gensms.conf': "/etc/",
            'gensms_modem.conf': "/etc/",
            'genpushover.conf': "/etc/",
            'gensyslog.conf': "/etc/",
            'genmqtt.conf': "/etc/",
            'genslack.conf': "/etc/",
            'genexercise.conf': "/etc/",
            'genemail2sms.conf': "/etc/",
            'genloader.conf': "/etc/",
            'mymail.conf': "/etc/",
            'mymodem.conf': "/etc/"
        }
        try:
            # Check to see if we have done this already by checking files in the genmon source directory
            if (not os.path.isfile(
                    os.path.dirname(os.path.realpath(__file__)) +
                    "/genmonlib/Message_dat") and not os.path.isfile(
                        os.path.dirname(os.path.realpath(__file__)) +
                        "/maintlog.json") and not os.path.isfile(
                            os.path.dirname(os.path.realpath(__file__)) +
                            "/outage.txt") and not os.path.isfile(
                                os.path.dirname(os.path.realpath(__file__)) +
                                "/kwlog.txt")
                    and not os.path.isfile("/etc/genmon.conf")):
                return False
            # validate target directory
            if not os.path.isdir(ConfigFilePath):
                try:
                    os.mkdir(ConfigFilePath)
                    if not os.access(ConfigFilePath + File, os.R_OK):
                        pass
                except Exception as e1:
                    log.error("Error validating target directory: " + str(e1),
                              LogLine=True)

            # move files
            for File, Path in FileList.items():
                try:
                    SourceFile = Path + File
                    if os.path.isfile(SourceFile):
                        log.error("Moving " + SourceFile + " to " +
                                  ConfigFilePath)
                        if not MySupport.CopyFile(SourceFile,
                                                  ConfigFilePath + File,
                                                  move=True,
                                                  log=log):
                            log.error("Error: using alternate move method")
                            move(SourceFile, ConfigFilePath + File)
                        if not os.access(ConfigFilePath + File, os.R_OK):
                            pass
                except Exception as e1:
                    log.error("Error moving " + SourceFile)
        except Exception as e1:
            log.error("Error moving files: " + str(e1), LogLine=True)
        return True

    #---------------------------------------------------------------------------
    def FixPyOWMMaintIssues(self):
        try:
            # check version of pyowm
            import pyowm
            if sys.version_info[0] < 3:
                required_version = "2.9.0"
            else:
                required_version = "2.10.0"

            if not self.LibraryIsInstalled("pyowm"):
                self.LogError(
                    "Error in FixPyOWMMaintIssues: pyowm not installed")
                return False

            installed_version = self.GetLibararyVersion("pyowm")

            if installed_version == None:
                self.LogError(
                    "Error in FixPyOWMMaintIssues: pyowm version not found")
                return None

            if self.VersionTuple(installed_version) <= self.VersionTuple(
                    required_version):
                return True

            self.LogInfo(
                "Found wrong version of pyowm, uninstalling and installing the correct version."
            )

            self.InstallLibrary("pyowm", uninstall=True)

            self.InstallLibrary("pyowm", version=required_version)

            return True
        except Exception as e1:
            self.LogErrorLine("Error in FixPyOWMMaintIssues: " + str(e1))
            return False

    #---------------------------------------------------------------------------
    def GetLibararyVersion(self, libraryname, importonly=False):

        try:

            try:
                import importlib
                my_module = importlib.import_module(libraryname)
                return my_module.__version__
            except:

                if importonly:
                    return None
                # if we get here then the libarary does not support a __version__ attribute
                # lets use pip to get the version
                try:
                    if sys.version_info[0] < 3:
                        pipProgram = "pip2"
                    else:
                        pipProgram = "pip3"

                    # This will check if pip is installed
                    if "linux" in sys.platform:
                        self.CheckBaseSoftware()

                    install_list = [pipProgram, 'freeze', libraryname]

                    process = Popen(install_list, stdout=PIPE, stderr=PIPE)
                    output, _error = process.communicate()

                    if _error:
                        self.LogInfo(
                            "Error in GetLibararyVersion using pip : " +
                            libraryname + ": " + str(_error))
                    rc = process.returncode

                    # process output of pip freeze
                    lines = output.splitlines()

                    for line in lines:
                        line = line.decode("utf-8")
                        line = line.strip()
                        if line.startswith(libraryname):
                            items = line.split('==')
                            if len(items) <= 2:
                                return items[1]
                    return None

                except Exception as e1:
                    self.LogInfo("Error getting version of module: " +
                                 libraryname + ": " + str(e1),
                                 LogLine=True)
                    return None
        except Exception as e1:
            self.LogErrorLine("Error in GetLibararyVersion: " + str(e1))
            return None

    #---------------------------------------------------------------------------
    def LibraryIsInstalled(self, libraryname):

        try:
            import importlib
            my_module = importlib.import_module(libraryname)
            return True
        except Exception as e1:
            return False

    #---------------------------------------------------------------------------
    def InstallLibrary(self,
                       libraryname,
                       update=False,
                       version=None,
                       uninstall=False):

        try:
            if sys.version_info[0] < 3:
                pipProgram = "pip2"
            else:
                pipProgram = "pip3"

            if version != None and uninstall == False:
                libraryname = libraryname + "==" + version

            # This will check if pip is installed
            if "linux" in sys.platform:
                self.CheckBaseSoftware()

            if update:
                install_list = [pipProgram, 'install', libraryname, '-U']
            elif uninstall:
                install_list = [pipProgram, 'uninstall', '-y', libraryname]
            else:
                install_list = [pipProgram, 'install', libraryname]

            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallLibrary using pip : " +
                             libraryname + " : UnInstall: " + str(uninstall) +
                             ": " + str(_error))
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error installing module: " + libraryname +
                         " : UnInstall: " + str(uninstall) + ": " + str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def ValidateConfig(self):

        ErrorOccured = False
        if not len(self.CachedConfig):
            self.LogInfo("Error: Empty configruation found.")
            return False

        for Module, Settiings in self.CachedConfig.items():
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not os.path.isfile(
                            os.path.join(self.ModulePath,
                                         self.CachedConfig[Module]["module"])):
                        self.LogInfo(
                            "Enable to find file " +
                            os.path.join(self.ModulePath,
                                         self.CachedConfig[Module]["module"]))
                        ErrorOccured = True

                # validate config file and if it is not there then copy it.
                if not self.CachedConfig[Module]["conffile"] == None and len(
                        self.CachedConfig[Module]["conffile"]):
                    ConfFileList = self.CachedConfig[Module]["conffile"].split(
                        ",")
                    for ConfigFile in ConfFileList:
                        ConfigFile = ConfigFile.strip()
                        if not os.path.isfile(
                                os.path.join(self.ConfigFilePath, ConfigFile)):
                            if os.path.isfile(
                                    os.path.join(self.ConfPath, ConfigFile)):
                                self.LogInfo("Copying " + ConfigFile + " to " +
                                             self.ConfigFilePath)
                                copyfile(
                                    os.path.join(self.ConfPath, ConfigFile),
                                    os.path.join(self.ConfigFilePath,
                                                 ConfigFile))
                            else:
                                self.LogInfo(
                                    "Enable to find config file " +
                                    os.path.join(self.ConfPath, ConfigFile))
                                ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error validating config for " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False

        try:
            if not self.CachedConfig["genmon"]["enable"]:
                self.LogError(
                    "Warning: Genmon is not enabled, assume corrupt file.")
                ErrorOccured = True
            if not self.CachedConfig["genserv"]["enable"]:
                self.LogError("Warning: Genserv is not enabled")

        except Exception as e1:
            self.LogErrorLine(
                "Error in ValidateConfig, possible corrupt file. " + str(e1))
            ErrorOccured = True
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def AddEntry(self,
                 section=None,
                 module=None,
                 conffile="",
                 args="",
                 priority='2'):

        try:
            if section == None or module == None:
                return
            self.config.WriteSection(section)
            self.config.WriteValue('module', module, section=section)
            self.config.WriteValue('enable', 'False', section=section)
            self.config.WriteValue('hardstop', 'False', section=section)
            self.config.WriteValue('conffile', conffile, section=section)
            self.config.WriteValue('args', args, section=section)
            self.config.WriteValue('priority', priority, section=section)
        except Exception as e1:
            self.LogInfo("Error in AddEntry: " + str(e1), LogLine=True)
        return

    #---------------------------------------------------------------------------
    def UpdateIfNeeded(self):

        try:
            self.config.SetSection("gengpioin")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile',
                                       "gengpioin.conf",
                                       section="gengpioin")
                self.LogError("Updated entry gengpioin.conf")
            else:
                defValue = self.config.ReadValue('conffile', default="")
                if not len(defValue):
                    self.config.WriteValue('conffile',
                                           "gengpioin.conf",
                                           section="gengpioin")
                    self.LogError("Updated entry gengpioin.conf")

            self.config.SetSection("gengpio")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile',
                                       "gengpio.conf",
                                       section="gengpio")
                self.LogError("Updated entry gengpio.conf")
            else:
                defValue = self.config.ReadValue('conffile', default="")
                if not len(defValue):
                    self.config.WriteValue('conffile',
                                           "gengpio.conf",
                                           section="gengpio")
                    self.LogError("Updated entry gengpio.conf")

            # check version info
            self.config.SetSection("genloader")
            self.version = self.config.ReadValue("version", default="0.0.0")
            if self.version == "0.0.0" or not len(self.version):
                self.version = "0.0.0"
                self.NewInstall = True

            if self.VersionTuple(self.version) < self.VersionTuple(
                    ProgramDefaults.GENMON_VERSION):
                self.Upgrade = True

            if self.NewInstall or self.Upgrade:
                self.config.WriteValue("version",
                                       ProgramDefaults.GENMON_VERSION,
                                       section='genloader')
            if self.NewInstall:
                self.LogInfo("Running one time maintenance check")
                self.FixPyOWMMaintIssues()

            # TODO other version checks can be added here

            self.version = ProgramDefaults.GENMON_VERSION

        except Exception as e1:
            self.LogInfo("Error in UpdateIfNeeded: " + str(e1), LogLine=True)

    #---------------------------------------------------------------------------
    def GetConfig(self):

        try:

            Sections = self.config.GetSections()
            ValidSections = [
                'genmon', 'genserv', 'gengpio', 'gengpioin', 'genlog',
                'gensms', 'gensms_modem', 'genpushover', 'gensyslog',
                'genmqtt', 'genslack', 'genexercise', 'genemail2sms',
                'gentankutil', 'gentankdiy', 'genalexa', 'gensnmp', 'gentemp',
                'gengpioledblink', 'gencthat', 'genloader'
            ]
            for entry in ValidSections:
                if not entry in Sections:
                    if entry == 'genmon' or entry == 'genserv':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , file corruption. ")
                        return False
                    if entry == 'genslack':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genslack.py',
                                      conffile='genslack.conf')
                    if entry == 'genexercise':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genexercise.py',
                                      conffile='genexercise.conf')
                    if entry == 'genemail2sms':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genemail2sms.py',
                                      conffile='genemail2sms.conf')
                    if entry == 'gentankutil':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gentankutil.py',
                                      conffile='gentankutil.conf')
                    if entry == 'genalexa':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genalexa.py',
                                      conffile='genalexa.conf')
                    if entry == 'gensnmp':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gensnmp.py',
                                      conffile='gensnmp.conf')
                    if entry == 'gentemp':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gentemp.py',
                                      conffile='gentemp.conf')
                    if entry == 'gentankdiy':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gentankdiy.py',
                                      conffile='gentankdiy.conf')
                    if entry == 'gengpioledblink':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gengpioledblink.py',
                                      conffile='gengpioledblink.conf')
                    if entry == 'gencthat':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gencthat.py',
                                      conffile='gencthat.conf')
                    if entry == 'genloader':
                        self.LogError("Adding entry: " + entry)
                        self.config.WriteSection(entry)
                    else:
                        self.LogError("Warning: Missing entry: " + entry)

            self.UpdateIfNeeded()

            Sections = self.config.GetSections()
            for SectionName in Sections:
                if SectionName == 'genloader':
                    continue
                TempDict = {}
                self.config.SetSection(SectionName)
                if self.config.HasOption('module'):
                    TempDict['module'] = self.config.ReadValue('module')
                else:
                    self.LogError(
                        "Error in GetConfig: expcting module in section " +
                        str(SectionName))
                    TempDict['module'] = None

                if self.config.HasOption('enable'):
                    TempDict['enable'] = self.config.ReadValue(
                        'enable', return_type=bool)
                else:
                    self.LogError(
                        "Error in GetConfig: expcting enable in section " +
                        str(SectionName))
                    TempDict['enable'] = False

                if self.config.HasOption('hardstop'):
                    TempDict['hardstop'] = self.config.ReadValue(
                        'hardstop', return_type=bool)
                else:
                    self.LogError(
                        "Error in GetConfig: expcting hardstop in section " +
                        str(SectionName))
                    TempDict['hardstop'] = False

                if self.config.HasOption('conffile'):
                    TempDict['conffile'] = self.config.ReadValue('conffile')
                else:
                    self.LogError(
                        "Error in GetConfig: expcting confile in section " +
                        str(SectionName))
                    TempDict['conffile'] = None

                if self.config.HasOption('args'):
                    TempDict['args'] = self.config.ReadValue('args')
                else:
                    self.LogError(
                        "Error in GetConfig: expcting args in section " +
                        str(SectionName))
                    TempDict['args'] = None

                if self.config.HasOption('priority'):
                    TempDict['priority'] = self.config.ReadValue(
                        'priority', return_type=int, default=None)
                else:
                    self.LogError(
                        "Error in GetConfig: expcting priority in section " +
                        str(SectionName))
                    TempDict['priority'] = None

                if self.config.HasOption('postloaddelay'):
                    TempDict['postloaddelay'] = self.config.ReadValue(
                        'postloaddelay', return_type=int, default=0)
                else:
                    TempDict['postloaddelay'] = 0

                if self.config.HasOption('pid'):
                    TempDict['pid'] = self.config.ReadValue('pid',
                                                            return_type=int,
                                                            default=0,
                                                            NoLog=True)
                else:
                    TempDict['pid'] = 0

                self.CachedConfig[SectionName] = TempDict
            return True

        except Exception as e1:
            self.LogInfo("Error parsing config file: " + str(e1), LogLine=True)
            return False
        return True

    #---------------------------------------------------------------------------
    def ConvertToInt(self, value, default=None):

        try:
            return int(str(value))
        except:
            return default

    #---------------------------------------------------------------------------
    def GetLoadOrder(self):

        LoadOrder = []
        LoadDict = {}
        try:
            for Module, Settiings in self.CachedConfig.items():
                # get the load order of all modules, even if they are disabled
                # since we need to stop all modules (even disabled ones) if the
                # conf file changed
                try:
                    if self.CachedConfig[Module]["priority"] == None:
                        LoadDict[Module] = 99
                    elif self.CachedConfig[Module]["priority"] >= 0:
                        LoadDict[Module] = self.CachedConfig[Module][
                            "priority"]
                    else:
                        LoadDict[Module] = 99
                except Exception as e1:
                    self.LogInfo("Error reading load order (retrying): " +
                                 str(e1),
                                 LogLine=True)
            #lambda kv: (-kv[1], kv[0])
            for key, value in sorted(LoadDict.items(),
                                     key=lambda kv: (-kv[1], kv[0])):
                #for key, value in sorted(LoadDict.iteritems(), key=lambda (k,v): (v,k)):
                LoadOrder.append(key)
        except Exception as e1:
            self.LogInfo("Error reading load order: " + str(e1), LogLine=True)

        return LoadOrder

    #---------------------------------------------------------------------------
    def StopModules(self):

        self.LogConsole("Stopping....")
        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to stop.")
            return False
        ErrorOccured = False
        for Module in self.LoadOrder:
            try:
                if not self.UnloadModule(
                        self.ModulePath,
                        self.CachedConfig[Module]["module"],
                        pid=self.CachedConfig[Module]["pid"],
                        HardStop=self.CachedConfig[Module]["hardstop"],
                        UsePID=True):
                    self.LogInfo("Error stopping " + Module)
                    ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error stopping module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def StartModules(self):

        self.LogConsole("Starting....")

        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to start.")
            return False
        ErrorOccured = False
        for Module in reversed(self.LoadOrder):
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not multi_instance:
                        # check that module is not loaded already, if it is then force it (hard) to unload
                        attempts = 0
                        while True:
                            if MySupport.IsRunning(
                                    prog_name=self.CachedConfig[Module]
                                ["module"],
                                    log=self.log,
                                    multi_instance=multi_instance):
                                # if loaded then kill it
                                if attempts >= 4:
                                    # kill it
                                    if not self.UnloadModule(
                                            self.ModulePath,
                                            self.CachedConfig[Module]
                                        ["module"],
                                            pid=None,
                                            HardStop=True,
                                            UsePID=False):
                                        self.LogInfo("Error killing " +
                                                     self.CachedConfig[Module]
                                                     ["module"])
                                else:
                                    attempts += 1
                                    time.sleep(1)
                            else:
                                break

                    if not self.LoadModule(
                            self.ModulePath,
                            self.CachedConfig[Module]["module"],
                            args=self.CachedConfig[Module]["args"]):
                        self.LogInfo("Error starting " + Module)
                        ErrorOccured = True
                    if not self.CachedConfig[Module][
                            "postloaddelay"] == None and self.CachedConfig[
                                Module]["postloaddelay"] > 0:
                        time.sleep(self.CachedConfig[Module]["postloaddelay"])
            except Exception as e1:
                self.LogInfo("Error starting module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def LoadModuleAlt(self, modulename, args=None):
        try:
            self.LogConsole("Starting " + modulename)
            # to load as a background process we just use os.system since Popen
            # is problematic in doing this
            CommandString = sys.executable + " " + modulename
            if args != None and len(args):
                CommandString += " " + args
            CommandString += " &"
            os.system(CommandString)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def LoadModule(self, path, modulename, args=None):
        try:
            try:
                import os
                fullmodulename = os.path.join(path, modulename)
            except Exception as e1:
                fullmodulename = path + "/" + modulename

            if args != None:
                self.LogConsole("Starting " + fullmodulename + " " + args)
            else:
                self.LogConsole("Starting " + fullmodulename)
            try:
                from subprocess import DEVNULL  # py3k
            except ImportError:
                import os
                DEVNULL = open(os.devnull, 'wb')

            if not len(args):
                args = None

            if "genserv.py" in modulename:
                OutputStream = DEVNULL
            else:
                OutputStream = subprocess.PIPE

            executelist = [sys.executable, fullmodulename]
            if args != None:
                executelist.extend(args.split(" "))
            # This will make all the programs use the same config files
            executelist.extend(["-c", self.ConfigFilePath])
            # close_fds=True
            pid = subprocess.Popen(executelist,
                                   stdout=OutputStream,
                                   stderr=OutputStream,
                                   stdin=OutputStream)
            return self.UpdatePID(modulename, pid.pid)

        except Exception as e1:
            self.LogInfo("Error loading module " + path + ": " + modulename +
                         ": " + str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def UnloadModule(self,
                     path,
                     modulename,
                     pid=None,
                     HardStop=False,
                     UsePID=False):
        try:
            LoadInfo = []
            if UsePID:
                if pid == None or pid == "" or pid == 0:
                    return True
                LoadInfo.append("kill")
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append(str(pid))
            else:
                LoadInfo.append('pkill')
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append('-u')
                LoadInfo.append('root')
                LoadInfo.append('-f')
                LoadInfo.append(modulename)

            self.LogConsole("Stopping " + modulename)
            process = Popen(LoadInfo, stdout=PIPE)
            output, _error = process.communicate()
            rc = process.returncode
            return self.UpdatePID(modulename, "")

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def UpdatePID(self, modulename, pid=None):

        try:
            filename = os.path.splitext(modulename)[0]  # remove extension
            if not self.config.SetSection(filename):
                self.LogError("Error settting section name in UpdatePID: " +
                              str(filename))
                return False
            self.config.WriteValue("pid", str(pid))
            return True
        except Exception as e1:
            self.LogInfo("Error writing PID for " + modulename + " : " +
                         str(e1))
            return False
        return True