From 4ac60cf090af9618bd52b4b30cac4ee31b5d5967 Mon Sep 17 00:00:00 2001
From: Monty Taylor <mordred@inaugust.com>
Date: Sun, 5 Nov 2017 13:24:37 +1100
Subject: Add ansible playbooks for 3 minute multi-cloud demo

---
 src/three-minute-demo/Dockerfile                   |  11 +++
 src/three-minute-demo/README.rst                   |  80 ++++++++++++++++
 src/three-minute-demo/ansible-playbook.sh          |  11 +++
 src/three-minute-demo/build-docker-image.sh        |   3 +
 src/three-minute-demo/demo.yaml                    | 101 +++++++++++++++++++++
 src/three-minute-demo/hosts                        |   1 +
 src/three-minute-demo/prep.yaml                    |   6 ++
 .../roles/build-image/defaults/main.yaml           |   3 +
 .../roles/build-image/tasks/main.yaml              |  19 ++++
 .../roles/get-cloud-config/tasks/main.yaml         |   6 ++
 .../roles/upload-image/defaults/main.yaml          |   3 +
 .../roles/upload-image/tasks/main.yaml             |  25 +++++
 src/three-minute-demo/templates/setup.json.j2      |   1 +
 13 files changed, 270 insertions(+)
 create mode 100644 src/three-minute-demo/Dockerfile
 create mode 100644 src/three-minute-demo/README.rst
 create mode 100755 src/three-minute-demo/ansible-playbook.sh
 create mode 100755 src/three-minute-demo/build-docker-image.sh
 create mode 100644 src/three-minute-demo/demo.yaml
 create mode 100644 src/three-minute-demo/hosts
 create mode 100644 src/three-minute-demo/prep.yaml
 create mode 100644 src/three-minute-demo/roles/build-image/defaults/main.yaml
 create mode 100644 src/three-minute-demo/roles/build-image/tasks/main.yaml
 create mode 100644 src/three-minute-demo/roles/get-cloud-config/tasks/main.yaml
 create mode 100644 src/three-minute-demo/roles/upload-image/defaults/main.yaml
 create mode 100644 src/three-minute-demo/roles/upload-image/tasks/main.yaml
 create mode 100644 src/three-minute-demo/templates/setup.json.j2

(limited to 'src/three-minute-demo')

diff --git a/src/three-minute-demo/Dockerfile b/src/three-minute-demo/Dockerfile
new file mode 100644
index 0000000..823c94e
--- /dev/null
+++ b/src/three-minute-demo/Dockerfile
@@ -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"]
diff --git a/src/three-minute-demo/README.rst b/src/three-minute-demo/README.rst
new file mode 100644
index 0000000..1247ea1
--- /dev/null
+++ b/src/three-minute-demo/README.rst
@@ -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.
diff --git a/src/three-minute-demo/ansible-playbook.sh b/src/three-minute-demo/ansible-playbook.sh
new file mode 100755
index 0000000..87c3c18
--- /dev/null
+++ b/src/three-minute-demo/ansible-playbook.sh
@@ -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 $*
diff --git a/src/three-minute-demo/build-docker-image.sh b/src/three-minute-demo/build-docker-image.sh
new file mode 100755
index 0000000..d229241
--- /dev/null
+++ b/src/three-minute-demo/build-docker-image.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+docker build -t three-minute-demo .
diff --git a/src/three-minute-demo/demo.yaml b/src/three-minute-demo/demo.yaml
new file mode 100644
index 0000000..985f265
--- /dev/null
+++ b/src/three-minute-demo/demo.yaml
@@ -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
diff --git a/src/three-minute-demo/hosts b/src/three-minute-demo/hosts
new file mode 100644
index 0000000..2fbb50c
--- /dev/null
+++ b/src/three-minute-demo/hosts
@@ -0,0 +1 @@
+localhost
diff --git a/src/three-minute-demo/prep.yaml b/src/three-minute-demo/prep.yaml
new file mode 100644
index 0000000..412bfd4
--- /dev/null
+++ b/src/three-minute-demo/prep.yaml
@@ -0,0 +1,6 @@
+- hosts: localhost
+  gather_facts: false
+  roles:
+  - get-cloud-config
+  - build-image
+  - upload-image
diff --git a/src/three-minute-demo/roles/build-image/defaults/main.yaml b/src/three-minute-demo/roles/build-image/defaults/main.yaml
new file mode 100644
index 0000000..b6283b8
--- /dev/null
+++ b/src/three-minute-demo/roles/build-image/defaults/main.yaml
@@ -0,0 +1,3 @@
+distro: debian
+image_formats:
+- qcow2
diff --git a/src/three-minute-demo/roles/build-image/tasks/main.yaml b/src/three-minute-demo/roles/build-image/tasks/main.yaml
new file mode 100644
index 0000000..57be287
--- /dev/null
+++ b/src/three-minute-demo/roles/build-image/tasks/main.yaml
@@ -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 }}"
diff --git a/src/three-minute-demo/roles/get-cloud-config/tasks/main.yaml b/src/three-minute-demo/roles/get-cloud-config/tasks/main.yaml
new file mode 100644
index 0000000..e6f5ecd
--- /dev/null
+++ b/src/three-minute-demo/roles/get-cloud-config/tasks/main.yaml
@@ -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 }}"
diff --git a/src/three-minute-demo/roles/upload-image/defaults/main.yaml b/src/three-minute-demo/roles/upload-image/defaults/main.yaml
new file mode 100644
index 0000000..b6283b8
--- /dev/null
+++ b/src/three-minute-demo/roles/upload-image/defaults/main.yaml
@@ -0,0 +1,3 @@
+distro: debian
+image_formats:
+- qcow2
diff --git a/src/three-minute-demo/roles/upload-image/tasks/main.yaml b/src/three-minute-demo/roles/upload-image/tasks/main.yaml
new file mode 100644
index 0000000..c14c7eb
--- /dev/null
+++ b/src/three-minute-demo/roles/upload-image/tasks/main.yaml
@@ -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 }}"
diff --git a/src/three-minute-demo/templates/setup.json.j2 b/src/three-minute-demo/templates/setup.json.j2
new file mode 100644
index 0000000..1f6e6ab
--- /dev/null
+++ b/src/three-minute-demo/templates/setup.json.j2
@@ -0,0 +1 @@
+{{ hostvars[inventory_hostname]|to_json }}
-- 
cgit v1.2.3