Add ansible playbooks for 3 minute multi-cloud demo

This commit is contained in:
Monty Taylor 2017-11-05 13:24:37 +11:00
parent 2f5dfc4951
commit 4ac60cf090
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
13 changed files with 270 additions and 0 deletions

View File

@ -0,0 +1,11 @@
FROM python
RUN apt-get update && \
apt-get install -y qemu-utils libffi-dev libssl-dev sudo \
rpm yum-utils debootstrap && \
pip install ansible shade diskimage-builder
VOLUME /demo
WORKDIR /demo
ENTRYPOINT ["ansible-playbook"]
CMD ["demo.yaml"]

View File

@ -0,0 +1,80 @@
3 Minute Demo of OpenStack Public Clouds
========================================
This is all the Ansible needed for the 3 minute public cloud demo.
It uses docker containers to avoid the need to install things on the local
computer. The Dockerfile uses the base ``python`` docker image regardless
of other distro since it's just a container for installing ansible.
.. note::
There is nothing docker-specific about the demo, it's just being used as
a convenient way to bundle actions without polluting the user's computer.
The playbooks themselves can be used directly for people who have the
pre-reqs of ansible, shade and diskimage-builder installed or who do not
mind installing them globally.
Building Docker Image
---------------------
Step one is building the docker image:
.. code-block:: bash
docker build -t three-minute-demo .
A convenience script, ``build-docker-image.sh`` is provided that runs that
command.
Wrapper Script
--------------
Once the ``three-minute-demo`` image exists, the ``ansible-playbook.sh`` script
will user it to run ``ansible-playbook``. By default it will run the
``run.yaml`` playbook, but that can be overridden by passing parameters to the
script.
The ``ansible-playbook.sh`` script will also bind-mount the current directory
as the main work dir and ``~/.config/openstack`` into ``/etc/openstack`` in the
container so that ``clouds.yaml`` is available.
.. note::
If ~/.config/openstack doesn't exist but /etc/openstack does,
ansible-playbook.sh will mount /etc/openstack instead. If a different setup
is desired, you can always run docker commands.
Building and Uploading Images
-----------------------------
The demo depends on base images existing. The ``prep.yaml`` playbook will
create the images and upload them to all of the cloud regions.
.. code-block:: bash
./ansible-playbook.sh prep.yaml
By default it will create a minimal ubuntu image. That can be changed by
setting ``distro`` on the ansible-playbook command line to something else, such
as ``fedora`` or ``centos``.
.. code-block:: bash
./ansible-playbook.sh -edistro=fedora prep.yaml
The Demo
--------
``ansible-playbook.sh`` defaults to running ``demo.yaml``, which will create a
server in each cloud region, install Apache on that server, write out a json
file for apache to serve, fetch the contents into a variable and print out the
FQDN.
If you're thinking "wow, that's not useful" - you're right! This isn't intended
to be a demo of doing useful things with Ansible. It's intended to be a demo of
getting servers on a set of cloud regions across multiple public clouds and
then doing something with them.
Once you can perform a single task on the remote server with Ansible, you can
do anything with Ansible you want to do.

View File

@ -0,0 +1,11 @@
#!/bin/bash
if [ -d ${HOME}/.config/openstack ] ; then
CONFIG_DIR=${HOME}/.config/openstack
else
CONFIG_DIR=/etc/openstack
fi
exec docker run -it --rm --privileged \
-v${PWD}:/demo -v${CONFIG_DIR}:/etc/openstack \
three-minute-demo $*

View File

@ -0,0 +1,3 @@
#!/bin/sh
docker build -t three-minute-demo .

View File

