Learn OpenStack · core/orchestration/heat

Heat Operations

Stack Lifecycle

Create a Stack

# Basic stack creation
openstack stack create -t web-app.yaml web-app-stack

# With environment file and parameter overrides
openstack stack create \
  -t web-app.yaml \
  -e prod-env.yaml \
  --parameter db_password=secret123 \
  web-app-stack

# Multiple environment files (applied in order; later overrides earlier)
openstack stack create \
  -t web-app.yaml \
  -e base-env.yaml \
  -e prod-env.yaml \
  -e secrets.yaml \
  web-app-stack

# Wait for completion (poll until COMPLETE or FAILED)
openstack stack create --wait \
  -t web-app.yaml \
  -e prod-env.yaml \
  web-app-stack

# Dry-run preview (shows what resources would be created; does not create)
openstack stack create --dry-run \
  -t web-app.yaml \
  -e prod-env.yaml \
  web-app-stack

# Disable rollback on failure (useful for debugging)
openstack stack create --disable-rollback \
  -t web-app.yaml \
  web-app-stack

# Set a custom timeout (minutes)
openstack stack create --timeout 60 \
  -t web-app.yaml \
  web-app-stack

# Tag the stack
openstack stack create \
  -t web-app.yaml \
  --tag env=production,team=platform \
  web-app-stack

List Stacks

# List stacks in the current project
openstack stack list

# List all stacks (admin; all projects)
openstack stack list --all-projects

# Filter by status
openstack stack list --status CREATE_COMPLETE
openstack stack list --status ROLLBACK_COMPLETE

# Filter by tag
openstack stack list --tag env=production

# Show nested stacks
openstack stack list --nested

# Custom output columns
openstack stack list -c "Stack Name" -c "Stack Status" -c "Creation Time"

Stack status values:

Status Meaning
CREATE_IN_PROGRESS Stack creation running
CREATE_COMPLETE Stack created successfully
CREATE_FAILED Stack creation failed; resources may be partially created
UPDATE_IN_PROGRESS Stack update running
UPDATE_COMPLETE Stack updated successfully
UPDATE_FAILED Stack update failed
DELETE_IN_PROGRESS Stack deletion running
DELETE_COMPLETE Stack deleted (no longer visible in default list)
DELETE_FAILED Stack deletion failed; some resources could not be deleted
ROLLBACK_IN_PROGRESS Rolling back after a failed create or update
ROLLBACK_COMPLETE Rollback completed; stack is in previous state
ROLLBACK_FAILED Rollback itself failed
SUSPEND_IN_PROGRESS Suspending all resources
SUSPEND_COMPLETE All resources suspended
RESUME_IN_PROGRESS Resuming all resources
RESUME_COMPLETE All resources resumed
CHECK_IN_PROGRESS Checking resource states
CHECK_COMPLETE All resources verified against real-world state
SNAPSHOT_IN_PROGRESS Creating a stack snapshot
SNAPSHOT_COMPLETE Snapshot created
RESTORE_IN_PROGRESS Restoring from snapshot
RESTORE_COMPLETE Restore completed

Show Stack Details

# Full stack details (status, parameters, outputs, links)
openstack stack show web-app-stack

# Show as JSON
openstack stack show -f json web-app-stack

# Show stack outputs
openstack stack output list web-app-stack
openstack stack output show web-app-stack floating_ip
openstack stack output show web-app-stack db_connection_string

# Show the template that was used to create the stack
openstack stack template show web-app-stack

Update a Stack

# Update with a new template
openstack stack update \
  -t web-app-v2.yaml \
  -e prod-env.yaml \
  web-app-stack

# Update a single parameter without changing the template
openstack stack update \
  --existing \
  --parameter instance_count=5 \
  web-app-stack

# Update and wait for completion
openstack stack update --wait \
  -t web-app-v2.yaml \
  web-app-stack

# Perform a dry-run update preview
openstack stack update --dry-run \
  -t web-app-v2.yaml \
  web-app-stack

# Update without rollback on failure
openstack stack update --disable-rollback \
  -t web-app-v2.yaml \
  web-app-stack

