Search code examples
pythontwistedopenshift

How to very SIMPLY deploy a Twisted Server on OPenshift


I've got the right environment setup, python 2.7.5, Twisted installed and imports work in the Python Shell.

I have a very simple Server instance to display a landing page that Works on local machine fine.

from twisted.web import http

class MyRequestHandler(http.Request):
    pages={
    '/': '<h1>Geo-Address Server</h1>Twisted Server is Up and Running..',
    '/test': '<h1>Test</h1>Test page',
    }
    def process(self):
        print self.path
        if self.pages.has_key(self.path):
            self.write(self.pages[self.path])
        else:
            self.setResponseCode(http.NOT_FOUND)
            self.write("<h1>Not Found</h1>Sorry, page does not exist")
        self.finish()

class MyHttp(http.HTTPChannel):
    requestFactory=MyRequestHandler

class MyHttpFactory(http.HTTPFactory):
    protocol=MyHttp

if __name__=='__main__':
    from twisted.internet import reactor
    reactor.listenTCP(8080, MyHttpFactory())
    reactor.run()

However, deploying this on the Openshift Server fails to run. If I try to run the script

python script.py &

I get:

reactor.listenTCP(8080, MyHttpFactory()) File "/var/lib/openshift/5378ea844382ec89da000432/python/virtenv/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 495, in listenTCP p.startListening() File "/var/lib/openshift/5378ea844382ec89da000432/python/virtenv/lib/python2.7/site-packages/twisted/internet/tcp.py", line 979, in startListening raise CannotListenError(self.interface, self.port, le) twisted.internet.error.CannotListenError: Couldn't listen on any:8080: [Errno 13] Permission denied.

Reading through SO, most people just say to bind to port 8080(which I have done), but still I get the same error.


Solution

  • As the kb says

    Please note: We don't allow arbitrary binding of ports on the externally accessible IP address.

    It is possible to bind to the internal IP with port range: 15000 - 35530. All other ports are reserved for specific processes to avoid conflicts. Since we're binding to the internal IP, you will need to use port forwarding to access it: https://openshift.redhat.com/community/blogs/getting-started-with-port-forwarding-on-openshift

    Therefor, just find out the $OPENSHIFT_PYTHON_IP

    echo $OPENSHIFT_PYTHON_IP
    

    Then add that address to the reactor listener's interface

    reactor.listenTCP(15000, MyHttpFactory(), interface='127.X.X.X')
    

    Alternative(and the best) way to do it is by picking the value in the code. That way, if the IP changes dynamically, you still get the current IP

    import os
    
    local_hostname =os.getenv("OPENSHIFT_INTERNAL_IP")
    ..
    ..
    reactor.listenTCP(15000, MyHttpFactory(), interface=local_hostname)
    

    Note: You can only bind to the port range (15000-35530)