Piotr Kliczewski has uploaded a new change for review.

Change subject: ssl: configurable implementation
......................................................................

ssl: configurable implementation

We want to choose ssl implementation during build process.

Change-Id: I6501981bbd5276c49731b0d9eba4794286b0f823
Signed-off-by: pkliczewski <[email protected]>
---
M debian/vdsm-python.install
M lib/vdsm/Makefile.am
M lib/vdsm/jsonrpcvdscli.py
A lib/vdsm/sslutils.py
M lib/vdsm/utils.py
M lib/vdsm/vdscli.py
M lib/yajsonrpc/stompreactor.py
M tests/crossImportsTests.py.in
M tests/integration/Makefile.am
M tests/integration/jsonRpcHelper.py
M tests/integration/m2chelper.py
A tests/integration/sslhelper.py
M tests/protocoldetectorTests.py
M tests/sslTests.py
M tests/stompTests.py
M tests/vdscliTests.py
M vdsm.spec.in
M vdsm/clientIF.py
M vdsm/kaxmlrpclib.py
M vdsm/protocoldetector.py
M vdsm/virt/migration.py
21 files changed, 562 insertions(+), 88 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/94/44494/1

diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install
index 36c0d9f..d9402c3 100644
--- a/debian/vdsm-python.install
+++ b/debian/vdsm-python.install
@@ -12,7 +12,6 @@
 ./usr/lib/python2.7/dist-packages/vdsm/ipwrapper.py
 ./usr/lib/python2.7/dist-packages/vdsm/jsonrpcvdscli.py
 ./usr/lib/python2.7/dist-packages/vdsm/libvirtconnection.py
-./usr/lib/python2.7/dist-packages/vdsm/m2cutils.py
 ./usr/lib/python2.7/dist-packages/vdsm/netconfpersistence.py
 ./usr/lib/python2.7/dist-packages/vdsm/netinfo.py
 ./usr/lib/python2.7/dist-packages/vdsm/netlink/__init__.py
@@ -30,6 +29,7 @@
 ./usr/lib/python2.7/dist-packages/vdsm/qemuimg.py
 ./usr/lib/python2.7/dist-packages/vdsm/response.py
 ./usr/lib/python2.7/dist-packages/vdsm/schedule.py
+./usr/lib/python2.7/dist-packages/vdsm/sslutils.py
 ./usr/lib/python2.7/dist-packages/vdsm/tool/__init__.py
 ./usr/lib/python2.7/dist-packages/vdsm/tool/dummybr.py
 ./usr/lib/python2.7/dist-packages/vdsm/tool/dump_bonding_defaults.py
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index ec1a140..4a2bcb1 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -40,6 +40,7 @@
        qemuimg.py \
        response.py \
        schedule.py \
+       sslutils.py \
        sysctl.py \
        udevadm.py \
        utils.py \
diff --git a/lib/vdsm/jsonrpcvdscli.py b/lib/vdsm/jsonrpcvdscli.py
index 1687b6f..391d79e 100644
--- a/lib/vdsm/jsonrpcvdscli.py
+++ b/lib/vdsm/jsonrpcvdscli.py
@@ -22,7 +22,6 @@
 from uuid import uuid4
 import socket
 
-from . import m2cutils
 from yajsonrpc import stompreactor
 from yajsonrpc import \
     JsonRpcRequest, \
@@ -30,6 +29,10 @@
 
 from vdsm import response
 from .config import config
