Vagrant provisioning with Ansible - mysql_db not finding PyMySQL

Viewed 1633

I'm spinning up a vagrant vm using the following vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
    config.vm.box = "centos/7"

    config.vm.network "private_network", ip: "192.168.1.15",
        virtualbox__intnet: true

    # provision with ansible playbook
    config.vm.provision "ansible_local" do |ansible|
        ansible.playbook = "provisioning/playbook.yml"
    end
end

where provisioning/playbook.yml looks like:

---
- name: Set up the things and stuff
  hosts: all
  become: true

  tasks:
  - name: Update Yum
    yum:
      name: "*" 
      state: latest

  - name: install yum utils
    yum:
      name: yum-utils
      state: present

  - name: install development tools
    yum:
      name: "@Development tools"
      state: present

  - name: install ius release
    yum:
      name: https://centos7.iuscommunity.org/ius-release.rpm
      state: present

  - name: install python36
    yum:
      name: python36u
      state: present

  - name: install pip36
    yum:
      name: python36u-pip
      state: latest

  - name: upgrade pip36 to latest version
    pip:
      name: pip
      extra_args: --upgrade
      executable: pip3.6

  - name: install pymysql for python3 (for app connection to mysql)
    pip:
      name: pymysql
      executable: pip3.6

  - name: Install MYSQL server
    yum:
      name: mariadb-server
      state: latest

  - name: start mariadb-server and enable it on reboot
    service: 
      name: mariadb 
      state: started 
      enabled: true

  - name: copy database dump file to server
    copy:
      src: files/db_restore_file.sql
      dest: /tmp

  - name: create database and tables
    mysql_db:
      state: import
      name: all
      target: /tmp/db_restore_file.sql 

and when I run vagrant up, everything looks peachy until it hits the mysql_db line where I get the following error message:

fatal: [default]: FAILED! => {"changed": false, "msg": "The PyMySQL (Python 2.7 and Python 3.X) or MySQL-python (Python 2.X) module is required."} to retry, use: --limit @/vagrant/provisioning/playbook.retry

ok.... so I vagrant ssh into the vm to check on things. Entering a python3.6 session allows me to successfully import pymysql:

[vagrant@localhost ~]$ python3.6
Python 3.6.7 (default, Dec  5 2018, 15:02:05)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymysql
>>>

and (for some semblance of completeness in this post) of course there's no pymysql module for python 2 (as expected..I didn't install one...):

[vagrant@localhost ~]$ python
Python 2.7.5 (default, Oct 30 2018, 23:45:53)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymysql
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named pymysql
>>>

What is going on here? Do I need to tell Ansible (or Vagrant) to explicitly use python3.6 in this case? If so, what's the preferred way of doing that? I don't want to install any python2.x modules on that vm.

Thanks in advance and let me know if there is any missing information here.

EDIT #1

adding the task

  - name: Set ansible python interpreter to python3.6
    set_fact:
      ansible_python_interpreter: python3.6

tells the Ansible on the VM to explicitly use python3.6. If you add this before the task 'copy database dump file to server', you receive:

TASK [copy database dump file to server] *************************************** fatal: [default]: FAILED! => {"changed": false, "checksum": "...omitted_checksum...", "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"} to retry, use: --limit @/vagrant/provisioning/playbook.retry

and since I cannot seem to find a clean way to install libselinux-python for python3.6 with Ansible, I just add the set_fact task after the file copy and before the 'create database and tables' task...seems to work but feels dirty switching python interpreters like that.

1 Answers

Ansible will use the default Python install unless you tell it to do otherwise, and therefore as you don't have the necessary modules installed under Python 2, the module fails.

Ansible provides a ansible_python_interpreter parameter which takes the full path to the Python binary, which can tell Ansible to use an alternate version of Python. You can set this in a variety of places. Commonly, this is done in the inventory by creating a group for hosts that require Python 3 to be used:

 [python3_hosts]
 some_host
 another_host

 [python3_hosts:vars]
 ansible_python_interpreter = /path/to/alt/python

but it can also be set in ansible.cfg, the 'vars' section of a playbook, and maybe even in a 'vars' section of an individual task (Disclaimer: not tried that.)

Related