Merge "Add my_ip option in cinder.conf"
diff --git a/files/apts/cinder b/files/apts/cinder
index 32cb3a0..f8e3b6d 100644
--- a/files/apts/cinder
+++ b/files/apts/cinder
@@ -3,3 +3,5 @@
 qemu-utils
 libpq-dev
 python-dev
+open-iscsi
+open-iscsi-utils # Deprecated since quantal dist:lucid,oneiric,precise
diff --git a/files/keystone_data.sh b/files/keystone_data.sh
index 45f9c81..3f3137c 100755
--- a/files/keystone_data.sh
+++ b/files/keystone_data.sh
@@ -58,9 +58,9 @@
     # Nova needs ResellerAdmin role to download images when accessing
     # swift through the s3 api.
     keystone user-role-add \
-        --tenant_id $SERVICE_TENANT \
-        --user_id $NOVA_USER \
-        --role_id $RESELLER_ROLE
+        --tenant-id $SERVICE_TENANT \
+        --user-id $NOVA_USER \
+        --role-id $RESELLER_ROLE
 fi
 
 # Heat
@@ -69,9 +69,9 @@
                                               --pass="$SERVICE_PASSWORD" \
                                               --tenant_id $SERVICE_TENANT \
                                               --email=heat@example.com)
-    keystone user-role-add --tenant_id $SERVICE_TENANT \
-                           --user_id $HEAT_USER \
-                           --role_id $SERVICE_ROLE
+    keystone user-role-add --tenant-id $SERVICE_TENANT \
+                           --user-id $HEAT_USER \
+                           --role-id $SERVICE_ROLE
     # heat_stack_user role is for users created by Heat
     keystone role-create --name heat_stack_user
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
@@ -106,9 +106,9 @@
         --tenant_id $SERVICE_TENANT \
         --email=glance@example.com)
     keystone user-role-add \
-        --tenant_id $SERVICE_TENANT \
-        --user_id $GLANCE_USER \
-        --role_id $ADMIN_ROLE
+        --tenant-id $SERVICE_TENANT \
+        --user-id $GLANCE_USER \
+        --role-id $ADMIN_ROLE
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
         GLANCE_SERVICE=$(get_id keystone service-create \
             --name=glance \
@@ -129,13 +129,13 @@
                                               --pass="$SERVICE_PASSWORD" \
                                               --tenant_id $SERVICE_TENANT \
                                               --email=ceilometer@example.com)
-    keystone user-role-add --tenant_id $SERVICE_TENANT \
-                           --user_id $CEILOMETER_USER \
-                           --role_id $ADMIN_ROLE
+    keystone user-role-add --tenant-id $SERVICE_TENANT \
+                           --user-id $CEILOMETER_USER \
+                           --role-id $ADMIN_ROLE
     # Ceilometer needs ResellerAdmin role to access swift account stats.
-    keystone user-role-add --tenant_id $SERVICE_TENANT \
-                           --user_id $CEILOMETER_USER \
-                           --role_id $RESELLER_ROLE
+    keystone user-role-add --tenant-id $SERVICE_TENANT \
+                           --user-id $CEILOMETER_USER \
+                           --role-id $RESELLER_ROLE
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
         CEILOMETER_SERVICE=$(get_id keystone service-create \
             --name=ceilometer \
@@ -192,7 +192,7 @@
         --pass="$ADMIN_PASSWORD" \
         --email=alt_demo@example.com)
     keystone user-role-add \
-        --tenant_id $ALT_DEMO_TENANT \
-        --user_id $ALT_DEMO_USER \
-        --role_id $MEMBER_ROLE
+        --tenant-id $ALT_DEMO_TENANT \
+        --user-id $ALT_DEMO_USER \
+        --role-id $MEMBER_ROLE
 fi
diff --git a/files/rpms-suse/cinder b/files/rpms-suse/cinder
index 49e2cb8..55078da 100644
--- a/files/rpms-suse/cinder
+++ b/files/rpms-suse/cinder
@@ -3,3 +3,4 @@
 qemu-tools
 python-devel
 postgresql-devel
+open-iscsi
diff --git a/files/rpms/cinder b/files/rpms/cinder
index 699f2fc..c4edb68 100644
--- a/files/rpms/cinder
+++ b/files/rpms/cinder
@@ -3,3 +3,4 @@
 qemu-img
 python-devel
 postgresql-devel
+iscsi-initiator-utils
diff --git a/functions b/functions
index f24cc89..df8166a 100644
--- a/functions
+++ b/functions
@@ -1454,7 +1454,6 @@
     local check_command=""
     MULTI_HOST=`trueorfalse False $MULTI_HOST`
     if [[ "$MULTI_HOST" = "True" && "$from_net" = "$PRIVATE_NETWORK_NAME" ]]; then
-        sleep $boot_timeout
         return
     fi
     if [[ "$expected" = "True" ]]; then
@@ -1645,6 +1644,37 @@
 }
 
 
+# ``policy_add policy_file policy_name policy_permissions``
+#
+# Add a policy to a policy.json file
+# Do nothing if the policy already exists
+
+function policy_add() {
+    local policy_file=$1
+    local policy_name=$2
+    local policy_perm=$3
+
+    if grep -q ${policy_name} ${policy_file}; then
+        echo "Policy ${policy_name} already exists in ${policy_file}"
+        return
+    fi
+
+    # Add a terminating comma to policy lines without one
+    # Remove the closing '}' and all lines following to the end-of-file
+    local tmpfile=$(mktemp)
+    uniq ${policy_file} | sed -e '
+        s/]$/],/
+        /^[}]/,$d
+    ' > ${tmpfile}
+
+    # Append policy and closing brace
+    echo "    \"${policy_name}\": ${policy_perm}" >>${tmpfile}
+    echo "}" >>${tmpfile}
+
+    mv ${tmpfile} ${policy_file}
+}
+
+
 # Restore xtrace
 $XTRACE
 
