Using Ansible with OpenStack

Monty Taylor

twitter: @e_monty

Who am I?

Office of Technology



Who am I?

Technical Committee

Developer Infrastructure Core Team

Former Foundation Board of Directors

PTL of shade project


Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.

Why Ansible is Great

  • simple declarative YAML syntax
  • list of tasks to perform - easy to debug
  • agentless - don't infect machines under management
  • Open Source - thousands of contributors worldwide

Ansible Overview

  • task - an action to perform
  • module - code that exposes a type of action
  • role - reusable collection of tasks to acomplish a goal
  • play - tasks and roles run on a specific host or hosts
  • inventory - list of locations available to run plays on
  • playbook - file containing one or more plays

Ansible Simple Example


- hosts: all
  - name: Print hostname of server
    command: hostname

A playbook containing a play that will run against all hosts in the inventory. It has one task that uses the command module to run the "hostname" command.

Ansible Longer Example


- hosts: git
    - create-mirror-locations
- hosts:
    - create-repositories

A playboook containing two plays. The first runs a role called "create-mirror-locations" against a group of hosts from the inventory called "git". Then it runs a role called "create-repositories" against a host from the inventory called "".

Ansible Modules

  • Usually written in Python
  • Can do anything, not limited to executing commands on a server
  • Manipulate Network Switch Config (ansible-network)
  • Build Containers (ansible-container)
  • Interact with REST APIs

Ansible OpenStack Modules

Interop - Work on All OpenStack Clouds

  • Ansible's OpenStack modules work the same on every OpenStack cloud

Don't let the existence of Rackspace modules confuse you. The OpenStack modules work just great on Rackspace

Work Around Deployer Differences ... To a Point

  • Herculean effort is made to hide a giant amount of differences
  • Even so - some bugs are EWONTFIX

A provider decided to redefine the OpenStack Availability Zone concept complete with incompatible API changes. That is unsupportable.

PS. Don't do that

Based on shade library

  • OpenStack python library to abstract deployment differences
  • designed for multi-cloud
  • simple to use
  • massive scale
    • optional advanced features to handle >20k servers a day
  • Initial logic/design extracted from OpenStack Infra's nodepool
  • Turned in to library for re-use in Ansible

Integration Testing

  • Every shade patch is integration tested in OpenStack Infra
  • Every shade patch tests the ansible modules in OpenStack Infra
  • Support coming very soon to test PRs to ansible modules in OpenStack Infra

Let's Take a Few Steps Back

OpenStack in Ansible and Multi-cloud Operations are easy...

but you need to know a few things.

  • Module structure
  • Terminology
  • Config

Module Structure

  • All modules start with os_
  • End-user oriented modules are named for the resource
    • os_image
    • os_sever
  • Operator oriented modules are named for the service
    • os_nova_flavor
    • os_keystone_domain
  • If it could go both ways, we prefer user orientation
    • os_user
    • os_group
  • If more than one service provides a resource, they DTRT
    • os_security_group
    • os_floating_ip

OpenStack Dynamic Inventory Script

  • Uses all hosts in all clouds as one inventory
  • Excludes hosts without IPs
  • Makes a bunch of auto-groups (flavor, image, az, region, cloud)
  • Makes groups for metadata['groups']

New inventory plugin coming in Ansible 2.4

Modules for All OpenStack Resources are Welcome Upstream

  • If there is a thing you want to manage that doesn't have a module, add one
  • We're very welcoming/accepting
  • Same goes for features to existing modules

To Serve All Users, We Have to be Strict

  • Modules that touch OpenStack APIs must do so via shade library
  • In user modules, vendor differences should be hidden
  • In operator modules, exposing them is ok


  • Information about the clouds you want to connect to is stored in a file called clouds.yaml.
  • In OpenStack Pike release, Horizon provides downloadable clouds.yaml
  • Both yaml and yml are acceptable.
  • clouds.yaml can be in your homedir: ~/.config/openstack/clouds.yaml or system-wide: /etc/openstack/clouds.yaml.
  • Information in your homedir, if it exists, takes precedence.
  • Full docs on clouds.yaml are at

What about Mac and Windows?

USER_CONFIG_DIR is different on Linux, OSX and Windows.

  • Linux: ~/.config/openstack
  • OSX: ~/Library/Application Support/openstack
  • Windows: C:\\Users\\USERNAME\\AppData\\Local\\OpenStack\\openstack

