From d2e010cbe139cf17f17fd73fae0822bf58f3afe2 Mon Sep 17 00:00:00 2001
From: Alexander Block <ablock84@gmail.com>
Date: Tue, 10 Jan 2017 16:11:42 +0100
Subject: [PATCH] Add kernel upgrade for CentOS

---
 cluster.yml                             |  1 +
 inventory/group_vars/all.yml            |  3 +++
 roles/kernel-upgrade/defaults/main.yml  |  9 ++++++++
 roles/kernel-upgrade/tasks/centos-7.yml | 28 +++++++++++++++++++++++
 roles/kernel-upgrade/tasks/main.yml     |  5 +++++
 roles/kernel-upgrade/tasks/reboot.yml   | 30 +++++++++++++++++++++++++
 6 files changed, 76 insertions(+)
 create mode 100644 roles/kernel-upgrade/defaults/main.yml
 create mode 100644 roles/kernel-upgrade/tasks/centos-7.yml
 create mode 100644 roles/kernel-upgrade/tasks/main.yml
 create mode 100644 roles/kernel-upgrade/tasks/reboot.yml

diff --git a/cluster.yml b/cluster.yml
index f77b45951..e773931bf 100644
--- a/cluster.yml
+++ b/cluster.yml
@@ -26,6 +26,7 @@
 - hosts: k8s-cluster:etcd:calico-rr
   any_errors_fatal: true
   roles:
+    - { role: kernel-upgrade, tags: kernel-upgrade, when: kernel_upgrade is defined and kernel_upgrade }
     - { role: kubernetes/preinstall, tags: preinstall }
     - { role: docker, tags: docker }
     - role: rkt
diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml
index 88a357a82..d04b7c95c 100644
--- a/inventory/group_vars/all.yml
+++ b/inventory/group_vars/all.yml
@@ -222,3 +222,6 @@ efk_enabled: false
 ## cluster of Hashicorp's Vault is started to issue certificates (using etcd
 ## as a backend). Options are "script" or "vault"
 cert_management: script
+
+# Please specify true if you want to perform a kernel upgrade
+kernel_upgrade: false
diff --git a/roles/kernel-upgrade/defaults/main.yml b/roles/kernel-upgrade/defaults/main.yml
new file mode 100644
index 000000000..51ebd68ff
--- /dev/null
+++ b/roles/kernel-upgrade/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+
+elrepo_key_url: 'https://www.elrepo.org/RPM-GPG-KEY-elrepo.org'
+elrepo_rpm : elrepo-release-7.0-2.el7.elrepo.noarch.rpm
+elrepo_mirror : http://www.elrepo.org
+
+elrepo_url : '{{elrepo_mirror}}/{{elrepo_rpm}}'
+
+elrepo_kernel_package: "kernel-lt"
diff --git a/roles/kernel-upgrade/tasks/centos-7.yml b/roles/kernel-upgrade/tasks/centos-7.yml
new file mode 100644
index 000000000..b3181c213
--- /dev/null
+++ b/roles/kernel-upgrade/tasks/centos-7.yml
@@ -0,0 +1,28 @@
+---
+
+- name: install ELRepo key
+  rpm_key: state=present key='{{ elrepo_key_url }}'
+
+- name: install elrepo repository
+  yum:
+    name: '{{elrepo_url}}'
+    state: present
+
+- name: upgrade kernel
+  yum: name={{elrepo_kernel_package}} state=present enablerepo=elrepo-kernel
+  register: upgrade
+
+- name: change default grub entry
+  lineinfile:
+    dest: '/etc/default/grub'
+    regexp: '^GRUB_DEFAULT=.*'
+    line: 'GRUB_DEFAULT=0'
+  when: upgrade.changed
+  register: grub_entry
+
+- name: re-generate grub-config
+  command: grub2-mkconfig -o /boot/grub2/grub.cfg
+  when: upgrade.changed and grub_entry.changed
+
+- include: reboot.yml
+  when: upgrade.changed
\ No newline at end of file
diff --git a/roles/kernel-upgrade/tasks/main.yml b/roles/kernel-upgrade/tasks/main.yml
new file mode 100644
index 000000000..999eb94ae
--- /dev/null
+++ b/roles/kernel-upgrade/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+
+- include: centos-7.yml
+  when: ansible_distribution in ["CentOS","RedHat"] and
+        ansible_distribution_major_version >= 7
diff --git a/roles/kernel-upgrade/tasks/reboot.yml b/roles/kernel-upgrade/tasks/reboot.yml
new file mode 100644
index 000000000..51c383386
--- /dev/null
+++ b/roles/kernel-upgrade/tasks/reboot.yml
@@ -0,0 +1,30 @@
+---
+
+# Reboot the machine gets more complicated as we want to support bastion hosts. A simple wait_for task would not work
+# as we can not directly reach the hosts (except the bastion). In case a basion is used, we first check for it to come
+# back. After it is back, we check for all the hosts by delegating to the bastion.
+
+- name: Rebooting server
+  shell: nohup bash -c "sleep 5 && shutdown -r now 'Reboot required for updated kernel'" &
+
+- name: Wait for some seconds
+  pause: seconds=10
+
+- set_fact:
+    is_bastion: "{{ inventory_hostname == 'bastion' }}"
+    wait_for_delegate: "localhost"
+- set_fact:
+    wait_for_delegate: "{{hostvars['bastion']['ansible_ssh_host']}}"
+  when: "{{ 'bastion' in groups['all'] }}"
+
+- name: wait for bastion to come back
+  wait_for: host={{ ansible_ssh_host }} port=22 delay=10 timeout=300
+  become: false
+  delegate_to: localhost
+  when: "is_bastion"
+
+- name: waiting for server to come back (using bastion if necessary)
+  wait_for: host={{ ansible_ssh_host }} port=22 delay=10 timeout=300
+  become: false
+  delegate_to: "{{ wait_for_delegate }}"
+  when: "not is_bastion"
-- 
GitLab