0

I'm trying to set a backend using py2neo on google app engine. It works just fine when pushed on the dev on app engine, however, unfortunately, it doesn't work when I use it on localhost.

First, i've setted the HOME environment variable in python (thanks to that tip, my code works on my dev) but it doesn't fix the localhost problem

Then, i've followed that advice "ImportError: No module named _ssl" with dev_appserver.py from Google App Engine it prevents one exception but another rises after.

Here is my traceback

    ft1.1: Traceback (most recent call last):
  File "/Users/Arnaud/Documents/project/app/test/neo4j/test_graph_handler.py", line 13, in test_get_direct_neighbours
    selection = self.graph_handler.get_direct_neighbours("8")
  File "/Users/Arnaud/Documents/project/app/neo4j/graph_handler.py", line 20, in get_direct_neighbours
    labels(l) AS `relationship`" % self.protect(ean))
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/database/__init__.py", line 694, in run
    return self.begin(autocommit=True).run(statement, parameters, **kwparameters)
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/database/__init__.py", line 370, in begin
    return self.transaction_class(self, autocommit)
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/database/__init__.py", line 1212, in __init__
    self.session = driver.session()
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/packages/neo4j/v1/session.py", line 126, in session
    connection = connect(self.address, self.ssl_context, **self.config)
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/packages/neo4j/v1/bolt.py", line 444, in connect
    if not store.match_or_trust(host, der_encoded_server_certificate):
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/packages/neo4j/v1/bolt.py", line 397, in match_or_trust
    f_out = os_open(self.path, O_CREAT | O_APPEND | O_WRONLY, 0o600)  # TODO: Windows
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/devappserver2/python/stubs.py", line 73, in fake_open
    raise OSError(errno.EROFS, 'Read-only file system', filename)
OSError: [Errno 30] Read-only file system: '/Users/Arnaud/.neo4j/known_hosts'

As everything lauches in a sandboxed environnement and with a fake user, the exception is normal but it does not happen on the dev.

And here is /Users/Arnaud/Documents/project/app/neo4j/graph_handler.py:20

 13     def get_direct_neighbours(self, ean):
 14         selection = self.graph.run("\
 15                 MATCH\
 16                 (:Product {ean: '%s'})-->(l)<--(n:Product)\
 17                 RETURN\
 18                 n.ean AS `ean`,\
 19                 n.name AS `name`,\
 20                 labels(l) AS `relationship`" % self.protect(ean))
 21         return selection

So to understand why it would work on the dev, I tried to localize where sandbox and dev execution start being different. and it is right here in /Users/Arnaud/Documents/project/app/libs/py2neo/packages/neo4j/v1/bolt.py:427

427     if ssl_context and SSL_AVAILABLE:
428         host, port = host_port
429         if __debug__: log_info("~~ [SECURE] %s", host)
430         try:
431             s = ssl_context.wrap_socket(s, server_hostname=host if HAS_SNI else None)
432         except SSLError as cause:
433             error = ProtocolError("Cannot establish secure connection; %s" % cause.args[1])
434             error.__cause__ = cause
435             raise error
436         else:
437             # Check that the server provides a certificate
438             der_encoded_server_certificate = s.getpeercert(binary_form=True)
439             if der_encoded_server_certificate is None:
440                 raise ProtocolError("When using a secure socket, the server should always provide a certificate")
441             trust = config.get("trust", TRUST_DEFAULT)
442             if trust == TRUST_ON_FIRST_USE:
443                 store = PersonalCertificateStore()
444                 if not store.match_or_trust(host, der_encoded_server_certificate):
445                     raise ProtocolError("Server certificate does not match known certificate for %r; check "
446                                         "details in file %r" % (host, KNOWN_HOSTS))
447     else:
448         der_encoded_server_certificate = None

Because in the dev, ssl loading fails in ssl_compat.py while on localhost, it succeeds and so the code goes inside the if statement and fails at line 444

To understand that I forced SSL_AVAILABLE to be falsy, however even with that I have wierd problems about app engine sockets which are not recognized as sockets

ft1.1: Traceback (most recent call last):
  File "/Users/Arnaud/Documents/project/app/test/neo4j/test_graph_handler.py", line 13, in test_get_direct_neighbours
    selection = self.graph_handler.get_direct_neighbours("8")
  File "/Users/Arnaud/Documents/project/app/neo4j/graph_handler.py", line 20, in get_direct_neighbours
    labels(l) AS `relationship`" % self.protect(ean))
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/database/__init__.py", line 694, in run
    return self.begin(autocommit=True).run(statement, parameters, **kwparameters)
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/database/__init__.py", line 370, in begin
    return self.transaction_class(self, autocommit)
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/database/__init__.py", line 1212, in __init__
    self.session = driver.session()
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/packages/neo4j/v1/session.py", line 126, in session
    connection = connect(self.address, self.ssl_context, **self.config)
  File "/Users/Arnaud/Documents/project/app/libs/py2neo/packages/neo4j/v1/bolt.py", line 460, in connect
    ready_to_read, _, _ = select((s,), (), (), 0)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/remote_socket/_remote_socket.py", line 483, in select
    _SetState(request, _GetSocket(value), POLLIN)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/remote_socket/_remote_socket.py", line 425, in _GetSocket
    raise ValueError('select only supported on socket objects.')
ValueError: select only supported on socket objects.

If anyone have faced the same issues, I would be interested in that because having to push on the dev before any test quite painful.

EDIT: For those who would want to know, as I have no answer from nigel yet and I needed some fast solution, i've created my own class to send and recieve cypher requests, it's compatible with app engine and i've putted it on a gist: https://gist.github.com/ArnaudParan/e26f291ba8b3c08e5b762d549667c7d6 It's experimental and might not work if you ask for full nodes but if it can help, i publish it

Community
  • 1
  • 1
Arnaud PARAN
  • 126
  • 5

1 Answers1

0

The 1st traceback could indicate that the py2neo package may be incompatible with GAE's sandbox restrictions. In particular it shows an attempt to open the /Users/Arnaud/.neo4j/known_hosts file in write mode (os_open(self.path, O_CREAT | O_APPEND | O_WRONLY, 0o600)) which is not allowed. Check if it's somehow possible to configure py2neo to not do that.

The sandbox also has restrictions on sockets, see Limitations and restrictions.

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
  • Thanks for replying, i've been searching for that in the code and docs but i have not managed to find it, I search again and I try to ask the creator of the library and then I come back to you. – Arnaud PARAN Aug 08 '16 at 14:12