Merge "Add sample config check to tox pep8 job"
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
new file mode 100644
index 0000000..cea6e92
--- /dev/null
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -0,0 +1,64 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import datetime
+
+from tempest.api.compute import base
+from tempest.test import attr
+import urllib
+
+
+class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest):
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(InstanceUsageAuditLogTestJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.instance_usages_audit_log_client
+
+    @attr(type='gate')
+    def test_list_instance_usage_audit_logs(self):
+        # list instance usage audit logs
+        resp, body = self.adm_client.list_instance_usage_audit_logs()
+        self.assertEqual(200, resp.status)
+        expected_items = ['total_errors', 'total_instances', 'log',
+                          'num_hosts_running', 'num_hosts_done',
+                          'num_hosts', 'hosts_not_run', 'overall_status',
+                          'period_ending', 'period_beginning',
+                          'num_hosts_not_run']
+        for item in expected_items:
+            self.assertIn(item, body)
+
+    @attr(type='gate')
+    def test_get_instance_usage_audit_log(self):
+        # Get instance usage audit log before specified time
+        now = datetime.datetime.now()
+        resp, body = self.adm_client.get_instance_usage_audit_log(
+            urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S")))
+
+        self.assertEqual(200, resp.status)
+        expected_items = ['total_errors', 'total_instances', 'log',
+                          'num_hosts_running', 'num_hosts_done', 'num_hosts',
+                          'hosts_not_run', 'overall_status', 'period_ending',
+                          'period_beginning', 'num_hosts_not_run']
+        for item in expected_items:
+            self.assertIn(item, body)
+
+
+class InstanceUsageAuditLogTestXML(InstanceUsageAuditLogTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
new file mode 100644
index 0000000..dcf41c5
--- /dev/null
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -0,0 +1,56 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import datetime
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+import urllib
+
+
+class InstanceUsageAuditLogNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(InstanceUsageAuditLogNegativeTestJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.instance_usages_audit_log_client
+
+    @attr(type=['negative', 'gate'])
+    def test_instance_usage_audit_logs_with_nonadmin_user(self):
+        # the instance_usage_audit_logs API just can be accessed by admin user
+        self.assertRaises(exceptions.Unauthorized,
+                          self.instance_usages_audit_log_client.
+                          list_instance_usage_audit_logs)
+        now = datetime.datetime.now()
+        self.assertRaises(exceptions.Unauthorized,
+                          self.instance_usages_audit_log_client.
+                          get_instance_usage_audit_log,
+                          urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S")))
+
+    @attr(type=['negative', 'gate'])
+    def test_get_instance_usage_audit_logs_with_invalid_time(self):
+        self.assertRaises(exceptions.BadRequest,
+                          self.adm_client.get_instance_usage_audit_log,
+                          "invalid_time")
+
+
+class InstanceUsageAuditLogNegativeTestXML(
+    InstanceUsageAuditLogNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index dac245b..4b6816b 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -155,6 +155,8 @@
         cls.availability_zone_client = cls.os.availability_zone_client
         cls.aggregates_client = cls.os.aggregates_client
         cls.services_client = cls.os.services_client
+        cls.instance_usages_audit_log_client = \
+            cls.os.instance_usages_audit_log_client
         cls.hypervisor_client = cls.os.hypervisor_client
         cls.servers_client_v3_auth = cls.os.servers_client_v3_auth
         cls.certificates_client = cls.os.certificates_client
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index a06e209..521a480 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -17,71 +17,19 @@
 
 import datetime
 
-from tempest.api import compute
 from tempest.api.compute import base
-from tempest import clients
 from tempest import exceptions
 from tempest.test import attr
 
 
 class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
     _interface = 'json'
-
-    @classmethod
-    def _ensure_no_servers(cls, servers, username, tenant_name):
-        """
-        If there are servers and there is tenant isolation then a
-        skipException is raised to skip the test since it requires no servers
-        to already exist for the given user/tenant.
-        If there are servers and there is not tenant isolation then the test
-        blocks while the servers are being deleted.
-        """
-        if len(servers):
-            if not cls.config.compute.allow_tenant_isolation:
-                for srv in servers:
-                    cls.client.wait_for_server_termination(srv['id'],
-                                                           ignore_error=True)
-            else:
-                msg = ("User/tenant %(u)s/%(t)s already have "
-                       "existing server instances. Skipping test." %
-                       {'u': username, 't': tenant_name})
-                raise cls.skipException(msg)
+    force_tenant_isolation = True
 
     @classmethod
     def setUpClass(cls):
         super(ListServersNegativeTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
-        cls.servers = []
-
-        if compute.MULTI_USER:
-            if cls.config.compute.allow_tenant_isolation:
-                creds = cls.isolated_creds.get_alt_creds()
-                username, tenant_name, password = creds
-                cls.alt_manager = clients.Manager(username=username,
-                                                  password=password,
-                                                  tenant_name=tenant_name)
-            else:
-                # Use the alt_XXX credentials in the config file
-                cls.alt_manager = clients.AltManager()
-            cls.alt_client = cls.alt_manager.servers_client
-
-        # Under circumstances when there is not a tenant/user
-        # created for the test case, the test case checks
-        # to see if there are existing servers for the
-        # either the normal user/tenant or the alt user/tenant
-        # and if so, the whole test is skipped. We do this
-        # because we assume a baseline of no servers at the
-        # start of the test instead of destroying any existing
-        # servers.
-        resp, body = cls.client.list_servers()
-        cls._ensure_no_servers(body['servers'],
-                               cls.os.username,
-                               cls.os.tenant_name)
-
-        resp, body = cls.alt_client.list_servers()
-        cls._ensure_no_servers(body['servers'],
-                               cls.alt_manager.username,
-                               cls.alt_manager.tenant_name)
 
         # The following servers are created for use
         # by the test methods in this class. These
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
new file mode 100644
index 0000000..a177cea
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -0,0 +1,118 @@
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.test import attr
+
+import time
+
+
+class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        if not cls.config.service_available.neutron:
+            raise cls.skipException("Neutron is required")
+        super(AttachInterfacesTestJSON, cls).setUpClass()
+        cls.client = cls.os.interfaces_client
+
+    def _check_interface(self, iface, port_id=None, network_id=None,
+                         fixed_ip=None):
+        self.assertIn('port_state', iface)
+        if port_id:
+            self.assertEqual(iface['port_id'], port_id)
+        if network_id:
+            self.assertEqual(iface['net_id'], network_id)
+        if fixed_ip:
+            self.assertEqual(iface['fixed_ips'][0]['ip_address'], fixed_ip)
+
+    def _create_server_get_interfaces(self):
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        resp, ifs = self.client.list_interfaces(server['id'])
+        resp, body = self.client.wait_for_interface_status(
+            server['id'], ifs[0]['port_id'], 'ACTIVE')
+        ifs[0]['port_state'] = body['port_state']
+        return server, ifs
+
+    def _test_create_interface(self, server):
+        resp, iface = self.client.create_interface(server['id'])
+        resp, iface = self.client.wait_for_interface_status(
+            server['id'], iface['port_id'], 'ACTIVE')
+        self._check_interface(iface)
+        return iface
+
+    def _test_create_interface_by_network_id(self, server, ifs):
+        network_id = ifs[0]['net_id']
+        resp, iface = self.client.create_interface(server['id'],
+                                                   network_id=network_id)
+        resp, iface = self.client.wait_for_interface_status(
+            server['id'], iface['port_id'], 'ACTIVE')
+        self._check_interface(iface, network_id=network_id)
+        return iface
+
+    def _test_show_interface(self, server, ifs):
+        iface = ifs[0]
+        resp, _iface = self.client.show_interface(server['id'],
+                                                  iface['port_id'])
+        self.assertEqual(iface, _iface)
+
+    def _test_delete_interface(self, server, ifs):
+        # NOTE(danms): delete not the first or last, but one in the middle
+        iface = ifs[1]
+        self.client.delete_interface(server['id'], iface['port_id'])
+        for i in range(0, 5):
+            _r, _ifs = self.client.list_interfaces(server['id'])
+            if len(ifs) != len(_ifs):
+                break
+            time.sleep(1)
+
+        self.assertEqual(len(_ifs), len(ifs) - 1)
+        for _iface in _ifs:
+            self.assertNotEqual(iface['port_id'], _iface['port_id'])
+        return _ifs
+
+    def _compare_iface_list(self, list1, list2):
+        # NOTE(danms): port_state will likely have changed, so just
+        # confirm the port_ids are the same at least
+        list1 = [x['port_id'] for x in list1]
+        list2 = [x['port_id'] for x in list2]
+
+        self.assertEqual(sorted(list1), sorted(list2))
+
+    @attr(type='gate')
+    def test_create_list_show_delete_interfaces(self):
+        server, ifs = self._create_server_get_interfaces()
+        interface_count = len(ifs)
+        self.assertTrue(interface_count > 0)
+        self._check_interface(ifs[0])
+
+        iface = self._test_create_interface(server)
+        ifs.append(iface)
+
+        iface = self._test_create_interface_by_network_id(server, ifs)
+        ifs.append(iface)
+
+        resp, _ifs = self.client.list_interfaces(server['id'])
+        self._compare_iface_list(ifs, _ifs)
+
+        self._test_show_interface(server, ifs)
+
+        _ifs = self._test_delete_interface(server, ifs)
+        self.assertEqual(len(ifs) - 1, len(_ifs))
+
+
+class AttachInterfacesTestXML(AttachInterfacesTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
new file mode 100644
index 0000000..7ca8a52
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -0,0 +1,84 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ServerAddressesTest(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServerAddressesTest, cls).setUpClass()
+        cls.client = cls.servers_client
+
+        resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+    @attr(type=['negative', 'gate'])
+    def test_list_server_addresses_invalid_server_id(self):
+        # List addresses request should fail if server id not in system
+        self.assertRaises(exceptions.NotFound, self.client.list_addresses,
+                          '999')
+
+    @attr(type=['negative', 'gate'])
+    def test_list_server_addresses_by_network_neg(self):
+        # List addresses by network should fail if network name not valid
+        self.assertRaises(exceptions.NotFound,
+                          self.client.list_addresses_by_network,
+                          self.server['id'], 'invalid')
+
+    @attr(type='smoke')
+    def test_list_server_addresses(self):
+        # All public and private addresses for
+        # a server should be returned
+
+        resp, addresses = self.client.list_addresses(self.server['id'])
+        self.assertEqual('200', resp['status'])
+
+        # We do not know the exact network configuration, but an instance
+        # should at least have a single public or private address
+        self.assertTrue(len(addresses) >= 1)
+        for network_name, network_addresses in addresses.iteritems():
+            self.assertTrue(len(network_addresses) >= 1)
+            for address in network_addresses:
+                self.assertTrue(address['addr'])
+                self.assertTrue(address['version'])
+
+    @attr(type='smoke')
+    def test_list_server_addresses_by_network(self):
+        # Providing a network type should filter
+        # the addresses return by that type
+
+        resp, addresses = self.client.list_addresses(self.server['id'])
+
+        # Once again we don't know the environment's exact network config,
+        # but the response for each individual network should be the same
+        # as the partial result of the full address list
+        id = self.server['id']
+        for addr_type in addresses:
+            resp, addr = self.client.list_addresses_by_network(id, addr_type)
+            self.assertEqual('200', resp['status'])
+
+            addr = addr[addr_type]
+            for address in addresses[addr_type]:
+                self.assertTrue(any([a for a in addr if a == address]))
+
+
+class ServerAddressesTestXML(ServerAddressesTest):
+    _interface = 'xml'
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
new file mode 100644
index 0000000..dacebf1
--- /dev/null
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -0,0 +1,120 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.volume.base import BaseVolumeTest
+from tempest import clients
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+class VolumesTransfersTest(BaseVolumeTest):
+    _interface = "json"
+
+    @classmethod
+    def setUpClass(cls):
+        super(VolumesTransfersTest, cls).setUpClass()
+
+        # Add another tenant to test volume-transfer
+        if cls.config.compute.allow_tenant_isolation:
+            creds = cls.isolated_creds.get_alt_creds()
+            username, tenant_name, password = creds
+            cls.os_alt = clients.Manager(username=username,
+                                         password=password,
+                                         tenant_name=tenant_name,
+                                         interface=cls._interface)
+            cls.alt_tenant_id = cls.isolated_creds.get_alt_tenant()['id']
+
+            # Add admin tenant to cleanup resources
+            adm_creds = cls.isolated_creds.get_admin_creds()
+            admin_username, admin_tenant_name, admin_password = adm_creds
+            cls.os_adm = clients.Manager(username=admin_username,
+                                         password=admin_password,
+                                         tenant_name=admin_tenant_name,
+                                         interface=cls._interface)
+        else:
+            cls.os_alt = clients.AltManager()
+            alt_tenant_name = cls.os_alt.tenant_name
+            identity_client = cls._get_identity_admin_client()
+            _, tenants = identity_client.list_tenants()
+            cls.alt_tenant_id = [tnt['id'] for tnt in tenants
+                                 if tnt['name'] == alt_tenant_name][0]
+            cls.os_adm = clients.ComputeAdminManager(interface=cls._interface)
+
+        cls.client = cls.volumes_client
+        cls.alt_client = cls.os_alt.volumes_client
+        cls.adm_client = cls.os_adm.volumes_client
+
+    @attr(type='gate')
+    def test_create_get_list_accept_volume_transfer(self):
+        # Create a volume first
+        vol_name = rand_name('-Volume-')
+        _, volume = self.client.create_volume(size=1, display_name=vol_name)
+        self.addCleanup(self.adm_client.delete_volume, volume['id'])
+        self.client.wait_for_volume_status(volume['id'], 'available')
+
+        # Create a volume transfer
+        resp, transfer = self.client.create_volume_transfer(volume['id'])
+        self.assertEqual(202, resp.status)
+        transfer_id = transfer['id']
+        auth_key = transfer['auth_key']
+        self.client.wait_for_volume_status(volume['id'],
+                                           'awaiting-transfer')
+
+        # Get a volume transfer
+        resp, body = self.client.get_volume_transfer(transfer_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(volume['id'], body['volume_id'])
+
+        # List volume transfers, the result should be greater than
+        # or equal to 1
+        resp, body = self.client.list_volume_transfers()
+        self.assertEqual(200, resp.status)
+        self.assertGreaterEqual(len(body), 1)
+
+        # Accept a volume transfer by alt_tenant
+        resp, body = self.alt_client.accept_volume_transfer(transfer_id,
+                                                            auth_key)
+        self.assertEqual(202, resp.status)
+        self.alt_client.wait_for_volume_status(volume['id'], 'available')
+
+    def test_create_list_delete_volume_transfer(self):
+        # Create a volume first
+        vol_name = rand_name('-Volume-')
+        _, volume = self.client.create_volume(size=1, display_name=vol_name)
+        self.addCleanup(self.adm_client.delete_volume, volume['id'])
+        self.client.wait_for_volume_status(volume['id'], 'available')
+
+        # Create a volume transfer
+        resp, body = self.client.create_volume_transfer(volume['id'])
+        self.assertEqual(202, resp.status)
+        transfer_id = body['id']
+        self.client.wait_for_volume_status(volume['id'],
+                                           'awaiting-transfer')
+
+        # List all volume transfers, there's only one in this test
+        resp, body = self.client.list_volume_transfers()
+        self.assertEqual(200, resp.status)
+        self.assertEqual(volume['id'], body[0]['volume_id'])
+
+        # Delete a volume transfer
+        resp, body = self.client.delete_volume_transfer(transfer_id)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_volume_status(volume['id'], 'available')
+
+
+class VolumesTransfersTestXML(VolumesTransfersTest):
+    _interface = "xml"
diff --git a/tempest/clients.py b/tempest/clients.py
index a52ed5d..9029d5f 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -35,6 +35,8 @@
 from tempest.services.compute.json.hypervisor_client import \
     HypervisorClientJSON
 from tempest.services.compute.json.images_client import ImagesClientJSON
+from tempest.services.compute.json.instance_usage_audit_log_client import \
+    InstanceUsagesAuditLogClientJSON
 from tempest.services.compute.json.interfaces_client import \
     InterfacesClientJSON
 from tempest.services.compute.json.keypairs_client import KeyPairsClientJSON
@@ -71,6 +73,8 @@
     FloatingIPsClientXML
 from tempest.services.compute.xml.hypervisor_client import HypervisorClientXML
 from tempest.services.compute.xml.images_client import ImagesClientXML
+from tempest.services.compute.xml.instance_usage_audit_log_client import \
+    InstanceUsagesAuditLogClientXML
 from tempest.services.compute.xml.interfaces_client import \
     InterfacesClientXML
 from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
@@ -217,6 +221,8 @@
             self.token_v3_client = V3TokenClientXML(*client_args)
             self.network_client = NetworkClientXML(*client_args)
             self.credentials_client = CredentialsClientXML(*client_args)
+            self.instance_usages_audit_log_client = \
+                InstanceUsagesAuditLogClientXML(*client_args)
 
             if client_args_v3_auth:
                 self.servers_client_v3_auth = ServersClientXML(
@@ -259,6 +265,8 @@
             self.token_v3_client = V3TokenClientJSON(*client_args)
             self.network_client = NetworkClientJSON(*client_args)
             self.credentials_client = CredentialsClientJSON(*client_args)
+            self.instance_usages_audit_log_client = \
+                InstanceUsagesAuditLogClientJSON(*client_args)
 
             if client_args_v3_auth:
                 self.servers_client_v3_auth = ServersClientJSON(
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
new file mode 100644
index 0000000..07ce1bb
--- /dev/null
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -0,0 +1,40 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from tempest.common.rest_client import RestClient
+
+
+class InstanceUsagesAuditLogClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(InstanceUsagesAuditLogClientJSON, self).__init__(
+            config, username, password, auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_instance_usage_audit_logs(self):
+        url = 'os-instance_usage_audit_log'
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body["instance_usage_audit_logs"]
+
+    def get_instance_usage_audit_log(self, time_before):
+        url = 'os-instance_usage_audit_log/%s' % time_before
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body["instance_usage_audit_log"]
diff --git a/tempest/services/compute/v3/json/interfaces_client.py b/tempest/services/compute/v3/json/interfaces_client.py
new file mode 100644
index 0000000..06e6476
--- /dev/null
+++ b/tempest/services/compute/v3/json/interfaces_client.py
@@ -0,0 +1,80 @@
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+import time
+
+from tempest.common.rest_client import RestClient
+from tempest import exceptions
+
+
+class InterfacesClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(InterfacesClientJSON, self).__init__(config, username, password,
+                                                   auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_interfaces(self, server):
+        resp, body = self.get('servers/%s/os-interface' % server)
+        body = json.loads(body)
+        return resp, body['interfaceAttachments']
+
+    def create_interface(self, server, port_id=None, network_id=None,
+                         fixed_ip=None):
+        post_body = dict(interfaceAttachment=dict())
+        if port_id:
+            post_body['port_id'] = port_id
+        if network_id:
+            post_body['net_id'] = network_id
+        if fixed_ip:
+            post_body['fixed_ips'] = [dict(ip_address=fixed_ip)]
+        post_body = json.dumps(post_body)
+        resp, body = self.post('servers/%s/os-interface' % server,
+                               headers=self.headers,
+                               body=post_body)
+        body = json.loads(body)
+        return resp, body['interfaceAttachment']
+
+    def show_interface(self, server, port_id):
+        resp, body = self.get('servers/%s/os-interface/%s' % (server, port_id))
+        body = json.loads(body)
+        return resp, body['interfaceAttachment']
+
+    def delete_interface(self, server, port_id):
+        resp, body = self.delete('servers/%s/os-interface/%s' % (server,
+                                                                 port_id))
+        return resp, body
+
+    def wait_for_interface_status(self, server, port_id, status):
+        """Waits for a interface to reach a given status."""
+        resp, body = self.show_interface(server, port_id)
+        interface_status = body['port_state']
+        start = int(time.time())
+
+        while(interface_status != status):
+            time.sleep(self.build_interval)
+            resp, body = self.show_interface(server, port_id)
+            interface_status = body['port_state']
+
+            timed_out = int(time.time()) - start >= self.build_timeout
+
+            if interface_status != status and timed_out:
+                message = ('Interface %s failed to reach %s status within '
+                           'the required time (%s s).' %
+                           (port_id, status, self.build_timeout))
+                raise exceptions.TimeoutException(message)
+
+        return resp, body
diff --git a/tempest/services/compute/v3/xml/interfaces_client.py b/tempest/services/compute/v3/xml/interfaces_client.py
new file mode 100644
index 0000000..a84e0bd
--- /dev/null
+++ b/tempest/services/compute/v3/xml/interfaces_client.py
@@ -0,0 +1,105 @@
+# Copyright 2013 IBM Corp.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import time
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest import exceptions
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import Text
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class InterfacesClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(InterfacesClientXML, self).__init__(config, username, password,
+                                                  auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _process_xml_interface(self, node):
+        iface = xml_to_json(node)
+        # NOTE(danms): if multiple addresses per interface is ever required,
+        # xml_to_json will need to be fixed or replaced in this case
+        iface['fixed_ips'] = [dict(iface['fixed_ips']['fixed_ip'].items())]
+        return iface
+
+    def list_interfaces(self, server):
+        resp, body = self.get('servers/%s/os-interface' % server, self.headers)
+        node = etree.fromstring(body)
+        interfaces = [self._process_xml_interface(x)
+                      for x in node.getchildren()]
+        return resp, interfaces
+
+    def create_interface(self, server, port_id=None, network_id=None,
+                         fixed_ip=None):
+        doc = Document()
+        iface = Element('interfaceAttachment')
+        if port_id:
+            _port_id = Element('port_id')
+            _port_id.append(Text(port_id))
+            iface.append(_port_id)
+        if network_id:
+            _network_id = Element('net_id')
+            _network_id.append(Text(network_id))
+            iface.append(_network_id)
+        if fixed_ip:
+            _fixed_ips = Element('fixed_ips')
+            _fixed_ip = Element('fixed_ip')
+            _ip_address = Element('ip_address')
+            _ip_address.append(Text(fixed_ip))
+            _fixed_ip.append(_ip_address)
+            _fixed_ips.append(_fixed_ip)
+            iface.append(_fixed_ips)
+        doc.append(iface)
+        resp, body = self.post('servers/%s/os-interface' % server,
+                               headers=self.headers,
+                               body=str(doc))
+        body = self._process_xml_interface(etree.fromstring(body))
+        return resp, body
+
+    def show_interface(self, server, port_id):
+        resp, body = self.get('servers/%s/os-interface/%s' % (server, port_id),
+                              self.headers)
+        body = self._process_xml_interface(etree.fromstring(body))
+        return resp, body
+
+    def delete_interface(self, server, port_id):
+        resp, body = self.delete('servers/%s/os-interface/%s' % (server,
+                                                                 port_id))
+        return resp, body
+
+    def wait_for_interface_status(self, server, port_id, status):
+        """Waits for a interface to reach a given status."""
+        resp, body = self.show_interface(server, port_id)
+        interface_status = body['port_state']
+        start = int(time.time())
+
+        while(interface_status != status):
+            time.sleep(self.build_interval)
+            resp, body = self.show_interface(server, port_id)
+            interface_status = body['port_state']
+
+            timed_out = int(time.time()) - start >= self.build_timeout
+
+            if interface_status != status and timed_out:
+                message = ('Interface %s failed to reach %s status within '
+                           'the required time (%s s).' %
+                           (port_id, status, self.build_timeout))
+                raise exceptions.TimeoutException(message)
+        return resp, body
diff --git a/tempest/services/compute/xml/instance_usage_audit_log_client.py b/tempest/services/compute/xml/instance_usage_audit_log_client.py
new file mode 100644
index 0000000..175997b
--- /dev/null
+++ b/tempest/services/compute/xml/instance_usage_audit_log_client.py
@@ -0,0 +1,41 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class InstanceUsagesAuditLogClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(InstanceUsagesAuditLogClientXML, self).__init__(
+            config, username, password, auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_instance_usage_audit_logs(self):
+        url = 'os-instance_usage_audit_log'
+        resp, body = self.get(url, self.headers)
+        instance_usage_audit_logs = xml_to_json(etree.fromstring(body))
+        return resp, instance_usage_audit_logs
+
+    def get_instance_usage_audit_log(self, time_before):
+        url = 'os-instance_usage_audit_log/%s' % time_before
+        resp, body = self.get(url, self.headers)
+        instance_usage_audit_log = xml_to_json(etree.fromstring(body))
+        return resp, instance_usage_audit_log
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index 670492a..93b28a2 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -201,3 +201,48 @@
         resp, body = self.post('volumes/%s/action' % volume_id, post_body,
                                self.headers)
         return resp, body
+
+    def create_volume_transfer(self, vol_id, display_name=None):
+        """Create a volume transfer."""
+        post_body = {
+            'volume_id': vol_id
+        }
+        if display_name:
+            post_body['name'] = display_name
+        post_body = json.dumps({'transfer': post_body})
+        resp, body = self.post('os-volume-transfer',
+                               post_body,
+                               self.headers)
+        body = json.loads(body)
+        return resp, body['transfer']
+
+    def get_volume_transfer(self, transfer_id):
+        """Returns the details of a volume transfer."""
+        url = "os-volume-transfer/%s" % str(transfer_id)
+        resp, body = self.get(url, self.headers)
+        body = json.loads(body)
+        return resp, body['transfer']
+
+    def list_volume_transfers(self, params=None):
+        """List all the volume transfers created."""
+        url = 'os-volume-transfer'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['transfers']
+
+    def delete_volume_transfer(self, transfer_id):
+        """Delete a volume transfer."""
+        return self.delete("os-volume-transfer/%s" % str(transfer_id))
+
+    def accept_volume_transfer(self, transfer_id, transfer_auth_key):
+        """Accept a volume transfer."""
+        post_body = {
+            'auth_key': transfer_auth_key,
+        }
+        url = 'os-volume-transfer/%s/accept' % transfer_id
+        post_body = json.dumps({'accept': post_body})
+        resp, body = self.post(url, post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['transfer']
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index 0edf7f3..b1e54ed 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -284,3 +284,56 @@
         if body:
             body = xml_to_json(etree.fromstring(body))
         return resp, body
+
+    def create_volume_transfer(self, vol_id, display_name=None):
+        """Create a volume transfer."""
+        post_body = Element("transfer",
+                            volume_id=vol_id)
+        if display_name:
+            post_body.add_attr('name', display_name)
+        resp, body = self.post('os-volume-transfer',
+                               str(Document(post_body)),
+                               self.headers)
+        volume = xml_to_json(etree.fromstring(body))
+        return resp, volume
+
+    def get_volume_transfer(self, transfer_id):
+        """Returns the details of a volume transfer."""
+        url = "os-volume-transfer/%s" % str(transfer_id)
+        resp, body = self.get(url, self.headers)
+        volume = xml_to_json(etree.fromstring(body))
+        return resp, volume
+
+    def list_volume_transfers(self, params=None):
+        """List all the volume transfers created."""
+        url = 'os-volume-transfer'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url, self.headers)
+        body = etree.fromstring(body)
+        volumes = []
+        if body is not None:
+            volumes += [self._parse_volume_transfer(vol) for vol in list(body)]
+        return resp, volumes
+
+    def _parse_volume_transfer(self, body):
+        vol = dict((attr, body.get(attr)) for attr in body.keys())
+        for child in body.getchildren():
+            tag = child.tag
+            if tag.startswith("{"):
+                tag = tag.split("}", 1)
+            vol[tag] = xml_to_json(child)
+        return vol
+
+    def delete_volume_transfer(self, transfer_id):
+        """Delete a volume transfer."""
+        return self.delete("os-volume-transfer/%s" % str(transfer_id))
+
+    def accept_volume_transfer(self, transfer_id, transfer_auth_key):
+        """Accept a volume transfer."""
+        post_body = Element("accept", auth_key=transfer_auth_key)
+        url = 'os-volume-transfer/%s/accept' % transfer_id
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        volume = xml_to_json(etree.fromstring(body))
+        return resp, volume
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index a32525d..d37ab6d 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -25,19 +25,12 @@
 from tempest.openstack.common import log as logging
 from tempest.stress import cleanup
 
-admin_manager = clients.AdminManager()
-
 LOG = logging.getLogger(__name__)
 processes = []
 
 
-def do_ssh(command, host):
-    username = admin_manager.config.stress.target_ssh_user
-    key_filename = admin_manager.config.stress.target_private_key_path
-    if not (username and key_filename):
-        LOG.error('username and key_filename should not be empty')
-        return None
-    ssh_client = ssh.Client(host, username, key_filename=key_filename)
+def do_ssh(command, host, ssh_user, ssh_key=None):
+    ssh_client = ssh.Client(host, ssh_user, key_filename=ssh_key)
     try:
         return ssh_client.exec_command(command)
     except exceptions.SSHExecCommandFailed:
@@ -46,14 +39,14 @@
         return None
 
 
-def _get_compute_nodes(controller):
+def _get_compute_nodes(controller, ssh_user, ssh_key=None):
     """
     Returns a list of active compute nodes. List is generated by running
     nova-manage on the controller.
     """
     nodes = []
     cmd = "nova-manage service list | grep ^nova-compute"
-    output = do_ssh(cmd, controller)
+    output = do_ssh(cmd, controller, ssh_user, ssh_key)
     if not output:
         return nodes
     # For example: nova-compute xg11eth0 nova enabled :-) 2011-10-31 18:57:46
@@ -65,14 +58,15 @@
     return nodes
 
 
-def _has_error_in_logs(logfiles, nodes, stop_on_error=False):
+def _has_error_in_logs(logfiles, nodes, ssh_user, ssh_key=None,
+                       stop_on_error=False):
     """
     Detect errors in the nova log files on the controller and compute nodes.
     """
     grep = 'egrep "ERROR|TRACE" %s' % logfiles
     ret = False
     for node in nodes:
-        errors = do_ssh(grep, node)
+        errors = do_ssh(grep, node, ssh_user, ssh_key)
         if len(errors) > 0:
             LOG.error('%s: %s' % (node, errors))
             ret = True
@@ -88,18 +82,17 @@
     terminate_all_processes()
 
 
-def terminate_all_processes():
+def terminate_all_processes(check_interval=20):
     """
     Goes through the process list and terminates all child processes.
     """
-    log_check_interval = int(admin_manager.config.stress.log_check_interval)
     for process in processes:
         if process['process'].is_alive():
             try:
                 process['process'].terminate()
             except Exception:
                 pass
-    time.sleep(log_check_interval)
+    time.sleep(check_interval)
     for process in processes:
         if process['process'].is_alive():
             try:
@@ -115,15 +108,19 @@
     """
     Workload driver. Executes an action function against a nova-cluster.
     """
+    admin_manager = clients.AdminManager()
+
+    ssh_user = admin_manager.config.stress.target_ssh_user
+    ssh_key = admin_manager.config.stress.target_private_key_path
     logfiles = admin_manager.config.stress.target_logfiles
     log_check_interval = int(admin_manager.config.stress.log_check_interval)
     default_thread_num = int(admin_manager.config.stress.
                              default_thread_number_per_action)
     if logfiles:
         controller = admin_manager.config.stress.target_controller
-        computes = _get_compute_nodes(controller)
+        computes = _get_compute_nodes(controller, ssh_user, ssh_key)
         for node in computes:
-            do_ssh("rm -f %s" % logfiles, node)
+            do_ssh("rm -f %s" % logfiles, node, ssh_user, ssh_key)
     for test in tests:
         if test.get('use_admin', False):
             manager = admin_manager
@@ -196,7 +193,8 @@
 
         if not logfiles:
             continue
-        if _has_error_in_logs(logfiles, computes, stop_on_error):
+        if _has_error_in_logs(logfiles, computes, ssh_user, ssh_key,
+                              stop_on_error):
             had_errors = True
             break
 
diff --git a/tools/tempest_auto_config.py b/tools/tempest_auto_config.py
index aef6a1f..fe9f5af 100644
--- a/tools/tempest_auto_config.py
+++ b/tools/tempest_auto_config.py
@@ -14,38 +14,50 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+#
+# This script aims to configure an initial Openstack environment with all the
+# necessary configurations for tempest's run using nothing but Openstack's
+# native API.
+# That includes, creating users, tenants, registering images (cirros),
+# configuring neutron and so on.
+#
+# ASSUMPTION: this script is run by an admin user as it is meant to configure
+# the Openstack environment prior to actual use.
 
 # Config
 import ConfigParser
 import os
+import tarfile
+import urllib2
 
 # Default client libs
+import glanceclient as glance_client
 import keystoneclient.v2_0.client as keystone_client
 
 # Import Openstack exceptions
+import glanceclient.exc as glance_exception
 import keystoneclient.exceptions as keystone_exception
 
 
-DEFAULT_CONFIG_DIR = "%s/etc" % os.path.abspath(os.path.pardir)
-DEFAULT_CONFIG_FILE = "tempest.conf"
-DEFAULT_CONFIG_SAMPLE = "tempest.conf.sample"
+TEMPEST_TEMP_DIR = os.getenv("TEMPEST_TEMP_DIR", "/tmp").rstrip('/')
+TEMPEST_ROOT_DIR = os.getenv("TEMPEST_ROOT_DIR", os.getenv("HOME")).rstrip('/')
 
 # Environment variables override defaults
-TEMPEST_CONFIG_DIR = os.environ.get('TEMPEST_CONFIG_DIR') or DEFAULT_CONFIG_DIR
-TEMPEST_CONFIG = os.environ.get('TEMPEST_CONFIG') or "%s/%s" % \
-    (TEMPEST_CONFIG_DIR, DEFAULT_CONFIG_FILE)
-TEMPEST_CONFIG_SAMPLE = os.environ.get('TEMPEST_CONFIG_SAMPLE') or "%s/%s" % \
-    (TEMPEST_CONFIG_DIR, DEFAULT_CONFIG_SAMPLE)
-
-# Admin credentials
-OS_USERNAME = os.environ.get('OS_USERNAME')
-OS_PASSWORD = os.environ.get('OS_PASSWORD')
-OS_TENANT_NAME = os.environ.get('OS_TENANT_NAME')
-OS_AUTH_URL = os.environ.get('OS_AUTH_URL')
-
+TEMPEST_CONFIG_DIR = os.getenv("TEMPEST_CONFIG_DIR",
+                               "%s%s" % (TEMPEST_ROOT_DIR, "/etc")).rstrip('/')
+TEMPEST_CONFIG_FILE = os.getenv("TEMPEST_CONFIG_FILE",
+                                "%s%s" % (TEMPEST_CONFIG_DIR, "/tempest.conf"))
+TEMPEST_CONFIG_SAMPLE = os.getenv("TEMPEST_CONFIG_SAMPLE",
+                                  "%s%s" % (TEMPEST_CONFIG_DIR,
+                                            "/tempest.conf.sample"))
 # Image references
-IMAGE_ID = os.environ.get('IMAGE_ID')
-IMAGE_ID_ALT = os.environ.get('IMAGE_ID_ALT')
+IMAGE_DOWNLOAD_CHUNK_SIZE = 8 * 1024
+IMAGE_UEC_SOURCE_URL = os.getenv("IMAGE_UEC_SOURCE_URL",
+                                 "http://download.cirros-cloud.net/0.3.1/"
+                                 "cirros-0.3.1-x86_64-uec.tar.gz")
+TEMPEST_IMAGE_ID = os.getenv('IMAGE_ID')
+TEMPEST_IMAGE_ID_ALT = os.getenv('IMAGE_ID_ALT')
+IMAGE_STATUS_ACTIVE = 'active'
 
 
 class ClientManager(object):
@@ -76,26 +88,52 @@
 
         return self.identity_client
 
+    def get_image_client(self, version="1", *args, **kwargs):
+        """
+        This method returns Openstack glance python client
+        :param version: a string representing the version of the glance client
+        to use.
+        :param string endpoint: A user-supplied endpoint URL for the glance
+                            service.
+        :param string token: Token for authentication.
+        :param integer timeout: Allows customization of the timeout for client
+                                http requests. (optional)
+        :return: a Client object representing the glance client
+        """
+        if not self.image_client:
+            self.image_client = glance_client.Client(version, *args, **kwargs)
 
-def getTempestConfigSample():
+        return self.image_client
+
+
+def get_tempest_config(path_to_config):
     """
     Gets the tempest configuration file as a ConfigParser object
-    :return: the tempest configuration file
+    :param path_to_config: path to the config file
+    :return: a ConfigParser object representing the tempest configuration file
     """
     # get the sample config file from the sample
-    config_sample = ConfigParser.ConfigParser()
-    config_sample.readfp(open(TEMPEST_CONFIG_SAMPLE))
+    config = ConfigParser.ConfigParser()
+    config.readfp(open(path_to_config))
 
-    return config_sample
+    return config
 
 
 def update_config_admin_credentials(config, config_section):
     """
     Updates the tempest config with the admin credentials
-    :param config: an object representing the tempest config file
+    :param config: a ConfigParser object representing the tempest config file
     :param config_section: the section name where the admin credentials are
     """
-    # Check if credentials are present
+    # Check if credentials are present, default uses the config credentials
+    OS_USERNAME = os.getenv('OS_USERNAME',
+                            config.get(config_section, "admin_username"))
+    OS_PASSWORD = os.getenv('OS_PASSWORD',
+                            config.get(config_section, "admin_password"))
+    OS_TENANT_NAME = os.getenv('OS_TENANT_NAME',
+                               config.get(config_section, "admin_tenant_name"))
+    OS_AUTH_URL = os.getenv('OS_AUTH_URL', config.get(config_section, "uri"))
+
     if not (OS_AUTH_URL and
             OS_USERNAME and
             OS_PASSWORD and
@@ -113,31 +151,31 @@
                                       config_identity_params)
 
 
-def update_config_section_with_params(config, section, params):
+def update_config_section_with_params(config, config_section, params):
     """
     Updates a given config object with given params
-    :param config: the object representing the config file of tempest
-    :param section: the section we would like to update
+    :param config: a ConfigParser object representing the tempest config file
+    :param config_section: the section we would like to update
     :param params: the parameters we wish to update for that section
     """
     for option, value in params.items():
-        config.set(section, option, value)
+        config.set(config_section, option, value)
 
 
-def get_identity_client_kwargs(config, section_name):
+def get_identity_client_kwargs(config, config_section):
     """
     Get the required arguments for the identity python client
-    :param config: the tempest configuration file
-    :param section_name: the section name in the configuration where the
+    :param config: a ConfigParser object representing the tempest config file
+    :param config_section: the section name in the configuration where the
     arguments can be found
     :return: a dictionary representing the needed arguments for the identity
     client
     """
-    username = config.get(section_name, 'admin_username')
-    password = config.get(section_name, 'admin_password')
-    tenant_name = config.get(section_name, 'admin_tenant_name')
-    auth_url = config.get(section_name, 'uri')
-    dscv = config.get(section_name, 'disable_ssl_certificate_validation')
+    username = config.get(config_section, 'admin_username')
+    password = config.get(config_section, 'admin_password')
+    tenant_name = config.get(config_section, 'admin_tenant_name')
+    auth_url = config.get(config_section, 'uri')
+    dscv = config.get(config_section, 'disable_ssl_certificate_validation')
     kwargs = {'username': username,
               'password': password,
               'tenant_name': tenant_name,
@@ -185,21 +223,21 @@
 
 def create_users_and_tenants(identity_client,
                              config,
-                             identity_section):
+                             config_section):
     """
     Creates the two non admin users and tenants for tempest
     :param identity_client: openstack identity python client
-    :param config: tempest configuration file
-    :param identity_section: the section name of identity in the config
+    :param config: a ConfigParser object representing the tempest config file
+    :param config_section: the section name of identity in the config
     """
     # Get the necessary params from the config file
-    tenant_name = config.get(identity_section, 'tenant_name')
-    username = config.get(identity_section, 'username')
-    password = config.get(identity_section, 'password')
+    tenant_name = config.get(config_section, 'tenant_name')
+    username = config.get(config_section, 'username')
+    password = config.get(config_section, 'password')
 
-    alt_tenant_name = config.get(identity_section, 'alt_tenant_name')
-    alt_username = config.get(identity_section, 'alt_username')
-    alt_password = config.get(identity_section, 'alt_password')
+    alt_tenant_name = config.get(config_section, 'alt_tenant_name')
+    alt_username = config.get(config_section, 'alt_username')
+    alt_password = config.get(config_section, 'alt_password')
 
     # Create the necessary users for the test runs
     create_user_with_tenant(identity_client, username, password, tenant_name)
@@ -207,28 +245,153 @@
                             alt_tenant_name)
 
 
+def get_image_client_kwargs(identity_client, config, config_section):
+    """
+    Get the required arguments for the image python client
+    :param identity_client: openstack identity python client
+    :param config: a ConfigParser object representing the tempest config file
+    :param config_section: the section name of identity in the config
+    :return: a dictionary representing the needed arguments for the image
+    client
+    """
+
+    token = identity_client.auth_token
+    endpoint = identity_client.\
+        service_catalog.url_for(service_type='image', endpoint_type='publicURL'
+                                )
+    dscv = config.get(config_section, 'disable_ssl_certificate_validation')
+    kwargs = {'endpoint': endpoint,
+              'token': token,
+              'insecure': dscv}
+
+    return kwargs
+
+
+def images_exist(image_client):
+    """
+    Checks whether the images ID's located in the environment variable are
+    indeed registered
+    :param image_client: the openstack python client representing the image
+    client
+    """
+    exist = True
+    if not TEMPEST_IMAGE_ID or not TEMPEST_IMAGE_ID_ALT:
+        exist = False
+    else:
+        try:
+            image_client.images.get(TEMPEST_IMAGE_ID)
+            image_client.images.get(TEMPEST_IMAGE_ID_ALT)
+        except glance_exception.HTTPNotFound:
+            exist = False
+
+    return exist
+
+
+def download_and_register_uec_images(image_client, download_url,
+                                     download_folder):
+    """
+    Downloads and registered the UEC AKI/AMI/ARI images
+    :param image_client:
+    :param download_url: the url of the uec tar file
+    :param download_folder: the destination folder we wish to save the file to
+    """
+    basename = os.path.basename(download_url)
+    path = os.path.join(download_folder, basename)
+
+    request = urllib2.urlopen(download_url)
+
+    # First, download the file
+    with open(path, "wb") as fp:
+        while True:
+            chunk = request.read(IMAGE_DOWNLOAD_CHUNK_SIZE)
+            if not chunk:
+                break
+
+            fp.write(chunk)
+
+    # Then extract and register images
+    tar = tarfile.open(path, "r")
+    for name in tar.getnames():
+        file_obj = tar.extractfile(name)
+        format = "aki"
+
+        if file_obj.name.endswith(".img"):
+            format = "ami"
+
+        if file_obj.name.endswith("initrd"):
+            format = "ari"
+
+        # Register images in image client
+        image_client.images.create(name=file_obj.name, disk_format=format,
+                                   container_format=format, data=file_obj,
+                                   is_public="true")
+
+    tar.close()
+
+
+def create_images(image_client, config, config_section,
+                  download_url=IMAGE_UEC_SOURCE_URL,
+                  download_folder=TEMPEST_TEMP_DIR):
+    """
+    Creates images for tempest's use and registers the environment variables
+    IMAGE_ID and IMAGE_ID_ALT with registered images
+    :param image_client: Openstack python image client
+    :param config: a ConfigParser object representing the tempest config file
+    :param config_section: the section name where the IMAGE ids are set
+    :param download_url: the URL from which we should download the UEC tar
+    :param download_folder: the place where we want to save the download file
+    """
+    if not images_exist(image_client):
+        # Falls down to the default uec images
+        download_and_register_uec_images(image_client, download_url,
+                                         download_folder)
+        image_ids = []
+        for image in image_client.images.list():
+            image_ids.append(image.id)
+
+        os.environ["IMAGE_ID"] = image_ids[0]
+        os.environ["IMAGE_ID_ALT"] = image_ids[1]
+
+    params = {'image_ref': os.getenv("IMAGE_ID"),
+              'image_ref_alt': os.getenv("IMAGE_ID_ALT")}
+
+    update_config_section_with_params(config, config_section, params)
+
+
 def main():
     """
     Main module to control the script
     """
-    # TODO(tkammer): add support for existing config file
-    config_sample = getTempestConfigSample()
-    update_config_admin_credentials(config_sample, 'identity')
+    # Check if config file exists or fall to the default sample otherwise
+    path_to_config = TEMPEST_CONFIG_SAMPLE
+
+    if os.path.isfile(TEMPEST_CONFIG_FILE):
+        path_to_config = TEMPEST_CONFIG_FILE
+
+    config = get_tempest_config(path_to_config)
+    update_config_admin_credentials(config, 'identity')
 
     client_manager = ClientManager()
 
     # Set the identity related info for tempest
-    identity_client_kwargs = get_identity_client_kwargs(config_sample,
+    identity_client_kwargs = get_identity_client_kwargs(config,
                                                         'identity')
     identity_client = client_manager.get_identity_client(
         **identity_client_kwargs)
 
     # Create the necessary users and tenants for tempest run
-    create_users_and_tenants(identity_client,
-                             config_sample,
-                             'identity')
+    create_users_and_tenants(identity_client, config, 'identity')
 
-    # TODO(tkammer): add image implementation
+    # Set the image related info for tempest
+    image_client_kwargs = get_image_client_kwargs(identity_client,
+                                                  config,
+                                                  'identity')
+    image_client = client_manager.get_image_client(**image_client_kwargs)
+
+    # Create the necessary users and tenants for tempest run
+    create_images(image_client, config, 'compute')
+
+    # TODO(tkammer): add network implementation
 
 if __name__ == "__main__":
     main()