Check, Suspend, and Resume

# Check — reconcile Heat's recorded state against the actual state of each resource
# (e.g. if someone deleted a server manually, check will mark it as gone)
openstack stack check web-app-stack

# Suspend all resources in a stack (puts instances in SUSPENDED state, etc.)
openstack stack suspend web-app-stack

# Resume a suspended stack
openstack stack resume web-app-stack

Delete a Stack

# Delete a stack and all its resources
openstack stack delete web-app-stack

# Delete without confirmation prompt
openstack stack delete --yes web-app-stack

# Delete and wait for completion
openstack stack delete --wait --yes web-app-stack

# Abandon a stack (remove from Heat without deleting resources)
openstack stack abandon web-app-stack

# Adopt an existing set of resources into a new stack
# (re-import resources previously abandoned)
openstack stack adopt \
  -t web-app.yaml \
  --adopt-file abandon-output.json \
  web-app-stack

Resource Operations

List Resources

# List all resources in a stack
openstack stack resource list web-app-stack

# List resources including nested stacks
openstack stack resource list --nested-depth 3 web-app-stack

# Filter by resource status
openstack stack resource list --filter status=CREATE_FAILED web-app-stack

# List in a specific format
openstack stack resource list -f json web-app-stack

Show a Resource

# Show resource details (type, status, physical ID, links)
openstack stack resource show web-app-stack web_server

# Show resource metadata
openstack stack resource metadata web-app-stack web_server

# Mark a resource as needing replacement on the next update
openstack stack resource mark-unhealthy web-app-stack web_server --reason "kernel panic"

Signal a Resource

Some resources accept signals to trigger transitions (wait conditions, auto-scaling policies):

# Send a signal to a wait condition handle
openstack stack resource signal web-app-stack wait_handle

# Send a signal with JSON data
openstack stack resource signal \
  --data '{"status": "SUCCESS", "reason": "Setup complete", "id": "1"}' \
  web-app-stack wait_handle

Event Operations

List Events

# List events for a stack (newest first)
openstack stack event list web-app-stack

# List events including nested stacks
openstack stack event list --nested-depth 2 web-app-stack

# Follow events in real time (like tail -f)
openstack stack event list --follow web-app-stack

# List events for a specific resource
openstack stack event list web-app-stack --resource web_server

# Limit output
openstack stack event list --limit 50 web-app-stack

Show an Event

# Show a specific event (by event ID from the list)
openstack stack event show web-app-stack web_server <event-id>

Template Operations

Validate a Template

# Validate template syntax and resource types
openstack orchestration template validate -t web-app.yaml

# Validate with environment
openstack orchestration template validate \
  -t web-app.yaml \
  -e prod-env.yaml

# Show resolved parameter types and constraints
openstack orchestration template validate \
  -t web-app.yaml \
  --show-nested

List Resource Types

# List all available resource types
openstack orchestration resource type list

# Filter by name
openstack orchestration resource type list --filter name=OS::Nova

# Show schema (properties, attributes) for a specific resource type
openstack orchestration resource type show OS::Nova::Server
openstack orchestration resource type show OS::Neutron::Router
openstack orchestration resource type show OS::Heat::AutoScalingGroup

Generate a Template Skeleton

# Generate a minimal template for a resource type
openstack orchestration template version list
openstack orchestration template generate \
  --template-type hot \
  OS::Nova::Server OS::Neutron::Net OS::Neutron::Subnet

Stack Snapshots

# Create a snapshot of a stack (saves current resource state)
openstack stack snapshot create web-app-stack --name pre-upgrade-snapshot

# List snapshots
openstack stack snapshot list web-app-stack

# Show a snapshot
openstack stack snapshot show web-app-stack <snapshot-id>

# Restore from a snapshot
openstack stack snapshot restore web-app-stack <snapshot-id>

# Delete a snapshot
openstack stack snapshot delete web-app-stack <snapshot-id>

Complete HOT Template Example

The following template creates a fully networked single-server application stack with: - Private network, subnet, and router - Security group allowing SSH and HTTP - A Nova server - A Cinder volume attached to the server - A floating IP

