Esempio n. 1
0
class SHchkconfig(ServiceHelperTemplate):
    """SHchkconfig is the Service Helper for systems using the chkconfig command to
    configure services. (RHEL up to 6, SUSE, Centos up to 6, etc)
    
    @author: David Kennel


    """
    def __init__(self, environment, logdispatcher):
        """
        Constructor
        """
        super(SHchkconfig, self).__init__(environment, logdispatcher)
        self.environ = environment
        self.logger = logdispatcher
        self.initobjs()
        self.localize()

    def initobjs(self):
        """initialize class objects"""

        self.ch = CommandHelper(self.logger)

    def localize(self):
        """set base command paths (chkconfig and service) based on OS"""

        self.svc = ""
        self.chk = ""

        chk_paths = ["/sbin/chkconfig", "/usr/sbin/chkconfig"]
        for cp in chk_paths:
            if os.path.exists(cp):
                self.chk = cp
                break
        service_paths = ["/sbin/service", "/usr/sbin/service"]
        for sp in service_paths:
            if os.path.exists(sp):
                self.svc = sp
                break

        if not self.svc:
            raise IOError(
                "Could not locate the service utility on this system")
        if not self.chk:
            raise IOError(
                "Could not locate the chkconfig utility on this system")

    def startService(self, service, **kwargs):
        """start a given service

        :param service: string; name of service
        :param kwargs: return: success
        :param **kwargs: 
        :returns: success
        :rtype: bool
@author: Breen Malmberg

        """

        success = True

        self.ch.executeCommand(self.svc + " " + service + " start")
        retcode = self.ch.getReturnCode()
        if retcode != 0:
            success = False

        if not self.isRunning(service):
            success = False

        return success

    def stopService(self, service, **kwargs):
        """stop a given service

        :param service: param kwargs:
        :param **kwargs: 
        :returns: success
        :rtype: bool
@author: Breen Malmberg

        """

        success = True

        self.ch.executeCommand(self.svc + " " + service + " stop")
        retcode = self.ch.getReturnCode()
        if retcode != 0:
            success = False

        if self.isRunning(service):
            success = False

        return success

    def disableService(self, service, **kwargs):
        """Disables the specified service and stops it if
        it is running

        :param service: string; Name of the service to be disabled
        :param **kwargs: 
        :returns: bool
        @author: David Kennel
        @change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit;
                logging edit

        """

        disabled = True

        self.ch.executeCommand(self.chk + " " + service + " off")
        retcode = self.ch.getReturnCode()
        if retcode != 0:
            disabled = False

        if self.auditService(service):
            disabled = False

        if not self.stopService(service):
            disabled = False

        return disabled

    def enableService(self, service, **kwargs):
        """Enables a service and starts it if it is not running as long as we are
        not in install mode

        :param service: string; Name of the service to be enabled
        :param **kwargs: 
        :returns: enabled
        :rtype: bool
@author: David Kennel
@change: Breen Malmberg - 04/10/2019 -

        """

        enabled = True

        self.ch.executeCommand(self.chk + " " + service + " on")
        retcode = self.ch.getReturnCode()
        if retcode != 0:
            enabled = False

        if not self.auditService(service):
            enabled = False

        if not self.startService(service):
            enabled = False

        return enabled

    def auditService(self, service, **kwargs):
        """Checks the status of a service and returns a bool indicating whether or
        not the service is enabled

        :param service: string; Name of the service to audit
        :param **kwargs: 
        :returns: enabled
        :rtype: bool
@author: ???
@change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit;
        logging edit

        """

        enabled = True

        if not self.audit_chkconfig_service(service):
            enabled = False

        return enabled

    def audit_chkconfig_service(self, service):
        """uses the chkconfig command to check if a given
        service is enabled or not

        :param service: 
        :returns: enabled
        :rtype: bool
@author: Breen Malmberg

        """

        enabled = True

        self.ch.executeCommand(self.chk + " --list " + service)
        retcode = self.ch.getReturnCode()
        if retcode != 0:
            enabled = False
            self.logger.log(LogPriority.DEBUG,
                            "Failed to get status of service: " + service)
            return enabled

        output = self.ch.getOutputString()
        if not re.search(":on", output):
            enabled = False

        return enabled

    def isRunning(self, service, **kwargs):
        """Check to see if a service is currently running.

        :param service: string; Name of the service to check
        :param **kwargs: 
        :returns: running
        :rtype: bool
@author: ???
@change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit;
        logging edit

        """

        running = True
        # see: http://refspecs.linuxbase.org/LSB_3.1.0/LSB-generic/LSB-generic/iniscrptact.html
        success_codes = [0]

        self.ch.executeCommand(self.svc + " " + service + " status")
        retcode = self.ch.getReturnCode()
        if retcode not in success_codes:
            running = False
            self.logger.log(
                LogPriority.DEBUG,
                "Command error while getting run status of service: " +
                service)
            return running

        outputlines = self.ch.getOutput()
        # need to parse for either sysv or systemd output
        if not self.parse_running(outputlines):
            running = False

        return running

    def parse_running(self, outputlines):
        """check whether given service is running, with the
        service command
        this is the older (classic) systemV case

        :param outputlines: list; list of strings to search
        :returns: running
        :rtype: bool
@author: Breen Malmberg

        """

        running = True
        systemctl_locations = ["/usr/bin/systemctl", "/bin/systemctl"]
        if any(os.path.exists(sl) for sl in systemctl_locations):
            searchterms = ["Active:\s+inactive", "Active:\s+unknown"]
        else:
            searchterms = [
                "is stopped", "hook is not installed", "is not running"
            ]

        for line in outputlines:
            if any(re.search(st, line) for st in searchterms):
                running = False
                break

        return running

    def reloadService(self, service, **kwargs):
        """Reload (HUP) a service so that it re-reads it's config files. Called
        by rules that are configuring a service to make the new configuration
        active.

        :param service: string; Name of service to be reloaded
        :param **kwargs: 
        :returns: reloaded
        :rtype: bool
@author: ???
@change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit;
        logging edit

        """

        reloaded = True

        # force-reload: cause the configuration to be reloaded if the service supports this,
        # otherwise restart the service if it is running
        self.ch.executeCommand(self.svc + " " + service + " force-reload")
        retcode = self.ch.getReturnCode()
        if retcode != 0:
            reloaded = False
            self.logger.log(LogPriority.DEBUG,
                            "Failed to reload service: " + service)

        return reloaded

    def listServices(self, **kwargs):
        """Return a list containing strings that are service names.

        :param **kwargs: 
        :returns: service_list
        :rtype: list
@author: ???
@change: Breen Malmberg - 04/10/2019 - method refactor; doc string edit;
        logging edit

        """

        service_list = []

        self.ch.executeCommand(self.chk + " --list")
        outputlines = self.ch.getOutput()
        for line in outputlines:
            try:
                service_list.append(line.split()[0])
            except IndexError:
                pass

        return service_list

    def getStartCommand(self, service):
        """retrieve the start command.  Mostly used by event recording

        :param service: 
        :returns: string - start command
        @author: dwalker

        """
        return self.svc + " " + service + " start"

    def getStopCommand(self, service):
        """retrieve the stop command.  Mostly used by event recording

        :param service: 
        :returns: string - stop command
        @author: dwalker

        """
        return self.svc + " " + service + " stop"

    def getEnableCommand(self, service):
        """retrieve the enable command.  Mostly used by event recording

        :param service: 
        :returns: string - enable command
        @author: dwalker

        """
        return self.chk + " " + service + " on"

    def getDisableCommand(self, service):
        """retrieve the start command.  Mostly used by event recording

        :param service: 
        :returns: string - disable command
        @author: dwalker

        """
        return self.chk + " " + service + " off"
