Merge "Cleanup using about the data_utils module and functions again"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index f1a6f67..567b85a 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -1,458 +1,737 @@
 [DEFAULT]
-#log_config = /opt/stack/tempest/etc/logging.conf.sample
 
-# disable logging to the stderr
-use_stderr = false
+#
+# Options defined in tempest.openstack.common.lockutils
+#
 
-# log file
-log_file = tempest.log
+# Whether to disable inter-process locks (boolean value)
+#disable_process_locking=false
 
-# lock/semaphore base directory
-lock_path=/tmp
+# Directory to use for lock files. (string value)
+#lock_path=<None>
 
-default_log_levels=tempest.stress=INFO,amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO,eventlet.wsgi.server=WARN
+
+#
+# Options defined in tempest.openstack.common.log
+#
+
+# Print debugging output (set logging level to DEBUG instead
+# of default WARNING level). (boolean value)
+#debug=false
+
+# Print more verbose output (set logging level to INFO instead
+# of default WARNING level). (boolean value)
+#verbose=false
+
+# Log output to standard error (boolean value)
+#use_stderr=true
+
+# format string to use for log messages with context (string
+# value)
+#logging_context_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s%(message)s
+
+# format string to use for log messages without context
+# (string value)
+#logging_default_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
+
+# data to append to log format when level is DEBUG (string
+# value)
+#logging_debug_format_suffix=%(funcName)s %(pathname)s:%(lineno)d
+
+# prefix each line of exception output with this format
+# (string value)
+#logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
+
+# list of logger=LEVEL pairs (list value)
+#default_log_levels=amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO
+
+# publish error events (boolean value)
+#publish_errors=false
+
+# make deprecations fatal (boolean value)
+#fatal_deprecations=false
+
+# If an instance is passed with the log message, format it
+# like this (string value)
+#instance_format="[instance: %(uuid)s] "
+
+# If an instance UUID is passed with the log message, format
+# it like this (string value)
+#instance_uuid_format="[instance: %(uuid)s] "
+
+# If this option is specified, the logging configuration file
+# specified is used and overrides any other logging options
+# specified. Please see the Python logging module
+# documentation for details on logging configuration files.
+# (string value)
+#log_config=<None>
+
+# DEPRECATED. A logging.Formatter log message format string
+# which may use any of the available logging.LogRecord
+# attributes. This option is deprecated.  Please use
+# logging_context_format_string and
+# logging_default_format_string instead. (string value)
+#log_format=<None>
+
+# Format string for %%(asctime)s in log records. Default:
+# %(default)s (string value)
+#log_date_format=%Y-%m-%d %H:%M:%S
+
+# (Optional) Name of log file to output to. If no default is
+# set, logging will go to stdout. (string value)
+# Deprecated group/name - [DEFAULT]/logfile
+#log_file=<None>
+
+# (Optional) The base directory used for relative --log-file
+# paths (string value)
+# Deprecated group/name - [DEFAULT]/logdir
+#log_dir=<None>
+
+# Use syslog for logging. (boolean value)
+#use_syslog=false
+
+# syslog facility to receive log lines (string value)
+#syslog_log_facility=LOG_USER
+
 
 [identity]
-# This section contains configuration options that a variety of Tempest
-# test clients use when authenticating with different user/tenant
-# combinations
 
-# The type of endpoint for a Identity service. Unless you have a
-# custom Keystone service catalog implementation, you probably want to leave
-# this value as "identity"
-catalog_type = identity
-# Ignore SSL certificate validation failures? Use when in testing
-# environments that have self-signed SSL certs.
-disable_ssl_certificate_validation = false
-# URL for where to find the OpenStack Identity API endpoint (Keystone)
-uri = http://127.0.0.1:5000/v2.0/
-# URL for where to find the OpenStack V3 Identity API endpoint (Keystone)
-uri_v3 = http://127.0.0.1:5000/v3/
-# The identity region. Also used as the other services' region name unless
-# they are set explicitly.
-region = RegionOne
+#
+# Options defined in tempest.config
+#
 
-# This should be the username of a user WITHOUT administrative privileges
-username = demo
-# The above non-administrative user's password
-password = secret
-# The above non-administrative user's tenant name
-tenant_name = demo
+# Catalog type of the Identity service. (string value)
+#catalog_type=identity
 
-# This should be the username of an alternate user WITHOUT
-# administrative privileges
-alt_username = alt_demo
-# The above non-administrative user's password
-alt_password = secret
-# The above non-administrative user's tenant name
-alt_tenant_name = alt_demo
+# Set to True if using self-signed SSL certificates. (boolean
+# value)
+#disable_ssl_certificate_validation=false
 
-# This should be the username of a user WITH administrative privileges
-admin_username = admin
-# The above administrative user's password
-admin_password = secret
-# The above administrative user's tenant name
-admin_tenant_name = admin
+# Full URI of the OpenStack Identity API (Keystone), v2
+# (string value)
+#uri=<None>
 
-# The role that is required to administrate keystone.
-admin_role = admin
+# Full URI of the OpenStack Identity API (Keystone), v3
+# (string value)
+#uri_v3=<None>
 
-[compute]
-# This section contains configuration options used when executing tests
-# against the OpenStack Compute API.
+# The identity region name to use. Also used as the other
+# services' region name unless they are set explicitly. If no
+# such region is found in the service catalog, the first found
+# one is used. (string value)
+#region=RegionOne
 
-# Allows test cases to create/destroy tenants and users. This option
-# enables isolated test cases and better parallel execution,
-# but also requires that OpenStack Identity API admin credentials
-# are known.
-allow_tenant_isolation = true
+# Username to use for Nova API requests. (string value)
+#username=demo
 
-# Allows test cases to create/destroy tenants and users. This option
-# enables isolated test cases and better parallel execution,
-# but also requires that OpenStack Identity API admin credentials
-# are known.
-allow_tenant_reuse = true
+# Tenant name to use for Nova API requests. (string value)
+#tenant_name=demo
 
-# Reference data for tests. The ref and ref_alt should be
-# distinct images/flavors.
-image_ref = {$IMAGE_ID}
-image_ref_alt = {$IMAGE_ID_ALT}
-flavor_ref = 1
-flavor_ref_alt = 2
+# Role required to administrate keystone. (string value)
+#admin_role=admin
 
-# User name used to authenticate to an instance
-image_ssh_user = root
+# API key to use when authenticating. (string value)
+#password=pass
 
-# Password used to authenticate to an instance
-image_ssh_password = password
+# Username of alternate user to use for Nova API requests.
+# (string value)
+#alt_username=<None>
 
-# User name used to authenticate to an instance using the alternate image
-image_alt_ssh_user = root
+# Alternate user's Tenant name to use for Nova API requests.
+# (string value)
+#alt_tenant_name=<None>
 
-# Password used to authenticate to an instance using the alternate image
-image_alt_ssh_password = password
+# API key to use when authenticating as alternate user.
+# (string value)
+#alt_password=<None>
 
-# Number of seconds to wait while looping to check the status of an
-# instance that is building.
-build_interval = 10
+# Administrative Username to use forKeystone API requests.
+# (string value)
+#admin_username=admin
 
-# Number of seconds to time out on waiting for an instance
-# to build or reach an expected status
-build_timeout = 600
+# Administrative Tenant name to use for Keystone API requests.
+# (string value)
+#admin_tenant_name=admin
 
-# Run additional tests that use SSH for instance validation?
-# This requires the instances be routable from the host
-#  executing the tests
-run_ssh = false
+# API key to use when authenticating as admin. (string value)
+#admin_password=pass
 
-# Name of a user used to authenticate to an instance.
-ssh_user = cirros
 
-# Visible fixed network name
-fixed_network_name = private
+[stress]
 
-# Network id used for SSH (public, private, etc)
-network_for_ssh = public
+#
+# Options defined in tempest.config
+#
 
-# IP version of the address used for SSH
-ip_version_for_ssh = 4
+# Directory containing log files on the compute nodes (string
+# value)
+#nova_logdir=<None>
 
-# Number of seconds to wait to ping to an instance
-ping_timeout = 60
+# Maximum number of instances to create during test. (integer
+# value)
+#max_instances=16
 
-# Number of seconds to wait to authenticate to an instance
-ssh_timeout = 300
+# Controller host. (string value)
+#controller=<None>
 
-# Additinal wait time for clean state, when there is
-# no OS-EXT-STS extension availiable
-ready_wait = 0
+# Controller host. (string value)
+#target_controller=<None>
 
-# Number of seconds to wait for output from ssh channel
-ssh_channel_timeout = 60
+# ssh user. (string value)
+#target_ssh_user=<None>
 
-# Dose the SSH uses Floating IP?
-use_floatingip_for_ssh = true
+# Path to private key. (string value)
+#target_private_key_path=<None>
 
-# The type of endpoint for a Compute API service. Unless you have a
-# custom Keystone service catalog implementation, you probably want to leave
-# this value as "compute"
-catalog_type = compute
+# regexp for list of log files. (string value)
+#target_logfiles=<None>
 
-# The type of endpoint for a Compute v3 API service. Unless you have a
-# custom Keystone service catalog implementation, you probably want to leave
-# this value as "computev3"
-catalog_v3_type = computev3
+# time (in seconds) between log file error checks. (integer
+# value)
+#log_check_interval=60
 
-# The name of a region for compute. If empty or commented-out, the value of
-# identity.region is used instead. If no such region is found in the service
-# catalog, the first found one is used.
-#region = RegionOne
+# The number of threads created while stress test. (integer
+# value)
+#default_thread_number_per_action=4
 
-# Expected first device name when a volume is attached to an instance
-volume_device_name = vdb
-
-[compute-feature-enabled]
-# Do we run the Nova V3 API tests?
-api_v3 = false
-
-# Does the Compute API support creation of images?
-create_image = true
-
-# For resize to work with libvirt/kvm, one of the following must be true:
-# Single node: allow_resize_to_same_host=true must be set in nova.conf
-# Cluster: the 'nova' user must have scp access between cluster nodes
-resize = true
-
-# Does the compute API support changing the admin password?
-change_password = false
-
-# Run live migration tests (requires 2 hosts)
-live_migration = false
-
-# Use block live migration (Otherwise, non-block migration will be
-# performed, which requires XenServer pools in case of using XS)
-block_migration_for_live_migration = false
-
-# Supports iSCSI block migration - depends on a XAPI supporting
-# relax-xsm-sr-check
-block_migrate_cinder_iscsi = false
-
-# When set to false, disk config tests are forced to skip
-disk_config = true
-
-# When set to false, flavor extra data tests are forced to skip
-flavor_extra = true
-
-[compute-admin]
-# This should be the username of a user WITH administrative privileges
-# If not defined the admin user from the identity section will be used
-username =
-# The above administrative user's password
-password =
-# The above administrative user's tenant name
-tenant_name =
-
-[image]
-# This section contains configuration options used when executing tests
-# against the OpenStack Images API
-
-# The type of endpoint for an Image API service. Unless you have a
-# custom Keystone service catalog implementation, you probably want to leave
-# this value as "image"
-catalog_type = image
-
-# The name of a region for image. If empty or commented-out, the value of
-# identity.region is used instead. If no such region is found in the service
-# catalog, the first found one is used.
-#region = RegionOne
-
-# HTTP image to use for glance http image testing
-http_image = http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
 
 [image-feature-enabled]
-# Is the image api_v1 enabled
-api_v1 = True
-# Is the image api_v2 enabled
-api_v2 = True
+
+#
+# Options defined in tempest.config
+#
+
+# Is the v2 image API enabled (boolean value)
+#api_v2=true
+
+# Is the v1 image API enabled (boolean value)
+#api_v1=true
+
+
+[compute]
+
+#
+# Options defined in tempest.config
+#
+
+# Allows test cases to create/destroy tenants and users. This
+# option enables isolated test cases and better parallel
+# execution, but also requires that OpenStack Identity API
+# admin credentials are known. (boolean value)
+#allow_tenant_isolation=false
+
+# If allow_tenant_isolation is True and a tenant that would be
+# created for a given test already exists (such as from a
+# previously-failed run), re-use that tenant instead of
+# failing because of the conflict. Note that this would result
+# in the tenant being deleted at the end of a subsequent
+# successful run. (boolean value)
+#allow_tenant_reuse=true
+
+# Valid secondary image reference to be used in tests. (string
+# value)
+#image_ref={$IMAGE_ID}
+
+# Valid secondary image reference to be used in tests. (string
+# value)
+#image_ref_alt={$IMAGE_ID_ALT}
+
+# Valid primary flavor to use in tests. (integer value)
+#flavor_ref=1
+
+# Valid secondary flavor to be used in tests. (integer value)
+#flavor_ref_alt=2
+
+# User name used to authenticate to an instance. (string
+# value)
+#image_ssh_user=root
+
+# Password used to authenticate to an instance. (string value)
+#image_ssh_password=password
+
+# User name used to authenticate to an instance using the
+# alternate image. (string value)
+#image_alt_ssh_user=root
+
+# Password used to authenticate to an instance using the
+# alternate image. (string value)
+#image_alt_ssh_password=password
+
+# Time in seconds between build status checks. (integer value)
+#build_interval=10
+
+# Timeout in seconds to wait for an instance to build.
+# (integer value)
+#build_timeout=300
+
+# Does the test environment support snapshots? (boolean value)
+#run_ssh=false
+
+# User name used to authenticate to an instance. (string
+# value)
+#ssh_user=root
+
+# Timeout in seconds to wait for ping to succeed. (integer
+# value)
+#ping_timeout=60
+
+# Timeout in seconds to wait for authentication to succeed.
+# (integer value)
+#ssh_timeout=300
+
+# Additional wait time for clean state, when there is no OS-
+# EXT-STS extension available (integer value)
+#ready_wait=0
+
+# Timeout in seconds to wait for output from ssh channel.
+# (integer value)
+#ssh_channel_timeout=60
+
+# Visible fixed network name  (string value)
+#fixed_network_name=private
+
+# Network used for SSH connections. (string value)
+#network_for_ssh=public
+
+# IP version used for SSH connections. (integer value)
+#ip_version_for_ssh=4
+
+# Dose the SSH uses Floating IP? (boolean value)
+#use_floatingip_for_ssh=true
+
+# Catalog type of the Compute service. (string value)
+#catalog_type=compute
+
+# The compute region name to use. If empty, the value of
+# identity.region is used instead. If no such region is found
+# in the service catalog, the first found one is used. (string
+# value)
+#region=
+
+# Catalog type of the Compute v3 service. (string value)
+#catalog_v3_type=computev3
+
+# Path to a private key file for SSH access to remote hosts
+# (string value)
+#path_to_private_key=<None>
+
+# Expected device name when a volume is attached to an
+# instance (string value)
+#volume_device_name=vdb
+
+# Time in seconds before a shelved instance is eligible for
+# removing from a host.  -1 never offload, 0 offload when
+# shelved. This time should be the same as the time of
+# nova.conf, and some tests will run for as long as the time.
+# (integer value)
+#shelved_offload_time=0
+
 
 [network]