SITE_CONFIG_DIR is different on Linux, OSX and Windows.

  • Linux: /etc/openstack
  • OSX: /Library/Application Support/openstack
  • Windows: C:\\ProgramData\\OpenStack\\openstack

Config Terminology

For multi-cloud, think of two types:

  • profile - Facts about the cloud that are true for everyone
  • cloud - Information specific to a given user

Remember your Execution Context!

  • ansible executes code on remote systems
  • clouds.yaml needs to be on the host where the modules run
  • auth information can be passed to modules directly
  • other config (currently) MUST go in clouds.yaml
  • Ability to pass entire cloud config to module coming soon

basic clouds.yaml for the example code

Simple example of a clouds.yaml

    profile: citycloud
      username: mordred
      project_id: 65222a4d09ea4c68934fa1028c77f394
      user_domain_id: d0919bd5e8d74e49adf0e145807ffc38
      project_domain_id: d0919bd5e8d74e49adf0e145807ffc38

Where's the password?


  • Optional additional file just like clouds.yaml
  • Values overlaid on clouds.yaml
  • Useful if you want to protect secrets more stringently

Example secure.yaml

  • No, my password isn't XXXXXXXX
  • cloud name should match clouds.yaml
  • Optional - I actually keep mine in my clouds.yaml

      password: XXXXXXXX

more clouds.yaml

More information can be provided.

  • Use v3 of the identity API - even if others are present
  • Use for image API instead of what's in the catalog

  identity_api_version: 3
  profile: vexxhost
    user_domain_id: default
    project_domain_id: default
    project_name: d8af8a8f-a573-48e6-898a-af333b970a2d
    username: 0b8c435b-cc4d-4e05-8a47-a2ada0539af1

Much more complex clouds.yaml example

  • Not using a profile - all settings included
  • In the ams01 region there are two networks with undiscoverable qualities
  • Each one are labeled here so choices can be made
  • Any of the settings can be specific to a region if needed
  • region settings override cloud settings
  • cloud does not support floating-ips

    username: api-55f9a00fb2619
    project_name: inap-17037
  identity_api_version: 3
  floating_ip_source: None
  - name: ams01
      - name: inap-17037-WAN1654
        routes_externally: true
        default_interface: true
      - name: inap-17037-LAN3631
        routes_externally: false

Extra Variables to Control Inventory Behavior

  • expand_hostvars
    whether to make extra API calls to fill out additional information about each server
  • use_hostnames
    changes the behavior from registering every host with its UUID and making a group of its hostname to only doing this if the hostname in question has more than one server
  • fail_on_errors
    causes the inventory to fail and return no hosts if one cloud has failed
  use_hostnames: False
  expand_hostvars: True
  fail_on_errors: True

Test Your Config

- hosts: localhost
  - os_auth:
      cloud: "{{ }}"
      region_name: "{{ item.region }}"
    - cloud: my-vexxhost
      region: ca-ymq-1
    - cloud: my-citycloud
      region: Buf1
    - cloud: my-internap
      region: ams01

More Interesting

- hosts: localhost
  - os_server:
      name: "my-server"
      cloud: "{{ }}"
      region_name: "{{ item.region }}"
      image: "{{ item.image }}"
      flavor: "{{ item.flavor }}"
      auto_ip: true
    - cloud: my-vexxhost
      region: ca-ymq-1
      image: Ubuntu 16.04.1 LTS [2017-03-03]
      flavor: v1-standard-4
    - cloud: my-citycloud
      region: Buf1
      image: Ubuntu 16.04 Xenial Xerus
      flavor: 4C-4GB-100GB
    - cloud: my-internap
      region: ams01
      image: Ubuntu 16.04 LTS (Xenial Xerus)
      flavor: A1.4

Check That There is an Inventory

python ~/src/ --list

Cleanup After Ourselves

- hosts: localhost
  - os_server:
      cloud: "{{ }}"
      region_name: "{{ item.region }}"
      name: my-server
      state: absent
    - cloud: my-vexxhost
      region: ca-ymq-1
    - cloud: my-citycloud
      region: Buf1
    - cloud: my-internap
      region: ams01

Check out Ansible Cloud Launcher

  • Role for launching resources on an OpenStack Cloud

Check out Linch-pin

  • From our friends in CentOS

Linch-pin provides a collection of Ansible playbooks for provisioning, decommissioning, and managing resources across multiple infrastructures. The main goal of linch-pin is to facilitate provisioning and orchestration of resources in a multi-cloud environment through a topology file.

Thank you!

twitter: @e_monty