Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Stefane Fermigier
neo
Commits
bff5c82f
Commit
bff5c82f
authored
Oct 02, 2015
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add SSL support
parent
107ca7df
Changes
27
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
320 additions
and
41 deletions
+320
-41
README
README
+19
-12
TODO
TODO
+0
-3
neo.conf
neo.conf
+11
-0
neo/admin/app.py
neo/admin/app.py
+2
-1
neo/client/Storage.py
neo/client/Storage.py
+3
-1
neo/client/component.xml
neo/client/component.xml
+15
-0
neo/lib/app.py
neo/lib/app.py
+26
-1
neo/lib/config.py
neo/lib/config.py
+8
-0
neo/lib/connection.py
neo/lib/connection.py
+7
-0
neo/lib/connector.py
neo/lib/connector.py
+65
-0
neo/master/app.py
neo/master/app.py
+2
-1
neo/master/backup_app.py
neo/master/backup_app.py
+1
-0
neo/neoctl/app.py
neo/neoctl/app.py
+4
-4
neo/neoctl/neoctl.py
neo/neoctl/neoctl.py
+2
-2
neo/scripts/neoctl.py
neo/scripts/neoctl.py
+2
-1
neo/scripts/runner.py
neo/scripts/runner.py
+1
-0
neo/storage/app.py
neo/storage/app.py
+2
-1
neo/tests/__init__.py
neo/tests/__init__.py
+3
-0
neo/tests/ca.crt
neo/tests/ca.crt
+18
-0
neo/tests/create-certs
neo/tests/create-certs
+9
-0
neo/tests/functional/__init__.py
neo/tests/functional/__init__.py
+17
-2
neo/tests/node.crt
neo/tests/node.crt
+16
-0
neo/tests/node.key
neo/tests/node.key
+28
-0
neo/tests/testConnection.py
neo/tests/testConnection.py
+1
-0
neo/tests/threaded/__init__.py
neo/tests/threaded/__init__.py
+11
-5
neo/tests/threaded/test.py
neo/tests/threaded/test.py
+4
-7
neo/tests/threaded/testSSL.py
neo/tests/threaded/testSSL.py
+43
-0
No files found.
README
View file @
bff5c82f
...
...
@@ -40,23 +40,12 @@ There's also a tool to convert back to FileStorage.
See also http://www.neoppod.org/links for more detailed information about
features related to scalability.
Disclaimer
==========
In addition of the disclaimer contained in the licence this code is
released under, please consider the following.
NEO does not implement any authentication mechanism between its nodes, and
does not encrypt data exchanged between nodes either.
If you want to protect your cluster from malicious nodes, or your data from
being snooped, please consider encrypted tunelling (such as openvpn).
Requirements
============
- Linux 2.6 or later
- Python 2.7.x
- Python 2.7.x
(2.7.9 or later for SSL support)
- For storage nodes using MySQL backend:
...
...
@@ -166,6 +155,24 @@ Packs are currently not replicated, which means packing should always be done
up to a TID that is already fully replicated, so that the backup cluster has a
full history (and not random holes).
SSL support
-----------
In addition to any external solution like OpenVPN, NEO has builtin SSL support
to authenticate and encrypt communications between nodes.
All commands and configuration files have options to specify a CA certificate,
the node certificate and the node private key. A certificate can be shared
by several nodes.
NEO always uses the latest SSL protocol supported by the Python interpreter,
without fallback to older versions. A "SSL: WRONG_VERSION_NUMBER" error means
that a node runs in an older environment (Python + OpenSSL) than others.
Note also that you can't mix non-SSL nodes and SSL nodes, even between a
upstream cluster and a backup one. In doing so, connections can get stuck,
or fail with malformed packets or SSL handshake errors.
Deployment
==========
...
...
TODO
View file @
bff5c82f
...
...
@@ -168,6 +168,3 @@
- Investigate delta compression for stored data
Idea would be to have a few most recent revisions being stored fully, and
older revision delta-compressed, in order to save space.
- Consider using multicast for cluster-wide notifications. (BANDWITH)
Currently, multi-receivers notifications are sent in unicast to each
receiver. Multicast should be used.
neo.conf
View file @
bff5c82f
...
...
@@ -43,6 +43,13 @@ partitions: 12
;
upstream_cluster
:
test2
;
upstream_masters
:
127
.
0
.
0
.
1
:
30000
# The 3 following options must be specified to enabled SSL.
# CA should be the same for all nodes, and it can be the concatenation of
# several CAs and CRLs.
;
ca
= ~/
etc
/
ca
.
crt
;
cert
= ~/
etc
/
cert
.
crt
;
key
= ~/
etc
/
cert
.
key
# Individual nodes parameters
# Some parameters makes no sense to be defined in [DEFAULT] section.
# They are:
...
...
@@ -60,6 +67,10 @@ bind: 127.0.0.1:9999
# common section.
;
logfile
: ~/
log
/
admin
.
log
# Nodes can have their own certicates.
;
cert
=
admin
.
crt
;
key
=
admin
.
key
# Master nodes
[
master
]
bind
:
127
.
0
.
0
.
1
:
10000
...
...
neo/admin/app.py
View file @
bff5c82f
...
...
@@ -30,7 +30,8 @@ class Application(BaseApplication):
"""The storage node application."""
def
__init__
(
self
,
config
):
super
(
Application
,
self
).
__init__
(
config
.
getDynamicMasterList
())
super
(
Application
,
self
).
__init__
(
config
.
getSSL
(),
config
.
getDynamicMasterList
())
for
address
in
config
.
getMasters
():
self
.
nm
.
createMaster
(
address
=
address
)
...
...
neo/client/Storage.py
View file @
bff5c82f
...
...
@@ -65,7 +65,9 @@ class Storage(BaseStorage.BaseStorage,
):
setattr
(
self
,
method_id
,
raiseReadOnlyError
)
if
_app
is
None
:
_app
=
Application
(
master_nodes
,
name
,
compress
=
compress
,
**
kw
)
ssl
=
[
kw
.
pop
(
x
,
None
)
for
x
in
(
'ca'
,
'cert'
,
'key'
)]
_app
=
Application
(
master_nodes
,
name
,
compress
=
compress
,
ssl
=
ssl
if
any
(
ssl
)
else
None
,
**
kw
)
self
.
app
=
_app
@
property
...
...
neo/client/component.xml
View file @
bff5c82f
...
...
@@ -39,5 +39,20 @@
be added/removed without requiring a config change each time.
</description>
</key>
<key
name=
"ca"
datatype=
"existing-file"
>
<description>
Certificate authority in PEM format.
</description>
</key>
<key
name=
"cert"
datatype=
"existing-file"
>
<description>
Certificate in PEM format.
</description>
</key>
<key
name=
"key"
datatype=
"existing-file"
>
<description>
Private key in PEM format.
</description>
</key>
</sectiontype>
</component>
neo/lib/app.py
View file @
bff5c82f
...
...
@@ -14,13 +14,38 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from
.
import
logging
from
.event
import
EventManager
from
.node
import
NodeManager
class
BaseApplication
(
object
):
def
__init__
(
self
,
dynamic_master_list
=
None
):
ssl
=
None
def
__init__
(
self
,
ssl
=
None
,
dynamic_master_list
=
None
):
if
ssl
:
if
not
all
(
ssl
):
raise
ValueError
(
"To enable encryption, 3 files must be"
" provided: the CA certificate, and the certificate"
" of this node with its private key."
)
ca
,
cert
,
key
=
ssl
import
ssl
version
,
version_name
=
max
((
getattr
(
ssl
,
k
),
k
)
for
k
in
dir
(
ssl
)
if
k
.
startswith
(
"PROTOCOL_TLSv"
))
self
.
ssl
=
context
=
ssl
.
SSLContext
(
version
)
context
.
options
|=
(
0
|
ssl
.
OP_CIPHER_SERVER_PREFERENCE
|
ssl
.
OP_NO_COMPRESSION
)
context
.
set_ciphers
(
ssl
.
_RESTRICTED_SERVER_CIPHERS
)
context
.
verify_mode
=
ssl
.
CERT_REQUIRED
context
.
load_verify_locations
(
ca
)
context
.
load_cert_chain
(
cert
,
key
)
context
.
verify_flags
|=
ssl
.
VERIFY_X509_STRICT
|
(
context
.
cert_store_stats
()[
'crl'
]
and
ssl
.
VERIFY_CRL_CHECK_LEAF
)
logging
.
info
(
"TLS %s enabled for %s"
,
float
(
version_name
[
13
:].
replace
(
"_"
,
"."
)),
self
)
self
.
_handlers
=
{}
self
.
em
=
EventManager
()
self
.
nm
=
NodeManager
(
dynamic_master_list
)
...
...
neo/lib/config.py
View file @
bff5c82f
...
...
@@ -25,6 +25,9 @@ def getOptionParser():
parser
=
OptionParser
()
parser
.
add_option
(
'-l'
,
'--logfile'
,
help
=
'log debugging information to specified SQLite DB'
)
parser
.
add_option
(
'--ca'
,
help
=
'certificate authority in PEM format'
)
parser
.
add_option
(
'--cert'
,
help
=
'certificate in PEM format'
)
parser
.
add_option
(
'--key'
,
help
=
'private key in PEM format'
)
return
parser
def
getServerOptionParser
():
...
...
@@ -80,6 +83,11 @@ class ConfigurationManager(object):
def
getLogfile
(
self
):
return
self
.
__getPath
(
'logfile'
,
True
)
def
getSSL
(
self
):
r
=
[
self
.
__getPath
(
key
,
True
)
for
key
in
(
'ca'
,
'cert'
,
'key'
)]
if
any
(
r
):
return
r
def
getMasters
(
self
):
""" Get the master node list except itself """
masters
=
self
.
__get
(
'masters'
)
...
...
neo/lib/connection.py
View file @
bff5c82f
...
...
@@ -299,6 +299,7 @@ class ListeningConnection(BaseConnection):
"""A listen connection."""
def
__init__
(
self
,
app
,
handler
,
addr
):
self
.
_ssl
=
app
.
ssl
logging
.
debug
(
'listening to %s:%d'
,
*
addr
)
connector
=
self
.
ConnectorClass
(
addr
)
BaseConnection
.
__init__
(
self
,
app
.
em
,
handler
,
connector
,
addr
)
...
...
@@ -310,6 +311,9 @@ class ListeningConnection(BaseConnection):
logging
.
debug
(
'accepted a connection from %s:%d'
,
*
addr
)
handler
=
self
.
getHandler
()
new_conn
=
ServerConnection
(
self
.
em
,
handler
,
connector
,
addr
)
if
self
.
_ssl
:
connector
.
ssl
(
self
.
_ssl
)
self
.
em
.
addWriter
(
new_conn
)
handler
.
connectionAccepted
(
new_conn
)
def
getAddress
(
self
):
...
...
@@ -580,6 +584,7 @@ class ClientConnection(Connection):
client
=
True
def
__init__
(
self
,
app
,
handler
,
node
):
self
.
_ssl
=
app
.
ssl
addr
=
node
.
getAddress
()
connector
=
self
.
ConnectorClass
(
addr
)
Connection
.
__init__
(
self
,
app
.
em
,
handler
,
connector
,
addr
)
...
...
@@ -619,6 +624,8 @@ class ClientConnection(Connection):
self
.
writable
()
def
_connectionCompleted
(
self
):
if
self
.
_ssl
:
self
.
connector
.
ssl
(
self
.
_ssl
)
self
.
writable
=
self
.
lockWrapper
(
super
(
ClientConnection
,
self
).
writable
)
self
.
connecting
=
False
self
.
updateTimeout
(
time
())
...
...
neo/lib/connector.py
View file @
bff5c82f
...
...
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
socket
import
ssl
import
errno
from
time
import
time
from
.
import
logging
...
...
@@ -109,6 +110,14 @@ class SocketConnector(object):
self
.
socket
.
close
()
self
.
_error
(
'listen'
,
e
)
def
ssl
(
self
,
ssl
):
self
.
socket
=
ssl
.
wrap_socket
(
self
.
socket
,
server_side
=
self
.
is_server
,
do_handshake_on_connect
=
False
,
suppress_ragged_eofs
=
False
)
self
.
__class__
=
self
.
SSLHandshakeConnectorClass
self
.
queued
or
self
.
queued
.
append
(
''
)
def
getError
(
self
):
return
self
.
socket
.
getsockopt
(
socket
.
SOL_SOCKET
,
socket
.
SO_ERROR
)
...
...
@@ -212,6 +221,62 @@ class SocketConnectorIPv6(SocketConnector):
registerConnectorHandler
(
SocketConnectorIPv4
)
registerConnectorHandler
(
SocketConnectorIPv6
)
def
overlay_connector_class
(
cls
):
name
=
cls
.
__name__
[
1
:]
alias
=
name
+
'ConnectorClass'
for
base
in
connector_registry
.
itervalues
():
setattr
(
base
,
alias
,
type
(
name
+
base
.
__name__
,
cls
.
__bases__
+
(
base
,),
cls
.
__dict__
))
return
cls
@
overlay_connector_class
class
_SSL
:
def
_error
(
self
,
op
,
exc
):
if
isinstance
(
exc
,
ssl
.
SSLError
):
logging
.
debug
(
"%s failed for %s: %s"
,
op
,
self
,
exc
)
raise
ConnectorException
SocketConnector
.
_error
(
self
,
op
,
exc
)
def
receive
(
self
,
read_buf
):
try
:
while
1
:
read_buf
.
append
(
self
.
socket
.
recv
(
4096
))
except
ssl
.
SSLWantReadError
:
pass
except
socket
.
error
,
e
:
self
.
_error
(
'recv'
,
e
)
@
overlay_connector_class
class
_SSLHandshake
(
_SSL
):
def
receive
(
self
,
read_buf
=
None
):
# ???Writer | send | receive
# -----------+--------+--------
# want read | remove | -
# want write | - | add
try
:
self
.
socket
.
do_handshake
()
except
ssl
.
SSLWantReadError
:
return
read_buf
is
None
except
ssl
.
SSLWantWriteError
:
return
read_buf
is
not
None
except
socket
.
error
,
e
:
self
.
_error
(
'SSL handshake'
,
e
)
if
not
self
.
queued
[
0
]:
del
self
.
queued
[
0
]
self
.
__class__
=
self
.
SSLConnectorClass
cipher
,
proto
,
bits
=
self
.
socket
.
cipher
()
logging
.
debug
(
"SSL handshake done for %s: %s %s"
,
self
,
cipher
,
bits
)
if
read_buf
is
None
:
return
self
.
send
()
self
.
receive
(
read_buf
)
return
self
.
queued
send
=
receive
class
ConnectorException
(
Exception
):
pass
...
...
neo/master/app.py
View file @
bff5c82f
...
...
@@ -47,7 +47,8 @@ class Application(BaseApplication):
uuid
=
None
def
__init__
(
self
,
config
):
super
(
Application
,
self
).
__init__
(
config
.
getDynamicMasterList
())
super
(
Application
,
self
).
__init__
(
config
.
getSSL
(),
config
.
getDynamicMasterList
())
self
.
tm
=
TransactionManager
(
self
.
onTransactionCommitted
)
self
.
name
=
config
.
getCluster
()
...
...
neo/master/backup_app.py
View file @
bff5c82f
...
...
@@ -74,6 +74,7 @@ class BackupApplication(object):
self
.
nm
.
createMaster
(
address
=
master_address
)
em
=
property
(
lambda
self
:
self
.
app
.
em
)
ssl
=
property
(
lambda
self
:
self
.
app
.
ssl
)
def
close
(
self
):
self
.
nm
.
close
()
...
...
neo/neoctl/app.py
View file @
bff5c82f
...
...
@@ -44,8 +44,8 @@ uuid_int = (lambda ns: lambda uuid:
)({
str
(
k
)[
0
]:
v
for
k
,
v
in
UUID_NAMESPACES
.
iteritems
()})
class
TerminalNeoCTL
(
object
):
def
__init__
(
self
,
address
):
self
.
neoctl
=
NeoCTL
(
address
)
def
__init__
(
self
,
*
args
,
**
kw
):
self
.
neoctl
=
NeoCTL
(
*
args
,
**
kw
)
def
__del__
(
self
):
self
.
neoctl
.
close
()
...
...
@@ -231,8 +231,8 @@ class TerminalNeoCTL(object):
class
Application
(
object
):
"""The storage node application."""
def
__init__
(
self
,
address
):
self
.
neoctl
=
TerminalNeoCTL
(
address
)
def
__init__
(
self
,
*
args
,
**
kw
):
self
.
neoctl
=
TerminalNeoCTL
(
*
args
,
**
kw
)
def
execute
(
self
,
args
):
"""Execute the command given."""
...
...
neo/neoctl/neoctl.py
View file @
bff5c82f
...
...
@@ -27,8 +27,8 @@ class NeoCTL(BaseApplication):
connection
=
None
connected
=
False
def
__init__
(
self
,
address
):
super
(
NeoCTL
,
self
).
__init__
()
def
__init__
(
self
,
address
,
**
kw
):
super
(
NeoCTL
,
self
).
__init__
(
**
kw
)
self
.
server
=
self
.
nm
.
createAdmin
(
address
=
address
)
self
.
handler
=
CommandEventHandler
(
self
)
self
.
response_queue
=
[]
...
...
neo/scripts/neoctl.py
View file @
bff5c82f
...
...
@@ -42,5 +42,6 @@ def main(args=None):
logging
.
setup
(
options
.
logfile
)
from
neo.neoctl.app
import
Application
print
Application
(
address
).
execute
(
args
)
ssl
=
options
.
ca
,
options
.
cert
,
options
.
key
print
Application
(
address
,
ssl
=
ssl
if
any
(
ssl
)
else
None
).
execute
(
args
)
neo/scripts/runner.py
View file @
bff5c82f
...
...
@@ -66,6 +66,7 @@ UNIT_TEST_MODULES = [
'neo.tests.threaded.test'
,
'neo.tests.threaded.testImporter'
,
'neo.tests.threaded.testReplication'
,
'neo.tests.threaded.testSSL'
,
]
FUNC_TEST_MODULES
=
[
...
...
neo/storage/app.py
View file @
bff5c82f
...
...
@@ -41,7 +41,8 @@ class Application(BaseApplication):
"""The storage node application."""
def
__init__
(
self
,
config
):
super
(
Application
,
self
).
__init__
(
config
.
getDynamicMasterList
())
super
(
Application
,
self
).
__init__
(
config
.
getSSL
(),
config
.
getDynamicMasterList
())
# set the cluster name
self
.
name
=
config
.
getCluster
()
...
...
neo/tests/__init__.py
View file @
bff5c82f
...
...
@@ -68,6 +68,9 @@ IP_VERSION_FORMAT_DICT = {
ADDRESS_TYPE
=
socket
.
AF_INET
SSL
=
os
.
path
.
dirname
(
__file__
)
+
os
.
sep
SSL
=
SSL
+
"ca.crt"
,
SSL
+
"node.crt"
,
SSL
+
"node.key"
logging
.
default_root_handler
.
handle
=
lambda
record
:
None
logging
.
backlog
(
None
,
1
<<
20
)
...
...
neo/tests/ca.crt
0 → 100644
View file @
bff5c82f
-----BEGIN CERTIFICATE-----
MIIC7TCCAdWgAwIBAgIJAL8e44sA7PDMMA0GCSqGSIb3DQEBCwUAMA0xCzAJBgNV
BAMMAkNBMB4XDTE1MDkzMDEzNTQzMFoXDTIxMDMyMjEzNTQzMFowDTELMAkGA1UE
AwwCQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgT7DVKM4ViQt3
B0oJC4RGi10dNfpNZZpgA5iC2UJ1u6AqqCf0PCQkrmuIzW3l1TenlOiLNdVASkkT
wf1lekIgg4tR8/22oGTAnfY6R9r1C6jAMV72v1sffz8D6qfkMPzKchJt55zywdhm
KscUsMGzXPGIeKrG20m83dSIO4RmCmq/f4BcuWJu6Kkq4n9Wc2IsvpKk+lqEUxI/
QoqdT6OvMXooGs3t892uvKDu++muBj2Y/yyaXt1tCCjDFsRMLWl3Skks+4PeMCZ4
wugyXEBk3d5Yzdv5NsFzFBjAuRCGxJXEOEcfHj4Xj9qTCErZ1jKzgnuxJCtgdqRC
r4beX1U3AgMBAAGjUDBOMB0GA1UdDgQWBBSFY/jKvo0iSTEzzOIcZZUZCT8JfTAf
BgNVHSMEGDAWgBSFY/jKvo0iSTEzzOIcZZUZCT8JfTAMBgNVHRMEBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQAB0LKDAuhodpyNVwEE9Yl+Q/IiPEPCaix6URJnRn1O
gQnXuZLo1xtJh6wJh1faG1/qNCFMxWEJ+0VkJ7r6v38cNXfYG9OcmD0S6YnNjSuO
VliAtqVVtj8MppJ4vMatLrNi4cvyYucebtNyBCzSIAi+6bkkHeaVgi1EtxXvq+AS
iZp3gl84oXv/gV7Bz4SXmVpFJnhsDMoQZG2KAULAgfZ2Am2I+ffG90cD/oEnS/3O
k3btqTvgIO8MWt8PY3sUOhJEoJYKnC9DppmhOhUTn4zzIIDSluKEOBHZiFb9AcmF
PvzL+8xiORCdUe1d6ANQQlUd0MM810BXZFYEXFbgKg8o
-----END CERTIFICATE-----
neo/tests/create-certs
0 → 100755
View file @
bff5c82f
#!/bin/sh -e
DAYS
=
2000
at_exit
()
{
rm
-f
"
$CAkey
"
;
}
trap
at_exit 0
CAkey
=
`
mktemp
`
openssl req
-new
-x509
-nodes
-keyout
"
$CAkey
"
-out
ca.crt
-subj
/CN
=
CA
-days
$DAYS
openssl req
-new
-nodes
-keyout
node.key
-subj
/CN
=
node |
openssl x509
-CA
ca.crt
-CAkey
"
$CAkey
"
-req
-out
node.crt
-set_serial
1
-days
$DAYS
neo/tests/functional/__init__.py
View file @
bff5c82f
...
...
@@ -38,7 +38,7 @@ from neo.lib.protocol import ClusterStates, NodeTypes, CellStates, NodeStates, \
UUID_NAMESPACES
from
neo.lib.util
import
dump
from
..
import
cluster
,
DB_USER
,
setupMySQLdb
,
NeoTestBase
,
buildUrlFromString
,
\
ADDRESS_TYPE
,
IP_VERSION_FORMAT_DICT
,
getTempDirectory
ADDRESS_TYPE
,
IP_VERSION_FORMAT_DICT
,
getTempDirectory
,
SSL
from
neo.client.Storage
import
Storage
from
neo.storage.database
import
buildDatabaseManager
...
...
@@ -223,6 +223,8 @@ class NEOProcess(object):
class
NEOCluster
(
object
):
SSL
=
None
def
__init__
(
self
,
db_list
,
master_count
=
1
,
partitions
=
1
,
replicas
=
0
,
db_user
=
DB_USER
,
db_password
=
''
,
name
=
None
,
cleanup_on_delete
=
False
,
temp_dir
=
None
,
clear_databases
=
True
,
...
...
@@ -289,7 +291,7 @@ class NEOCluster(object):
self
.
_newProcess
(
NodeTypes
.
STORAGE
,
logger
and
'storage_%u'
%
i
,
0
,
adapter
=
adapter
,
database
=
self
.
db_template
(
db
))
# create neoctl
self
.
neoctl
=
NeoCTL
((
self
.
local_ip
,
admin_port
))
self
.
neoctl
=
NeoCTL
((
self
.
local_ip
,
admin_port
)
,
ssl
=
self
.
SSL
)
def
_newProcess
(
self
,
node_type
,
logfile
=
None
,
port
=
None
,
**
kw
):
self
.
uuid_dict
[
node_type
]
=
uuid
=
1
+
self
.
uuid_dict
.
get
(
node_type
,
0
)
...
...
@@ -301,6 +303,8 @@ class NEOCluster(object):
kw
[
'logfile'
]
=
os
.
path
.
join
(
self
.
temp_dir
,
logfile
+
'.log'
)
if
port
is
not
None
:
kw
[
'bind'
]
=
'%s:%u'
%
(
buildUrlFromString
(
self
.
local_ip
),
port
)
if
self
.
SSL
:
kw
[
'ca'
],
kw
[
'cert'
],
kw
[
'key'
]
=
self
.
SSL
self
.
process_dict
.
setdefault
(
node_type
,
[]).
append
(
NEOProcess
(
command_dict
[
node_type
],
uuid
,
kw
))
...
...
@@ -402,6 +406,8 @@ class NEOCluster(object):
def
getZODBStorage
(
self
,
**
kw
):
master_nodes
=
self
.
master_nodes
.
replace
(
'/'
,
' '
)
if
self
.
SSL
:
kw
[
'ca'
],
kw
[
'cert'
],
kw
[
'key'
]
=
self
.
SSL
result
=
Storage
(
master_nodes
=
master_nodes
,
name
=
self
.
cluster_name
,
...
...
@@ -633,6 +639,15 @@ class NEOCluster(object):
class
NEOFunctionalTest
(
NeoTestBase
):
def
setUp
(
self
):
if
random
.
randint
(
0
,
1
):
NEOCluster
.
SSL
=
SSL
super
(
NEOFunctionalTest
,
self
).
setUp
()
def
_tearDown
(
self
,
success
):
super
(
NEOFunctionalTest
,
self
).
_tearDown
(
success
)
NEOCluster
.
SSL
=
None
def
setupLog
(
self
):
logging
.
setup
(
os
.
path
.
join
(
self
.
getTempDirectory
(),
'test.log'
))
...
...
neo/tests/node.crt
0 → 100644
View file @
bff5c82f
-----BEGIN CERTIFICATE-----
MIICkDCCAXgCAQEwDQYJKoZIhvcNAQELBQAwDTELMAkGA1UEAwwCQ0EwHhcNMTUw
OTMwMTM1NDMwWhcNMjEwMzIyMTM1NDMwWjAPMQ0wCwYDVQQDDARub2RlMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJ+ClJyjhJOJdGUyqHn79opMLP3m
1g27uBWKT+OGd4FcreVoRDxPVuxZxMtDCZcBfUHVvOoSlS06khwSxViEe1hxwHRa
n2qMWlwvaWeNY0CFH5V+DI4XSNojgny85Lb5jB69FuPcrHnwxLk2OFntrXEeNbEa
d7QSoNbPajbJIp5BS/WR9iu5Z5JYdumLWjTvOU+eZc4iA6Wa2kdDtbqkGi4wOJ1L
/ggATL+p+QFcubVptztPT8vq7gvDdGJgXLJ2lPHV0V/sdJB1FB4mSJEDDjSm2Hpp
qPVJSO1GrAy5Ld+0SnXIZZejhIUJIumocY08r+vzDSQ/8NnqXR4Odz1TWwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4IBAQBlYkkInDDDcgnNRdUmzxwejs1PmEehZ3H5FkMp
TsmpoVC+oqM+QywMu8UJRtCjXnnJdAUbVYuZ1Tjm7qvFIhN+5OlIVxJ+8WcmZPSe
lj0N7Dv2nE1diTDS+qPZVPZ0demo1LafRmPomPWiM/CQRlMPxXnimuiYOROhWGn6
jsyoOwquMkAc6Ub++l4OCxLAP0eTgJFkivmqpaYZXG4o7zFvcQ3rQ66rQrMl69sR
8/MVqbT5Sq1CEJbepP4GaFfa5l3CVy7WH2MhCV1/9mNwcXafkTgx3q2HsPon4Dze
kNwiguNAM4L/j4dbIwz+CIVWcgpBCrfv2JYu+jGlRpxIDeWR
-----END CERTIFICATE-----
neo/tests/node.key
0 → 100644
View file @
bff5c82f
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4n4KUnKOEk4l0
ZTKoefv2ikws/ebWDbu4FYpP44Z3gVyt5WhEPE9W7FnEy0MJlwF9QdW86hKVLTqS
HBLFWIR7WHHAdFqfaoxaXC9pZ41jQIUflX4MjhdI2iOCfLzktvmMHr0W49ysefDE
uTY4We2tcR41sRp3tBKg1s9qNskinkFL9ZH2K7lnklh26YtaNO85T55lziIDpZra
R0O1uqQaLjA4nUv+CABMv6n5AVy5tWm3O09Py+ruC8N0YmBcsnaU8dXRX+x0kHUU
HiZIkQMONKbYemmo9UlI7UasDLkt37RKdchll6OEhQki6ahxjTyv6/MNJD/w2epd
Hg53PVNbAgMBAAECggEACCWh0YUIAjWwfx5oGd8oKzz3F5Usto1slzb8H4Je0K84
s8PH0hsHNULAw1pk3ut2+VwKXofFwid4yjHK8kJxti+09VUtGpPNFb+zp+cV6idS
uI4UPeGXTXOy1XNDsqQQZwqENZpghovrAANcTShKwLiZKK1kCZw8pjRUes9oGMrn
zLXvNPgpJbRUPPYFa34jJyaJtiBEgIBWBmAeEk4ccTYFk4Kon93Ljmobm/6H8WZE
bxomzJjFVMSjW/NmMWnalX5H7GegJVOtkOGvHf25dHBdbdU772ReY4PRZJEGwn8E
QcZjzaKkLB34IlbjWjH0nnanNa6DyjhulaqkHjAtIQKBgQDf3zPefVHss4FrajU8
Nvch6mpayOeJ3RzOAiMzmfI/O3zcJqqrlOOKQjvP5feAoLOJTcvu4hAMfUix/7LR
Qag5nALIllox6QnoMWmvKUbcekXunf/PUVFQ7SC3RJKtqh5oq5wRGJWcDPP6/Okk
t+64NeQOT3lPs2LNyy7KpB5YlQKBgQDTHln2fYKCLnJ66+3QPjDSJrwdUD6HFiwp
X5BfNUKpnxged+buFbgp5TB2vu6Z5A3AxwmWXBFiuvHLpl3uSAEIRbFQ+elagUXa
BoiPOnq1b00X/Vdkd3sX4czVemIG9DIA1uo31Gd9fFWMLHZGBOwqgNKiJOgQZXTq
dX/tAGrQLwKBgGt59aXf1j/j4cMWxx30aWq/5nVVNEtsetKwFgRE6RbQUV5DtfYP
0bljmOFzTwJSpD7LuZcisn+8efTyg/+QHNojevafsAd8EISHjGxKTbm1ffNTqSb3
rClE3kr9wclb/aNUl+VhPxoe4dbiKm+1WgbX4He6Ucwgm9OeswUYC3WNAoGAK1i/
/+wlL7V5q+NlIKykOYHafepL7FCRIK2OZv34gfs4aIkV0SyEc5WrLbZmJxK8ACjd
vxGIQE1B+B5gitwd2iT1Ezs8vmhsfyd4QnAvYbFIkvRhTS97BpxGAk7ucZ8R5To7
PNtPpGQy7GT0o8u+8bshhEkvnK44Iyuc6Hx9ceECgYAjM1jEreHzi96v8pmneJja
VIoNNu2PoTS1nTWN+/6//B62GxpKM5UCYZDRDC8urPXb6tXSC29I104yrNJQEGXz
/acVGnA6GJV639pXz++hf2NMHKandlKY+Cz2euZT/qUU80W+B5korsubIS6ATeee
+QU2yqNaC1ZvTO2L1OLYRg==
-----END PRIVATE KEY-----
neo/tests/testConnection.py
View file @
bff5c82f
...
...
@@ -56,6 +56,7 @@ class ConnectionTests(NeoUnitTestBase):
def
setUp
(
self
):
NeoUnitTestBase
.
setUp
(
self
)
self
.
app
=
Mock
({
'__repr__'
:
'Fake App'
})
self
.
app
.
ssl
=
None
self
.
em
=
self
.
app
.
em
=
Mock
({
'__repr__'
:
'Fake Em'
})
self
.
handler
=
Mock
({
'__repr__'
:
'Fake Handler'
})
self
.
address
=
(
"127.0.0.7"
,
93413
)
...
...
neo/tests/threaded/__init__.py
View file @
bff5c82f
...
...
@@ -502,6 +502,8 @@ class ConnectionFilter(object):
class
NEOCluster
(
object
):
SSL
=
None
def
__init__
(
orig
,
self
):
# temporary definition for SimpleQueue patch
orig
(
self
)
lock
=
self
.
_lock
...
...
@@ -563,7 +565,8 @@ class NEOCluster(object):
self
.
master_nodes
=
' '
.
join
(
'%s:%s'
%
x
for
x
in
master_list
)
weak_self
=
weakref
.
proxy
(
self
)
kw
=
dict
(
cluster
=
weak_self
,
getReplicas
=
replicas
,
getAdapter
=
adapter
,
getPartitions
=
partitions
,
getReset
=
clear_databases
)
getPartitions
=
partitions
,
getReset
=
clear_databases
,
getSSL
=
self
.
SSL
)
if
upstream
is
not
None
:
self
.
upstream
=
weakref
.
proxy
(
upstream
)
kw
.
update
(
getUpstreamCluster
=
upstream
.
name
,
...
...
@@ -600,7 +603,7 @@ class NEOCluster(object):
self
.
storage_list
=
[
StorageApplication
(
getDatabase
=
db
%
x
,
**
kw
)
for
x
in
db_list
]
self
.
admin_list
=
[
AdminApplication
(
**
kw
)]
self
.
neoctl
=
NeoCTL
(
self
.
admin
.
getVirtualAddress
())
self
.
neoctl
=
NeoCTL
(
self
.
admin
.
getVirtualAddress
()
,
ssl
=
self
.
SSL
)
def
__repr__
(
self
):
return
"<%s(%s) at 0x%x>"
%
(
self
.
__class__
.
__name__
,
...
...
@@ -634,7 +637,7 @@ class NEOCluster(object):
for
node
in
getattr
(
self
,
node_type
+
'_list'
):
node
.
resetNode
(
**
kw
)
self
.
neoctl
.
close
()
self
.
neoctl
=
NeoCTL
(
self
.
admin
.
getVirtualAddress
())
self
.
neoctl
=
NeoCTL
(
self
.
admin
.
getVirtualAddress
()
,
ssl
=
self
.
SSL
)
def
start
(
self
,
storage_list
=
None
,
fast_startup
=
False
):
self
.
_patch
()
...
...
@@ -656,10 +659,13 @@ class NEOCluster(object):
assert
state
in
(
ClusterStates
.
RUNNING
,
ClusterStates
.
BACKINGUP
),
state
self
.
enableStorageList
(
storage_list
)
def
newClient
(
self
):
return
ClientApplication
(
name
=
self
.
name
,
master_nodes
=
self
.
master_nodes
,
compress
=
self
.
compress
,
ssl
=
self
.
SSL
)
@
cached_property
def
client
(
self
):
client
=
ClientApplication
(
name
=
self
.
name
,
master_nodes
=
self
.
master_nodes
,
compress
=
self
.
compress
)
client
=
self
.
newClient
()
# Make sure client won't be reused after it was closed.
def
close
():
client
=
self
.
client
...
...
neo/tests/threaded/test.py
View file @
bff5c82f
...
...
@@ -29,7 +29,7 @@ from neo.lib.connection import ConnectionClosed, MTClientConnection
from
neo.lib.protocol
import
CellStates
,
ClusterStates
,
NodeStates
,
Packets
,
\
ZERO_TID
from
..
import
expectedFailure
,
_UnexpectedSuccess
,
Patch
from
.
import
ClientApplication
,
NEOCluster
,
NEOThreadedTest
from
.
import
NEOCluster
,
NEOThreadedTest
from
neo.lib.util
import
add64
,
makeChecksum
from
neo.client.exception
import
NEOStorageError
from
neo.client.pool
import
CELL_CONNECTED
,
CELL_GOOD
...
...
@@ -601,8 +601,7 @@ class Test(NEOThreadedTest):
# (at this time, we still have x=0 and y=1)
t2
,
c2
=
cluster
.
getTransaction
()
# Copy y to x using a different Master-Client connection
client
=
ClientApplication
(
name
=
cluster
.
name
,
master_nodes
=
cluster
.
master_nodes
)
client
=
cluster
.
newClient
()
txn
=
transaction
.
Transaction
()
client
.
tpc_begin
(
txn
)
client
.
store
(
x1
.
_p_oid
,
x1
.
_p_serial
,
y
,
''
,
txn
)
...
...
@@ -715,8 +714,7 @@ class Test(NEOThreadedTest):
self
.
tic
()
# modify x with another client
client
=
ClientApplication
(
name
=
cluster
.
name
,
master_nodes
=
cluster
.
master_nodes
)
client
=
cluster
.
newClient
()
txn
=
transaction
.
Transaction
()
client
.
tpc_begin
(
txn
)
client
.
store
(
x1
.
_p_oid
,
x1
.
_p_serial
,
y
,
''
,
txn
)
...
...
@@ -804,8 +802,7 @@ class Test(NEOThreadedTest):
with
cluster
.
master
.
filterConnection
(
cluster
.
storage
)
as
m2s
:
m2s
.
add
(
delayNotifyInformation
)
cluster
.
client
.
master_conn
.
close
()
client
=
ClientApplication
(
name
=
cluster
.
name
,
master_nodes
=
cluster
.
master_nodes
)
client
=
cluster
.
newClient
()
p
=
Patch
(
client
.
storage_bootstrap_handler
,
notReady
=
notReady
)
try
:
p
.
apply
()
...
...
neo/tests/threaded/testSSL.py
0 → 100644
View file @
bff5c82f
#
# Copyright (C) 2015 Nexedi SA
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import
unittest
from
..
import
SSL
from
.
import
NEOCluster
,
test
,
testReplication
class
SSLMixin
:
@
classmethod
def
setUpClass
(
cls
):
NEOCluster
.
SSL
=
SSL
@
classmethod
def
tearDownClass
(
cls
):
NEOCluster
.
SSL
=
None
class
SSLTests
(
SSLMixin
,
test
.
Test
):
# exclude expected failures
testDeadlockAvoidance
=
testStorageFailureDuringTpcFinish
=
None
class
SSLReplicationTests
(
SSLMixin
,
testReplication
.
ReplicationTests
):
# do not repeat slowest tests with SSL
testBackupNodeLost
=
testBackupNormalCase
=
None
if
__name__
==
"__main__"
:
unittest
.
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment