aboutsummaryrefslogblamecommitdiffstats
path: root/src/lib/sos/policyredhat.py
blob: b5a022033214fabcc5918ba4771ee9433c87f4bd (plain) (tree)


















                                                                        
         
               



                               
             
         
              










                                          




                                       
     


                                                              










                                                            



                                                    



                              
 



                                  






                                                         
                                
                                                      
 
                                
                                                      
 
                                  




                                                                        




                                                                            


                                               
                 









                                                                             
             




                                                                     
 



                                                                                      

                                                       
                     



                                             




                              
            
                                                                                
                                 
                                

                    
 


                                                              





















                                                                                      
                          






                                                                   
 





                                             











                                                                                 

                                                                

                                                           
 

                                               
                                                                                                                  
                                                                               
 





                                                                                                                          
 

                                       







                                                                            
 
              
 





                                                                      
 
                             
 




                                                                       
                                                                                                        
 
                                                                                                    
 
                                                 
 
                           
                                                        
                               
                                                        

                         








































                                                                                                                                                                                                                                                          
                                                            
                  





                                                                                                                                 
                  
 
             



                                                                                           
                 
                                                                        
             
 





                                   
 





























































                                                                                              
## policy-redhat.py
## Implement policies required for the sos system support tool

## Copyright (C) Steve Conklin <sconklin@redhat.com>

### This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.

## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.

## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import os
import commands
import sys
import string
from tempfile import gettempdir
from sos.helpers import *
import random
import re
import hashlib
import rpm
import time

sys.path.insert(0, "/usr/share/rhn/")
try:
    from up2date_client import up2dateAuth
    from up2date_client import config
    from rhn import rpclib
except:
    # might fail if non-RHEL
    pass

#class SosError(Exception):
#    def __init__(self, code, message):
#        self.code = code
#        self.message = message
#    
#    def __str__(self):
#        return 'Sos Error %s: %s' % (self.code, self.message)

def memoized(function):
    ''' function decorator to allow caching of return values
    '''
    function.cache={}
    def f(*args):
        try:
            return function.cache[args]
        except KeyError:
            result = function.cache[args] = function(*args)
            return result
    return f

