%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /usr/share/yum-plugins/
Upload File :
Create Path :
Current File : //usr/share/yum-plugins/rhnplugin.py

"""
Yum plugin for RHN access.

This plugin provides access to Spacewalk to yum via up2date modules
and XMLRPC calls.
"""

import os
import sys
import urllib
import locale

from yum.plugins import TYPE_CORE
from yum.yumRepo import YumRepository

import yum.Errors

from urlgrabber.grabber import URLGrabber
from urlgrabber.grabber import URLGrabError
try:
    from urlgrabber.grabber import pycurl
except ImportError:
    pycurl = None

from iniparse import INIConfig

import gettext
t = gettext.translation('yum-rhn-plugin', fallback=True)
_ = t.ugettext

# TODO: Get the up2date stuff that we need in a better place,
# so we don't have to do path magic.
sys.path.append("/usr/share/rhn/")

import up2date_client.up2dateAuth as up2dateAuth
from up2date_client import config
from up2date_client import rhnChannel
from up2date_client import rhnPackageInfo
from up2date_client import up2dateErrors
import rhn.transports

__revision__ = "$Rev$"

requires_api_version = '2.5'
plugin_type = TYPE_CORE
pcklAuthFileName = "/var/spool/up2date/loginAuth.pkl"
cachedRHNReposFile = 'rhnplugin.repos'
versionRHNRepoFile = 'rhnversion'

rhn_enabled = True

COMMUNICATION_ERROR = _("There was an error communicating with CLN.")

from M2Crypto.SSL import SSLError


def get_mirror_url(up2date_cfg):
    if not up2date_cfg['mirrorURL']:
        return 'http://repo.cloudlinux.com/cloudlinux/mirrorlists/cln-mirrors'
    else:
        return up2date_cfg['mirrorURL']


def clnreg():
    os.system('/usr/sbin/clnreg_ks')


