def __init__(self): cmd.Cmd.__init__(self) confighelper.get_config_helper() self._init_logger() common.ssl_check() common.set_plugin_dict(self._get_plugins()) self._load_plugins(common.get_plugin_dict())
def non_interactive_action(self): try: if len(self.pkgAry) >= 1: print _('The vmlinux debug images from the following packages ' 'will be extracted to: %s') % \ confighelper.get_config_helper().get( option='kern_debug_dir') for pkg in self.pkgAry: print pkg if not self._options['noprompt']: line = raw_input(_('Continue (y/n)? ')) if str(line).strip().lower() != 'y': print _('Canceling') return # Start installing' extpaths = self.yumhelper.extractKernelDebugs(self.pkgAry) for extractedpkg in extpaths: print _('Kernel vmlinux file for %s was ' 'extracted to %s') % (extractedpkg['package'], extractedpkg['path']) else: print _('No packages to install.') # pylint: disable=W0703 except Exception, e: logger.log(logging.WARNING, e)
def non_interactive_action(self): try: if len(self.pkgAry) >= 1: print _( "The vmlinux debug images from the following packages " "will be extracted to: %s" ) % confighelper.get_config_helper().get(option="kern_debug_dir") for pkg in self.pkgAry: print pkg if not self._options["noprompt"]: line = raw_input(_("Continue (y/n)? ")) if str(line).strip().lower() != "y": print _("Canceling") return # Start installing' extpaths = self.yumhelper.extractKernelDebugs(self.pkgAry) for extractedpkg in extpaths: print _("Kernel vmlinux file for %s was " "extracted to %s") % ( extractedpkg["package"], extractedpkg["path"], ) else: print _("No packages to install.") # pylint: disable=W0703 except Exception, e: logger.log(logging.WARNING, e)
def extractKernelDebugs(self, pkgAry): extracted_paths = [] kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') if not os.path.exists(kernelext_dir): err = _('Unable to download kernel debug symbols because the ' 'cache directory, %s, does not exist.') % \ (kernelext_dir) print err logger.log(logging.ERROR, err) raise Exception(err) # Is the destination director writeable? if not os.access(kernelext_dir, os.W_OK): err = \ _('Unable to download kernel debug symbols because the ' 'cache directory, %s, is not writeable.') % \ (kernelext_dir) print err logger.log(logging.ERROR, str) raise Exception(err) for pkgobj in pkgAry: ret = self._extractKernelDebug(pkgobj, kernelext_dir) if ret: if hasattr(pkgobj, 'nvr'): pkgnvr = pkgobj.nvr else: pkgnvr = "%s-%s-%s" % (pkgobj.name, pkgobj.version, pkgobj.release) extracted_paths.append({'package': pkgnvr, 'path': ret}) return extracted_paths
def config_set_proxy_user(cls, user, global_config=False): cfg = confighelper.get_config_helper() cfg.set(section='RHHelp', option='proxy_user', value=user, persist=True, global_config=global_config)
def ssl_check(): '''Check SSL configuration options Will print warnings for various potentially unsafe situations as a means to alert of possible Man-in-the-Middle vectors, or SSL communication is likely to fail.''' # Import confighelper - we need to know how various bits are configured. cfg = confighelper.get_config_helper() if cfg.get(option='no_verify_ssl'): # Unsafe/Not Recommended. Warn user, suggest loading the CA cert for # the proxy/server msg = _('Warning: no_ssl_verify is enabled in the Red Hat Support Tool' ' configuration, this may allow other servers to intercept' ' communications with Red Hat. If you have a transparent SSL' ' proxy server, you can trust it\'s Certificate Authority' ' using: \'config ssl_ca <filepath>\'') logging.warn(msg) print msg elif (cfg.get(option='ssl_ca') and not os.access(cfg.get(option='ssl_ca'), os.R_OK)): # Customer has configured a path to a CA certificate to trust, but we # can't find or access the Certificate Authority file that we will pass # to the API. It's not a failure, but we should warn, in case they do # use Red Hat APIs msg = _('Warning: Red Hat Support Tool is unable to access the' ' designated Certificate Authority certificate for server' ' verification at %s. Please correct/replace this file,' ' otherwise functionality may be limited.') logging.warn(msg) print msg return
def config_set_kern_debug_dir(cls, kern_debug_dir, global_config=False): cfg = confighelper.get_config_helper() cfg.set(section='RHHelp', option='kern_debug_dir', value=kern_debug_dir, persist=True, global_config=global_config)
def _parse_solutions(self, solAry): ''' Use this for non-interactive display of results. ''' try: for val in solAry: # doc is displayed in non-interactive mode doc = u'' doc += '%-8s %-60s\n' % ('%s:' % Constants.TITLE, val.get_title()) if self._options['summary']: summary = val.get_abstract() if summary: summary = " ".join(summary.replace('\n', ' ').split()) doc += '%-8s %-60s\n' % (Constants.CASE_SUMMARY, summary) doc += '%-8s %-60s\n' % (Constants.ID, val.get_id()) kcsState = val.get_kcsState()[0:3].upper() kcsStateExplanation = self.state_explanations.get(kcsState, '') doc += _('State: %s\n' % (kcsStateExplanation)) vuri = val.get_view_uri() if(vuri): doc += '%-8s %-60s' % (Constants.URL, vuri) else: doc += '%-8s %-60s' % (Constants.URL, re.sub("api\.|/rs", "", val.get_uri())) doc += '\n\n%s%s%s\n\n' % (Constants.BOLD, str('-' * Constants.MAX_RULE), Constants.END) # disp_opt_text is displayed in interactive mode if confighelper.get_config_helper().get(option='ponies'): published_state = val.get_ModerationState()[0].upper() disp_opt_text = '[%7s:%s:%s] %s' % (val.get_id(), kcsState, published_state, val.get_title()) else: disp_opt_text = '[%7s:%s] %s' % (val.get_id(), kcsState, val.get_title()) # TODO: nicely display the summary within disp_opt_text if self._options['summary']: disp_opt_text += ' *** %s %s' % (Constants.CASE_SUMMARY, summary) disp_opt = ObjectDisplayOption(disp_opt_text, 'interactive_action', val.get_id()) self._submenu_opts.append(disp_opt) self._sections[disp_opt] = doc # pylint: disable=W0702 except: msg = _('ERROR: problem parsing the solutions.') print msg logger.log(logging.WARNING, msg) return False if(disp_opt): return True return False
def config_set_url(cls, url, global_config=False): cfg = confighelper.get_config_helper() cfg.set(section='RHHelp', option='url', value=url, persist=True, global_config=global_config)
def setup_debug_repos(self, repos_to_enable='*debug*', repos_to_disable='*'): debug_repos = confighelper.get_config_helper().get( option='debug_repos') if debug_repos: repos_to_enable = debug_repos self.setup_repos(repos_to_enable, repos_to_disable)
def _parse_solutions(self, solAry): ''' Use this for non-interactive display of results. ''' try: for val in solAry: # doc is displayed in non-interactive mode doc = u'' doc += '%-8s %-60s\n' % ('%s:' % Constants.TITLE, val.get_title()) if self._options['summary']: summary = val.get_abstract() if summary: summary = " ".join(summary.replace('\n', ' ').split()) doc += '%-8s %-60s\n' % (Constants.CASE_SUMMARY, summary) doc += '%-8s %-60s\n' % (Constants.ID, val.get_id()) kcsState = val.get_kcsState()[0:3].upper() kcsStateExplanation = self.state_explanations.get(kcsState, '') doc += _('State: %s\n' % (kcsStateExplanation)) vuri = val.get_view_uri() if (vuri): doc += '%-8s %-60s' % (Constants.URL, vuri) else: doc += '%-8s %-60s' % ( Constants.URL, re.sub("api\.|/rs", "", val.get_uri())) doc += '\n\n%s%s%s\n\n' % (Constants.BOLD, str('-' * Constants.MAX_RULE), Constants.END) # disp_opt_text is displayed in interactive mode if confighelper.get_config_helper().get(option='ponies'): published_state = val.get_ModerationState()[0].upper() disp_opt_text = '[%7s:%s:%s] %s' % (val.get_id(), kcsState, published_state, val.get_title()) else: disp_opt_text = '[%7s:%s] %s' % (val.get_id(), kcsState, val.get_title()) # TODO: nicely display the summary within disp_opt_text if self._options['summary']: disp_opt_text += ' *** %s %s' % (Constants.CASE_SUMMARY, summary) disp_opt = ObjectDisplayOption(disp_opt_text, 'interactive_action', val.get_id()) self._submenu_opts.append(disp_opt) self._sections[disp_opt] = doc # pylint: disable=W0702 except: msg = _('ERROR: problem parsing the solutions.') print msg logger.log(logging.WARNING, msg) return False if (disp_opt): return True return False
def get_options(cls): ''' Subclasses that need command line options should override this method and return an array of optparse.Option(s) to be used by the OptionParser. Example: return [Option("-f", "--file", action="store", dest="filename", help='Some file'), Option("-c", "--case", action="store", dest="casenumber", help='A case')] Would produce the following: Command (? for help): help mycommand Usage: mycommand [options] Use the 'mycommand' command to find a knowledge base solution by ID Options: -h, --help show this help message and exit -f, --file Some file -c, --case A case Example: - mycommand -c 12345 -f abc.txt ''' def public_opt_callback(option, opt_str, value, parser): ''' Callback function for the public option that converts the string into an equivalent boolean value ''' ret = common.str_to_bool(value) if ret is None: msg = _("ERROR: Unexpected argument to %s: %s\nValid values" " are true or false (default: %s true)" % (opt_str, value, opt_str)) print msg raise Exception(msg) else: parser.values.public = ret public_opt_help = SUPPRESS_HELP if confighelper.get_config_helper().get(option='ponies'): public_opt_help = \ _('True or False. Use this to toggle a public or private comment' ' (default=True). Example: -p false') return [Option("-c", "--casenumber", dest="casenumber", help=_('The case number from which the comment ' 'should be added. (required)'), default=False), Option("-p", "--public", dest="public", help=public_opt_help, type='string', action='callback', callback=public_opt_callback)]
def config_set_ssl_ca(cls, ssl_ca, global_config=False): cfg = confighelper.get_config_helper() if not os.access(ssl_ca, os.R_OK): msg = _('Unable to read certificate at %s') % (ssl_ca) print msg raise Exception(msg) cfg.set(section='RHHelp', option='ssl_ca', value=ssl_ca, persist=True, global_config=global_config)
def config_set_debug(cls, debug, global_config=False): if debug in logging._levelNames: cfg = confighelper.get_config_helper() cfg.set(section='RHHelp', option='debug', value=debug, persist=True, global_config=global_config) else: raise EmptyValueError( _('%s is not a valid logging level.') % debug)
def _check_is_public(self): if confighelper.get_config_helper().get(option='ponies') and \ common.is_interactive(): if self._options['public'] is None: line = raw_input(_('Is this a public attachment ([y]/n)? ')) if str(line).strip().lower() == 'n': self._options['public'] = False else: self._options['public'] = True else: if self._options['public'] is None: self._options['public'] = True
def postinit(self): self._submenu_opts = deque() kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') image_list = list_extracted_vmlinuxes(kernelext_dir) if len(image_list) == 0: msg = _('No vmlinux images were found in %s' % (kernelext_dir)) print msg raise Exception(msg) for pkg in image_list: self._submenu_opts.append(DisplayOption(pkg, 'interactive_action'))
def _delete_vmlinuxes(self, deleteque=None): if not deleteque: raise Exception() failedkernels = [] kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') for kernel in deleteque: kpath = os.path.join(kernelext_dir, kernel.display_text) if kpath != kernelext_dir and os.path.exists(kpath): try: shutil.rmtree(kpath) # pylint: disable=W0702 except: failedkernels.append(kernel.display_text) return failedkernels
def interactive_action(self, display_option=None): pkgname = display_option.display_text kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') doc = u'' if pkgname: vmlinuxpath = os.path.join(kernelext_dir, pkgname, 'vmlinux') if os.path.exists(vmlinuxpath): vmlinux = VMLinux(vmlinuxpath) doc += _('Information for %s\n' % (pkgname)) doc += _(' uname -r string: %s\n' % (vmlinux.get_version())) doc += _(' Location: %s\n' % (vmlinuxpath)) doc += _(' Size: %d bytes' % (os.stat(vmlinuxpath).st_size)) try: print doc.encode("UTF-8", 'replace') # pylint: disable=W0703 except Exception, e: logger.log(logging.WARNING, e) import sys print doc.encode(sys.getdefaultencoding(), 'replace') else: raise Exception()
def _find_debug_symbols(self): ''' At this point self.vmcore had better be non-null. This method will call vmcorehelper's get_debug_symbols which scans the designated debug symbols directory looking for debug symbols which match the given core file. If symbols are found, the VMCore object will be passed a VMLinux object. ''' kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') vmlinux = vmcorehelper.get_debug_symbols( kernelext_dir, self.vmcore.getKernelVersion()) if vmlinux: self.vmcore.setDebugSymbols(vmlinux) else: print _('WARNING: Debug symbols for %s were not found.') % \ self._args[0] line = raw_input(_('Would you like to install kernel-debuginfo-%s ' 'from available debug repositories (y/n)? ') % \ self.vmcore.getKernelVersion()) if str(line).strip().lower() == 'y': print _('Installing kernel-debuginfo-%s') % \ self.vmcore.getKernelVersion() lh = LaunchHelper(GetKernelDebugPackages) lh.run(self.vmcore.getKernelVersion(), pt_exception=True) vmlinux = vmcorehelper.get_debug_symbols( kernelext_dir, self.vmcore.getKernelVersion()) if vmlinux: self.vmcore.setDebugSymbols(vmlinux) else: raise Exception( _('Installation of debug images failed, ' 'cannot proceed with debug session')) else: raise Exception('User elected not to install debug ' 'packages for kernel-debuginfo-%s' % \ self.vmcore.getKernelVersion())
def postinit(self): kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') self._submenu_opts = deque() searchopts = [] kernels = list_extracted_vmlinuxes(kernelext_dir) results = [] if common.is_interactive() and self._line == '': searchopts.append("*") else: searchopts = self._line.split() # itertools.product() would be a good option here, but not supported in # python 2.4 for kernel in kernels: for search in searchopts: if fnmatch(kernel, search): results.append(kernel) # Make the results unique, and process options for option in results: self._submenu_opts.append( DisplayOption(option, 'interactive_action'))
def postinit(self): kernelext_dir = confighelper.get_config_helper().get( option='kern_debug_dir') self._submenu_opts = deque() searchopts = [] kernels = list_extracted_vmlinuxes(kernelext_dir) results = [] if common.is_interactive() and self._line == '': searchopts.append("*") else: searchopts = self._line.split() # itertools.product() would be a good option here, but not supported in # python 2.4 for kernel in kernels: for search in searchopts: if fnmatch(kernel, search): results.append(kernel) # Make the results unique, and process options for option in results: self._submenu_opts.append(DisplayOption(option, 'interactive_action'))
def _init_logger(self): pw = pwd.getpwuid(os.getuid()) dotdir = os.path.join(pw.pw_dir, '.redhat-support-tool') logging_folder = os.path.join(dotdir, 'logs') if not os.path.exists(logging_folder): os.makedirs(logging_folder, 0700) logging_file = os.path.join(logging_folder, 'red_hat_support_tool.log') handler = logging.handlers.RotatingFileHandler(logging_file, maxBytes=20000, backupCount=5) handler.setFormatter(logging.Formatter(LOG_FORMAT)) logging.root.addHandler(handler) stat_info = os.stat(logging_file) if (stat_info.st_size > 0): logging.root.handlers[0].doRollover() # Set default level to WARNING logging.root.setLevel(logging.WARNING) logging_level = logging.getLevelName( confighelper.get_config_helper().get(option='debug')) logging.root.setLevel(logging_level) global logger logger = logging.getLogger("redhat-support-tool.rhhelp") logger.setLevel(logging.root.getEffectiveLevel())
def _init_logger(self): pw = pwd.getpwuid(os.getuid()) dotdir = os.path.join(pw.pw_dir, '.redhat-support-tool') logging_folder = os.path.join(dotdir, 'logs') if not os.path.exists(logging_folder): os.makedirs(logging_folder, 0700) logging_file = os.path.join(logging_folder, 'red_hat_support_tool.log') handler = logging.handlers.RotatingFileHandler(logging_file, maxBytes=20000, backupCount=5) handler.setFormatter(logging.Formatter(LOG_FORMAT)) logging.root.addHandler(handler) stat_info = os.stat(logging_file) if(stat_info.st_size > 0): logging.root.handlers[0].doRollover() # Set default level to WARNING logging.root.setLevel(logging.WARNING) logging_level = logging.getLevelName(confighelper.get_config_helper() .get(option='debug')) logging.root.setLevel(logging_level) global logger logger = logging.getLogger("redhat-support-tool.rhhelp") logger.setLevel(logging.root.getEffectiveLevel())
def config_get_kern_debug_dir(cls): cfg = confighelper.get_config_helper() return cfg.get(section='RHHelp', option='kern_debug_dir')
class ListCases(InteractivePlugin): plugin_name = 'listcases' ALL = _("Display all cases") partial_entries = _('%s of %s cases displayed. Type \'m\' to see more.') end_of_entries = _('No more cases to display') _submenu_opts = None _sections = None casesAry = None # Help should not print the option list help_is_options = False # Record the last offset value used with the API, and the maximum results # we should display for one search query. _nextOffset = 0 _MAX_OFFSET = confighelper.get_config_helper().get(option='max_results') _MAX_OFFSET = 1500 if not _MAX_OFFSET else int(_MAX_OFFSET) _limit = 50 if _MAX_OFFSET >= 50 else _MAX_OFFSET _caseGroupNumbers = None # for displaying cases owned by an associate as per SFDC _associateSSOName = None _view = None @classmethod def get_usage(cls): ''' The usage statement that will be printed by OptionParser. Example: - %prog -c CASENUMBER [options] <comment text here> Important: %prog is a OptionParser built-in. Use it! ''' return _('%prog') @classmethod def get_desc(cls): ''' The description statement that will be printed by OptionParser. Example: - 'Use the \'%s\' command to add a comment to a case.'\ % cls.plugin_name ''' return _('Use the \'%s\' command to list your open support cases.\n' '- For Red Hat employees it lists open cases in your queue.\n' '- For other users it lists open cases in your account.\n' % cls.plugin_name) @classmethod def get_epilog(cls): ''' The epilog string that will be printed by OptionParser. Usually used to print an example of how to use the program. Example: Examples: - %s -c 12345678 Lorem ipsum dolor sit amet, consectetur adipisicing - %s -c 12345678 ''' return _('Example:\n' ' - %s\n' ' - %s -g groupname -c -s status -a\n' ' - %s -o ownerSSOName -s severity\n' ' - %s -o all') % (cls.plugin_name, cls.plugin_name, cls.plugin_name, cls.plugin_name) @classmethod def get_options(cls): ''' Subclasses that need command line options should override this method and return an array of optparse.Option(s) to be used by the OptionParser. Example: return [Option("-f", "--file", action="store", dest="filename", help='Some file'), Option("-c", "--case", action="store", dest="casenumber", help='A case')] Would produce the following: Command (? for help): help mycommand Usage: mycommand [options] Use the 'mycommand' command to find a knowledge base solution by ID Options: -h, --help show this help message and exit -f, --file Some file -c, --case A case Example: - mycommand -c 12345 -f abc.txt ''' return [ Option('-c', '--includeclosed', dest='includeclosed', action='store_true', help=_('Show closed cases. (optional)'), default=False), Option('-o', '--owner', dest='owner', help=_('For Red Hat employees only. Show cases ' 'for another Red Hat employee portal login ID.' ' Specify -o ALL to show cases in the Red Hat ' 'account instead of your case queue. (optional)'), default=None), Option('-g', '--casegroup', dest='casegroup', help=_('Show cases belonging to a particular case group' ' in your account. (optional) Note, use the ' '\'listcasegroups\' command to see the case ' 'groups in your account.'), default=None), #Option('-k', '--keyword', dest='keyword', # help=_('Only show cases with the given keyword in ' # 'their title. (optional)'), default=None), Option('-u', '--ungrouped', dest='ungrouped', action='store_true', help=_('Include ungrouped cases in results. When this ' 'is set then -o owner options will be ignored.' '(optional)'), default=False), Option('-s', '--sortby', dest='sortfield', help=_("Sort cases by a particular field. Available " "fields to sort by are: 'caseNumber' (default), " "'createdDate', 'lastModifiedDate', 'severity', " "'status'. (optional)"), default='caseNumber'), Option('-a', '--ascending', dest='sortorder', action='store_const', const='ASC', help=_('Sort results in ascending order. Default is ' 'to sort in descending order (optional)'), default='DESC') ] def _check_case_group(self): if self._options['casegroup']: valid_groups = [] given_groupAry = str(self._options['casegroup']).split(',') real_groupAry = common.get_groups() for i in given_groupAry: match = False for j in real_groupAry: if i.lower() == j.get_name().lower() or \ i == str(j.get_number()): valid_groups.append(j.get_number()) match = True if (not match): msg = _("Unable to find case group %s" % i) print msg raise Exception(msg) if len(valid_groups) > 0: self._caseGroupNumbers = valid_groups logger.log( logging.INFO, 'Casegroup(%s) casegroupnumber(%s)' % (given_groupAry, self._caseGroupNumbers)) def _check_owner(self): # Firstly, determine for whom listcases is being run and if they're a # Red Hat employee (isInternal == True) or not # If they're internal, then display the open cases they *own* in SFDC # ...except however if the -o all, -g or -u options are specified, then # it displays cases in the Red Hat employee's account. # If they're not internal, then display the open cases in their account try: api = apihelper.get_api() username = api.config.username userobj = contextmanager.get('user') if not userobj: userobj = api.users.get(username) contextmanager.add('user', userobj) if self._options['owner']: if not userobj.isInternal: raise Exception( "The -o switch is only available to Red Hat" " employees") elif self._options['owner'].lower() != 'all': username = self._options['owner'] userobj = api.users.get(username) if not userobj.isInternal: # for some reason RH users can't display non-RH users raise Exception("Red Hat employees are unable to list" "cases for non-Red Hat portal users.") if userobj.isInternal: if not (str(self._options['owner']).lower() == 'all' or self._caseGroupNumbers or self._options['ungrouped']): # this will trigger the display of cases owned as per SFDC self._associateSSOName = username self._view = 'internal' except RequestError, re: if re.status == 404: msg = _("Unable to find user %s" % username) else: msg = _('Problem querying the support services API. Reason: ' '%s' % re.reason) print msg logger.log(logging.WARNING, msg) raise except ConnectionError: msg = _('Problem connecting to the support services API. ' 'Is the service accessible from this host?') print msg logger.log(logging.WARNING, msg) raise
def get_options(cls): ''' Subclasses that need command line options should override this method and return an array of optparse.Option(s) to be used by the OptionParser. Example: return [Option("-f", "--file", action="store", dest="filename", help='Some file'), Option("-c", "--case", action="store", dest="casenumber", help='A case')] Would produce the following: Command (? for help): help mycommand Usage: mycommand [options] Use the 'mycommand' command to find a knowledge base solution by ID Options: -h, --help show this help message and exit -f, --file Some file -c, --case A case Example: - mycommand -c 12345 -f abc.txt ''' max_split_size_mb = cls.max_split_size / 1024 / 1024 errmsg1 = _("ERROR: can't use -s/--split and -x/--no-split options " "together") errmsg2 = _("ERROR: -s/--split takes at most one optional argument " "(found %d: %s)") errmsg3 = _("ERROR: the optional argument to -s/--split must be an " "integer between 1 and %d (MB)" % max_split_size_mb) def check_nosplit_callback(option, opt_str, value, parser): ''' Callback function for -x/--no-split option - Report error if the -s/--split option has already been seen ''' if not parser.values.split is None: print errmsg1 raise Exception(errmsg1) parser.values.nosplit = True def set_split_size_callback(option, opt_str, value, parser): ''' Callback function for -s/--split option - Report error if the -x/--no-split option has already been seen The -s/--split option can take 0 or 1 arguments - With 0 args - use the default max_split_size - With 1 arg - the argument sets the split size - With >1 arg - report error ''' if not parser.values.nosplit is None: print errmsg1 raise Exception(errmsg1) assert value is None value = [] def floatable(arg): try: float(arg) return True except ValueError: return False for arg in parser.rargs: # stop on --foo like options if arg[:2] == "--" and len(arg) > 2: break # stop on -a, but not on -3 or -3.0 if arg[:1] == "-" and len(arg) > 1 and not floatable(arg): break value.append(arg) if len(value) == 0: splitsize = max_split_size_mb elif len(value) > 1: print(errmsg2 % (len(value), ' '.join(value))) raise Exception(errmsg2) else: try: splitsize = int(value[0]) except ValueError: print errmsg3 raise Exception(errmsg3) if splitsize > max_split_size_mb or splitsize < 1: print errmsg3 raise Exception(errmsg3) del parser.rargs[:len(value)] parser.values.split = True parser.values.splitsize = splitsize * 1024 * 1024 def public_opt_callback(option, opt_str, value, parser): ''' Callback function for the public option that converts the string into an equivalent boolean value ''' ret = common.str_to_bool(value) if ret is None: msg = _("ERROR: Unexpected argument to %s: %s\nValid values" " are true or false (default: %s true)" % (opt_str, value, opt_str)) print msg raise Exception(msg) else: parser.values.public = ret public_opt_help = SUPPRESS_HELP if confighelper.get_config_helper().get(option='ponies'): public_opt_help = \ _('True or False. Use this to toggle a public or private comment' ' (default=True). Example: -p false') return [ Option("-c", "--casenumber", dest="casenumber", help=_('The case number from which the comment ' 'should be added. (required)'), default=False), Option("-p", "--public", dest="public", help=public_opt_help, type='string', action='callback', callback=public_opt_callback), Option("-d", "--description", dest="description", help=_("A description for the attachment. The \ Red Hat Support Tool will generate a default description for the attachment \ if none is provided that contains the name of the file and the RPM package to \ which it belongs if available. (optional)"), default=False), Option("-x", "--no-split", dest="nosplit", action='callback', callback=check_nosplit_callback, help=_('Do not attempt to split uploaded files, upload ' 'may fail as a result if an alternative ' 'destination is not available.')), Option("-s", "--split", dest="split", action="callback", callback=set_split_size_callback, help=_("The uploaded attachment file will be \ intentionally split. An optional size parameter (in MB) can be supplied and \ the attachment will be split into 'size' (MB) chunks. Default/Maximum chunk \ size: %d (MB)" % max_split_size_mb)), Option("-f", "--use-ftp", dest="useftp", action='store_true', default=False, help=_('Upload via FTP to %s instead of the Red Hat ' 'Customer Portal.' % libconfig.ftp_host)), Option("-z", "--no-compress", dest="nocompress", action='store_true', default=False, help=_("If the attachment file is uncompressed, don't " 'compress it for upload.')) ]
def _make_api(): cfg = confighelper.get_config_helper() logger.log(logging.DEBUG, 'user(%s)' % cfg.get(option='user')) logger.log(logging.DEBUG, 'proxy_url(%s)' % cfg.get(option='proxy_url')) logger.log(logging.DEBUG, 'proxy_user(%s)' % cfg.get(option='proxy_user')) ''' logger.log(logging.DEBUG, 'password(%s)' % cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user'))) logger.log(logging.DEBUG, 'proxy_password(%s)' % cfg.pw_decode( cfg.get(option='proxy_password'), cfg.get(option='proxy_user'))) ''' global _api if not _api: try: url = cfg.get(option='url') user = cfg.get(option='user') passwd = cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user')) # ensure we have a userid if user == None or user == '': user = cfg.prompt_for_user() # ensure we have a password if passwd == None or passwd == '': passwd = cfg.prompt_for_password() if cfg.get(option='no_verify_ssl'): no_verify_ssl = True else: no_verify_ssl = False ssl_ca = cfg.get(option='ssl_ca') if url: _api = API(username=cfg.get(option='user'), password=cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user')), url=url, proxy_url=cfg.get(option='proxy_url'), proxy_user=cfg.get(option='proxy_user'), proxy_pass=cfg.pw_decode(cfg.get(option='proxy_password'), cfg.get(option='proxy_user')), userAgent=USER_AGENT, no_verify_ssl=no_verify_ssl, ssl_ca=ssl_ca) else: _api = API(username=cfg.get(option='user'), password=cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user')), proxy_url=cfg.get(option='proxy_url'), proxy_user=cfg.get(option='proxy_user'), proxy_pass=cfg.pw_decode(cfg.get(option='proxy_password'), cfg.get(option='proxy_user')), userAgent=USER_AGENT, no_verify_ssl=no_verify_ssl, ssl_ca=ssl_ca) except: # Ideally we could just get rid of this try: except: block as it # does absolutely nothing! raise return _api
def config_get_debug(cls): cfg = confighelper.get_config_helper() return cfg.get(section='RHHelp', option='debug')
def config_get_url(cls): cfg = confighelper.get_config_helper() return cfg.get(section='RHHelp', option='url')
class Search(InteractivePlugin): plugin_name = 'search' partial_entries = _('%s of %s solutions displayed. Type \'m\' to' ' see more, \'r\' to start from the beginning' ' again, or \'?\' for help with the codes displayed' ' in the above output.') end_of_entries = _('No more solutions to display') more_entries_maybe = _('More solutions may be available. Type \'m\' to try' ' and find more') state_explanations = { 'WIP': _('Work In Progress: This solution is a Work' ' in Progress.'), 'UNV': _('Unverified: This solution has not yet been' ' verified to work by Red Hat customers.'), 'VER': _('Verified: This solution has been verified' ' to work by Red Hat Customers and Support' ' Engineers for the specified product' ' version(s).') } # Help should not print the option list help_is_options = False _submenu_opts = None _sections = None _solAry = None # Record the last offset value used with the API, and the maximum results # we should display for one search query. _nextOffset = 0 _MAX_OFFSET = confighelper.get_config_helper().get(option='max_results') _MAX_OFFSET = 500 if not _MAX_OFFSET else int(_MAX_OFFSET) _limit = 50 if _MAX_OFFSET >= 50 else _MAX_OFFSET @classmethod def get_usage(cls): ''' The usage statement that will be printed by OptionParser. Example: - %prog -c CASENUMBER [options] <comment text here> Important: %prog is a OptionParser built-in. Use it! ''' return _('%prog [options] <keywords>') @classmethod def get_desc(cls): ''' The description statement that will be printed by OptionParser. Example: - 'Use the \'%s\' command to add a comment to a case.'\ % cls.plugin_name ''' return _('Use the \'%s\' command to search the entire knowledge base ' 'for solutions with given keywords, a log message, program ' 'configuration variables, etc.') % cls.plugin_name @classmethod def get_epilog(cls): ''' The epilog string that will be printed by OptionParser. Usually used to print an example of how to use the program. Example: Examples: - %s -c 12345678 Lorem ipsum dolor sit amet, consectetur adipisicing - %s -c 12345678 ''' return _("""Examples: - %s RHEV - %s -s Starting osa-dispatcher: RHN 9899 Traceback caught""") \ % (cls.plugin_name, cls.plugin_name) @classmethod def get_options(cls): return [ Option("-s", "--summary", dest="summary", default=False, help=_('Display summary information about matched ' 'articles'), action='store_true') ] def validate_args(self): msg = _("ERROR: %s requires text to search.")\ % self.plugin_name if not self._line: if common.is_interactive(): line = raw_input( _('Please provide the text to search (or' ' \'q\' to exit): ')) line = str(line).strip() if line == 'q': raise Exception() if str(line).strip(): self._line = line else: print msg raise Exception(msg) def get_intro_text(self): return _('\nType the number of the solution to view or \'e\' ' 'to return to the previous menu.') def get_prompt_text(self): return _('Select a Solution: ') def get_sub_menu_options(self): return self._submenu_opts def get_more_options(self, num_options): if (len(self._solAry) < self._nextOffset or len(self._solAry) == 0 or self._nextOffset >= self._MAX_OFFSET): # Either we did not max out on results last time, there were # no results last time, or we have seen more than _MAX_OFFSET # results. return False # Strata introduces an issue where if the limit > 50, it will only # return 50 results. This creates a potential issue if the terminal # size is greater than 53. limit = self._get_limit() if num_options > limit: num_options = limit searchopts = {'limit': num_options, 'offset': self._nextOffset} self._nextOffset += num_options newresults = self._get_solutions(searchopts) if len(newresults) == 0: return False self._solAry.extend(newresults) self._parse_solutions(newresults) return True def do_help(self, line): doclines = [ _('Red Hat Support assigns a state with all knowledge' ' solutions, which is displayed in the above output.'), '', _('The current states are:') ] for doc in doclines: print doc for state in self.state_explanations.keys(): print ' %s - %s' % (state, self.state_explanations[state]) common.do_help(self) def postinit(self): self._submenu_opts = deque() self._sections = {} searchopts = {'limit': self._limit, 'offset': 0} self._nextOffset = self._limit self._solAry = self._get_solutions(searchopts) if not self._parse_solutions(self._solAry): msg = _("Unable to find solutions") print msg logger.log(logging.WARNING, msg) raise Exception() if not common.is_interactive(): while self.get_more_options(self._limit): continue def non_interactive_action(self): doc = u'' for opt in self._submenu_opts: doc += self._sections[opt] try: print doc.encode("UTF-8", 'replace') # pylint: disable=W0703 except Exception, e: # There are some truly bizarre errors when you pipe # the output from python's 'print' function with sys encoding # set to ascii. These errors seem to manifes when you pipe # to something like 'more' or 'less'. You'll get encoding # errors. Curiously, you don't see them with 'grep' or even # simply piping to terminal. WTF :( logger.log(logging.WARNING, e) import sys print doc.encode(sys.getdefaultencoding(), 'replace')
def config_get_proxy_user(cls): cfg = confighelper.get_config_helper() return cfg.get(section='RHHelp', option='proxy_user')
def config_set_proxy_password(cls, global_config=False): cfg = confighelper.get_config_helper() cfg.prompt_for_proxy_password(prompt=False, global_config=global_config)
def _make_api(): cfg = confighelper.get_config_helper() logger.log(logging.DEBUG, 'user(%s)' % cfg.get(option='user')) logger.log(logging.DEBUG, 'proxy_url(%s)' % cfg.get(option='proxy_url')) logger.log(logging.DEBUG, 'proxy_user(%s)' % cfg.get(option='proxy_user')) ''' logger.log(logging.DEBUG, 'password(%s)' % cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user'))) logger.log(logging.DEBUG, 'proxy_password(%s)' % cfg.pw_decode( cfg.get(option='proxy_password'), cfg.get(option='proxy_user'))) ''' global _api if not _api: try: url = cfg.get(option='url') user = cfg.get(option='user') passwd = cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user')) # ensure we have a userid if user == None or user == '': user = cfg.prompt_for_user() # ensure we have a password if passwd == None or passwd == '': passwd = cfg.prompt_for_password() if cfg.get(option='no_verify_ssl'): no_verify_ssl = True else: no_verify_ssl = False ssl_ca = cfg.get(option='ssl_ca') if url: _api = API(username=cfg.get(option='user'), password=cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user')), url=url, proxy_url=cfg.get(option='proxy_url'), proxy_user=cfg.get(option='proxy_user'), proxy_pass=cfg.pw_decode( cfg.get(option='proxy_password'), cfg.get(option='proxy_user')), userAgent=USER_AGENT, no_verify_ssl=no_verify_ssl, ssl_ca=ssl_ca) else: _api = API(username=cfg.get(option='user'), password=cfg.pw_decode(cfg.get(option='password'), cfg.get(option='user')), proxy_url=cfg.get(option='proxy_url'), proxy_user=cfg.get(option='proxy_user'), proxy_pass=cfg.pw_decode( cfg.get(option='proxy_password'), cfg.get(option='proxy_user')), userAgent=USER_AGENT, no_verify_ssl=no_verify_ssl, ssl_ca=ssl_ca) except: # Ideally we could just get rid of this try: except: block as it # does absolutely nothing! raise return _api
def get_options(cls): ''' Subclasses that need command line options should override this method and return an array of optparse.Option(s) to be used by the OptionParser. Example: return [Option("-f", "--file", action="store", dest="filename", help='Some file'), Option("-c", "--case", action="store", dest="casenumber", help='A case')] Would produce the following: Command (? for help): help mycommand Usage: mycommand [options] Use the 'mycommand' command to find a knowledge base solution by ID Options: -h, --help show this help message and exit -f, --file Some file -c, --case A case Example: - mycommand -c 12345 -f abc.txt ''' max_split_size_mb = cls.max_split_size / 1024 / 1024 errmsg1 = _("ERROR: can't use -s/--split and -x/--no-split options " "together") errmsg2 = _("ERROR: -s/--split takes at most one optional argument " "(found %d: %s)") errmsg3 = _("ERROR: the optional argument to -s/--split must be an " "integer between 1 and %d (MB)" % max_split_size_mb) def check_nosplit_callback(option, opt_str, value, parser): ''' Callback function for -x/--no-split option - Report error if the -s/--split option has already been seen ''' if not parser.values.split is None: print errmsg1 raise Exception(errmsg1) parser.values.nosplit = True def set_split_size_callback(option, opt_str, value, parser): ''' Callback function for -s/--split option - Report error if the -x/--no-split option has already been seen The -s/--split option can take 0 or 1 arguments - With 0 args - use the default max_split_size - With 1 arg - the argument sets the split size - With >1 arg - report error ''' if not parser.values.nosplit is None: print errmsg1 raise Exception(errmsg1) assert value is None value = [] def floatable(arg): try: float(arg) return True except ValueError: return False for arg in parser.rargs: # stop on --foo like options if arg[:2] == "--" and len(arg) > 2: break # stop on -a, but not on -3 or -3.0 if arg[:1] == "-" and len(arg) > 1 and not floatable(arg): break value.append(arg) if len(value) == 0: splitsize = max_split_size_mb elif len(value) > 1: print (errmsg2 % (len(value), ' '.join(value))) raise Exception(errmsg2) else: try: splitsize = int(value[0]) except ValueError: print errmsg3 raise Exception(errmsg3) if splitsize > max_split_size_mb or splitsize < 1: print errmsg3 raise Exception(errmsg3) del parser.rargs[:len(value)] parser.values.split = True parser.values.splitsize = splitsize * 1024 * 1024 def public_opt_callback(option, opt_str, value, parser): ''' Callback function for the public option that converts the string into an equivalent boolean value ''' ret = common.str_to_bool(value) if ret is None: msg = _("ERROR: Unexpected argument to %s: %s\nValid values" " are true or false (default: %s true)" % (opt_str, value, opt_str)) print msg raise Exception(msg) else: parser.values.public = ret public_opt_help = SUPPRESS_HELP if confighelper.get_config_helper().get(option='ponies'): public_opt_help = \ _('True or False. Use this to toggle a public or private comment' ' (default=True). Example: -p false') return [Option("-c", "--casenumber", dest="casenumber", help=_('The case number from which the comment ' 'should be added. (required)'), default=False), Option("-p", "--public", dest="public", help=public_opt_help, type='string', action='callback', callback=public_opt_callback), Option("-d", "--description", dest="description", help=_("A description for the attachment. The \ Red Hat Support Tool will generate a default description for the attachment \ if none is provided that contains the name of the file and the RPM package to \ which it belongs if available. (optional)"), default=False), Option("-x", "--no-split", dest="nosplit", action='callback', callback=check_nosplit_callback, help=_('Do not attempt to split uploaded files, upload ' 'may fail as a result if an alternative ' 'destination is not available.')), Option("-s", "--split", dest="split", action="callback", callback=set_split_size_callback, help=_("The uploaded attachment file will be \ intentionally split. An optional size parameter (in MB) can be supplied and \ the attachment will be split into 'size' (MB) chunks. Default/Maximum chunk \ size: %d (MB)" % max_split_size_mb)), Option("-f", "--use-ftp", dest="useftp", action='store_true', default=False, help=_('Upload via FTP to %s instead of the Red Hat ' 'Customer Portal.' % libconfig.ftp_host)), Option("-z", "--no-compress", dest="nocompress", action='store_true', default=False, help=_("If the attachment file is uncompressed, don't " 'compress it for upload.'))]
def config_get_ssl_ca(cls): cfg = confighelper.get_config_helper() return cfg.get(section='RHHelp', option='ssl_ca')
def non_interactive_action(self): if self._options['global']: global_config = True else: global_config = False # check for display mode if len(self._args) == 0: # TODO: maybe implement __repr__ on confighelper and print that? # get list of global config options # get list of local config options pass # get / set config option... else: # determine section and option. items = self._args[0].split('.') if len(items) == 1: section = 'RHHelp' option = items[0] else: section = items[0] option = items[1] # get option's owning class if section == 'RHHelp': opt_class = self.__class__ else: opt_class = common.get_plugin_dict()[section] # process command... try: # handle 'unset' command if self._options['unset']: cfg = confighelper.get_config_helper() cfg.remove_option(section, option, global_config) # 'password' is a special case: a one-arg set... elif option == 'password': self.config_set_password(global_config=global_config) # 'proxy_password' is the other special case: a one-arg set... elif option == 'proxy_password': self.config_set_proxy_password(global_config=global_config) # is this a 'set' or a 'get'? # 'gets' have one arg... elif len(self._args) == 1: func = getattr(opt_class, 'config_get_' + option) print func() # ... 'sets' will have two args elif len(self._args) == 2: func = getattr(opt_class, 'config_set_' + option) func(self._args[1], global_config=global_config) except AttributeError: msg = _('ERROR: %s is not a valid configuration file option.')\ % self._args[0] print msg logger.log(logging.WARNING, msg) raise except EmptyValueError, eve: print eve logger.log(logging.WARNING, eve) raise except Exception, e: logger.log(logging.WARNING, e) raise