From 5cb375645c0b48e4bdc13f94b8ef6b6a1bd91fbc Mon Sep 17 00:00:00 2001
From: Paul Bourke <paul.bourke@oracle.com>
Date: Fri, 7 Apr 2017 12:53:24 +0100
Subject: [PATCH] Add a Kolla 'devstack' mode

Add a new variable 'kolla_devmode', which when enabled, clones and
bindmounts service source code into the containers.

This commit adds the relevant changes for Heat, more services can be
added and built upon.

Usage:
* Set 'kolla_devmode: yes'

* Code is cloned to /opt/stack/{{ project_name }} on target
  node(s)

* Users can develop in these repos, and simply restart the container to
  pick up / test changes.

Debugging can be done from the host via 'remote_pdb'[0].

[0] https://pypi.python.org/pypi/remote-pdb

Implements: blueprint mount-sources
Change-Id: Ic0431b10d723bf84eeefc72039376fe0058dd902
---
 ansible/group_vars/all.yml                    |  4 +
 ansible/roles/destroy/defaults/main.yml       |  1 +
 ansible/roles/destroy/tasks/cleanup_host.yml  |  2 +
 ansible/roles/heat/defaults/main.yml          | 12 +++
 ansible/roles/heat/handlers/main.yml          |  6 +-
 ansible/roles/heat/tasks/clone.yml            |  6 ++
 ansible/roles/heat/tasks/deploy.yml           |  7 ++
 doc/index.rst                                 |  1 +
 doc/kolla-for-openstack-development.rst       | 75 +++++++++++++++++++
 ...penstack-development-e4fa7991c8f4dc77.yaml |  4 +
 tools/cleanup-host                            |  5 ++
 tools/kolla-ansible                           | 18 ++++-
 12 files changed, 134 insertions(+), 7 deletions(-)
 create mode 100644 ansible/roles/heat/tasks/clone.yml
 create mode 100644 doc/kolla-for-openstack-development.rst
 create mode 100644 releasenotes/notes/kolla-for-openstack-development-e4fa7991c8f4dc77.yaml

diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 896eb9de13..ad49b18669 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -43,6 +43,10 @@ kolla_enable_sanity_glance: "{{ kolla_enable_sanity_checks }}"
 kolla_enable_sanity_cinder: "{{ kolla_enable_sanity_checks }}"
 kolla_enable_sanity_swift: "{{ kolla_enable_sanity_checks }}"
 
+kolla_dev_repos_directory: "/opt/stack/"
+kolla_dev_repos_git: "https://git.openstack.org/openstack"
+kolla_dev_repos_pull: "no"
+kolla_dev_mode: "no"
 
 ####################
 # kolla-kubernetes
diff --git a/ansible/roles/destroy/defaults/main.yml b/ansible/roles/destroy/defaults/main.yml
index 3590870d5e..57c9fd5e44 100644
--- a/ansible/roles/destroy/defaults/main.yml
+++ b/ansible/roles/destroy/defaults/main.yml
@@ -1,2 +1,3 @@
 ---
 destroy_include_images: "{{ enable_destroy_images }}"
+destroy_include_dev: "no"
diff --git a/ansible/roles/destroy/tasks/cleanup_host.yml b/ansible/roles/destroy/tasks/cleanup_host.yml
index 38ca03f78a..50bf449505 100644
--- a/ansible/roles/destroy/tasks/cleanup_host.yml
+++ b/ansible/roles/destroy/tasks/cleanup_host.yml
@@ -5,6 +5,8 @@
         enable_swift={{ enable_swift }}
         kolla_internal_vip_address={{ kolla_internal_vip_address }}
         kolla_external_vip_address={{ kolla_external_vip_address }}
+        kolla_dev_repos_directory={{ kolla_dev_repos_directory }}
+        destroy_include_dev={{ destroy_include_dev }}
         /tmp/kolla-cleanup/tools/cleanup-host
 
 - name: Destroying kolla-cleanup folder
