diff --git a/README.md b/README.md
index cfc82a6cdbf10a1ee7001da1f8451f86b47934e9..02bdb72a47c78c491efd5be95f331b1b339a101d 100644
--- a/README.md
+++ b/README.md
@@ -67,9 +67,9 @@ plugins can be deployed for a given single cluster.
 Requirements
 --------------
 
-* **Ansible v2.2 (or newer) and python-netaddr is installed on the machine
+* **Ansible v2.3 (or newer) and python-netaddr is installed on the machine
   that will run Ansible commands**
-* **Jinja 2.8 (or newer) is required to run the Ansible Playbooks**
+* **Jinja 2.9 (or newer) is required to run the Ansible Playbooks**
 * The target servers must have **access to the Internet** in order to pull docker images.
 * The target servers are configured to allow **IPv4 forwarding**.
 * **Your ssh key must be copied** to all the servers part of your inventory.
diff --git a/requirements.txt b/requirements.txt
index ccf58ea3a38269e3fe0ee41c658ebafe2cc6ee4c..6458113ac548ecfba541c9124c1c0eaf30bcacf2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,14 +1,3 @@
-ansible==2.2.1.0
+ansible>=2.3.0
 netaddr
-# Ansible 2.2.1 requires jinja2<2.9, see <https://github.com/ansible/ansible/blob/v2.2.1.0-1/setup.py#L25>,
-# but without explicit limiting upper jinja2 version here pip ignores
-# Ansible requirements and installs latest available jinja2
-# (pip is not very smart here), which is incompatible with with
-# Ansible 2.2.1.
-# With incompatible jinja2 version "ansible-vault create" (and probably other parts)
-# fails with:
-#   ERROR! Unexpected Exception: The 'jinja2<2.9' distribution was not found 
-#   and is required by ansible
-# This upper limit should be removed in 2.2.2 release, see:
-# <https://github.com/ansible/ansible/commit/978311bf3f91dae5806ab72b665b0937adce38ad>
-jinja2>=2.8,<2.9
+jinja2>=2.9.6
diff --git a/roles/download/tasks/main.yml b/roles/download/tasks/main.yml
index 37c72462e46ce313464fdfbcd2c5bafbe773e626..24d1b5bcabd24405d49172c28f592cf9705b50ae 100644
--- a/roles/download/tasks/main.yml
+++ b/roles/download/tasks/main.yml
@@ -2,14 +2,18 @@
 - name: downloading...
   debug:
     msg: "{{ download.url }}"
-  when: "{{ download.enabled|bool and not download.container|bool }}"
+  when:
+    - download.enabled|bool
+    - not download.container|bool
 
 - name: Create dest directories
   file:
     path: "{{local_release_dir}}/{{download.dest|dirname}}"
     state: directory
     recurse: yes
-  when: "{{ download.enabled|bool and not download.container|bool }}"
+  when:
+    - download.enabled|bool
+    - not download.container|bool
   tags: bootstrap-os
 
 - name: Download items
@@ -23,7 +27,9 @@
   until: "'OK' in get_url_result.msg or 'file already exists' in get_url_result.msg"
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
-  when: "{{ download.enabled|bool and not download.container|bool }}"
+  when:
+    - download.enabled|bool
+    - not download.container|bool
 
 - name: Extract archives
   unarchive:
@@ -32,7 +38,11 @@
     owner: "{{ download.owner|default(omit) }}"
     mode: "{{ download.mode|default(omit) }}"
     copy: no
-  when: "{{ download.enabled|bool and not download.container|bool and download.unarchive is defined and download.unarchive == True }}"
+  when:
+    - download.enabled|bool
+    - not download.container|bool
+    - download.unarchive is defined
+    - download.unarchive == True
 
 - name: Fix permissions
   file:
@@ -40,7 +50,10 @@
     path: "{{local_release_dir}}/{{download.dest}}"
     owner: "{{ download.owner|default(omit) }}"
     mode: "{{ download.mode|default(omit) }}"
-  when: "{{ download.enabled|bool and not download.container|bool and (download.unarchive is not defined or download.unarchive == False) }}"
+  when:
+    - download.enabled|bool
+    - not download.container|bool
+    - (download.unarchive is not defined or download.unarchive == False)
 
 - set_fact:
     download_delegate: "{% if download_localhost %}localhost{% else %}{{groups['kube-master'][0]}}{% endif %}"
@@ -53,13 +66,15 @@
     recurse: yes
     mode: 0755
     owner: "{{ansible_ssh_user|default(ansible_user_id)}}"
-  when: "{{ download.enabled|bool and download.container|bool }}"
+  when:
+    - download.enabled|bool
+    - download.container|bool
   tags: bootstrap-os
 
 # This is required for the download_localhost delegate to work smooth with Container Linux by CoreOS cluster nodes
 - name: Hack python binary path for localhost
   raw: sh -c "mkdir -p /opt/bin; ln -sf /usr/bin/python /opt/bin/python"
-  when: "{{ download_delegate == 'localhost' }}"
+  when: download_delegate == 'localhost'
   delegate_to: localhost
   failed_when: false
   run_once: true
@@ -73,12 +88,18 @@
   delegate_to: localhost
   become: false
   run_once: true
-  when: "{{ download_run_once|bool and download.enabled|bool and download.container|bool and download_delegate == 'localhost' }}"
+  when:
+    - download_run_once|bool
+    - download.enabled|bool
+    - download.container|bool
+    - download_delegate == 'localhost'
   tags: localhost
 
 - name: Make download decision if pull is required by tag or sha256
   include: set_docker_image_facts.yml
-  when: "{{ download.enabled|bool and download.container|bool }}"
+  when:
+    - download.enabled|bool
+    - download.container|bool
   delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
   run_once: "{{ download_run_once|bool }}"
   tags: facts
@@ -86,7 +107,9 @@
 - name: pulling...
   debug:
     msg: "{{ pull_args }}"
-  when: "{{ download.enabled|bool and download.container|bool }}"
+  when:
+    - download.enabled|bool
+    - download.container|bool
 
 #NOTE(bogdando) this brings no docker-py deps for nodes
 - name: Download containers if pull is required or told to always pull
@@ -95,7 +118,10 @@
   until: pull_task_result|succeeded
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
-  when: "{{ download.enabled|bool and download.container|bool and pull_required|bool|default(download_always_pull) }}"
+  when:
+    - download.enabled|bool
+    - download.container|bool
+    - pull_required|bool|default(download_always_pull)
   delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
   run_once: "{{ download_run_once|bool }}"
 
@@ -110,7 +136,10 @@
 - name: "Update the 'container_changed' fact"
   set_fact:
     container_changed: "{{ pull_required|bool|default(false) or not 'up to date' in pull_task_result.stdout }}"
-  when: "{{ download.enabled|bool and download.container|bool and pull_required|bool|default(download_always_pull) }}"
+  when:
+    - download.enabled|bool
+    - download.container|bool
+    - pull_required|bool|default(download_always_pull)
   delegate_to: "{{ download_delegate if download_run_once|bool else inventory_hostname }}"
   run_once: "{{ download_run_once|bool }}"
   tags: facts
@@ -120,7 +149,10 @@
     path: "{{fname}}"
   register: img
   changed_when: false
-  when: "{{ download.enabled|bool and download.container|bool and download_run_once|bool }}"
+  when:
+    - download.enabled|bool
+    - download.container|bool
+    - download_run_once|bool
   delegate_to: "{{ download_delegate }}"
   become: false
   run_once: true
@@ -131,7 +163,12 @@
   delegate_to: "{{ download_delegate }}"
   register: saved
   run_once: true
-  when: (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] or download_delegate == "localhost") and download_run_once|bool and download.enabled|bool and download.container|bool and (container_changed|bool or not img.stat.exists)
+  when:
+    - (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] or download_delegate == "localhost")
+    - download_run_once|bool
+    - download.enabled|bool
+    - download.container|bool
+    - (container_changed|bool or not img.stat.exists)
 
 - name: Download | copy container images to ansible host
   synchronize:
@@ -140,7 +177,14 @@
     mode: pull
   delegate_to: localhost
   become: false
-  when: not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and inventory_hostname == groups['kube-master'][0] and download_delegate != "localhost" and download_run_once|bool and download.enabled|bool and download.container|bool and saved.changed
+  when:
+    - not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
+    - inventory_hostname == groups['kube-master'][0]
+    - download_delegate != "localhost"
+    - download_run_once|bool
+    - download.enabled|bool
+    - download.container|bool
+    - saved.changed
 
 - name: Download | upload container images to nodes
   synchronize:
@@ -153,10 +197,21 @@
   until: get_task|succeeded
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
-  when: (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and inventory_hostname != groups['kube-master'][0] or download_delegate == "localhost") and download_run_once|bool and download.enabled|bool and download.container|bool
+  when:
+    - (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and
+      inventory_hostname != groups['kube-master'][0] or
+      download_delegate == "localhost")
+    - download_run_once|bool
+    - download.enabled|bool
+    - download.container|bool
   tags: [upload, upgrade]
 
 - name: Download | load container images
   shell: "{{ docker_bin_dir }}/docker load < {{ fname }}"
-  when: (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and inventory_hostname != groups['kube-master'][0] or download_delegate == "localhost") and download_run_once|bool and download.enabled|bool and download.container|bool
+  when:
+    - (not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"] and
+      inventory_hostname != groups['kube-master'][0] or download_delegate == "localhost")
+    - download_run_once|bool
+    - download.enabled|bool
+    - download.container|bool
   tags: [upload, upgrade]
diff --git a/roles/kernel-upgrade/tasks/reboot.yml b/roles/kernel-upgrade/tasks/reboot.yml
index 5e01dd8fcf9297acb6f84f60388030001775a2bc..87748f3f6c9e1e49e6047092931f0a1ea24da5b0 100644
--- a/roles/kernel-upgrade/tasks/reboot.yml
+++ b/roles/kernel-upgrade/tasks/reboot.yml
@@ -17,7 +17,7 @@
 
 - set_fact:
     wait_for_delegate: "{{hostvars['bastion']['ansible_ssh_host']}}"
-  when: "{{ 'bastion' in groups['all'] }}"
+  when: "'bastion' in groups['all']"
 
 - name: wait for bastion to come back
   wait_for:
@@ -27,7 +27,7 @@
     timeout: 300
   become: false
   delegate_to: localhost
-  when: "is_bastion"
+  when: is_bastion
 
 - name: waiting for server to come back (using bastion if necessary)
   wait_for:
@@ -37,4 +37,4 @@
     timeout: 300
   become: false
   delegate_to: "{{ wait_for_delegate }}"
-  when: "not is_bastion"
+  when: not is_bastion
diff --git a/roles/kubernetes/preinstall/tasks/etchosts.yml b/roles/kubernetes/preinstall/tasks/etchosts.yml
index 181fbcb0f400b25e522fc02c2b1cd586e263b648..df330be088c344181cc3560b9fdf5382497146a7 100644
--- a/roles/kubernetes/preinstall/tasks/etchosts.yml
+++ b/roles/kubernetes/preinstall/tasks/etchosts.yml
@@ -17,7 +17,10 @@
     line: "{{ loadbalancer_apiserver.address }} {{ apiserver_loadbalancer_domain_name| default('lb-apiserver.kubernetes.local') }}"
     state: present
     backup: yes
-  when: loadbalancer_apiserver is defined and loadbalancer_apiserver.address is defined and apiserver_loadbalancer_domain_name is defined
+  when:
+    - loadbalancer_apiserver is defined
+    - loadbalancer_apiserver.address is defined
+    - apiserver_loadbalancer_domain_name is defined
 
 - name: Hosts | localhost ipv4 in hosts file
   lineinfile:
diff --git a/roles/kubernetes/preinstall/tasks/main.yml b/roles/kubernetes/preinstall/tasks/main.yml
index 3ae785d6eaec712ec58547e3b12e7115c1895d1c..2f5bff2290d2ed7c1c4be97415bd218622559014 100644
--- a/roles/kubernetes/preinstall/tasks/main.yml
+++ b/roles/kubernetes/preinstall/tasks/main.yml
@@ -43,7 +43,7 @@
     path: "{{ kube_config_dir }}"
     state: directory
     owner: kube
-  when: "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  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
@@ -51,7 +51,7 @@
     path: "{{ kube_script_dir }}"
     state: directory
     owner: kube
-  when: "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  when: "inventory_hostname in groups['k8s-cluster']"
   tags: [k8s-secrets, bootstrap-os]
 
 - name: Create kubernetes manifests directory
@@ -59,17 +59,21 @@
     path: "{{ kube_manifest_dir }}"
     state: directory
     owner: kube
-  when: "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  when: "inventory_hostname in groups['k8s-cluster']"
   tags: [kubelet, 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', 'openstack' or 'vsphere'"
-  when: cloud_provider is defined and cloud_provider not in ['generic', 'gce', 'aws', 'azure', 'openstack', 'vsphere']
+  when:
+    - cloud_provider is defined
+    - cloud_provider not in ['generic', 'gce', 'aws', 'azure', 'openstack', 'vsphere']
   tags: [cloud-provider, facts]
 
 - include: "{{ cloud_provider }}-credential-check.yml"
-  when: cloud_provider is defined and cloud_provider in [ 'openstack', 'azure', 'vsphere' ]
+  when:
+    - cloud_provider is defined
+    - cloud_provider in [ 'openstack', 'azure', 'vsphere' ]
   tags: [cloud-provider, facts]
 
 - name: Create cni directories
@@ -80,7 +84,9 @@
   with_items:
     - "/etc/cni/net.d"
     - "/opt/cni/bin"
-  when: kube_network_plugin in ["calico", "weave", "canal"] and "{{ inventory_hostname in groups['k8s-cluster'] }}"
+  when:
+    - kube_network_plugin in ["calico", "weave", "canal"]
+    - inventory_hostname in groups['k8s-cluster']
   tags: [network, calico, weave, canal, bootstrap-os]
 
 - name: Update package management cache (YUM)
@@ -91,7 +97,9 @@
   until: yum_task_result|succeeded
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
-  when: ansible_pkg_mgr == 'yum' and not is_atomic
+  when:
+    - ansible_pkg_mgr == 'yum'
+    - not is_atomic
   tags: bootstrap-os
 
 - name: Install latest version of python-apt for Debian distribs
@@ -109,14 +117,17 @@
   until: dnf_task_result|succeeded
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
-  when: ansible_distribution == "Fedora" and
-        ansible_distribution_major_version > 21
+  when:
+    - ansible_distribution == "Fedora"
+    - 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 not is_atomic
+  when:
+    - ansible_distribution in ["CentOS","RedHat"]
+    - not is_atomic
   register: epel_task_result
   until: epel_task_result|succeeded
   retries: 4
@@ -149,7 +160,9 @@
   selinux:
     policy: targeted
     state: permissive
-  when: ansible_os_family == "RedHat" and slc.stat.exists == True
+  when:
+    - ansible_os_family == "RedHat"
+    - slc.stat.exists == True
   changed_when: False
   tags: bootstrap-os
 
@@ -159,7 +172,9 @@
     line: "precedence ::ffff:0:0/96  100"
     state: present
     backup: yes
-  when: disable_ipv6_dns and not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
+  when:
+    - disable_ipv6_dns
+    - not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
   tags: bootstrap-os
 
 - name: set default sysctl file path
@@ -176,7 +191,9 @@
 - name: Change sysctl file path to link source if linked
   set_fact:
     sysctl_file_path: "{{sysctl_file_stat.stat.lnk_source}}"
-  when: sysctl_file_stat.stat.islnk is defined and sysctl_file_stat.stat.islnk
+  when:
+    - sysctl_file_stat.stat.islnk is defined
+    - sysctl_file_stat.stat.islnk
   tags: bootstrap-os
 
 - name: Enable ip forwarding
@@ -193,22 +210,33 @@
     dest: "{{ kube_config_dir }}/cloud_config"
     group: "{{ kube_cert_group }}"
     mode: 0640
-  when: inventory_hostname in groups['k8s-cluster'] and cloud_provider is defined and cloud_provider in [ 'openstack', 'azure', 'vsphere' ]
+  when:
+    - inventory_hostname in groups['k8s-cluster']
+    - cloud_provider is defined
+    - cloud_provider in [ 'openstack', 'azure', 'vsphere' ]
   tags: [cloud-provider]
 
 - include: etchosts.yml
   tags: [bootstrap-os, etchosts]
 
 - include: resolvconf.yml
-  when: dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'
+  when:
+    - dns_mode != 'none'
+    - resolvconf_mode == 'host_resolvconf'
   tags: [bootstrap-os, resolvconf]
 
 - include: dhclient-hooks.yml
-  when: dns_mode != 'none' and resolvconf_mode == 'host_resolvconf' and not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
+  when:
+    - dns_mode != 'none'
+    - resolvconf_mode == 'host_resolvconf'
+    - not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
   tags: [bootstrap-os, resolvconf]
 
 - include: dhclient-hooks-undo.yml
-  when: dns_mode != 'none' and resolvconf_mode != 'host_resolvconf' and not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
+  when:
+    - dns_mode != 'none'
+    - resolvconf_mode != 'host_resolvconf'
+    - not ansible_os_family in ["CoreOS", "Container Linux by CoreOS"]
   tags: [bootstrap-os, resolvconf]
 
 - name: Check if we are running inside a Azure VM
@@ -218,7 +246,7 @@
   tags: bootstrap-os
 
 - include: growpart-azure-centos-7.yml
-  when: azure_check.stat.exists and
-        ansible_distribution in ["CentOS","RedHat"]
+  when:
+    - azure_check.stat.exists
+    - ansible_distribution in ["CentOS","RedHat"]
   tags: bootstrap-os
-
diff --git a/roles/kubernetes/secrets/tasks/sync_kube_master_certs.yml b/roles/kubernetes/secrets/tasks/sync_kube_master_certs.yml
index 0561d65811ecc2b9b78a19a883c7e86712232133..b02120ccb92a1623b8fedb41a7f228709286b9a7 100644
--- a/roles/kubernetes/secrets/tasks/sync_kube_master_certs.yml
+++ b/roles/kubernetes/secrets/tasks/sync_kube_master_certs.yml
@@ -6,7 +6,7 @@
   with_items: "{{ groups['kube-master'] }}"
 
 - include: ../../../vault/tasks/shared/sync_file.yml
-  vars: 
+  vars:
     sync_file: "{{ item }}"
     sync_file_dir: "{{ kube_cert_dir }}"
     sync_file_group: "{{ kube_cert_group }}"
@@ -38,7 +38,7 @@
   set_fact:
     kube_api_certs_needed: "{{ item.path }}"
   with_items: "{{ sync_file_results|d([]) }}"
-  when: "{{ item.no_srcs }}"
+  when: item.no_srcs
 
 - name: sync_kube_master_certs | Unset sync_file_results after apiserver cert
   set_fact:
@@ -46,7 +46,7 @@
 
 
 - include: ../../../vault/tasks/shared/sync_file.yml
-  vars: 
+  vars:
     sync_file: ca.pem
     sync_file_dir: "{{ kube_cert_dir }}"
     sync_file_group: "{{ kube_cert_group }}"
diff --git a/roles/network_plugin/calico/tasks/main.yml b/roles/network_plugin/calico/tasks/main.yml
index 2f3096bf3dc3c2e8b4367b10e34ffecd8c715867..eda9c2934540dfe4039734244858826e82a8111e 100644
--- a/roles/network_plugin/calico/tasks/main.yml
+++ b/roles/network_plugin/calico/tasks/main.yml
@@ -56,7 +56,7 @@
   retries: 4
   delay: "{{ retry_stagger | random + 3 }}"
   changed_when: false
-  when: "{{ overwrite_hyperkube_cni|bool }}"
+  when: overwrite_hyperkube_cni|bool
   tags: [hyperkube, upgrade]
 
 - name: Calico | Set cni directory permissions
diff --git a/roles/vault/tasks/bootstrap/start_vault_temp.yml b/roles/vault/tasks/bootstrap/start_vault_temp.yml
index 161ef92d679f5802e212b8f0d5eea339cac41e24..4a5e6bc5ed0c2006a4f1bf326eab14004042eca2 100644
--- a/roles/vault/tasks/bootstrap/start_vault_temp.yml
+++ b/roles/vault/tasks/bootstrap/start_vault_temp.yml
@@ -3,7 +3,7 @@
 - name: bootstrap/start_vault_temp | Ensure vault-temp isn't already running
   shell: if docker rm -f {{ vault_temp_container_name }} 2>&1 1>/dev/null;then echo true;else echo false;fi
   register: vault_temp_stop_check
-  changed_when: "{{ 'true' in vault_temp_stop_check.stdout }}"
+  changed_when: "'true' in vault_temp_stop_check.stdout"
 
 - name: bootstrap/start_vault_temp | Start single node Vault with file backend
   command: >