From 8cc84e132ad1fec3dcf43420e30349f079e53b71 Mon Sep 17 00:00:00 2001
From: Bogdan Dobrelya <bdobrelia@mirantis.com>
Date: Thu, 8 Dec 2016 14:36:00 +0100
Subject: [PATCH] Add tags

Add tags to allow more granular tasks filtering.
Add generator script for MD formatted tags found.
Add docs for tags how-to.

Signed-off-by: Bogdan Dobrelya <bdobrelia@mirantis.com>
---
 docs/ansible.md                               | 60 +++++++++++++++++++
 roles/bootstrap-os/tasks/bootstrap-coreos.yml |  4 +-
 roles/bootstrap-os/tasks/bootstrap-ubuntu.yml |  2 +
 roles/dnsmasq/meta/main.yml                   |  1 +
 roles/dnsmasq/tasks/main.yml                  |  2 +
 roles/docker/tasks/main.yml                   |  4 +-
 roles/docker/tasks/non-systemd.yml            |  7 ++-
 roles/download/tasks/main.yml                 |  3 +
 roles/etcd/meta/main.yml                      |  1 +
 roles/etcd/tasks/configure.yml                |  1 +
 roles/etcd/tasks/gen_certs.yml                |  3 +
 roles/etcd/tasks/main.yml                     |  4 ++
 roles/etcd/tasks/pre_upgrade.yml              |  2 +
 roles/etcd/tasks/set_cluster_health.yml       |  1 +
 roles/kubernetes-apps/ansible/tasks/main.yaml |  4 ++
 .../network_plugin/meta/main.yml              |  1 +
 roles/kubernetes/master/meta/main.yml         |  1 +
 roles/kubernetes/master/tasks/main.yml        | 11 +++-
 roles/kubernetes/master/tasks/pre-upgrade.yml |  4 ++
 roles/kubernetes/node/meta/main.yml           | 11 ++++
 roles/kubernetes/node/tasks/main.yml          | 12 ++--
 roles/kubernetes/preinstall/meta/main.yml     |  1 +
 roles/kubernetes/preinstall/tasks/main.yml    | 24 ++++++++
 roles/kubernetes/secrets/tasks/gen_certs.yml  |  2 +
 roles/kubernetes/secrets/tasks/main.yml       |  5 +-
 roles/network_plugin/calico/meta/main.yml     |  4 ++
 roles/network_plugin/calico/tasks/main.yml    |  9 +++
 roles/network_plugin/canal/meta/main.yml      |  5 ++
 roles/network_plugin/canal/tasks/main.yml     |  2 +
 roles/network_plugin/flannel/meta/main.yml    |  1 +
 roles/network_plugin/flannel/tasks/main.yml   |  7 ++-
 roles/network_plugin/meta/main.yml            |  4 ++
 roles/network_plugin/weave/meta/main.yml      |  1 +
 roles/network_plugin/weave/tasks/main.yml     |  1 +
 scripts/gen_tags.sh                           | 10 ++++
 35 files changed, 205 insertions(+), 10 deletions(-)
 create mode 100644 scripts/gen_tags.sh

diff --git a/docs/ansible.md b/docs/ansible.md
index 101c0a075..513ed0dce 100644
--- a/docs/ansible.md
+++ b/docs/ansible.md
@@ -48,3 +48,63 @@ etcd
 Group vars
 --------------
 The main variables to change are located in the directory ```inventory/group_vars/all.yml```.
+
+Ansible tags
+------------
+
+The following tags are defined in playbooks:
+
+|                 Tag name | Used for
+|--------------------------|---------
+|                     apps | K8s apps definitions
+|                    azure | Cloud-provider Azure
+|             bootstrap-os | Anything related to host OS configuration
+|                   calico | Network plugin Calico
+|                    canal | Network plugin Canal
+|           cloud-provider | Cloud-provider related tasks
+|                  dnsmasq | Configuring DNS stack for hosts and K8s apps
+|                 download | Fetching container images
+|                     etcd | Configuring etcd cluster
+|         etcd-pre-upgrade | Upgrading etcd cluster
+|             etcd-secrets | Configuring etcd certs/keys
+|                 etchosts | Configuring /etc/hosts entries for hosts
+|                    facts | Gathering facts and misc check results
+|                  flannel | Network plugin flannel
+|                      gce | Cloud-provider GCP
+|                hyperkube | Manipulations with K8s hyperkube image
+|          k8s-pre-upgrade | Upgrading K8s cluster
+|              k8s-secrets | Configuring K8s certs/keys
+|                      kpm | Installing K8s apps definitions with KPM
+|           kube-apiserver | Configuring self-hosted kube-apiserver
+|  kube-controller-manager | Configuring self-hosted kube-controller-manager
+|                  kubectl | Installing kubectl and bash completion
+|                  kubelet | Configuring kubelet service
+|               kube-proxy | Configuring self-hosted kube-proxy
+|           kube-scheduler | Configuring self-hosted kube-scheduler
+|                   master | Configuring K8s master node role
+|               netchecker | Installing netchecker K8s app
+|                  network | Configuring networking plugins for K8s
+|                    nginx | Configuring LB for kube-apiserver instances
+|                     node | Configuring K8s minion (compute) node role
+|                openstack | Cloud-provider OpenStack
+|               preinstall | Preliminary configuration steps
+|               resolvconf | Configuring /etc/resolv.conf for hosts/apps
+|                  upgrade | Upgrading, f.e. container images/binaries
+|                    weave | Network plugin Weave
+
+Note: Use the ``bash scripts/gen_tags.sh`` command to generate a list of all
+tags found in the codebase. New tags will be listed with the empty "Used for"
+field.
+
+Example command to filter and apply only DNS configuration tasks and skip
+everything else related to host OS configuration and downloading images of containers:
+
+```
+ansible-playbook -i inventory/inventory.ini cluster.yml  --tags preinstall,dnsmasq,facts --skip-tags=download,bootstrap-os
+```
+And this play only removes the K8s cluster DNS resolver IP from hosts' /etc/resolv.conf files:
+```
+ansible-playbook -i inventory/inventory.ini -e dns_server='' cluster.yml --tags resolvconf
+```
+
+Note: use `--tags` and `--skip-tags` wise and only if you're 100% sure what you're doing.
diff --git a/roles/bootstrap-os/tasks/bootstrap-coreos.yml b/roles/bootstrap-os/tasks/bootstrap-coreos.yml
index a638ad82b..a1a21dad6 100644
--- a/roles/bootstrap-os/tasks/bootstrap-coreos.yml
+++ b/roles/bootstrap-os/tasks/bootstrap-coreos.yml
@@ -3,7 +3,7 @@
   raw: stat /opt/bin/.bootstrapped
   register: need_bootstrap
   ignore_errors: True