-# This section contains configuration options used when executing tests
-# against the OpenStack Network API.
 
-# Version of the Neutron API
-api_version = v1.1
-# Catalog type of the Neutron Service
-catalog_type = network
+#
+# Options defined in tempest.config
+#
 
-# The name of a region for network. If empty or commented-out, the value of
-# identity.region is used instead. If no such region is found in the service
-# catalog, the first found one is used.
-#region = RegionOne
+# Catalog type of the Neutron service. (string value)
+#catalog_type=network
 
-# A large private cidr block from which to allocate smaller blocks for
-# tenant networks.
-tenant_network_cidr = 10.100.0.0/16
+# The network region name to use. If empty, the value of
+# identity.region is used instead. If no such region is found
+# in the service catalog, the first found one is used. (string
+# value)
+#region=
 
-# The mask bits used to partition the tenant block.
-tenant_network_mask_bits = 24
+# The cidr block to allocate tenant networks from (string
+# value)
+#tenant_network_cidr=10.100.0.0/16
 
-# If tenant networks are reachable, connectivity checks will be
-# performed directly against addresses on those networks.
-tenant_networks_reachable = false
+# The mask bits for tenant networks (integer value)
+#tenant_network_mask_bits=28
 
-# Id of the public network that provides external connectivity.
-public_network_id = {$PUBLIC_NETWORK_ID}
+# Whether tenant network connectivity should be evaluated
+# directly (boolean value)
+#tenant_networks_reachable=false
 
-# Id of a shared public router that provides external connectivity.
-# A shared public router would commonly be used where IP namespaces
-# were disabled.  If namespaces are enabled, it would be preferable
-# for each tenant to have their own router.
-public_router_id = {$PUBLIC_ROUTER_ID}
+# Id of the public network that provides external connectivity
+# (string value)
+#public_network_id=
+
+# Id of the public router that provides external connectivity
+# (string value)
+#public_router_id=
+
+
+[boto]
+
+#
+# Options defined in tempest.config
+#
+
+# EC2 URL (string value)
+#ec2_url=http://localhost:8773/services/Cloud
+
+# S3 URL (string value)
+#s3_url=http://localhost:8080
+
+# AWS Secret Key (string value)
+#aws_secret=<None>
+
+# AWS Access Key (string value)
+#aws_access=<None>
+
+# S3 Materials Path (string value)
+#s3_materials_path=/opt/stack/devstack/files/images/s3-materials/cirros-0.3.0
+
+# ARI Ramdisk Image manifest (string value)
+#ari_manifest=cirros-0.3.0-x86_64-initrd.manifest.xml
+
+# AMI Machine Image manifest (string value)
+#ami_manifest=cirros-0.3.0-x86_64-blank.img.manifest.xml
+
+# AKI Kernel Image manifest (string value)
+#aki_manifest=cirros-0.3.0-x86_64-vmlinuz.manifest.xml
+
+# Instance type (string value)
+#instance_type=m1.tiny
+
+# boto Http socket timeout (integer value)
+#http_socket_timeout=3
+
+# boto num_retries on error (integer value)
+#num_retries=1
+
+# Status Change Timeout (integer value)
+#build_timeout=60
+
+# Status Change Test Interval (integer value)
+#build_interval=1
+
+
+[scenario]
+
+#
+# Options defined in tempest.config
+#
+
+# Directory containing image files (string value)
+#img_dir=/opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
+
+# AMI image file name (string value)
+#ami_img_file=cirros-0.3.1-x86_64-blank.img
+
+# ARI image file name (string value)
+#ari_img_file=cirros-0.3.1-x86_64-initrd
+
+# AKI image file name (string value)
+#aki_img_file=cirros-0.3.1-x86_64-vmlinuz
+
+# ssh username for the image file (string value)
+#ssh_user=cirros
+
+# specifies how many resources to request at once. Used for
+# large operations testing. (integer value)
+#large_ops_number=0
+
+
+[image]
+
+#
+# Options defined in tempest.config
+#
+
+# Catalog type of the Image service. (string value)
+#catalog_type=image
+
+# The image region name to use. If empty, the value of
+# identity.region is used instead. If no such region is found
+# in the service catalog, the first found one is used. (string
+# value)
+#region=
+
+# http accessible image (string value)
+#http_image=http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
+
+
+[compute-admin]
+
+#
+# Options defined in tempest.config
+#
+
+# Administrative Username to use for Nova API requests.
+# (string value)
+#username=admin
+
+# Administrative Tenant name to use for Nova API requests.
+# (string value)
+#tenant_name=admin
+
+# API key to use when authenticating as admin. (string value)
+#password=pass
+
+
+[cli]
+
+#
+# Options defined in tempest.cli
+#
+
+# enable cli tests (boolean value)
+#enabled=true
+
+# directory where python client binaries are located (string
+# value)
+#cli_dir=/usr/local/bin
+
+# Number of seconds to wait on a CLI timeout (integer value)
+#timeout=15
 
 
 [volume]
-# This section contains the configuration options used when executing tests
-# against the OpenStack Block Storage API service
 
-# The type of endpoint for a Cinder or Block Storage API service.
-# Unless you have a custom Keystone service catalog implementation, you
-# probably want to leave this value as "volume"
-catalog_type = volume
-# The name of a region for volume. If empty or commented-out, the value of
-# identity.region is used instead. If no such region is found in the service
-# catalog, the first found one is used.
-#region = RegionOne
-# The disk format to use when copying a volume to image
-disk_format = raw
-# Number of seconds to wait while looping to check the status of a
-# volume that is being made available
-build_interval = 10
-# Number of seconds to time out on waiting for a volume
-# to be available or reach an expected status
-build_timeout = 300
-# If multi_backend is enabled there must be 2 volume_backend_names (
-# backend1_name and backend2_name) which have to be different)
-backend1_name = BACKEND_1
-backend2_name = BACKEND_2
-# Protocol and vendor of volume backend to target when testing volume-types.
-# You should update to reflect those exported by configured backend driver.
-storage_protocol = iSCSI
-vendor_name = Open Source
+#
+# Options defined in tempest.config
+#
 
-[volume-feature-enabled]
-#Runs Cinder multi-backend tests (requires 2 backends declared in cinder.conf)
-multi_backend = false
+# Time in seconds between volume availability checks. (integer
+# value)
+#build_interval=10
 
-[object-storage]
-# This section contains configuration options used when executing tests
-# against the OpenStack Object Storage API.
+# Timeout in seconds to wait for a volume to becomeavailable.
+# (integer value)
+#build_timeout=300
 
-# You can configure the credentials in the compute section
+# Catalog type of the Volume Service (string value)
+#catalog_type=volume
 
-# The type of endpoint for an Object Storage API service. Unless you have a
-# custom Keystone service catalog implementation, you probably want to leave
-# this value as "object-store"
-catalog_type = object-store
+# The volume region name to use. If empty, the value of
+# identity.region is used instead. If no such region is found
+# in the service catalog, the first found one is used. (string
+# value)
+#region=
 
