diff --git a/.gitmodules b/.gitmodules
index 1537cb216..695d0b0ea 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -82,3 +82,6 @@
 [submodule "packstack/puppet/modules/mongodb"]
 	path = packstack/puppet/modules/mongodb
 	url = https://github.com/puppetlabs/puppetlabs-mongodb.git
+[submodule "packstack/puppet/modules/heat"]
+	path = packstack/puppet/modules/heat
+	url = https://github.com/packstack/puppet-heat.git
diff --git a/packstack/plugins/heat_750.py b/packstack/plugins/heat_750.py
new file mode 100644
index 000000000..269f71017
--- /dev/null
+++ b/packstack/plugins/heat_750.py
@@ -0,0 +1,202 @@
+"""
+Installs and configures heat
+"""
+
+import uuid
+import logging
+import os
+
+from packstack.installer import utils
+from packstack.installer import validators
+
+from packstack.modules.ospluginutils import (getManifestTemplate,
+                                             manifestfiles,
+                                             appendManifestFile)
+
+controller = None
+
+# Plugin name
+PLUGIN_NAME = "OS-HEAT"
+PLUGIN_NAME_COLORED = utils.color_text(PLUGIN_NAME, 'blue')
+
+logging.debug("plugin %s loaded", __name__)
+
+
+def initConfig(controllerObject):
+    global controller
+    controller = controllerObject
+    logging.debug("Adding OpenStack Heat configuration")
+    parameters = [
+        {"CMD_OPTION"      : "heat-host",
+         "USAGE"           : ('The IP address of the server on which '
+                              'to install Heat service'),
+         "PROMPT"          : 'Enter the IP address of the Heat service',
+         "OPTION_LIST"     : [],
+         "VALIDATORS"      : [validators.validate_ssh],
+         "DEFAULT_VALUE"   : utils.get_localhost_ip(),
+         "MASK_INPUT"      : False,
+         "LOOSE_VALIDATION": True,
+         "CONF_NAME"       : "CONFIG_HEAT_HOST",
+         "USE_DEFAULT"     : False,
+         "NEED_CONFIRM"    : False,
+         "CONDITION"       : False },
+
+        {"CMD_OPTION"      : "heat-mysql-password",
+         "USAGE"	         : 'The password used by Heat user to authenticate against MySQL',
+         "PROMPT"          : "Enter the password for the Heat MySQL user",
+         "OPTION_LIST"     : [],
+         "VALIDATORS"      : [validators.validate_not_empty],
+         "DEFAULT_VALUE"   : uuid.uuid4().hex[:16],
+         "MASK_INPUT"      : True,
+         "LOOSE_VALIDATION": False,
+         "CONF_NAME"       : "CONFIG_HEAT_DB_PW",
+         "USE_DEFAULT"     : True,
+         "NEED_CONFIRM"    : True,
+         "CONDITION"       : False },
+
+        {"CMD_OPTION"      : "heat-ks-passwd",
+         "USAGE"           : "The password to use for the Heat to authenticate with Keystone",
+         "PROMPT"          : "Enter the password for the Heat Keystone access",
+         "OPTION_LIST"     : [],
+         "VALIDATORS"      : [validators.validate_not_empty],
+         "DEFAULT_VALUE"   : uuid.uuid4().hex[:16],
+         "MASK_INPUT"      : True,
+         "LOOSE_VALIDATION": False,
+         "CONF_NAME"       : "CONFIG_HEAT_KS_PW",
+         "USE_DEFAULT"     : True,
+         "NEED_CONFIRM"    : True,
+         "CONDITION"       : False },
+
+        {"CMD_OPTION"      : "os-heat-cloudwatch-install",
+         "USAGE"           : ("Set to 'y' if you would like Packstack to "
+                              "install Heat CloudWatch API"),
+         "PROMPT"          : "Should Packstack install Heat CloudWatch API",
+         "OPTION_LIST"     : ["y", "n"],
+         "VALIDATORS"      : [validators.validate_options],
+         "DEFAULT_VALUE"   : "n",
+         "MASK_INPUT"      : False,
+         "LOOSE_VALIDATION": False,
+         "CONF_NAME"       : "CONFIG_HEAT_CLOUDWATCH_INSTALL",
+         "USE_DEFAULT"     : False,
+         "NEED_CONFIRM"    : False,
+         "CONDITION"       : False },
+
+        {"CMD_OPTION"      : "os-heat-cfn-install",
+         "USAGE"           : ("Set to 'y' if you would like Packstack to "
+                              "install Heat CloudFormation API"),
+         "PROMPT"          : "Should Packstack install Heat CloudFormation API",
+         "OPTION_LIST"     : ["y", "n"],
+         "VALIDATORS"      : [validators.validate_options],
+         "DEFAULT_VALUE"   : "n",
+         "MASK_INPUT"      : False,
+         "LOOSE_VALIDATION": False,
+         "CONF_NAME"       : "CONFIG_HEAT_CFN_INSTALL",
+         "USE_DEFAULT"     : False,
+         "NEED_CONFIRM"    : False,
+         "CONDITION"       : False },
+        ]
+    group = {"GROUP_NAME"          : "Heat",
+             "DESCRIPTION"         : "Heat Config parameters",
+             "PRE_CONDITION"       : "CONFIG_HEAT_INSTALL",
+             "PRE_CONDITION_MATCH" : "y",
+             "POST_CONDITION"      : False,
+             "POST_CONDITION_MATCH": True}
+    controller.addGroup(group, parameters)
+
+    parameters = [
+        {"CMD_OPTION"      : "heat-api-cloudwatch-host",
+         "USAGE"           : ('The IP address of the server on which '
+                              'to install Heat CloudWatch API service'),
+         "PROMPT"          : ('Enter the IP address of the Heat CloudWatch API '
+                              'server'),
+         "OPTION_LIST"     : [],
+         "VALIDATORS"      : [validators.validate_ssh],
+         "DEFAULT_VALUE"   : utils.get_localhost_ip(),
+         "MASK_INPUT"      : False,
+         "LOOSE_VALIDATION": True,
+         "CONF_NAME"       : "CONFIG_HEAT_CLOUDWATCH_HOST",
+         "USE_DEFAULT"     : False,
+         "NEED_CONFIRM"    : False,
+         "CONDITION"       : False },
+    ]
+    group = {"GROUP_NAME"          : "Heat CloudWatch API",
+             "DESCRIPTION"         : "Heat CloudWatch API config parameters",
+             "PRE_CONDITION"       : "CONFIG_HEAT_CLOUDWATCH_INSTALL",
+             "PRE_CONDITION_MATCH" : "y",
+             "POST_CONDITION"      : False,
+             "POST_CONDITION_MATCH": True}
+    controller.addGroup(group, parameters)
+
+    parameters = [
+        {"CMD_OPTION"      : "heat-api-cfn-host",
+         "USAGE"           : ('The IP address of the server on which '
+                              'to install Heat CloudFormation API service'),
+         "PROMPT"          : ('Enter the IP address of the Heat CloudFormation '
+                              'API server'),
+         "OPTION_LIST"     : [],
+         "VALIDATORS"      : [validators.validate_ssh],
+         "DEFAULT_VALUE"   : utils.get_localhost_ip(),
+         "MASK_INPUT"      : False,
+         "LOOSE_VALIDATION": True,
+         "CONF_NAME"       : "CONFIG_HEAT_CFN_HOST",
+         "USE_DEFAULT"     : False,
+         "NEED_CONFIRM"    : False,
+         "CONDITION"       : False },
+    ]
+    group = {"GROUP_NAME"          : "Heat CloudFormation API",
+             "DESCRIPTION"         : "Heat CloudFormation API config parameters",
+             "PRE_CONDITION"       : "CONFIG_HEAT_CFN_INSTALL",
+             "PRE_CONDITION_MATCH" : "y",
+             "POST_CONDITION"      : False,
+             "POST_CONDITION_MATCH": True}
+    controller.addGroup(group, parameters)
+
+
+def initSequences(controller):
+    if controller.CONF['CONFIG_HEAT_INSTALL'] != 'y':
+        return
+    steps = [{'title': 'Adding Heat manifest entries',
+              'functions': [create_manifest]},
+             {'title': 'Adding Heat Keystone manifest entries',
+              'functions':[create_keystone_manifest]}]
+
+    if controller.CONF.get('CONFIG_HEAT_CLOUDWATCH_INSTALL', 'n') == 'y':
+        steps.append({'title': 'Adding Heat CloudWatch API manifest entries',
+                      'functions': [create_cloudwatch_manifest]})
+    if controller.CONF.get('CONFIG_HEAT_CFN_INSTALL', 'n') == 'y':
+        steps.append({'title': 'Adding Heat CloudFormation API manifest entries',
+                      'functions': [create_cfn_manifest]})
+    controller.addSequence("Installing Heat", [], [], steps)
+
+
+def create_manifest(config):
+    if config['CONFIG_HEAT_CLOUDWATCH_INSTALL'] == 'y':
+        config['CONFIG_HEAT_WATCH_HOST'] = config['CONFIG_HEAT_CLOUDWATCH_HOST']
+    else:
+        config['CONFIG_HEAT_WATCH_HOST'] = config['CONFIG_HEAT_HOST']
+    if config['CONFIG_HEAT_CFN_INSTALL'] == 'y':
+        config['CONFIG_HEAT_METADATA_HOST'] = config['CONFIG_HEAT_CFN_HOST']
+    else:
+        config['CONFIG_HEAT_METADATA_HOST'] = config['CONFIG_HEAT_HOST']
+
+    manifestfile = "%s_heat.pp" % controller.CONF['CONFIG_HEAT_HOST']
+    manifestdata = getManifestTemplate("heat.pp")
+    appendManifestFile(manifestfile, manifestdata)
+
+
+def create_keystone_manifest(config):
+    manifestfile = "%s_keystone.pp" % controller.CONF['CONFIG_KEYSTONE_HOST']
+    manifestdata = getManifestTemplate("keystone_heat.pp")
+    appendManifestFile(manifestfile, manifestdata)
+
+
+def create_cloudwatch_manifest(config):
+    manifestfile = "%s_heatcw.pp" % controller.CONF['CONFIG_HEAT_CLOUDWATCH_HOST']
+    manifestdata = getManifestTemplate("heat_cloudwatch.pp")
+    appendManifestFile(manifestfile, manifestdata, marker='heat')
+
+
+def create_cfn_manifest(config):
+    manifestfile = "%s_heatcnf.pp" % controller.CONF['CONFIG_HEAT_CFN_HOST']
+    manifestdata = getManifestTemplate("heat_cfn.pp")
+    appendManifestFile(manifestfile, manifestdata, marker='heat')
diff --git a/packstack/plugins/mysql_001.py b/packstack/plugins/mysql_001.py
index 7527746f8..c903a176a 100644
--- a/packstack/plugins/mysql_001.py
+++ b/packstack/plugins/mysql_001.py
@@ -103,7 +103,7 @@ def createmanifest(config):
         manifestdata.append(getManifestTemplate(template))
 
     append_for("keystone", suffix)
-    for mod in ['nova', 'cinder', 'glance', 'neutron']:
+    for mod in ['nova', 'cinder', 'glance', 'neutron', 'heat']:
         if config['CONFIG_%s_INSTALL' % mod.upper()] == 'y':
             append_for(mod, suffix)
 
diff --git a/packstack/plugins/prescript_000.py b/packstack/plugins/prescript_000.py
index 406a2a636..4bee99578 100644
--- a/packstack/plugins/prescript_000.py
+++ b/packstack/plugins/prescript_000.py
@@ -119,6 +119,18 @@ def initConfig(controllerObject):
                    "USE_DEFAULT"     : False,
                    "NEED_CONFIRM"    : False,
                    "CONDITION"       : False },
+                  {"CMD_OPTION"      : "os-heat-install",
+                   "USAGE"           : "Set to 'y' if you would like Packstack to install Heat",
+                   "PROMPT"          : "Should Packstack install Heat",
+                   "OPTION_LIST"     : ["y", "n"],
+                   "VALIDATORS"      : [validators.validate_options],
+                   "DEFAULT_VALUE"   : "n",
+                   "MASK_INPUT"      : False,
+                   "LOOSE_VALIDATION": False,
+                   "CONF_NAME"       : "CONFIG_HEAT_INSTALL",
+                   "USE_DEFAULT"     : False,
+                   "NEED_CONFIRM"    : False,
+                   "CONDITION"       : False },
                   {"CMD_OPTION"      : "os-client-install",
                    "USAGE"           : "Set to 'y' if you would like Packstack to install the OpenStack Client packages. An admin \"rc\" file will also be installed",
                    "PROMPT"          : "Should Packstack install OpenStack client tools",
diff --git a/packstack/plugins/puppet_950.py b/packstack/plugins/puppet_950.py
index a7627c8ce..dfb3bb443 100644
--- a/packstack/plugins/puppet_950.py
+++ b/packstack/plugins/puppet_950.py
@@ -77,7 +77,7 @@ def installdeps(config):
 def copyPuppetModules(config):
     os_modules = ' '.join(('apache', 'ceilometer', 'cinder', 'concat',
                            'create_resources', 'firewall', 'glance',
-                           'horizon', 'inifile', 'keystone',
+                           'heat', 'horizon', 'inifile', 'keystone',
                            'memcached', 'mongodb', 'mysql', 'neutron',
                            'nova', 'openstack', 'packstack', 'qpid',
                            'rsync', 'ssh', 'stdlib', 'swift', 'sysctl',
diff --git a/packstack/puppet/modules/heat b/packstack/puppet/modules/heat
new file mode 160000
index 000000000..84d623b0d
--- /dev/null
+++ b/packstack/puppet/modules/heat
@@ -0,0 +1 @@
+Subproject commit 84d623b0d38bcb136b7ba0948d3fd066dac4c637
diff --git a/packstack/puppet/templates/heat.pp b/packstack/puppet/templates/heat.pp
new file mode 100644
index 000000000..f9c82b365
--- /dev/null
+++ b/packstack/puppet/templates/heat.pp
@@ -0,0 +1,23 @@
+
+class { 'heat':
+    keystone_host     => '%(CONFIG_KEYSTONE_HOST)s',
+    keystone_password => '%(CONFIG_HEAT_KS_PW)s',
+    auth_uri          => 'http://%(CONFIG_KEYSTONE_HOST)s:35357/v2.0',
+    rpc_backend   => 'heat.openstack.common.rpc.impl_qpid',
+    qpid_hostname => '%(CONFIG_QPID_HOST)s',
+    verbose       => true,
+    debug         => true
+}
+
+class {"heat::db":
+    sql_connection => "mysql://heat:%(CONFIG_HEAT_DB_PW)s@%(CONFIG_MYSQL_HOST)s/heat"
+}
+
+class { 'heat::api':
+}
+
+class { 'heat::engine':
+    heat_metadata_server_url      => 'http://%(CONFIG_HEAT_METADATA_HOST)s:8000',
+    heat_waitcondition_server_url => 'http://%(CONFIG_HEAT_METADATA_HOST)s:8000/v1/waitcondition',
+    heat_watch_server_url         => 'http://%(CONFIG_HEAT_WATCH_HOST)s:8003',
+}
diff --git a/packstack/puppet/templates/heat_cfn.pp b/packstack/puppet/templates/heat_cfn.pp
new file mode 100644
index 000000000..c4afe0066
--- /dev/null
+++ b/packstack/puppet/templates/heat_cfn.pp
@@ -0,0 +1,18 @@
+
+class { 'heat':
+    keystone_host     => '%(CONFIG_KEYSTONE_HOST)s',
+    keystone_password => '%(CONFIG_HEAT_KS_PW)s',
+    auth_uri          => 'http://%(CONFIG_KEYSTONE_HOST)s:35357/v2.0',
+    rpc_backend   => 'heat.openstack.common.rpc.impl_qpid',
+    qpid_hostname => '%(CONFIG_QPID_HOST)s',
+    verbose       => true,
+    debug         => true
+}
+
+class {"heat::db":
+    sql_connection => "mysql://heat:%(CONFIG_HEAT_DB_PW)s@%(CONFIG_MYSQL_HOST)s/heat"
+}
+
+class { 'heat::api_cfn':
+}
+
diff --git a/packstack/puppet/templates/heat_cloudwatch.pp b/packstack/puppet/templates/heat_cloudwatch.pp
new file mode 100644
index 000000000..8ea6ceec5
--- /dev/null
+++ b/packstack/puppet/templates/heat_cloudwatch.pp
@@ -0,0 +1,17 @@
+
+class { 'heat':
+    keystone_host     => '%(CONFIG_KEYSTONE_HOST)s',
+    keystone_password => '%(CONFIG_HEAT_KS_PW)s',
+    auth_uri          => 'http://%(CONFIG_KEYSTONE_HOST)s:35357/v2.0',
+    rpc_backend   => 'heat.openstack.common.rpc.impl_qpid',
+    qpid_hostname => '%(CONFIG_QPID_HOST)s',
+    verbose       => true,
+    debug         => true
+}
+
+class {"heat::db":
+    sql_connection => "mysql://heat:%(CONFIG_HEAT_DB_PW)s@%(CONFIG_MYSQL_HOST)s/heat"
+}
+
+class { 'heat::api_cloudwatch':
+}
diff --git a/packstack/puppet/templates/keystone_heat.pp b/packstack/puppet/templates/keystone_heat.pp
new file mode 100644
index 000000000..4d012a307
--- /dev/null
+++ b/packstack/puppet/templates/keystone_heat.pp
@@ -0,0 +1,20 @@
+
+if '%(CONFIG_HEAT_CFN_INSTALL)s' == 'y' {
+    class {"heat::keystone::auth":
+        password => "%(CONFIG_HEAT_KS_PW)s",
+        heat_public_address => "%(CONFIG_HEAT_HOST)s",
+        heat_admin_address => "%(CONFIG_HEAT_HOST)s",
+        heat_internal_address => "%(CONFIG_HEAT_HOST)s",
+        cfn_public_address => "%(CONFIG_HEAT_HOST)s",
+        cfn_admin_address => "%(CONFIG_HEAT_HOST)s",
+        cfn_internal_address => "%(CONFIG_HEAT_HOST)s",
+    }
+} else {
+    class {"heat::keystone::auth":
+        password => "%(CONFIG_HEAT_KS_PW)s",
+        heat_public_address => "%(CONFIG_HEAT_HOST)s",
+        heat_admin_address => "%(CONFIG_HEAT_HOST)s",
+        heat_internal_address => "%(CONFIG_HEAT_HOST)s",
+        cfn_auth_name => undef,
+    }
+}
diff --git a/packstack/puppet/templates/mysql_heat_install.pp b/packstack/puppet/templates/mysql_heat_install.pp
new file mode 100644
index 000000000..dce040627
--- /dev/null
+++ b/packstack/puppet/templates/mysql_heat_install.pp
@@ -0,0 +1,4 @@
+class {"heat::db::mysql":
+    password      => "%(CONFIG_HEAT_DB_PW)s",
+    allowed_hosts => "%%",
+}
diff --git a/packstack/puppet/templates/mysql_heat_noinstall.pp b/packstack/puppet/templates/mysql_heat_noinstall.pp
new file mode 100644
index 000000000..c40b09818
--- /dev/null
+++ b/packstack/puppet/templates/mysql_heat_noinstall.pp
@@ -0,0 +1,27 @@
+
+remote_database { 'heat':
+    ensure      => 'present',
+    charset     => 'latin1',
+    db_host     => '%(CONFIG_MYSQL_HOST)s',
+    db_user     => '%(CONFIG_MYSQL_USER)s',
+    db_password => '%(CONFIG_MYSQL_PW)s',
+    provider    => 'mysql',
+}
+
+remote_database_user { 'heat@%%':
+    password_hash => mysql_password('%(CONFIG_HEAT_DB_PW)s'),
+    db_host       => '%(CONFIG_MYSQL_HOST)s',
+    db_user       => '%(CONFIG_MYSQL_USER)s',
+    db_password   => '%(CONFIG_MYSQL_PW)s',
+    provider      => 'mysql',
+    require       => Remote_database['heat'],
+}
+
+remote_database_grant { 'heat@%%/heat':
+    privileges  => "all",
+    db_host     => '%(CONFIG_MYSQL_HOST)s',
+    db_user     => '%(CONFIG_MYSQL_USER)s',
+    db_password => '%(CONFIG_MYSQL_PW)s',
+    provider    => 'mysql',
+    require     => Remote_database_user['heat@%%'],
+}