From 5fc7ad6878c6483b4246c6f9b3fcc7ecebe3cead Mon Sep 17 00:00:00 2001 From: Chris Coley <chris@codingallnight.com> Date: Wed, 4 Jul 2018 14:11:44 -0700 Subject: [PATCH] Update the bootstrap tasks to fail if Python is not available Initially, this role would check if Python was available in the default location of '/usr/bin/python', and would install Python 2 if it wasn't. I didn't like the idea of installing Python 2 so I updated the role to look for a usable Python interpreter in other standard locations, including Python 3's default location of '/usr/bin/python3'. Then it would tell the user to set 'ansible_python_interpreter' to one of the interpreters it found. I liked this because it gave the user the choice of how to resolve the issue. However, this role was running all the Python finding/checking tasks for every host and that struck me as inefficient, so I changed it. Now, the role checks if the host is pingable. If it is not, then it runs tasks to determine why that specific host is not pingable. It then relays that information to the user by failing out with the fail module and a descriptive message. Hosts that are pingable do not run these tasks. --- defaults/main.yml | 7 ---- tasks/bootstrap.yml | 67 +++++--------------------------- tasks/diagnose-unpingable.yml | 32 +++++++++++++++ tasks/find-python-executable.yml | 21 ++++++++++ tasks/test-python-executable.yml | 22 +++++++++++ 5 files changed, 85 insertions(+), 64 deletions(-) create mode 100644 tasks/diagnose-unpingable.yml create mode 100644 tasks/find-python-executable.yml create mode 100644 tasks/test-python-executable.yml diff --git a/defaults/main.yml b/defaults/main.yml index 23329f3..99f43ab 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -15,12 +15,5 @@ common_utils: - screen - unzip - vim - -# The path to the python executable to use -# If set and the path is executable, then it will be used. -# Else if Python 2 is executable, use it. -# Else if Python 3 is executable, use if. -# Else, fail. -ansible_python_interpreter: ... # vi: set ts=2 sts=2 sw=2 et ft=yaml: diff --git a/tasks/bootstrap.yml b/tasks/bootstrap.yml index dec5621..fcbba72 100644 --- a/tasks/bootstrap.yml +++ b/tasks/bootstrap.yml @@ -1,65 +1,17 @@ --- -- name: Bootstrap the host by selecting which Python interpreter to use, and other OS specific stuff +- name: Bootstrap the host by making sure the host is pingable and installing OS specific requirements tags: bootstrap block: - # If ansible_python_interpreter is set and exists, use it. - # Elif python 2 exists, use it. - # Elif python 3 exists, use it. - # Else, fail. - - name: Figure out which version of Python to use - when: ansible_python_interpreter is not defined or not ansible_python_interpreter - block: - - name: Check if /usr/bin/python is executable - raw: 'test -x /usr/bin/python' - changed_when: false - failed_when: false - register: python_default - - name: Set 'ansible_python_interpreter' to /usr/bin/python - when: python_default.rc is defined and python_default.rc == 0 - set_fact: - ansible_python_interpreter: /usr/bin/python - - - name: Check if /usr/bin/python2 is executable - raw: 'test -x /usr/bin/python2' - changed_when: false - failed_when: false - register: python_2 - - name: Set 'ansible_python_interpreter' to /usr/bin/python2 - when: python_2.rc is defined and python_2.rc == 0 - set_fact: - ansible_python_interpreter: /usr/bin/python2 - - - name: Check if /usr/bin/python3 is executable - raw: 'test -x /usr/bin/python3' - changed_when: false - failed_when: false - register: python_3 - - name: Set 'ansible_python_interpreter' to /usr/bin/python3 - when: python_3.rc is defined and python_3.rc == 0 - set_fact: - ansible_python_interpreter: /usr/bin/python3 - -# - debug: -# var: ansible_python_interpreter - - - name: Check if 'ansible_python_interpreter' is executable - raw: 'test -x {{ ansible_python_interpreter }}' - changed_when: false + - name: Check if the host is pingable + ping: + register: _can_ping failed_when: false - register: python_executable - - name: Assert that 'ansible_python_interpreter' is executable - assert: - that: - - ansible_python_interpreter is defined and ansible_python_interpreter - - python_executable.rc is defined and python_executable.rc == 0 -# - name: Install Python -# raw: > -# (test -e /etc/redhat-release && yum install -y python) -# || (test -e /etc/debian_version && apt-get -y update && apt-get install -y python) -# when: result.rc is defined and result.rc == 1 + - name: If the host is not pingable, find out why + include_tasks: tasks/diagnose-unpingable.yml + when: _can_ping.ping is not defined or _can_ping.ping != 'pong' - - name: Gather facts to determine host OS + - name: Gather minimal facts to determine host OS setup: gather_subset: min @@ -74,7 +26,8 @@ - vars/{{ ansible_os_family | lower }}.yml skip: true - - include_tasks: '{{ item }}' + - name: Include OS specific bootstrap tasks + include_tasks: '{{ item }}' with_first_found: - tasks/bootstrap_{{ ansible_distribution | lower }}-{{ ansible_distribution_version | lower }}.yml - tasks/bootstrap_{{ ansible_distribution | lower }}-{{ ansible_distribution_release | lower }}.yml diff --git a/tasks/diagnose-unpingable.yml b/tasks/diagnose-unpingable.yml new file mode 100644 index 0000000..960854b --- /dev/null +++ b/tasks/diagnose-unpingable.yml @@ -0,0 +1,32 @@ +# +# This task list attempts to diagnose why a host is not pingable with Ansible's +# built-in ping module. It is currently able to diagnose issues with Python +# being unavailable, or Python being an unsupported version. +# +--- +# If the error has a defined error message and is not related to Python not +# being found, then display that message +- fail: + msg: '{{ _can_ping.msg }}' + when: _can_ping.msg is defined and (_can_ping.rc is not defined or _can_ping.rc != 127) + +# If the error is related to Python not being found, then try to find the +# available Python interpreters +- name: Python is not found + when: _can_ping.rc is defined and _can_ping.rc == 127 + block: + - include_tasks: tasks/find-python-executable.yml + - fail: + msg: "Unable to find Python on {{ inventory_hostname }}.\n + Please set 'ansible_python_interpreter' to an executable Python interpreter.\n + The host has these available: ( {{ _python_interpreters | join(' , ') }} )" + +# This block is a catchall that runs whenever an unanticipated error occurs +- name: Something Unexpected Happened + block: + - debug: + var: _can_ping + - fail: + msg: Something Unexpected Happened +... +# vi: set ts=2 sts=2 sw=2 et ft=yaml: diff --git a/tasks/find-python-executable.yml b/tasks/find-python-executable.yml new file mode 100644 index 0000000..08b84f3 --- /dev/null +++ b/tasks/find-python-executable.yml @@ -0,0 +1,21 @@ +# +# This task list atempts to find all the available Python interpreters on a host +# and build a list of them in a variable called '_python_interpreters'. +# +--- +- block: + # Initialize an empty list of available interpreters + - set_fact: + _python_interpreters: [] + + # Loop through the common interpreter paths, testing if they are available + - name: Find a usable Python interpreter + include_tasks: tasks/test-python-executable.yml + loop_control: + loop_var: _python_path + with_items: + - /usr/bin/python + - /usr/bin/python2 + - /usr/bin/python3 +... +# vi: set ts=2 sts=2 sw=2 et ft=yaml: diff --git a/tasks/test-python-executable.yml b/tasks/test-python-executable.yml new file mode 100644 index 0000000..2a219d5 --- /dev/null +++ b/tasks/test-python-executable.yml @@ -0,0 +1,22 @@ +# +# This task list tests is a python interpreter path is executable, and appends +# it to a list of executable paths if it is. Ansible has version requirements +# for Python interpreters, but this task list doesn't check for those. +# +# Parameters: +# _python_path An absolute path to a Python interpreter. +# _python_interpreters A list to append executable paths to. +# +--- +- name: Check if '{{ _python_path }}' is executable + raw: 'test -x {{ _python_path }}' + changed_when: false + failed_when: false + register: __can_exec + +- name: If '{{ _python_path }}' is executable, append it to the list of available interpreters + set_fact: + _python_interpreters: "{{ _python_interpreters }} + [ '{{ _python_path }}' ]" + when: __can_exec.rc is defined and __can_exec.rc == 0 +... +# vi: set ts=2 sts=2 sw=2 et ft=yaml: -- GitLab