-# The name of a region for object storage. If empty or commented-out, the
-# value of identity.region is used instead. If no such region is found in
-# the service catalog, the first found one is used.
-#region = RegionOne
+# Name of the backend1 (must be declared in cinder.conf)
+# (string value)
+#backend1_name=BACKEND_1
 
-# Number of seconds to time on waiting for a container to container
-# synchronization complete
-container_sync_timeout = 120
-# Number of seconds to wait while looping to check the status of a
-# container to container synchronization
-container_sync_interval = 5
+# Name of the backend2 (must be declared in cinder.conf)
+# (string value)
+#backend2_name=BACKEND_2
 
-# Set operator role for tests that require creating a container
-operator_role = Member
+# Backend protocol to target when creating volume types
+# (string value)
+#storage_protocol=iSCSI
 
-[object-storage-feature-enabled]
-# Set to True if the Account Quota middleware is enabled
-accounts_quotas = True
-# Set to True if the Container Quota middleware is enabled
-container_quotas = True
-# Set to True if the Crossdomain middleware is enabled
-crossdomain_available = True
+# Backend vendor to target when creating volume types (string
+# value)
+#vendor_name=Open Source
 
-[boto]
-# This section contains configuration options used when executing tests
-# with boto.
+# Disk format to use when copying a volume to image (string
+# value)
+#disk_format=raw
 
-# EC2 URL
-ec2_url = http://localhost:8773/services/Cloud
-# S3 URL
-s3_url = http://localhost:3333
-
-# Use keystone ec2-* command to get those values for your test user and tenant
-aws_access =
-aws_secret =
-
-# Image materials for S3 upload
-# ALL content of the specified directory will be uploaded to S3
-s3_materials_path = /opt/stack/devstack/files/images/s3-materials/cirros-0.3.1
-
-# The manifest.xml files, must be in the s3_materials_path directory
-# Subdirectories not allowed!
-# The filenames will be used as a Keys in the S3 Buckets
-
-# ARI Ramdisk manifest. Must be in the above s3_materials_path
-ari_manifest = cirros-0.3.1-x86_64-initrd.manifest.xml
-
-# AMI Machine Image manifest. Must be in the above s3_materials_path
-ami_manifest = cirros-0.3.1-x86_64-blank.img.manifest.xml
-
-# AKI Kernel Image manifest, Must be in the above s3_materials_path
-aki_manifest = cirros-0.3.1-x86_64-vmlinuz.manifest.xml
-
-# Instance type
-instance_type = m1.tiny
-
-# TCP/IP connection timeout
-http_socket_timeout = 5
-
-# Number of retries actions on connection or 5xx error
-num_retries = 1
-
-# Status change wait timout
-build_timeout = 120
-
-# Status change wait interval
-build_interval = 1
-
-[orchestration]
-# The type of endpoint for an Orchestration API service. Unless you have a
-# custom Keystone service catalog implementation, you probably want to leave
-# this value as "orchestration"
-catalog_type = orchestration
-
-# The name of a region for orchestration. If empty or commented-out, the value
-# of identity.region is used instead. If no such region is found in the service
-# catalog, the first found one is used.
-#region = RegionOne
-
-# Status change wait interval
-build_interval = 1
-
-# Status change wait timout. This may vary across environments as some some
-# tests spawn full VMs, which could be slow if the test is already in a VM.
-build_timeout = 300
-
-# Instance type for tests. Needs to be big enough for a
-# full OS plus the test workload
-instance_type = m1.micro
-
-# Name of heat-cfntools enabled image to use when launching test instances
-# If not specified, tests that spawn instances will not run
-#image_ref = ubuntu-vm-heat-cfntools
-
-# Name of existing keypair to launch servers with. The default is not to specify
-# any key, which will generate a keypair for each test class
-#keypair_name = heat_key
 
 [dashboard]
-# URL where to find the dashboard home page
-dashboard_url = 'http://localhost/'
 
-# URL where to submit the login form
-login_url = 'http://localhost/auth/login/'
+#
+# Options defined in tempest.config
+#
 
-[scenario]
-# Directory containing image files
-img_dir = /opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
+# Where the dashboard can be found (string value)
+#dashboard_url=http://localhost/
 
-# AMI image file name
-ami_img_file = cirros-0.3.1-x86_64-blank.img
+# Login page for the dashboard (string value)
+#login_url=http://localhost/auth/login/
 
-# ARI image file name
-ari_img_file = cirros-0.3.1-x86_64-initrd
 
-# AKI image file name
-aki_img_file = cirros-0.3.1-x86_64-vmlinuz
+[orchestration]
 
-# ssh username for the image file
-ssh_user = cirros
+#
+# Options defined in tempest.config
+#
 
-# specifies how many resources to request at once. Used for large operations
-# testing."
-large_ops_number = 0
+# Catalog type of the Orchestration service. (string value)
+#catalog_type=orchestration
 
-[cli]
-# Enable cli tests
-enabled = true
-# directory where python client binaries are located
-cli_dir = /usr/local/bin
-# Number of seconds to wait on a CLI timeout
-timeout = 15
+# The orchestration region name to use. If empty, the value of
+# identity.region is used instead. If no such region is found
+# in the service catalog, the first found one is used. (string
+# value)
+#region=
 
-[service_available]
-# Whether or not cinder is expected to be available
-cinder = true
-# Whether or not neutron is expected to be available
-neutron = false
-# Whether or not glance is expected to be available
-glance = true
-# Whether or not swift is expected to be available
-swift = true
-# Whether or not nova is expected to be available
-nova = true
-# Whether or not Heat is expected to be available
-heat = false
-# Whether or not Ceilometer is expected to be available
-ceilometer = True
-# Whether or not horizon is expected to be available
-horizon = true
+# Allows test cases to create/destroy tenants and users. This
+# option enables isolated test cases and better parallel
+# execution, but also requires that OpenStack Identity API
+# admin credentials are known. (boolean value)
+#allow_tenant_isolation=false
 
-[stress]
-# Maximum number of instances to create during test
-max_instances = 32
-# Time (in seconds) between log file error checks
-log_check_interval = 60
-# The default number of threads created while stress test
-default_thread_number_per_action = 4
+# Time in seconds between build status checks. (integer value)
+#build_interval=1
+
+# Timeout in seconds to wait for a stack to build. (integer
+# value)
+#build_timeout=300
+
+# Instance type for tests. Needs to be big enough for a full
+# OS plus the test workload (string value)
+#instance_type=m1.micro
+
+# Name of heat-cfntools enabled image to use when launching
+# test instances. (string value)
+#image_ref=<None>
+
+# Name of existing keypair to launch servers with. (string
+# value)
+#keypair_name=<None>
+
+# Value must match heat configuration of the same name.
+# (integer value)
+#max_template_size=524288
+
+
+[object-storage]
+
+#
+# Options defined in tempest.config
+#
+
+# Catalog type of the Object-Storage service. (string value)
+#catalog_type=object-store
+
+# The object-storage region name to use. If empty, the value
+# of identity.region is used instead. If no such region is
+# found in the service catalog, the first found one is used.
+# (string value)
+#region=
+
+# Number of seconds to time on waiting for a containerto
+# container synchronization complete. (integer value)
+#container_sync_timeout=120
+
+# Number of seconds to wait while looping to check thestatus
+# of a container to container synchronization (integer value)
+#container_sync_interval=5
+
+# Role to add to users created for swift tests to enable
+# creating containers (string value)
+#operator_role=Member
+
 
 [debug]