+try:
+    from . import m2cutils as sslutils
+except ImportError:
+    from . import sslutils
 
 
 _COMMAND_CONVERTER = {
diff --git a/lib/vdsm/sslutils.py b/lib/vdsm/sslutils.py
new file mode 100644
index 0000000..63fc9cc
--- /dev/null
+++ b/lib/vdsm/sslutils.py
@@ -0,0 +1,302 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from __future__ import absolute_import
+import httplib
+import logging
+import os
+import socket
+import ssl
+import xmlrpclib
+
+from vdsm.utils import (
+    monotonic_time,
+)
+from .config import config
+
+
+DEFAULT_ACCEPT_TIMEOUT = 5
+SOCKET_DEFAULT_TIMEOUT = socket._GLOBAL_DEFAULT_TIMEOUT
+
+
+class SSLSocket(object):
+    def __init__(self, sock):
+        self.sock = sock
+        self._data = ''
+
+    # ssl do not accept flag other than 0
+    def read(self, size=4096, flag=None):
+        result = None
+        if flag == socket.MSG_PEEK:
+            bytes_left = size - len(self._data)
+            if bytes_left > 0:
+                self._data += self.sock.read(bytes_left)
+            result = self._data
+        else:
+            if self._data:
+                result = self._data
+                self._data = ''
+            else:
+                result = self.sock.read(size)
+        return result
+    recv = read
+
+    def pending(self):
+        pending = self.sock.pending()
+        if self._data:
+            pending = pending + len(self._data)
+        return pending
+
+    def __getattr__(self, name):
+        return getattr(self.sock, name)
+
+    def makefile(self, mode='rb', bufsize=-1):
+        if mode == 'rb':
+            return socket._fileobject(self, mode, bufsize)
+        else:
+            return self.sock.makefile(mode, bufsize)
+
+
+class SSLContext(object):
+    def __init__(self, cert_file, key_file, ca_certs=None,
+                 protocol=ssl.PROTOCOL_TLSv1):
+        self.cert_file = cert_file
+        self.key_file = key_file
+        self.ca_certs = ca_certs
+        self.protocol = protocol
+
+
+class VerifyingHTTPSConnection(httplib.HTTPSConnection):
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=SOCKET_DEFAULT_TIMEOUT,
+                 ca_certs=None, cert_reqs=ssl.CERT_REQUIRED):
+        httplib.HTTPSConnection.__init__(self, host, port, key_file, cert_file,
+                                         strict, timeout)
+        self.ca_certs = ca_certs
+        self.cert_reqs = cert_reqs
+
+    def connect(self):
+        "Connect to a host on a given (SSL) port."
+
+        sock = socket.create_connection((self.host, self.port), self.timeout)
+        if self._tunnel_host:
+            self.sock = sock
+            self._tunnel()
+        # DK added: pass ca_cert to sslsocket
+        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
+                                    ca_certs=self.ca_certs, server_side=False,
+                                    cert_reqs=self.cert_reqs)
+
+
+class VerifyingSafeTransport(xmlrpclib.SafeTransport):
+    def __init__(self, use_datetime=0, key_file=None, cert_file=None,
+                 ca_certs=None, cert_reqs=ssl.CERT_REQUIRED,
+                 timeout=SOCKET_DEFAULT_TIMEOUT):
+        xmlrpclib.SafeTransport.__init__(self, use_datetime)
+        self.key_file = key_file
+        self.cert_file = cert_file
+        self.ca_certs = ca_certs
+        self.cert_reqs = cert_reqs
+        self._timeout = timeout
+
+    def make_connection(self, host):
+        """Return VerifyingHTTPS object that is aware of ca_certs, and will
+        create VerifyingHTTPSConnection.
+        In Python 2.7, return VerifyingHTTPSConnection object
+        """
+        chost, self._extra_headers, x509 = self.get_host_info(host)
+        if hasattr(xmlrpclib.SafeTransport, "single_request"):   # Python 2.7
+            return VerifyingHTTPSConnection(
+                chost, None, key_file=self.key_file, strict=None,
+                cert_file=self.cert_file, timeout=self._timeout,
+                ca_certs=self.ca_certs,
+                cert_reqs=self.cert_reqs)
+        else:
+            return VerifyingHTTPS(
+                chost, None, key_file=self.key_file,
+                cert_file=self.cert_file, timeout=self._timeout,
+                ca_certs=self.ca_certs,
+                cert_reqs=self.cert_reqs)
+
+
+class VerifyingHTTPS(httplib.HTTPS):
+    _connection_class = VerifyingHTTPSConnection
+
+    def __init__(self, host='', port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=SOCKET_DEFAULT_TIMEOUT,
+                 ca_certs=None, cert_reqs=ssl.CERT_REQUIRED):
+        """A ca_cert-aware HTTPS object,
+        that creates a VerifyingHTTPSConnection
+        """
+        # provide a default host, pass the X509 cert info
+
+        # urf. compensate for bad input.
+        if port == 0:
+            port = None
+        self._setup(self._connection_class(host=host,
+                                           port=port,
+                                           key_file=key_file,
+                                           cert_file=cert_file,
+                                           strict=strict,
+                                           timeout=timeout,
+                                           ca_certs=ca_certs,
+                                           cert_reqs=cert_reqs))
+
+        # we never actually use these for anything, but we keep them
+        # here for compatibility with post-1.5.2 CVS.
+        self.key_file = key_file
+        self.cert_file = cert_file
+
+
+class SSLHandshakeDispatcher(object):
+    """
+    SSLHandshakeDispatcher is dispatcher implementation to process ssl
+    handshake in asynchronous way. Once we are done with handshaking we
+    we need to swap our dispatcher implementation with message processing
+    dispatcher. We use handshake_finished_handler function to perform
+    swapping. The handler implementation need to invoke
+
+    dispatcher.switch_implementation()
+
+    where we provide message processing dispatcher as parameter.
+    """
+    log = logging.getLogger("ProtocolDetector.SSLHandshakeDispatcher")
+    SSL_HANDSHAKE_TIMEOUT = 10
+
+    def __init__(
+        self,
+        sslinfo,
+        handshake_finished_handler,
+        handshake_timeout=SSL_HANDSHAKE_TIMEOUT,
+    ):
+        self._give_up_at = monotonic_time() + handshake_timeout
+        self._has_been_set_up = False
+        self._is_handshaking = True
+        self.want_read = True
+        self.want_write = True
+        self._sslinfo = sslinfo
+        self._handshake_finished_handler = handshake_finished_handler
+
+    def _set_up_socket(self, dispatcher):
+        client_socket = dispatcher.socket
+        client_socket = SSLSocket(
+            ssl.wrap_socket(client_socket,
+                            keyfile=self._sslinfo.key_file,
+                            certfile=self._sslinfo.cert_file,
+                            server_side=True,
+                            cert_reqs=ssl.CERT_REQUIRED,
+                            ssl_version=self._sslinfo.protocol,
+                            ca_certs=self._sslinfo.ca_certs,
+                            do_handshake_on_connect=False))
+
+        dispatcher.socket = client_socket
+        self._has_been_set_up = True
+
+    def next_check_interval(self):
+        return max(self._give_up_at - monotonic_time(), 0)
+
+    def readable(self, dispatcher):
+        if self.has_expired():
+            dispatcher.close()
+            return False
+
+        return self.want_read
+
+    def writable(self, dispatcher):
+        if self.has_expired():
+            dispatcher.close()
+            return False
+
+        return self.want_write
+
+    def has_expired(self):
+        return monotonic_time() >= self._give_up_at
+
+    def handle_read(self, dispatcher):
+        self._handle_io(dispatcher)
+
+    def handle_write(self, dispatcher):
+        self._handle_io(dispatcher)
+
+    def _handle_io(self, dispatcher):
+        if not self._has_been_set_up:
+            self._set_up_socket(dispatcher)
+
+        if self._is_handshaking:
+            self._handshake(dispatcher)
+        else:
+            if not self._verify_host(dispatcher.socket.getpeercert(),
+                                     dispatcher.socket.getpeername()[0]):
+                self.log.error("peer certificate does not match host name")
+                dispatcher.socket.close()
+                return
+
+            self._handshake_finished_handler(dispatcher)
+
+    def _verify_host(self, peercert, addr):
+        if not peercert:
+            return False
+
+        for sub in peercert.get("subject", ()):
+            for key, value in sub:
+                if key == "commonName":
+                    return self._compare_names(addr, value)
+
+        return False
+
+    def _compare_names(self, addr, name):
+        if addr == name or addr == '127.0.0.1':
+            return True
+        else:
+            return name.lower() == socket.gethostbyaddr(addr)[0].lower()
+
+    def _handshake(self, dispatcher):
+        try:
+            dispatcher.socket.do_handshake()
+        except ssl.SSLError as err:
+            self.want_read = self.want_write = False
+            if err.args[0] == ssl.SSL_ERROR_WANT_READ:
+                self.want_read = True
+            elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
+                self.want_write = True
+            else:
+                dispatcher.close()
+                raise
+        else:
+            self.want_read = self.want_write = True
+            self._is_handshaking = False
+
+
+def create_ssl_context():
+        sslinfo = None
+        if config.getboolean('vars', 'ssl'):
+            truststore_path = config.get('vars', 'trust_store_path')
+            protocol = (
+                ssl.PROTOCOL_SSLv23
+                if config.get('vars', 'ssl_protocol') == 'sslv23'
+                else ssl.PROTOCOL_TLSv1
+            )
+            sslinfo = SSLContext(
+                key_file=os.path.join(truststore_path, 'keys', 'vdsmkey.pem'),
+                cert_file=os.path.join(truststore_path, 'certs',
+                                       'vdsmcert.pem'),
+                ca_certs=os.path.join(truststore_path, 'certs', 'cacert.pem'),
+                protocol=protocol
+            )
+        return sslinfo
diff --git a/lib/vdsm/utils.py b/lib/vdsm/utils.py
index d847a23..b7818eb 100644
--- a/lib/vdsm/utils.py
+++ b/lib/vdsm/utils.py
@@ -54,11 +54,16 @@
 import threading
 import time
 import vdsm.infra.zombiereaper as zombiereaper