diff --git a/ansible/roles/heat/defaults/main.yml b/ansible/roles/heat/defaults/main.yml
index 3c10e92f8d..7178655821 100644
--- a/ansible/roles/heat/defaults/main.yml
+++ b/ansible/roles/heat/defaults/main.yml
@@ -10,6 +10,7 @@ heat_services:
     volumes:
       - "{{ node_config_directory }}/heat-api/:{{ container_config_directory }}/:ro"
       - "/etc/localtime:/etc/localtime:ro"
+      - "{{ kolla_dev_repos_directory ~ '/heat/heat:/var/lib/kolla/venv/lib/python2.7/site-packages/heat' if heat_dev_mode | bool else '' }}"
       - "kolla_logs:/var/log/kolla/"
   heat-api-cfn:
     container_name: heat_api_cfn
@@ -19,6 +20,7 @@ heat_services:
     volumes:
       - "{{ node_config_directory }}/heat-api-cfn/:{{ container_config_directory }}/:ro"
       - "/etc/localtime:/etc/localtime:ro"
+      - "{{ kolla_dev_repos_directory ~ '/heat/heat:/var/lib/kolla/venv/lib/python2.7/site-packages/heat' if heat_dev_mode | bool else '' }}"
       - "kolla_logs:/var/log/kolla/"
   heat-engine:
     container_name: heat_engine
@@ -28,6 +30,7 @@ heat_services:
     volumes:
       - "{{ node_config_directory }}/heat-engine/:{{ container_config_directory }}/:ro"
       - "/etc/localtime:/etc/localtime:ro"
+      - "{{ kolla_dev_repos_directory ~ '/heat/heat:/var/lib/kolla/venv/lib/python2.7/site-packages/heat' if heat_dev_mode | bool else '' }}"
       - "kolla_logs:/var/log/kolla/"
 
 ####################
@@ -56,6 +59,7 @@ heat_engine_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ doc
 heat_engine_tag: "{{ heat_tag }}"
 heat_engine_image_full: "{{ heat_engine_image }}:{{ heat_engine_tag }}"
 
+
 ####################
 # OpenStack
 ####################
@@ -73,3 +77,11 @@ heat_stack_user_role: "heat_stack_user"
 heat_stack_owner_role: "heat_stack_owner"
 
 openstack_heat_auth: "{{ openstack_auth }}"
+
+
+####################
+# Kolla
+####################
+heat_git_repository: "{{ kolla_dev_repos_git }}/{{ project_name }}"
+heat_dev_repos_pull: "{{ kolla_dev_repos_pull }}"
+heat_dev_mode: "{{ kolla_dev_mode }}"
diff --git a/ansible/roles/heat/handlers/main.yml b/ansible/roles/heat/handlers/main.yml
index c85ff2b477..d336500182 100644
--- a/ansible/roles/heat/handlers/main.yml
+++ b/ansible/roles/heat/handlers/main.yml
@@ -12,7 +12,7 @@
     common_options: "{{ docker_common_options }}"
     name: "{{ service.container_name }}"
     image: "{{ service.image }}"
-    volumes: "{{ service.volumes }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
   when:
     - action != "config"
     - inventory_hostname in groups[service.group]
@@ -35,7 +35,7 @@
     common_options: "{{ docker_common_options }}"
     name: "{{ service.container_name }}"
     image: "{{ service.image }}"
-    volumes: "{{ service.volumes }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
   when:
     - action != "config"
     - inventory_hostname in groups[service.group]
@@ -58,7 +58,7 @@
     common_options: "{{ docker_common_options }}"
     name: "{{ service.container_name }}"
     image: "{{ service.image }}"
-    volumes: "{{ service.volumes }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
   when:
     - action != "config"
     - inventory_hostname in groups[service.group]