-# Enable diagnostic commands
-enable = true
+
+#
+# Options defined in tempest.config
+#
+
+# Enable diagnostic commands (boolean value)
+#enable=true
+
+
+[service_available]
+
+#
+# Options defined in tempest.config
+#
+
+# Whether or not cinder is expected to be available (boolean
+# value)
+#cinder=true
+
+# Whether or not neutron is expected to be available (boolean
+# value)
+#neutron=false
+
+# Whether or not glance is expected to be available (boolean
+# value)
+#glance=true
+
+# Whether or not swift is expected to be available (boolean
+# value)
+#swift=true
+
+# Whether or not nova is expected to be available (boolean
+# value)
+#nova=true
+
+# Whether or not Heat is expected to be available (boolean
+# value)
+#heat=false
+
+# Whether or not Ceilometer is expected to be available
+# (boolean value)
+#ceilometer=true
+
+# Whether or not Horizon is expected to be available (boolean
+# value)
+#horizon=true
+
+
+[compute-feature-enabled]
+
+#
+# Options defined in tempest.config
+#
+
+# If false, skip all nova v3 tests. (boolean value)
+#api_v3=false
+
+# If false, skip disk config tests (boolean value)
+#disk_config=true
+
+# If false, skip flavor extra data test (boolean value)
+#flavor_extra=true
+
+# Does the test environment support changing the admin
+# password? (boolean value)
+#change_password=false
+
+# Does the test environment support snapshots? (boolean value)
+#create_image=false
+
+# Does the test environment support resizing? (boolean value)
+#resize=false
+
+# Does the test environment support live migration available?
+# (boolean value)
+#live_migration=false
+
+# Does the test environment use block devices for live
+# migration (boolean value)
+#block_migration_for_live_migration=false
+
+# Does the test environment block migration support cinder
+# iSCSI volumes (boolean value)
+#block_migrate_cinder_iscsi=false
+
+
+[object-storage-feature-enabled]
+
+#
+# Options defined in tempest.config
+#
+
+# Set to True if the container quota middleware is enabled
+# (boolean value)
+#container_quotas=true
+
+# Set to True if the Account Quota middleware is enabled
+# (boolean value)
+#accounts_quotas=true
+
+# Set to True if the Crossdomain middleware is enabled
+# (boolean value)
+#crossdomain=true
+
+
+[volume-feature-enabled]
+
+#
+# Options defined in tempest.config
+#
+
+# Runs Cinder multi-backend test (requires 2 backends)
+# (boolean value)
+#multi_backend=false
+
+
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 5b4ca87..49b0429 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -25,7 +25,7 @@
 
     """
     Tests Flavor Extra Spec API extension.
-    SET, UNSET Flavor Extra specs require admin privileges.
+    SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
     GET Flavor Extra specs can be performed even by without admin privileges.
     """
 
@@ -86,13 +86,6 @@
         self.assertEqual(update_resp.status, 200)
         self.assertEqual({"key1": "value"}, update_body)
 
-        # GET a key value and verify
-        show_resp, get_body = \
-            self.client.get_flavor_extra_spec_with_key(self.flavor['id'],
-                                                       "key1")
-        self.assertEqual(show_resp.status, 200)
-        self.assertEqual(get_body, 'value')
-
         # GET extra specs and verify the value of the key2
         # is the same as before
         get_resp, get_body = \
@@ -109,7 +102,7 @@
         self.assertEqual(unset_resp.status, 200)
 
     @attr(type='gate')
-    def test_flavor_non_admin_get_all_keys_and_specified_key(self):
+    def test_flavor_non_admin_get_all_keys(self):
         specs = {"key1": "value1", "key2": "value2"}
         set_resp, set_body = self.client.set_flavor_extra_spec(
             self.flavor['id'], specs)
@@ -120,12 +113,19 @@
         for key in specs:
             self.assertEqual(body[key], specs[key])
 
-        get_resp, get_body = \
-            self.flavors_client.get_flavor_extra_spec_with_key(
-                self.flavor['id'],
-                "key1")
-        self.assertEqual(get_resp.status, 200)
-        self.assertEqual("value1", get_body)
+    @attr(type='gate')
+    def test_flavor_non_admin_get_specific_key(self):
+        specs = {"key1": "value1", "key2": "value2"}
+        resp, body = self.client.set_flavor_extra_spec(
+            self.flavor['id'], specs)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(body['key1'], 'value1')
+        self.assertIn('key2', body)
+        resp, body = self.flavors_client.get_flavor_extra_spec_with_key(
+            self.flavor['id'], 'key1')
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(body['key1'], 'value1')
+        self.assertNotIn('key2', body)
 
 
 class FlavorsExtraSpecsTestXML(FlavorsExtraSpecsTestJSON):
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index 044d6ad..d7e1f9f 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -24,7 +24,11 @@
 
 
 class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
-    """the Negative tests for FlavorsExtraSpecs."""
+
+    """
+    Negative Tests Flavor Extra Spec API extension.
+    SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
+    """
 
     _interface = 'json'
 
@@ -68,6 +72,21 @@
                           specs)
 
     @attr(type=['negative', 'gate'])