def init_hook(conduit):
    """
    Plugin initialization hook. We setup the Spacewlk channels here.

    We get a list of Spacewalk channels from the server, then make a repo object for
    each one. This list of repos is then added to yum's list of repos via the 
    conduit.
    """

    global rhn_enabled

    RHN_DISABLED = _("CLN support will be disabled.")

    conduit_conf = conduit.getConf()
    timeout = conduit.confFloat('main', 'timeout', conduit_conf.timeout)

    if not os.geteuid()==0:
        # If non-root notify user Spacewalk repo not accessible
        conduit.error(0, _("*Note* CloudLinux Network repositories are not listed below. You must run this command as root to access CLN repositories."))
        rhn_enabled = False
        return

    up2date_cfg = config.initUp2dateConfig()
    proxy_dict = {}
    try:
        proxy_url = get_proxy_url(up2date_cfg)
        if proxy_url:
            proxy_url = proxy_url.encode(locale.getpreferredencoding())
            if up2date_cfg['useNoSSLForPackages']:
                proxy_dict = {'http' : proxy_url}
            else:
                proxy_dict = {'https' : proxy_url}
    except BadProxyConfig:
        rhn_enabled = False
        PROXY_ERROR =  _("There was an error parsing the CLN proxy settings.")
        conduit.error(0, PROXY_ERROR + "\n" + RHN_DISABLED)
        return
    # check commands and options which don't need network communication
    prog_name = os.path.basename(sys.argv[0])
    if prog_name == 'yum':
        cmd_args = sys.argv[1:]
        if ('--help' in cmd_args
            or '--version' in cmd_args
            or cmd_args == []):
            rhn_enabled = False
            conduit.info(10, _("Either --version, --help or no commands entered") +
                     "\n" + RHN_DISABLED)
            return
        if 'clean' in cmd_args:
            addCachedRepos(conduit)
            conduit.info(10, _("Cleaning") + "\n" + RHN_DISABLED)
            # cleanup cached login info
            if os.path.exists(pcklAuthFileName):
                os.unlink(pcklAuthFileName)
            return
        if ('-C' in cmd_args
            or '--cacheonly' in cmd_args):
            rhn_enabled = False
            addCachedRepos(conduit)
            conduit.info(10, _("Using list of CLN repos from cache") +
                     "\n" + RHN_DISABLED)
            return
    #
    #
    mirror_url = get_mirror_url(up2date_cfg)
    clnreg_retry = 0
    while clnreg_retry < 2:
        clnreg_retry += 1

        try:
            login_info = up2dateAuth.getLoginInfo(timeout=timeout)
        except up2dateErrors.RhnServerException, e:
            if clnreg_retry == 1:
                clnreg()
                continue
            if hasattr(conduit._base, 'exit_code') and 'check-update' in sys.argv:
                conduit._base.exit_code = 1
            rewordError(e)
            conduit.error(0, COMMUNICATION_ERROR + "\n" + RHN_DISABLED + "\n" +
                unicode(e))
            rhn_enabled = False
            return

        if not login_info:
            if clnreg_retry == 1:
                clnreg()
                continue
            conduit.error(0, _("This system is not registered with CLN.") +
                    "\n" + _("You can use rhn_register to register.") +
                    "\n" + RHN_DISABLED)
            rhn_enabled = False
            truncateRHNReposCache(conduit)
            return

        CHANNELS_DISABLED = _("CLN channel support will be disabled.")
        try:
            svrChannels = rhnChannel.getChannelDetails(timeout=timeout)
        except up2dateErrors.NoChannelsError:
            if clnreg_retry == 1:
                clnreg()
                continue
            conduit.error(0, _("This system is not subscribed to any channels.") +
                "\n" + CHANNELS_DISABLED)
            truncateRHNReposCache(conduit)
            return
        except up2dateErrors.NoSystemIdError:
            if clnreg_retry == 1:
                clnreg()
                continue
            conduit.error(0, _("This system may not be registered to CLN. SystemId could not be acquired.") +
                    "\n" + _("You can use rhn_register to register.") +
                    "\n" + RHN_DISABLED)
            rhn_enabled = False
            return
        except up2dateErrors.RhnServerException, e:
            if clnreg_retry == 1:
                clnreg()
                continue
            if hasattr(conduit._base, 'exit_code') and 'check-update' in sys.argv:
                conduit._base.exit_code = 1
            conduit.error(0, COMMUNICATION_ERROR + "\n" + CHANNELS_DISABLED +
                "\n" + unicode(e))
            return

        if rhn_enabled:
            conduit.info(2, _("This system is receiving updates from CLN."))
            break

    repos = conduit.getRepos()
    cachedir = conduit_conf.cachedir
    sslcacert = get_ssl_ca_cert(up2date_cfg)

    cachefile = openRHNReposCache(conduit)
    for channel in svrChannels:
        if channel['version']:
            repo = RhnRepo(channel, mirror_url, cachedir)
            setRHNRepoDefaults(conduit, repo)
            repo.basecachedir = cachedir
            repo.base_persistdir = cachedir
            repo.proxy = proxy_url
            repo.sslcacert = sslcacert
            repo._proxy_dict = proxy_dict
            if repo.timeout < timeout:
                repo.timeout = timeout
            updateRHNRepoOptions(conduit, repo)
            repos.add(repo)
            if cachefile:
                cachefile.write("%s %s\n" % (repo.id, repo.name))
            if not currentRHNRepoVersion(repo, channel['version']):
                repo._metadataCurrent = False
    if cachefile:
        cachefile.close()

def openRHNReposCache(conduit):
    cachedir = conduit.getConf().cachedir
    cachefilename = os.path.join(cachedir, cachedRHNReposFile)
    try:
        if not os.path.exists(cachedir):
            os.makedirs(cachedir, 0755)
        cachefile = open(cachefilename, 'w')
    except:
        cachefile = None
    return cachefile

def truncateRHNReposCache(conduit):
    cachefile = openRHNReposCache(conduit)
    if cachefile:
        cachefile.truncate()
        cachefile.close()