diff --git a/lib/cinder b/lib/cinder
index aed3004..324db9d 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -336,9 +336,9 @@
             --email=cinder@example.com \
             | grep " id " | get_field 2)
         keystone user-role-add \
-            --tenant_id $SERVICE_TENANT \
-            --user_id $CINDER_USER \
-            --role_id $ADMIN_ROLE
+            --tenant-id $SERVICE_TENANT \
+            --user-id $CINDER_USER \
+            --role-id $ADMIN_ROLE
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
             CINDER_SERVICE=$(keystone service-create \
                 --name=cinder \
diff --git a/lib/ironic b/lib/ironic
new file mode 100644
index 0000000..2ce5038
--- /dev/null
+++ b/lib/ironic
@@ -0,0 +1,222 @@
+# lib/ironic
+# Functions to control the configuration and operation of the **Ironic** service
+
+# Dependencies:
+# ``functions`` file
+# ``DEST``, ``DATA_DIR``, ``STACK_USER`` must be defined
+# ``SERVICE_{TENANT_NAME|PASSWORD}`` must be defined
+# ``SERVICE_HOST``
+# ``KEYSTONE_TOKEN_FORMAT`` must be defined
+
+# ``stack.sh`` calls the entry points in this order:
+#
+# install_ironic
+# configure_ironic
+# init_ironic
+# start_ironic
+# stop_ironic
+# cleanup_ironic
+
+# Save trace setting
+XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+# Defaults
+# --------
+
+# Set up default directories
+IRONIC_DIR=$DEST/ironic
+IRONIC_AUTH_CACHE_DIR=${IRONIC_AUTH_CACHE_DIR:-/var/cache/ironic}
+IRONIC_CONF_DIR=${IRONIC_CONF_DIR:-/etc/ironic}
+IRONIC_CONF_FILE=$IRONIC_CONF_DIR/ironic.conf
+IRONIC_ROOTWRAP_CONF=$IRONIC_CONF_DIR/rootwrap.conf
+IRONIC_ROOTWRAP_FILTERS=$IRONIC_CONF_DIR/rootwrap.d
+IRONIC_POLICY_JSON=$IRONIC_CONF_DIR/policy.json
+
+# Support entry points installation of console scripts
+IRONIC_BIN_DIR=$(get_python_exec_prefix)
+
+# Ironic connection info.  Note the port must be specified.
+IRONIC_SERVICE_PROTOCOL=http
+IRONIC_HOSTPORT=${IRONIC_HOSTPORT:-$SERVICE_HOST:6385}
+
+
+# Functions
+# ---------
+
+# cleanup_ironic() - Remove residual data files, anything left over from previous
+# runs that would need to clean up.
+function cleanup_ironic() {
+    sudo rm -rf $IRONIC_AUTH_CACHE_DIR
+}
+
+# configure_ironic() - Set config files, create data dirs, etc
+function configure_ironic() {
+    if [[ ! -d $IRONIC_CONF_DIR ]]; then
+        sudo mkdir -p $IRONIC_CONF_DIR
+    fi
+    sudo chown $STACK_USER $IRONIC_CONF_DIR
+
+    # Copy over ironic configuration file and configure common parameters.
+    cp $IRONIC_DIR/etc/ironic/ironic.conf.sample $IRONIC_CONF_FILE
+    iniset $IRONIC_CONF_FILE DEFAULT debug True
+    inicomment $IRONIC_CONF_FILE DEFAULT log_file
+    iniset $IRONIC_CONF_FILE DEFAULT sql_connection `database_connection_url ironic`
+    iniset $IRONIC_CONF_FILE DEFAULT use_syslog $SYSLOG
+
+    # Configure Ironic conductor, if it was enabled.
+    if is_service_enabled ir-cond; then
+        configure_ironic_conductor
+    fi
+
+    # Configure Ironic API, if it was enabled.
+    if is_service_enabled ir-api; then
+        configure_ironic_api
+    fi
+}
+
+# configure_ironic_api() - Is used by configure_ironic(). Performs
+# API specific configuration.
+function configure_ironic_api() {
+    iniset $IRONIC_CONF_FILE keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
+    iniset $IRONIC_CONF_FILE keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
+    iniset $IRONIC_CONF_FILE keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+    iniset $IRONIC_CONF_FILE keystone_authtoken auth_uri $KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/
+    iniset $IRONIC_CONF_FILE keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
+    iniset $IRONIC_CONF_FILE keystone_authtoken admin_user ironic
+    iniset $IRONIC_CONF_FILE keystone_authtoken admin_password $SERVICE_PASSWORD
+    if is_service_enabled qpid; then
+        iniset $IRONIC_CONF_FILE DEFAULT notifier_strategy qpid
+    elif [ -n "$RABBIT_HOST" ] &&  [ -n "$RABBIT_PASSWORD" ]; then
+        iniset $IRONIC_CONF_FILE DEFAULT notifier_strategy rabbit
+    fi
+    iniset_rpc_backend ironic $IRONIC_CONF_FILE DEFAULT
+    iniset $IRONIC_CONF_FILE keystone_authtoken signing_dir $IRONIC_AUTH_CACHE_DIR/api
+
+    cp -p $IRONIC_DIR/etc/ironic/policy.json $IRONIC_POLICY_JSON
+}
+
+# configure_ironic_conductor() - Is used by configure_ironic().
+# Sets conductor specific settings.
+function configure_ironic_conductor() {
+    cp $IRONIC_DIR/etc/ironic/rootwrap.conf $IRONIC_ROOTWRAP_CONF
+    cp -r $IRONIC_DIR/etc/ironic/rootwrap.d $IRONIC_ROOTWRAP_FILTERS
+
+    iniset $IRONIC_CONF DEFAULT rootwrap_config $IRONIC_ROOTWRAP_CONF
+}
+
+# create_ironic_cache_dir() - Part of the init_ironic() process
+function create_ironic_cache_dir() {
+    # Create cache dir
+    sudo mkdir -p $IRONIC_AUTH_CACHE_DIR/api
+    sudo chown $STACK_USER $IRONIC_AUTH_CACHE_DIR/api
+    rm -f $IRONIC_AUTH_CACHE_DIR/api/*
+    sudo mkdir -p $IRONIC_AUTH_CACHE_DIR/registry
+    sudo chown $STACK_USER $IRONIC_AUTH_CACHE_DIR/registry
+    rm -f $IRONIC_AUTH_CACHE_DIR/registry/*
+}
+
+# create_ironic_accounts() - Set up common required ironic accounts
+
+# Tenant               User       Roles
+# ------------------------------------------------------------------
+# service              ironic     admin        # if enabled
+create_ironic_accounts() {
+
+    SERVICE_TENANT=$(keystone tenant-list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
+    ADMIN_ROLE=$(keystone role-list | awk "/ admin / { print \$2 }")
+
+    # Ironic
+    if [[ "$ENABLED_SERVICES" =~ "ir-api" ]]; then
+        IRONIC_USER=$(keystone user-create \
+            --name=ironic \
+            --pass="$SERVICE_PASSWORD" \
+            --tenant_id $SERVICE_TENANT \
+            --email=ironic@example.com \
+            | grep " id " | get_field 2)
+        keystone user-role-add \
+            --tenant_id $SERVICE_TENANT \
+            --user_id $IRONIC_USER \
+            --role_id $ADMIN_ROLE
+        if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
+            IRONIC_SERVICE=$(keystone service-create \
+                --name=ironic \
+                --type=baremetal \
+                --description="Ironic baremetal provisioning service" \
+                | grep " id " | get_field 2)
+            keystone endpoint-create \
+                --region RegionOne \
+                --service_id $IRONIC_SERVICE \
+                --publicurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT/v1/" \
+                --adminurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT/v1/" \
+                --internalurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT/v1/"
+        fi
+    fi
+}
+
+
+# init_ironic() - Initialize databases, etc.
+function init_ironic() {
+    # (Re)create  ironic database
+    recreate_database ironic utf8
+
+    # Migrate ironic database
+    $IRONIC_BIN_DIR/ironic-dbsync
+
+    create_ironic_cache_dir
+
+    # Create keystone artifacts for Ironic.
+    create_ironic_accounts
+}
+
+# install_ironic() - Collect source and prepare
+function install_ironic() {
+    git_clone $IRONIC_REPO $IRONIC_DIR $IRONIC_BRANCH
+    setup_develop $IRONIC_DIR
+}
+
+# start_ironic() - Start running processes, including screen
+function start_ironic() {
+    # Start Ironic API server, if enabled.
+    if is_service_enabled ir-api; then
+        start_ironic_api
+    fi
+
+    # Start Ironic conductor, if enabled.
+    if is_service_enabled ir-cond; then
+        start_ironic_conductor
+    fi
+}
+
+# start_ironic_api() - Used by start_ironic().
+# Starts Ironic API server.
+function start_ironic_api() {
+    screen_it ir-api "cd $IRONIC_DIR; $IRONIC_BIN_DIR/ironic-api --config-file=$IRONIC_CONF_FILE"
+    echo "Waiting for ir-api ($IRONIC_HOSTPORT) to start..."
+    if ! timeout $SERVICE_TIMEOUT sh -c "while ! http_proxy= wget -q -O- http://$IRONIC_HOSTPORT; do sleep 1; done"; then
+      die $LINENO "ir-api did not start"
+    fi
+}
+
+# start_ironic_conductor() - Used by start_ironic().
+# Starts Ironic conductor.
+function start_ironic_conductor() {
+    screen_it ir-cond "cd $IRONIC_DIR; $IRONIC_BIN_DIR/ironic-conductor --config-file=$IRONIC_CONF_FILE"
+    # TODO(romcheg): Find a way to check whether the conductor has started.
+}
+
+# stop_ironic() - Stop running processes
+function stop_ironic() {
+    # Kill the Ironic screen windows
+    screen -S $SCREEN_NAME -p ir-api -X kill
+    screen -S $SCREEN_NAME -p ir-cond -X kill
+}
+
+
+# Restore xtrace
+$XTRACE
+
+# Local variables:
+# mode: shell-script
+# End:
diff --git a/lib/keystone b/lib/keystone
index 0a35dd5..535710f 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -217,9 +217,9 @@
         --name admin \
         | grep " id " | get_field 2)
     keystone user-role-add \
-        --user_id $ADMIN_USER \
-        --role_id $ADMIN_ROLE \
-        --tenant_id $ADMIN_TENANT
+        --user-id $ADMIN_USER \
+        --role-id $ADMIN_ROLE \
+        --tenant-id $ADMIN_TENANT
 
     # service
     SERVICE_TENANT=$(keystone tenant-create \
@@ -244,10 +244,10 @@
         --pass "$ADMIN_PASSWORD" \
         --email demo@example.com \
         | grep " id " | get_field 2)
-    keystone user-role-add --user_id $DEMO_USER --role_id $MEMBER_ROLE --tenant_id $DEMO_TENANT
-    keystone user-role-add --user_id $ADMIN_USER --role_id $ADMIN_ROLE --tenant_id $DEMO_TENANT
-    keystone user-role-add --user_id $DEMO_USER --role_id $ANOTHER_ROLE --tenant_id $DEMO_TENANT
-    keystone user-role-add --user_id $DEMO_USER --role_id $MEMBER_ROLE --tenant_id $INVIS_TENANT
+    keystone user-role-add --user-id $DEMO_USER --role-id $MEMBER_ROLE --tenant-id $DEMO_TENANT
+    keystone user-role-add --user-id $ADMIN_USER --role-id $ADMIN_ROLE --tenant-id $DEMO_TENANT
+    keystone user-role-add --user-id $DEMO_USER --role-id $ANOTHER_ROLE --tenant-id $DEMO_TENANT
+    keystone user-role-add --user-id $DEMO_USER --role-id $MEMBER_ROLE --tenant-id $INVIS_TENANT
 
     # Keystone
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
diff --git a/lib/neutron b/lib/neutron
index 01fe3ea..dc3c622 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -301,9 +301,9 @@
             --email=neutron@example.com \
             | grep " id " | get_field 2)
         keystone user-role-add \
-            --tenant_id $SERVICE_TENANT \
-            --user_id $NEUTRON_USER \
-            --role_id $ADMIN_ROLE
+            --tenant-id $SERVICE_TENANT \
+            --user-id $NEUTRON_USER \
+            --role-id $ADMIN_ROLE
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
             NEUTRON_SERVICE=$(keystone service-create \
                 --name=neutron \
@@ -521,6 +521,15 @@
         done
     fi
 
+    if [ "$VIRT_DRIVER" = 'fake' ]; then
+        # Disable arbitrary limits
+        iniset $NEUTRON_CONF quotas quota_network -1
+        iniset $NEUTRON_CONF quotas quota_subnet -1
+        iniset $NEUTRON_CONF quotas quota_port -1
+        iniset $NEUTRON_CONF quotas quota_security_group -1
+        iniset $NEUTRON_CONF quotas quota_security_group_rule -1
+    fi
+
     _neutron_setup_rootwrap
 }
 
diff --git a/lib/nova b/lib/nova
index 0b65f84..19093ad 100644
--- a/lib/nova
+++ b/lib/nova
@@ -399,9 +399,9 @@
             --email=nova@example.com \
             | grep " id " | get_field 2)
         keystone user-role-add \
-            --tenant_id $SERVICE_TENANT \
-            --user_id $NOVA_USER \
-            --role_id $ADMIN_ROLE
+            --tenant-id $SERVICE_TENANT \
+            --user-id $NOVA_USER \
+            --role-id $ADMIN_ROLE
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
             NOVA_SERVICE=$(keystone service-create \
                 --name=nova \
diff --git a/lib/swift b/lib/swift
index 8e64152..f72beaf 100644
--- a/lib/swift
+++ b/lib/swift
@@ -464,7 +464,7 @@
 
     SWIFT_USER=$(keystone user-create --name=swift --pass="$SERVICE_PASSWORD" \
         --tenant_id $SERVICE_TENANT --email=swift@example.com | grep " id " | get_field 2)
-    keystone user-role-add --tenant_id $SERVICE_TENANT --user_id $SWIFT_USER --role_id $ADMIN_ROLE
+    keystone user-role-add --tenant-id $SERVICE_TENANT --user-id $SWIFT_USER --role-id $ADMIN_ROLE
 
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
         SWIFT_SERVICE=$(keystone service-create --name=swift --type="object-store" \
@@ -479,14 +479,14 @@
 
     SWIFT_TENANT_TEST1=$(keystone tenant-create --name=swifttenanttest1 | grep " id " | get_field 2)
     SWIFT_USER_TEST1=$(keystone user-create --name=swiftusertest1 --pass=testing --email=test@example.com | grep " id " | get_field 2)
-    keystone user-role-add --user_id $SWIFT_USER_TEST1 --role_id $ADMIN_ROLE --tenant_id $SWIFT_TENANT_TEST1
+    keystone user-role-add --user-id $SWIFT_USER_TEST1 --role-id $ADMIN_ROLE --tenant-id $SWIFT_TENANT_TEST1
 
     SWIFT_USER_TEST3=$(keystone user-create --name=swiftusertest3 --pass=testing3 --email=test3@example.com | grep " id " | get_field 2)
-    keystone user-role-add --user_id $SWIFT_USER_TEST3 --role_id $ANOTHER_ROLE --tenant_id $SWIFT_TENANT_TEST1
+    keystone user-role-add --user-id $SWIFT_USER_TEST3 --role-id $ANOTHER_ROLE --tenant-id $SWIFT_TENANT_TEST1
 
     SWIFT_TENANT_TEST2=$(keystone tenant-create --name=swifttenanttest2 | grep " id " | get_field 2)
     SWIFT_USER_TEST2=$(keystone user-create --name=swiftusertest2 --pass=testing2 --email=test2@example.com | grep " id " | get_field 2)
-    keystone user-role-add --user_id $SWIFT_USER_TEST2 --role_id $ADMIN_ROLE --tenant_id $SWIFT_TENANT_TEST2
+    keystone user-role-add --user-id $SWIFT_USER_TEST2 --role-id $ADMIN_ROLE --tenant-id $SWIFT_TENANT_TEST2
 }
 
 # init_swift() - Initialize rings
diff --git a/stack.sh b/stack.sh
index c3f69ad..89e4c24 100755
--- a/stack.sh
+++ b/stack.sh
@@ -318,6 +318,7 @@
 source $TOP_DIR/lib/neutron
 source $TOP_DIR/lib/baremetal
 source $TOP_DIR/lib/ldap
+source $TOP_DIR/lib/ironic
 
 # Look for Nova hypervisor plugin
 NOVA_PLUGINS=$TOP_DIR/lib/nova_plugins
@@ -596,64 +597,6 @@
 # Do the ugly hacks for borken packages and distros
 $TOP_DIR/tools/fixup_stuff.sh
 
-
-# System-specific preconfigure
-# ============================
-
-if [[ is_fedora && $DISTRO =~ (rhel6) ]]; then
-    # Disable selinux to avoid configuring to allow Apache access
-    # to Horizon files or run nodejs (LP#1175444)
-    if selinuxenabled; then
-        sudo setenforce 0
-    fi
-
-    # The following workarounds break xenserver
-    if [ "$VIRT_DRIVER" != 'xenserver' ]; then
-        # An old version of ``python-crypto`` (2.0.1) may be installed on a
-        # fresh system via Anaconda and the dependency chain
-        # ``cas`` -> ``python-paramiko`` -> ``python-crypto``.
-        # ``pip uninstall pycrypto`` will remove the packaged ``.egg-info``
-        #  file but leave most of the actual library files behind in
-        # ``/usr/lib64/python2.6/Crypto``. Later ``pip install pycrypto``
-        # will install over the packaged files resulting
-        # in a useless mess of old, rpm-packaged files and pip-installed files.
-        # Remove the package so that ``pip install python-crypto`` installs
-        # cleanly.
-        # Note: other RPM packages may require ``python-crypto`` as well.
-        # For example, RHEL6 does not install ``python-paramiko packages``.
-        uninstall_package python-crypto
-
-        # A similar situation occurs with ``python-lxml``, which is required by
-        # ``ipa-client``, an auditing package we don't care about.  The
-        # build-dependencies needed for ``pip install lxml`` (``gcc``,
-        # ``libxml2-dev`` and ``libxslt-dev``) are present in
-        # ``files/rpms/general``.
-        uninstall_package python-lxml
-    fi
-
-    # If the ``dbus`` package was installed by DevStack dependencies the
-    # uuid may not be generated because the service was never started (PR#598200),
-    # causing Nova to stop later on complaining that ``/var/lib/dbus/machine-id``
-    # does not exist.
-    sudo service messagebus restart
-
-    # ``setup.py`` contains a ``setup_requires`` package that is supposed
-    # to be transient.  However, RHEL6 distribute has a bug where
-    # ``setup_requires`` registers entry points that are not cleaned
-    # out properly after the setup-phase resulting in installation failures
-    # (bz#924038).  Pre-install the problem package so the ``setup_requires``
-    # dependency is satisfied and it will not be installed transiently.
-    # Note we do this before the track-depends below.
-    pip_install hgtools
-
-    # RHEL6's version of ``python-nose`` is incompatible with Tempest.
-    # Install nose 1.1 (Tempest-compatible) from EPEL
-    install_package python-nose1.1
-    # Add a symlink for the new nosetests to allow tox for Tempest to
-    # work unmolested.
-    sudo ln -sf /usr/bin/nosetests1.1 /usr/local/bin/nosetests
-fi
-
 install_rpc_backend
 
 if is_service_enabled $DATABASE_BACKENDS; then
@@ -785,6 +728,11 @@
     # don't be naive and add to existing line!
 fi
 
+if is_service_enabled ir-api ir-cond; then
+    install_ironic
+    configure_ironic
+fi
+
 if [[ $TRACK_DEPENDS = True ]]; then
     $DEST/.venv/bin/pip freeze > $DEST/requires-post-pip
     if ! diff -Nru $DEST/requires-pre-pip $DEST/requires-post-pip > $DEST/requires.diff; then
@@ -953,6 +901,15 @@
     init_glance
 fi
 
+# Ironic
+# ------
+
+if is_service_enabled ir-api ir-cond; then
+    echo_summary "Configuring Ironic"
+    init_ironic
+fi
+
+
 
 # Neutron
 # -------
@@ -1202,6 +1159,12 @@
     start_glance
 fi
 
+# Launch the Ironic services
+if is_service_enabled ir-api ir-cond; then
+    echo_summary "Starting Ironic"
+    start_ironic
+fi
+
 # Create an access key and secret key for nova ec2 register image
 if is_service_enabled key && is_service_enabled swift3 && is_service_enabled nova; then
     NOVA_USER_ID=$(keystone user-list | grep ' nova ' | get_field 1)
diff --git a/stackrc b/stackrc
index 8b97536..f9a977c 100644
--- a/stackrc
+++ b/stackrc
@@ -96,6 +96,10 @@
 HORIZON_REPO=${HORIZON_REPO:-${GIT_BASE}/openstack/horizon.git}
 HORIZON_BRANCH=${HORIZON_BRANCH:-master}
 
+# baremetal provisionint service
+IRONIC_REPO=${IRONIC_REPO:-${GIT_BASE}/openstack/ironic.git}
+IRONIC_BRANCH=${IRONIC_BRANCH:-master}
+
 # unified auth system (manages accounts/tokens)
 KEYSTONE_REPO=${KEYSTONE_REPO:-${GIT_BASE}/openstack/keystone.git}
 KEYSTONE_BRANCH=${KEYSTONE_BRANCH:-master}
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index 60d0f46..371b25f 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -9,10 +9,17 @@
 #   pip 1.4 doesn't fix it (1.3 did)
 # - httplib2 0.8 permissions are 600 in the package and
 #   pip 1.4 doesn't fix it (1.3 did)
+# - RHEL6:
+#   - set selinux not enforcing
+#   - (re)start messagebus daemon
+#   - remove distro packages python-crypto and python-lxml
+#   - pre-install hgtools to work around a bug in RHEL6 distribute
+#   - install nose 1.1 from EPEL
+
 
 # Keep track of the current directory
 TOOLS_DIR=$(cd $(dirname "$0") && pwd)
-TOP_DIR=`cd $TOOLS_DIR/..; pwd`
+TOP_DIR=$(cd $TOOLS_DIR/..; pwd)
 
 # Change dir to top of devstack
 cd $TOP_DIR
@@ -22,6 +29,10 @@
 
 FILES=$TOP_DIR/files
 
+
+# Python Packages
+# ---------------
+
 # Pre-install affected packages so we can fix the permissions
 sudo pip install prettytable
 sudo pip install httplib2
@@ -41,3 +52,65 @@
     fi
 
 done
+
+
+# RHEL6
+# -----
+
+if [[ $DISTRO =~ (rhel6) ]]; then
+
+    # Disable selinux to avoid configuring to allow Apache access
+    # to Horizon files or run nodejs (LP#1175444)
+    # FIXME(dtroyer): see if this can be skipped without node or if Horizon is not enabled
+    if selinuxenabled; then
+        sudo setenforce 0
+    fi
+
+    # If the ``dbus`` package was installed by DevStack dependencies the
+    # uuid may not be generated because the service was never started (PR#598200),
+    # causing Nova to stop later on complaining that ``/var/lib/dbus/machine-id``
+    # does not exist.
+    sudo service messagebus restart
+
+    # The following workarounds break xenserver
+    if [ "$VIRT_DRIVER" != 'xenserver' ]; then
+        # An old version of ``python-crypto`` (2.0.1) may be installed on a
+        # fresh system via Anaconda and the dependency chain
+        # ``cas`` -> ``python-paramiko`` -> ``python-crypto``.
+        # ``pip uninstall pycrypto`` will remove the packaged ``.egg-info``
+        #  file but leave most of the actual library files behind in
+        # ``/usr/lib64/python2.6/Crypto``. Later ``pip install pycrypto``
+        # will install over the packaged files resulting
+        # in a useless mess of old, rpm-packaged files and pip-installed files.
+        # Remove the package so that ``pip install python-crypto`` installs
+        # cleanly.
+        # Note: other RPM packages may require ``python-crypto`` as well.
+        # For example, RHEL6 does not install ``python-paramiko packages``.
+        uninstall_package python-crypto
+
+        # A similar situation occurs with ``python-lxml``, which is required by
+        # ``ipa-client``, an auditing package we don't care about.  The
+        # build-dependencies needed for ``pip install lxml`` (``gcc``,
+        # ``libxml2-dev`` and ``libxslt-dev``) are present in
+        # ``files/rpms/general``.
+        uninstall_package python-lxml
+    fi
+
+    # ``setup.py`` contains a ``setup_requires`` package that is supposed
+    # to be transient.  However, RHEL6 distribute has a bug where
+    # ``setup_requires`` registers entry points that are not cleaned
+    # out properly after the setup-phase resulting in installation failures
+    # (bz#924038).  Pre-install the problem package so the ``setup_requires``
+    # dependency is satisfied and it will not be installed transiently.
+    # Note we do this before the track-depends in ``stack.sh``.
+    pip_install hgtools
+
+
+    # RHEL6's version of ``python-nose`` is incompatible with Tempest.
+    # Install nose 1.1 (Tempest-compatible) from EPEL
+    install_package python-nose1.1
+    # Add a symlink for the new nosetests to allow tox for Tempest to
+    # work unmolested.
+    sudo ln -sf /usr/bin/nosetests1.1 /usr/local/bin/nosetests
+
+fi
diff --git a/tools/xen/README.md b/tools/xen/README.md
index af54d72..06192ed 100644
--- a/tools/xen/README.md
+++ b/tools/xen/README.md
@@ -1,48 +1,54 @@
-# Getting Started With XenServer 5.6 and Devstack
-The purpose of the code in this directory it to help developers bootstrap
-a XenServer 5.6 (or greater) + Openstack development environment.  This file gives
-some pointers on how to get started.
+# Getting Started With XenServer and Devstack
 
-Xenserver is a Type 1 hypervisor, so it needs to be installed on bare metal.
-The Openstack services are configured to run within a "privileged" virtual
-machine on the Xenserver host (called OS domU). The VM uses the XAPI toolstack
-to communicate with the host.
+The purpose of the code in this directory it to help developers bootstrap a
+XenServer 6.2 (older versions may also work) + Openstack development
+environment. This file gives some pointers on how to get started.
+
+Xenserver is a Type 1 hypervisor, so it is best installed on bare metal.  The
+Openstack services are configured to run within a virtual machine (called OS
+domU) on the XenServer host. The VM uses the XAPI toolstack to communicate with
+the host over a network connection (see `MGT_BRIDGE_OR_NET_NAME`).
 
 The provided localrc helps to build a basic environment.
-The requirements are:
+
+## Introduction
+
+### Requirements
+
  - An internet-enabled network with a DHCP server on it
  - XenServer box plugged in to the same network
 This network will be used as the OpenStack management network. The VM Network
 and the Public Network will not be connected to any physical interfaces, only
 new virtual networks will be created by the `install_os_domU.sh` script.
 
-Steps to follow:
+### Steps to follow
+
  - Install XenServer
  - Download Devstack to XenServer
  - Customise `localrc`
  - Start `install_os_domU.sh` script
 
+### Brief explanation
+
 The `install_os_domU.sh` script will:
  - Setup XenAPI plugins
  - Create the named networks, if they don't exist
- - Preseed-Netinstall an Ubuntu Virtual Machine, with 1 network interface:
-   - eth0 - Connected to `UBUNTU_INST_BRIDGE_OR_NET_NAME`, defaults to
-   `MGT_BRIDGE_OR_NET_NAME`
+ - Preseed-Netinstall an Ubuntu Virtual Machine (NOTE: you can save and reuse
+   it, see [Reuse the Ubuntu VM](#reuse-the-ubuntu-vm)), with 1 network
+   interface:
+   - `eth0` - Connected to `UBUNTU_INST_BRIDGE_OR_NET_NAME`, defaults to
+     `MGT_BRIDGE_OR_NET_NAME`
  - After the Ubuntu install process finished, the network configuration is
  modified to:
-   - eth0 - Management interface, connected to `MGT_BRIDGE_OR_NET_NAME`
-   - eth1 - VM interface, connected to `VM_BRIDGE_OR_NET_NAME`
-   - eth2 - Public interface, connected to `PUB_BRIDGE_OR_NET_NAME`
-   - (eth3) - Optional network interface if neutron is used, to enforce xapi to
-   create the underlying bridge.
+   - `eth0` - Management interface, connected to `MGT_BRIDGE_OR_NET_NAME`. Xapi
+     must be accessible through this network.
+   - `eth1` - VM interface, connected to `VM_BRIDGE_OR_NET_NAME`
+   - `eth2` - Public interface, connected to `PUB_BRIDGE_OR_NET_NAME`
  - Start devstack inside the created OpenStack VM
 
 ## Step 1: Install Xenserver
-Install XenServer 5.6+ on a clean box. You can get XenServer by signing
-up for an account on citrix.com, and then visiting:
-https://www.citrix.com/English/ss/downloads/details.asp?downloadId=2311504&productId=683148
-
-For details on installation, see: http://wiki.openstack.org/XenServer/Install
+Install XenServer on a clean box. You can download the latest XenServer for
+free from: http://www.xenserver.org/
 
 The XenServer IP configuration depends on your local network setup. If you are
 using dhcp, make a reservation for XenServer, so its IP address won't change
@@ -85,17 +91,20 @@
     XENAPI_CONNECTION_URL="http://address_of_your_xenserver"
     VNCSERVER_PROXYCLIENT_ADDRESS=address_of_your_xenserver
 
-    # Do not download the usual images
-    IMAGE_URLS=""
-    # Explicitly set virt driver here
+    # Download a vhd and a uec image
+    IMAGE_URLS="\
+    https://github.com/downloads/citrix-openstack/warehouse/cirros-0.3.0-x86_64-disk.vhd.tgz,\
+    http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz"
+
+    # Explicitly set virt driver
     VIRT_DRIVER=xenserver
-    # Explicitly enable multi-host
+
+    # Explicitly enable multi-host for nova-network HA
     MULTI_HOST=1
+
     # Give extra time for boot
     ACTIVE_TIMEOUT=45
 
-    # NOTE: the value of FLAT_NETWORK_BRIDGE will automatically be determined
-    # by install_os_domU.sh script.
     EOF
 
 ## Step 4: Run `./install_os_domU.sh` from the `tools/xen` directory
@@ -107,12 +116,60 @@
 installed and tail the run.sh.log file. You will need to wait until it run.sh
 has finished executing.
 
-## Step 5: Do cloudy stuff!
-* Play with horizon
-* Play with the CLI
-* Log bugs to devstack and core projects, and submit fixes!
+# Appendix
 
-## Step 6: Run from snapshot
-If you want to quicky re-run devstack from a clean state,
-using the same settings you used in your previous run,
-you can revert the DomU to the snapshot called `before_first_boot`
+This section contains useful information for running devstack in CI
+environments / using ubuntu network mirrors.
+
+## Use a specific Ubuntu mirror for installation
+
+To speed up the Ubuntu installation, you can use a specific mirror. To specify
+a mirror explicitly, include the following settings in your `localrc` file:
+
+    UBUNTU_INST_HTTP_HOSTNAME="archive.ubuntu.com"
+    UBUNTU_INST_HTTP_DIRECTORY="/ubuntu"
+
+These variables set the `mirror/http/hostname` and `mirror/http/directory`
+settings in the ubuntu preseed file. The minimal ubuntu VM will use the
+specified parameters.
+
+## Use an http proxy to speed up Ubuntu installation
+
+To further speed up the Ubuntu VM and package installation, an internal http
+proxy could be used. `squid-deb-proxy` has prooven to be stable. To use an http
+proxy, specify:
+
+    UBUNTU_INST_HTTP_PROXY="http://ubuntu-proxy.somedomain.com:8000"
+
+in your `localrc` file.
+
+## Reuse the Ubuntu VM
+
+Performing a minimal ubuntu installation could take a lot of time, depending on
+your mirror/network speed. If you run `install_os_domU.sh` script on a clean
+hypervisor, you can speed up the installation, by re-using the ubuntu vm from
+a previous installation.
+
+### Export the Ubuntu VM to an XVA
+
+Given you have an nfs export `TEMPLATE_NFS_DIR`:
+
+    TEMPLATE_FILENAME=devstack-jeos.xva
+    TEMPLATE_NAME=jeos_template_for_devstack
+    mountdir=$(mktemp -d)
+    mount -t nfs "$TEMPLATE_NFS_DIR" "$mountdir"
+    VM="$(xe template-list name-label="$TEMPLATE_NAME" --minimal)"
+    xe template-export template-uuid=$VM filename="$mountdir/$TEMPLATE_FILENAME"
+    umount "$mountdir"
+    rm -rf "$mountdir"
+
+### Import the Ubuntu VM
+
+Given you have an nfs export `TEMPLATE_NFS_DIR` where you exported the Ubuntu
+VM as `TEMPLATE_FILENAME`:
+
+    mountdir=$(mktemp -d)
+    mount -t nfs "$TEMPLATE_NFS_DIR" "$mountdir"
+    xe vm-import filename="$mountdir/$TEMPLATE_FILENAME"
+    umount "$mountdir"
+    rm -rf "$mountdir"
diff --git a/tools/xen/functions b/tools/xen/functions
index 7616a5f..a5c4b70 100644
--- a/tools/xen/functions
+++ b/tools/xen/functions
@@ -268,3 +268,22 @@
 
     xe network-attach uuid=$net host-uuid=$host
 }
+
+function set_vm_memory() {
+    local vm_name_label
+    local memory
+
+    vm_name_label="$1"
+    memory="$2"
+
+    local vm
+
+    vm=$(_vm_uuid "$vm_name_label")
+
+    xe vm-memory-limits-set \
+        static-min=${memory}MiB \
+        static-max=${memory}MiB \
+        dynamic-min=${memory}MiB \
+        dynamic-max=${memory}MiB \
+        uuid=$vm
+}
diff --git a/tools/xen/install_os_domU.sh b/tools/xen/install_os_domU.sh
index 997644d..b49504d 100755
--- a/tools/xen/install_os_domU.sh
+++ b/tools/xen/install_os_domU.sh
@@ -181,7 +181,7 @@
     mgmt_ip=$(echo $XENAPI_CONNECTION_URL | tr -d -c '1234567890.')
     domid=$(xe vm-list name-label="$GUEST_NAME" params=dom-id minimal=true)
     port=$(xenstore-read /local/domain/$domid/console/vnc-port)
-    echo "vncviewer -via $mgmt_ip localhost:${port:2}"
+    echo "vncviewer -via root@$mgmt_ip localhost:${port:2}"
     while true
     do
         state=$(xe_min vm-list name-label="$GUEST_NAME" power-state=halted)
@@ -228,8 +228,11 @@
     $THIS_DIR/scripts/install-os-vpx.sh \
         -t "$UBUNTU_INST_TEMPLATE_NAME" \
         -n "$UBUNTU_INST_BRIDGE_OR_NET_NAME" \
-        -l "$GUEST_NAME" \
-        -r "$OSDOMU_MEM_MB"
+        -l "$GUEST_NAME"
+
+    set_vm_memory "$GUEST_NAME" "$OSDOMU_MEM_MB"
+
+    xe vm-start vm="$GUEST_NAME"
 
     # wait for install to finish
     wait_for_VM_to_halt
@@ -255,6 +258,9 @@
 # Install XenServer tools, and other such things
 $THIS_DIR/prepare_guest_template.sh "$GUEST_NAME"
 
+# Set virtual machine parameters
+set_vm_memory "$GUEST_NAME" "$OSDOMU_MEM_MB"
+
 # start the VM to run the prepare steps
 xe vm-start vm="$GUEST_NAME"
 
diff --git a/tools/xen/scripts/install-os-vpx.sh b/tools/xen/scripts/install-os-vpx.sh
index 8ee8b67..c94a593 100755
--- a/tools/xen/scripts/install-os-vpx.sh
+++ b/tools/xen/scripts/install-os-vpx.sh
@@ -20,8 +20,6 @@
 set -eux
 
 BRIDGE=
-RAM=
-BALLOONING=
 NAME_LABEL=
 TEMPLATE_NAME=
 
@@ -29,7 +27,7 @@
 {
 cat << EOF
 
-  Usage: $0 -t TEMPLATE_NW_INSTALL -l NAME_LABEL [-n BRIDGE] [-r RAM] [-b] 
+  Usage: $0 -t TEMPLATE_NW_INSTALL -l NAME_LABEL [-n BRIDGE]
 
   Install a VM from a template
 
@@ -37,9 +35,6 @@
 
      -h           Shows this message.
      -t template  VM template to use
-     -b           Enable memory ballooning. When set min_RAM=RAM/2 max_RAM=RAM.
-     -r MiB       Specifies RAM used by the VPX, in MiB.
-                  By default it will take the value from the XVA.
      -l name      Specifies the name label for the VM.
      -n bridge    The bridge/network to use for eth0. Defaults to xenbr0
 EOF
@@ -53,12 +48,6 @@
       h) usage
          exit 1
          ;;
-      b)
-         BALLOONING=1
-         ;;
-      r)
-         RAM=$OPTARG
-         ;;
       n)
          BRIDGE=$OPTARG
          ;;
@@ -119,19 +108,6 @@
 }
 
 
-set_memory()
-{
-  local v="$1"
-  if [ "$RAM" != "" ]
-  then
-    echo "Setting RAM to $RAM MiB."
-    [ "$BALLOONING" == 1 ] && RAM_MIN=$(($RAM / 2)) || RAM_MIN=$RAM
-    xe vm-memory-limits-set static-min=16MiB static-max=${RAM}MiB \
-                            dynamic-min=${RAM_MIN}MiB dynamic-max=${RAM}MiB \
-                            uuid="$v"
-  fi
-}
-
 
 # Make the VM auto-start on server boot.
 set_auto_start()
@@ -161,5 +137,3 @@
 create_vif "$vm_uuid"
 xe vm-param-set other-config:os-vpx=true uuid="$vm_uuid"
 xe vm-param-set actions-after-reboot=Destroy uuid="$vm_uuid"
-set_memory "$vm_uuid"
-xe vm-start uuid=$vm_uuid
diff --git a/tools/xen/xenrc b/tools/xen/xenrc
index 03b30ac..f698be1 100644
--- a/tools/xen/xenrc
+++ b/tools/xen/xenrc
@@ -13,7 +13,7 @@
 
 # Size of image
 VDI_MB=${VDI_MB:-5000}
-OSDOMU_MEM_MB=1024
+OSDOMU_MEM_MB=2048
 OSDOMU_VDI_GB=8
 
 # Network mapping. Specify bridge names or network names. Network names may
diff --git a/unstack.sh b/unstack.sh
index f053bcd..38f795b 100755
--- a/unstack.sh
+++ b/unstack.sh
@@ -33,6 +33,7 @@
 source $TOP_DIR/lib/horizon
 source $TOP_DIR/lib/swift
 source $TOP_DIR/lib/neutron
+source $TOP_DIR/lib/ironic
 
 # Determine what system we are running on.  This provides ``os_VENDOR``,
 # ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME``
@@ -79,6 +80,12 @@
     cleanup_swift
 fi
 
+# Ironic runs daemons
+if is_service_enabled ir-api ir-cond; then
+    stop_ironic
+    cleanup_ironic
+fi
+
 # Apache has the WSGI processes
 if is_service_enabled horizon; then
     stop_horizon