heat_template_version: 2021-04-16

description: |
  Single-server web application with private network, security group,
  persistent volume, and floating IP.

parameters:
  key_name:
    type: string
    description: SSH key pair for instance access
    constraints:
      - custom_constraint: nova.keypair

  flavor:
    type: string
    default: m1.small
    description: Instance flavor
    constraints:
      - custom_constraint: nova.flavor

  image:
    type: string
    default: ubuntu-24.04
    description: Boot image name or ID
    constraints:
      - custom_constraint: glance.image

  public_net:
    type: string
    default: public
    description: External network name for floating IPs

  private_net_cidr:
    type: string
    default: 192.168.100.0/24
    description: CIDR for the private subnet

  private_net_gateway:
    type: string
    default: 192.168.100.1
    description: Gateway address for the private subnet

  volume_size:
    type: number
    default: 20
    description: Data volume size in GB
    constraints:
      - range: {min: 1, max: 500}

  db_password:
    type: string
    description: Database password (hidden)
    hidden: true

resources:

  # ── Networking ─────────────────────────────────────────────────────────────

  private_network:
    type: OS::Neutron::Net
    properties:
      name: web-app-net

  private_subnet:
    type: OS::Neutron::Subnet
    properties:
      network: {get_resource: private_network}
      cidr: {get_param: private_net_cidr}
      gateway_ip: {get_param: private_net_gateway}
      dns_nameservers: [8.8.8.8, 8.8.4.4]
      allocation_pools:
        - start: 192.168.100.10
          end: 192.168.100.200

  router:
    type: OS::Neutron::Router
    properties:
      name: web-app-router
      external_gateway_info:
        network: {get_param: public_net}

  router_interface:
    type: OS::Neutron::RouterInterface
    properties:
      router: {get_resource: router}
      subnet: {get_resource: private_subnet}

  # ── Security ────────────────────────────────────────────────────────────────

  web_security_group:
    type: OS::Neutron::SecurityGroup
    properties:
      name: web-sg
      description: Allow SSH and HTTP/HTTPS inbound
      rules:
        - protocol: tcp
          port_range_min: 22
          port_range_max: 22
          remote_ip_prefix: 0.0.0.0/0
        - protocol: tcp
          port_range_min: 80
          port_range_max: 80
          remote_ip_prefix: 0.0.0.0/0
        - protocol: tcp
          port_range_min: 443
          port_range_max: 443
          remote_ip_prefix: 0.0.0.0/0
        - protocol: icmp
          remote_ip_prefix: 0.0.0.0/0

  # ── Compute ─────────────────────────────────────────────────────────────────

  server_port:
    type: OS::Neutron::Port
    properties:
      network: {get_resource: private_network}
      fixed_ips:
        - subnet: {get_resource: private_subnet}
      security_groups:
        - {get_resource: web_security_group}

  web_server:
    type: OS::Nova::Server
    properties:
      name: web-app-server
      image: {get_param: image}
      flavor: {get_param: flavor}
      key_name: {get_param: key_name}
      networks:
        - port: {get_resource: server_port}
      user_data_format: RAW
      user_data:
        str_replace:
          template: |
            #!/bin/bash
            set -ex
            apt-get update -y
            apt-get install -y nginx
            systemctl enable --now nginx
            echo "DB_PASSWORD=$db_password" >> /etc/app.env
          params:
            $db_password: {get_param: db_password}

  # ── Storage ──────────────────────────────────────────────────────────────────

  data_volume:
    type: OS::Cinder::Volume
    properties:
      name: web-app-data
      size: {get_param: volume_size}
      volume_type: __DEFAULT__

  volume_attachment:
    type: OS::Cinder::VolumeAttachment
    properties:
      volume_id: {get_resource: data_volume}
      instance_uuid: {get_resource: web_server}

  # ── Floating IP ──────────────────────────────────────────────────────────────

  floating_ip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: {get_param: public_net}
      port_id: {get_resource: server_port}