Esempio n. 2
0
class MacPkgr(object):

    def __init__(self, environ, logger):
        '''
        Mac package manager based on other stonix package managers.

        Uses the stonix IHmac and InstallingHelper Libraries.  They can
        install .zip, .tar, .tar.gz, .pkg and .mpkg files via an http or
        https URL

        :param environ: environment object
        :param logger: logdispatcher object

        # Methods specific to Mac.

        @note: Uses the stonix IHmac and InstallingHelper Libraries.  They can
               install .zip, .tar, .tar.gz, .pkg and .mpkg files via an http or
               https URL

        @note: WARNING: To use checkInstall or removepackage, this package
               manager converts all of the plists in the /var/db/receipts
               directory to text, then converts they all back to binary when it
               is done performing a reverse lookup to find if a specific
               package is installed. I would love to use Greg Neagle's
               FoundationPlist.py, but licenses are not compatible.
        @change: Breen Malmberg - 2/28/2017 - Made the missing macreporoot message more
                clear and helpful; added logic to also check if it is 'None'
        '''

        self.environ = environ

        self.osfamily = self.environ.getosfamily()
        if not re.match("^darwin$", self.osfamily.strip()):
            return

        #####
        # setting up to call ctypes to do a filesystem sync
        if self.environ.getosfamily() == "darwin":
            self.libc = C.CDLL("/usr/lib/libc.dylib")
        else:
            self.libc = None

        self.logger = logger
        self.detailedresults = ""
        self.pkgUrl = ""
        self.reporoot = ""
        if not MACREPOROOT:
            raise NoRepoException("Please ensure that the constant, MACREPOROOT, is properly defined in localize.py and is not set to 'None'")
        elif MACREPOROOT == None:
            raise NoRepoException("Please ensure that the constant, MACREPOROOT, is properly defined in localize.py and is not set to 'None'")
        else:
            self.reporoot = MACREPOROOT
        self.dotmd5 = True
        self.logger.log(LogPriority.DEBUG,
                        "Done initializing MacPkgr class...")
        self.ch = CommandHelper(self.logger)
        self.connection = Connectivity(self.logger)

    def installPackage(self, package):
        '''
        Install a package. Return a bool indicating success or failure.

        :param package: Path to the package past the REPOROOT
        
        IE. package would be: QuickAdd.Stonix.pkg rather than:
            https://jss.lanl.gov/CasperShare/QuickAdd.Stonix.pkg
            \_____________________________/ \________________/
                            |                        |
                        REPOROOT                  package
        
        Where REPOROOT is initialized in the class __init__, and package is
        passed in to this method
        
        This assumes that all packages installed via an instance of this class
        will be retrieved from the same REPOROOT.  If you need to use another
        REPOROOT, please use another instance of this class.

        :returns: success
        :rtype: bool
@author: dwalker, Roy Nielsen
@change: Breen Malmberg - 2/28/2017 - added logic to handle case where
        self.reporoot is undefined; added logging; minor doc string edit

        '''

        success = False

        if not self.reporoot:
            self.logger.log(LogPriority.WARNING, "No MacRepoRoot defined! Unable to determine package URL!")
            return success

        try:

            self.package = package
            #####
            # Create a class variable that houses the whole URL
            if self.reporoot.endswith("/"):
                self.pkgUrl = self.reporoot + self.package
            else:
                self.pkgUrl = self.reporoot + "/" + self.package
            message = "self.pkgUrl: " + str(self.pkgUrl)
            self.logger.log(LogPriority.DEBUG, message)

            if re.search("://", self.pkgUrl):
                if self.connection.isPageAvailable(self.pkgUrl):
                    #####
                    # Download into a temporary directory
                    success = self.downloadPackage()
                    if success:
                        #####
                        # Apple operating systems have a lazy attitude towards
                        # writing to disk - the package doesn't get fully
                        # written to disk until the following method is called.
                        # Otherwise when the downloaded package is further
                        # manipulated, (uncompressed or installed) the
                        # downloaded file is not there.  There may be other
                        # ways to get python to do the filesystem sync...
                        try:
                            self.libc.sync()
                        except:
                            pass
                        #####
                        # Make sure the md5 of the file matches that of the
                        # server
                        if self.checkMd5():
                            #####
                            # unarchive if necessary
                            compressed = [".tar", ".tar.gz", ".tgz",
                                          ".tar.bz", ".tbz", ".zip"]
                            for extension in compressed:
                                if self.tmpLocalPkg.endswith(extension):
                                    self.unArchive()
                                try:
                                    self.libc.sync()
                                except:
                                    pass
                            #####
                            # The unArchive renames self.tmpLocalPkg to the
                            # actual software to install that is inside the
                            # package.
                            #
                            # install - if extension is .app, copy to the
                            #           /Applications folder, otherwise if it
                            #           is a .pkg or .mpkg use the installer
                            #           command
                            if self.tmpLocalPkg.endswith(".app"):
                                success = self.copyInstall()

                            elif self.tmpLocalPkg.endswith(".pkg") or \
                                 self.tmpLocalPkg.endswith(".mpkg"):
                                success = self.installPkg()
            else:
                #####
                # Otherwise the repository is on a mounted filesystem
                self.logger.log(LogPriority.DEBUG, "Looking for a local " +
                                                   "filesystem repo...")
                self.tmpLocalPkg = self.reporoot + self.package

        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
            raise err
        if success:
            try:
                self.libc.sync()
            except:
                pass
        return success

    ###########################################################################

    def getPkgUrl(self):
        '''Setter for the class varialbe pkgUrl
        
        @author: Roy Nielsen


        '''
        return self.pkgUrl

    ###########################################################################

    def setPkgUrl(self, pkgUrl=""):
        '''Setter for the class varialbe pkgUrl
        
        @author: Roy Nielsen

        :param pkgUrl:  (Default value = "")

        '''
        self.pkgUrl = pkgUrl

    ###########################################################################

    def removePackage(self, package="", install_root="/"):
        '''Remove a package domain. Return a bool indicating success or failure.
        Not yet implemented...
        
        Will use pkgutil to determine domain, then delete files in receipt..

        :param string: package : Name of the package to be removed, must be
            recognizable to the underlying package manager.
        :param package:  (Default value = "")
        :param install_root:  (Default value = "/")
        :returns: bool :
        @author: rsn

        '''
        success = False
        self.package = package
        try:
            self.logger.log(LogPriority.DEBUG, "Package: " + str(package))
            domain = None
            domain = self.findDomain(package)
            self.logger.log(LogPriority.DEBUG,
                            "removePackage - Domain: " + domain)
            if domain:
                cmd_one = ["/usr/sbin/pkgutil",
                           "--only-files",
                           "--files",
                           domain]
                cmd_two = ["/usr/sbin/pkgutil",
                           "--only-dirs",
                           "--files",
                           domain]

                #####
                # Use the pkgutil command to get a list of files in the package
                # receipt
                count = 0
                self.ch.executeCommand(cmd_one)
                files2remove = self.ch.getOutputString().split("\n")
                print(("Files to remove: " + str(files2remove)))
                self.logger.log(LogPriority.DEBUG, files2remove)
                if str(self.ch.getReturnCode()) == str(0):
                    for file in files2remove:
                        if file:
                            try:
                                #####
                                # Make sure "/" is prepended to the file as
                                # pkgutil does not report the first "/" in the
                                # file path
                                os.remove(install_root + file)
                                count = count + 1
                            except OSError as err:
                                self.logger.log(LogPriority.DEBUG,
                                                "Error trying to remove: " +
                                                str(file))
                                self.logger.log(LogPriority.DEBUG,
                                                "With Exception: " +
                                                str(err))
                        else:
                            #####
                            # Potentially empty filename in the list, need to
                            # bump the count to match.
                            count = count + 1

                    #####
                    # Directory list will include directories such as /usr
                    # and /usr/local... Sucess is obtained only if all of
                    # the files (not directories) are deleted.
                    if count == len(files2remove):
                        success = True
                    else:
                        self.logger.log(LogPriority.WARNING,
                                        "Count: " + str(count))
                        self.logger.log(LogPriority.WARNING,
                                        "Files removed: " +
                                        str(len(files2remove)))

                    #####
                    # Use the pkgutil command to get a list of directories
                    # in the package receipt
                    self.ch.executeCommand(cmd_two)
                    dirs2remove = self.ch.getOutputString().split("\n")
                    #####
                    # Reverse list as list is generated with parents first
                    # rather than children first.
                    dirs2remove.reverse()
                    self.logger.log(LogPriority.DEBUG, dirs2remove)
                    if str(self.ch.getReturnCode()) == str(0):
                        for dir in dirs2remove:
                            if dir:
                                try:
                                    #####
                                    # Make sure "/" is prepended to the directory
                                    # tree as pkgutil does not report the first "/"
                                    # in the file path
                                    os.rmdir(install_root + dir)
                                    #####
                                    # We don't care if any of the child directories
                                    # still have files, as directories such as
                                    # /usr/bin, /usr/local/bin are reported by
                                    # pkgutil in the directory listing, which is
                                    # why we use os.rmdir rather than shutil.rmtree
                                    # and we don't report on the success or failure
                                    # of removing directories.
                                except OSError as err:
                                    self.logger.log(LogPriority.DEBUG,
                                                    "Error trying to remove: "
                                                    + str(dir))
                                    self.logger.log(LogPriority.DEBUG,
                                                    "With Exception: " +
                                                    str(err))
                                    pass

                        #####
                        # Make the system package database "forget" the package
                        # was installed.
                        cmd_three = ["/usr/sbin/pkgutil", "--forget", domain]
                        self.ch.executeCommand(cmd_three)
                        if re.match("^%s$" %
                                    str(self.ch.getReturnCode()).strip(),
                                    str(0)):
                            success = True
                else:
                    self.logger.log(LogPriority.DEBUG, "Page: \"" +
                                    str(package) + "\" Not found")

        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        if success:
            try:
                self.libc.sync()
            except:
                pass
        print(("Remove Package success: " + str(success)))
        return success

    ###########################################################################

    def checkInstall(self, package):
        '''Check the installation status of a package. Return a bool; True if
        the package is installed.
        
        Use pkgutil to determine if package has been installed or not.

        :param string: package : Name of the package whose installation status
            is to be checked, must be recognizable to the underlying package
            manager.
        :param package: 
        :returns: bool :
        @author: rsn

        '''
        success = False
        self.package = package
        try:
            #####
            # Perform a reverse lookup to get the domain...
            domain = self.findDomain(package)
            self.logger.log(LogPriority.DEBUG, "Domain: " + str(domain))
            if domain:
                success = True
                self.logger.log(LogPriority.DEBUG,
                                "Domain: " + str(domain) + " found")

        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)

        return success

    ###########################################################################

    def checkAvailable(self, package):
        '''Check if a package is available at the "reporoot"

        :param package: 
        :returns: success
        :rtype: bool
@author: Roy Nielsen
@change: Breen Malmberg - 2/28/2017 - added logic to handle case where
        self.reporoot is undefined; added logging; minor doc string edit

        '''

        success = False
        self.package = package

        if not self.reporoot:
            self.logger.log(LogPriority.WARNING, "No MacRepoRoot defined! Unable to determine package URL!")
            return success

        try:

            self.logger.log(LogPriority.DEBUG, "Checking if: " +
                            str(package)) + " is available on the server..."
            self.logger.log(LogPriority.DEBUG, "From repo: " +
                            str(self.reporoot))

            self.pkgUrl = self.reporoot + "/" + package

            # If there network, install, else no network, log
            if self.connection.isPageAvailable(self.pkgUrl):
                self.logger.log(LogPriority.DEBUG, "There is a connection to" +
                                                   " the server...")
                #####
                # Download the file
                self.downloadPackage()

                #####
                # Perform a md5 checksum - if there is a match, return
                # success = True
                if self.checkMd5():
                    success = True
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)

        return success

    ###########################################################################

    def getInstall(self, package):
        return self.installPackage(package)

    ###########################################################################

    def getRemove(self, package):
        return self.removePackage(package)

    ###########################################################################

    def findDomain(self, pkg=""):
        '''Go through the package receipts database to find a package, and return
        a domain.  Apple stores package information in "domain" format, rather
        than a package name format. Accessing the package name means we need to
        look through all the ".plist" files in /var/db/receipts to find the
        package name, then we can return the domain so that can be used for
        package management.
        
        Install package receipts can be found in /var/db/receipts.
        
        A domain is the filename in the receipts database without the ".plist"
        or ".bom".
        
        An example is org.macports.MacPorts

        :param eters: pkg - the name of the install package that we need the
                     domain for.
        :param pkg:  (Default value = "")
        :returns: s: domains - the first domain in a possible list of domains.
        
        @author: Roy Nielsen

        '''
        try:
            self.logger.log(LogPriority.DEBUG, "Looking for: " + str(pkg))
            path = "/var/db/receipts/"
            files = []
            domain = ""
            for name in os.listdir(path):
                if os.path.isfile(os.path.join(path, name)) and \
                   os.path.isfile(os.path.join(path, name)) and \
                   name.endswith(".plist"):
                    files.append(name)

            unwrap = "/usr/bin/plutil -convert xml1 /var/db/receipts/*.plist"
            wrap = "/usr/bin/plutil -convert binary1 /var/db/receipts/*.plist"

            self.ch.executeCommand(unwrap)

            if not re.match("^%s$" % str(self.ch.getReturnCode()), str(0)):
                #####
                # Unwrap command didn't work... return None
                domain = None
            else:
                try:
                    self.libc.sync()
                except:
                    pass
                #####
                # Unwrap command worked, process the receipt plists
                for afile in files:
                    if re.match("^\..+.plist", afile):
                        continue
                    self.logger.log(LogPriority.DEBUG, "afile: " + str(afile))
                    #####
                    # Get the path without the plist file extension.
                    afile_path = os.path.join(path, afile)
                    #####
                    # Make sure we have a valid file on the filesystem
                    if os.path.isfile(afile_path):
                        try:
                            plist = plistlib.readPlist(afile_path)
                        except Exception as err:
                            self.logger.log(LogPriority.DEBUG, "Exception " +
                                                               "trying to use" +
                                                               " plistlib: " +
                                                               str(err))
                            raise err
                        else:
                            if re.match("^%s$" % plist['PackageFileName'],
                                        pkg):
                                #####
                                # Find the first instance of the
                                # PackageFileName without the .plist.
                                domain = ".".join(afile.split(".")[:-1])
                                break
                #####
                # Make the plists binary again...
                self.ch.executeCommand(wrap)

                #####
                # Log the domain...
                self.logger.log(LogPriority.DEBUG, "Domain: " + str(domain))
            print(("findDomain: " + str(domain)))
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)

        return domain

    ###########################################################################

    def downloadPackage(self):
        '''Download the package in the self.package URL to a temporary directory
        created by tempfile.mkdtemp.  Does not checked for a cached file.
        
        @Note: path to downloaded file will be in the self.tmpLocalPkg variable
               for use by other class methods.
        
        @author: Roy Nielsen


        '''
        success = False
        urlfile = None
        try:
            self.tmpDir = ""
            if self.pkgUrl:
                #####
                # Make a temporary directory to download the package
                try:
                    self.tmpDir = tempfile.mkdtemp()
                    self.logger.log(LogPriority.DEBUG, "tmpDir: " +
                                                       str(self.tmpDir))
                except Exception as err:
                    message = "Problem creating temporary directory: " + \
                              str(err)
                    self.logger.log(LogPriority.WARNING, message)
                    raise err
                else:
                    #####
                    # First try to open the URL
                    if self.connection.isPageAvailable(self.pkgUrl):
                        urlfile = urllib.request.urlopen(self.pkgUrl, timeout=10)
                        #####
                        # Get just the package name out of the "package" url
                        urlList = self.pkgUrl.split("/")
                        self.pkgName = urlList[-1]
                        self.tmpLocalPkg = os.path.join(self.tmpDir,
                                                        self.pkgName)
                        try:
                            #####
                            # Next try to open a file for writing the local file
                            f = open(str(self.tmpLocalPkg).strip(), "w")
                        except IOError as err:
                            message = "Error opening file - err: " + str(err)
                            self.logger.log(LogPriority.INFO, message)
                            raise err
                        except Exception as err:
                            message = "Generic exception opening file - err: " + \
                                      str(err)
                            self.logger.log(LogPriority.INFO, message)
                            raise err
                        else:
                            self.logger.log(LogPriority.DEBUG,
                                            "..................")
                            #####
                            # take data out of the url stream and put it in the
                            # file a chunk at a time - more sane for large files
                            chunk = 16 * 1024 * 1024
                            counter = 0
                            while 1:
                                try:
                                    if urlfile:
                                        databytes = urlfile.read(chunk)
                                        if not databytes:
                                            message = "Done reading file: " + \
                                                      self.pkgUrl
                                            self.logger.log(LogPriority.DEBUG,
                                                            message)
                                            break
                                        data = databytes
                                        f.write(data.decode('utf-8', 'replace'))
                                        message = "Read " + str(len(databytes)) + \
                                            " bytes"
                                        self.logger.log(LogPriority.DEBUG,
                                                        message)
                                    else:
                                        raise IOError("What file???")
                                except (OSError or IOError) as err:
                                    #####
                                    # Catch in case we run out of space on the
                                    # local system during the download process
                                    message = "IO error: " + str(err)
                                    self.logger.log(LogPriority.INFO, message)
                                    raise err
                                except SSLError:
                                    # This will catch timeouts. Due to a bug in
                                    # the urlfile object, it will sometimes not
                                    # read, and will need to be recreated. The
                                    # counter ensures that if the error is not
                                    # a simple timeout, it will not get stuck
                                    # in an infinite loop.
                                    counter += 1
                                    if counter > 3:
                                        raise
                                    self.logger.log(LogPriority.DEBUG,
                                                    "Connection timed out. " +
                                                    "Creating new urlfile " +
                                                    "object.")
                                    urlfile = urllib.request.urlopen(self.pkgUrl,
                                                              timeout=10)
                                else:
                                    success = True
                            f.close()
                        urlfile.close()
                    else:
                        message = "Error opening the URL: " + str(self.pkgUrl)
                        self.logger.log(LogPriority.DEBUG, message)
            else:
                message = "Need a valid package url. Can't download nothing..."
                self.logger.log(LogPriority.DEBUG, message)
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.INFO, self.detailedresults)
        return success

    ###########################################################################

    def checkMd5(self):
        '''Validate that the MD5 of the file is the same as the one on the server,
        for consistency's sake, ie we got a good download.
        
        Takes an MD5 of the local file, then appends it to the filename with a
        ".", then does a request and getreqpose and checks for a "200 in the
        response.status field.
        
        .<filename>.<UPPER-md5sum>
        
        Specific to the Casper server for Macs.  If you want to override this
        method for another OS, subclass this class, or rewrite the function.
        
        @author: Roy Nielsen


        '''
        success = False
        try:
            hashSuccess, myhash = self.getDownloadedFileMd5sum()
            if hashSuccess and myhash:
                #####
                # Generate the name of the hash using the generated md5
                hashname = "." + self.package + \
                           "." + str(myhash).upper().strip()

                message = "Hashname: " + str(hashname).strip()
                self.logger.log(LogPriority.DEBUG, message)

                #####
                # Generate a web link to the hash file
                hashUrlList = self.pkgUrl.split("/")
                del hashUrlList[-1]
                hashUrlList.append(str(hashname))
                self.hashUrl = "/".join(hashUrlList)

                self.logger.log(LogPriority.DEBUG, "Page: " + self.hashUrl)

                if self.connection.isPageAvailable(self.hashUrl):
                    success = True
                    message = "Found url: " + str(self.hashUrl)
                else:
                    message = "Did NOT find url: " + str(self.hashUrl)
                self.logger.log(LogPriority, message)
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.INFO, self.detailedresults)

        return success

    ###########################################################################

    def getDownloadedFileMd5sum(self):
        '''Get the md5sum of a file on the local filesystem.  Calculate the data
        in chunks in case of large files.


        :returns: s: retval - the md5sum of the file, or -1 if unsuccessful in
                           getting the md5sum
        
        @author: Roy Nielsen

        '''
        success = False
        try:
            retval = None
            try:
                if os.path.exists(self.tmpLocalPkg):
                    fh = open(self.tmpLocalPkg, 'r')
                else:
                    raise Exception("Cannot open a non-existing file...")
            except Exception as err:
                message = "Cannot open file: " + self.tmpLocalPkg + \
                    " for reading."
                self.logger.log(LogPriority.WARNING, message)
                self.logger.log(LogPriority.WARNING, "Exception : " + str(err))
                success = False
                retval = '0'
            else:
                chunk = 16 * 1024 * 1024
                m = hashlib.md5()
                while True:
                    data = fh.read(chunk).encode('utf-8')
                    if not data:
                        break
                    m.update(data)
                retval = m.hexdigest()

        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.INFO, self.detailedresults)
        else:
            success = True

        return success, str(retval).strip()

    ###########################################################################

    def unArchive(self):
        '''Unarchive tar, tar.gz, tgz, tar.bz, and zip files.  Using tarfile and
        zipfile libraries
        
        @Note: Will look for the first "*.app" or "*.pkg", and use that as the
               self.tmpLocalPkg that the rest of the class will use to try to
               install.  This way the compressed file can be named something
               different than the actual package to install.  This means that
               the compressed package can be named generically and a specified
               version is in the compressed file.
        
               Caution - This means when removing the package means you need to
               know the name of the package inside the compressed file to
               remove the installed file.
        
        @author: Roy Nielsen


        '''
        try:
            retval = 0
            ##############################################
            # Check if the file is a tar file of some sort
            inTarList = False
            tars = ["tar", "tgz", "tar.gz", "tbz", "tar.bz"]
            for extension in tars:
                if filename.endswith(extension):
                    inTarList = True

            if re.match("^\s*$", filename):
                self.logger.log(LogPriority.DEBUG,
                                "Emtpy archive name, cannot uncompress.")
                retval = -1
            elif inTarList:
                import tarfile
                try:
                    #####
                    # Open the tar file to prepare for extraction
                    tar = tarfile.open(filename)
                    try:
                        message = "file: " + filename + ", dest: " + destination
                        self.logger.log(LogPriority.DEBUG, message)
                        #####
                        # Extract the tarball at the "destination" location
                        tar.extractall(destination)
                    except (OSError | IOError) as err:
                        message = "Error extracting archive: " + str(err)
                        self.logger.log(LogPriority.WARNING, message)
                        raise err
                except Exception as err:
                    message = "Error opening archive: " + str(err)
                    self.logger.log(LogPriority.DEBUG, message)
                    raise err
                else:
                    tar.close()
                    retval = 0

            elif filename.endswith("zip"):
                ###############################################
                # Process if it a zip file.
                #
                # partial reference at:
                # http://stackoverflow.com/questions/279945/set-permissions-on-a-compressed-file-in-python
                import zipfile
                #####
                # create a zipfile object, method for python 2.5:
                # http://docs.python.org/release/2.5.2/lib/module-zipfile.html
                # Use this type of method as without it the unzipped
                # permissions aren't what they are supposed to be.
                uzfile = zipfile.ZipFile(filename, "r")
                if zipfile.is_zipfile(filename):
                    #####
                    # if the file is a zipfile
                    #
                    # list the files inside the zipfile
                    # for internal_filename in uzfile.namelist():
                    for ifilename in uzfile.filelist:
                        perm = ((ifilename.external_attr >> 16) & 0o777)
                        internal_filename = ifilename.filename
                        message = "extracting file: " + str(internal_filename)
                        self.logger.log(LogPriority.DEBUG, message)
                        #####
                        # Process directories first
                        if internal_filename.endswith("/"):
                            #####
                            # if a directory is found, create it (zipfile
                            # doesn't)
                            try:
                                os.makedirs(os.path.join(destination,
                                                         internal_filename.strip("/")),
                                            perm)
                            except OSError as err:
                                message = "Error making directory: " + str(err)
                                self.logger.log(LogPriority.DEBUG, message)
                                raise err
                            else:
                                continue
                        #####
                        # Now process if it is not a directoy
                        try:
                            contents = uzfile.read(internal_filename)
                        except RuntimeError as err:
                            #####
                            # Calling read() on a closed ZipFile will raise a
                            # RuntimeError
                            self.logger.log(LogPriority.DEBUG,
                                            ["InstallingHelper.un_archive",
                                             "Called read on a closed ZipFile: "
                                             + str(err)])
                            raise err
                        else:
                            try:
                                #####
                                # using os.open as regular open doesn't give
                                # the ability to set permissions on a file.
                                unzip_file = os.path.join(destination,
                                                          internal_filename)
                                target = os.open(unzip_file,
                                                 os.O_CREAT | os.O_WRONLY,
                                                 perm)
                                try:
                                    #####
                                    # when an exception is thrown in the try block, the
                                    # execution immediately passes to the finally block
                                    # After all the statements in the finally block are
                                    # executed, the exception is raised again and is 
                                    # handled in the except statements if present in
                                    # the next higher layer of the try-except statement
                                    os.write(target, contents)
                                finally:
                                    os.close(target)
                            except OSError as err:
                                message = "Error opening file for writing: " + \
                                          str(err)
                                self.logger.log(LogPriority.WARNING, message)
                                raise err
                    uzfile.close()
                    if not retval < -1:
                        # if there was not an error creating a directory as
                        # part of the unarchive process
                        retval = 0
                else:
                    # Not a zipfile based on the file's "magic number"
                    self.logger.log(LogPriority.DEBUG,
                                    ["InstallingHelper.un_archive",
                                     "file: " + filename +
                                     " is not a zipfile."])
                    retval = -1
            #####
            # Find the first item in the directory that is a .app | .pkg | .mpkg
            # Use that as the self.tmpLocalPkg that the rest of the class will
            # use to try to install.  This way the compressed file can be
            # named something different than the actual package to install.
            # This means that the compressed package can be named generically
            # and a specified version is in the compressed file.
            # Caution - This means when removing the package means you need
            # to know the name of the package inside the compressed file to
            # remove the installed file.
            dirlist = os.listdir(self.tmpDir)
            for myfile in dirlist:
                if re.search(".app", myfile) or \
                   re.search(".pkg", myfile) or \
                   re.search(".mpkg", myfile):
                    self.tmpLocalPkg = self.tmpDir + "/" + str(myfile)
                    break

        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.INFO, self.detailedresults)

        return retval

    ###########################################################################

    def copyInstall(self, dest="/Applications", isdir=True, mode=0o775,
                    owner="root", group="admin"):
        '''Copies a directory tree, or contents of a directory to "dest"
        destination.

        :param dest:  (Default value = "/Applications")
        :param isdir:  (Default value = True)
        :param mode:  (Default value = 0775)
        :param owner:  (Default value = "root")
        :param group:  (Default value = "admin")

        '''
        try:
            if re.match("^\s*$", self.tmpDir):
                self.tmpDir = "."

            src_path = self.tmpDir + "/" + self.pkgName

            self.logger.log(LogPriority.DEBUG, "New src_path: " + src_path)

            if isdir:
                try:
                    shutil.copytree(src_path, dest)
                except Exception as err:
                    message = "Unable to recursively copy dir: " + src_path + \
                              " error: " + str(err)
                    self.logger.log(LogPriority.ERROR, message)
                    raise Exception(message)
                else:
                    success = True
                    #####
                    # try to chmod the directory (not recursively)
                    try:
                        os.chmod(dest, mode)
                    except OSError as err:
                        success = False
                        message = "Unable to change mode: " + str(err)
                        self.logger.log(LogPriority.ERROR, message)
                        raise Exception(message)
                    #####
                    # UID & GID needed to chown the directory
                    uid = 0
                    gid = 80
                    try:
                        uid = pwd.getpwnam(owner)[2]
                    except KeyError as err:
                        success = False
                        message = "Error: " + str(err)
                        self.logger.log(LogPriority.DEBUG, message)
                        raise Exception(message)
                    try:
                        gid = grp.getgrnam(group)[2]
                    except KeyError as err:
                        success = False
                        message = "Error: " + str(err)
                        self.logger.log(LogPriority.DEBUG, message)
                        raise Exception(message)
                    #####
                    # Can only chown if uid & gid are int's
                    if ((type(uid) == type(int())) and
                        (type(gid) == type(int()))):
                        try:
                            os.chown(dest, uid, gid)
                        except OSError as err:
                            success = False
                            message = "Error: " + str(err)
                            self.logger.log(LogPriority.DEBUG, message)
                            raise Exception(message)
            else:
                try:
                    dir_list = os.listdir(src_path)
                except OSError as err:
                    message = "Error listing files from: " + src_path + \
                              " error: " + str(err)
                    self.logger.log(LogPriority.ERROR, message)
                    raise Exception(message)
                else:
                    for myfile in dir_list:
                        try:
                            shutil.copy2(myfile, dest)
                        except Exception as err:
                            message = "Error copying file: " + myfile + \
                                      " error: " + str(err)
                            self.logger.log(LogPriority.DEBUG, message)
                            raise
                        else:
                            success = True
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.INFO, self.detailedresults)

        return success

    ##########################################################################

    def installPkg(self):
        '''This function references generic methods from the InstallingHelper
        class to download an archived .pkg or .mpkg file, check md5sum of
        the file against the md5 on the server, unarchive the file and
        install the package. It will remove the temporary directory that
        the file was downloaded and unarchived to when the install is
        complete.
        
        local vars:
        tmp_dir = the temporary directory that is created for the downloaded
                  file, and to unarchive it into.
        self.sig_match = A variable that tells if the signature of the
                         downloaded file and the server string match.  Set
                         in the download_and_prepare method of the parent
                         class
        pkg_extension = for verifying that the package extension is either
                        ".pkg" or ".mpkg"
        self.package_name = the name of the package to be downloaded, without
                            the archive extension.  Set in the InstallingHelper
                            class.
        
        @author: Roy Nielsen


        '''
        success = False
        try:
            #####
            # Check if it's a pkg or mpkg
            if self.tmpLocalPkg.endswith(".pkg") or \
               self.tmpLocalPkg.endswith(".mpkg"):
                #####
                # set up the install package command string
                cmd = ["/usr/bin/sudo", "/usr/sbin/installer", "-verboseR",
                       "-pkg", self.tmpLocalPkg, "-target", "/"]
                self.ch.executeCommand(cmd)
                self.logger.log(LogPriority.DEBUG,
                                self.ch.getOutputString())
                if self.ch.getReturnCode() == 0:
                    success = True
                    #####
                    # remove the temporary directory where the archive was
                    # downloaded and unarchived.
                    try:
                        shutil.rmtree(self.tmpDir)
                    except Exception as err:
                        self.logger.log(LogPriority.ERROR,
                                        "Exception: " + str(err))
                        raise err
                    else:
                        success = True
            else:
                self.logger.log(LogPriority.ERROR, "Valid package " +
                                "extension not found, cannot install:" +
                                " " + self.tmpLocalPkg)
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            print(err)
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.INFO, self.detailedresults)

        return success