+    def test_flavor_non_admin_update_specific_key(self):
+        # non admin user is not allowed to update flavor extra spec
+        specs = {"key1": "value1", "key2": "value2"}
+        resp, body = self.client.set_flavor_extra_spec(
+            self.flavor['id'], specs)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(body['key1'], 'value1')
+        self.assertRaises(exceptions.Unauthorized,
+                          self.flavors_client.
+                          update_flavor_extra_spec,
+                          self.flavor['id'],
+                          'key1',
+                          key1='value1_new')
+
+    @attr(type=['negative', 'gate'])
     def test_flavor_non_admin_unset_keys(self):
         specs = {"key1": "value1", "key2": "value2"}
         set_resp, set_body = self.client.set_flavor_extra_spec(
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/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index d61acfb..2ccc3a8 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -15,11 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import uuid
-
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -32,7 +29,7 @@
         cls.client = cls.security_groups_client
         cls.neutron_available = cls.config.service_available.neutron
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_security_group_rules_create(self):
         # Positive test: Creation of Security Group rule
         # should be successful
@@ -55,7 +52,7 @@
         self.addCleanup(self.client.delete_security_group_rule, rule['id'])
         self.assertEqual(200, resp.status)
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_security_group_rules_create_with_optional_arguments(self):
         # Positive test: Creation of Security Group rule
         # with optional arguments
@@ -94,110 +91,7 @@
         self.addCleanup(self.client.delete_security_group_rule, rule['id'])
         self.assertEqual(200, resp.status)
 
-    @attr(type=['negative', 'smoke'])
-    def test_security_group_rules_create_with_invalid_id(self):
-        # Negative test: Creation of Security Group rule should FAIL
-        # with invalid Parent group id
-        # Adding rules to the invalid Security Group id
-        parent_group_id = data_utils.rand_int_id(start=999)
-        if self.neutron_available:
-            parent_group_id = str(uuid.uuid4())
-        ip_protocol = 'tcp'
-        from_port = 22
-        to_port = 22
-        self.assertRaises(exceptions.NotFound,
-                          self.client.create_security_group_rule,
-                          parent_group_id, ip_protocol, from_port, to_port)
-
-    @attr(type=['negative', 'gate'])
-    def test_security_group_rules_create_with_invalid_ip_protocol(self):
-        # Negative test: Creation of Security Group rule should FAIL
-        # with invalid ip_protocol
-        # Creating a Security Group to add rule to it
-        s_name = data_utils.rand_name('securitygroup-')
-        s_description = data_utils.rand_name('description-')
-        resp, securitygroup = self.client.create_security_group(s_name,
-                                                                s_description)
-        # Adding rules to the created Security Group
-        parent_group_id = securitygroup['id']
-        ip_protocol = data_utils.rand_name('999')
-        from_port = 22
-        to_port = 22
-
-        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_security_group_rule,
-                          parent_group_id, ip_protocol, from_port, to_port)
-
-    @attr(type=['negative', 'gate'])
-    def test_security_group_rules_create_with_invalid_from_port(self):
-        # Negative test: Creation of Security Group rule should FAIL
-        # with invalid from_port
-        # Creating a Security Group to add rule to it
-        s_name = data_utils.rand_name('securitygroup-')
-        s_description = data_utils.rand_name('description-')
-        resp, securitygroup = self.client.create_security_group(s_name,
-                                                                s_description)
-        # Adding rules to the created Security Group
-        parent_group_id = securitygroup['id']
-        ip_protocol = 'tcp'
-        from_port = data_utils.rand_int_id(start=999, end=65535)
-        to_port = 22
-        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_security_group_rule,
-                          parent_group_id, ip_protocol, from_port, to_port)
-
-    @attr(type=['negative', 'gate'])
-    def test_security_group_rules_create_with_invalid_to_port(self):
-        # Negative test: Creation of Security Group rule should FAIL
-        # with invalid to_port
-        # Creating a Security Group to add rule to it
-        s_name = data_utils.rand_name('securitygroup-')
-        s_description = data_utils.rand_name('description-')
-        resp, securitygroup = self.client.create_security_group(s_name,
-                                                                s_description)
-        # Adding rules to the created Security Group
-        parent_group_id = securitygroup['id']
-        ip_protocol = 'tcp'
-        from_port = 22
-        to_port = data_utils.rand_int_id(start=65536)
-        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_security_group_rule,
-                          parent_group_id, ip_protocol, from_port, to_port)
-
-    @attr(type=['negative', 'gate'])
-    def test_security_group_rules_create_with_invalid_port_range(self):
-        # Negative test: Creation of Security Group rule should FAIL
-        # with invalid port range.
-        # Creating a Security Group to add rule to it.
-        s_name = data_utils.rand_name('securitygroup-')
-        s_description = data_utils.rand_name('description-')
-        resp, securitygroup = self.client.create_security_group(s_name,
-                                                                s_description)
-        # Adding a rule to the created Security Group
-        secgroup_id = securitygroup['id']
-        ip_protocol = 'tcp'
-        from_port = 22
-        to_port = 21
-        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_security_group_rule,
-                          secgroup_id, ip_protocol, from_port, to_port)
-
-    @attr(type=['negative', 'smoke'])
-    def test_security_group_rules_delete_with_invalid_id(self):
-        # Negative test: Deletion of Security Group rule should be FAIL
-        # with invalid rule id
-        group_rule_id = data_utils.rand_int_id(start=999)
-        if self.neutron_available:
-            group_rule_id = str(uuid.uuid4())
-        self.assertRaises(exceptions.NotFound,
-                          self.client.delete_security_group_rule,
-                          group_rule_id)
-
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_security_group_rules_list(self):
         # Positive test: Created Security Group rules should be
         # in the list of all rules
@@ -240,6 +134,44 @@
         self.assertTrue(any([i for i in rules if i['id'] == rule1_id]))
         self.assertTrue(any([i for i in rules if i['id'] == rule2_id]))
 
