Merge "Create a Tempest conf from a Devstack env"
diff --git a/tempest/tools/conf_from_devstack b/tempest/tools/conf_from_devstack
new file mode 100755
index 0000000..f3f1309
--- /dev/null
+++ b/tempest/tools/conf_from_devstack
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# 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.
+
+"""
+Simple script that analyzes a devstack environment and constructs
+a Tempest configuration file for the devstack environment.
+"""
+
+import optparse
+import os
+import subprocess
+import sys
+
+SUCCESS = 0
+FAILURE = 1
+
+
+def execute(cmd, raise_error=True):
+    """
+    Executes a command in a subprocess. Returns a tuple
+    of (exitcode, out, err), where out is the string output
+    from stdout and err is the string output from stderr when
+    executing the command.
+
+    :param cmd: Command string to execute
+    :param raise_error: If returncode is not 0 (success), then
+                        raise a RuntimeError? Default: True)
+    """
+
+    process = subprocess.Popen(cmd,
+                               shell=True,
+                               stdin=subprocess.PIPE,
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.PIPE)
+    result = process.communicate()
+    (out, err) = result
+    exitcode = process.returncode
+    if process.returncode != 0 and raise_error:
+        msg = "Command %(cmd)s did not succeed. Returned an exit "\
+              "code of %(exitcode)d."\
+              "\n\nSTDOUT: %(out)s"\
+              "\n\nSTDERR: %(err)s" % locals()
+        raise RuntimeError(msg)
+    return exitcode, out, err
+
+
+def add_options(parser):
+    """
+    Adds CLI options to a supplied option parser
+
+    :param parser: `optparse.OptionParser`
+    """
+    parser.add_option('-o', '--outfile', metavar="PATH",
+                      help=("File to save generated config to. Default: "
+                            "prints config to stdout."))
+    parser.add_option('-v', '--verbose', default=False, action="store_true",
+                      help="Print more verbose output")
+    parser.add_option('-D', '--devstack-dir', metavar="PATH",
+                      default=os.getcwd(),
+                      help="Directory to find devstack. Default: $PWD")
+
+
+def get_devstack_localrc(options):
+    """
+    Finds the localrc file in the devstack directory and returns a dict
+    representing the key/value pairs in the localrc file.
+    """
+    localrc_path = os.path.join(os.path.abspath(options.devstack_dir), 'localrc')
+    if not os.path.exists(localrc_path):
+        raise RuntimeError("Failed to find localrc file in devstack dir %s" %
+                           options.devstack_dir)
+
+    if options.verbose:
+        print "Reading localrc settings from %s" % localrc_path
+
+    try:
+        settings = dict([line.split('=') for line in
+                        open(localrc_path, 'r').readlines()
+                        if not line.startswith('#')])
+        return settings
+    except (TypeError, ValueError) as e:
+        raise RuntimeError("Failed to read settings from localrc file %s. "
+                           "Got error: %s" % (localrc_path, e))
+
+
+def main():
+    oparser = optparse.OptionParser()
+    add_options(oparser)
+
+    options, args = oparser.parse_args()
+
+    localrc = get_devstack_localrc(options)
+
+    conf_settings = {
+        'service_host': localrc.get('HOST_IP', '127.0.0.1'),
+        'service_port': 5000,  # Make this configurable when devstack does
+        'identity_api_version': 'v2.0',  # Ditto
+        'user': localrc.get('USERNAME', 'admin'),
+        'password': localrc.get('ADMIN_PASSWORD', 'password')
+    }
+
+    # We need to determine the UUID of the base image, so we
+    # query the Glance endpoint for a list of images...
+    cmd = "glance index -A %s" % localrc['SERVICE_TOKEN']
+    retcode, out, err = execute(cmd)
+
+    if retcode != 0:
+        raise RuntimeError("Unable to get list of images from Glance. "
+                           "Got error: %s" % err)
+
+    image_lines = out.split('\n')[2:]
+    for line in image_lines:
+        if 'ami' in line:
+            conf_settings['base_image_uuid'] = line.split()[0]
+            break
+
+    if 'base_image_uuid' not in conf_settings:
+        raise RuntimeError("Unable to find any AMI images in glance index")
+
+    if options.verbose:
+        print "Found base image with UUID %s" % conf_settings['base_image_uuid']
+
+    tempest_conf = """
+[nova]
+host=%(service_host)s
+port=%(service_port)s
+apiVer=%(identity_api_version)s
+path=tokens
+user=%(user)s
+api_key=%(password)s
+tenant_name=%(user)s
+ssh_timeout=300
+build_interval=10
+build_timeout=600
+
+[environment]
+image_ref=%(base_image_uuid)s
+image_ref_alt=4
+flavor_ref=1
+flavor_ref_alt=2
+create_image_enabled=true
+resize_available=true
+authentication=keystone_v2""" % conf_settings
+
+    if options.outfile:
+        outfile_path = os.path.abspath(options.outfile)
+        if os.path.exists(outfile_path):
+            confirm = raw_input("Output file already exists. Overwrite? [y/N]")
+            if confirm != 'Y':
+                print "Exiting"
+                return SUCCESS
+        with open(outfile_path, 'wb') as outfile:
+            outfile.write(tempest_conf)
+        if options.verbose:
+            print "Wrote tempest config to %s" % outfile_path
+    else:
+        print tempest_conf
+
+
+if __name__ == '__main__':
+    try:
+        sys.exit(main())
+    except RuntimeError, e:
+        sys.exit("ERROR: %s" % e)