def addCachedRepos(conduit):
    """
    Add list of repos we've seen last time (from cache file)
    """
    repos = conduit.getRepos()
    cachedir = conduit.getConf().cachedir
    cachefilename = os.path.join(cachedir, cachedRHNReposFile)
    if not os.access(cachefilename, os.R_OK):
        return
    cachefile = open(cachefilename, 'r')
    repolist = [ line.rstrip().split(' ', 1) for line in cachefile.readlines()]
    cachefile.close()
    urls = ["http://dummyvalue"]
    for repo_item in repolist:
        if len(repo_item) == 1:
            repo_item.append('')
        (repoid, reponame) = repo_item
        repodir = os.path.join(cachedir, repoid)
        if os.path.isdir(repodir):
            repo = YumRepository(repoid)
            setRHNRepoDefaults(conduit, repo)
            repo.basecachedir = cachedir
            repo.baseurl = urls
            repo.urls = repo.baseurl
            repo.name = reponame
            updateRHNRepoOptions(conduit, repo)
            repo.enable()
            if not repos.findRepos(repo.id):
                repos.add(repo)

def currentRHNRepoVersion(repo, repoversion):
    cachedir = repo.cachedir
    versionfilename = os.path.join(cachedir, versionRHNRepoFile)
    last_version = None
    versionfile = None
    try:
        if not os.path.exists(cachedir):
            os.makedirs(cachedir, 0755)
        if os.path.exists(versionfilename):
            versionfile = open(versionfilename, 'r+')
            last_version = versionfile.readline().strip('\n')
            versionfile.seek(0,0)
        else:
            versionfile = open(versionfilename, 'w')
        versionfile.write(repoversion + '\n')
        versionfile.close()
    except:
        if versionfile:
            versionfile.close()
    return (last_version == repoversion)

def posttrans_hook(conduit):
    """ Post rpm transaction hook. We update the RHN profile here. """
    global rhn_enabled
    if rhn_enabled:
        timeout = conduit.confFloat('main', 'timeout',
                conduit.getConf().timeout)
        up2date_cfg = config.initUp2dateConfig()
        if up2date_cfg.has_key('writeChangesToLog') and up2date_cfg['writeChangesToLog'] == 1:
            ts_info = conduit.getTsInfo()
            delta = make_package_delta(ts_info)
            rhnPackageInfo.logDeltaPackages(delta)
        if up2dateAuth.getSystemId(): # are we registred?
            try:
                rhnPackageInfo.updatePackageProfile(timeout=timeout)
            except up2dateErrors.RhnServerException, e:
                conduit.error(0, COMMUNICATION_ERROR + "\n" +
                    _("Package profile information could not be sent.") + "\n" + 
                    unicode(e))

def rewordError(e):
    """ This is compensating for hosted/satellite returning back an error
        message instructing RHEL5 clients to run "rhn_register"
        bz: 438175
    """
    replacedText = _("Error Message:") + "\n\t" + \
        _("Please run rhn_register as root on this client")
    index = e.errmsg.find(": 9\n")
    if index == -1:
        return
    if e.errmsg.find("up2date", 0, index) == -1:
        return
    #Find where the "Error Class Code" text begins, to account
    #for different languages, looking for new line character
    #preceeding the Error Class Code
    indexB = e.errmsg.rfind("\n", 0, index)
    e.errmsg = "\n" + replacedText + e.errmsg[indexB:]
                
            

