├── .gitignore ├── LICENSE ├── README.md ├── Vagrantfile ├── defaults └── main.yml ├── meta └── main.yml ├── tasks ├── main.yml ├── packaging_tools.yml ├── python.yml └── readline.yml ├── test.yml └── vars └── main.yml /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | *.pyc 3 | *.egg-info 4 | *.log 5 | .DS_Store 6 | .vagrant 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Whisker Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ansible-python 2 | 3 | [![Ansible Galaxy](http://img.shields.io/badge/galaxy-whiskerlabs.python-660198.svg)](https://galaxy.ansible.com/list#/roles/4007) 4 | 5 | An Ansible role for installing a sane Python execution environment. 6 | 7 | This role installs (from source) target versions of the Python programming language, 8 | Setuptools, and pip. Virtualenv is then installed with pip. 9 | 10 | By default, the packaging tools (i.e. setuptools, pip, and virtualenv) 11 | are upgraded to their latest versions. This functionality can be 12 | disabled by setting the variable `python_upgrade_packaging_tools` to 13 | `no`. 14 | 15 | ## Installation 16 | 17 | `ansible-python` is tested with Ansible 1.9.x. It likely works on older 18 | versions, but we haven't had occasion to check. README patches are 19 | welcome if this requirement needs amending. 20 | 21 | To install with Ansible Galaxy: 22 | 23 | $ ansible-galaxy install whiskerlabs.python 24 | 25 | Or alternatively, add the path to a local copy of this repository to 26 | `roles_path` within your project's `ansible.cfg` file: 27 | 28 | roles_path = /path/to/role_dir 29 | 30 | where `/path/to/role_dir` is a parent directory of `ansible-python`. 31 | 32 | Consult 33 | [Ansible documentation](http://docs.ansible.com/intro_configuration.html) 34 | for more info on how to configure `roles_path` in an Ansible 35 | configuration file. 36 | 37 | ## Testing 38 | 39 | A [Vagrantfile](http://docs.vagrantup.com/v2/vagrantfile/index.html) 40 | is provided for testing the role within a VM during development. The 41 | role is invoked by an 42 | [Ansible provisioner](https://docs.vagrantup.com/v2/provisioning/ansible.html) 43 | (via a test.yml example playbook) in a bare Ubuntu 14.04 virtual 44 | machine. 45 | 46 | Provided Vagrant and Virtualbox are installed, run `vagrant up` from 47 | the root of this repository to launch and provision a VM. Run `vagrant 48 | provision` to re-run the provisioner. 49 | 50 | ## Variables 51 | 52 | A number of defaults and variables are provided to parameterize the 53 | downloaded tarball paths, options passed to `configure` scripts, and 54 | system packages to install. See `defaults/main.yml` and 55 | `vars/main.yml` for an exaustive list, but the following are the most 56 | likely knobs to be turned: 57 | 58 | python_version (default: 2.7.12) 59 | python_setuptools_version (default: 20.9.0) 60 | python_pip_version (default: 8.1.1) 61 | python_virtualenv_version (default: 15.0.1) 62 | python_upgrade_packaging_tools: (default: yes) 63 | python_install_root (default: /usr/local) 64 | python_apt_package_deps (default: [build-essential, libbz2-dev, libssl-dev, openssl, zlib1g-dev]) 65 | python_dnf_package_deps (default: [@Development tools, ncurses-devel, openssl-devel, zlib-devel]) 66 | 67 | ## Support 68 | 69 | For questions or bug reports, please 70 | [file an issue on Github](https://github.com/whiskerlabs/ansible-python/issues). 71 | 72 | For any other inquiries, send mail to `software at whiskerlabs.com`. 73 | 74 | ## Credits 75 | 76 | Installation procedure is, for the most part, cribbed from Brian 77 | Wickman's 78 | [bootstrap_python.sh script](https://github.com/wickman/python-bootstrap/). 79 | 80 | ## License 81 | 82 | Copyright 2016 Whisker Labs 83 | 84 | Licensed under the MIT License. See LICENSE for details. 85 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | VAGRANTFILE_API_VERSION = "2" 5 | 6 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 7 | config.vm.box = "debian/jessie64" 8 | 9 | config.vm.provision "ansible" do |ansible| 10 | ansible.playbook = "test.yml" 11 | ansible.sudo = true 12 | ansible.extra_vars = { ansible_ssh_user: "vagrant" } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Target versions 3 | python_version: 2.7.12 4 | python_setuptools_version: 20.9.0 5 | python_pip_version: 8.1.1 6 | python_virtualenv_version: 15.0.1 7 | 8 | # If yes, setuptools, pip, and virtualenv are upgraded to the latest 9 | # versions. The target versions defined above are still installed, but 10 | # may be replaced with any newer version. 11 | # 12 | # If `auto_upgrade_packaging_tools` is no, then the versions above are 13 | # heeded. 14 | python_upgrade_packaging_tools: yes 15 | 16 | # Path to a temporary sandbox directory within which to download, 17 | # extract, and build source tarballs. This directory is removed after 18 | # installation is complete. 19 | python_sandbox_path: /tmp/python 20 | 21 | # Path to a directory in which to install Python and related tooling. 22 | python_install_root: /usr/local 23 | 24 | # The Python installation's bin directory. Helpful when invoking 25 | # `python` or `pip` from Ansible. 26 | python_bin: "{{python_install_root}}/bin" 27 | 28 | # Options passed to `./configure` when building readline 6.2 29 | python_readline_6_2_configure_options: CFLAGS=-fPIC --disable-shared --enable-static --prefix={{python_sandbox_path}}/readline 30 | 31 | # Options passed to `./configure` when building Python. 32 | python_configure_options: --prefix={{python_install_root}} 33 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Inspired by https://github.com/wickman/python-bootstrap/ 3 | galaxy_info: 4 | author: Evan Meagher 5 | description: Install specific versions of Python and Python packaging tools 6 | company: Whisker Labs 7 | license: MIT 8 | min_ansible_version: 1.9 9 | 10 | platforms: 11 | - name: Debian 12 | versions: 13 | - all 14 | - name: Ubuntu 15 | versions: 16 | - all 17 | 18 | categories: 19 | #- cloud 20 | #- cloud:ec2 21 | #- cloud:gce 22 | #- cloud:rax 23 | #- clustering 24 | #- database 25 | #- database:nosql 26 | #- database:sql 27 | - development 28 | #- monitoring 29 | #- networking 30 | #- packaging 31 | - system 32 | #- web 33 | dependencies: [] 34 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: create sandbox directory 3 | file: 4 | path: "{{python_sandbox_path}}" 5 | state: directory 6 | 7 | - name: ensure that python installation directory exists 8 | file: 9 | path: "{{python_install_root}}" 10 | state: directory 11 | 12 | - name: download source tarballs 13 | get_url: 14 | url: "{{item.url}}" 15 | dest: "{{item.dest}}" 16 | with_items: 17 | - url: "{{python_readline_6_2_tgz_url}}" 18 | dest: "{{python_readline_6_2_tgz_local_path}}" 19 | - url: "{{python_tgz_url}}" 20 | dest: "{{python_tgz_local_path}}" 21 | - url: "{{python_setuptools_tgz_url}}" 22 | dest: "{{python_setuptools_tgz_local_path}}" 23 | - url: "{{python_pip_tgz_url}}" 24 | dest: "{{python_pip_tgz_local_path}}" 25 | 26 | - name: unarchive source tarballs 27 | unarchive: 28 | copy: no 29 | src: "{{item}}" 30 | dest: "{{python_sandbox_path}}" 31 | with_items: 32 | - "{{python_readline_6_2_tgz_local_path}}" 33 | - "{{python_tgz_local_path}}" 34 | - "{{python_setuptools_tgz_local_path}}" 35 | - "{{python_pip_tgz_local_path}}" 36 | 37 | - name: install apt packages 38 | apt: 39 | name: "{{item}}" 40 | state: latest 41 | update_cache: yes 42 | with_items: "{{python_apt_package_deps}}" 43 | when: ansible_os_family == "Debian" 44 | 45 | - name: install dnf packages 46 | dnf: 47 | name: "{{item}}" 48 | state: latest 49 | with_items: "{{python_dnf_package_deps}}" 50 | when: ansible_os_family == "RedHat" 51 | 52 | - include: readline.yml 53 | - include: python.yml 54 | - include: packaging_tools.yml 55 | 56 | - name: remove sandbox directory 57 | file: 58 | path: "{{python_sandbox_path}}" 59 | state: absent 60 | -------------------------------------------------------------------------------- /tasks/packaging_tools.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: build and install python packaging tools 3 | command: "{{python_bin}}/python setup.py install" 4 | args: 5 | chdir: "{{python_sandbox_path}}/{{item.dir}}" 6 | creates: "{{python_bin}}/{{item.bin}}" 7 | with_items: 8 | # dir: the directory containing the library's setup.py to invoke. 9 | # bin: the library's installed binary, used with `creates` to 10 | # predicate installation. 11 | - dir: setuptools-{{python_setuptools_version}} 12 | bin: easy_install 13 | - dir: pip-{{python_pip_version}} 14 | bin: pip 15 | 16 | - name: install virtualenv 17 | pip: 18 | name: virtualenv 19 | version: "{{python_virtualenv_version}}" 20 | executable: "{{python_bin}}/pip" 21 | 22 | - name: upgrade packaging tools 23 | pip: 24 | name: "{{item}}" 25 | state: latest 26 | executable: "{{python_bin}}/pip" 27 | with_items: 28 | - setuptools 29 | - pip 30 | - virtualenv 31 | when: python_upgrade_packaging_tools 32 | -------------------------------------------------------------------------------- /tasks/python.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: configure a makefile for python source 3 | shell: ./configure {{python_configure_options}} 4 | args: 5 | chdir: "{{python_sandbox_path}}/Python-{{python_version}}" 6 | environment: 7 | LDFLAGS: "-L{{python_sandbox_path}}/readline/lib" 8 | CFLAGS: "-I{{python_sandbox_path}}/readline/include" 9 | 10 | - name: build python from source 11 | shell: make -j5 12 | args: 13 | chdir: "{{python_sandbox_path}}/Python-{{python_version}}" 14 | 15 | - name: install python 16 | shell: make install 17 | args: 18 | chdir: "{{python_sandbox_path}}/Python-{{python_version}}" 19 | -------------------------------------------------------------------------------- /tasks/readline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: configure a makefile for readline 6.2 3 | shell: ./configure {{python_readline_6_2_configure_options}} 4 | args: 5 | chdir: "{{python_sandbox_path}}/readline-6.2" 6 | 7 | - name: build readline 6.2 from source 8 | shell: make -j3 9 | args: 10 | chdir: "{{python_sandbox_path}}/readline-6.2" 11 | 12 | - name: install readline 6.2 in the python installation sandbox 13 | shell: make install 14 | args: 15 | chdir: "{{python_sandbox_path}}/readline-6.2" 16 | -------------------------------------------------------------------------------- /test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | vars_files: 4 | - 'defaults/main.yml' 5 | - 'vars/main.yml' 6 | tasks: 7 | - include: 'tasks/main.yml' 8 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # apt package dependencies. 3 | # These libraries are sufficient to build most core Python modules 4 | # (e.g. ssl, bz2), but the following may not be built: 5 | # 6 | # _bsddb _sqlite3 _tkinter 7 | # bsddb185 dbm dl 8 | # gdbm imageop sunaudiodev 9 | python_apt_package_deps: 10 | - build-essential 11 | - libbz2-dev 12 | - libncurses5-dev 13 | - libssl-dev 14 | - openssl 15 | - zlib1g-dev 16 | 17 | python_dnf_package_deps: 18 | - "@Development tools" 19 | - ncurses-devel 20 | - openssl-devel 21 | - zlib-devel 22 | 23 | # readline 6.2 tarball paths 24 | python_readline_6_2_tgz_file_name: readline-6.2.tar.gz 25 | python_readline_6_2_tgz_url: http://ftp.gnu.org/gnu/readline/{{python_readline_6_2_tgz_file_name}} 26 | python_readline_6_2_tgz_local_path: "{{python_sandbox_path}}/{{python_readline_6_2_tgz_file_name}}" 27 | 28 | # Python tarball paths 29 | python_tgz_file_name: Python-{{python_version}}.tgz 30 | python_tgz_url: http://python.org/ftp/python/{{python_version}}/{{python_tgz_file_name}} 31 | python_tgz_local_path: "{{python_sandbox_path}}/{{python_tgz_file_name}}" 32 | 33 | # Setuptools tarball paths 34 | python_setuptools_tgz_file_name: setuptools-{{python_setuptools_version}}.tar.gz 35 | python_setuptools_tgz_url: https://pypi.python.org/packages/source/s/setuptools/{{python_setuptools_tgz_file_name}} 36 | python_setuptools_tgz_local_path: "{{python_sandbox_path}}/{{python_setuptools_tgz_file_name}}" 37 | 38 | # pip tarball paths 39 | python_pip_tgz_file_name: pip-{{python_pip_version}}.tar.gz 40 | python_pip_tgz_url: https://pypi.python.org/packages/source/p/pip/{{python_pip_tgz_file_name}} 41 | python_pip_tgz_local_path: "{{python_sandbox_path}}/{{python_pip_tgz_file_name}}" 42 | --------------------------------------------------------------------------------