-
+  tags: facts
 
 - name: Bootstrap | Run bootstrap.sh
   script: bootstrap.sh
@@ -11,6 +11,7 @@
 
 - set_fact:
     ansible_python_interpreter: "/opt/bin/python"
+  tags: facts
 
 - name: Bootstrap | Check if we need to install pip
   shell: "{{ansible_python_interpreter}} -m pip --version"
@@ -18,6 +19,7 @@
   ignore_errors: True
   changed_when: false
   when: (need_bootstrap | failed)
+  tags: facts
 
 - name: Bootstrap | Copy get-pip.py
   copy: src=get-pip.py dest=~/get-pip.py
diff --git a/roles/bootstrap-os/tasks/bootstrap-ubuntu.yml b/roles/bootstrap-os/tasks/bootstrap-ubuntu.yml
index efd7a768a..19b258790 100644
--- a/roles/bootstrap-os/tasks/bootstrap-ubuntu.yml
+++ b/roles/bootstrap-os/tasks/bootstrap-ubuntu.yml
@@ -5,6 +5,7 @@
   raw: which python
   register: need_bootstrap
   ignore_errors: True
+  tags: facts
 
 - name: Bootstrap | Install python 2.x
   raw: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python-minimal
@@ -12,3 +13,4 @@
 
 - set_fact:
     ansible_python_interpreter: "/usr/bin/python"
+  tags: facts
diff --git a/roles/dnsmasq/meta/main.yml b/roles/dnsmasq/meta/main.yml
index 7a1c8ca17..240fbab9e 100644
--- a/roles/dnsmasq/meta/main.yml
+++ b/roles/dnsmasq/meta/main.yml
@@ -3,3 +3,4 @@ dependencies:
   - role: download
     file: "{{ downloads.dnsmasq }}"
     when: not skip_dnsmasq|default(false) and download_localhost|default(false)
+    tags: [download, dnsmasq]
diff --git a/roles/dnsmasq/tasks/main.yml b/roles/dnsmasq/tasks/main.yml
index 6b271a1e2..c82e83218 100644
--- a/roles/dnsmasq/tasks/main.yml
+++ b/roles/dnsmasq/tasks/main.yml
@@ -1,5 +1,7 @@
 ---
 - include: dnsmasq.yml
   when: "{{ not skip_dnsmasq_k8s|bool }}"
+  tags: dnsmasq
 
 - include: resolvconf.yml
+  tags: resolvconf
diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml
index c3bd842f3..b7485c3d6 100644
--- a/roles/docker/tasks/main.yml
+++ b/roles/docker/tasks/main.yml
@@ -12,6 +12,7 @@
       paths:
       - ../vars
       skip: true
+  tags: facts
 
 - name: check for minimum kernel version
   fail:
@@ -20,6 +21,7 @@
           {{ docker_kernel_min_version }} on
           {{ ansible_distribution }}-{{ ansible_distribution_version }}
   when: (ansible_os_family != "CoreOS") and (ansible_kernel|version_compare(docker_kernel_min_version, "<"))
+  tags: facts
 
 - name: ensure docker repository public key is installed
   action: "{{ docker_repo_key_info.pkg_key }}"
@@ -76,4 +78,4 @@
     enabled: yes
     state: started
   with_items:
-    - docker
\ No newline at end of file
+    - docker
diff --git a/roles/docker/tasks/non-systemd.yml b/roles/docker/tasks/non-systemd.yml
index 48139e625..ea8c8e97a 100644
--- a/roles/docker/tasks/non-systemd.yml
+++ b/roles/docker/tasks/non-systemd.yml
@@ -4,19 +4,23 @@
   set_fact:
     docker_options_file: >-
       {%- if ansible_os_family == "Debian" -%}/etc/default/docker{%- elif ansible_os_family == "RedHat" -%}/etc/sysconfig/docker{%- endif -%}
+  tags: facts
 
 - name: Set docker options config variable name
   set_fact:
     docker_options_name: >-
       {%- if ansible_os_family == "Debian" -%}DOCKER_OPTS{%- elif ansible_os_family == "RedHat" -%}other_args{%- endif -%}
+  tags: facts
 
 - name: Set docker options config value to be written
   set_fact:
     docker_options_value: '"{{ docker_options }} $DOCKER_NETWORK_OPTIONS $DOCKER_STORAGE_OPTIONS $INSECURE_REGISTRY"'
+  tags: facts
 
 - name: Set docker options config line to be written
   set_fact:
     docker_options_line: "{{ docker_options_name }}={{ docker_options_value }}"