outputs:

  floating_ip:
    description: Public floating IP address of the web server
    value: {get_attr: [floating_ip, floating_ip_address]}

  private_ip:
    description: Private IP address of the web server
    value: {get_attr: [web_server, first_address]}

  server_id:
    description: Nova instance UUID
    value: {get_resource: web_server}

  volume_id:
    description: Cinder volume UUID
    value: {get_resource: data_volume}

Environment File Example

# prod-env.yaml
# Apply with: openstack stack create -t main.yaml -e prod-env.yaml my-stack

parameters:
  # Exact values for this deployment
  key_name: prod-keypair
  flavor: m1.large
  image: ubuntu-24.04
  public_net: provider-net
  private_net_cidr: 10.20.0.0/24
  private_net_gateway: 10.20.0.1
  volume_size: 100
  db_password: MySuperSecretProdPassword!

parameter_defaults:
  # Fallback defaults; used when a parameter is not set by higher-priority sources
  flavor: m1.medium
  image: ubuntu-22.04
  volume_size: 20

resource_registry:
  # Override OS::Nova::Server with a custom organization template
  # (e.g., adds mandatory monitoring agents)
  MyOrg::Server: file:///etc/heat/templates/base-server.yaml
  # Prevent Heat from managing keypairs (they are pre-provisioned)
  OS::Nova::KeyPair: OS::Heat::None

Heat Configuration Reference

Configuration file: /etc/heat/heat.conf

[DEFAULT]
# Number of engine worker processes to spawn
num_engine_workers = 4

# Maximum number of resources per stack
max_resources_per_stack = 1000

# Maximum number of stacks per project (0 = unlimited)
max_stacks_per_tenant = 100

# Default stack creation timeout (minutes)
stack_action_timeout = 60

# Enable convergence engine (default: true)
convergence_engine = true

# RPC transport URL (RabbitMQ)
transport_url = rabbit://heat:rabbit_pass@10.0.0.10:5672/

# Log to file
log_file = /var/log/heat/heat.log
log_dir = /var/log/heat

# Debug logging
debug = false

[heat_api]
# Bind address and port for heat-api
bind_host = 0.0.0.0
bind_port = 8004
workers = 4

[heat_api_cfn]
# Bind address and port for heat-api-cfn (CloudFormation compat)
bind_host = 0.0.0.0
bind_port = 8000
workers = 2

[database]
# SQLAlchemy connection string
connection = mysql+pymysql://heat:heat_db_pass@10.0.0.10/heat

# Connection pool settings
max_pool_size = 20
max_overflow = 20
pool_timeout = 30

[keystone_authtoken]
# Keystone middleware for heat-api authentication
www_authenticate_uri = http://10.0.0.10:5000
auth_url = http://10.0.0.10:5000
memcached_servers = 10.0.0.10:11211
auth_type = password
project_domain_name = Default
user_domain_name = Default
project_name = service
username = heat
password = heat_service_password

[clients_keystone]
# Keystone endpoint used by heat-engine for trust operations
auth_uri = http://10.0.0.10:5000

[trustee]
# Service user for creating and consuming Keystone trusts
auth_type = password
auth_url = http://10.0.0.10:5000
username = heat
password = heat_service_password
user_domain_id = default

[oslo_messaging_rabbit]
# RabbitMQ connection settings (if using oslo_messaging backend)
rabbit_ha_queues = true
heartbeat_timeout_threshold = 60

[oslo_policy]
enforce_scope = true
enforce_new_defaults = true

[paste_deploy]
api_paste_config = /etc/heat/api-paste.ini

Service Management

# Start Heat services (systemd)
systemctl start openstack-heat-api
systemctl start openstack-heat-api-cfn
systemctl start openstack-heat-engine

# Enable on boot
systemctl enable openstack-heat-api
systemctl enable openstack-heat-api-cfn
systemctl enable openstack-heat-engine

# View logs
journalctl -u openstack-heat-engine -f
tail -f /var/log/heat/heat-engine.log

# Initialize or upgrade the database schema
heat-manage db_sync

# Clean up old stack events from the database
heat-manage purge_deleted -g 30  # purge events older than 30 days