class SosPolicy:
    "This class implements various policies for sos"
    def __init__(self):
        self.report_file = ""
        self.report_md5 = ""
        self.reportName = ""
        self.ticketNumber = ""

    def setCommons(self, commons):
        self.cInfo = commons
        return

    def validatePlugin(self, pluginpath):
        "Validates the plugin as being acceptable to run"
        # return value
        # TODO implement this
        #print "validating %s" % pluginpath
        return True

    def pkgProvides(self, name):
        return self.pkgByName(name).get('providename')

    def pkgRequires(self, name):
        return self.pkgByName(name).get('requirename')

    def allPkgsByName(self, name):
        return self.allPkgs("name", name)

    def allPkgsByNameRegex(self, regex_name):
        reg = re.compile(regex_name)
        return [pkg for pkg in self.allPkgs() if reg.match(pkg['name'])]

    def pkgByName(self, name):
        # TODO: do a full NEVRA compare and return newest version, best arch
        try:
            # lame attempt at locating newest
            return self.allPkgsByName(name)[-1]
        except:
            pass
        return {}

    def allPkgs(self, ds = None, value = None):
        # if possible return the cached values
        try:                   return self._cache_rpm[ "%s-%s" % (ds,value) ]
        except AttributeError: self._cache_rpm = {}
        except KeyError:       pass

        ts = rpm.TransactionSet()
        if ds and value:
            mi = ts.dbMatch(ds, value)
        else:
            mi = ts.dbMatch()

        self._cache_rpm[ "%s-%s" % (ds,value) ] = [pkg for pkg in mi]
        del mi, ts
        return self._cache_rpm[ "%s-%s" % (ds,value) ]

    def runlevelByService(self, name):
        ret = []
        try:
           for tabs in commands.getoutput("/sbin/chkconfig --list %s" % name).split():
              try:
                 (runlevel, onoff) = tabs.split(":", 1)
              except:
                 pass
              else:
                 if onoff == "on":
                    ret.append(int(runlevel))
        except:
           pass
        return ret

    def runlevelDefault(self):
        try:
            reg=self.doRegexFindAll(r"^id:(\d{1}):initdefault:", "/etc/inittab")
            for initlevel in reg:
                return initlevel
        except:
            return 3

    def kernelVersion(self):
        return commands.getoutput("/bin/uname -r").strip("\n")

    def hostName(self):
        return commands.getoutput("/bin/hostname").split(".")[0]

    def rhelVersion(self):
        try:
            pkgname = self.pkgByName("redhat-release")["version"]
            if pkgname[0] == "4":
                return 4
            elif pkgname in [ "5Server", "5Client" ]:
                return 5
        except: pass
        return False

    def rhnUsername(self):
        try:
            cfg = config.initUp2dateConfig()

            return rpclib.xmlrpclib.loads(up2dateAuth.getSystemId())[0][0]['username']
        except:
            # ignore any exception and return an empty username
            return ""

    def isKernelSMP(self):
        if commands.getoutput("/bin/uname -v").split()[1] == "SMP":
            return True
        else:
            return False

    def getArch(self):
        return commands.getoutput("/bin/uname -m").strip()

    def pkgNVRA(self, pkg):
        fields = pkg.split("-")
        version, release, arch = fields[-3:]
        name = "-".join(fields[:-3])
        return (name, version, release, arch)

    def getDstroot(self):
        """Find a temp directory to form the root for our gathered information
           and reports.
        """
        dstroot = "/tmp/%s-%s" % (self.hostName(), time.strftime("%Y%m%d%H%M%S"))
        try:
            os.mkdir(dstroot, 0700)
        except:
            return False
        return dstroot

    def preWork(self):
        # this method will be called before the gathering begins

        localname = self.rhnUsername()
        if len(localname) == 0: localname = self.hostName()

        if not self.cInfo['cmdlineopts'].batch:
            try:
                self.reportName = raw_input(_("Please enter your first initial and last name [%s]: ") % localname)
                self.reportName = re.sub(r"[^a-zA-Z.0-9]", "", self.reportName)

                self.ticketNumber = raw_input(_("Please enter the case number that you are generating this report for: "))
                self.ticketNumber = re.sub(r"[^0-9]", "", self.ticketNumber)
                print
            except:
                print
                sys.exit(0)

        if len(self.reportName) == 0:
            self.reportName = localname
        
        if self.cInfo['cmdlineopts'].customerName:
            self.reportName = self.cInfo['cmdlineopts'].customerName        
            self.reportName = re.sub(r"[^a-zA-Z.0-9]", "", self.reportName)

        if self.cInfo['cmdlineopts'].ticketNumber:
            self.ticketNumber = self.cInfo['cmdlineopts'].ticketNumber
            self.ticketNumber = re.sub(r"[^0-9]", "", self.ticketNumber)

        return

    def renameResults(self, newName):
        newName = os.path.join(gettempdir(), newName)
        if len(self.report_file) and os.path.isfile(self.report_file):
            try:    os.rename(self.report_file, newName)
            except: return False
        self.report_file = newName

    def packageResults(self):

        if len(self.ticketNumber):
            self.reportName = self.reportName + "." + self.ticketNumber
        else:
            self.reportName = self.reportName

        self.renameResults("sosreport-%s-%s.tar.bz2" % (self.reportName, time.strftime("%Y%m%d%H%M%S")))

        tarcmd = "/bin/tar -jcf %s %s" % (self.report_file, os.path.basename(self.cInfo['dstroot']))

        print _("Creating compressed archive...")

        curwd = os.getcwd()
        os.chdir(os.path.dirname(self.cInfo['dstroot']))
        oldmask = os.umask(077)
        status, shout = commands.getstatusoutput(tarcmd)
        os.umask(oldmask)
        os.chdir(curwd)
        return

    def cleanDstroot(self):
        if not os.path.isdir(os.path.join(self.cInfo['dstroot'],"sos_commands")):
            # doesn't look like a dstroot, refusing to clean
            return False
        os.system("/bin/rm -rf %s" % self.cInfo['dstroot'])

    def encryptResults(self):
        # make sure a report exists
        if not self.report_file:
           return False

        print _("Encrypting archive...")
        gpgname = self.report_file + ".gpg"

        try:
           keyring = self.cInfo['config'].get("general", "gpg_keyring")
        except:
           keyring = "/usr/share/sos/rhsupport.pub"

        try:
           recipient = self.cInfo['config'].get("general", "gpg_recipient")
        except:
           recipient = "support@redhat.com"

        status, output = commands.getstatusoutput("""/usr/bin/gpg --trust-model always --batch --keyring "%s" --no-default-keyring --compress-level 0 --encrypt --recipient "%s" --output "%s" "%s" """ % (keyring, recipient, gpgname, self.report_file))
        if status == 0:
            os.unlink(self.report_file)
            self.report_file = gpgname
        else:
           print _("There was a problem encrypting your report.")
           sys.exit(1)

    def displayResults(self):
        # make sure a report exists
        if not self.report_file:
           return False

        # calculate md5
        fp = open(self.report_file, "r")
        self.report_md5 = hashlib.md5(fp.read()).hexdigest()
        fp.close()

        self.renameResults("sosreport-%s-%s-%s.tar.bz2" % (self.reportName, time.strftime("%Y%m%d%H%M%S"), self.report_md5[-4:]))

        # store md5 into file
        fp = open(self.report_file + ".md5", "w")
        fp.write(self.report_md5 + "\n")
        fp.close()

        print
        print _("Your sosreport has been generated and saved in:\n  %s") % self.report_file
        print
        if len(self.report_md5):
            print _("The md5sum is: ") + self.report_md5
            print
        print _("Please send this file to your support representative.")
        print

    def uploadResults(self):
        # make sure a report exists
        if not self.report_file:
           return False

        print

        # make sure it's readable
        try:
           fp = open(self.report_file, "r")
        except:
           return False

        # read ftp URL from configuration
        try:
           upload_url = self.cInfo['config'].get("general", "upload_url")
        except:
           upload_url = "ftp://dropbox.redhat.com/incoming"

        from urlparse import urlparse
        url = urlparse(upload_url)

        if url[0] != "ftp":
           print _("Cannot upload to specified URL.")
           return

        # extract username and password from URL, if present
        if url[1].find("@") > 0:
           username, host = url[1].split("@", 1)
           if username.find(":") > 0:
              username, passwd = username.split(":", 1)
           else:
              passwd = None
        else:
           username, passwd, host = None, None, url[1]

        # extract port, if present
        if host.find(":") > 0:
           host, port = host.split(":", 1)
           port = int(port)
        else:
           port = 21

        path = url[2]

        try:
           from ftplib import FTP
           upload_name = os.path.basename(self.report_file)

           ftp = FTP()
           ftp.connect(host, port)
           if username and passwd:
              ftp.login(username, passwd)
           else:
              ftp.login()
           ftp.cwd(path)
           ftp.set_pasv(True)
           ftp.storbinary('STOR %s' % upload_name, fp)
           ftp.quit()
        except:
           print _("There was a problem uploading your report to Red Hat support.")
        else:
           print _("Your report was successfully uploaded to Red Hat's ftp server with name:")
           print "  " + upload_name
           print
           print _("Please communicate this name to your support representative.")
           print

        fp.close()