-from M2Crypto import SSL
 
 from cpopen import CPopen
 from . import cmdutils
 from . import constants
+try:
+    from M2Crypto import SSL
+    _m2cEnabled = True
+except ImportError:
+    import ssl
+    _m2cEnabled = False
 
 try:
     # If failing to import old code, then try importing the legacy code
@@ -1251,11 +1256,18 @@
 
 
 def create_connected_socket(host, port, sslctx=None, timeout=None):
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     if sslctx:
-        sock = SSL.Connection(sslctx.context)
-    else:
-        sock = socket.socket(socket.AF_INET,
-                             socket.SOCK_STREAM)
+        if _m2cEnabled:
+            sock = SSL.Connection(sslctx.context)
+        else:
+            sock = ssl.wrap_socket(sock,
+                                   keyfile=sslctx.key_file,
+                                   certfile=sslctx.cert_file,
+                                   server_side=False,
+                                   cert_reqs=ssl.CERT_REQUIRED,
+                                   ssl_version=sslctx.protocol,
+                                   ca_certs=sslctx.ca_certs)
     sock.settimeout(timeout)
     sock.connect((host, port))
     return sock
diff --git a/lib/vdsm/vdscli.py b/lib/vdsm/vdscli.py
index a78a67a..cf083e3 100644
--- a/lib/vdsm/vdscli.py
+++ b/lib/vdsm/vdscli.py
@@ -26,7 +26,10 @@
 import re
 import sys
 from xml.parsers.expat import ExpatError
-from . import m2cutils
+try:
+    from . import m2cutils as sslutils
+except ImportError:
+    from . import sslutils
 
 
 _USE_SSL = False
@@ -60,7 +63,7 @@
             self.timeout = kwargs['timeout']
             del kwargs['timeout']
         else:
-            self.timeout = m2cutils.SOCKET_DEFAULT_TIMEOUT
+            self.timeout = sslutils.SOCKET_DEFAULT_TIMEOUT
 
         xmlrpclib.Transport.__init__(self, *args, **kwargs)
 
@@ -107,8 +110,8 @@
 
 
 def connect(hostPort=None, useSSL=None, tsPath=None,
-            TransportClass=m2cutils.VerifyingSafeTransport,
-            timeout=m2cutils.SOCKET_DEFAULT_TIMEOUT):
+            TransportClass=sslutils.VerifyingSafeTransport,
+            timeout=sslutils.SOCKET_DEFAULT_TIMEOUT):
 
     hostPort = cannonizeHostPort(hostPort)
     if useSSL is None:
diff --git a/lib/yajsonrpc/stompreactor.py b/lib/yajsonrpc/stompreactor.py
index ee710f5..5dfa805 100644
--- a/lib/yajsonrpc/stompreactor.py
+++ b/lib/yajsonrpc/stompreactor.py
@@ -23,10 +23,14 @@
 from vdsm import utils
 from vdsm.config import config
 from vdsm.compat import json
-from vdsm.m2cutils import SSLSocket
 from . import JsonRpcClient, JsonRpcServer
 from . import stomp
 from .betterAsyncore import Dispatcher, Reactor
+try:
+    from vdsm.m2cutils import SSLSocket
+except ImportError:
+    from ssl import SSLSocket
+
 
 _STATE_LEN = "Waiting for message length"
 _STATE_MSG = "Waiting for message"
diff --git a/tests/crossImportsTests.py.in b/tests/crossImportsTests.py.in
index a3e1d81..a997211 100644
--- a/tests/crossImportsTests.py.in
+++ b/tests/crossImportsTests.py.in
@@ -51,4 +51,7 @@
         else:
             mods = get_mods(os.path.join(get_python_lib(), pkg_name))
 
+        # ignore M2Crypto
+        mods.remove('m2cutils')
+
         __import__(pkg_name, fromlist=mods)
diff --git a/tests/integration/Makefile.am b/tests/integration/Makefile.am
index 525ddd8..7fd327d 100644
--- a/tests/integration/Makefile.am
+++ b/tests/integration/Makefile.am
@@ -25,4 +25,5 @@
        jsonRpcHelper.py \
        jsonRpcTests.py \
        m2chelper.py \
+       sslhelper.py \
        $(NULL)
diff --git a/tests/integration/jsonRpcHelper.py 
b/tests/integration/jsonRpcHelper.py
index 65ec5e3..fbb74c1 100644
--- a/tests/integration/jsonRpcHelper.py
+++ b/tests/integration/jsonRpcHelper.py
@@ -37,7 +37,10 @@
 from protocoldetector import MultiProtocolAcceptor
 from rpc.bindingjsonrpc import BindingJsonRpc
 from vdsm import utils
-from m2chelper import DEAFAULT_SSL_CONTEXT
+try:
+    from integration.m2chelper import DEAFAULT_SSL_CONTEXT
+except ImportError:
+    from integration.sslhelper import DEAFAULT_SSL_CONTEXT
 
 PERMUTATIONS = tuple(product((True, False), ("xml", "stomp")))
 
diff --git a/tests/integration/m2chelper.py b/tests/integration/m2chelper.py
index 77a2767..7ece453 100644
--- a/tests/integration/m2chelper.py
+++ b/tests/integration/m2chelper.py
@@ -17,9 +17,11 @@
 #
 # Refer to the README and COPYING files for full details of the license
 #
-
 import os
-from vdsm.m2cutils import SSLContext
+import SimpleXMLRPCServer
+import threading
+from M2Crypto import SSL
+from vdsm.m2cutils import SSLContext, SSLServerSocket
 
 CERT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..')
 CRT_FILE = os.path.join(CERT_DIR, "server.crt")
@@ -29,3 +31,43 @@
 
 DEAFAULT_SSL_CONTEXT = SSLContext(
     CRT_FILE, KEY_FILE, session_id="server-tests")
+
+
+def get_server_socket(key_file, cert_file, socket):
+    return SSLServerSocket(raw=socket,
+                           keyfile=key_file,
+                           certfile=cert_file,
+                           ca_certs=cert_file)
+
+
+class TestServer():
+
+    def __init__(self, host, service):
+        self.server = SimpleXMLRPCServer.SimpleXMLRPCServer((host, 0),
+                                                            logRequests=False)
+        self.server.socket = SSLServerSocket(raw=self.server.socket,
+                                             keyfile=KEY_FILE,
+                                             certfile=CRT_FILE,
+                                             ca_certs=CRT_FILE)
+        _, self.port = self.server.socket.getsockname()
+        self.server.register_instance(service)
+
+    def start(self):
+        self.thread = threading.Thread(target=self.serve_forever)
+        self.thread.daemon = True
+        self.thread.start()
+
+    def serve_forever(self):
+        try:
+            self.server.serve_forever()
+        except SSL.SSLError:
+            # expected sslerror is thrown in server side during test_invalid
+            # method we do not want to pollute test console output
+            pass
+
+    def stop(self):
+        self.server.shutdown()
+
+    def get_timeout(self):
+        self.server.socket.accept_timeout = 1
+        return self.server.socket.accept_timeout + 1
diff --git a/tests/integration/sslhelper.py b/tests/integration/sslhelper.py
new file mode 100644
index 0000000..acc2516
--- /dev/null
+++ b/tests/integration/sslhelper.py
@@ -0,0 +1,82 @@
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+import os
+import SimpleXMLRPCServer
+import ssl
+import threading
+from vdsm.sslutils import SSLContext
+
+CERT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..')
+CRT_FILE = os.path.join(CERT_DIR, "server.crt")
+KEY_FILE = os.path.join(CERT_DIR, "server.key")
+OTHER_CRT_FILE = os.path.join(CERT_DIR, "other.crt")
+OTHER_KEY_FILE = os.path.join(CERT_DIR, "other.key")
+
+DEAFAULT_SSL_CONTEXT = SSLContext(cert_file=CRT_FILE, key_file=KEY_FILE,
+                                  ca_certs=CRT_FILE)
+
+
+def get_server_socket(key_file, cert_file, socket):
+    return ssl.wrap_socket(socket,
+                           keyfile=key_file,
+                           certfile=cert_file,
+                           server_side=False,
+                           cert_reqs=ssl.CERT_REQUIRED,
+                           ssl_version=ssl.PROTOCOL_TLSv1,
+                           ca_certs=cert_file)
+
+
+class TestServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
+
+    def __init__(self, host, service):
+        SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, (host, 0),
+                                                       logRequests=False,
+                                                       bind_and_activate=False)
+
+        self.socket = ssl.wrap_socket(self.socket,
+                                      keyfile=KEY_FILE,
+                                      certfile=CRT_FILE,
+                                      server_side=True,
+                                      cert_reqs=ssl.CERT_REQUIRED,
+                                      ssl_version=ssl.PROTOCOL_TLSv1,
+                                      ca_certs=CRT_FILE,
+                                      do_handshake_on_connect=False)
+
+        self.server_bind()
+        self.server_activate()
+
+        _, self.port = self.socket.getsockname()
+        self.register_instance(service)
+
+    def finish_request(self, request, client_address):
+        if self.timeout is not None:
+            request.settimeout(self.timeout)
+
+        request.do_handshake()
+
+        return SimpleXMLRPCServer.SimpleXMLRPCServer.finish_request(
+            self,
+            request,
+            client_address)
+
+    def handle_error(self, request, client_address):
+        # ignored due to expected sslerrors when perorming plain connection
+        pass
+
+    def start(self):
+        self.thread = threading.Thread(target=self.serve_forever)
+        self.thread.daemon = True
+        self.thread.start()
+
+    def stop(self):
+        self.shutdown()
+
+    def get_timeout(self):
+        self.timeout = 1
+        return self.timeout + 1
diff --git a/tests/protocoldetectorTests.py b/tests/protocoldetectorTests.py
index f90eb43..927b44a 100644
--- a/tests/protocoldetectorTests.py
+++ b/tests/protocoldetectorTests.py
@@ -26,10 +26,12 @@
 from contextlib import contextmanager
 
 from yajsonrpc.betterAsyncore import Reactor
-from vdsm import m2cutils
 from protocoldetector import MultiProtocolAcceptor
-from integration.m2chelper import KEY_FILE, CRT_FILE
 from testlib import VdsmTestCase, expandPermutations, permutations
+try:
+    from integration.m2chelper import KEY_FILE, CRT_FILE, DEAFAULT_SSL_CONTEXT
+except:
+    from integration.sslhelper import KEY_FILE, CRT_FILE, DEAFAULT_SSL_CONTEXT
 
 
 class Detector(object):
@@ -97,7 +99,7 @@
     GRACETIME = 0.5
     CONCURRENCY = 5
     PERMUTATIONS = ((False,), (True,))
-    SSLCTX = m2cutils.SSLContext(CRT_FILE, KEY_FILE, ca_cert=CRT_FILE)
+    SSLCTX = DEAFAULT_SSL_CONTEXT
     BUFSIZE = 512
 
     def setUp(self):
diff --git a/tests/sslTests.py b/tests/sslTests.py
index b40f263..b7a4bfb 100644
--- a/tests/sslTests.py
+++ b/tests/sslTests.py
@@ -22,7 +22,6 @@
 import errno
 import os
 import re
-import SimpleXMLRPCServer
 import socket
 import ssl
 import subprocess
@@ -31,12 +30,21 @@
 import xmlrpclib
 
 from contextlib import contextmanager, closing
-from M2Crypto import SSL
-from integration.m2chelper import KEY_FILE, \
-    CRT_FILE, OTHER_KEY_FILE, OTHER_CRT_FILE
 from testlib import VdsmTestCase as TestCaseBase