diff --git a/ansible/roles/heat/tasks/clone.yml b/ansible/roles/heat/tasks/clone.yml
new file mode 100644
index 0000000000..d9ad99bda3
--- /dev/null
+++ b/ansible/roles/heat/tasks/clone.yml
@@ -0,0 +1,6 @@
+---
+- name: Cloning source repositories for development
+  git:
+    repo: "{{ heat_git_repository }}"
+    dest: "{{ kolla_dev_repos_directory }}/{{ project_name }}"
+    update: "{{ heat_dev_repos_pull }}"
diff --git a/ansible/roles/heat/tasks/deploy.yml b/ansible/roles/heat/tasks/deploy.yml
index 2607a81a52..c7df48d3a2 100644
--- a/ansible/roles/heat/tasks/deploy.yml
+++ b/ansible/roles/heat/tasks/deploy.yml
@@ -7,6 +7,13 @@
         inventory_hostname in groups['heat-api-cfn'] or
         inventory_hostname in groups['heat-engine']
 
+- include: clone.yml
+  when:
+    - heat_dev_mode | bool
+    - inventory_hostname in groups['heat-api'] or
+      inventory_hostname in groups['heat-api-cfn'] or
+      inventory_hostname in groups['heat-engine']
+
 - include: bootstrap.yml
   when: inventory_hostname in groups['heat-api']
 
diff --git a/doc/index.rst b/doc/index.rst
index 86f96684fb..44c1a11b92 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -48,6 +48,7 @@ Overview
    advanced-configuration
    operating-kolla
    security
+   kolla-for-openstack-development
    troubleshooting
 
 Services
diff --git a/doc/kolla-for-openstack-development.rst b/doc/kolla-for-openstack-development.rst
new file mode 100644
index 0000000000..5fedac556d
--- /dev/null
+++ b/doc/kolla-for-openstack-development.rst
@@ -0,0 +1,75 @@
+=====================================
+Using Kolla For OpenStack Development
+=====================================
+
+Kolla-ansible can be used to deploy containers in a way suitable for doing
+development on OpenStack services.
+
+.. note::
+
+    This functionality is new in the Pike release.
+
+Heat was the first service to be supported, and so the following will use
+submitting a patch to Heat using Kolla as an example.
+
+Only source containers are supported.
+
+.. WARNING::
+
+   Kolla dev mode is intended for OpenStack hacking/development only. Do not
+   use this in production!
+
+Enabling Kolla "dev mode"
+-------------------------
+
+To enable dev mode for all supported services, set in ``/etc/kolla/globals.yml``:
+
+::
+
+    kolla_dev_mode: true
+
+To enable it just for heat, set:
+
+::
+
+    heat_dev_mode: true
+
+Usage
+-----
+
+When enabled, the source repo for the service in question will be cloned under
+``/opt/stack/`` on the target node(s). This will be bind mounted into the
+container's virtualenv under the location expected by the service on startup.
+
+After making code changes, simply restart the container to pick them up:
+
+::
+
+    docker restart heat_api
+
+Debugging
+---------
+
+``remote_pdb`` can be used to perform debugging with Kolla containers. First,
+make sure it is installed in the container in question:
+
+::
+
+    docker exec -it -u root heat_api pip install remote_pdb
+
+Then, set your breakpoint as follows:
+
+::
+
+    from remote_pdb import RemotePdb
+    RemotePdb('127.0.0.1', 4444).set_trace()
+
+Once you run the code(restart the container), pdb can be accessed using
+``socat``:
+
+::
+
+    socat readline tcp:127.0.0.1:4444
+
+For more information on remote_pdb, see
+https://pypi.python.org/pypi/remote-pdb.
diff --git a/releasenotes/notes/kolla-for-openstack-development-e4fa7991c8f4dc77.yaml b/releasenotes/notes/kolla-for-openstack-development-e4fa7991c8f4dc77.yaml
new file mode 100644
index 0000000000..6ab247152d
--- /dev/null
+++ b/releasenotes/notes/kolla-for-openstack-development-e4fa7991c8f4dc77.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - Add a Kolla 'devstack' mode. See doc/kolla-for-openstack-development.rst
+    for more info.
diff --git a/tools/cleanup-host b/tools/cleanup-host
index cc2aa322ab..bf7584d3cc 100755
--- a/tools/cleanup-host
+++ b/tools/cleanup-host
@@ -63,3 +63,8 @@ for dir in $FOLDER_PATH*; do
         rm -rfv $dir
     fi
 done