+    @attr(type='smoke')
+    def test_security_group_rules_delete_when_peer_group_deleted(self):
+        # Positive test:rule will delete when peer group deleting
+        # Creating a Security Group to add rules to it
+        s1_name = data_utils.rand_name('securitygroup1-')
+        s1_description = data_utils.rand_name('description1-')
+        resp, sg1 = \
+            self.client.create_security_group(s1_name, s1_description)
+        self.addCleanup(self.client.delete_security_group, sg1['id'])
+        self.assertEqual(200, resp.status)
+        # Creating other Security Group to access to group1
+        s2_name = data_utils.rand_name('securitygroup2-')
+        s2_description = data_utils.rand_name('description2-')
+        resp, sg2 = \
+            self.client.create_security_group(s2_name, s2_description)
+        self.assertEqual(200, resp.status)
+        sg2_id = sg2['id']
+        # Adding rules to the Group1
+        ip_protocol = 'tcp'
+        from_port = 22
+        to_port = 22
+        resp, rule = \
+            self.client.create_security_group_rule(sg1['id'],
+                                                   ip_protocol,
+                                                   from_port,
+                                                   to_port,
+                                                   group_id=sg2_id)
+
+        self.assertEqual(200, resp.status)
+        # Delete group2
+        resp, body = self.client.delete_security_group(sg2_id)
+        self.assertEqual(202, resp.status)
+        # Get rules of the Group1
+        resp, rules = \
+            self.client.list_security_group_rules(sg1['id'])
+        # The group1 has no rules because group2 has deleted
+        self.assertEqual(0, len(rules))
+
 
 class SecurityGroupRulesTestXML(SecurityGroupRulesTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
new file mode 100644
index 0000000..1c38268
--- /dev/null
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -0,0 +1,183 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+# 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 testtools
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
+from tempest.test import attr
+from tempest.test import skip_because
+
+
+class SecurityGroupRulesNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(SecurityGroupRulesNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.security_groups_client
+
+    @skip_because(bug="1182384",
+                  condition=config.TempestConfig().service_available.neutron)
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_non_existent_id(self):
+        # Negative test: Creation of Security Group rule should FAIL
+        # with non existent Parent group id
+        # Adding rules to the non existent Security Group id
+        parent_group_id = data_utils.rand_int_id(start=999)
+        ip_protocol = 'tcp'
+        from_port = 22
+        to_port = 22
+        self.assertRaises(exceptions.NotFound,
+                          self.client.create_security_group_rule,
+                          parent_group_id, ip_protocol, from_port, to_port)
+
+    @testtools.skipIf(config.TempestConfig().service_available.neutron,
+                      "Neutron not check the security_group_id")
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_invalid_id(self):
+        # Negative test: Creation of Security Group rule should FAIL
+        # with Parent group id which is not integer
+        # Adding rules to the non int Security Group id
+        parent_group_id = data_utils.rand_name('non_int_id')
+        ip_protocol = 'tcp'
+        from_port = 22
+        to_port = 22
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_security_group_rule,
+                          parent_group_id, ip_protocol, from_port, to_port)
+
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_duplicate(self):
+        # Negative test: Create Security Group rule duplicate should fail
+        # Creating a Security Group to add rule to it
+        s_name = data_utils.rand_name('securitygroup-')
+        s_description = data_utils.rand_name('description-')
+        resp, sg = self.client.create_security_group(s_name, s_description)
+        self.assertEqual(200, resp.status)
+        # Adding rules to the created Security Group
+        parent_group_id = sg['id']
+        ip_protocol = 'tcp'
+        from_port = 22
+        to_port = 22
+
+        self.addCleanup(self.client.delete_security_group, sg['id'])
+        resp, rule = \
+            self.client.create_security_group_rule(parent_group_id,
+                                                   ip_protocol,
+                                                   from_port,
+                                                   to_port)
+        self.addCleanup(self.client.delete_security_group_rule, rule['id'])
+        self.assertEqual(200, resp.status)
+        # Add the same rule to the group should fail
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_security_group_rule,
+                          parent_group_id, ip_protocol, from_port, to_port)
+
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_invalid_ip_protocol(self):
+        # Negative test: Creation of Security Group rule should FAIL
+        # with invalid ip_protocol
+        # Creating a Security Group to add rule to it
+        s_name = data_utils.rand_name('securitygroup-')
+        s_description = data_utils.rand_name('description-')
+        resp, securitygroup = self.client.create_security_group(s_name,
+                                                                s_description)
+        # Adding rules to the created Security Group
+        parent_group_id = securitygroup['id']
+        ip_protocol = data_utils.rand_name('999')
+        from_port = 22
+        to_port = 22
+
+        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_security_group_rule,
+                          parent_group_id, ip_protocol, from_port, to_port)
+
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_invalid_from_port(self):
+        # Negative test: Creation of Security Group rule should FAIL
+        # with invalid from_port
+        # Creating a Security Group to add rule to it
+        s_name = data_utils.rand_name('securitygroup-')
+        s_description = data_utils.rand_name('description-')
+        resp, securitygroup = self.client.create_security_group(s_name,
+                                                                s_description)
+        # Adding rules to the created Security Group
+        parent_group_id = securitygroup['id']
+        ip_protocol = 'tcp'
+        from_port = data_utils.rand_int_id(start=65536)
+        to_port = 22
+        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_security_group_rule,
+                          parent_group_id, ip_protocol, from_port, to_port)
+
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_invalid_to_port(self):
+        # Negative test: Creation of Security Group rule should FAIL
+        # with invalid to_port
+        # Creating a Security Group to add rule to it
+        s_name = data_utils.rand_name('securitygroup-')
+        s_description = data_utils.rand_name('description-')
+        resp, securitygroup = self.client.create_security_group(s_name,
+                                                                s_description)
+        # Adding rules to the created Security Group
+        parent_group_id = securitygroup['id']
+        ip_protocol = 'tcp'
+        from_port = 22
+        to_port = data_utils.rand_int_id(start=65536)
+        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_security_group_rule,
+                          parent_group_id, ip_protocol, from_port, to_port)
+
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_invalid_port_range(self):
+        # Negative test: Creation of Security Group rule should FAIL
+        # with invalid port range.
+        # Creating a Security Group to add rule to it.
+        s_name = data_utils.rand_name('securitygroup-')
+        s_description = data_utils.rand_name('description-')
+        resp, securitygroup = self.client.create_security_group(s_name,
+                                                                s_description)
+        # Adding a rule to the created Security Group
+        secgroup_id = securitygroup['id']
+        ip_protocol = 'tcp'
+        from_port = 22
+        to_port = 21
+        self.addCleanup(self.client.delete_security_group, securitygroup['id'])
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_security_group_rule,
+                          secgroup_id, ip_protocol, from_port, to_port)
+
+    @skip_because(bug="1182384",
+                  condition=config.TempestConfig().service_available.neutron)
+    @attr(type=['negative', 'smoke'])
+    def test_delete_security_group_rule_with_non_existent_id(self):
+        # Negative test: Deletion of Security Group rule should be FAIL
+        # with non existent id
+        non_existent_rule_id = data_utils.rand_int_id(start=999)
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_security_group_rule,
+                          non_existent_rule_id)
+
+
+class SecurityGroupRulesNegativeTestXML(SecurityGroupRulesNegativeTestJSON):
+    _interface = 'xml'
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/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index ee6d656..133bae0 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -123,8 +123,3 @@
         image_list = map(lambda x: x['id'], images_list)
         for image in self.created_images:
             self.assertIn(image, image_list)
-
-    @attr(type=['negative', 'gate'])
-    def test_get_image_by_null_id(self):
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_image, '')
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
new file mode 100644
index 0000000..5bdaa99
--- /dev/null
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -0,0 +1,84 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+# Copyright 2013 IBM Corp.
+#
+#    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 uuid
+
+from tempest.api.image import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ImagesNegativeTest(base.BaseV2ImageTest):
+
+    """
+    here we have -ve tests for get_image and delete_image api
+
+    Tests
+        ** get non-existent image
+        ** get image with image_id=NULL
+        ** get the deleted image
+        ** delete non-existent image
+        ** delete rimage with  image_id=NULL
+        ** delete the deleted image
+     """
+
+    @attr(type=['negative', 'gate'])
+    def test_get_non_existent_image(self):
+        # get the non-existent image
+        non_existent_id = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.get_image,
+                          non_existent_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_image_null_id(self):
+        # get image with image_id = NULL
+        image_id = ""
+        self.assertRaises(exceptions.NotFound, self.client.get_image, image_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_delete_deleted_image(self):
+        # get and delete the deleted image
+        # create and delete image
+        resp, body = self.client.create_image(name='test',
+                                              container_format='bare',
+                                              disk_format='raw')
+        image_id = body['id']
+        self.assertEqual(201, resp.status)
+        self.client.delete_image(image_id)
+        self.client.wait_for_resource_deletion(image_id)
+
+        # get the deleted image
+        self.assertRaises(exceptions.NotFound, self.client.get_image, image_id)
+
+        # delete the deleted image
+        self.assertRaises(exceptions.NotFound, self.client.delete_image,
+                          image_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_non_existing_image(self):
+        # delete non-existent image
+        non_existent_image_id = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.delete_image,
+                          non_existent_image_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_image_null_id(self):
+        # delete image with image_id=NULL
+        image_id = ""
+        self.assertRaises(exceptions.NotFound, self.client.delete_image,
+                          image_id)
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
new file mode 100644
index 0000000..5e838e5
--- /dev/null
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -0,0 +1,110 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD
+# 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 BaseVolumeAdminTest
+from tempest.common.utils import data_utils
+from tempest.test import attr
+
+
+class SnapshotsActionsTest(BaseVolumeAdminTest):
+    _interface = "json"
+
+    @classmethod
+    def setUpClass(cls):
+        super(SnapshotsActionsTest, cls).setUpClass()
+        cls.client = cls.snapshots_client
+
+        # Create admin volume client
+        cls.admin_snapshots_client = cls.os_adm.snapshots_client
+
+        # Create a test shared volume for tests
+        vol_name = data_utils.rand_name(cls.__name__ + '-Volume-')
+        resp_vol, cls.volume = \
+            cls.volumes_client.create_volume(size=1, display_name=vol_name)
+        cls.volumes_client.wait_for_volume_status(cls.volume['id'],
+                                                  'available')
+
+        # Create a test shared snapshot for tests
+        snap_name = data_utils.rand_name(cls.__name__ + '-Snapshot-')
+        resp_snap, cls.snapshot = \
+            cls.client.create_snapshot(cls.volume['id'],
+                                       display_name=snap_name)
+        cls.client.wait_for_snapshot_status(cls.snapshot['id'],
+                                            'available')
+
+    @classmethod
+    def tearDownClass(cls):
+        # Delete the test snapshot
+        cls.client.delete_snapshot(cls.snapshot['id'])
+        cls.client.wait_for_resource_deletion(cls.snapshot['id'])
+
+        # Delete the test volume
+        cls.volumes_client.delete_volume(cls.volume['id'])
+        cls.volumes_client.wait_for_resource_deletion(cls.volume['id'])
+
+        super(SnapshotsActionsTest, cls).tearDownClass()
+
+    def tearDown(self):
+        # Set snapshot's status to available after test
+        status = 'available'
+        snapshot_id = self.snapshot['id']
+        self.admin_snapshots_client.reset_snapshot_status(snapshot_id,
+                                                          status)
+        super(SnapshotsActionsTest, self).tearDown()
+
+    def _get_progress_alias(self):
+        return 'os-extended-snapshot-attributes:progress'
+
+    @attr(type='gate')
+    def test_reset_snapshot_status(self):
+        # Reset snapshot status to creating
+        status = 'creating'
+        resp, body = self.admin_snapshots_client.\
+            reset_snapshot_status(self.snapshot['id'], status)
+        self.assertEqual(202, resp.status)
+        resp_get, snapshot_get \
+            = self.admin_snapshots_client.get_snapshot(self.snapshot['id'])
+        self.assertEqual(200, resp_get.status)
+        self.assertEqual(status, snapshot_get['status'])
+
+    @attr(type='gate')
+    def test_update_snapshot_status(self):
+        # Reset snapshot status to creating
+        status = 'creating'
+        self.admin_snapshots_client.\
+            reset_snapshot_status(self.snapshot['id'], status)
+
+        # Update snapshot status to error
+        progress = '80%'
+        status = 'error'
+        progress_alias = self._get_progress_alias()
+        resp, body = self.client.update_snapshot_status(self.snapshot['id'],
+                                                        status, progress)
+        self.assertEqual(202, resp.status)
+        resp_get, snapshot_get \
+            = self.admin_snapshots_client.get_snapshot(self.snapshot['id'])
+        self.assertEqual(200, resp_get.status)
+        self.assertEqual(status, snapshot_get['status'])
+        self.assertEqual(progress, snapshot_get[progress_alias])
+
+
+class SnapshotsActionsTestXML(SnapshotsActionsTest):
+    _interface = "xml"
+
+    def _get_progress_alias(self):
+        return '{http://docs.openstack.org/volume/ext' \
+               '/extended_snapshot_attributes/api/v1}progress'
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/common/generate_sample_tempest.py b/tempest/common/generate_sample_tempest.py
new file mode 100644
index 0000000..3811088
--- /dev/null
+++ b/tempest/common/generate_sample_tempest.py
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 sys
+
+from tempest import config
+from tempest.openstack.common.config import generator
+
+
+config.TempestConfig()
+generator.generate(sys.argv[1:])
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 9459590..5dbb3a7 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -412,7 +412,11 @@
                 resp_body = self.network_admin_client.list_ports()
             self.ports = resp_body['ports']
         ports_to_delete = [
-            port for port in self.ports if port['network_id'] == network_id]
+            port
+            for port in self.ports
+            if (port['network_id'] == network_id and
+                port['device_owner'] != 'network:router_interface')
+        ]
         for port in ports_to_delete:
             try:
                 LOG.info('Cleaning up port id %s, name %s' %
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 588e5cd..00d6f8a 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -103,14 +103,14 @@
         return resp, body['extra_specs']
 
     def get_flavor_extra_spec_with_key(self, flavor_id, key):
-        """Gets a specified key value for the mentioned flavor."""
+        """Gets extra Specs key-value of the mentioned flavor and key."""
         resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
                               key))
         body = json.loads(body)
