├── .bumpversion.cfg ├── .travis.yml ├── LICENSE ├── README.md ├── defaults └── main.yml ├── files └── bootstrap.sh ├── meta └── main.yml ├── tasks └── main.yml ├── tests ├── default │ ├── inventory │ └── test.yml ├── opt │ ├── inventory │ └── test.yml └── test.cfg └── vars └── main.yml /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.6.3 3 | commit = True 4 | tag = True 5 | tag_name = v{new_version} 6 | 7 | [bumpversion:file:README.md] 8 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | python: "2.7" 4 | 5 | env: 6 | global: 7 | - ANSIBLE_CONFIG=tests/test.cfg 8 | matrix: 9 | - TEST=opt ANSIBLE_VERSION=1.9.4 10 | - TEST=opt ANSIBLE_VERSION=2.0.2.0 11 | - TEST=opt ANSIBLE_VERSION=2.1.0.0 12 | - TEST=default ANSIBLE_VERSION=1.9.4 13 | - TEST=default ANSIBLE_VERSION=2.0.2.0 14 | - TEST=default ANSIBLE_VERSION=2.1.0.0 15 | 16 | before_install: 17 | - sudo apt-get update -qq 18 | - sudo apt-get install -y curl libncurses5 19 | 20 | install: 21 | - pip install ansible==$ANSIBLE_VERSION 22 | 23 | script: 24 | # syntax check 25 | - "ansible-playbook -i tests/$TEST/inventory tests/$TEST/test.yml --syntax-check" 26 | # run playbook 27 | - "ansible-playbook -i tests/$TEST/inventory tests/$TEST/test.yml --sudo" 28 | # Run the playbook again, checking idempotence. 29 | - > 30 | ansible-playbook -i tests/$TEST/inventory tests/$TEST/test.yml --sudo 31 | | grep -q 'changed=0.*failed=0' 32 | && (echo 'Idempotence test: pass' && exit 0) 33 | || (echo 'Idempotence test: fail' && exit 1) 34 | # pinging host, using bootstrapped python 35 | - "ansible -i tests/$TEST/inventory all -m ping" 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 VMware, Inc. 4 | Copyright (c) 2014 Roman Shtylman 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/vmware/ansible-coreos-bootstrap.svg?branch=master)](https://travis-ci.org/vmware/ansible-coreos-bootstrap) 2 | 3 | IMPORTANT: after ansible 2.1, the following trick is no longer valid: 4 | ``` 5 | ansible_python_interpreter="PATH=/home/core/bin:$PATH python" 6 | ``` 7 | 8 | The good news is that it's no longer needed either. The following now works and 9 | is compatible with old and new ansible (and is simpler): 10 | ``` 11 | ansible_python_interpreter="/home/core/bin/python" 12 | ``` 13 | 14 | # coreos-bootstrap 15 | 16 | In order to effectively run ansible, the target machine needs to have a python interpreter. Coreos machines are minimal and do not ship with any version of python. To get around this limitation we can install [pypy](http://pypy.org/), a lightweight python interpreter. The coreos-bootstrap role will install pypy for us and we will update our inventory file to use the installed python interpreter. 17 | 18 | Current version: 0.6.3 19 | 20 | # install 21 | 22 | ``` 23 | ansible-galaxy install vmware.coreos-bootstrap 24 | ``` 25 | 26 | # Configure your project 27 | 28 | Unlike a typical role, you need to configure Ansible to use an alternative python interpreter for coreos hosts. This can be done by adding a `coreos` group to your inventory file and setting the group's vars to use the new python interpreter. This way, you can use ansible to manage CoreOS and non-CoreOS hosts. Simply put every host that has CoreOS into the `coreos` inventory group and it will automatically use the specified python interpreter. 29 | ``` 30 | [coreos] 31 | host-01 32 | host-02 33 | 34 | [coreos:vars] 35 | ansible_ssh_user=core 36 | ansible_python_interpreter="/home/core/bin/python" 37 | ``` 38 | 39 | This will configure ansible to use the python interpreter at `/home/core/bin/python` which will be created by the coreos-bootstrap role. 40 | 41 | ## Bootstrap Playbook 42 | 43 | Now you can simply add the following to your playbook file and include it in your `site.yml` so that it runs on all hosts in the coreos group. 44 | 45 | ```yaml 46 | - hosts: coreos 47 | gather_facts: False 48 | roles: 49 | - vmware.coreos-bootstrap 50 | ``` 51 | 52 | Make sure that `gather_facts` is set to false, otherwise ansible will try to first gather system facts using python which is not yet installed! 53 | 54 | ## Example Playbook 55 | 56 | After bootstrap, you can use ansible as usual to manage system services, install python modules (via pip), and run containers. Below is a basic example that starts the `etcd` service, installs the `docker-py` module and then uses the ansible `docker` module to pull and start a basic nginx container. 57 | 58 | ```yaml 59 | - name: Nginx Example 60 | hosts: web 61 | tasks: 62 | - name: Start etcd 63 | service: name=etcd.service state=started 64 | sudo: yes 65 | sudo_user: root 66 | 67 | - name: Install docker-py 68 | pip: name=docker-py 69 | 70 | - name: pull container 71 | raw: docker pull nginx:1.7.1 72 | 73 | - name: launch nginx container 74 | docker: 75 | image="nginx:1.7.1" 76 | name="example-nginx" 77 | ports="8080:80" 78 | state=running 79 | ``` 80 | 81 | # License 82 | MIT 83 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for sigma.coreos-bootstrap 3 | coreos_ssl_certs: "/etc/ssl/certs" 4 | coreos_pkg_home: "/home/core" 5 | 6 | coreos_pypy_url: "https://bitbucket.org/squeaky/portable-pypy/downloads" 7 | coreos_pypy_flavor: "linux_x86_64-portable" 8 | coreos_pypy_version: "5.4.1" 9 | coreos_pypy_sha256: "0b59f8e69c7883d454fce6364ab01a5ec6a481ed7f0cc0f1612c3b0c253f7da4" 10 | 11 | ansible_facts_dir: "/etc/ansible/facts.d" 12 | -------------------------------------------------------------------------------- /files/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -x 5 | 6 | if [[ `stat -c '%U' $PKG_HOME 2>/dev/null || echo root` != `whoami` ]]; then 7 | SUDO="sudo" 8 | else 9 | SUDO="" 10 | fi 11 | 12 | PYPY_HOME="$PKG_HOME/pypy" 13 | PYPY_INSTALL="$PKG_HOME/.pypy" 14 | 15 | cd /tmp 16 | 17 | FILENAME="pypy-$PYPY_VERSION-$PYPY_FLAVOR.tar.bz2" 18 | curl --retry 5 -L -o "$FILENAME" "$PYPY_DOWNLOAD_URL/$FILENAME" 19 | 20 | if [[ -n "$PYPY_SHA256" ]]; then 21 | echo "$PYPY_SHA256 $FILENAME" > "$FILENAME.sha256" 22 | sha256sum -c "$FILENAME.sha256" 23 | fi 24 | 25 | tar -xjf "$FILENAME" 26 | rm -f "$FILENAME" 27 | 28 | $SUDO mkdir -p "$PYPY_INSTALL" 29 | $SUDO rm -rf "$PYPY_INSTALL" 30 | $SUDO mv -n "pypy-$PYPY_VERSION-$PYPY_FLAVOR" "$PYPY_INSTALL" 31 | 32 | # make sure PATH contains the location where pip, wheel and friends are 33 | # so that ansible knows where to find them 34 | # this is needed since ansible 2.1 changed the way ansible_python_interpreter 35 | # is parsed 36 | cat < "$PYPY_INSTALL/site-packages/sitecustomize.py" 37 | import os 38 | import sys 39 | 40 | os.environ["PATH"] += os.pathsep + os.path.sep.join([sys.prefix, "bin"]) 41 | EOF 42 | 43 | $SUDO mkdir -p `dirname "$PYPY_HOME"` 44 | $SUDO rm -rf "$PYPY_HOME" 45 | 46 | $SUDO "$PYPY_INSTALL/bin/pypy" "$PYPY_INSTALL/bin/virtualenv-pypy" --system-site-packages "$PYPY_HOME" 47 | 48 | $SUDO mkdir -p "$PKG_HOME/bin" 49 | 50 | $SUDO ln -sf "$PYPY_HOME/bin/python" "$PKG_HOME/bin/python" 51 | $SUDO ln -sf "$PYPY_HOME/bin/pip" "$PKG_HOME/bin/pip" 52 | $SUDO ln -sf "$PYPY_HOME/bin/wheel" "$PKG_HOME/bin/wheel" 53 | 54 | sudo mkdir -p "$ANSIBLE_FACTS_DIR" 55 | sudo chown `whoami` "$ANSIBLE_FACTS_DIR" 56 | 57 | PYPY_SSL_PATH=`$PYPY_INSTALL/bin/pypy -c 'from __future__ import print_function; import ssl; print(ssl.get_default_verify_paths().openssl_capath)'` 58 | 59 | if [ $PYPY_SSL_PATH != "None" ]; then 60 | sudo mkdir -p `dirname $PYPY_SSL_PATH` 61 | sudo ln -sf $COREOS_SSL_CERTS $PYPY_SSL_PATH 62 | fi 63 | 64 | PIP_VERSION=`$PYPY_HOME/bin/pip --version | awk '{ print $2 }'` 65 | WHEEL_VERSION=`$PYPY_HOME/bin/wheel version | awk '{ print $2 }'` 66 | 67 | # install needed modules 68 | $PYPY_HOME/bin/pip install docker-py 69 | 70 | cat > "$ANSIBLE_FACTS_DIR/bootstrap.fact" <