Esempio n. 3
0
class Zypper(object):
    """The template class that provides a framework that must be implemented by
    all platform specific pkgmgr classes.
    
    @author: Derek T Walker
    @change: 2012/08/08 Derek Walker - Original Implementation
    @change: 2014/09/10 dkennel - Added -n option to search command string
    @change: 2014/12/24 Breen Malmberg - fixed a typo in the old search string;
            fixed multiple pep8 violations; changed search strings to be match exact and
            search for installed or available separately
    @change: 2015/08/20 eball - Added getPackageFromFile and self.rpm var
    @change: 2016/08/02 eball - Moved checkInstall return out of else block
    @change: 2017/04/19 Breen Malmberg - refactored multiple methods; cleaned up doc
            strings; added logging; added two methods: Update and checkUpdate;
            removed detailedresults reset in __init__ (this should always be handled
            in the calling rule); replaced detailedresults instances with logging;
            added the flag "--quiet" to the install variable


    """
    def __init__(self, logger):
        self.logger = logger
        self.ch = CommandHelper(self.logger)
        self.zyploc = "/usr/bin/zypper"
        self.install = self.zyploc + " --non-interactive --quiet install "
        self.remove = self.zyploc + " --non-interactive remove "
        self.searchi = self.zyploc + " --non-interactive search --match-exact -i "
        self.searchu = self.zyploc + " --non-interactive search --match-exact -u "
        self.updates = self.zyploc + " lu "
        self.upzypp = self.zyploc + " up "
        self.rpm = "/usr/bin/rpm -q "
        self.pkgtype = "zypper"
        self.pkgerrs = [1, 2, 3, 4, 5, 6]
        self.pkgnotfound = [104]

    def installpackage(self, package):
        """Install a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be installed, must be
                recognizable to the underlying package manager.
        :returns: installed
        :rtype: bool
@author: Derek Walker
@change: Breen Malmberg - 12/24/2014 - fixed method doc string formatting
@change: Breen Malmberg - 10/1/2018 - added check for package manager lock and retry loop

        """

        installed = True
        maxtries = 12
        trynum = 0

        while psRunning("zypper"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to install package due to zypper package manager being in-use by another process."
                )
                installed = False
                return installed
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "zypper package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            self.ch.executeCommand(self.install + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrs:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG,
                                "Package installation because:\n" + errstr)
                installed = False
            elif retcode in self.pkgnotfound:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package installation failed because zypper could not find a package named: "
                    + str(package))
                installed = False

            if installed:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " installed successfully")
            else:
                self.logger.log(LogPriority.DEBUG,
                                "Failed to install package " + str(package))

        except Exception:
            raise
        return installed

    def removepackage(self, package):
        """Remove a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be removed, must be
                recognizable to the underlying package manager.
        :returns: removed
        :rtype: bool
@author: Derek Walker
@change: 12/24/2014 - Breen Malmberg - fixed method doc string formatting;
        fixed an issue with var 'removed' not
        being initialized before it was called

        """

        removed = True
        maxtries = 12
        trynum = 0

        while psRunning("zypper"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to remove package due to zypper package manager being in-use by another process."
                )
                removed = False
                return removed
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "zypper package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            self.ch.executeCommand(self.remove + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrs:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG,
                                "Package removal failed because:\n" + errstr)
                removed = False
            elif retcode in self.pkgnotfound:
                self.logger.log(
                    LogPriority.DEBUG, "No package found matching: " +
                    str(package) + ". Nothing to remove")

            if removed:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " was removed successfully")
            else:
                self.logger.log(LogPriority.DEBUG,
                                "Failed to remove package " + str(package))

        except Exception:
            raise
        return removed

    def checkInstall(self, package):
        """Check the installation status of a package. Return a bool; True if
        the package is installed.

        :param string package: Name of the package whose installation status
            is to be checked, must be recognizable to the underlying package
            manager.
        :param package: 
        :returns: bool
        @author: Derek Walker
        @change: 12/24/2014 - Breen Malmberg - fixed method doc string formatting
        @change: 12/24/2014 - Breen Malmberg - changed var name 'found' to
            'installed'
        @change: 12/24/2014 - Breen Malmberg - now uses correct search syntax
        @change: 12/24/2014 - Breen Malmberg - removed detailedresults update on
            'found but not installed' as this no longer applies to this method

        """

        installed = True
        maxtries = 12
        trynum = 0

        while psRunning("zypper"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to check status of  package due to zypper package manager being in-use by another process."
                )
                installed = False
                return installed
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "zypper package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            self.ch.executeCommand(self.searchi + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrs:
                errstr = self.ch.getErrorString()
                self.logger.log(
                    LogPriority.DEBUG, "Failed to check for package: " +
                    str(package) + " because:\n" + errstr)
                installed = False
            elif retcode in self.pkgnotfound:
                installed = False

            if installed:
                self.logger.log(LogPriority.DEBUG,
                                " Package " + str(package) + " is installed")
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    " Package " + str(package) + " is NOT installed")

        except Exception:
            raise
        return installed

    def checkAvailable(self, package):
        """check if given package is available to install on the current system

        :param package: 
        :returns: bool
        @author: Derek Walker
        @change: 12/24/2014 - Breen Malmberg - added method documentation
        @change: 12/24/2014 - Breen Malmberg - changed var name 'found' to
            'available'
        @change: 12/24/2014 - Breen Malmberg - fixed search syntax and updated search
            variable name
        @change: Breen Malmberg - 5/1/2017 - replaced detailedresults with logging;
                added parameter validation

        """

        available = True
        found = False
        maxtries = 12
        trynum = 0

        while psRunning("zypper"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to check availability of package, due to zypper package manager being in-use by another process."
                )
                available = False
                return available
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "zypper package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            self.ch.executeCommand(self.searchu + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrs:
                errstr = self.ch.getErrorString()
                self.logger.log(
                    LogPriority.DEBUG, "Failed to check if package: " +
                    str(package) + " is available, because:\n" + errstr)
                available = False
            elif retcode in self.pkgnotfound:
                available = False
            else:
                output = self.ch.getOutput()
                for line in output:
                    if re.search(package, line):
                        found = True
                if not found:
                    available = False

            if available:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " is available to install")
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " is NOT available to install")

        except Exception:
            raise
        return available

    def checkUpdate(self, package=""):
        """check for available updates for specified
        package.
        if no package is specified, then check for
        updates to the entire system.

        :param package: string; name of package to check (Default value = "")
        :returns: updatesavail
        :rtype: bool
@author: Breen Malmberg

        """

        # zypper does not have a package-specific list updates mechanism
        # you have to list all updates or nothing

        updatesavail = True

        try:

            if package:
                self.ch.executeCommand(self.updates + " | grep " + package)
            else:
                self.ch.executeCommand(self.updates)

            retcode = self.ch.getReturnCode()
            if retcode in [2, 3, 4, 5, 6]:
                errstr = self.ch.getErrorString()
                self.logger.log(
                    LogPriority.DEBUG,
                    "Failed to check for updates because:\n" + errstr)
                updatesavail = False
            elif retcode in self.pkgnotfound:
                updatesavail = False

            if not updatesavail:
                self.logger.log(LogPriority.DEBUG, "No updates available")
            else:
                self.logger.log(LogPriority.DEBUG, "Updates available")

        except Exception:
            raise
        return updatesavail

    def Update(self, package=""):
        """update a specified package
        if no package name is specified,
        then update all packages on the system

        :param package: string; name of package to update (Default value = "")
        :returns: updated
        :rtype: bool
@author: Breen Malmberg

        """

        updated = True

        try:

            self.ch.executeCommand(self.upzypp + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrs:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG,
                                "Failed to update because:\n" + errstr)
                updated = False
            elif retcode in self.pkgnotfound:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Unable to find package named: " + str(package))
                updated = False

            if updated:
                self.logger.log(LogPriority.DEBUG,
                                "Updates applied successfully")
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to apply updates")

        except Exception:
            raise
        return updated

    def getPackageFromFile(self, filename):
        """Returns the name of the package that provides the given
        filename/path.

        :param filename: 
        :returns: string name of package if found, None otherwise
        @author: Eric Ball

        """

        packagename = ""

        try:

            self.ch.executeCommand(self.rpm + "-f " + filename)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrs:
                errstr = self.ch.getErrorString()
                self.logger.log(
                    LogPriority.DEBUG,
                    "Failed to get package name because:\n" + errstr)
            else:
                outputstr = self.ch.getOutputString()
                packagename = outputstr

        except Exception:
            raise

        return packagename

    def getInstall(self):
        """return the install command string for the zypper pkg manager


        :returns: string
        @author: Derek Walker
        @change: 12/24/2014 - Breen Malmberg - added method documentation

        """

        return self.install

    def getRemove(self):
        """return the uninstall/remove command string for the zypper pkg manager


        :returns: string
        @author: Derek Walker
        @change: 12/24/2014 - Breen Malmberg - added method documentation

        """

        return self.remove
Esempio n. 4
0
class Freebsd(object):
    '''The template class that provides a framework that must be implemented by
    all platform specific pkgmgr classes.
    
    :version:
    @author: Derek T Walker 08-06-2012


    '''

    def __init__(self, logger):
        self.logger = logger
        self.ch = CommandHelper(self.logger)
        self.install = "/usr/sbin/pkg_add -r -f "
        self.remove = "/usr/sbin/pkg_delete "
        self.info = "/usr/sbin/pkg_info "
        self.versioncheck = "/usr/sbin/pkg_version -l < "

###############################################################################
    def installpackage(self, package):
        '''Install a package. Return a bool indicating success or failure.

        :param string: package : Name of the package to be installed, must be
                recognizable to the underlying package manager.
        :param package: 
        :returns: installed
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017 - doc string fixes; refactor
        of method; parameter validation

        '''

        installed = False

        try:

            # parameter validation
            if not package:
                self.logger.log(LogPriority.DEBUG, "Parameter: package was blank!")
                return installed
            if not isinstance(package, str):
                self.logger.log(LogPriority.DEBUG, "Parameter: package needs to be of type string. Got: " + str(type(package)))
                return installed

            self.ch.executeCommand(self.install + package)

            if self.ch.getReturnCode() == 0:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " installed successfully")
                installed = True
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to install package " + str(package))

        except Exception:
            raise
        return installed

