Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add RSYNC_PROXY and Location-Aware Support for RHN #44

Merged
merged 2 commits into from

2 participants

@ubeck
  • add RSYNC_PROXY at mrepo
  • rhnlib for Location-Aware Support (rhnlib-2.1.4-17.el4_8.1) -> comments at rhn directory are not correct after my push
@dagwieers dagwieers merged commit 458dc2d into dagwieers:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
3  mrepo
@@ -208,6 +208,7 @@ class Config:
self.ftp_proxy = self.getoption('main', 'ftp_proxy', None)
self.http_proxy = self.getoption('main', 'http_proxy', None)
self.https_proxy = self.getoption('main', 'https_proxy', None)
+ self.RSYNC_PROXY = self.getoption('main', 'RSYNC_PROXY', None)
self.cmd = {}
self.cmd['createrepo'] = self.getoption('main', 'createrepocmd', '/usr/bin/createrepo')
@@ -1685,6 +1686,8 @@ def main():
os.environ['http_proxy'] = cf.http_proxy
if cf.https_proxy:
os.environ['https_proxy'] = cf.https_proxy
+ if cf.RSYNC_PROXY:
+ os.environ['RSYNC_PROXY'] = cf.RSYNC_PROXY
### Select list of distributions in order of appearance
if not op.dists:
View
2  rhn/SSL.py
@@ -6,7 +6,7 @@
#
# Author: Mihai Ibanescu <misa@redhat.com>
-# $Id: SSL.py 137099 2008-02-19 17:27:26Z pkilambi $
+# $Id: SSL.py 191145 2010-03-01 10:21:24Z msuchy $
"""
rhn.SSL builds an abstraction on top of the objects provided by pyOpenSSL
View
32 rhn/SmartIO.py
@@ -1,3 +1,4 @@
+#/usr/bin/env python
#
# Smart IO class
#
@@ -5,7 +6,7 @@
#
# Author: Mihai Ibanescu <misa@redhat.com>
-# $Id: SmartIO.py 98118 2006-07-19 19:07:30Z jbowes $
+# $Id: SmartIO.py 191145 2010-03-01 10:21:24Z msuchy $
"""
This module implements the SmartIO class
"""
@@ -58,27 +59,10 @@ def __getattr__(self, name):
# Creates a temporary file and passes back its file descriptor
def _tempfile(tmpdir='/tmp'):
- # Try to create the file a couple of times
- filename = "%s/_rhn_transports-%d" % (tmpdir, os.getpid())
- for i in range(5):
- try:
- fd = os.open(filename, os.O_CREAT | os.O_RDWR | os.O_EXCL)
- except OSError, e:
- if e.errno == 17:
- # File exists
- filename = "%s-%.5f" % (filename, time.time() % 10)
- continue
- # Another error, raise it
- raise
- else:
- break
- else:
- # Failed to get the temp file
- raise IOError, "Could not create temporary file"
-
- # To make sure it's a temp file, unlink it
- os.unlink(filename)
+ import tempfile
+ (fd, fname) = tempfile.mkstemp(prefix="_rhn_transports-%d-" \
+ % os.getpid(), dir=tmpdir)
+ # tempfile, unlink it
+ os.unlink(fname)
+ return os.fdopen(fd, "wb+")
- # Convert the file descriptor into a stream
- f = os.fdopen(fd, "wb+")
- return f
View
45 rhn/UserDictCase.py
@@ -4,7 +4,9 @@
# Copyright (c) 2001-2005, Red Hat Inc.
# All rights reserved.
#
-# $Id: UserDictCase.py 102336 2006-09-14 18:51:39Z jbowes $
+# $Id: UserDictCase.py 191145 2010-03-01 10:21:24Z msuchy $
+
+import string
from types import StringType
from UserDict import UserDict
@@ -14,47 +16,36 @@ class UserDictCase(UserDict):
def __init__(self, data = None):
self.kcase = {}
UserDict.__init__(self, data)
-
- def __lower_string(self, key):
- """ Return the lower() of key if it is a string. """
- if isinstance(key, StringType):
- return key.lower()
- else:
- return key
-
# some methods used to make the class work as a dictionary
def __setitem__(self, key, value):
- lkey = self.__lower_string(key)
+ lkey = key
+ if isinstance(key, StringType):
+ lkey = string.lower(key)
self.data[lkey] = value
self.kcase[lkey] = key
-
def __getitem__(self, key):
- key = self.__lower_string(key)
+ if isinstance(key, StringType):
+ key = string.lower(key)
if not self.data.has_key(key):
return None
return self.data[key]
-
- get = __getitem__
-
def __delitem__(self, key):
- key = self.__lower_string(key)
+ if isinstance(key, StringType):
+ key = string.lower(key)
del self.data[key]
del self.kcase[key]
-
+ get = __getitem__
def keys(self):
return self.kcase.values()
-
def items(self):
return self.get_hash().items()
-
def has_key(self, key):
- key = self.__lower_string(key)
+ if isinstance(key, StringType):
+ key = string.lower(key)
return self.data.has_key(key)
-
def clear(self):
self.data.clear()
self.kcase.clear()
-
# return this data as a real hash
def get_hash(self):
return reduce(lambda a, (ik, v), hc=self.kcase:
@@ -63,19 +54,19 @@ def get_hash(self):
# return the data for marshalling
def __getstate__(self):
return self.get_hash()
-
# we need a setstate because of the __getstate__ presence screws up deepcopy
def __setstate__(self, state):
self.__init__(state)
-
# get a dictionary out of this instance ({}.update doesn't get instances)
def dict(self):
return self.get_hash()
-
def update(self, dict):
for (k, v) in dict.items():
- self[k] = v
-
+ lk = k
+ if isinstance(k, StringType):
+ lk = string.lower(k)
+ self.data[lk] = v
+ self.kcase[lk] = k
# Expose an iterator. This would normally fail if there is no iter()
# function defined - but __iter__ will never be called on python 1.5.2
def __iter__(self):
View
2  rhn/__init__.py
@@ -3,7 +3,7 @@
#
# Copyright (c) 2005 Red Hat, Inc.
#
-# $Id: __init__.py 89042 2005-07-05 22:05:02Z wregglej $
+# $Id: __init__.py 191145 2010-03-01 10:21:24Z msuchy $
"""
rhn - A collection of modules used by Red Hat Network
"""
View
23 rhn/connections.py
@@ -6,7 +6,7 @@
#
# Author: Mihai Ibanescu <misa@redhat.com>
-# $Id: connections.py 116568 2007-05-21 23:30:08Z pkilambi $
+# $Id: connections.py 191145 2010-03-01 10:21:24Z msuchy $
import sys
@@ -14,23 +14,8 @@
import SSL
import nonblocking
-# Testing which version of python we run
-if hasattr(sys, "version_info"):
- # python 2.2 or newer
- import httplib
-else:
- # Older version, with incompatible httplib; import the patched one
- import _httplib
- httplib = _httplib
-
-# Testing which version of python we run
-if hasattr(sys, "version_info"):
- # python 2.2 or newer
- import xmlrpclib
-else:
- # Older version, with incompatible httplib; import the patched one
- import _internal_xmlrpclib
- xmlrpclib = _internal_xmlrpclib
+import httplib
+import xmlrpclib
# Import into the local namespace some httplib-related names
_CS_REQ_SENT = httplib._CS_REQ_SENT
@@ -89,7 +74,7 @@ def __init__(self, host, port=None):
self._cb_ex = []
self._cb_user_data = None
self._cb_callback = None
- self._user_agent = "rhn.connections $Revision: 116568 $ (python)"
+ self._user_agent = "rhn.connections $Revision: 191145 $ (python)"
def set_callback(self, rs, ws, ex, user_data, callback):
# XXX check the params
View
15 rhn/nonblocking.py
@@ -1,17 +1,26 @@
+#!/usr/bin/env python
#
#
#
-# $Id: nonblocking.py 102302 2006-09-14 14:25:34Z jbowes $
+# $Id: nonblocking.py 191145 2010-03-01 10:21:24Z msuchy $
import select
import fcntl
+# Testing which version of python we run
+import sys
+if hasattr(sys, "version_info"):
+ # python 2.2 or newer; FCNTL is deprecated
+ FCNTL = fcntl
+else:
+ # Older version, with valid FCNTL
+ import FCNTL
class NonBlockingFile:
def __init__(self, fd):
# Keep a copy of the file descriptor
self.fd = fd
- fcntl.fcntl(self.fd.fileno(), fcntl.F_SETFL, fcntl.O_NDELAY | fcntl.FNDELAY)
+ fcntl.fcntl(self.fd.fileno(), FCNTL.F_SETFL, FCNTL.O_NDELAY | FCNTL.FNDELAY)
# Set the callback-related stuff
self.read_fd_set = []
self.write_fd_set = []
@@ -24,7 +33,7 @@ def set_callback(self, read_fd_set, write_fd_set, exc_fd_set,
self.read_fd_set = read_fd_set
# Make the objects non-blocking
for f in self.read_fd_set:
- fcntl.fcntl(f.fileno(), fcntl.F_SETFL, fcntl.O_NDELAY | fcntl.FNDELAY)
+ fcntl.fcntl(f.fileno(), FCNTL.F_SETFL, FCNTL.O_NDELAY | FCNTL.FNDELAY)
self.write_fd_set = write_fd_set
self.exc_fd_set = exc_fd_set
View
110 rhn/rhnLockfile.py
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2008--2010 Red Hat, Inc.
+#
+# This software is licensed to you under the GNU General Public License,
+# version 2 (GPLv2). There is NO WARRANTY for this software, express or
+# implied, including the implied warranties of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
+# along with this software; if not, see
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# Red Hat trademarks are not licensed under GPLv2. No permission is
+# granted to use or replicate Red Hat trademarks that are incorporated
+# in this software or its documentation.
+#
+
+import os
+import sys
+import fcntl
+from errno import EWOULDBLOCK, EEXIST
+import fcntl
+
+class LockfileLockedException(Exception):
+ """thrown ONLY when pid file is locked."""
+ pass
+
+class Lockfile:
+
+ """class that provides simple access to a PID-style lockfile.
+
+ methods: __init__(lockfile), acquire(), and release()
+ NOTE: currently acquires upon init
+ The *.pid file will be acquired, or an LockfileLockedException is raised.
+ """
+
+ def __init__(self, lockfile, pid=None):
+ """create (if need be), and acquire lock on lockfile
+
+ lockfile example: '/var/run/up2date.pid'
+ """
+
+ # cleanup the path and assign it.
+ self.lockfile = os.path.abspath(
+ os.path.expanduser(
+ os.path.expandvars(lockfile)))
+
+ self.pid = pid
+ if not self.pid:
+ self.pid = os.getpid()
+
+ # create the directory structure
+ dirname = os.path.dirname(self.lockfile)
+ if not os.path.exists(dirname):
+ try:
+ os.makedirs(dirname)
+ except OSError, e:
+ if hasattr(e, 'errno') and e.errno == EEXIST:
+ # race condition... dirname exists now.
+ pass
+ else:
+ raise
+
+ # open the file -- non-destructive read-write, unless it needs
+ # to be created XXX: potential race condition upon create?
+ self.f = os.open(self.lockfile, os.O_RDWR|os.O_CREAT|os.O_SYNC)
+ self.acquire()
+
+ def acquire(self):
+ """acquire the lock; else raise LockfileLockedException."""
+
+ try:
+ fcntl.flock(self.f, fcntl.LOCK_EX|fcntl.LOCK_NB)
+ except IOError, e:
+ if e.errno == EWOULDBLOCK:
+ raise LockfileLockedException(
+ "cannot acquire lock on %s." % self.lockfile)
+ else:
+ raise
+ # unlock upon exit
+ fcntl.fcntl(self.f, fcntl.F_SETFD, 1)
+ # truncate and write the pid
+ os.ftruncate(self.f, 0)
+ os.write(self.f, str(self.pid) + '\n')
+
+ def release(self):
+ # Remove the lock file
+ os.unlink(self.lockfile)
+ fcntl.flock(self.f, fcntl.LOCK_UN)
+ os.close(self.f)
+
+
+def main():
+ """test code"""
+
+ try:
+ L = Lockfile('./test.pid')
+ except LockfileLockedException, e:
+ sys.stderr.write("%s\n" % e)
+ sys.exit(-1)
+ else:
+ print "lock acquired "
+ print "...sleeping for 10 seconds"
+ import time
+ time.sleep(10)
+ L.release()
+ print "lock released "
+
+if __name__ == '__main__':
+ # test code
+ sys.exit(main() or 0)
+
View
78 rhn/rpclib.py
@@ -6,15 +6,15 @@
#
# Author: Mihai Ibanescu <misa@redhat.com>
-# $Id: rpclib.py 118741 2007-07-31 21:23:02Z pkilambi $
+# $Id: rpclib.py 198366 2010-11-24 12:51:35Z msuchy $
-__version__ = "$Revision: 118741 $"
+__version__ = "$Revision: 198366 $"
import string
import transports
import urllib
-
-from types import ListType, TupleType
+import re
+from types import ListType, TupleType, StringType, UnicodeType, DictType, DictionaryType
from UserDictCase import UserDictCase
@@ -279,16 +279,41 @@ def accept_ranges(self):
return headers['Accept-Ranges']
return None
+ def _strip_characters(self, *args):
+ """ Strip characters, which are not allowed according:
+ http://www.w3.org/TR/2006/REC-xml-20060816/#charsets
+ From spec:
+ Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
+ """
+ regexp = r'[\x00-\x08]|[\x0b-\x0c]|[\x0e-\x1f]'
+ result=[]
+ for item in args:
+ item_type = type(item)
+ if item_type == StringType or item_type == UnicodeType:
+ item = re.sub(regexp, '', item)
+ elif item_type == TupleType:
+ item = tuple(map(self._strip_characters, item))
+ elif item_type == ListType:
+ item = map(self._strip_characters, item)
+ elif item_type == DictType or item_type == DictionaryType:
+ item = dict([(self._strip_characters(name, val)) for name, val in item.iteritems()])
+ # else: some object - should take care of himself
+ # numbers - are safe
+ result.append(item)
+ if len(result) == 1:
+ return result[0]
+ else:
+ return tuple(result)
+
def _request(self, methodname, params):
# call a method on the remote server
# the loop is used to handle redirections
- num = 0
redirect_response = 0
-
+ retry = 0
while 1:
- if num >= MAX_REDIRECTIONS:
- raise InvalidRedirectionError("Too many redirects")
- num = num + 1
+ if retry >= MAX_REDIRECTIONS:
+ raise InvalidRedirectionError(
+ "Unable to fetch requested Package")
# Clear the transport headers first
self._transport.clear_headers()
@@ -305,18 +330,26 @@ def _request(self, methodname, params):
# Advertise that we follow redirects
#changing the version from 1 to 2 to support backward compatibility
self._transport.add_header("X-RHN-Transport-Capability",
- "follow-redirects=2")
+ "follow-redirects=3")
if redirect_response:
self._transport.add_header('X-RHN-Redirect', '0')
if send_handler:
self._transport.add_header('X-RHN-Path', send_handler)
- request = self._req_body(params, methodname)
+ request = self._req_body(self._strip_characters(params), methodname)
try:
- response = self._transport.request(self._host, self._handler,
- request, verbose=self._verbose)
+ if self._redirected:
+ type, uri = urllib.splittype(self._redirected)
+ self._redirected = None
+
+ host, handler = urllib.splithost(uri)
+ response = self._transport.request(host, handler,
+ request, verbose=self._verbose)
+ else:
+ response = self._transport.request(self._host, \
+ self._handler, request, verbose=self._verbose)
save_response = self._transport.response_status
except xmlrpclib.ProtocolError, pe:
if self.use_handler_path:
@@ -328,13 +361,20 @@ def _request(self, methodname, params):
raise InvalidRedirectionError("Redirects not allowed")
if save_response == 200:
+ # reset _host and _handler for next request
+ type, uri = urllib.splittype(self._uri)
+ self._host, self._handler = urllib.splithost(uri)
+ # exit redirects loop and return response
break
- elif save_response not in [200,302]:
- self._redirected = self._uri
- self.use_handler_path = 1
- else:
+ elif save_response in (301, 302):
self._redirected = self._transport.redirected()
self.use_handler_path = 0
+ redirect_response = 1
+ else:
+ # Retry pkg fetch
+ retry = retry + 1
+ self.use_handler_path = 1
+ continue
if self._verbose:
print "%s redirected to %s" % (self._uri, self._redirected)
@@ -356,7 +396,6 @@ def _request(self, methodname, params):
raise InvalidRedirectionError(
"HTTPS redirected to HTTP is not supported")
- self._host, self._handler = urllib.splithost(uri)
if not self._handler:
self._handler = "/RPC2"
@@ -365,9 +404,6 @@ def _request(self, methodname, params):
raise InvalidRedirectionError("Redirects not allowed")
else:
redirect_response = 1
- num = 0
- continue
-
#
# Create a new transport for the redirected service and
# set up the parameters on the new transport
View
37 rhn/transports.py
@@ -1,3 +1,4 @@
+#/usr/bin/env python
#
# Helper transport objects
#
@@ -8,21 +9,22 @@
# - Cristian Gafton <gafton@redhat.com>
# - Erik Troan <ewt@redhat.com>
-# $Id: transports.py 102540 2006-09-18 20:19:31Z jbowes $
+# $Id: transports.py 191145 2010-03-01 10:21:24Z msuchy $
# Transport objects
import os
import sys
import time
+import string
from types import IntType, StringType, ListType
from SmartIO import SmartIO
from UserDictCase import UserDictCase
import connections
-import xmlrpclib
+xmlrpclib = connections.xmlrpclib
-__version__ = "$Revision: 102540 $"
+__version__ = "$Revision: 191145 $"
# XXX
COMPRESS_LEVEL = 6
@@ -347,11 +349,12 @@ def __init__(self, headers=None, progressCallback=None, bufferSize=1024,
if not headers:
# we need to get them from environment
if os.environ.has_key("HTTP_CONTENT_TRANSFER_ENCODING"):
- self.transfer = os.environ["HTTP_CONTENT_TRANSFER_ENCODING"].lower()
+ self.transfer = string.lower(
+ os.environ["HTTP_CONTENT_TRANSFER_ENCODING"])
if os.environ.has_key("HTTP_CONTENT_ENCODING"):
- self.encoding = os.environ["HTTP_CONTENT_ENCODING"].lower()
+ self.encoding = string.lower(os.environ["HTTP_CONTENT_ENCODING"])
if os.environ.has_key("CONTENT-TYPE"):
- self.type = os.environ["CONTENT-TYPE"].lower()
+ self.type = string.lower(os.environ["CONTENT-TYPE"])
if os.environ.has_key("CONTENT_LENGTH"):
self.length = int(os.environ["CONTENT_LENGTH"])
if os.environ.has_key("HTTP_ACCEPT_LANGUAGE"):
@@ -365,7 +368,7 @@ def __init__(self, headers=None, progressCallback=None, bufferSize=1024,
# us with sane values --gaftonc (actually mimetools is the culprit)
for header in headers.keys():
value = headers[header]
- h = header.lower()
+ h = string.lower(header)
if h == "content-length":
try:
self.length = int(value)
@@ -373,16 +376,16 @@ def __init__(self, headers=None, progressCallback=None, bufferSize=1024,
self.length = 0
elif h == "content-transfer-encoding":
# RFC 2045 #6.1: case insensitive
- self.transfer = value.lower()
+ self.transfer = string.lower(value)
elif h == "content-encoding":
# RFC 2616 #3.5: case insensitive
- self.encoding = value.lower()
+ self.encoding = string.lower(value)
elif h == "content-type":
# RFC 2616 #3.7: case insensitive
- self.type = value.lower()
+ self.type = string.lower(value)
elif h == "accept-language":
# RFC 2616 #3.10: case insensitive
- self.lang = value.lower()
+ self.lang = string.lower(value)
elif h == "x-package-filename":
self.name = value
@@ -416,7 +419,7 @@ def read(self, fd = sys.stdin):
def decode(self, fd = sys.stdin):
# The octet-stream data are passed right back
- if self.type == "application/octet-stream":
+ if self.type in ["application/octet-stream", "application/x-rpm"]:
return InputStream(fd, self.length, self.name, close=fd.close)
if not self.io:
@@ -625,7 +628,7 @@ def set_header(self, name, arg):
# fields into one "field-name: field-value" pair, without
# changing the semantics of the message, by appending each
# subsequent field-value to the first, each separated by a comma.
- self.headers[name] = ','.join(map(str, arg))
+ self.headers[name] = string.join(map(str, arg), ',')
else:
self.headers[name] = str(arg)
@@ -678,7 +681,7 @@ def process(self, data):
# other headers
self.set_header("X-Transport-Info",
'Extended Capabilities Transport (C) Red Hat, Inc (version %s)' %
- __version__.split()[1])
+ string.split(__version__)[1])
self.__processed = 1
# reset the transport options
@@ -742,7 +745,7 @@ def lookupTransfer(transfer, strict=0):
return transfer
if isinstance(transfer, StringType):
for i in range(len(Output.transfers)):
- if Output.transfers[i] == transfer.lower():
+ if Output.transfers[i] == string.lower(transfer):
return i
if strict:
raise ValueError("Unsupported transfer %s" % transfer)
@@ -759,7 +762,7 @@ def lookupEncoding(encoding, strict=0):
return encoding
if isinstance(encoding, StringType):
for i in range(len(Output.encodings)):
- if encoding.lower() in Output.encodings[i]:
+ if string.lower(encoding) in Output.encodings[i]:
return i
if strict:
raise ValueError("Unsupported encoding %s" % encoding)
@@ -778,7 +781,7 @@ def __init__(self, file_obj, length = 0, name = None,
self.bufferSize=bufferSize
self.name = ""
if name:
- self.name = name[name.rfind("/")+1:]
+ self.name = name[string.rfind(name, "/")+1:]
self.progressCallback = progressCallback
def __len__(self):
Something went wrong with that request. Please try again.