class RhnRepo(YumRepository):

    """
    Repository object for Spacewalk.

    This, along with the RhnPackageSack, adapts up2date for use with
    yum.
    """
    rhn_needed_headers = ['X-RHN-Server-Id',
                          'X-RHN-Auth-User-Id',
                          'X-RHN-Auth',
                          'X-RHN-Auth-Server-Time',
                          'X-RHN-Auth-Expire-Offset']
    
    def __init__(self, channel, mirror_url, cachedir):
        YumRepository.__init__(self, channel['label'])
        self.basecachedir = cachedir
        self.base_persistdir = cachedir
        self.name = channel['name']
        self.label = channel['label']
        self._callbacks_changed = False
        self.mirrorlist = mirror_url

        urls = []
        for url in self.urls:
            urls.append(url + 'GET-REQ/' + self.id)
        self.baseurl = urls
        self.urls = self.baseurl
        self.failovermethod = 'priority'
        self.keepalive = 0
        self.bandwidth = 0
        self.retries = 1
        self.throttle = 0
        self.timeout = 60.0
        self.metadata_expire = 21700

        self.http_caching = True

        self.gpgkey = []
        self.gpgcheck = False
        self.up2date_cfg = config.initUp2dateConfig()
    
        try:
            self.gpgkey = get_gpg_key_urls(channel['gpg_key_url'])
        except InvalidGpgKeyLocation:
            #TODO: Warn about this or log it
            pass

        self.enable()

    def setupRhnHttpHeaders(self):
        """ Set up self.http_headers with needed RHN X-RHN-blah headers """
        
        try:
            li = up2dateAuth.getLoginInfo(timeout=self.timeout)
        except up2dateErrors.RhnServerException, e:
            raise yum.Errors.RepoError(unicode(e)), None, sys.exc_info()[2]
        except Exception, e:
            raise yum.Errors.RepoError(unicode(e)), None, sys.exc_info()[2]

        # TODO:  do evalution on li auth times to see if we need to obtain a
        # new session...

        for header in RhnRepo.rhn_needed_headers:
            if not li.has_key(header):
                error = _("Missing required login information for RHN: %s") \
                    % header
                raise yum.Errors.RepoError(error)
            
            self.http_headers[header] = li[header]
        if not self.up2date_cfg['useNoSSLForPackages']:
            self.http_headers['X-RHN-Transport-Capability'] = "follow-redirects=3"

    # Override the 'private' __get method so we can do our auth stuff.
    def _getFile(self, url=None, relative=None, local=None,
        start=None, end=None, copy_local=0, checkfunc=None, text=None,
        reget='simple', cache=True, size=None, **kwargs):
        for server in self.urls:
            url = server
            try:
                try:
                    return self._noExceptionWrappingGet(url, relative, local,
                        start, end, copy_local, checkfunc, text, reget, cache, size)
                except URLGrabError, e:
                    try:
                        up2dateAuth.updateLoginInfo(timeout=self.timeout,
                                                    mirrorServer=url)
                    except up2dateErrors.RhnServerException, e:
                        raise yum.Errors.RepoError(unicode(e)), None, sys.exc_info()[2]

                    return self._noExceptionWrappingGet(url, relative, local,
                        start, end, copy_local, checkfunc, text, reget, cache, size)

            except URLGrabError, e:
                raise yum.Errors.RepoError, \
                    "failed to retrieve %s from %s\nerror was %s" % (relative,
                    self.id, e), sys.exc_info()[2]
            except SSLError, e:
                raise yum.Errors.RepoError(unicode(e)), None, sys.exc_info()[2]
            except up2dateErrors.InvalidRedirectionError, e:
                raise up2dateErrors.InvalidRedirectionError(e), None, sys.exc_info()[2]
    _YumRepository__get = _getFile

    # This code is copied from yum, we should get the original code to
    # provide more detail in its exception, so we don't have to cut n' paste
    def _noExceptionWrappingGet(self, url=None, relative=None, local=None,
        start=None, end=None, copy_local=0, checkfunc=None, text=None,
        reget='simple', cache=True, size=None):
        """retrieve file from the mirrorgroup for the repo
           relative to local, optionally get range from
           start to end, also optionally retrieve from a specific baseurl"""

        # if local or relative is None: raise an exception b/c that shouldn't happen
        # return the path to the local file

        self.setupRhnHttpHeaders()
        if pycurl:
            # pycurl/libcurl workaround: in libcurl setting an empty HTTP header means
            # remove that header from the list
            # but we have to send and empty X-RHN-Auth-User-Id ...
            AuthUserH = 'X-RHN-Auth-User-Id'
            if (AuthUserH in self.http_headers and not self.http_headers[AuthUserH]):
                self.http_headers[AuthUserH] = "\r\nX-libcurl-Empty-Header-Workaround: *"

        # Turn our dict into a list of 2-tuples
        headers = YumRepository._YumRepository__headersListFromDict(self)   # pylint: disable-msg=E1101

        # We will always prefer to send no-cache.
        if not (cache or self.http_headers.has_key('Pragma')):
            headers.append(('Pragma', 'no-cache'))

        headers = tuple(headers)

        if local is None or relative is None:
            raise yum.Errors.RepoError, \
                  "get request for Repo %s, gave no source or dest" % self.id

        if self.failure_obj:
            (f_func, f_args, f_kwargs) = self.failure_obj
            self.failure_obj = (f_func, f_args, f_kwargs)

        if self.cache == 1:
            if os.path.exists(local): # FIXME - we should figure out a way
                return local          # to run the checkfunc from here

            else: # ain't there - raise
                raise yum.Errors.RepoError, \
                    "Caching enabled but no local cache of %s from %s" % (local,
                           self)

        if url is not None:
            remote = url + '/' + relative
            result = self.grab.urlgrab(remote, local,
                                      text = text,
                                      range = (start, end),
                                      copy_local=copy_local,
                                      reget = reget,
                                      checkfunc=checkfunc,
                                      http_headers=headers,
                                      ssl_ca_cert = self.sslcacert.encode('utf-8'),
                                      timeout=self.timeout,
                                      size = size,
                                      retry_no_cache=self._retry_no_cache
                                      )
            return result

        result = None
        urlException = None
        for server in self.urls:
            #force to http if configured
            if self.up2date_cfg['useNoSSLForPackages'] == 1:
                server = force_http(server)
            #Sanity check the url
            check_url(server)
            # Construct the full url string
            remote = server + '/' + relative
            try:
                result = self.grab.urlgrab(remote, local,
                                          text = text,
                                          range = (start, end),
                                          copy_local=copy_local,
                                          reget = reget,
                                          checkfunc=checkfunc,
                                          http_headers=headers,
                                          ssl_ca_cert = self.sslcacert.encode('utf-8'),
                                          timeout=self.timeout,
                                          size = size,
                                          retry_no_cache=self._retry_no_cache
                                          )
                return result
            except URLGrabError, e:
                urlException = e
                continue
            
        if result == None:
            raise urlException
        return result

    def _setupGrab(self):
        """sets up the grabber functions. We don't want to use mirrors."""

        try:
            ugopts = self._default_grabopts()
            if "http_headers" in ugopts:
                del(ugopts["http_headers"])
        except AttributeError: # this method does not exist on RHEL5
            ugopts = { 'keepalive': self.keepalive,
                'bandwidth': self.bandwidth,
                'retry': self.retries,
                'throttle': self.throttle,
                'proxies': self.proxy_dict,
                'timeout': self.timeout,
            }
        headers = tuple(YumRepository._YumRepository__headersListFromDict(self)) # pylint: disable-msg=E1101

        self._grabfunc = URLGrabber(
                                   progress_obj=self.callback,
                                   interrupt_callback=self.interrupt_callback,
                                   copy_local=self.copy_local,
                                   http_headers=headers,
                                   reget='simple',
                                   **ugopts)
        #bz453690 ensure that user-agent header matches for communication from
        #up2date library calls, as well as yum-rhn-plugin calls
        self._grabfunc.opts.user_agent = rhn.transports.Transport.user_agent
        self._grab = self._grabfunc
    setupGrab = _setupGrab

    def _getgrabfunc(self):
        if not self._grabfunc or self._callbacks_changed:
            self._setupGrab()
            self._callbacks_changed = False
        return self._grabfunc
    def _getgrab(self):
        if not self._grab or self._callbacks_changed:
            self._setupGrab()
            self._callbacks_changed = False
        return self._grab

    grabfunc = property(lambda self: self._getgrabfunc())
    grab = property(lambda self: self._getgrab())

    def _setChannelEnable(self, value=1):
        """ Enable or disable channel in file rhnplugin.conf.
            channel is label of channel and value should be 1 or 0.
        """
        cfg = INIConfig(file('/etc/yum/pluginconf.d/rhnplugin.conf'))
        # we cannot use directly cfg[channel].['enabled'], because
        # if that section do not exist it raise error
        func = getattr(cfg, self.label)
        func.enabled = value
        f = open('/etc/yum/pluginconf.d/rhnplugin.conf', 'w')
        print >> f, cfg
        f.close()

    def enablePersistent(self):
        """
        Persistently enable channel in rhnplugin.conf
        """
        self._setChannelEnable(1)
        self.enable()

    def disablePersistent(self):
        """
        Persistently disable channel in rhnplugin.conf
        """
        self._setChannelEnable(0)
        self.disable()

    def _getRepoXML(self):
        try:
            return YumRepository._getRepoXML(self)
        except yum.Errors.RepoError:
            # Refresh our loginInfo then try again
            # possibly it's out of date
            up2dateAuth.updateLoginInfo(timeout=self.timeout)
            return YumRepository._getRepoXML(self)