###############################################################################
    def removepackage(self, package):
        '''Remove a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be removed, must be
                recognizable to the underlying package manager.
        :returns: removed
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017 - refactor of method; doc string fixes;
        parameter validation

        '''

        removed = True

        try:

            # parameter validation
            if not package:
                self.logger.log(LogPriority.DEBUG, "Parameter: package was blank!")
                return removed
            if not isinstance(package, str):
                self.logger.log(LogPriority.DEBUG, "Parameter: package needs to be of type string. Got: " + str(type(package)))
                return removed

            self.ch.executeCommand(self.remove + package)
            retcode = self.ch.getReturnCode()
            if retcode != 0:
                self.logger.log(LogPriority.DEBUG, "Failed to remove package " + str(package))
                removed = False
            else:
                self.logger.log(LogPriority.DEBUG, "Successfully removed package " + str(package))

        except Exception:
            raise
        return removed

###############################################################################
    def checkInstall(self, package):
        '''Check the installation status of a package. Return a bool; True if
        the package is installed.

        :param package: string; Name of the package whose installation status
                is to be checked, must be recognizable to the underlying package
                manager.
        :returns: installed
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017 - refactor of method; doc
        string fixes; parameter validation

        '''

        installed = False

        try:

            # parameter validation
            if not package:
                self.logger.log(LogPriority.DEBUG, "Parameter: package was blank!")
                return installed
            if not isinstance(package, str):
                self.logger.log(LogPriority.DEBUG, "Parameter: package needs to be of type string. Got: " + str(type(package)))
                return installed

            self.ch.executeCommand(self.info + package)
            retcode = self.ch.getReturnCode()
            if retcode != 0:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT installed")
            else:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is installed")
                installed = True

        except Exception:
            raise
        return installed

    def checkUpdate(self, package=""):
        '''STUB METHOD
        check for updates for the specified package
        if package is not specified, check for all
        package updates
        
        currently unfinished as I have no earthly idea
        how to reliably manage packages on bsd
        (ports? portsmanager? portsmaster? pkg_zzz? pkg?)
        also versioning heavily affects what package manager
        binary(ies) is/are available.

        :param package: string; name of package to check (Default value = "")
        :returns: updatesavail
        :rtype: bool
@author: Breen Malmberg

        '''

        updatesavail = False

        try:

            pass # stub

        except Exception:
            raise
        return updatesavail

    def Update(self, package=""):
        '''STUB METHOD
        update the specified package
        if no package is specified, then update
        all packages on the system
        
        currently unfinished as I have no earthly idea
        how to reliably manage packages on bsd
        (ports? portsmanager? portsmaster? pkg_zzz? pkg?)
        also versioning heavily affects what package manager
        binary(ies) is/are available.

        :param package: string; name of package to update (Default value = "")
        :returns: updated
        :rtype: bool
@author: Breen Malmberg

        '''

        updated = False

        try:

            pass # stub

        except Exception:
            raise
        return updated

    def getPackageFromFile(self, filename):
        '''return a string containing the name of the package
        which provides the specified filename

        :param filename: 
        :returns: packagename
        :rtype: string
@author: Breen Malmberg

        '''

        packagename = ""

        try:

            # parameter validation
            if not filename:
                self.logger.log(LogPriority.DEBUG, "Parameter: filename was blank!")
                return packagename
            if not isinstance(filename, str):
                self.logger.log(LogPriority.DEBUG, "Parameter: filename needs to be of type string. Got: " + str(type(filename)))
                return packagename

            self.ch.executeCommand(self.info + " -W " + filename)
            if self.ch.getReturnCode() == 0:
                packagename = self.ch.getOutputString()
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to get the package for the given filename")

        except Exception:
            raise
        return packagename

###############################################################################
    def getInstall(self):
        return self.install

###############################################################################
    def getRemove(self):
        return self.remove

    def getInfo(self):
        return self.info
class zzzTestRuleDisableOpenSafeSafari(RuleTest):
    
    def setUp(self):
        RuleTest.setUp(self)
        self.rule = DisableOpenSafeSafari(self.config,
                                          self.environ,
                                          self.logdispatch,
                                          self.statechglogger)
        self.rulename = self.rule.rulename
        self.rulenumber = self.rule.rulenumber
        self.ch = CommandHelper(self.logdispatch)
        self.dc = "/usr/bin/defaults"
        self.path = "com.apple.Safari"
        self.key = "AutoOpenSafeDownloads"
    def tearDown(self):
        pass

    def runTest(self):
        self.simpleRuleTest()

    def setConditionsForRule(self):
        '''
        This makes sure the intial report fails by executing the following
        commands:
        defaults write com.apple.Safari AutoOpenSafeDownloads -bool yes
        @param self: essential if you override this definition
        @return: boolean - If successful True; If failure False
        @author: dwalker
        '''
        success = False
        cmd = [self.dc, "write", self.path, self.key, "-bool", "yes"]
        self.logdispatch.log(LogPriority.DEBUG, str(cmd))
        if self.ch.executeCommand(cmd):
            success = self.checkReportForRule(False, True)
        return success
    
    def checkReportForRule(self, pCompliance, pRuleSuccess):
        '''
        To see what happended run these commands:
        defaults read com.apple.Safari AutoOpenSafeDownloads
        @param self: essential if you override this definition
        @return: boolean - If successful True; If failure False
        @author: ekkehard j. koch
        '''
        success = True
        self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + \
                             str(pCompliance) + ".")
        self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \
                             str(pRuleSuccess) + ".")
        cmd = [self.dc, "read", self.path, self.key]
        self.logdispatch.log(LogPriority.DEBUG, str(cmd))
        if self.ch.executeCommand(cmd):
            output = self.ch.getOutputString()
        return success

    def checkFixForRule(self, pRuleSuccess):
        self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \
                             str(pRuleSuccess) + ".")
        success = self.checkReportForRule(True, pRuleSuccess)
        return success

    def checkUndoForRule(self, pRuleSuccess):
        self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \
                             str(pRuleSuccess) + ".")
        success = self.checkReportForRule(False, pRuleSuccess)
        return success
