From a0f5e4ad5eeaabb8866ca32f99d4d24252064ed8 Mon Sep 17 00:00:00 2001 From: Florian Utz Date: Sat, 24 Feb 2018 21:15:23 +0100 Subject: [PATCH] add molecule --- .yamllint | 13 +++++ Makefile | 64 ++++++++++++++++++++++ molecule/default/Dockerfile.j2 | 13 +++++ molecule/default/INSTALL.rst | 16 ++++++ molecule/default/create.yml | 69 ++++++++++++++++++++++++ molecule/default/destroy.yml | 33 ++++++++++++ molecule/default/molecule.yml | 23 ++++++++ molecule/default/playbook.yml | 31 +++++++++++ molecule/default/prepare.yml | 5 ++ molecule/default/tests/test_default.py | 14 +++++ molecule/default/tests/test_default.pyc | Bin 0 -> 1021 bytes requirements.txt | 3 ++ 12 files changed, 284 insertions(+) create mode 100644 .yamllint create mode 100644 Makefile create mode 100644 molecule/default/Dockerfile.j2 create mode 100644 molecule/default/INSTALL.rst create mode 100644 molecule/default/create.yml create mode 100644 molecule/default/destroy.yml create mode 100644 molecule/default/molecule.yml create mode 100644 molecule/default/playbook.yml create mode 100644 molecule/default/prepare.yml create mode 100644 molecule/default/tests/test_default.py create mode 100644 molecule/default/tests/test_default.pyc create mode 100644 requirements.txt diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..3a2255e --- /dev/null +++ b/.yamllint @@ -0,0 +1,13 @@ +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + line-length: disable + # NOTE(retr0h): Templates no longer fail this lint rule. + # Uncomment if running old Molecule templates. + # truthy: disable diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..abcf7a6 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +# Makefile for Ubuntu1604-CIS +.PHONY: help +help: + @echo + @echo This Makefile is used to test this role. Typical use: + @echo + @echo ' make test' + @echo ' make clean' + @echo ' make compare' + @echo + @echo + @echo To use the isolated environment from this directory: + @echo + @echo ' make venv' + @echo ' . bin/activate' + @echo + @echo Molecule has built-in help + @echo + @echo ' molecule' + @echo + @echo "Run just the role 'molecule converge'" + @echo "Login to the VM 'molecule login'" + @echo + @echo To run an audit using 'molecule verify' see tests/test_default.yml + @echo To compare audit results between setups with docker vs vagrant run 'make compare' + +# virtualenv allows isolation of python libraries +.PHONY: venv +venv: bin/python + +bin/python: + ## System's python 2.7 needs only 2 things: + # pip is the package manager for python + pip -V || sudo easy_install pip + # virtualenv allows isolation of python libraries + virtualenv --version || sudo easy_install virtualenv + + # Now with those two we can isolate our test setup. + virtualenv . + bin/pip install -r requirements.txt + virtualenv --relocatable . + +# cleanup virtualenv and molecule leftovers +clean: + rm -rf .molecule bin lib include lib64 share + rm -f .Python pip-selfcheck.json + +.PHONY: lint +lint: bin/python + ( . bin/activate && find . -name "*.yml" |grep -v .molecule |xargs bin/yamllint ) + +.PHONY: test +test: bin/python + ( . bin/activate && bin/molecule test ) + +.PHONY: compare +compare: + rm -rf .molecule + cp vagrant.yml molecule.yml + molecule test + rm -rf .molecule + cp docker.yml molecule.yml + molecule test + diff tests/vagrant.txt tests/docker.txt diff --git a/molecule/default/Dockerfile.j2 b/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..9f689d9 --- /dev/null +++ b/molecule/default/Dockerfile.j2 @@ -0,0 +1,13 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get upgrade -y && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python2-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; fi diff --git a/molecule/default/INSTALL.rst b/molecule/default/INSTALL.rst new file mode 100644 index 0000000..e26493b --- /dev/null +++ b/molecule/default/INSTALL.rst @@ -0,0 +1,16 @@ +******* +Install +******* + +Requirements +============ + +* Docker Engine +* docker-py + +Install +======= + +.. code-block:: bash + + $ sudo pip install docker-py diff --git a/molecule/default/create.yml b/molecule/default/create.yml new file mode 100644 index 0000000..9cedc65 --- /dev/null +++ b/molecule/default/create.yml @@ -0,0 +1,69 @@ +--- +- name: Create + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + vars: + molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}" + molecule_ephemeral_directory: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}" + molecule_scenario_directory: "{{ lookup('env', 'MOLECULE_SCENARIO_DIRECTORY') }}" + molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}" + tasks: + - name: Create Dockerfiles from image names + template: + src: "{{ molecule_scenario_directory }}/Dockerfile.j2" + dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.image | regex_replace('[^a-zA-Z0-9_]', '_') }}" + with_items: "{{ molecule_yml.platforms }}" + register: platforms + + - name: Discover local Docker images + docker_image_facts: + name: "molecule_local/{{ item.item.name }}" + with_items: "{{ platforms.results }}" + register: docker_images + + - name: Build an Ansible compatible image + docker_image: + path: "{{ molecule_ephemeral_directory }}" + name: "molecule_local/{{ item.item.image }}" + dockerfile: "{{ item.item.dockerfile | default(item.invocation.module_args.dest) }}" + force: "{{ item.item.force | default(true) }}" + with_items: "{{ platforms.results }}" + when: platforms.changed or docker_images.results | map(attribute='images') | select('equalto', []) | list | count >= 0 + + - name: Create docker network(s) + docker_network: + name: "{{ item }}" + state: present + with_items: "{{ molecule_yml.platforms | molecule_get_docker_networks }}" + + - name: Create molecule instance(s) + docker_container: + name: "{{ item.name }}" + hostname: "{{ item.name }}" + image: "molecule_local/{{ item.image }}" + state: started + recreate: false + log_driver: json-file + command: "{{ item.command | default('bash -c \"while true; do sleep 10000; done\"') }}" + privileged: "{{ item.privileged | default(omit) }}" + volumes: "{{ item.volumes | default(omit) }}" + capabilities: "{{ item.capabilities | default(omit) }}" + exposed_ports: "{{ item.exposed_ports | default(omit) }}" + published_ports: "{{ item.published_ports | default(omit) }}" + ulimits: "{{ item.ulimits | default(omit) }}" + networks: "{{ item.networks | default(omit) }}" + dns_servers: "{{ item.dns_servers | default(omit) }}" + register: server + with_items: "{{ molecule_yml.platforms }}" + async: 7200 + poll: 0 + + - name: Wait for instance(s) creation to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: docker_jobs + until: docker_jobs.finished + retries: 300 + with_items: "{{ server.results }}" diff --git a/molecule/default/destroy.yml b/molecule/default/destroy.yml new file mode 100644 index 0000000..ec4da49 --- /dev/null +++ b/molecule/default/destroy.yml @@ -0,0 +1,33 @@ +--- +- name: Destroy + hosts: localhost + connection: local + gather_facts: false + no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}" + vars: + molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}" + molecule_yml: "{{ lookup('file', molecule_file) | molecule_from_yaml }}" + tasks: + - name: Destroy molecule instance(s) + docker_container: + name: "{{ item.name }}" + state: absent + force_kill: "{{ item.force_kill | default(true) }}" + register: server + with_items: "{{ molecule_yml.platforms }}" + async: 7200 + poll: 0 + + - name: Wait for instance(s) deletion to complete + async_status: + jid: "{{ item.ansible_job_id }}" + register: docker_jobs + until: docker_jobs.finished + retries: 300 + with_items: "{{ server.results }}" + + - name: Delete docker network(s) + docker_network: + name: "{{ item }}" + state: absent + with_items: "{{ molecule_yml.platforms | molecule_get_docker_networks }}" diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..e636baa --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,23 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint +platforms: + - name: instance + image: solita/ubuntu-systemd:latest + privileged: True + command: /sbin/init +provisioner: + name: ansible + lint: + name: ansible-lint + enabled: false +scenario: + name: default +verifier: + name: testinfra + lint: + name: flake8 diff --git a/molecule/default/playbook.yml b/molecule/default/playbook.yml new file mode 100644 index 0000000..f9487dd --- /dev/null +++ b/molecule/default/playbook.yml @@ -0,0 +1,31 @@ +--- +- name: Converge + hosts: all + vars: + ubuntu1604cis_skip_for_travis: true + ubuntu1604_selinux_disable: true + pre_tasks: + - name: install packages for testing under docker + apt: + name: "{{ item }}" + state: present + with_items: + - openssh-server + - name: pretask2 + file: + name: /boot/grub + state: directory + changed_when: False + - name: pretask3 + file: + name: /boot/grub/grub.cfg + state: touch + changed_when: False + - name: pretask3 + file: + name: /etc/default/grub + state: touch + changed_when: False + + roles: + - role: Ubuntu1604-CIS diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml new file mode 100644 index 0000000..5358b3b --- /dev/null +++ b/molecule/default/prepare.yml @@ -0,0 +1,5 @@ +--- +- name: Prepare + hosts: all + gather_facts: false + tasks: [] diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py new file mode 100644 index 0000000..eedd64a --- /dev/null +++ b/molecule/default/tests/test_default.py @@ -0,0 +1,14 @@ +import os + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + + +def test_hosts_file(host): + f = host.file('/etc/hosts') + + assert f.exists + assert f.user == 'root' + assert f.group == 'root' diff --git a/molecule/default/tests/test_default.pyc b/molecule/default/tests/test_default.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbd799e356acd3320a6fb53c7c5eea8424b56a4f GIT binary patch literal 1021 zcmdr~&2H2%5FRJnUs3jiP%pi3$)%eESA?jlAQmlKX%~>#OXS8*aq5jDds0!gdue$A zo{9(J0buNG+EU(tBp#2yjK3Lw!FZtW?BtxH`Yh5s!qxCqZ*-gk?Q>suAC0H@IrhE+C0bm3--7@xtoJZhZJ^%+j z_-+l-vF3@-G94OJ>Z@e{b9<43FM&CFXg|#`y_u+_=LHT zC2uv3noAtgSppUW%)MMY1i5W8z=qL~J!6SinVJMZY8-gKuX@y?(r(0Sr%tuZZClr* zqbIlv395#$p#7uJJqkVQcF(%aTZG8^LRnJ>qBDtk*WA9;pjU^@d}a5Y`TyGE+wf{> S1l_6E{u+k9Jc;OK`|%$)CnKf+ literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9c30eaf --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +molecule==2.9.0 +yamllint==1.11.0 +docker-py=1.10.6