def make_package_delta(ts_info):
    """
    Construct an RHN style package delta from a yum TransactionData object.

    Return a hash containing two keys: added and removed.
    Each key's value is a list of RHN style package tuples.
    """

    delta = {}
    delta["added"] = []
    delta["removed"] = []

    # Make sure the transaction data has the packages in nice lists.
    ts_info.makelists()

    for ts_member in ts_info.installed:
        package = ts_member.po
        pkgtup = __rhn_pkg_tup_from_po(package)
        delta["added"].append(pkgtup)

    for ts_member in ts_info.depinstalled:
        package = ts_member.po
        pkgtup = __rhn_pkg_tup_from_po(package)
        delta["added"].append(pkgtup)

    for ts_member in ts_info.updated:
        package = ts_member.po
        pkgtup = __rhn_pkg_tup_from_po(package)
        delta["added"].append(pkgtup)

    for ts_member in ts_info.depupdated:
        package = ts_member.po
        pkgtup = __rhn_pkg_tup_from_po(package)
        delta["added"].append(pkgtup)

    for ts_member in ts_info.removed:
        package = ts_member.po
        pkgtup = __rhn_pkg_tup_from_po(package)
        delta["removed"].append(pkgtup)

    for ts_member in ts_info.depremoved:
        package = ts_member.po
        pkgtup = __rhn_pkg_tup_from_po(package)
        delta["removed"].append(pkgtup)

    return delta

def __rhn_pkg_tup_from_po(package):
    """ Construct an rhn-style package tuple from a yum package object. """

    name = package.returnSimple('name')
    epoch = package.returnSimple('epoch')
    version = package.returnSimple('version')
    release = package.returnSimple('release')
    arch = package.returnSimple('arch')

    return (name, version, release, epoch, arch)


class BadConfig(Exception):
    pass

class BadProxyConfig(BadConfig):
    pass

class BadSslCaCertConfig(BadConfig):
    pass

def get_proxy_url(up2date_cfg):
    if not up2date_cfg['enableProxy']:
        return None

    proxy_url = ""
    if up2date_cfg['useNoSSLForPackages']:
        proxy_url = 'http://'
    else:
        proxy_url = 'https://'
    if up2date_cfg['enableProxyAuth']:
        if not up2date_cfg.has_key('proxyUser') or \
            up2date_cfg['proxyUser'] == '':
            raise BadProxyConfig
        if not up2date_cfg.has_key('proxyPassword') or \
            up2date_cfg['proxyPassword'] == '':
            raise BadProxyConfig
        proxy_url = proxy_url + up2date_cfg['proxyUser']
        proxy_url = proxy_url + ':'
        proxy_url = proxy_url + urllib.quote(up2date_cfg['proxyPassword'])
        proxy_url = proxy_url + '@'
   
    netloc = config.getProxySetting()
    if netloc == '':
        raise BadProxyConfig
    return proxy_url + netloc


class InvalidGpgKeyLocation(Exception):
    pass

def is_valid_gpg_key_url(key_url):
    proto_split = key_url.split('://')
    if len(proto_split) != 2:
        return False
    
    proto, path = proto_split
    if proto.lower() != 'file':
        return False

    path = os.path.normpath(path)
    if not path.startswith('/etc/pki/rpm-gpg/'):
        return False
    return True

def get_gpg_key_urls(key_url_string):
    """
    Parse the key urls and validate them.

    key_url_string is a space seperated list of gpg key urls that must be
    located in /etc/pkg/rpm-gpg/.
    Return a list of strings containing the key urls.
    Raises InvalidGpgKeyLocation if any of the key urls are invalid.
    """
    key_urls = key_url_string.split()
    for key_url in key_urls:
        if not is_valid_gpg_key_url(key_url):
            raise InvalidGpgKeyLocation
    return key_urls

def get_ssl_ca_cert(up2date_cfg):
    if not (up2date_cfg.has_key('sslCACert') and up2date_cfg['sslCACert']):
        raise BadSslCaCertConfig

    ca_certs = up2date_cfg['sslCACert']
    if type(ca_certs) == list:
        return ca_certs[0]

    return ca_certs

def check_url(serverurl):
    typ, uri = urllib.splittype(serverurl)
    if typ != None:
        typ = typ.lower()
    up2date_cfg = config.initUp2dateConfig()
    if up2date_cfg['useNoSSLForPackages']:
        if typ.strip() not in ("http"):
            raise up2dateErrors.InvalidProtocolError("You specified an invalid "
                    "protocol.  Option useNoSSLServerForPackages requires http")
    elif typ.strip() not in ("http", "https"):
        raise up2dateErrors.InvalidProtocolError("You specified an invalid "
                                                 "protocol. Only https and "
                                                 "http are allowed.")

def force_http(serverurl):
    """
    Returns a url using http
    """
    httpUrl = serverurl
    typ, uri = urllib.splittype(serverurl)
    if typ != None:
        typ = typ.lower().strip()
    if typ not in ("http"):
        httpUrl = "http:" + uri
    return httpUrl

def getRHNRepoOptions(conduit, repoid):
    from ConfigParser import NoSectionError
    conduit.info(5, "Looking for repo options for [%s]" % (repoid))
    try:
        if conduit:
            if hasattr(conduit, "_conf") and hasattr(conduit._conf, "items"):
                return conduit._conf.items(repoid)
    except NoSectionError:
        pass
    return None

def setRHNRepoDefaults(conduit, repo):
    # newly created repo gets defaults hardwired in yum/config.py
    # update repo defaults according to values parsed from yum.conf
    conf = conduit.getConf()
    for opt, value in repo.iteritems():
        if hasattr(conf, opt):
            setattr(repo, opt, getattr(conf, opt))
    if hasattr(conf, '_repos_persistdir'):
        repo.base_persistdir = conf._repos_persistdir

def updateRHNRepoOptions(conduit, repo):
    pluginOptions = getRHNRepoOptions(conduit, 'main')
    repoOptions = getRHNRepoOptions(conduit, repo.id)
    for options in [pluginOptions, repoOptions]:
        if options:
            for o in options:
                if o[0] == 'exclude': # extend current list
                    setattr(repo, o[0], ",".join(repo.exclude) + ',' + o[1])
                else: # replace option
                    setattr(repo, o[0], o[1])
                conduit.info(5, "Repo '%s' setting option '%s' = '%s'" %
                    (repo.id, o[0], o[1]))

def config_hook(conduit):
    if hasattr(conduit, 'registerPackageName'):
        conduit.registerPackageName("yum-rhn-plugin")

Zerion Mini Shell 1.0