Esempio n. 6
0
class Yum(object):
    """The template class that provides a framework that must be implemented by
    all platform specific pkgmgr classes.

    """

    def __init__(self, logger):
        self.environ = Environment()
        self.logger = logger
        self.ch = CommandHelper(self.logger)
        self.yumloc = "/usr/bin/yum"
        self.install = self.yumloc + " install -y "
        self.remove = self.yumloc + " remove -y "
        self.search = self.yumloc + " list "
        self.checkupdates = self.search + "updates "
        self.listavail = self.search + "available "
        self.listinstalled = self.search + "installed "
        self.updatepkg = self.yumloc + " update -y --obsoletes "
        myos = self.environ.getostype().lower()
        if re.search("red hat.*?release 6", myos) or \
                re.search("^centos$", myos.strip()):
            self.rpmloc = "/bin/rpm"
        else:
            self.rpmloc = "/usr/bin/rpm"
        self.provides = self.rpmloc + " -qf "
        self.query = self.rpmloc + " -qa "

    def installpackage(self, package):
        """Install a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be installed, must be
                recognizable to the underlying package manager.
        :return: installed
        :rtype: bool

        """

        installed = True
        maxtries = 12
        trynum = 0

        while psRunning("yum"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(LogPriority.DEBUG, "Timed out while attempting to install package due to yum package manager being in-use by another process.")
                installed = False
                return installed
            else:
                self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...")
                time.sleep(5)

        try:

            self.ch.executeCommand(self.install + package)
            retcode = self.ch.getReturnCode()

            if retcode != 0:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG, "Yum command failed with: " + str(errstr))
                installed = False

            if installed:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was installed successfully")
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to install package " + str(package))

        except Exception:
            raise
        return installed

    def removepackage(self, package):
        """Remove a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be removed, must be
                recognizable to the underlying package manager.
        :return: removed
        :rtype: bool

        """

        removed = True
        maxtries = 12
        trynum = 0

        while psRunning("yum"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(LogPriority.DEBUG, "Timed out while attempting to remove package, due to yum package manager being in-use by another process.")
                removed = False
                return removed
            else:
                self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...")
                time.sleep(5)

        try:

            self.ch.executeCommand(self.remove + package)
            retcode = self.ch.getReturnCode()
            if retcode != 0:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG, "Yum command failed with: " + str(errstr))
                removed = False

            if removed:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was successfully removed")
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to remove package " + str(package))

        except Exception:
            raise
        return removed

    def checkInstall(self, package):
        """Check the installation status of a package. Return a bool; True if
        the package is installed.

        :param package: string; Name of the package whose installation status
            is to be checked, must be recognizable to the underlying package
            manager.
        :return: found
        :rtype: bool

        """

        installed = True
        maxtries = 12
        trynum = 0
        acceptablecodes = [1,0]

        while psRunning("yum"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check status of package, due to yum package manager being in-use by another process.")
                installed = False
                return installed
            else:
                self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...")
                time.sleep(5)

        try:

            self.ch.executeCommand(self.listinstalled + package)
            retcode = self.ch.getReturnCode()
            if retcode not in acceptablecodes:
                installed = False
                errmsg = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG, "Yum command failed with: " + str(errmsg))
            else:
                outputlines = self.ch.getAllList()
                for line in outputlines:
                    if re.search("No matching Packages", line, re.I):
                        installed = False

            if installed:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is installed")
            else:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT installed")

        except Exception:
            raise
        return installed

    def Update(self, package=""):
        """update specified package if any updates
        are available for it
        if no package is specified, update all
        packages which can be updated on the system

        :param package: string; name of package to update (Default value = "")
        :return: updated
        :rtype: bool

        """

        updated = True

        try:

            try:
                self.ch.executeCommand(self.updatepkg + package)
                retcode = self.ch.getReturnCode()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    updated = False
                    raise repoError('yum', retcode, str(errstr))
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                    updated = False

            if package:
                if updated:
                    self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was successfully updated")
                else:
                    self.logger.log(LogPriority.DEBUG, "No updates were found for package " + str(package))
            else:
                if updated:
                    self.logger.log(LogPriority.DEBUG, "All packages were successfully updated")
                else:
                    self.logger.log(LogPriority.DEBUG, "No updates were found for this system")

        except Exception:
            raise
        return updated

    def checkUpdate(self, package=""):
        """check if there are any updates available for
        specified package
        if no package is specified, check if any updates
        are available for the current system

        :param package: string; name of package to check (Default value = "")
        :return: updatesavail
        :rtype: bool

        """

        updatesavail = False

        try:

            try:
                self.ch.executeCommand(self.checkupdates + package)
                retcode = self.ch.getReturnCode()
                output = self.ch.getOutputString()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    raise repoError('yum', retcode, str(errstr))
                else:
                    if re.search("Updated packages", output, re.IGNORECASE):
                        updatesavail = True
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                else:
                    if re.search("Updated packages", output, re.IGNORECASE):
                        updatesavail = True

            if package:
                if updatesavail:
                    self.logger.log(LogPriority.DEBUG, "Updates are available for package " + str(package))
                else:
                    self.logger.log(LogPriority.DEBUG, "No updates are available for package " + str(package))
            else:
                if updatesavail:
                    self.logger.log(LogPriority.DEBUG, "Updates are available for this system")
                else:
                    self.logger.log(LogPriority.DEBUG, "No updates are available for this system")

        except Exception:
            raise
        return updatesavail

    def checkAvailable(self, package):
        """check if specified package is available to install
        return True if it is
        return False if not

        :param package: string; name of package to check
        :return: available
        :rtype: bool

        """

        available = True
        maxtries = 12
        trynum = 0

        while psRunning("yum"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check availability of package, due to yum package manager being in-use by another process.")
                available = False
                return available
            else:
                self.logger.log(LogPriority.DEBUG, "Yum package manager is in-use by another process. Waiting for it to be freed...")
                time.sleep(5)

        try:

            self.ch.executeCommand(self.listavail + package)
            retcode = self.ch.getReturnCode()
            if retcode in [0,1]:
                output = self.ch.getAllList()
                for line in output:
                    if re.search("No matching Packages", line, re.I):
                        available = False
            else:
                errstr = self.ch.getErrorString()
                available = False
                self.logger.log(LogPriority.DEBUG, errstr)

            if available:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is available to install")
            else:
                self.logger.log(LogPriority.DEBUG, "No package " + str(package) + " was found to install")

        except Exception:
            raise
        return available

    def getPackageFromFile(self, filename):
        """Returns the name of the package that provides the given
        filename/path.

        :param filename: string; The name or path of the file to resolve
        :return: packagename
        :rtype: string

        """

        packagename = ""

        try:

            try:
                self.ch.executeCommand(self.provides + filename)
                retcode = self.ch.getReturnCode()
                outputstr = self.ch.getOutputString()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    raise repoError('yum', retcode, str(errstr))
                else:
                    packagename = outputstr
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))

        except Exception:
            raise
        return packagename

    def getInstall(self):
        return self.install

    def getRemove(self):
        return self.remove
Esempio n. 7
0
class SystemIntegrityProtectionObject():
    '''the SystemIntegrityProtectionObject gets System Integrity Protection(SIP)
    data from the local system
    @author: ekkehard


    '''
    def __init__(self, logdispatcher):
        '''
        initialize lanlMacInfo
        @author: ekkehard
        '''
        # Make sure we have the full path for all commands
        self.logdispatch = logdispatcher
        self.ch = CommandHelper(self.logdispatch)
        self.csrutil = "/usr/bin/csrutil"
        self.sw_vers = "/usr/bin/sw_vers"
        self.osx_major_version = 0
        self.osx_minor_version = 0
        self.osx_version_string = ""
        self.initializeOSXVersionBoolean = False
        self.initializeSIPStatusBoolean = False
        self.sipstatus = ""
        # Reset messages
        self.messageReset()

    def getSIPStatus(self):
        '''get the current System Integrity Protection (SIP) status
        @author: ekkehard


        :returns: dictionary entry

        '''
        osx_version = self.initializeOSXVersion()
        sipstatus = self.initializeSIPStatus()
        msg = "SIP status is " + str(
            sipstatus) + ". OS X Version string is " + str(osx_version) + "."
        self.logdispatch.log(LogPriority.DEBUG, msg)
        return self.sipstatus

    def initializeOSXVersion(self, forceInitializtion=False):
        '''initialize OS X version info
        @author: ekkehard

        :param forceInitializtion:  (Default value = False)
        :returns: boolean - True

        '''
        success = True
        if forceInitializtion:
            self.initializeOSXVersionBoolean = False
        if not self.initializeOSXVersionBoolean:
            try:
                self.initializeOSXVersionBoolean = True
                # Get the major version of OS X
                command = self.sw_vers + " -productVersion | awk -F. '{print $1}'"
                self.ch.executeCommand(command)
                errorcode = self.ch.getError()
                osxmajorversion = self.ch.getOutputString().strip()
                self.osx_major_version = int(osxmajorversion)
                msg = "(" + str(errorcode) + ") OS X Major Version is " + str(
                    self.osx_major_version)
                self.logdispatch.log(LogPriority.DEBUG, msg)
                # Get the minor version of OS X
                command = self.sw_vers + " -productVersion | awk -F. '{print $2}'"
                self.ch.executeCommand(command)
                errorcode = self.ch.getError()
                osxminorversion = self.ch.getOutputString().strip()
                self.osx_minor_version = int(osxminorversion)
                msg = "(" + str(errorcode) + ") OS X Minor Version is " + str(
                    self.osx_minor_version)
                self.logdispatch.log(LogPriority.DEBUG, msg)
                # Get full version string
                command = self.sw_vers + " -productVersion"
                self.ch.executeCommand(command)
                errorcode = self.ch.getError()
                self.osx_version_string = self.ch.getOutputString().strip()
                self.osx_minor_version = int(osxminorversion)
                msg = "(" + str(errorcode) + ") OS X Version string is " + str(
                    self.osx_minor_version)
                self.logdispatch.log(LogPriority.DEBUG, msg)
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception:
                msg = traceback.format_exc()
                self.logdispatch.log(LogPriority.ERROR, msg)
                success = False
        return success

    def initializeSIPStatus(self, forceInitializtion=False):
        '''Initialize SIP Status
        @author: ekkehard

        :param forceInitializtion:  (Default value = False)
        :returns: boolean - True

        '''
        success = True
        if forceInitializtion:
            self.initializeSIPStatusBoolean = False
        if not self.initializeSIPStatusBoolean:
            try:
                self.initializeSIPStatusBoolean = True
                if self.osx_major_version < 10:
                    self.sipstatus = "Not Applicable"
                elif self.osx_minor_version < 11:
                    command = self.sw_vers + " -productVersion"
                    self.ch.executeCommand(command)
                    errorcode = self.ch.getError()
                    self.sipstatus = "Not Applicable For " + self.osx_version_string
                    msg = "(" + str(errorcode) + ") SIP status is " + str(
                        self.sipstatus)
                    self.logdispatch.log(LogPriority.DEBUG, msg)
                elif os.path.exists(self.csrutil):
                    command = self.csrutil + " status | awk '/status/ {print $5}' | sed 's/\.$//'"
                    self.ch.executeCommand(command)
                    errorcode = self.ch.getError()
                    sipstatus = self.ch.getOutputString().strip()
                    if sipstatus == "disabled":
                        self.sipstatus = "Disabled"
                    elif sipstatus == "enabled":
                        self.sipstatus = "Enabled"
                    else:
                        self.sipstatus = "Not Applicable - " + str(
                            sipstatus) + " not a know status value."
                    msg = "(" + str(errorcode) + ") SIP status is " + str(
                        self.sipstatus)
                    self.logdispatch.log(LogPriority.DEBUG, msg)
                else:
                    self.sipstatus = "Not Applicable - " + str(
                        self.csrutil) + " not available!"
                msg = "The System Ingegrity Protection status is " + str(
                    self.sipstatus)
                self.logdispatch.log(LogPriority.DEBUG, msg)
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception:
                msg = traceback.format_exc()
                self.logdispatch.log(LogPriority.ERROR, msg)
                success = False
        return success

    def report(self):
        '''report if the SIP status is anabled or disabled.

        :param self: essential if you override this definition
        :returns: boolean
        @note: None

        '''
        compliant = True
        sipstatus = self.getSIPStatus()
        if sipstatus == "Disabled":
            compliant = False
            msg = self.messageAppend(
                "- System Ingegrity Protection (SIP) is disabled but should be enabled!"
            )
            self.logdispatch.log(LogPriority.DEBUG, msg)
        elif sipstatus == "Enabled":
            msg = self.messageAppend(
                "- System Ingegrity Protection (SIP) is enabled!")
            self.logdispatch.log(LogPriority.DEBUG, msg)
        else:
            msg = self.messageAppend("- " + str(sipstatus))
            self.logdispatch.log(LogPriority.DEBUG, msg)
        return compliant

    def fix(self):
        fixed = True
        return fixed

    def messageGet(self):
        '''get the formatted message string.
        @author: ekkehard j. koch

        :param self: essential if you override this definition
        :returns: string
        @note: None

        '''
        return self.msg

    def messageAppend(self, pMessage=""):
        '''append and format message to the message string.
        @author: ekkehard j. koch

        :param self: essential if you override this definition
        :param pMessage:  (Default value = "")
        :returns: boolean - true
        @note: None

        '''
        datatype = type(pMessage)
        if datatype == str:
            if not (pMessage == ""):
                msg = pMessage
                if (self.msg == ""):
                    self.msg = msg
                else:
                    self.msg = self.msg + "\n" + \
                    msg
        elif datatype == list:
            if not (pMessage == []):
                for item in pMessage:
                    msg = item
                    if (self.msg == ""):
                        self.msg = msg
                    else:
                        self.msg = self.msg + "\n" + \
                        msg
        else:
            raise TypeError("pMessage with value" + str(pMessage) + \
                            "is of type " + str(datatype) + " not of " + \
                            "type " + str(str) + \
                            " or type " + str(list) + \
                            " as expected!")
        return self.msg

    def messageReset(self):
        '''reset the message string.
        @author: ekkehard j. koch

        :param self: essential if you override this definition
        :returns: boolean - true
        @note: none

        '''
        self.msg = ""
        return self.msg