+
+if [[ "$destroy_include_dev" == "yes" ]]; then
+    echo "Cleaning up dev repos..."
+    rm -rfv "${kolla_dev_repos_directory}"
+fi
diff --git a/tools/kolla-ansible b/tools/kolla-ansible
index 47bae34a1e..53174cae46 100755
--- a/tools/kolla-ansible
+++ b/tools/kolla-ansible
@@ -51,7 +51,8 @@ Commands:
     mariadb_recovery    Recover a completely stopped mariadb cluster
     bootstrap-servers   bootstrap servers with kolla deploy dependencies
     destroy             Destroy Kolla containers, volumes and host configuration
-                        (--include-images to also destroy Kolla images)
+                            --include-images to also destroy Kolla images
+                            --include-dev to also destroy dev mode repos
     deploy              Deploy and start all kolla containers
     deploy-bifrost      Deploy and start bifrost container
     deploy-servers      Enroll and deploy servers with bifrost
@@ -96,7 +97,7 @@ EOF
 }
 
 SHORT_OPTS="hi:p:t:k:e:v"
-LONG_OPTS="help,inventory:,playbook:,tags:,key:,extra:,verbose,configdir:,passwords:,limit:,yes-i-really-really-mean-it,include-images"
+LONG_OPTS="help,inventory:,playbook:,tags:,key:,extra:,verbose,configdir:,passwords:,limit:,yes-i-really-really-mean-it,include-images,include-dev"
 ARGS=$(getopt -o "${SHORT_OPTS}" -l "${LONG_OPTS}" --name "$0" -- "$@") || { usage >&2; exit 2; }
 
 eval set -- "$ARGS"
@@ -111,8 +112,9 @@ CONFIG_DIR="/etc/kolla"
 PASSWORDS_FILE="${CONFIG_DIR}/passwords.yml"
 DANGER_CONFIRM=
 INCLUDE_IMAGES=
-# Serial is not recommended and disabled by default. User could enable it by
-# simply configuring ANSIBLE_SERIAL variable.
+INCLUDE_DEV=
+# Serial is not recommended and disabled by default. Users can enable it by
+# configuring ANSIBLE_SERIAL variable.
 ANSIBLE_SERIAL=${ANSIBLE_SERIAL:-0}
 
 while [ "$#" -gt 0 ]; do
@@ -153,6 +155,11 @@ while [ "$#" -gt 0 ]; do
             shift 1
             ;;
 
+    (--include-dev)
+            INCLUDE_DEV="$1"
+            shift 1
+            ;;
+
     (--key|-k)
             VAULT_PASS_FILE="$2"
             EXTRA_OPTS="$EXTRA_OPTS --vault-password-file=$VAULT_PASS_FILE"
@@ -211,6 +218,9 @@ case "$1" in
         if [[ "${INCLUDE_IMAGES}" == "--include-images" ]]; then
             EXTRA_OPTS="$EXTRA_OPTS -e destroy_include_images=yes"
         fi
+        if [[ "${INCLUDE_DEV}" == "--include-dev" ]]; then
+            EXTRA_OPTS="$EXTRA_OPTS -e destroy_include_dev=yes"
+        fi
         if [[ "${DANGER_CONFIRM}" != "--yes-i-really-really-mean-it" ]]; then
             cat << EOF
 WARNING: