From 4ac60cf090af9618bd52b4b30cac4ee31b5d5967 Mon Sep 17 00:00:00 2001 From: Monty Taylor 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 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