Initial import of tests from the Zodiac project. On suggestion from Westmaas, imported tests under the nova directory
(final naming TBD) to more quickly get them imported. To run these tests, execute 'nosetests nova/tests'.
I've also only submitted the most stable of the tests. More to come.

Change-Id: I2abd961992c02b27c4deaa9f11a49ba91c5b765d

Fixed config defaults

Change-Id: I90d5ea20167caddbec6b4cf51a0df9bb333514cb
diff --git a/storm/common/__init__.py b/storm/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/storm/common/__init__.py
diff --git a/storm/common/rest_client.py b/storm/common/rest_client.py
new file mode 100644
index 0000000..44658fa
--- /dev/null
+++ b/storm/common/rest_client.py
@@ -0,0 +1,96 @@
+import httplib2
+import json
+import storm.config
+
+
+class RestClient(object):
+
+    def __init__(self, user, key, auth_url, tenant_name=None):
+        self.config = storm.config.StormConfig()
+
+        if self.config.env.authentication == 'keystone_v2':
+            self.token, self.base_url = self.keystone_v2_auth(user,
+                                                              key,
+                                                              auth_url,
+                                                              tenant_name)
+        else:
+            self.token, self.base_url = self.basic_auth(user,
+                                                        key,
+                                                        auth_url)
+
+    def basic_auth(self, user, api_key, auth_url):
+        """
+        Provides authentication for the target API
+        """
+
+        params = {}
+        params['headers'] = {'User-Agent': 'Test-Client', 'X-Auth-User': user,
+                             'X-Auth-Key': api_key}
+
+        self.http_obj = httplib2.Http()
+        resp, body = self.http_obj.request(auth_url, 'GET', **params)
+        try:
+            return resp['x-auth-token'], resp['x-server-management-url']
+        except:
+            raise
+
+    def keystone_v2_auth(self, user, api_key, auth_url, tenant_name):
+        """
+        Provides authentication via Keystone 2.0
+        """
+
+        creds = {'auth': {
+                'passwordCredentials': {
+                    'username': user,
+                    'password': api_key,
+                },
+                'tenantName': tenant_name
+            }
+        }
+
+        self.http_obj = httplib2.Http()
+        headers = {'Content-Type': 'application/json'}
+        body = json.dumps(creds)
+        resp, body = self.http_obj.request(auth_url, 'POST',
+                                           headers=headers, body=body)
+
+        try:
+            auth_data = json.loads(body)['access']
+            token = auth_data['token']['id']
+            endpoints = auth_data['serviceCatalog'][0]['endpoints']
+            mgmt_url = endpoints[0]['publicURL']
+
+            #TODO (dwalleck): This is a horrible stopgap.
+            #Need to join strings more cleanly
+            temp = mgmt_url.rsplit('/')
+            service_url = temp[0] + '//' + temp[2] + '/' + temp[3] + '/'
+            management_url = service_url + tenant_name
+            return token, management_url
+        except KeyError:
+            print "Failed to authenticate user"
+            raise
+
+    def post(self, url, body, headers):
+        return self.request('POST', url, headers, body)
+
+    def get(self, url):
+        return self.request('GET', url)
+
+    def delete(self, url):
+        return self.request('DELETE', url)
+
+    def put(self, url, body, headers):
+        return self.request('PUT', url, headers, body)
+
+    def request(self, method, url, headers=None, body=None):
+        """ A simple HTTP request interface."""
+
+        self.http_obj = httplib2.Http()
+        if headers == None:
+            headers = {}
+        headers['X-Auth-Token'] = self.token
+
+        req_url = "%s/%s" % (self.base_url, url)
+        resp, body = self.http_obj.request(req_url, method,
+                                           headers=headers, body=body)
+        return resp, body
diff --git a/storm/common/ssh.py b/storm/common/ssh.py
new file mode 100644
index 0000000..2f1d96b
--- /dev/null
+++ b/storm/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 = int(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=20)
+                _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
diff --git a/storm/common/utils/__init__.py b/storm/common/utils/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/storm/common/utils/__init__.py
diff --git a/storm/common/utils/data_utils.py b/storm/common/utils/data_utils.py
new file mode 100644
index 0000000..e4d9db5
--- /dev/null
+++ b/storm/common/utils/data_utils.py
@@ -0,0 +1,5 @@
+import random
+
+
+def rand_name(self, name='test'):
+    return name + str(random.randint(1, 99999999999))