Esempio n. 8
0
class AptGet(object):
    """Linux specific package manager for distributions that use the apt-get
    command to install packages.
    
    @author: Derek T Walker
    @change: 2012/08/06 Derek Walker - Original Implementation
    @change: 2015/08/20 eball - Added getPackageFromFile
    @change: 2017/04/27 Breen Malmberg - added two methods checkUpdate
            and Update; fixed doc string formatting; removed detailedresults
            reset in init; replaced with --force-yes flag with --assume-yes
            (from the man page for apt-get: Force yes. This is a dangerous
            option that will cause apt-get to continue without prompting
            if it is doing something potentially harmful. It should not
            be used except in very special situations. Using --force-yes
            can potentially destroy your system!)
    @change: 2017/08/16 bgonz12 - Added DEBIAN_FRONTEND=noninteractive env var
            to remove function
    @change: 2017/10/18 Breen Malmberg - changed class var names to be more self-explanatory;
            changed command to check whether there are available packages to use the canonical
            debian/ubuntu method; added calls to repoError exception to determine exact nature
            and cause of any errors with querying or calling repositories on the system (this adds
            logging of the nature and cause(s) as well); changed log messaging to be more consistent
            in style/format; removed calls to validateParam due to concerns about the stability and
            reliability of that method


    """

    def __init__(self, logger):

        self.logger = logger
        self.ch = CommandHelper(self.logger)

        self.aptgetloc = "/usr/bin/apt-get"
        self.aptcacheloc = "/usr/bin/apt-cache"
        self.dpkgloc = "/usr/bin/dpkg"

        self.aptinstall = "DEBIAN_FRONTEND=noninteractive " + self.aptgetloc + " -y --assume-yes install "
        self.aptremove = "DEBIAN_FRONTEND=noninteractive " + self.aptgetloc + " -y remove "

        self.aptchkupdates = self.aptgetloc + " list --upgradeable "
        self.aptupgrade = self.aptgetloc + " -u upgrade --assume-yes "
        self.checkinstalled = "/usr/bin/apt list --installed "
        self.checkavailable = "/usr/bin/apt-cache search --names-only "
        self.findpkgforfilename = "/usr/bin/dpkg -S "
        self.pkgerrors = [1,100]

    def installpackage(self, package):
        """Install a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be installed, must be
                recognizable to the underlying package manager.
        :returns: installed
        :rtype: bool
@author: Derek Walker
@change: Breen Malmberg - 4/27/2017 - fixed doc string formatting;
        method now returns a variable; parameter validation added
        detailedresults replaced with logging
@change: Breen Malmberg - 10/1/2018 - added check for package manager lock and retry loop

        """

        installed = True
        maxtries = 12
        trynum = 0
        pslist = ["apt", "apt-get", "dpkg"]

        if type(package) is bytes:
            package = package.decode('utf-8')

        for ps in pslist:
            while psRunning(ps):
                trynum += 1
                if trynum == maxtries:
                    self.logger.log(LogPriority.DEBUG, "Timed out while attempting to install package, due to Apt package manager being in-use by another process.")
                    installed = False
                    return installed
                else:
                    self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...")
                    time.sleep(5)

        try:

            self.ch.executeCommand(self.aptinstall + package)
            retcode = self.ch.getReturnCode()
            errstr = self.ch.getErrorString()
            # recursive call to this method if package manager is still locked
            if re.search("Could not get lock", errstr, re.I):
                self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...")
                time.sleep(5)
                return self.installpackage(package)
            elif retcode in self.pkgerrors:
                installed = False
                self.logger.log(LogPriority.DEBUG, str(errstr))

            if installed:
                self.logger.log(LogPriority.DEBUG, "Successfully installed package " + str(package))
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to install package " + str(package))

        except Exception:
            raise
        return installed

    def removepackage(self, package):
        """Remove a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be removed, must be
                recognizable to the underlying package manager.
        :returns: removed
        :rtype: bool
@author: Derek T. Walker

        """

        removed = True
        maxtries = 12
        trynum = 0
        pslist = ["apt", "apt-get", "dpkg"]

        if type(package) is bytes:
            package = package.decode('utf-8')

        for ps in pslist:
            while psRunning(ps):
                trynum += 1
                if trynum == maxtries:
                    self.logger.log(LogPriority.DEBUG, "Timed out while attempting to remove package, due to Apt package manager being in-use by another process.")
                    removed = False
                    return removed
                else:
                    self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...")
                    time.sleep(5)

        try:

            self.ch.executeCommand(self.aptremove + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrors:
                errstr = self.ch.getErrorString()
                removed = False
                self.logger.log(LogPriority.DEBUG, str(errstr))

            if removed:
                self.logger.log(LogPriority.DEBUG, "Successfully removed package " + str(package))
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to remove package " + str(package))

        except Exception:
            raise
        return removed

    def checkInstall(self, package):
        """Check the installation status of a package. Return a bool; True if
        the package is installed.

        :param package: 
        :returns: installed
        :rtype: bool
@author: Derek Walker
@change: Breen Malmberg - 4/27/2017 - fixed doc string formatting;
        method now returns a variable; replaced detailedresults with
        logging

        """

        installed = False
        maxtries = 12
        trynum = 0
        pslist = ["apt", "apt-get", "dpkg"]

        if type(package) is bytes:
            package = package.decode('utf-8')

        for ps in pslist:
            while psRunning(ps):
                trynum += 1
                if trynum == maxtries:
                    self.logger.log(LogPriority.DEBUG, "Timed out while attempting to check status of package, due to Apt package manager being in-use by another process.")
                    installed = False
                    return installed
                else:
                    self.logger.log(LogPriority.DEBUG, "Apt package manager is in-use by another process. Waiting for it to be freed...")
                    time.sleep(5)

        try:

            self.ch.executeCommand(self.checkinstalled + package)
            retcode = self.ch.getReturnCode()
            outputstr = self.ch.getOutputString()
            if retcode in self.pkgerrors:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG, str(errstr))

            if re.search(package + ".*installed", outputstr, re.I):
                installed = True

            if not installed:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT installed")
            else:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is installed")

        except Exception:
            raise
        return installed

    def checkAvailable(self, package):
        """check if a given package is available

        :param package: string; Name of package to check
        :returns: found
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/27/2017 - created doc string;
        pulled result logging out of conditional

        """

        found = False
        outputstr = ""
        maxtries = 12
        trynum = 0
        pslist = ["apt", "apt-get", "dpkg"]

        if type(package) is bytes:
            package = package.decode('utf-8')

        for ps in pslist:
            while psRunning(ps):
                trynum += 1
                if trynum == maxtries:
                    self.logger.log(LogPriority.DEBUG,
                                    "Timed out while attempting to check availability of package, due to apt package manager being in-use by another process.")
                    available = False
                    return available
                else:
                    self.logger.log(LogPriority.DEBUG,
                                    "apt package manager is in-use by another process. Waiting for it to be freed...")
                    time.sleep(5)

        try:

            self.ch.executeCommand(self.checkavailable + "^" + package + "$")
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrors:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG, errstr)
            else:
                outputstr = self.ch.getOutputString()
                if re.search("^" + package, outputstr, re.I):
                    found = True

            if found:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is available to install")
            else:
                self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " is NOT available to install")

        except Exception:
            raise
        return found

    def Update(self, package=""):
        """update the specified package if any
        updates are available for it
        if no package is specified, apply
        all available updates for the system

        :param package: string; (OPTIONAL) name of package to update (Default value = "")
        :returns: updated
        :rtype: bool
@author: Breen Malmberg

        """

        updated = True

        try:

            if type(package) is bytes:
                package = package.decode('utf-8')

            self.ch.executeCommand(self.aptupgrade + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrors:
                errstr = self.ch.getErrorString()
                updated = False
                self.logger.log(LogPriority.DEBUG, errstr)

            if package:
                if updated:
                    self.logger.log(LogPriority.DEBUG, "Package " + str(package) + " was updated successfully")
                else:
                    self.logger.log(LogPriority.DEBUG, "Failed to apply updates to package " + str(package))
            else:
                if updated:
                    self.logger.log(LogPriority.DEBUG, "All updates were installed successfully")
                else:
                    self.logger.log(LogPriority.DEBUG, "Failed to apply updates")

        except Exception:
            raise
        return updated

    def checkUpdate(self, package=""):
        """check for updates for specified package
        if no package is specified, then check
        for updates for the entire system

        :param package: string; (OPTIONAL) Name of package to check (Default value = "")
        :returns: updatesavail
        :rtype: bool
@author: Breen Malmberg

        """

        updatesavail = False

        try:

            self.ch.executeCommand(self.aptchkupdates + package)
            retcode = self.ch.getReturnCode()
            if retcode in self.pkgerrors:
                errstr = self.ch.getErrorString()
                self.logger.log(LogPriority.DEBUG, errstr)
            else:
                outputstr = self.ch.getOutputString()
                if re.search("upgradable", outputstr, re.I):
                    updatesavail = True

            if package:
                if updatesavail:
                    self.logger.log(LogPriority.DEBUG, "Updates are available for package " + str(package))
                else:
                    self.logger.log(LogPriority.DEBUG, "No updates are available for package " + str(package))
            else:
                if updatesavail:
                    self.logger.log(LogPriority.DEBUG, "Updates are available for this system")
                else:
                    self.logger.log(LogPriority.DEBUG, "No updates are available for this system")

        except Exception:
            raise
        return updatesavail

    def getPackageFromFile(self, filename):
        """Returns the name of the package that provides the given
        filename/path.

        :param filename: 
        :returns: packagename
        :rtype: string
@author: Eric Ball
@change: Breen Malmberg - 4/17/2017 - fixed doc string formatting;
        method now returns a variable; added param validation

        """

        packagename = ""

        try:

            try:
                self.ch.executeCommand(self.findpkgforfilename + filename)
                retcode = self.ch.getReturnCode()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    raise repoError('apt', retcode, str(errstr))
                if self.ch.getReturnCode() == 0:
                    output = self.ch.getOutputString()
                    packagename = output.split(":")[0]
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                    pass

        except Exception:
            raise
        return packagename

    def getInstall(self):
        return self.aptinstall

    def getRemove(self):
        return self.aptremove
Esempio n. 9
0
class Dnf(object):
    '''The template class that provides a framework that must be implemented by
    all platform specific pkgmgr classes.  Specifically for Fedora
    
    :version:
    @author: Derek T Walker 08-13-2015
    @change: Breen Malmberg - 4/18/2017 - refactor of multiple methods;
            removed detailedresults reset in __init__; added the -q
            (non-interactive) flag to install and remove command var's;
            added a dnf info command var;
            added parameter validation to each method


    '''
    def __init__(self, logger):
        self.logger = logger
        self.ch = CommandHelper(self.logger)
        self.dnfloc = "/usr/bin/dnf"
        self.install = self.dnfloc + " install -yq "
        self.remove = self.dnfloc + " remove -yq "
        self.search = self.dnfloc + " search "
        self.checkinstalled = self.dnfloc + " list --installed "
        self.chavailable = self.dnfloc + " list --available "
        self.checkupdate = self.dnfloc + " check-update "
        self.rpm = "/bin/rpm -qf "
        self.updatepackage = self.dnfloc + " -yq upgrade "
        self.lockfiles = [
            "/var/run/dnf.lock", "/var/run/dnf.pid", "/run/dnf.lock",
            "/run/dnf.pid"
        ]

    def installpackage(self, package):
        '''Install a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be installed, must be
                recognizable to the underlying package manager.
        :returns: installed
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017 - refactored method; added logging; replaced
        detailedresults with logging
@change: Breen Malmberg - 10/1/2018 - added check for package manager lock and retry loop

        '''

        installed = True
        maxtries = 12
        trynum = 0

        while psRunning("dnf"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to install package, due to dnf package manager being in-use by another process."
                )
                installed = False
                return installed
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "dnf package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            try:
                self.ch.executeCommand(self.install + package)
                retcode = self.ch.getReturnCode()
                if retcode != 0:
                    raise repoError('dnf', retcode)
            except repoError as repoerr:
                if not repoerr.success:
                    installed = False

            if installed:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Successfully installed package " + str(package))
            else:
                self.logger.log(LogPriority.DEBUG,
                                "Failed to install package " + str(package))

        except Exception:
            raise
        return installed

    def removepackage(self, package):
        '''Remove a package. Return a bool indicating success or failure.

        :param package: string; Name of the package to be removed, must be
                recognizable to the underlying package manager.
        :returns: removed
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017

        '''

        removed = True
        maxtries = 12
        trynum = 0

        while psRunning("dnf"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to remove package, due to dnf package manager being in-use by another process."
                )
                installed = False
                return installed
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "dnf package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            try:
                self.ch.executeCommand(self.remove + package)
                retcode = self.ch.getReturnCode()
                if retcode != 0:
                    raise repoError('dnf', retcode)
            except repoError as repoerr:
                if not repoerr.success:
                    removed = False

            if removed:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " was successfully removed")
            else:
                self.logger.log(LogPriority.DEBUG,
                                "Failed to remove package " + str(package))

        except Exception:
            raise
        return removed

    def checkInstall(self, package):
        '''Check the installation status of a package. Return a bool; True if
        the package is installed.

        :param package: 
        :returns: installed
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017

        '''

        installed = False
        errstr = ""
        outputstr = ""
        maxtries = 12
        trynum = 0

        while psRunning("dnf"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to check status of package, due to dnf package manager being in-use by another process."
                )
                installed = False
                return installed
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "dnf package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            try:
                # There is no dnf search command which will only return an
                # "installed" result set. Therefore we must parse the output
                # to determine if the package is installed or just available.
                # The below command string will produce stdout with only the
                # installed result set of packages
                self.ch.executeCommand(self.checkinstalled + package +
                                       " | grep -iA 1 installed")
                retcode = self.ch.getReturnCode()
                errstr = self.ch.getErrorString()
                outputstr = self.ch.getOutputString()
                # With this command specifically, in this package manager, we
                # can't count exit code 1 as being an error because the check installed
                # command (with dnf) will return an error (1) exit code if no results are
                # returned, even if there is no error. We also can't use error or output strings
                # to parse because it is possible for this command to also return no output of any
                # kind, in addition to returning a 1 exit code... Therefore we must exempt exit
                # code 1 for this command specifically...
                if retcode != 0 | 1:
                    raise repoError('dnf', retcode, str(errstr))
                else:
                    if re.search(package, outputstr, re.IGNORECASE):
                        installed = True
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                    installed = False
                else:
                    if re.search(package, outputstr, re.IGNORECASE):
                        installed = True

            if installed:
                self.logger.log(LogPriority.DEBUG,
                                "Package " + str(package) + " is installed")
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " is NOT installed")

        except Exception:
            raise
        return installed

    def checkAvailable(self, package):
        '''check if the given package is available to install

        :param package: string; name of package to check for
        :returns: found
        :rtype: bool
@author: Derek T. Walker
@change: Breen Malmberg - 4/18/2017 - added doc string; refactor of method

        '''

        found = False
        maxtries = 12
        trynum = 0

        while psRunning("dnf"):
            trynum += 1
            if trynum == maxtries:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Timed out while attempting to check availability of package, due to dnf package manager being in-use by another process."
                )
                found = False
                return found
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "dnf package manager is in-use by another process. Waiting for it to be freed..."
                )
                time.sleep(5)

        try:

            try:
                self.ch.executeCommand(self.chavailable + package)
                retcode = self.ch.getReturnCode()
                outputstr = self.ch.getOutputString()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    raise repoError('dnf', retcode, str(errstr))
                else:
                    if re.search(package, outputstr, re.IGNORECASE):
                        found = True
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                else:
                    if re.search(package, outputstr, re.IGNORECASE):
                        found = True

            if found:
                self.logger.log(
                    LogPriority.DEBUG,
                    "Package " + str(package) + " is available to install")
            else:
                self.logger.log(
                    LogPriority.DEBUG,
                    "No package " + str(package) + " available to install")

        except Exception:
            raise
        return found

    def checkUpdate(self, package=""):
        '''check the specified package for updates
        if no package is specified, check for all/any
        updates on the system
        return True if there are updates available
        return False if there are no updates available

        :param package: string; name of package to check (Default value = "")
        :returns: updatesavail
        :rtype: bool
@author: Breen Malmberg

        '''

        updatesavail = False

        try:

            try:
                self.ch.executeCommand(self.checkupdate + package)
                retcode = self.ch.getReturnCode()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    raise repoError('dnf', retcode)
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                    return False
                else:
                    updatesavail = True

            if package:
                if updatesavail:
                    self.logger.log(LogPriority.DEBUG, "Updates are available")
                else:
                    self.logger.log(LogPriority.DEBUG,
                                    "No updates are available")
            else:
                if updatesavail:
                    self.logger.log(
                        LogPriority.DEBUG,
                        "Updates are available for package " + str(package))
                else:
                    self.logger.log(
                        LogPriority.DEBUG,
                        "No updates are available for package " + str(package))

        except Exception:
            raise
        return updatesavail

    def Update(self, package=""):
        '''update the specified package
        if no package is specified, update
        all packages on the system

        :param package: string; name of package to update (Default value = "")
        :returns: updated
        :rtype: bool
@author: Breen Malmberg

        '''

        updated = True

        try:

            try:
                self.ch.executeCommand(self.updatepackage + package)
                retcode = self.ch.getReturnCode()
                errstr = self.ch.getErrorString()
                if retcode != 0:
                    raise repoError('dnf', retcode)
                else:
                    updated = True
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                    return False
                else:
                    updated = True

            if package:
                if updated:
                    self.logger.log(
                        LogPriority.DEBUG,
                        "Package " + str(package) + " successfully updated")
                else:
                    self.logger.log(
                        LogPriority.DEBUG,
                        "Package " + str(package) + " was NOT updated")
            else:
                if updated:
                    self.logger.log(LogPriority.DEBUG,
                                    "All packages updated successfully")
                else:
                    self.logger.log(
                        LogPriority.DEBUG,
                        "One or more packages failed to update properly")

        except Exception:
            raise
        return updated

    def getPackageFromFile(self, filename):
        '''return a string with the name of the parent package
        in it

        :param filename: 
        :returns: packagename
        :rtype: string
@author: Eric Ball
@change: Breen Malmberg - 4/18/2017 - fixed doc string; refactored method

        '''

        packagename = ""

        try:

            try:
                self.ch.executeCommand(self.rpm + filename)
                retcode = self.ch.getReturnCode()
                errstr = self.ch.getErrorString()
                outputstr = self.ch.getOutputString()
                if retcode != 0:
                    raise repoError('dnf', retcode, str(errstr))
                else:
                    packagename = outputstr
            except repoError as repoerr:
                if not repoerr.success:
                    self.logger.log(LogPriority.WARNING, str(errstr))
                else:
                    packagename = outputstr

        except Exception:
            raise
        return packagename

    def getInstall(self):
        return self.install

    def getRemove(self):
        return self.remove

    def getSearch(self):
        return self.search

    def getInfo(self):
        return self.info

    def getCheck(self):
        return self.checkupdate