From 784cfb9446fb37ddd650ea4777bb91db0d43dc8d Mon Sep 17 00:00:00 2001 From: Jeroen De Meerleer Date: Wed, 7 Apr 2021 09:49:14 +0200 Subject: [PATCH] Added vagrant environment --- .gitattributes | 12 +++ .gitignore | 34 ++++++++ .yamllint | 60 ++++++++++++++ LICENSE | 20 +++++ Vagrantfile | 165 +++++++++++++++++++++++++++++++++++++ ansible/group_vars/all.yml | 4 + ansible/group_vars/dev.yml | 38 +++++++++ ansible/site.yml | 8 ++ custom-vagrant-hosts.yml | 42 ++++++++++ scripts/forwardports.sh | 10 +++ scripts/inventory.py | 49 +++++++++++ test/runbats.sh | 74 +++++++++++++++++ vagrant-groups.yml | 15 ++++ vagrant-hosts.yml | 47 +++++++++++ 14 files changed, 578 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .yamllint create mode 100644 LICENSE create mode 100644 Vagrantfile create mode 100644 ansible/group_vars/all.yml create mode 100644 ansible/group_vars/dev.yml create mode 100644 ansible/site.yml create mode 100644 custom-vagrant-hosts.yml create mode 100644 scripts/forwardports.sh create mode 100755 scripts/inventory.py create mode 100755 test/runbats.sh create mode 100644 vagrant-groups.yml create mode 100644 vagrant-hosts.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c689819 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +# Default behaviour +* text=auto + +# Shell scripts should have Unix endings +*.sh text eol=lf +*.bats text eol=lf +*.py text eol=lf + +# Windows Batch or PowerShell scripts should have CRLF endings +*.bat text eol=crlf +*.ps1 text eol=crlf + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6103dd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# .gitignore + +# Hidden Vagrant-directory +.vagrant + +# Python development +.ropeproject + +# Backup files (e.g. Vim, Gedit, etc.) +*~ + +# Compiled Python +*.pyc + +# BATS installation +test/bats/ + +# Vagrant base boxes (you never know when someone puts one in the repository) +*.box + +# Directories containing roles imported from Ansible Galaxy +# (user.role notation) +ansible/roles/*.* + +# Ansible Retry-files +*.retry + +# Ansible fact cache +.ansible_cache/ + +*.log + +# MacOS +.DS_store \ No newline at end of file diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..1c68f03 --- /dev/null +++ b/.yamllint @@ -0,0 +1,60 @@ +# .yamllint -- Custom rules for linting Yaml code +# Longer line length (120) is allowed +--- + +rules: + braces: + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + colons: + max-spaces-before: 0 + max-spaces-after: 1 + commas: + max-spaces-before: 0 + min-spaces-after: 1 + max-spaces-after: 1 + comments: + level: warning + require-starting-space: true + min-spaces-from-content: 2 + comments-indentation: + level: warning + document-end: disable + document-start: + level: warning + present: true + empty-lines: + max: 2 + max-start: 0 + max-end: 0 + empty-values: + forbid-in-block-mappings: false + forbid-in-flow-mappings: false + hyphens: + max-spaces-after: 1 + indentation: + spaces: consistent + indent-sequences: true + check-multi-line-strings: false + key-duplicates: enable + key-ordering: disable + line-length: + max: 120 + level: warning + allow-non-breakable-words: true + allow-non-breakable-inline-mappings: false + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + level: warning + +# vim: ft=yaml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..db4b0b4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Bert Van Vreckem + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..49f9249 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,165 @@ +# One Vagrantfile to rule them all! +# +# This is a generic Vagrantfile that can be used without modification in +# a variety of situations. Hosts and their properties are specified in +# `vagrant-hosts.yml`. Provisioning is done by an Ansible playbook, +# `ansible/site.yml`. +# +# See https://github.com/bertvv/ansible-skeleton/ for details + +require 'rbconfig' +require 'yaml' + +# set default LC_ALL for all BOXES +ENV["LC_ALL"] = "en_US.UTF-8" + +# Set your default base box here +DEFAULT_BASE_BOX = 'bento/centos-7.6' + +# When set to `true`, Ansible will be forced to be run locally on the VM +# instead of from the host machine (provided Ansible is installed). +FORCE_LOCAL_RUN = false + +# +# No changes needed below this point +# + +VAGRANTFILE_API_VERSION = '2' +PROJECT_NAME = '/' + File.basename(Dir.getwd) + +# set custom vagrant-hosts file +vagrant_hosts = ENV['VAGRANT_HOSTS'] ? ENV['VAGRANT_HOSTS'] : 'vagrant-hosts.yml' +hosts = YAML.load_file(File.join(__dir__, vagrant_hosts)) + +vagrant_groups = ENV['VAGRANT_GROUPS'] ? ENV['VAGRANT_GROUPS'] : 'vagrant-groups.yml' +groups = YAML.load_file(File.join(__dir__, vagrant_groups)) + +# {{{ Helper functions + +def run_locally? + windows_host? || FORCE_LOCAL_RUN +end + +def windows_host? + Vagrant::Util::Platform.windows? +end + +# Set options for the network interface configuration. All values are +# optional, and can include: +# - ip (default = DHCP) +# - netmask (default value = 255.255.255.0 +# - mac +# - auto_config (if false, Vagrant will not configure this network interface +# - intnet (if true, an internal network adapter will be created instead of a +# host-only adapter) +def network_options(host) + options = {} + + if host.key?('ip') + options[:ip] = host['ip'] + options[:netmask] = host['netmask'] ||= '255.255.255.0' + else + options[:type] = 'dhcp' + end + + options[:mac] = host['mac'].gsub(/[-:]/, '') if host.key?('mac') + options[:auto_config] = host['auto_config'] if host.key?('auto_config') + options[:virtualbox__intnet] = true if host.key?('intnet') && host['intnet'] + options +end + +def custom_synced_folders(vm, host) + return unless host.key?('synced_folders') + folders = host['synced_folders'] + + folders.each do |folder| + vm.synced_folder folder['src'], folder['dest'], folder['options'] + end +end + +# }}} + + +# Set options for shell provisioners to be run always. If you choose to include +# it you have to add a cmd variable with the command as data. +# +# Use case: start symfony dev-server +# +# example: +# shell_always: +# - cmd: php /srv/google-dev/bin/console server:start 192.168.52.25:8080 --force +def shell_provisioners_always(vm, host) + if host.has_key?('shell_always') + scripts = host['shell_always'] + + scripts.each do |script| + vm.provision "shell", inline: script['cmd'], run: "always" + end + end +end + +# }}} + +# Adds forwarded ports to your Vagrant machine +# +# example: +# forwarded_ports: +# - guest: 88 +# host: 8080 +def forwarded_ports(vm, host) + if host.has_key?('forwarded_ports') + ports = host['forwarded_ports'] + + ports.each do |port| + vm.network "forwarded_port", guest: port['guest'], host: port['host'] + end + end +end + +def provision_ansible(node, host, groups) + ansible_mode = run_locally? ? 'ansible_local' : 'ansible' + node.vm.provision ansible_mode do |ansible| + ansible.compatibility_mode = '2.0' + if ! groups.nil? + ansible.groups = groups + end + ansible.playbook = host.key?('playbook') ? + "ansible/#{host['playbook']}" : + "ansible/site.yml" + ansible.become = true + end +end + +# }}} + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + + hosts.each do |host| + config.vm.define host['name'] do |node| + node.vm.box = host['box'] ||= DEFAULT_BASE_BOX + node.vm.box_url = host['box_url'] if host.key? 'box_url' + + node.vm.hostname = host['name'] + node.vm.network :private_network, network_options(host) + custom_synced_folders(node.vm, host) + shell_provisioners_always(node.vm, host) + forwarded_ports(node.vm, host) + + node.vm.provider :virtualbox do |vb| + vb.memory = host['memory'] if host.key? 'memory' + vb.cpus = host['cpus'] if host.key? 'cpus' + + # Add VM to a VirtualBox group + # WARNING: if the name of the current directory is the same as the + # host name, this will fail. + vb.customize ['modifyvm', :id, '--groups', PROJECT_NAME] + end + + # Ansible provisioning + provision_ansible(node, host, groups) + end + end +end + +# -*- mode: ruby -*- +# vi: ft=ruby : diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml new file mode 100644 index 0000000..b66ae83 --- /dev/null +++ b/ansible/group_vars/all.yml @@ -0,0 +1,4 @@ +# group_vars/all.yml +# Variables visible to all nodes +--- + diff --git a/ansible/group_vars/dev.yml b/ansible/group_vars/dev.yml new file mode 100644 index 0000000..4e52bff --- /dev/null +++ b/ansible/group_vars/dev.yml @@ -0,0 +1,38 @@ +# group_vars/dev.yml +# Variables visible to all dev-nodes +--- +apache_vhosts: + - servername: webcron.test + documentroot: /mnt/dev-root/public + extra_parameters: | + SuexecUserGroup vagrant vagrant +apache_packages: + - apache2 + - apache2-utils + - apache2-suexec-pristine +apache_mods_enabled: + - rewrite.load + - suexec.load + - headers.load + - proxy.load + - proxy_fcgi.load +apache_remove_default_vhost: true +php_version: "8.0" +php_packages_extra: [ "libapache2-mod-php{{ php_version }}" ] +php_enable_apc: true +php_date_timezone: "Europe/Brussels" +php_upload_max_filesize: 4G +php_post_max_size: 4G +php_memory_limit: 2G +php_xdebug_version: '3.0.3' +php_opcache_zend_extension: "opcache.so" +php_opcache_enable: "1" +php_opcache_enable_cli: "1" +php_opcache_memory_consumption: "128" +php_opcache_interned_strings_buffer: "8" +php_opcache_max_accelerated_files: "10000" +php_opcache_max_wasted_percentage: "5" +php_opcache_validate_timestamps: "1" +php_opcache_revalidate_path: "0" +php_opcache_revalidate_freq: "1" +php_opcache_max_file_size: "0" \ No newline at end of file diff --git a/ansible/site.yml b/ansible/site.yml new file mode 100644 index 0000000..408b274 --- /dev/null +++ b/ansible/site.yml @@ -0,0 +1,8 @@ +# site.yml +--- +- hosts: all + roles: + - geerlingguy.apache + - geerlingguy.php-versions + - geerlingguy.php + - geerlingguy.php-xdebug diff --git a/custom-vagrant-hosts.yml b/custom-vagrant-hosts.yml new file mode 100644 index 0000000..0575418 --- /dev/null +++ b/custom-vagrant-hosts.yml @@ -0,0 +1,42 @@ +# Vagrantfile file for create primary server with 1..n siebling server for simulate cloud enviroment + + +# vagrant_hosts.yml +# +# List of hosts to be created by Vagrant. This file controls the Vagrant +# settings, specifically host name and network settings. You should at least +# have a `name:`. Other optional settings that can be specified: +# +# * `ip`: by default, an IP will be assigned by DHCP. If you want a fixed +# addres, specify it. +# * `netmask`: by default, the network mask is `255.255.255.0`. If you want +# another one, it should be specified. +# * `mac`: The MAC address to be assigned to the NIC. Several notations are +# accepted, including "Linux-style" (`00:11:22:33:44:55`) and +# "Windows-style" (`00-11-22-33-44-55`). The separator characters can +# be omitted altogether (`001122334455`). +# * `intnet`: If set to `true`, the network interface will be attached to an +# internal network rather than a host-only adapter. +# * `forwarded_ports`: A list of forwarded ports. Required items are `host` and 'guest` +# * `auto_config`: If set to `false`, Vagrant will not attempt to configure +# the network interface. +# * `shell_always`: a list of shell scripts to be run after boot of the +# machine. Required field is `cmd` having the path +# * `synced_folders`: A list of dicts that specify synced folders. `src` and +# `dest` are mandatory, `options:` are optional. For the possible options, +# see the Vagrant documentation[1]. Keys of options should be prefixed with +# a colon, e.g. `:owner:`. +# +# To enable *provisioning*, add these hosts to site.yml and assign some roles. +# +# [1] http://docs.vagrantup.com/v2/synced-folders/basic_usage.html +--- +- name: primary + box: debian/stretch64 + + +- name: worker + box: debian/stretch64 + + + diff --git a/scripts/forwardports.sh b/scripts/forwardports.sh new file mode 100644 index 0000000..e9bb89a --- /dev/null +++ b/scripts/forwardports.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +echo 1 > /proc/sys/net/ipv4/ip_forward + +iptables -F +iptables -t nat -F +iptables -X + +iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.56.11:80 +iptables -t nat -A POSTROUTING -p tcp -d 192.168.56.11 --dport 80 -j MASQUERADE diff --git a/scripts/inventory.py b/scripts/inventory.py new file mode 100755 index 0000000..f499d3b --- /dev/null +++ b/scripts/inventory.py @@ -0,0 +1,49 @@ +#! /usr/bin/python +# coding=utf8 +# +# Inventory script for Ansible skeleton, to be used on Windows host systems + +import socket +import sys +from getopt import getopt, GetoptError + + +# +# Helper functions +# + + +def usage(): + print ("Usage: %s [OPTION]\n" + " --list list all hosts\n" + " --host=HOST gives extra info" + "about the specified host\n") % sys.argv[0] + + +def list_hosts(): + host_name = socket.gethostname() + print "{ \"all\": { \"hosts\": [\"%s\"] } }" % host_name + + +def host_info(host): + print "{}" + +# +# Parse command line +# + +try: + opts, args = getopt(sys.argv[1:], "lh:", ['list', 'host=']) +except GetoptError as err: + print str(err) + usage() + sys.exit(2) + +for opt, opt_arg in opts: + if opt in ('-l', '--list'): + list_hosts() + sys.exit(0) + if opt in ('-h', '--host'): + host_info(opt_arg) + else: + assert False, "unhandled option: %s" % opt diff --git a/test/runbats.sh b/test/runbats.sh new file mode 100755 index 0000000..9acf082 --- /dev/null +++ b/test/runbats.sh @@ -0,0 +1,74 @@ +#! /usr/bin/env bash +# +# Author: Bert Van Vreckem +# +# Run BATS test files in the current directory, and the ones in the subdirectory +# matching the host name. +# +# The script installs BATS if needed. It's best to put ${bats_install_dir} in +# your .gitignore. + +set -o errexit # abort on nonzero exitstatus +set -o nounset # abort on unbound variable + +#{{{ Variables + +test_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +bats_archive="v1.1.0.tar.gz" +bats_url="https://github.com/bats-core/bats-core/archive/${bats_archive}" +bats_install_dir="/opt" +bats="${bats_install_dir}/bats/libexec/bats" + +test_file_pattern="*.bats" + +# color definitions +Blue='\e[0;34m' +Yellow='\e[0;33m' +Reset='\e[0m' + +#}}} +#{{{ Functions + +# Usage: install_bats_if_needed +install_bats_if_needed() { + pushd "${bats_install_dir}" > /dev/null + if [[ ! -d "${bats_install_dir}/bats" ]]; then + wget "${bats_url}" + tar xf "${bats_archive}" + mv bats-* bats + rm "${bats_archive}" + fi + popd > /dev/null +} + +# find_tests DIR [MAX_DEPTH] +find_tests() { + local max_depth="" + if [ "$#" -eq "2" ]; then + max_depth="-maxdepth $2" + fi + + local tests + tests=$(find "$1" "${max_depth}" -type f -name "${test_file_pattern}" -printf '%p\n' 2> /dev/null) + + echo "${tests}" +} +#}}} +# Script proper + +install_bats_if_needed + +# List all test cases (i.e. files in the test dir matching the test file +# pattern) +# Tests to be run on all hosts +global_tests=$(find_tests "${test_dir}" 1) + +# Tests for individual hosts +host_tests=$(find_tests "${test_dir}/${HOSTNAME}") + +# Loop over test files +for test_case in ${global_tests} ${host_tests}; do + echo -e "${Blue}Running test ${Yellow}${test_case}${Reset}" + ${bats} "${test_case}" +done diff --git a/vagrant-groups.yml b/vagrant-groups.yml new file mode 100644 index 0000000..26c25e1 --- /dev/null +++ b/vagrant-groups.yml @@ -0,0 +1,15 @@ +# Ansible group definitions +# +# This should be a dictionary with group names as keys and a list of hosts that +# are members of the group as values. E.g. +# +# web: +# - web001 +# - web002 +# db: +# - db001 +# +# Leave the file empty if you do not want to define groups. +--- +dev: + - webcron.test \ No newline at end of file diff --git a/vagrant-hosts.yml b/vagrant-hosts.yml new file mode 100644 index 0000000..47c29ec --- /dev/null +++ b/vagrant-hosts.yml @@ -0,0 +1,47 @@ +# vagrant_hosts.yml +# +# List of hosts to be created by Vagrant. For more information about the +# possible settings, see the documentation at +# +--- +- name: webcron.test + box: bento/ubuntu-18.04 + ip: 192.168.56.11 + memory: 2048 + cpus: 2 + forwarded_ports: + - host: 80 + guest: 80 + synced_folders: + - src: ../webcron + dest: /mnt/dev-root + options: + :create: true + :owner: vagrant + :group: vagrant + :mount_options: ['dmode=0755', 'fmode=0755'] + +# Example of a more elaborate host definition +# - name: srv002 +# box: bento/fedora-28 +# memory: 2048 +# cpus: 2 +# ip: 172.20.0.10 +# netmask: 255.255.0.0 +# mac: '13:37:de:ad:be:ef' +# playbook: srv002.yml +# forwarded_ports: +# - host: 8080 +# guest: 80 +# - host: 8443 +# guest: 443 +# synced_folders: +# - src: test +# dest: /tmp/test +# - src: www +# dest: /var/www/html +# options: +# :create: true +# :owner: root +# :group: root +# :mount_options: ['dmode=0755', 'fmode=0644']