-from vdsm.m2cutils import SSLServerSocket
-from vdsm.m2cutils import VerifyingSafeTransport
+from nose.plugins.skip import SkipTest
+try:
+    from vdsm.m2cutils import VerifyingSafeTransport
+    from integration.m2chelper import TestServer, \
+        get_server_socket, KEY_FILE, \
+        CRT_FILE, OTHER_KEY_FILE, OTHER_CRT_FILE
+    _m2cEnabled = True
+except ImportError:
+    from vdsm.sslutils import VerifyingSafeTransport
+    from integration.sslhelper import TestServer, \
+        get_server_socket, KEY_FILE, \
+        CRT_FILE, OTHER_KEY_FILE, OTHER_CRT_FILE
+    _m2cEnabled = False
+
 
 HOST = '127.0.0.1'
 
@@ -45,35 +53,6 @@
 
     def add(self, x, y):
         return x + y
-
-
-class TestServer():
-
-    def __init__(self):
-        self.server = SimpleXMLRPCServer.SimpleXMLRPCServer((HOST, 0),
-                                                            logRequests=False)
-        self.server.socket = SSLServerSocket(raw=self.server.socket,
-                                             keyfile=KEY_FILE,
-                                             certfile=CRT_FILE,
-                                             ca_certs=CRT_FILE)
-        _, self.port = self.server.socket.getsockname()
-        self.server.register_instance(MathService())
-
-    def start(self):
-        self.thread = threading.Thread(target=self.serve_forever)
-        self.thread.daemon = True
-        self.thread.start()
-
-    def serve_forever(self):
-        try:
-            self.server.serve_forever()
-        except SSL.SSLError:
-            # expected sslerror is thrown in server side during test_invalid
-            # method we do not want to pollute test console output
-            pass
-
-    def stop(self):
-        self.server.shutdown()
 
 
 class VerifyingClient():
@@ -97,7 +76,7 @@
 
 @contextmanager
 def verifyingclient(key_file, crt_file):
-    server = TestServer()
+    server = TestServer(HOST, MathService())
     server.start()
     try:
         client = VerifyingClient(server.port, key_file, crt_file)
@@ -112,9 +91,8 @@
 class SocketTests(TestCaseBase):
 
     def test_block_socket(self):
-        server = TestServer()
-        server.server.socket.accept_timeout = 1
-        timeout = server.server.socket.accept_timeout + 1
+        server = TestServer(HOST, MathService())
+        timeout = server.get_timeout()
         server.start()
         try:
             with closing(socket.socket(socket.AF_INET,
@@ -222,11 +200,8 @@
 
         # Create the server socket:
         self.server = socket.socket()
-        self.server = SSLServerSocket(
-            raw=self.server,
-            keyfile=self.keyfile,
-            certfile=self.certfile,
-            ca_certs=self.certfile)
+        self.server = get_server_socket(self.keyfile, self.certfile,
+                                        self.server)
         self.address = self.tryBind(ADDRESS)
         self.server.listen(5)
 
@@ -357,6 +332,11 @@
         Verify that SSL the session identifier is preserved when
         connecting two times without stopping the server.
         """
+        if not _m2cEnabled:
+            raise SkipTest(
+                'support for SSL sessions discontinued and may be reintroduced'
+                ' when we move to python 3'
+            )
 
         # Create a temporary file to store the session details:
         sessionDetailsFile = tempfile.NamedTemporaryFile(delete=False)
diff --git a/tests/stompTests.py b/tests/stompTests.py
index 3b38c95..3eabbb7 100644
--- a/tests/stompTests.py
+++ b/tests/stompTests.py
@@ -26,9 +26,12 @@
     dummyTextGenerator
 
 from integration.jsonRpcHelper import constructAcceptor
-from integration.m2chelper import DEAFAULT_SSL_CONTEXT
 from yajsonrpc.stompreactor import StandAloneRpcClient
-from vdsm.utils import running
+from vdsm import utils
+try:
+    from integration.m2chelper import DEAFAULT_SSL_CONTEXT
+except ImportError:
+    from integration.sslhelper import DEAFAULT_SSL_CONTEXT
 
 
 CALL_TIMEOUT = 15
@@ -61,9 +64,11 @@
         with constructAcceptor(self.log, use_ssl, _SampleBridge()) as acceptor:
             sslctx = DEAFAULT_SSL_CONTEXT if use_ssl else None
 
-            with running(StandAloneRpcClient(acceptor._host, acceptor._port,
-                                             'jms.topic.vdsm_requests',
-                                             str(uuid4()), sslctx)) as client:
+            with utils.running(StandAloneRpcClient(acceptor._host,
+                                                   acceptor._port,
+                                                   'jms.topic.vdsm_requests',
+                                                   str(uuid4()),
+                                                   sslctx)) as client:
                 self.assertEquals(client.callMethod('echo', (data,),
                                                     str(uuid4())),
                                   data)
@@ -75,7 +80,6 @@
         with constructAcceptor(self.log, use_ssl, _SampleBridge(),
                                'jms.queue.events') as acceptor:
             sslctx = DEAFAULT_SSL_CONTEXT if use_ssl else None
-
             client = StandAloneRpcClient(acceptor._host, acceptor._port,
                                          'jms.topic.vdsm_requests',
                                          'jms.queue.events', sslctx, False)
diff --git a/tests/vdscliTests.py b/tests/vdscliTests.py
index ba2cf36..bfcbddf 100644
--- a/tests/vdscliTests.py
+++ b/tests/vdscliTests.py
@@ -29,9 +29,14 @@
 
 from testlib import VdsmTestCase as TestCaseBase
 from testValidation import ValidateRunningAsRoot
-
-from vdsm import m2cutils
 from vdsm import vdscli
+try:
+    from vdsm import m2cutils as sslutils
+    from integration.m2chelper import get_server_socket
+except ImportError:
+    from vdsm import sslutils
+    from integration.sslhelper import get_server_socket
+
 
 HOST = '127.0.0.1'
 
@@ -51,11 +56,8 @@
         if useSSL:
             KEY_FILE = os.path.join(path, 'keys/vdsmkey.pem')
             CRT_FILE = os.path.join(path, 'certs/vdsmcert.pem')
-            self.server.socket = m2cutils.SSLServerSocket(
-                raw=self.server.socket,
-                keyfile=KEY_FILE,
-                certfile=CRT_FILE,
-                ca_certs=CRT_FILE)
+            self.server.socket = get_server_socket(KEY_FILE, CRT_FILE,
+                                                   self.server.socket)
 
         _, self.port = self.server.socket.getsockname()
         self.server.register_instance(TestingService())
@@ -74,7 +76,7 @@
 
 @contextmanager
 def setupclient(useSSL, tsPath,
-                timeout=m2cutils.SOCKET_DEFAULT_TIMEOUT):
+                timeout=sslutils.SOCKET_DEFAULT_TIMEOUT):
     server = TestServer(useSSL, tsPath)
     server.start()
     hostPort = '0:' + str(server.port)
diff --git a/vdsm.spec.in b/vdsm.spec.in
index ddb3184..7bcea09 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -42,6 +42,9 @@
 %global _polkitdir %{_localstatedir}/lib/polkit-1/localauthority/10-vendor.d
 %endif
 
+# enable m2crypto by default
+%global with_m2c 1
+
 # Gluster should not be shipped with RHEV
 %if ! 0%{?rhev_build}
 %global with_gluster 1
@@ -83,7 +86,9 @@
 BuildRequires: libnl3
 BuildRequires: libselinux-python
 BuildRequires: libvirt-python
+%if %{with_m2c}
 BuildRequires: m2crypto
+%endif
 BuildRequires: mom >= 0.4.5
 BuildRequires: openssl
 BuildRequires: policycoreutils-python
@@ -129,7 +134,9 @@
 Requires: %{name}-infra = %{version}-%{release}
 Requires: rpm-python
 Requires: nfs-utils
+%if %{with_m2c}
 Requires: m2crypto
+%endif
 Requires: libnl3
 Requires: curl
 Requires: %{name}-xmlrpc = %{version}-%{release}
@@ -295,7 +302,9 @@
 %package reg
 Summary:        VDSM registration package
 Requires: %{name} = %{version}-%{release}
+%if %{with_m2c}
 Requires: m2crypto
+%endif
 Requires: openssl
 Conflicts: ovirt-node < 3.0.4
 
@@ -307,7 +316,9 @@
 Summary:        VDSM python libraries
 Requires:       %{name}-infra = %{version}-%{release}
 Requires:       python-cpopen >= 1.2.3-5
+%if %{with_m2c}
 Requires:       m2crypto
+%endif
 Requires:       python-ioprocess >= 0.14
 
 %description python
@@ -1049,7 +1060,6 @@
 %{python_sitelib}/%{vdsm_name}/ipwrapper.py*
 %{python_sitelib}/%{vdsm_name}/jsonrpcvdscli.py*
 %{python_sitelib}/%{vdsm_name}/libvirtconnection.py*
-%{python_sitelib}/%{vdsm_name}/m2cutils.py*
 %{python_sitelib}/%{vdsm_name}/netinfo.py*
 %{python_sitelib}/%{vdsm_name}/netlink/__init__.py*
 %{python_sitelib}/%{vdsm_name}/netlink/addr.py*
@@ -1067,6 +1077,13 @@
 %{python_sitelib}/%{vdsm_name}/response.py*
 %{python_sitelib}/%{vdsm_name}/netconfpersistence.py*
 %{python_sitelib}/%{vdsm_name}/schedule.py*
+%if %{with_m2c}
+%{python_sitelib}/%{vdsm_name}/m2cutils.py*
+%exclude %{python_sitelib}/%{vdsm_name}/sslutils.py*
+%else
+%exclude %{python_sitelib}/%{vdsm_name}/m2cutils.py*
+%{python_sitelib}/%{vdsm_name}/sslutils.py*
+%endif
 %{python_sitelib}/%{vdsm_name}/sysctl.py*
 %{python_sitelib}/%{vdsm_name}/udevadm.py*
 %{python_sitelib}/%{vdsm_name}/utils.py*
diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py
index 5590db0..578b349 100644
--- a/vdsm/clientIF.py
+++ b/vdsm/clientIF.py
@@ -37,7 +37,6 @@
 from vdsm.compat import pickle
 from vdsm.define import doneCode, errCode
 import libvirt
-from vdsm import m2cutils
 from vdsm import libvirtconnection
 from vdsm import constants
 from vdsm import utils
@@ -55,6 +54,10 @@
 from virt.vmchannels import Listener
 from virt.vmdevices import hwclass
 from virt.utils import isVdsmImage
+try:
+    from vdsm import m2cutils as sslutils
+except ImportError:
+    from vdsm import sslutils
 try:
     import gluster.api as gapi
     _glusterEnabled = True
@@ -193,7 +196,7 @@
         return cls._instance
 
     def _createAcceptor(self, host, port):
-        sslctx = m2cutils.create_ssl_context()
+        sslctx = sslutils.create_ssl_context()
         self._reactor = Reactor()
 
         self._acceptor = MultiProtocolAcceptor(self._reactor, host,
@@ -205,7 +208,7 @@
             broker_port = config.getint('addresses', 'broker_port')
             request_queues = config.get('addresses', 'request_queues')
 
-            sslctx = m2cutils.create_ssl_context()
+            sslctx = sslutils.create_ssl_context()
             sock = socket.socket()
             sock.connect((broker_address, broker_port))
             if sslctx:
diff --git a/vdsm/kaxmlrpclib.py b/vdsm/kaxmlrpclib.py
index b38031e..b0640e8 100644
--- a/vdsm/kaxmlrpclib.py
+++ b/vdsm/kaxmlrpclib.py
@@ -110,7 +110,10 @@
 
 ###################
 # the same, for ssl
-from vdsm import m2cutils
+try:
+    from vdsm import m2cutils as sslutils
+except ImportError:
+    from vdsm import sslutils
 import ssl
 
 
@@ -122,7 +125,7 @@
 SslServerProxy = SslServer
 
 
-class TcpkeepSafeTransport(m2cutils.VerifyingSafeTransport):
+class TcpkeepSafeTransport(sslutils.VerifyingSafeTransport):
 
     def make_connection(self, host):
         chost, self._extra_headers, x509 = self.get_host_info(host)
@@ -139,17 +142,17 @@
                 cert_reqs=self.cert_reqs)
 
 
-class TcpkeepHTTPSConnection(m2cutils.VerifyingHTTPSConnection):
+class TcpkeepHTTPSConnection(sslutils.VerifyingHTTPSConnection):
     def __init__(self, host, port=None, key_file=None, cert_file=None,
                  strict=None, timeout=CONNECTTIMEOUT,
                  ca_certs=None, cert_reqs=ssl.CERT_REQUIRED):
-        m2cutils.VerifyingHTTPSConnection.__init__(
+        sslutils.VerifyingHTTPSConnection.__init__(
             self, host, port=port, key_file=key_file, cert_file=cert_file,
             strict=strict, timeout=timeout,
             ca_certs=ca_certs, cert_reqs=cert_reqs)
 
     def connect(self):
-        m2cutils.VerifyingHTTPSConnection.connect(self)
+        sslutils.VerifyingHTTPSConnection.connect(self)
 
         # after TCP_KEEPIDLE seconds of silence, TCP_KEEPCNT probes would be
         # sent, TCP_KEEPINTVL seconds apart of each other. If all of them fail,
@@ -160,5 +163,5 @@
         self.sock.setsockopt(socket.SOL_TCP, socket.TCP_KEEPCNT, KEEPCNT)
 
 
-class TcpkeepHTTPS(m2cutils.VerifyingHTTPS):
+class TcpkeepHTTPS(sslutils.VerifyingHTTPS):
     _connection_class = TcpkeepHTTPSConnection
diff --git a/vdsm/protocoldetector.py b/vdsm/protocoldetector.py
index 6d01a1c..dbdc730 100644
--- a/vdsm/protocoldetector.py
+++ b/vdsm/protocoldetector.py
@@ -24,7 +24,10 @@
 import vdsm.infra.filecontrol as filecontrol
 
 from vdsm.utils import monotonic_time
-from vdsm.m2cutils import SSLHandshakeDispatcher
+try:
+    from vdsm.m2cutils import SSLHandshakeDispatcher
+except ImportError:
+    from vdsm.sslutils import SSLHandshakeDispatcher
 
 
 def _create_socket(host, port):
diff --git a/vdsm/virt/migration.py b/vdsm/virt/migration.py
index 32caccb..6c41114 100644
--- a/vdsm/virt/migration.py
+++ b/vdsm/virt/migration.py
@@ -28,7 +28,6 @@
 from vdsm import utils
 from vdsm import vdscli
 from vdsm import jsonrpcvdscli
-from vdsm import m2cutils
 from vdsm.compat import pickle
 from vdsm.config import config
 from vdsm.define import NORMAL, Mbytes
@@ -40,6 +39,11 @@
 from . import vmexitreason
 from . import vmstatus
 
+try:
+    from vdsm import m2cutils as sslutils
+except ImportError:
+    from vdsm import sslutils
+
 
 MODE_REMOTE = 'remote'
 MODE_FILE = 'file'


-- 
To view, visit https://gerrit.ovirt.org/44494
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6501981bbd5276c49731b0d9eba4794286b0f823
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Piotr Kliczewski <[email protected]>
_______________________________________________
vdsm-patches mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to