Import all the stacktester stuff as-is (s/stacktester/kong/, though).
diff --git a/kong/common/__init__.py b/kong/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/kong/common/__init__.py
diff --git a/kong/common/http.py b/kong/common/http.py
new file mode 100644
index 0000000..47ac058
--- /dev/null
+++ b/kong/common/http.py
@@ -0,0 +1,57 @@
+from kong import exceptions
+
+import httplib2
+import os
+import time
+
+
+class Client(object):
+
+    USER_AGENT = 'python-nova_test_client'
+
+    def __init__(self, host='localhost', port=80, base_url=''):
+        #TODO: join these more robustly
+        self.base_url = "http://%s:%s/%s" % (host, port, base_url)
+
+    def poll_request(self, method, url, check_response, **kwargs):
+
+        timeout = kwargs.pop('timeout', 180)
+        interval = kwargs.pop('interval', 2)
+        # Start timestamp
+        start_ts = int(time.time())
+
+        while True:
+            resp, body = self.request(method, url, **kwargs)
+            if (check_response(resp, body)):
+                break
+            if (int(time.time()) - start_ts >= timeout):
+                raise exceptions.TimeoutException
+            time.sleep(interval)
+
+    def poll_request_status(self, method, url, status=200, **kwargs):
+
+        def check_response(resp, body):
+            return resp['status'] == str(status)
+
+        self.poll_request(method, url, check_response, **kwargs)
+
+
+    def request(self, method, url, **kwargs):
+        # Default to management_url, but can be overridden here 
+        # (for auth requests)
+        base_url = kwargs.get('base_url', self.management_url)
+
+        self.http_obj = httplib2.Http()
+
+        params = {}
+        params['headers'] = {'User-Agent': self.USER_AGENT}
+        params['headers'].update(kwargs.get('headers', {}))
+        if 'Content-Type' not in params.get('headers',{}):
+            params['headers']['Content-Type'] = 'application/json'
+
+        if 'body' in kwargs:
+            params['body'] = kwargs.get('body')
+
+        req_url = os.path.join(base_url, url.strip('/'))
+        resp, body = self.http_obj.request(req_url, method, **params)
+        return resp, body
diff --git a/kong/common/ssh.py b/kong/common/ssh.py
new file mode 100644
index 0000000..f650e64
--- /dev/null
+++ b/kong/common/ssh.py
@@ -0,0 +1,79 @@
+import time
+import socket 
+import warnings
+
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore")
+    import paramiko
+
+
+class Client(object):
+
+    def __init__(self, host, username, password, timeout=300):
+        self.host = host
+        self.username = username
+        self.password = password
+        self.timeout = timeout
+
+    def _get_ssh_connection(self):
+        """Returns an ssh connection to the specified host"""
+        _timeout = True
+        ssh = paramiko.SSHClient()
+        ssh.set_missing_host_key_policy(
+            paramiko.AutoAddPolicy())
+        _start_time = time.time()
+
+        while not self._is_timed_out(self.timeout, _start_time):
+            try:
+                ssh.connect(self.host, username=self.username, 
+                    password=self.password, look_for_keys=False,
+                    timeout=self.timeout)
+                _timeout = False
+                break
+            except socket.error:
+                continue
+            except paramiko.AuthenticationException:
+                time.sleep(15)
+                continue
+        if _timeout:
+            raise socket.error("SSH connect timed out")
+        return ssh
+
+    def _is_timed_out(self, timeout, start_time):
+        return (time.time() - timeout) > start_time
+
+    def connect_until_closed(self):
+        """Connect to the server and wait until connection is lost"""
+        try:
+            ssh = self._get_ssh_connection()
+            _transport = ssh.get_transport()
+            _start_time = time.time()
+            _timed_out = self._is_timed_out(self.timeout, _start_time)
+            while _transport.is_active() and not _timed_out:
+                time.sleep(5)
+                _timed_out = self._is_timed_out(self.timeout, _start_time)
+            ssh.close()
+        except (EOFError, paramiko.AuthenticationException, socket.error):
+            return
+
+    def exec_command(self, cmd):
+        """Execute the specified command on the server.
+
+        :returns: data read from standard output of the command
+
+        """
+        ssh = self._get_ssh_connection()
+        stdin, stdout, stderr = ssh.exec_command(cmd)
+        output = stdout.read()
+        ssh.close()
+        return output
+
+    def test_connection_auth(self):
+        """ Returns true if ssh can connect to server"""
+        try:
+            connection = self._get_ssh_connection()
+            connection.close()
+        except paramiko.AuthenticationException:
+            return False
+
+        return True