@ -0,0 +1,101 @@
- hosts: localhost
gather_facts: false
tasks:
- name: Read in cloud config
os_client_config:
- name: Add fake host for each cloud region so we can parallelize
add_host:
name: "{{ item.name }}-{{ item.region_name }}"
ansible_host: localhost
ansible_connection: local
groups: clouds
cloud: "{{ item.name }}"
region_name: "{{ item.region_name }}"
with_items: "{{ openstack.clouds }}"
- hosts: clouds
gather_facts: false
tasks:
- name: Upload ssh public key
os_keypair:
public_key_file: "{{ ansible_user_dir }}/.ssh/id_rsa.pub"
name: "three_minute_demo"
cloud: "{{ cloud }}"
region_name: "{{ region_name }}"
- name: Add wide-open security group
os_security_group:
name: three-minute-demo-group
description: Open security group
- name: Add rules to group
os_security_group_rules:
ethertype: "{{ item.ethertype }}"
remote_group: "{{ item.remote_group|default(omit) }}"
remote_ip_prefix: "{{ item.remote_ip_prefix|default(omit) }}"
security_group: three-minute-demo-group
with_items:
- ethertype: IPv4
remote_group: default
state: absent
- ethertype: IPv6
remote_group: default
state: absent
- ethertype: IPv4
remote_ip_prefix: 0.0.0.0/0
- ethertype: IPv6
remote_ip_prefix: ::/0
- name: Create a small VM
os_server:
auto_ip: true
key_name: three_minute_demo
name: three_minute_demo_server
cloud: "{{ cloud }}"
region_name: "{{ region_name }}"
wait: true
register: created_server
- name: Add VM to inventory
add_host:
name: "{{ cloud }}.{{ region_name }}.demo"
ansible_host: "{{ created_server.interface_ip }}"
group: demo_servers
- name: Print Interface IP for created server
debug:
var: created_server.interface_ip
- hosts: demo_servers
tasks:
- name: Install webserver
package:
name: apache2
state: installed
become: yes
- name: Write content
template:
src: templates/setup.json.j2
dest: /var/www/html/setup.json
become: yes
- name: Ensure webserver is running
service:
name: apache2
state: started
become: yes
- name: Get Info from Server
uri:
url: "http://{{ ansible_host }}/setup.json"
register: server_info
delegate_to: localhost
- name: Print FQDN information about host
debug:
var: server_info.json.ansible_fqdn

View File

@ -0,0 +1 @@
localhost

View File

@ -0,0 +1,6 @@
- hosts: localhost
gather_facts: false
roles:
- get-cloud-config
- build-image
- upload-image

View File

@ -0,0 +1,3 @@
distro: debian
image_formats:
- qcow2

View File

@ -0,0 +1,19 @@
- block:
- name: Check for existing image
stat:
path: "{{ distro }}.{{ image_formats[0] }}"
register: image_file
- name: Build image
command: |
disk-image-create -o {{ distro }} -t {{ image_formats | join(',') }} {{ distro }}-minimal simple-init growroot
when: not image_file.stat.exists
- rescue:
- name: Clean up after a build failure
file:
path: "{{ distro }}.{{ item }}"
state: absent
with_items: "{{ image_formats }}"

View File

@ -0,0 +1,6 @@
- name: Grab OpenStack cloud config from clouds.yaml
os_client_config:
- name: Get list of needed image formats
set_fact:
image_formats: "{{ openstack.clouds|json_query('[*].image_format') | unique }}"

View File

@ -0,0 +1,3 @@
distro: debian
image_formats:
- qcow2

View File

@ -0,0 +1,25 @@
# All three are marked no_log because auth info from clouds.yaml is being
# extracted and passed around
- name: Check for existing images
os_image_facts:
cloud: "{{ item.name }}"
region_name: "{{ item.region_name }}"
image: "three-minute-demo-image"
with_items: "{{ openstack.clouds }}"
no_log: true
register: image_records
- name: Get list of clouds without image
set_fact:
clouds_without_image: "{{ image_records.results|json_query('[?ansible_facts.openstack_image==null].item') }}"
no_log: true
- name: Upload image if it's not there
os_image:
cloud: "{{ item.name }}"
region_name: "{{ item.region_name }}"
name: "three-minute-demo-image"
filename: "{{ distro }}.{{ item.image_format }}"
no_log: true
with_items: "{{ clouds_without_image }}"

View File

@ -0,0 +1 @@
{{ hostvars[inventory_hostname]|to_json }}