+  tags: facts
 
 - name: Set docker proxy lines to be written
   set_fact:
@@ -24,6 +28,7 @@
      - { name: "HTTP_PROXY", value: '"{{ http_proxy }}"' }
      - { name: "HTTPS_PROXY", value: '"{{ https_proxy }}"' }
      - { name: "NO_PROXY", value: '"{{ no_proxy }}"' }
+  tags: facts
 
 - name: Remove docker daemon proxy config lines that don't match desired lines
   lineinfile:
@@ -58,4 +63,4 @@
     mode: 0644
   notify: restart docker
 
-- meta: flush_handlers
\ No newline at end of file
+- meta: flush_handlers
diff --git a/roles/download/tasks/main.yml b/roles/download/tasks/main.yml
index 0dc2d5daa..a7e8c7201 100644
--- a/roles/download/tasks/main.yml
+++ b/roles/download/tasks/main.yml
@@ -45,6 +45,7 @@
 
 - set_fact:
     download_delegate: "{% if download_localhost %}localhost{% else %}{{groups['kube-master'][0]}}{% endif %}"
+  tags: facts
 
 - name: Create dest directory for saved/loaded container images
   file: path="{{local_release_dir}}/containers" state=directory recurse=yes mode=0755 owner={{ansible_ssh_user|default(ansible_user_id)}}
@@ -78,6 +79,7 @@
 
 - set_fact:
     fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|regex_replace('/|\0|:', '_')}}.tar"
+  tags: facts
 
 - name: "Set default value for 'container_changed' to false"
   set_fact:
@@ -89,6 +91,7 @@
   when: "{{ download.enabled|bool and download.container|bool }}"
   delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
   run_once: "{{ download_run_once|bool }}"
+  tags: facts
 
 - name: Stat saved container image
   stat: path="{{fname}}"
diff --git a/roles/etcd/meta/main.yml b/roles/etcd/meta/main.yml
index b55966a99..c8a1c8c34 100644
--- a/roles/etcd/meta/main.yml
+++ b/roles/etcd/meta/main.yml
@@ -7,3 +7,4 @@ dependencies:
     when: (ansible_os_family != "CoreOS" and etcd_deployment_type == "docker" or inventory_hostname in groups['k8s-cluster'])
   - role: download
     file: "{{ downloads.etcd }}"
+    tags: download
diff --git a/roles/etcd/tasks/configure.yml b/roles/etcd/tasks/configure.yml
index a2ef38f2c..21141c8b4 100644
--- a/roles/etcd/tasks/configure.yml
+++ b/roles/etcd/tasks/configure.yml
@@ -5,6 +5,7 @@
   ignore_errors: true
   changed_when: false
   when: is_etcd_master
+  tags: facts
 
 - name: Configure | Add member to the cluster if it is not there
   when: is_etcd_master and etcd_member_in_cluster.rc != 0 and etcd_cluster_is_healthy.rc == 0
diff --git a/roles/etcd/tasks/gen_certs.yml b/roles/etcd/tasks/gen_certs.yml
index 8d1d34b74..a12c63ac8 100644
--- a/roles/etcd/tasks/gen_certs.yml
+++ b/roles/etcd/tasks/gen_certs.yml
@@ -42,6 +42,7 @@
 - set_fact:
     master_certs: ['ca-key.pem', 'admin.pem', 'admin-key.pem', 'member.pem', 'member-key.pem']
     node_certs: ['ca.pem', 'node.pem', 'node-key.pem']
+  tags: facts
 
 - name: Gen_certs | Gather etcd master certs
   shell: "tar cfz - -C {{ etcd_cert_dir }} {{ master_certs|join(' ') }} {{ node_certs|join(' ') }}| base64 --wrap=0"
@@ -78,6 +79,7 @@
     state=directory
     owner=kube
     recurse=yes
+  tags: facts
 
 - name: Gen_certs | set permissions on keys
   shell: chmod 0600 {{ etcd_cert_dir}}/*key.pem
@@ -94,6 +96,7 @@
       {%- elif ansible_os_family == "CoreOS" -%}
       /etc/ssl/certs/etcd-ca.pem
       {%- endif %}
+  tags: facts
 
 - name: Gen_certs | add CA to trusted CA dir
   copy:
diff --git a/roles/etcd/tasks/main.yml b/roles/etcd/tasks/main.yml
index 15be1a769..5b25a8392 100644
--- a/roles/etcd/tasks/main.yml
+++ b/roles/etcd/tasks/main.yml
@@ -1,9 +1,13 @@
 ---
 - include: pre_upgrade.yml
+  tags: etcd-pre-upgrade
 - include: check_certs.yml
+  tags: [etcd-secrets, facts]
 - include: gen_certs.yml
+  tags: etcd-secrets
 - include: install.yml
   when: is_etcd_master
+  tags: upgrade
 - include: set_cluster_health.yml
   when: is_etcd_master
 - include: configure.yml
diff --git a/roles/etcd/tasks/pre_upgrade.yml b/roles/etcd/tasks/pre_upgrade.yml
index d1962ea92..adaff581f 100644
--- a/roles/etcd/tasks/pre_upgrade.yml
+++ b/roles/etcd/tasks/pre_upgrade.yml
@@ -2,11 +2,13 @@
   stat:
     path: /etc/systemd/system/etcd-proxy.service
   register: kube_apiserver_service_file
+  tags: facts
 
 - name: "Pre-upgrade | check for etcd-proxy init script"
   stat:
     path: /etc/init.d/etcd-proxy
   register: kube_apiserver_init_script
+  tags: facts
 
 - name: "Pre-upgrade | stop etcd-proxy if service defined"
   service:
diff --git a/roles/etcd/tasks/set_cluster_health.yml b/roles/etcd/tasks/set_cluster_health.yml
index 1a27e4dcf..8ea7ae9fa 100644
--- a/roles/etcd/tasks/set_cluster_health.yml
+++ b/roles/etcd/tasks/set_cluster_health.yml
@@ -5,3 +5,4 @@
   ignore_errors: true
   changed_when: false
   when: is_etcd_master
+  tags: facts
diff --git a/roles/kubernetes-apps/ansible/tasks/main.yaml b/roles/kubernetes-apps/ansible/tasks/main.yaml
index a65b6b527..2977772c3 100644
--- a/roles/kubernetes-apps/ansible/tasks/main.yaml
+++ b/roles/kubernetes-apps/ansible/tasks/main.yaml
@@ -6,6 +6,7 @@
     - {file: kubedns-svc.yml, type: svc}
   register: manifests
   when: inventory_hostname == groups['kube-master'][0]
+  tags: dnsmasq
 
 - name: Kubernetes Apps | Start Resources
   kube:
@@ -17,11 +18,14 @@
     state: "{{item.changed | ternary('latest','present') }}"
   with_items: "{{ manifests.results }}"
   when: inventory_hostname == groups['kube-master'][0]
+  tags: dnsmasq
 
 - include: tasks/calico-policy-controller.yml
   when: ( enable_network_policy is defined and enable_network_policy == True ) or
     ( kube_network_plugin == 'canal' )
+  tags: [network, canal]
 
 - name: Kubernetes Apps | Netchecker
   include: tasks/netchecker.yml
   when: deploy_netchecker
+  tags: netchecker
diff --git a/roles/kubernetes-apps/network_plugin/meta/main.yml b/roles/kubernetes-apps/network_plugin/meta/main.yml
index 14a59e5c5..1024e63a8 100644
--- a/roles/kubernetes-apps/network_plugin/meta/main.yml
+++ b/roles/kubernetes-apps/network_plugin/meta/main.yml
@@ -2,3 +2,4 @@
 dependencies:
  - role: kubernetes-apps/network_plugin/canal
    when: kube_network_plugin == 'canal'
+   tags: canal
diff --git a/roles/kubernetes/master/meta/main.yml b/roles/kubernetes/master/meta/main.yml
index f4da42e39..3ce338939 100644
--- a/roles/kubernetes/master/meta/main.yml
+++ b/roles/kubernetes/master/meta/main.yml
@@ -2,3 +2,4 @@
 dependencies:
   - role: download
     file: "{{ downloads.hyperkube }}"
+    tags: [download, hyperkube]
diff --git a/roles/kubernetes/master/tasks/main.yml b/roles/kubernetes/master/tasks/main.yml
index 4dd748bcd..8e3353a21 100644
--- a/roles/kubernetes/master/tasks/main.yml
+++ b/roles/kubernetes/master/tasks/main.yml
@@ -1,6 +1,6 @@
 ---
 - include: pre-upgrade.yml
-
+  tags: k8s-pre-upgrade
 
 - name: Copy kubectl from hyperkube container
   command: "/usr/bin/docker run --rm -v {{ bin_dir }}:/systembindir {{ hyperkube_image_repo }}:{{ hyperkube_image_tag }} /bin/cp /hyperkube /systembindir/kubectl"
@@ -9,12 +9,14 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
+  tags: [hyperkube, kubectl, upgrade]
 
 - name: Gather kubectl bash completion
   command: "{{ bin_dir }}/kubectl completion bash"
   no_log: true
   register: kubectl_bash_completion
   when: ansible_os_family in ["Debian","RedHat"]
+  tags: kubectl
 
 - name: Write kubectl bash completion
   copy:
@@ -24,12 +26,14 @@
     group: root
     mode: 0755
   when: ansible_os_family in ["Debian","RedHat"] and kubectl_bash_completion.changed
+  tags: [kubectl, upgrade]
 
 - name: Write kube-apiserver manifest
   template:
     src: manifests/kube-apiserver.manifest.j2
     dest: "{{ kube_manifest_dir }}/kube-apiserver.manifest"
   notify: Master | wait for the apiserver to be running
+  tags: kube-apiserver
 
 - meta: flush_handlers
 # Create kube-system namespace
@@ -37,6 +41,7 @@
   copy: src=namespace.yml dest=/etc/kubernetes/kube-system-ns.yml
   run_once: yes
   when: inventory_hostname == groups['kube-master'][0]
+  tags: apps
 
 - name: Check if kube-system exists
   command: "{{ bin_dir }}/kubectl get ns kube-system"
@@ -44,11 +49,13 @@
   changed_when: False
   failed_when: False
   run_once: yes
+  tags: apps
 
 - name: Create 'kube-system' namespace
   command: "{{ bin_dir }}/kubectl create -f /etc/kubernetes/kube-system-ns.yml"
   changed_when: False
   when: kubesystem|failed and inventory_hostname == groups['kube-master'][0]
+  tags: apps
 
 # Write other manifests
 - name: Write kube-controller-manager manifest
@@ -56,9 +63,11 @@
     src: manifests/kube-controller-manager.manifest.j2
     dest: "{{ kube_manifest_dir }}/kube-controller-manager.manifest"
   notify: Master | wait for kube-controller-manager
+  tags: kube-controller-manager
 
 - name: Write kube-scheduler manifest
   template:
     src: manifests/kube-scheduler.manifest.j2
     dest: "{{ kube_manifest_dir }}/kube-scheduler.manifest"
   notify: Master | wait for kube-scheduler
+  tags: kube-scheduler
diff --git a/roles/kubernetes/master/tasks/pre-upgrade.yml b/roles/kubernetes/master/tasks/pre-upgrade.yml
index 3b9f26de1..cf7d2bea9 100644
--- a/roles/kubernetes/master/tasks/pre-upgrade.yml
+++ b/roles/kubernetes/master/tasks/pre-upgrade.yml
@@ -3,17 +3,20 @@
   stat:
     path: /etc/systemd/system/kube-apiserver.service
   register: kube_apiserver_service_file
+  tags: [facts, kube-apiserver]
 
 - name: "Pre-upgrade | check for kube-apiserver init script"
   stat:
     path: /etc/init.d/kube-apiserver
   register: kube_apiserver_init_script
+  tags: [facts, kube-apiserver]
 
 - name: "Pre-upgrade | stop kube-apiserver if service defined"
   service:
     name: kube-apiserver
     state: stopped
   when: (kube_apiserver_service_file.stat.exists|default(False) or kube_apiserver_init_script.stat.exists|default(False))
+  tags: kube-apiserver
 
 - name: "Pre-upgrade | remove kube-apiserver service definition"
   file:
@@ -23,3 +26,4 @@
   with_items:
     - /etc/systemd/system/kube-apiserver.service
     - /etc/init.d/kube-apiserver
+  tags: kube-apiserver
diff --git a/roles/kubernetes/node/meta/main.yml b/roles/kubernetes/node/meta/main.yml
index a65501113..8959ebe20 100644
--- a/roles/kubernetes/node/meta/main.yml
+++ b/roles/kubernetes/node/meta/main.yml
@@ -2,28 +2,39 @@
 dependencies:
   - role: download
     file: "{{ downloads.hyperkube }}"
+    tags: [download, hyperkube, kubelet, network, canal, calico, weave, kube-controller-manager, kube-scheduler, kube-apiserver, kube-proxy, kubectl]
   - role: download
     file: "{{ downloads.pod_infra }}"
+    tags: [download, kubelet]
   - role: kubernetes/secrets
+    tags: k8s-secrets
   - role: download
     file: "{{ downloads.nginx }}"
+    tags: [download, nginx]
   - role: download
     file: "{{ downloads.testbox }}"
+    tags: download
   - role: download
     file: "{{ downloads.netcheck_server }}"
     when: deploy_netchecker
+    tags: [download, netchecker]
   - role: download
     file: "{{ downloads.netcheck_agent }}"
     when: deploy_netchecker
+    tags: [download, netchecker]
   - role: download
     file: "{{ downloads.netcheck_kubectl }}"
     when: deploy_netchecker
+    tags: [download, netchecker]
   - role: download
     file: "{{ downloads.kubednsmasq }}"
     when: not skip_dnsmasq_k8s|default(false)
+    tags: [download, dnsmasq]
   - role: download
     file: "{{ downloads.kubedns }}"
     when: not skip_dnsmasq_k8s|default(false)
+    tags: [download, dnsmasq]
   - role: download
     file: "{{ downloads.exechealthz }}"
     when: not skip_dnsmasq_k8s|default(false)
+    tags: [download, dnsmasq]
diff --git a/roles/kubernetes/node/tasks/main.yml b/roles/kubernetes/node/tasks/main.yml
index 0680798d3..67cc4ca86 100644
--- a/roles/kubernetes/node/tasks/main.yml
+++ b/roles/kubernetes/node/tasks/main.yml
@@ -1,23 +1,26 @@
 ---
 - include: install.yml
+  tags: kubelet
 
 - include: nginx-proxy.yml
   when: is_kube_master == false and loadbalancer_apiserver_localhost|default(false)
+  tags: nginx
 
 - name: Write kubelet config file
   template: src=kubelet.j2 dest={{ kube_config_dir }}/kubelet.env backup=yes
-  notify:
-    - restart kubelet
+  notify: restart kubelet
+  tags: kubelet
 
 - name: write the kubecfg (auth) file for kubelet
   template: src=node-kubeconfig.yaml.j2 dest={{ kube_config_dir }}/node-kubeconfig.yaml backup=yes
-  notify:
-    - restart kubelet
+  notify: restart kubelet
+  tags: kubelet
 
 - name: Write proxy manifest
   template:
     src: manifests/kube-proxy.manifest.j2
     dest: "{{ kube_manifest_dir }}/kube-proxy.manifest"
+  tags: kube-proxy
 
 # reload-systemd
 - meta: flush_handlers
@@ -27,3 +30,4 @@
     name: kubelet
     enabled: yes
     state: started
+  tags: kubelet
diff --git a/roles/kubernetes/preinstall/meta/main.yml b/roles/kubernetes/preinstall/meta/main.yml
index a98862cf6..cf440f5e2 100644
--- a/roles/kubernetes/preinstall/meta/main.yml
+++ b/roles/kubernetes/preinstall/meta/main.yml
@@ -2,3 +2,4 @@
 dependencies:
   - role: adduser
     user: "{{ addusers.kube }}"
+    tags: kubelet
diff --git a/roles/kubernetes/preinstall/tasks/main.yml b/roles/kubernetes/preinstall/tasks/main.yml
index 901544ac2..07dc53fec 100644
--- a/roles/kubernetes/preinstall/tasks/main.yml
+++ b/roles/kubernetes/preinstall/tasks/main.yml
@@ -3,6 +3,7 @@
   set_fact:
     bin_dir: "/opt/bin"
   when: ansible_os_family == "CoreOS"
+  tags: facts
 
 - name: check bin dir exists
   file:
@@ -10,11 +11,14 @@
     state: directory
     owner: root
   become: true
+  tags: bootstrap-os
 
 - include: gitinfos.yml
   when: run_gitinfos
+  tags: facts
 
 - include: set_facts.yml
+  tags: facts
 
 - name: gather os specific variables
   include_vars: "{{ item }}"
@@ -29,6 +33,7 @@
       paths:
       - ../vars
       skip: true
+  tags: facts
 
 - name: Create kubernetes config directory
   file:
@@ -36,6 +41,7 @@
     state: directory
     owner: kube
   when: "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  tags: [kubelet, k8s-secrets, kube-controller-manager, kube-apiserver, bootstrap-os, apps, network, master, node]
 
 - name: Create kubernetes script directory
   file:
@@ -43,6 +49,7 @@
     state: directory
     owner: kube
   when: "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  tags: [k8s-secrets, bootstrap-os]
 
 - name: Create kubernetes manifests directory
   file:
@@ -50,6 +57,7 @@
     state: directory
     owner: kube
   when: "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  tags: [kubelet, bootstrap-os, master, node]
 
 - name: Create kubernetes logs directory
   file:
@@ -57,17 +65,21 @@
     state: directory
     owner: kube
   when: ansible_service_mgr in ["sysvinit","upstart"] and "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  tags: [bootstrap-os, master, node]
 
 - name: check cloud_provider value
   fail:
     msg: "If set the 'cloud_provider' var must be set either to 'generic', 'gce', 'aws', 'azure' or 'openstack'"
   when: cloud_provider is defined and cloud_provider not in ['generic', 'gce', 'aws', 'openstack', 'azure']
+  tags: [cloud-provider, facts]
 
 - include: openstack-credential-check.yml
   when: cloud_provider is defined and cloud_provider == 'openstack'
+  tags: [cloud-provider, openstack, facts]
 
 - include: azure-credential-check.yml
   when: cloud_provider is defined and cloud_provider == 'azure'
+  tags: [cloud-provider, azure, facts]
 
 - name: Fix ipv4 forward rule in GCE security policy
   lineinfile:
@@ -79,6 +91,7 @@
     backup: yes
     validate: 'sysctl -f %s'
   when: cloud_provider is defined and cloud_provider == 'gce'
+  tags: [cloud-provider, gce, bootstrap-os]
 
 - name: Create cni directories
   file:
@@ -89,26 +102,31 @@
     - "/etc/cni/net.d"
     - "/opt/cni/bin"
   when: kube_network_plugin in ["calico", "weave", "canal"] and "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  tags: [network, calico, weave, canal, bootstrap-os]
 
 - name: Update package management cache (YUM)
   yum: update_cache=yes name='*'
   when: ansible_pkg_mgr == 'yum'
+  tags: bootstrap-os
 
 - name: Install latest version of python-apt for Debian distribs
   apt: name=python-apt state=latest update_cache=yes cache_valid_time=3600
   when: ansible_os_family == "Debian"
+  tags: bootstrap-os
 
 - name: Install python-dnf for latest RedHat versions
   command: dnf install -y python-dnf yum
   when: ansible_distribution == "Fedora" and
         ansible_distribution_major_version > 21
   changed_when: False
+  tags: bootstrap-os
 
 - name: Install epel-release on RedHat/CentOS
   shell: rpm -qa | grep epel-release || rpm -ivh {{ epel_rpm_download_url }}
   when: ansible_distribution in ["CentOS","RedHat"] and
         ansible_distribution_major_version >= 7
   changed_when: False
+  tags: bootstrap-os
 
 - name: Install packages requirements
   action:
@@ -121,6 +139,7 @@
   delay: "{{ retry_stagger | random + 3 }}"
   with_items: "{{required_pkgs | default([]) | union(common_required_pkgs|default([]))}}"
   when: ansible_os_family != "CoreOS"
+  tags: bootstrap-os
 
 - name: Disable IPv6 DNS lookup
   lineinfile:
@@ -129,12 +148,14 @@
     state: present
     backup: yes
   when: disable_ipv6_dns and ansible_os_family != "CoreOS"
+  tags: bootstrap-os
 
 # Todo : selinux configuration
 - name: Set selinux policy to permissive
   selinux: policy=targeted state=permissive
   when: ansible_os_family == "RedHat"
   changed_when: False
+  tags: bootstrap-os
 
 - name: Write openstack cloud-config
   template:
@@ -143,6 +164,7 @@
     group: "{{ kube_cert_group }}"
     mode: 0640
   when: cloud_provider is defined and cloud_provider == "openstack"
+  tags: [cloud-provider, openstack]
 
 - name: Write azure cloud-config
   template:
@@ -151,5 +173,7 @@
     group: "{{ kube_cert_group }}"
     mode: 0640
   when: cloud_provider is defined and cloud_provider == "azure"
+  tags: [cloud-provider, azure]
 
 - include: etchosts.yml
+  tags: [bootstrap-os, etchosts]
diff --git a/roles/kubernetes/secrets/tasks/gen_certs.yml b/roles/kubernetes/secrets/tasks/gen_certs.yml
index 28ae04892..ace2a3ba4 100644
--- a/roles/kubernetes/secrets/tasks/gen_certs.yml
+++ b/roles/kubernetes/secrets/tasks/gen_certs.yml
@@ -26,6 +26,7 @@
 - set_fact:
     master_certs: ['ca-key.pem', 'admin.pem', 'admin-key.pem', 'apiserver-key.pem', 'apiserver.pem']
     node_certs: ['ca.pem', 'node.pem', 'node-key.pem']
+  tags: facts
 
 - name: Gen_certs | Gather master certs
   shell: "tar cfz - -C {{ kube_cert_dir }} {{ master_certs|join(' ') }} {{ node_certs|join(' ') }} | base64 --wrap=0"
@@ -75,6 +76,7 @@
       {%- elif ansible_os_family == "CoreOS" -%}
       /etc/ssl/certs/kube-ca.pem
       {%- endif %}
+  tags: facts
 
 - name: Gen_certs | add CA to trusted CA dir
   copy:
diff --git a/roles/kubernetes/secrets/tasks/main.yml b/roles/kubernetes/secrets/tasks/main.yml
index 6837f4853..4dc6f8c30 100644
--- a/roles/kubernetes/secrets/tasks/main.yml
+++ b/roles/kubernetes/secrets/tasks/main.yml
@@ -1,6 +1,8 @@
 ---
 - include: check-certs.yml
+  tags: [k8s-secrets, facts]
 - include: check-tokens.yml
+  tags: [k8s-secrets, facts]
 
 - name: Make sure the certificate directory exits
   file:
@@ -34,5 +36,6 @@
   notify: set secret_changed
 
 - include: gen_certs.yml
-
+  tags: k8s-secrets
 - include: gen_tokens.yml
+  tags: k8s-secrets
diff --git a/roles/network_plugin/calico/meta/main.yml b/roles/network_plugin/calico/meta/main.yml
index 37d659c9e..fdd4e8483 100644
--- a/roles/network_plugin/calico/meta/main.yml
+++ b/roles/network_plugin/calico/meta/main.yml
@@ -2,9 +2,13 @@
 dependencies:
   - role: download
     file: "{{ downloads.calico_cni }}"
+    tags: download
   - role: download
     file: "{{ downloads.calico_node }}"
+    tags: download
   - role: download
     file: "{{ downloads.calicoctl }}"
+    tags: download
   - role: download
     file: "{{ downloads.hyperkube }}"
+    tags: download
diff --git a/roles/network_plugin/calico/tasks/main.yml b/roles/network_plugin/calico/tasks/main.yml
index 46c7f703b..0480354e8 100644
--- a/roles/network_plugin/calico/tasks/main.yml
+++ b/roles/network_plugin/calico/tasks/main.yml
@@ -3,6 +3,7 @@
   run_once: true
   set_fact:
     legacy_calicoctl: "{{ calicoctl_image_tag | version_compare('v1.0.0', '<') }}"
+  tags: facts
 
 - name: Calico | Write Calico cni config
   template:
@@ -46,6 +47,7 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
+  tags: [hyperkube, upgrade]
 
 - name: Calico | Copy cni plugins from calico/cni container
   command: "/usr/bin/docker run --rm -v /opt/cni/bin:/cnibindir {{ calico_cni_image_repo }}:{{ calico_cni_image_tag }} sh -c 'cp -a /opt/cni/bin/* /cnibindir/'"
@@ -55,6 +57,7 @@
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
   when: "{{ overwrite_hyperkube_cni|bool }}"
+  tags: [hyperkube, upgrade]
 
 - name: Calico | wait for etcd
   uri: url=https://localhost:2379/health validate_certs=no
@@ -75,6 +78,7 @@
   register: calico_conf
   delegate_to: "{{groups['etcd'][0]}}"
   run_once: true
+  tags: facts
 
 - name: Calico | Configure calico network pool
   shell: >
@@ -98,6 +102,7 @@
     ipip_arg: "--ipip"
   when: (legacy_calicoctl and
          cloud_provider is defined or ipip)
+  tags: facts
 
 - name: Calico (old) | Define nat-outgoing pool argument
   run_once: true
@@ -105,12 +110,14 @@
     nat_arg: "--nat-outgoing"
   when: (legacy_calicoctl and
          nat_outgoing|default(false) and not peer_with_router|default(false))
+  tags: facts
 
 - name: Calico (old) | Define calico pool task name
   run_once: true
   set_fact:
     pool_task_name: "with options {{ ipip_arg|default('') }} {{ nat_arg|default('') }}"
   when: (legacy_calicoctl and ipip_arg|default(false) or nat_arg|default(false))
+  tags: facts
 
 - name: Calico (old) | Configure calico network pool {{ pool_task_name|default('') }}
   command: "{{ bin_dir}}/calicoctl pool add {{ kube_pods_subnet }} {{ ipip_arg|default('') }} {{ nat_arg|default('') }}"
@@ -134,6 +141,7 @@
 - set_fact:
     calico_pools: "{{ calico_pools_raw.stdout | from_json }}"
   run_once: true
+  tags: facts
 
 - name: Calico | Check if calico pool is properly configured
   fail:
@@ -142,6 +150,7 @@
   when: ( calico_pools['node']['nodes'] | length > 1 ) or
         ( not calico_pools['node']['nodes'][0]['key'] | search(".*{{ kube_pods_subnet | ipaddr('network') }}.*") )
   run_once: true
+  tags: facts
 
 - name: Calico | Write /etc/network-environment
   template: src=network-environment.j2 dest=/etc/network-environment
diff --git a/roles/network_plugin/canal/meta/main.yml b/roles/network_plugin/canal/meta/main.yml
index d7bac0bc9..3d67dad5c 100644
--- a/roles/network_plugin/canal/meta/main.yml
+++ b/roles/network_plugin/canal/meta/main.yml
@@ -2,11 +2,16 @@
 dependencies:
   - role: download
     file: "{{ downloads.flannel }}"
+    tags: download
   - role: download
     file: "{{ downloads.calico_node }}"
+    tags: download
   - role: download
     file: "{{ downloads.calicoctl }}"
+    tags: download
   - role: download
     file: "{{ downloads.calico_cni }}"
+    tags: download
   - role: download
     file: "{{ downloads.calico_policy }}"
+    tags: download
diff --git a/roles/network_plugin/canal/tasks/main.yml b/roles/network_plugin/canal/tasks/main.yml
index 83f398a54..15ce2f657 100644
--- a/roles/network_plugin/canal/tasks/main.yml
+++ b/roles/network_plugin/canal/tasks/main.yml
@@ -49,6 +49,7 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
+  tags: [hyperkube, upgrade]
 
 - name: Canal | Copy cni plugins from calico/cni
   command: "/usr/bin/docker run --rm -v /opt/cni/bin:/cnibindir {{ calico_cni_image_repo }}:{{ calico_cni_image_tag }} sh -c 'cp -a /opt/cni/bin/* /cnibindir/'"
@@ -57,3 +58,4 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
+  tags: [hyperkube, upgrade]
diff --git a/roles/network_plugin/flannel/meta/main.yml b/roles/network_plugin/flannel/meta/main.yml
index 0edfe9aec..4a2caef72 100644
--- a/roles/network_plugin/flannel/meta/main.yml
+++ b/roles/network_plugin/flannel/meta/main.yml
@@ -2,3 +2,4 @@
 dependencies:
   - role: download
     file: "{{ downloads.flannel }}"
+    tags: download
diff --git a/roles/network_plugin/flannel/tasks/main.yml b/roles/network_plugin/flannel/tasks/main.yml
index ebb2b693d..3e5eff8e8 100644
--- a/roles/network_plugin/flannel/tasks/main.yml
+++ b/roles/network_plugin/flannel/tasks/main.yml
@@ -26,6 +26,7 @@
 
 - set_fact:
     flannel_subnet: "{{ flannel_subnet_output.stdout }}"
+  tags: facts
 
 - name: Flannel | Get flannel_mtu from subnet.env
   shell: cat /run/flannel/subnet.env | awk -F'=' '$1 == "FLANNEL_MTU" {print $2}'
@@ -34,17 +35,21 @@
 
 - set_fact:
     flannel_mtu: "{{ flannel_mtu_output.stdout }}"
+  tags: facts
 
 - set_fact:
     docker_options_file: >-
       {%- if ansible_os_family == "Debian" -%}/etc/default/docker{%- elif ansible_os_family == "RedHat" -%}/etc/sysconfig/docker{%- endif -%}
+  tags: facts
 
 - set_fact:
     docker_options_name: >-
       {%- if ansible_os_family == "Debian" -%}DOCKER_OPTS{%- elif ansible_os_family == "RedHat" -%}other_args{%- endif -%}
+  tags: facts
 
 - set_fact:
     docker_network_options: '"--bip={{ flannel_subnet }} --mtu={{ flannel_mtu }}"'
+  tags: facts
 
 - name: Flannel | Remove non-systemd docker daemon network options that don't match desired line
   lineinfile:
@@ -73,4 +78,4 @@
     - restart docker
   when: ansible_service_mgr == "systemd"
 
-- meta: flush_handlers
\ No newline at end of file
+- meta: flush_handlers
diff --git a/roles/network_plugin/meta/main.yml b/roles/network_plugin/meta/main.yml
index 8596c9d70..a964a4cba 100644
--- a/roles/network_plugin/meta/main.yml
+++ b/roles/network_plugin/meta/main.yml
@@ -2,9 +2,13 @@
 dependencies:
  - role: network_plugin/calico
    when: kube_network_plugin == 'calico'
+   tags: calico
  - role: network_plugin/flannel
    when: kube_network_plugin == 'flannel'
+   tags: flannel
  - role: network_plugin/weave
    when: kube_network_plugin == 'weave'
+   tags: weave
  - role: network_plugin/canal
    when: kube_network_plugin == 'canal'
+   tags: canal
diff --git a/roles/network_plugin/weave/meta/main.yml b/roles/network_plugin/weave/meta/main.yml
index 88346d304..a4e7c6fb7 100644
--- a/roles/network_plugin/weave/meta/main.yml
+++ b/roles/network_plugin/weave/meta/main.yml
@@ -2,3 +2,4 @@
 dependencies:
   - role: download
     file: "{{ downloads.weave }}"
+    tags: download
diff --git a/roles/network_plugin/weave/tasks/main.yml b/roles/network_plugin/weave/tasks/main.yml
index b9c00cd33..e74c1c334 100644
--- a/roles/network_plugin/weave/tasks/main.yml
+++ b/roles/network_plugin/weave/tasks/main.yml
@@ -6,6 +6,7 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
+  tags: [hyperkube, upgrade]
 
 - name: Weave | Install weave
   command: rsync -piu "{{ local_release_dir }}/weave/bin/weave" "{{ bin_dir }}/weave"
diff --git a/scripts/gen_tags.sh b/scripts/gen_tags.sh
new file mode 100644
index 000000000..9b8ec31fa
--- /dev/null
+++ b/scripts/gen_tags.sh
@@ -0,0 +1,10 @@
+#!/bin/sh -eo pipefail
+#Generate MD formatted tags from roles and cluster yaml files
+printf "|%25s |%9s\n" "Tag name" "Used for"
+echo "|--------------------------|---------"
+tags=$(grep -r tags: . | perl -ne '/tags:\s\[?(([\w\-_]+,?\s?)+)/ && printf "%s ", "$1"'|\
+  perl -ne 'print join "\n", split /\s|,/' | sort -u)
+for tag in $tags; do
+  match=$(cat docs/ansible.md | perl -ne "/^\|\s+${tag}\s\|\s+((\S+\s?)+)/ && printf \$1")
+  printf "|%25s |%s\n" "${tag}" " ${match}"
+done
-- 
GitLab