Hi, we had here some trouble with the proxy and installing hughe RPMs. In the end we found the OOM killer working because the proxy load the complete RPM into memory during delivery.
So I created two patches for the proxy: 0001: Is when sending content to the server via the proxy. Typically this way not much data are transfered, but it can happen. So I removed the "body" parameter from several functions and use "self.req" instead. 0002: This is when receiving data from the Server and deliver it to the client. I used the SmartIO class to create a temp file when copying the data from the response into the request. A direct usage of the FD was not possible. It seems, that the response FD is already removed when the request function try to read from it. So we need a temp file. Note: SmartIO uses /tmp by default to create the tempfile. New systems sometimes uses tmpfs on /tmp (Fedora?). So it might be a good idea to change the default to a place without tmpfs. -- Regards Michael Calmer -------------------------------------------------------------------------- Michael Calmer SUSE LINUX Products GmbH, Maxfeldstr. 5, D-90409 Nuernberg T: +49 (0) 911 74053 0 F: +49 (0) 911 74053575 - e-mail: michael.cal...@suse.com -------------------------------------------------------------------------- SUSE LINUX Products GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer HRB 16746 (AG Nürnberg)
>From 264b8a81d7d37b487de5849a048e8ad7869fd58c Mon Sep 17 00:00:00 2001 From: Michael Calmer <m...@suse.de> Date: Thu, 18 Apr 2013 12:38:50 +0200 Subject: [PATCH 1/2] do not read data into memory which should be send to the server --- proxy/proxy/broker/rhnBroker.py | 3 +-- proxy/proxy/redirect/rhnRedirect.py | 4 ++-- proxy/proxy/rhnShared.py | 19 ++++++++++++------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/proxy/proxy/broker/rhnBroker.py b/proxy/proxy/broker/rhnBroker.py index 00f920e..ddd2e34 100644 --- a/proxy/proxy/broker/rhnBroker.py +++ b/proxy/proxy/broker/rhnBroker.py @@ -201,7 +201,6 @@ class BrokerHandler(SharedHandler): % repr(_oto['X-RHN-Proxy-Auth'])) log_debug(3, 'Trying to connect to parent') - data = self.req.read() # Loops twice? Here's why: # o If no errors, the loop is broken and we move on. @@ -214,7 +213,7 @@ class BrokerHandler(SharedHandler): # Add the proxy version rhnFlags.get('outputTransportOptions')['X-RHN-Proxy-Version'] = str(_PROXY_VERSION) - status = self._serverCommo(data) # part 2 + status = self._serverCommo() # part 2 # check for proxy authentication blowup. respHeaders = self.responseContext.getHeaders() diff --git a/proxy/proxy/redirect/rhnRedirect.py b/proxy/proxy/redirect/rhnRedirect.py index 7f73fd8..e633132 100644 --- a/proxy/proxy/redirect/rhnRedirect.py +++ b/proxy/proxy/redirect/rhnRedirect.py @@ -90,7 +90,7 @@ class RedirectHandler(SharedHandler): self._connectToParent() # part 1 log_debug(4, 'Initiating communication with server...') - status = self._serverCommo(self.req.read()) # part 2 + status = self._serverCommo() # part 2 if (status != apache.OK) and (status != apache.HTTP_PARTIAL_CONTENT): log_debug(3, "Leaving handler with status code %s" % status) return status @@ -413,7 +413,7 @@ class RedirectHandler(SharedHandler): # redirected, so we can safely pass an empty string in as the request # body. - status = self._serverCommo('') + status = self._serverCommo() # This little hack isn't pretty, but lets us normalize our result code. diff --git a/proxy/proxy/rhnShared.py b/proxy/proxy/rhnShared.py index c44fad8..ba6df9d 100644 --- a/proxy/proxy/rhnShared.py +++ b/proxy/proxy/rhnShared.py @@ -181,11 +181,10 @@ class SharedHandler: port = None return scheme, host, port, path - def _serverCommo(self, data): + def _serverCommo(self): """ Handler part 2 Server (or next proxy) communication. - data is the self.req.read() """ log_debug(1) @@ -199,7 +198,7 @@ class SharedHandler: # Send the headers, the body and expect a response try: - status, headers, bodyFd = self._proxy2server(data) + status, headers, bodyFd = self._proxy2server() self.responseContext.setHeaders(headers) self.responseContext.setBodyFd(bodyFd) except IOError: @@ -325,13 +324,19 @@ class SharedHandler: self._forwardHTTPBody(bodyFd, self.req) - def _proxy2server(self, body): + def _proxy2server(self): hdrs = rhnFlags.get('outputTransportOptions') - log_debug(3, hdrs, "Content length", len(body)) + log_debug(3, hdrs) + size = -1 # Put the headers into the output connection object http_connection = self.responseContext.getConnection() for (k, vals) in hdrs.items(): + if k.lower() in ['content_length', 'content-length']: + try: + size = int(vals) + except ValueError: + pass if k.lower() in ['content_length', 'content_type']: # mod_wsgi modifies incoming headers so we have to transform them back k = k.replace('_','-') @@ -357,8 +362,8 @@ class SharedHandler: http_connection.endheaders() # Send the body too if there is a body - if body: - http_connection.send(body) + if size != 0: + http_connection.send(self.req.headers_in['wsgi.input']) # At this point everything is sent to the server # We now wait for the response -- 1.8.2
>From dfe7282f9d23746ce76aca085fc68b0870a8876a Mon Sep 17 00:00:00 2001 From: Michael Calmer <m...@suse.de> Date: Thu, 18 Apr 2013 16:39:39 +0200 Subject: [PATCH 2/2] Do not read response data into memory --- proxy/proxy/rhnShared.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/proxy/proxy/rhnShared.py b/proxy/proxy/rhnShared.py index ba6df9d..ed18308 100644 --- a/proxy/proxy/rhnShared.py +++ b/proxy/proxy/rhnShared.py @@ -24,6 +24,7 @@ from types import ListType, TupleType ## global imports from rhn import connections from rhn.SSL import TimeoutException +from rhn.SmartIO import SmartIO ## common imports from rhn.UserDictCase import UserDictCase @@ -447,11 +448,17 @@ class SharedHandler: # read content if there is some or the size is unknown if (size > 0 or size == -1) and (toRequest.method != 'HEAD'): + tfile = SmartIO(max_mem_size=CFG.BUFFER_SIZE) buf = fromResponse.read(CFG.BUFFER_SIZE) while buf: try: - toRequest.write(buf) + tfile.write(buf) buf = fromResponse.read(CFG.BUFFER_SIZE) except IOError: buf = 0 + tfile.seek(0) + if 'wsgi.file_wrapper' in toRequest.headers_in: + toRequest.output = toRequest.headers_in['wsgi.file_wrapper'](tfile, CFG.BUFFER_SIZE) + else: + toRequest.output = iter(lambda: tfile.read(CFG.BUFFER_SIZE), '') -- 1.8.2
_______________________________________________ Spacewalk-devel mailing list Spacewalk-devel@redhat.com https://www.redhat.com/mailman/listinfo/spacewalk-devel