-        return resp, body[key]
+        return resp, body
 
     def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
-        """Gets specified extra Specs details of the mentioned flavor."""
+        """Update specified extra Specs of the mentioned flavor and key."""
         resp, body = self.put('flavors/%s/os-extra_specs/%s' %
                               (flavor_id, key),
                               json.dumps(kwargs), self.headers)
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/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index d4c456e..363c1a8 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -154,14 +154,17 @@
         return resp, body
 
     def get_flavor_extra_spec_with_key(self, flavor_id, key):
-        """Gets a specified key detail for the mentioned flavor."""
-        resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
-                              key), self.headers)
-        body = xml_to_json(etree.fromstring(body))
+        """Gets extra Specs key-value of the mentioned flavor and key."""
+        resp, xml_body = self.get('flavors/%s/os-extra_specs/%s' %
+                                  (str(flavor_id), key), self.headers)
+        body = {}
+        element = etree.fromstring(xml_body)
+        key = element.get('key')
+        body[key] = xml_to_json(element)
         return resp, body
 
     def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
-        """Gets specified extra Specs details of the mentioned flavor."""
+        """Update extra Specs details of the mentioned flavor and key."""
         doc = Document()
         for (k, v) in kwargs.items():
             element = Element(k)
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/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index 10ba3fd..5d980eb 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -131,3 +131,21 @@
         except exceptions.NotFound:
             return True
         return False
+
+    def reset_snapshot_status(self, snapshot_id, status):
+        """Reset the specified snapshot's status."""
+        post_body = json.dumps({'os-reset_status': {"status": status}})
+        resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body,
+                               self.headers)
+        return resp, body
+
+    def update_snapshot_status(self, snapshot_id, status, progress):
+        """Update the specified snapshot's status."""
+        post_body = {
+            'status': status,
+            'progress': progress
+        }
+        post_body = json.dumps({'os-update_snapshot_status': post_body})
+        url = 'snapshots/%s/action' % str(snapshot_id)
+        resp, body = self.post(url, post_body, self.headers)
+        return resp, body
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/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index b7ba56b..5d59b07 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -147,3 +147,26 @@
         except exceptions.NotFound:
             return True
         return False
+
+    def reset_snapshot_status(self, snapshot_id, status):
+        """Reset the specified snapshot's status."""
+        post_body = Element("os-reset_status",
+                            status=status
+                            )
+        url = 'snapshots/%s/action' % str(snapshot_id)
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        if body:
+            body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def update_snapshot_status(self, snapshot_id, status, progress):
+        """Update the specified snapshot's status."""
+        post_body = Element("os-update_snapshot_status",
+                            status=status,
+                            progress=progress
+                            )
+        url = 'snapshots/%s/action' % str(snapshot_id)
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        if body:
+            body = xml_to_json(etree.fromstring(body))
+        return resp, body
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/config/check_uptodate.sh b/tools/config/check_uptodate.sh
new file mode 100755
index 0000000..9882ab6
--- /dev/null
+++ b/tools/config/check_uptodate.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+TEMPDIR=`mktemp -d`
+CFGFILE=tempest.conf.sample
+tools/config/generate_sample.sh -b ./ -p tempest -o $TEMPDIR
+if ! diff $TEMPDIR/$CFGFILE etc/$CFGFILE
+then
+    echo "E: tempest.conf.sample is not up to date, please run:"
+    echo "MODULEPATH=tempest.common.generate_sample_tempest tools/config/generate_sample.sh"
+    exit 42
+fi
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()
diff --git a/tox.ini b/tox.ini
index 9356dd7..6efac78 100644
--- a/tox.ini
+++ b/tox.ini
@@ -106,7 +106,11 @@
        -r{toxinidir}/test-requirements.txt
 
 [testenv:pep8]
-commands = flake8
+setenv = MODULEPATH=tempest.common.generate_sample_tempest
+commands =
+   flake8 {posargs}
+   {toxinidir}/tools/config/check_uptodate.sh
+
 deps = -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt