├── README ├── extras ├── .gitignore ├── oh-my-vagrant.pkla ├── update-omv.sh ├── make-vagrant-libvirt-rpm.sh ├── patch-bashrc.sh ├── git-pushx ├── get-xml-jenkins-job.sh ├── .rpmbuild │ └── SPECS │ │ └── vagrant-libvirt.spec ├── install-omv.sh ├── patch-hostmanager.sh ├── copr-build.py ├── post-push.git-hook ├── centos-ci.py └── vagrant.bashrc ├── vagrant ├── .gitignore ├── docker │ └── README ├── shell │ └── README ├── puppet │ ├── files │ │ └── README │ ├── hiera.yaml │ ├── hieradata │ │ └── common.yaml │ ├── modules │ │ └── Makefile │ └── manifests │ │ └── site.pp ├── kubernetes │ ├── applications │ │ └── README │ └── templates │ │ └── README ├── ansible │ └── modules │ │ └── README ├── sync.sh └── Vagrantfile ├── Gemfile ├── art ├── omv.png ├── Pacifico │ ├── Pacifico.ttf │ └── OFL.txt ├── Alfa_Slab_One │ ├── AlfaSlabOne-Regular.ttf │ └── OFL.txt └── omv.svg ├── .gitignore ├── vtest.sh ├── examples ├── README ├── debian.yaml ├── rhel.yaml ├── atomic.yaml ├── docker-build.yaml ├── shell-test.yaml ├── docker-subdirs.yaml ├── docker-kubernetes.yaml ├── shell.yaml ├── kubernetes-atomic.yaml ├── kubernetes-ansible.yaml ├── kubernetes.yaml ├── ansible.yaml ├── puppet-gluster.yaml └── ceph-deploy.yaml ├── INSTALL ├── .travis.yml ├── tag.sh ├── AUTHORS ├── TODO ├── COPYRIGHT ├── test.sh ├── .gitmodules ├── oh-my-vagrant.spec.in ├── bin └── omv.sh ├── README.md ├── Makefile ├── DOCUMENTATION.md └── COPYING /README: -------------------------------------------------------------------------------- 1 | Please see README.md 2 | -------------------------------------------------------------------------------- /extras/.gitignore: -------------------------------------------------------------------------------- 1 | vagrant-hostmanager/ 2 | .rpmbuild/ 3 | -------------------------------------------------------------------------------- /vagrant/.gitignore: -------------------------------------------------------------------------------- 1 | omv.yaml 2 | .vagrant/ 3 | .ssh/ 4 | -------------------------------------------------------------------------------- /vagrant/docker/README: -------------------------------------------------------------------------------- 1 | Put your Docker app's in here! :) 2 | -------------------------------------------------------------------------------- /vagrant/shell/README: -------------------------------------------------------------------------------- 1 | Put your shell scripts in here! :) 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'xdg' 4 | gem 'ruby-lint' 5 | -------------------------------------------------------------------------------- /art/omv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleidea/oh-my-vagrant/HEAD/art/omv.png -------------------------------------------------------------------------------- /vagrant/puppet/files/README: -------------------------------------------------------------------------------- 1 | This is: Oh My Vagrant! (https://ttboj.wordpress.com/) 2 | -------------------------------------------------------------------------------- /vagrant/kubernetes/applications/README: -------------------------------------------------------------------------------- 1 | Kubernetes applications go here. One per directory. 2 | -------------------------------------------------------------------------------- /vagrant/ansible/modules/README: -------------------------------------------------------------------------------- 1 | This directory contains ansible git repos that are managed automatically. 2 | -------------------------------------------------------------------------------- /art/Pacifico/Pacifico.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleidea/oh-my-vagrant/HEAD/art/Pacifico/Pacifico.ttf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | oh-my-vagrant-documentation.pdf 2 | screencasts/ 3 | old/ 4 | tmp/ 5 | rpmbuild/ 6 | jenkins_jobs.ini 7 | get-xml-jenkins-job.sh 8 | -------------------------------------------------------------------------------- /art/Alfa_Slab_One/AlfaSlabOne-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleidea/oh-my-vagrant/HEAD/art/Alfa_Slab_One/AlfaSlabOne-Regular.ttf -------------------------------------------------------------------------------- /vagrant/puppet/hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :backends: 3 | - yaml 4 | :yaml: 5 | :datadir: /etc/puppet/hieradata/ 6 | :hierarchy: 7 | - common 8 | -------------------------------------------------------------------------------- /vtest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ie 2 | 3 | # test suite for oh-my-vagrant patches... 4 | echo running vtest.sh 5 | vtest+ examples/shell-test.yaml 6 | -------------------------------------------------------------------------------- /vagrant/puppet/hieradata/common.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | welcome: 'This is: Oh My Vagrant! (https://ttboj.wordpress.com/)' 3 | # vim:expandtab ts=8 sw=8 sta 4 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | These are a bunch of omv.yaml example definitions. 2 | 3 | Please submit additional examples as patches. 4 | 5 | Happy Hacking! 6 | -------------------------------------------------------------------------------- /vagrant/kubernetes/templates/README: -------------------------------------------------------------------------------- 1 | Kubernetes templates for configuration go here. 2 | There is a maintained repository available at: 3 | 4 | https://github.com/purpleidea/omv-ktemplates 5 | -------------------------------------------------------------------------------- /extras/oh-my-vagrant.pkla: -------------------------------------------------------------------------------- 1 | [Allow vagrant libvirt management permissions] 2 | Identity=unix-group:vagrant 3 | Action=org.libvirt.unix.manage 4 | ResultAny=yes 5 | ResultInactive=yes 6 | ResultActive=yes 7 | -------------------------------------------------------------------------------- /extras/update-omv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # to invalid a stale cache, and update omv you can run: 4 | sudo dnf clean metadata --disablerepo=* --enablerepo=purpleidea-oh-my-vagrant 5 | sudo dnf update -y oh-my-vagrant 6 | -------------------------------------------------------------------------------- /vagrant/sync.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # TODO: quicken this operation by causing an rsync directly to /etc/puppet/ 4 | 5 | # stop on any error 6 | set -e 7 | 8 | # put fresh files into /vagrant on puppet master 9 | time vagrant rsync puppet 10 | 11 | # run puppet on puppet master which syncs files from /vagrant into /etc/puppet/ 12 | time vagrant provision puppet 13 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | On Fedora 21+ Oh-My-Vagrant is now available as a COPR: 2 | https://copr.fedoraproject.org/coprs/purpleidea/oh-my-vagrant/ 3 | https://ttboj.wordpress.com/2015/07/08/oh-my-vagrant-mainstream-mode-and-copr-rpms/ 4 | 5 | For CentOS/RHEL 7+ it is almost as easy to install. Please read: 6 | https://ttboj.wordpress.com/2015/08/11/vagrant-and-oh-my-vagrant-on-rhel7/ 7 | 8 | Happy Hacking! 9 | -------------------------------------------------------------------------------- /extras/make-vagrant-libvirt-rpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo hello > .rpmbuild/SOURCES/README 4 | tar -C .rpmbuild/SOURCES/ -cjf .rpmbuild/SOURCES/vagrant-libvirt-noop.tar.bz2 README 5 | # upload useless tarball to a server somewhere... 6 | rpmbuild --define "_topdir $(pwd)/.rpmbuild" -bs .rpmbuild/SPECS/vagrant-libvirt.spec 7 | rpmbuild --define "_topdir $(pwd)/.rpmbuild" -bb .rpmbuild/SPECS/vagrant-libvirt.spec 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 2.0.0 3 | notifications: 4 | irc: 5 | channels: 6 | - "irc.freenode.net#ohmyvagrant" 7 | template: 8 | - "%{repository} (%{commit}: %{author}): %{message}" 9 | - "More info : %{build_url}" 10 | on_success: always 11 | on_failure: always 12 | use_notice: false 13 | skip_join: false 14 | email: 15 | - travis-ci@shubin.ca 16 | script: 'make test' 17 | -------------------------------------------------------------------------------- /tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # TODO: don't run if current HEAD is already tagged (ensure this is idempotent) 3 | # take current HEAD with new version 4 | v=`git describe --match '[0-9]*\.[0-9]*\.[0-9]*' --tags --abbrev=0` 5 | t=`echo "${v%.*}.$((${v##*.}+1))"` # increment version 6 | echo "Version $t is now tagged!" 7 | echo "Pushing $t to origin..." 8 | echo "Press ^C within 3s to abort." 9 | sleep 3s 10 | git tag $t 11 | git push origin $t 12 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | This is a list of authors/contributors to the Oh-My-Vagrant project. 2 | If you're a contributor, please send a patch with your name. 3 | If you appreciate the work of one of the contributors, thank them a beverage! 4 | For a more exhaustive list please run: git log --format='%aN' | sort -u 5 | This list is sorted alphabetically by first name. 6 | 7 | Christoph Görn 8 | James Shubin 9 | Máirín Duffy 10 | Randy Barlow 11 | Scott Collier 12 | Vasyl "vk" Kaigorodov 13 | -------------------------------------------------------------------------------- /extras/patch-bashrc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # this script will patch your ~/.bashrc with some awesome addons! 4 | 5 | if ! grep -F '.bashrc.vagrant' ~/.bashrc; then 6 | cp vagrant.bashrc ~/.bashrc.vagrant 7 | echo 'if [ -f ~/.bashrc.vagrant ]; then' >> ~/.bashrc 8 | echo -e "\t. ~/.bashrc.vagrant" >> ~/.bashrc 9 | echo 'fi' >> ~/.bashrc 10 | echo 'Patched successfully!' 11 | else 12 | echo 'Script could not proceed automatically. Already patched?' 13 | exit 1 14 | fi 15 | -------------------------------------------------------------------------------- /extras/git-pushx: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # adds git pre-push and post-push hooks 3 | # modified from a script found on the internet 4 | 5 | GIT_DIR_="$(git rev-parse --git-dir)" 6 | e=$? 7 | if [ $e -ne 0 ]; then 8 | exit $e 9 | fi 10 | BRANCH="$(git rev-parse --symbolic --abbrev-ref $(git symbolic-ref HEAD))" 11 | 12 | PRE_PUSH="$GIT_DIR_/hooks/pre-push" 13 | POST_PUSH="$GIT_DIR_/hooks/post-push" 14 | 15 | test -x "$PRE_PUSH" && exec "$PRE_PUSH" "$BRANCH" "$@" 16 | 17 | git push "$@" 18 | 19 | test $? -eq 0 && test -x "$POST_PUSH" && exec "$POST_PUSH" "$BRANCH" "$@" 20 | -------------------------------------------------------------------------------- /examples/debian.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: debian-8 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: [] 15 | :cd: '' 16 | :puppet: false 17 | :classes: [] 18 | :shell: [] 19 | :docker: false 20 | :kubernetes: false 21 | :ansible: [] 22 | :playbook: [] 23 | :ansible_extras: {} 24 | :cachier: false 25 | :vms: [] 26 | :namespace: omv 27 | :count: 1 28 | :username: '' 29 | :password: '' 30 | :poolid: true 31 | :repos: [] 32 | :update: false 33 | :reboot: false 34 | :unsafe: false 35 | :nested: false 36 | :tests: [] 37 | :comment: '' 38 | :reallyrm: false 39 | -------------------------------------------------------------------------------- /examples/rhel.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: rhel-7.1-iso 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: [] 15 | :cd: '' 16 | :puppet: false 17 | :classes: [] 18 | :shell: [] 19 | :docker: false 20 | :kubernetes: false 21 | :ansible: [] 22 | :playbook: [] 23 | :ansible_extras: {} 24 | :cachier: false 25 | :vms: [] 26 | :namespace: omv 27 | :count: 1 28 | :username: '' 29 | :password: '' 30 | :poolid: true 31 | :repos: [] 32 | :update: false 33 | :reboot: false 34 | :unsafe: false 35 | :nested: false 36 | :tests: [] 37 | :comment: simple rhel example 38 | :reallyrm: false 39 | -------------------------------------------------------------------------------- /examples/atomic.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: atomic-fedora-22 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: [] 15 | :cd: '' 16 | :puppet: false 17 | :classes: [] 18 | :shell: [] 19 | :docker: false 20 | :kubernetes: false 21 | :ansible: [] 22 | :playbook: [] 23 | :ansible_extras: {} 24 | :cachier: false 25 | :vms: [] 26 | :namespace: omv 27 | :count: 1 28 | :username: '' 29 | :password: '' 30 | :poolid: true 31 | :repos: [] 32 | :update: false 33 | :reboot: false 34 | :unsafe: false 35 | :nested: false 36 | :tests: [] 37 | :comment: simple atomic example 38 | :reallyrm: false 39 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TODO 2 | 3 | * Add nested virt test to see if host has it enabled 4 | ** dustymabe+stribny will patch this 5 | *** http://dustymabe.com/2013/07/14/find-guest-ip-address-using-qemu-guest-agent/ 6 | * Add automatic qemu agent + virtualbox agent installation 7 | ** lala(virtualbox) + dustymabe(vagrant-libvirt) will work on this patch 8 | * Have a way to pass structured or non-string facts into the vms. 9 | ** Puppet could support a B64FACTER_name=... where the data is a base64 yaml. 10 | *** This would be useful anyways, but isn't the ideal approach for vagrant. 11 | ** One way could be to write to /etc/facter/facts.d/ before each puppet run. 12 | *** https://github.com/mitchellh/vagrant/issues/4762 13 | * Provide a way to add parameters to the classes we include. 14 | * Add some documentation. 15 | -------------------------------------------------------------------------------- /extras/get-xml-jenkins-job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # download a job configuration file 4 | # TODO: convert this to something jenkins-jobs can upload 5 | 6 | JENKINS_BASE='https://ci.centos.org' 7 | JENKINS_USERNAME='purpleidea' # TODO: set this 8 | JENKINS_PASSWORD='hunter2' # TODO: set this 9 | JENKINS_JOB='purpleidea-oh-my-vagrant' # TODO: set this 10 | 11 | # login first 12 | wget -q -O - --save-cookies cookies.txt --post-data "j_username=${JENKINS_USERNAME}&j_password=${JENKINS_PASSWORD}&remember_me=on&Submit=log+in" "${JENKINS_BASE}/j_acegi_security_check" 1> /dev/null 13 | # download the job 14 | # eg: https://ci.centos.org/job/purpleidea-oh-my-vagrant/config.xml 15 | wget -q -O - --load-cookies cookies.txt "${JENKINS_BASE}/job/${JENKINS_JOB}/config.xml" > config.xml 16 | # clean up the crumbs 17 | rm -rf cookies.txt 18 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012-2015+ James Shubin and the Oh-My-Vagrant contributors 2 | Written by James Shubin and the Oh-My-Vagrant contributors 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | -------------------------------------------------------------------------------- /examples/docker-build.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-7.1-docker 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: docker 17 | repository: https://github.com/purpleidea/docker-simple1 18 | directory: docker-simple1 19 | :cd: '' 20 | :puppet: false 21 | :classes: [] 22 | :shell: [] 23 | :docker: [] 24 | :kubernetes: false 25 | :ansible: [] 26 | :playbook: [] 27 | :ansible_extras: {} 28 | :cachier: false 29 | :vms: [] 30 | :namespace: omv 31 | :count: 1 32 | :username: '' 33 | :password: '' 34 | :poolid: true 35 | :repos: [] 36 | :update: false 37 | :reboot: false 38 | :unsafe: false 39 | :nested: false 40 | :tests: [] 41 | :comment: simple docker build example 42 | :reallyrm: false 43 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # test suite for oh-my-vagrant patches... 4 | echo running test.sh 5 | 6 | # ensure there is no trailing whitespace or other whitespace errors 7 | git diff-tree --check $(git hash-object -t tree /dev/null) HEAD 8 | 9 | # ensure entries to authors file are sorted 10 | start=$(($(grep -n '^[[:space:]]*$' AUTHORS | awk -F ':' '{print $1}' | head -1) + 1)) 11 | diff <(tail -n +$start AUTHORS | sort) <(tail -n +$start AUTHORS) 12 | 13 | # ensure we pass basic ruby-lint checks 14 | if which ruby-lint &>/dev/null; then # don't fail if not installed 15 | # TODO i would like to add on: 16 | # -a undefined_methods -a undefined_variables 17 | # but valid vagrant causes these to break at the moment. 18 | # if this is fixed remove all the -a arguments for default use! 19 | ruby-lint -a argument_amount -a loop_keywords -a pedantics -a shadowing_variables -a unused_variables -a useless_equality_checks vagrant/Vagrantfile 20 | fi 21 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vagrant/puppet/modules/module-data"] 2 | path = vagrant/puppet/modules/module-data 3 | url = https://github.com/ripienaar/puppet-module-data/ 4 | [submodule "vagrant/puppet/modules/stdlib"] 5 | path = vagrant/puppet/modules/stdlib 6 | url = https://github.com/puppetlabs/puppetlabs-stdlib 7 | [submodule "vagrant/puppet/modules/yum"] 8 | path = vagrant/puppet/modules/yum 9 | url = https://github.com/purpleidea/puppet-yum 10 | [submodule "vagrant/puppet/modules/puppet"] 11 | path = vagrant/puppet/modules/puppet 12 | url = https://github.com/purpleidea/puppet-puppet 13 | [submodule "vagrant/p4h"] 14 | path = vagrant/p4h 15 | url = https://github.com/purpleidea/p4h 16 | [submodule "vagrant/xdg"] 17 | path = vagrant/gems/xdg 18 | url = https://github.com/rubyworks/xdg 19 | [submodule "vagrant/kubernetes/templates/default"] 20 | path = vagrant/kubernetes/templates/default 21 | url = https://github.com/purpleidea/omv-ktemplates 22 | -------------------------------------------------------------------------------- /examples/shell-test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-7.1 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: [] 15 | :cd: '' 16 | :puppet: false 17 | :classes: [] 18 | :shell: 19 | - script: echo hello world > /tmp/hello1 20 | once: true 21 | - echo hello again > /tmp/hello2 22 | :docker: [] 23 | :kubernetes: false 24 | :ansible: [] 25 | :playbook: [] 26 | :ansible_extras: {} 27 | :cachier: false 28 | :vms: [] 29 | :namespace: omv 30 | :count: 1 31 | :username: '' 32 | :password: '' 33 | :poolid: true 34 | :repos: [] 35 | :update: false 36 | :reboot: false 37 | :unsafe: false 38 | :nested: false 39 | :tests: 40 | - echo These tests should be run with vtest+ 41 | - omv up 42 | - vssh root@omv1 -c test -e /tmp/hello1 -a -e /tmp/hello2 43 | - omv destroy 44 | :comment: simple shell run example with test 45 | :reallyrm: false 46 | -------------------------------------------------------------------------------- /extras/.rpmbuild/SPECS/vagrant-libvirt.spec: -------------------------------------------------------------------------------- 1 | %global project_version 0.0.24 2 | 3 | Name: vagrant-libvirt 4 | Version: 0.0.24 5 | #Release: __RELEASE__%{?dist} # use this to make dist specific builds 6 | Release: noop 7 | Summary: A fake vagrant-libvirt RPM 8 | License: AGPLv3+ 9 | URL: https://github.com/purpleidea/oh-my-vagrant 10 | Source0: https://dl.fedoraproject.org/pub/alt/purpleidea/oh-my-vagrant/SOURCES/vagrant-libvirt-noop.tar.bz2 11 | BuildArch: noarch 12 | 13 | Requires: vagrant >= 1.6.5 14 | 15 | %description 16 | A fake vagrant-libvirt RPM 17 | 18 | %prep 19 | %setup -c -q -T -D -a 0 20 | 21 | %build 22 | 23 | %install 24 | rm -rf %{buildroot} 25 | # _datadir is typically /usr/share/ 26 | install -d -m 0755 %{buildroot}/%{_datadir}/vagrant-libvirt/ 27 | echo "This is a phony vagrant-libvirt package." > %{buildroot}/%{_datadir}/vagrant-libvirt/README 28 | 29 | %files 30 | %{_datadir}/vagrant-libvirt/README 31 | 32 | # this changelog is auto-generated by git log 33 | %changelog 34 | -------------------------------------------------------------------------------- /examples/docker-subdirs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-7.1-docker 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: docker 17 | repository: https://github.com/fedora-cloud/Fedora-Dockerfiles 18 | directory: Fedora-Dockerfiles 19 | :cd: '' 20 | :puppet: false 21 | :classes: [] 22 | :shell: [] 23 | :docker: 24 | images: [] 25 | files: 26 | - Fedora-Dockerfiles/apache 27 | - Fedora-Dockerfiles/wordpress 28 | :kubernetes: false 29 | :ansible: [] 30 | :playbook: [] 31 | :ansible_extras: {} 32 | :cachier: false 33 | :vms: [] 34 | :namespace: omv 35 | :count: 1 36 | :username: '' 37 | :password: '' 38 | :poolid: true 39 | :repos: [] 40 | :update: false 41 | :reboot: false 42 | :unsafe: false 43 | :nested: false 44 | :tests: [] 45 | :comment: sub folder simple docker file build example 46 | :reallyrm: false 47 | -------------------------------------------------------------------------------- /examples/docker-kubernetes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-7.1-docker 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: docker 17 | repository: https://github.com/purpleidea/docker-simple1 18 | directory: docker-simple1 19 | - type: git 20 | system: kubernetes 21 | repository: https://github.com/purpleidea/kube-simple1 22 | directory: kube-simple1 23 | :cd: '' 24 | :puppet: false 25 | :classes: [] 26 | :shell: [] 27 | :docker: [] 28 | :kubernetes: 29 | applications: 30 | - kube-simple1/simple1.json 31 | :ansible: [] 32 | :playbook: [] 33 | :ansible_extras: {} 34 | :cachier: false 35 | :vms: [] 36 | :namespace: omv 37 | :count: 3 38 | :username: '' 39 | :password: '' 40 | :poolid: true 41 | :repos: [] 42 | :update: false 43 | :reboot: false 44 | :unsafe: false 45 | :nested: false 46 | :tests: [] 47 | :comment: simple docker kubernetes example 48 | :reallyrm: false 49 | -------------------------------------------------------------------------------- /examples/shell.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-7.1 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: shell 17 | repository: https://github.com/purpleidea/shell-simple1 18 | directory: shell-simple1 19 | :cd: '' 20 | :puppet: false 21 | :classes: [] 22 | :shell: 23 | - shell-simple1/hello1.sh 24 | - shell-simple1/hello2.py 25 | - path: shell-simple1/subdirectory/hello3.sh 26 | once: false 27 | - script: echo hello world > /tmp/hello4 28 | once: true 29 | - echo hello again > /tmp/hello5 30 | :docker: [] 31 | :kubernetes: false 32 | :ansible: [] 33 | :playbook: [] 34 | :ansible_extras: {} 35 | :cachier: false 36 | :vms: [] 37 | :namespace: omv 38 | :count: 1 39 | :username: '' 40 | :password: '' 41 | :poolid: true 42 | :repos: [] 43 | :update: false 44 | :reboot: false 45 | :unsafe: false 46 | :nested: false 47 | :tests: [] 48 | :comment: simple shell run example 49 | :reallyrm: false 50 | -------------------------------------------------------------------------------- /examples/kubernetes-atomic.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: atomic-fedora-22 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: docker 17 | repository: https://github.com/purpleidea/docker-simple1 18 | directory: docker-simple1 19 | - type: git 20 | system: kubernetes 21 | repository: https://github.com/purpleidea/kube-simple1 22 | directory: kube-simple1 23 | :cd: '' 24 | :puppet: false 25 | :classes: [] 26 | :shell: [] 27 | :docker: [] 28 | :kubernetes: 29 | applications: 30 | - kube-simple1/simple1.json 31 | :ansible: [] 32 | :playbook: [] 33 | :ansible_extras: {} 34 | :cachier: false 35 | :vms: [] 36 | :namespace: omv 37 | :count: 3 38 | :username: '' 39 | :password: '' 40 | :poolid: true 41 | :repos: [] 42 | :update: false 43 | :reboot: false 44 | :unsafe: false 45 | :nested: false 46 | :tests: [] 47 | :comment: 'simple kubernetes on atomic example without cached images' 48 | :reallyrm: false 49 | -------------------------------------------------------------------------------- /examples/kubernetes-ansible.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: fedora-21 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: ansible 17 | repository: https://github.com/eparis/kubernetes-ansible 18 | directory: kubernetes 19 | :cd: '' 20 | :puppet: false 21 | :classes: [] 22 | :shell: [] 23 | :docker: false 24 | :kubernetes: false 25 | :ansible: 26 | - kubernetes/setup.yml 27 | :playbook: [] 28 | :ansible_extras: {} 29 | :cachier: false 30 | :vms: 31 | - :name: master1 32 | :ansible: 33 | - masters 34 | - etcd 35 | :playbook: 36 | - kubernetes/setup.yml 37 | - :name: minion1 38 | :ansible: 39 | - minions 40 | - :name: minion2 41 | :ansible: 42 | - minions 43 | :namespace: omv 44 | :count: 0 45 | :username: '' 46 | :password: '' 47 | :poolid: true 48 | :repos: [] 49 | :update: false 50 | :reboot: false 51 | :unsafe: false 52 | :nested: false 53 | :tests: [] 54 | :comment: '' 55 | :reallyrm: false 56 | -------------------------------------------------------------------------------- /examples/kubernetes.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-7.1-docker 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: kubernetes 17 | repository: ~/code/kubernetes-simple1 18 | directory: fakeapp1 19 | - type: git 20 | system: kubernetes 21 | repository: ~/code/kubernetes-simple2 22 | directory: fakeapp2 23 | :cd: '' 24 | :puppet: false 25 | :classes: [] 26 | :shell: [] 27 | :docker: [] 28 | :kubernetes: 29 | master: omv0 30 | applications: 31 | - fakeapp1/foo1.json 32 | - file: fakeapp1/foo2.json 33 | roll: 'true' 34 | - fakeapp2/foo.json 35 | :ansible: [] 36 | :playbook: [] 37 | :ansible_extras: {} 38 | :cachier: false 39 | :vms: [] 40 | :namespace: omv 41 | :count: 3 42 | :username: '' 43 | :password: '' 44 | :poolid: true 45 | :repos: [] 46 | :update: false 47 | :reboot: false 48 | :unsafe: false 49 | :nested: false 50 | :tests: [] 51 | :comment: fake kubernetes example 52 | :reallyrm: false 53 | -------------------------------------------------------------------------------- /examples/ansible.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: fedora-21 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: ansible 17 | repository: https://github.com/purpleidea/ansible-simple1 18 | directory: ansible-simple1 19 | :cd: '' 20 | :puppet: false 21 | :classes: [] 22 | :shell: [] 23 | :docker: false 24 | :kubernetes: false 25 | :ansible: 26 | - ansible-simple1/setup.yml 27 | :playbook: [] 28 | :ansible_extras: {} 29 | :cachier: false 30 | :vms: 31 | - :name: primary1 32 | :ansible: 33 | - primary 34 | - machine 35 | :playbook: 36 | - ansible-simple1/primary.yml 37 | - :name: secondary1 38 | :ansible: 39 | - secondary 40 | - machine 41 | - :name: secondary2 42 | :ansible: 43 | - secondary 44 | - machine 45 | :namespace: omv 46 | :count: 0 47 | :username: '' 48 | :password: '' 49 | :poolid: true 50 | :repos: [] 51 | :update: false 52 | :reboot: false 53 | :unsafe: false 54 | :nested: false 55 | :tests: [] 56 | :comment: '' 57 | :reallyrm: false 58 | -------------------------------------------------------------------------------- /extras/install-omv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # this is a useful script for getting your centos-7.x ci infra setup, based on: 4 | # https://ttboj.wordpress.com/2015/08/11/vagrant-and-oh-my-vagrant-on-rhel7/ 5 | 6 | cat /etc/redhat-release | grep CentOS # check this is a CentOS machine 7 | sudo yum install -y gcc ruby-devel libvirt-devel libvirt qemu-kvm wget 8 | sudo systemctl start libvirtd.service 9 | wget https://releases.hashicorp.com/vagrant/1.7.4/vagrant_1.7.4_x86_64.rpm 10 | sudo yum install -y vagrant_1.7.4_x86_64.rpm 11 | vagrant plugin install vagrant-libvirt 12 | wget https://copr.fedoraproject.org/coprs/purpleidea/vagrant-libvirt/repo/epel-7/purpleidea-vagrant-libvirt-epel-7.repo 13 | sudo cp -a purpleidea-vagrant-libvirt-epel-7.repo /etc/yum.repos.d/ 14 | sudo yum install -y vagrant-libvirt # noop plugin for oh-my-vagrant dependency 15 | wget https://copr.fedoraproject.org/coprs/purpleidea/oh-my-vagrant/repo/epel-7/purpleidea-oh-my-vagrant-epel-7.repo 16 | sudo cp -a purpleidea-oh-my-vagrant-epel-7.repo /etc/yum.repos.d/ 17 | sudo yum install -y oh-my-vagrant 18 | . /etc/profile.d/oh-my-vagrant.sh # logout/login or source 19 | yes | omv init # install plugins 20 | -------------------------------------------------------------------------------- /examples/puppet-gluster.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: centos-6 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: 15 | - type: git 16 | system: puppet 17 | repository: https://github.com/purpleidea/puppet-common 18 | directory: common 19 | - type: git 20 | system: puppet 21 | repository: https://github.com/purpleidea/puppet-gluster 22 | directory: gluster 23 | - type: git 24 | system: puppet 25 | repository: https://github.com/purpleidea/puppet-keepalived 26 | directory: keepalived 27 | - type: git 28 | system: puppet 29 | repository: https://github.com/purpleidea/puppet-shorewall 30 | directory: shorewall 31 | :cd: '' 32 | :puppet: true 33 | :classes: 34 | '::gluster::simple': 35 | replica: 2 36 | volume: 37 | - puppet 38 | vrrp: true 39 | vip: 192.168.123.3 40 | :shell: [] 41 | :docker: false 42 | :kubernetes: false 43 | :ansible: [] 44 | :playbook: 45 | :ansible_extras: {} 46 | :cachier: false 47 | :vms: 48 | - :name: client1 49 | :classes: 50 | module1: 51 | arg1: val1 52 | arg2: val2 53 | module2: 54 | :namespace: annex 55 | :count: 4 56 | :username: '' 57 | :password: '' 58 | :poolid: true 59 | :repos: [] 60 | :update: false 61 | :reboot: false 62 | :unsafe: false 63 | :nested: false 64 | :tests: [] 65 | :comment: contrived puppet-gluster example 66 | :reallyrm: false 67 | -------------------------------------------------------------------------------- /extras/patch-hostmanager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # this script will install vagrant-hostmanager and patch it with the extra 4 | # features that are needed for oh-my-vagrant until they are upstream! 5 | # https://github.com/smdahlen/vagrant-hostmanager/pull/145 6 | 7 | # NOTE: some users have needed the following dependencies for this script: 8 | # 9 | # sudo dnf install ruby-devel libvirt-devel libxslt-devel libxml2-devel 10 | # gem install domain_name -v 0.5.24 11 | # gem install net-ssh -v '2.9.2' 12 | # 13 | # NOTE: it is recommended to run the 'gem install' commands as the user 14 | # NOTE: it is recommended to pick the versions as prompted on errors... 15 | 16 | vagrant plugin list | grep -qF 'vagrant-hostmanager' 17 | if [ $? -ne 0 ]; then 18 | vagrant plugin install --plugin-version 1.5.0 vagrant-hostmanager 19 | fi 20 | 21 | vagrant plugin list | grep -qF 'vagrant-hostmanager (1.5.0)' 22 | if [ $? -ne 0 ]; then 23 | echo 'Version of vagrant-hostmanager must be 1.5.0 for this script!' 24 | exit 1 25 | fi 26 | 27 | tempd=`mktemp -d` 28 | cd $tempd && git clone https://github.com/purpleidea/vagrant-hostmanager 29 | if [ ! -d 'vagrant-hostmanager' ]; then 30 | echo 'Problem cloning vagrant-hostmanager!' 31 | exit 1 32 | fi 33 | 34 | cd vagrant-hostmanager/ 35 | git checkout feat/oh-my-vagrant || ( 36 | echo 'Problem finding branch!' 37 | exit 1 38 | ) 39 | 40 | if [ -e ~/.vagrant.d/gems/gems/vagrant-hostmanager-1.5.0/ ]; then 41 | rsync -av --delete . ~/.vagrant.d/gems/gems/vagrant-hostmanager-1.5.0/ 42 | else 43 | echo 'Problem copying code!' 44 | exit 1 45 | fi 46 | 47 | echo 'Patched successfully!' 48 | -------------------------------------------------------------------------------- /examples/ceph-deploy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :domain: example.com 3 | :network: 192.168.123.0/24 4 | :image: fedora-23 5 | :cpus: '' 6 | :memory: '' 7 | :disks: 0 8 | :disksize: 40G 9 | :boxurlprefix: '' 10 | :sync: rsync 11 | :syncdir: '' 12 | :syncsrc: '' 13 | :folder: '' 14 | :extern: [] 15 | :cd: '' 16 | :puppet: false 17 | :classes: [] 18 | :shell: 19 | - script: | 20 | echo this is ceph-deploy on fedora-23 21 | dnf install -y ceph-deploy 22 | mkdir ceph-deploy 23 | cd ceph-deploy 24 | export CEPH_HOST=`hostname -f` 25 | ceph-deploy new $CEPH_HOST 26 | echo "osd crush chooseleaf type = 0" >> ceph.conf 27 | echo "osd pool default size = 1" >> ceph.conf 28 | ceph-deploy install --no-adjust-repos $CEPH_HOST 29 | ceph-deploy mon create-initial 30 | mkdir -p /srv/ceph/osd 31 | ceph-deploy osd prepare $CEPH_HOST:/srv/ceph/osd 32 | ceph-deploy osd activate $CEPH_HOST:/srv/ceph/osd 33 | ceph status 34 | #ceph-deploy purgedata $CEPH_HOST 35 | #ceph-deploy purge $CEPH_HOST 36 | #ceph-deploy forgetkeys 37 | #rm -rf /srv/ceph/osd 38 | echo you can now use ceph with the rbd command 39 | once: true 40 | :docker: false 41 | :kubernetes: false 42 | :ansible: [] 43 | :playbook: [] 44 | :ansible_extras: {} 45 | :cachier: false 46 | :vms: [] 47 | :namespace: omv 48 | :count: 1 49 | :username: '' 50 | :password: '' 51 | :poolid: true 52 | :repos: [] 53 | :update: false 54 | :reboot: false 55 | :unsafe: false 56 | :nested: false 57 | :tests: [] 58 | :comment: 'based on: https://www.berrange.com/posts/2015/12/21/ceph-single-node-deployment-on-fedora-23/' 59 | :reallyrm: false 60 | -------------------------------------------------------------------------------- /extras/copr-build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # README: 4 | # for initial setup, browse to: https://copr.fedoraproject.org/api/ 5 | # and it will have a ~/.config/copr config that you can download. 6 | # happy hacking! 7 | 8 | import os 9 | import sys 10 | import copr 11 | import time 12 | 13 | COPR = 'oh-my-vagrant' 14 | 15 | if len(sys.argv) != 2: 16 | print("Usage: %s " % sys.argv[0]) 17 | sys.exit(1) 18 | 19 | url = sys.argv[1] 20 | 21 | client = copr.CoprClient.create_from_file_config(os.path.expanduser("~/.config/copr")) 22 | 23 | result = client.create_new_build(COPR, [url]) 24 | if result.output != 'ok': 25 | print(result.error) 26 | sys.exit(1) 27 | print(result.message) 28 | 29 | # modified from: https://python-copr.readthedocs.org/en/latest/Examples.html#work-with-builds 30 | for bw in result.builds_list: 31 | print("Build #{}: {}".format(bw.build_id, bw.handle.get_build_details().status)) 32 | 33 | # cancel all created build 34 | #for bw in result.builds_list: 35 | # bw.handle.cancel_build() 36 | 37 | # get build status for each chroot 38 | #for bw in result.builds_list: 39 | # print("build: {}".format(bw.build_id)) 40 | # for ch, status in bw.handle.get_build_details().data["chroots"].items(): 41 | # print("\t chroot {}:\t {}".format(ch, status)) 42 | 43 | # simple build progress: 44 | 45 | watched = set(result.builds_list) 46 | done = set() 47 | state = {} 48 | for bw in watched: # store initial states 49 | state[bw.build_id] = bw.handle.get_build_details().status 50 | 51 | while watched != done: 52 | for bw in watched: 53 | if bw in done: 54 | continue 55 | status = bw.handle.get_build_details().status 56 | if status != state.get(bw.build_id): 57 | print("Build #{}: {}".format(bw.build_id, status)) 58 | state[bw.build_id] = status # update status 59 | 60 | if status in ['skipped', 'failed', 'succeeded']: 61 | done.add(bw) 62 | 63 | if watched == done: break # avoid long while sleep 64 | else: time.sleep(10) 65 | 66 | print 'Done!' 67 | -------------------------------------------------------------------------------- /oh-my-vagrant.spec.in: -------------------------------------------------------------------------------- 1 | %global project_version __VERSION__ 2 | 3 | Name: oh-my-vagrant 4 | Version: __VERSION__ 5 | Release: __RELEASE__ 6 | Summary: An easy to use dev environment for using vagrant with puppet, docker and more! 7 | License: AGPLv3+ 8 | URL: https://github.com/purpleidea/oh-my-vagrant 9 | Source0: https://dl.fedoraproject.org/pub/alt/purpleidea/oh-my-vagrant/SOURCES/oh-my-vagrant-%{project_version}.tar.bz2 10 | BuildArch: noarch 11 | 12 | Requires: vagrant >= 1.6.5 13 | Requires: vagrant-libvirt >= 0.0.24 14 | # git should really be a "suggests", since technically it's optional 15 | Requires: git 16 | Requires: polkit-pkla-compat 17 | # these deps are "runtime" because vagrant-hostmanager is built in userspace 18 | # if vagrant-hostmanager is ever packaged, then these deps should go away... 19 | Requires: ruby-devel 20 | Requires: gcc 21 | Requires: gcc-c++ 22 | Requires: libvirt-devel 23 | 24 | %description 25 | An easy to use dev environment for using vagrant with puppet, docker and more! 26 | 27 | %prep 28 | %setup -c -q -T -D -a 0 29 | 30 | %build 31 | 32 | %install 33 | rm -rf %{buildroot} 34 | # _datadir is typically /usr/share/ 35 | install -d -m 0755 %{buildroot}/%{_datadir}/oh-my-vagrant/ 36 | cp -r oh-my-vagrant-%{project_version}/* %{buildroot}/%{_datadir}/oh-my-vagrant/ 37 | echo %{project_version} > %{buildroot}/%{_datadir}/oh-my-vagrant/VERSION 38 | 39 | mkdir -p %{buildroot}/%{_bindir} 40 | install -m 0755 oh-my-vagrant-%{project_version}/bin/omv.sh %{buildroot}/%{_bindir}/omv 41 | 42 | mkdir -p %{buildroot}%{_sysconfdir}/profile.d 43 | install oh-my-vagrant-%{project_version}/extras/vagrant.bashrc -m 0755 %{buildroot}%{_sysconfdir}/profile.d/oh-my-vagrant.sh 44 | 45 | # pkla file for users in vagrant group 46 | # NOTE: this can apparently give you root access, see: 47 | # https://bugzilla.redhat.com/show_bug.cgi?id=1187019#c10 48 | mkdir -p %{buildroot}%{_sysconfdir}/polkit-1/localauthority/50-local.d/ 49 | install -m 0644 oh-my-vagrant-%{project_version}/extras/oh-my-vagrant.pkla %{buildroot}%{_sysconfdir}/polkit-1/localauthority/50-local.d/oh-my-vagrant.pkla 50 | 51 | %files 52 | %attr(0755, root, root) %{_sysconfdir}/profile.d/oh-my-vagrant.sh 53 | %{_datadir}/oh-my-vagrant/* 54 | %{_bindir}/omv 55 | %{_sysconfdir}/polkit-1/localauthority/50-local.d/oh-my-vagrant.pkla 56 | 57 | # this changelog is auto-generated by git log 58 | %changelog 59 | -------------------------------------------------------------------------------- /extras/post-push.git-hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # TODO: rename this to `post-push` and place in project/.git/hooks/ 3 | # TODO: it needs the `git-pushx` script added (b/c git hates post-push hooks) 4 | # TODO: it also needs the alias: pushx = !git-pushx in your ~/.gitconfig 5 | 6 | # This is a git hook to trigger Jenkins builds automatically. It logins in if 7 | # your Jenkins instance requires password authentication, and then kicks the 8 | # special "Build Triggers" -> "Trigger builds remotely (e.g., from scripts)" 9 | # URL for you. You'll have to set an "Authentication Token" manually first. 10 | 11 | # notify the centos jenkins ci that we should run a build 12 | JENKINS_BASE='https://ci.centos.org' 13 | JENKINS_USERNAME='purpleidea' # TODO: set this 14 | JENKINS_PASSWORD='hunter2' # TODO: set this 15 | JENKINS_JOB='purpleidea-oh-my-vagrant' # TODO: set this 16 | JENKINS_TOKEN='some-token-that-you-generate' # TODO: set this 17 | JENKINS_CAUSE='started+from+git+hook' # a url safe comment to pass as a build reason 18 | 19 | echo 'Running post-push hook...' 20 | branch="$1" 21 | if [ "$branch" = 'master' ] || [ "$1" = '--force' ]; then 22 | # login first 23 | wget -q -O - --save-cookies cookies.txt --post-data "j_username=${JENKINS_USERNAME}&j_password=${JENKINS_PASSWORD}&remember_me=on&Submit=log+in" "${JENKINS_BASE}/j_acegi_security_check" 1> /dev/null 24 | # trigger the build 25 | wget -q -O - --load-cookies cookies.txt "${JENKINS_BASE}/me/my-views/view/All/job/${JENKINS_JOB}/build?token=${JENKINS_TOKEN}&cause=${JENKINS_CAUSE}" 1> /dev/null 26 | # TODO: get the build id and wait for that specifically 27 | sleep 10s # give the build time to start 28 | # wait for result from build 29 | while true; do 30 | r=`wget -q -O - --load-cookies cookies.txt "${JENKINS_BASE}/job/${JENKINS_JOB}/lastBuild/api/json" | python -c 'import json,sys;obj=json.load(sys.stdin);print str(obj.get("result", "pending")) + obj.get("displayName", "")'` 31 | split=(${r//#/ }) 32 | r=${split[0]} 33 | b=${split[1]} 34 | if [ "$r" = 'pending' ] || [ "$r" = 'None' ]; then # build not ready yet 35 | echo "Build #${b} is pending..." 36 | sleep 10s 37 | elif [ "$r" = 'SUCCESS' ]; then 38 | e=0 39 | break 40 | else 41 | e=1 42 | break 43 | fi 44 | done 45 | echo "Build #${b}: $r" 46 | # clean up the crumbs 47 | rm -rf cookies.txt 48 | else 49 | echo 'Skipping post-push hook.' 50 | fi 51 | -------------------------------------------------------------------------------- /vagrant/puppet/modules/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for pulling in git modules for Vagrant deployment 2 | # Copyright (C) 2012-2013+ James Shubin 3 | # Written by James Shubin 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | 18 | # NOTE: if we remove a module, it won't get purged from the destination! 19 | 20 | # NOTE: this script can sync puppet- to a specific sha1sum commit, or it 21 | # can sync all of the repos to git master. This option can be useful for devel. 22 | 23 | BASE = 'https://github.com/purpleidea' 24 | MODULENAME = namespace 25 | MODULES := \ 26 | puppet-$(MODULENAME) \ 27 | puppet-module-data \ 28 | puppet-puppet \ 29 | puppet-shorewall \ 30 | puppetlabs-stdlib 31 | # NOTE: set to a git commit id if we need an specific commit for vagrant builds 32 | # NOTE: remember that new commits to master should change this to a specific id 33 | # if they will break the vagrant build process. hopefully we don't forget this! 34 | #SHA1SUM := master 35 | SHA1SUM := $(shell git rev-parse --verify HEAD) # goto whatever the main tree is at 36 | 37 | .PHONY: all modules $(MODULENAME) 38 | .SILENT: all modules $(MODULENAME) 39 | 40 | all: 41 | 42 | # 43 | # modules 44 | # 45 | # clone, and then pull 46 | modules: 47 | basename `pwd` | grep -q '^modules' || exit 1 # run in a modules dir! 48 | for i in $(MODULES); do \ 49 | j=`echo $$i | awk -F '-' '{print $$2}'`; \ 50 | [ -d "$$j" ] || git clone --depth 1 $(BASE)/$$i.git $$j; \ 51 | [ -d "$$j" ] && cd $$j && git pull; cd ..; \ 52 | done 53 | 54 | # 55 | # module 56 | # 57 | # just clone and pull this one 58 | $(MODULENAME): 59 | basename `pwd` | grep -q '^modules' || exit 1 # run in a modules dir! 60 | i='puppet-$(MODULENAME)'; \ 61 | j=`echo $$i | awk -F '-' '{print $$2}'`; \ 62 | [ -d "$$j" ] || git clone ../../../. $$j; \ 63 | [ -d "$$j" ] && cd $$j && git checkout master && git pull && git checkout $(SHA1SUM); cd .. 64 | -------------------------------------------------------------------------------- /vagrant/puppet/manifests/site.pp: -------------------------------------------------------------------------------- 1 | class motd { # this will get put on every host... 2 | $url = 'https://ttboj.wordpress.com/' 3 | file { '/etc/motd': 4 | content => "This is: Oh My Vagrant! (${url})\n", 5 | } 6 | } 7 | 8 | define omv_include() { # this is a cheap enc in puppet and used by omv 9 | 10 | # TODO: unfortunately we're passing data into puppet via the FACTER_ 11 | # environment variables that vagrant generates... this is limited and 12 | # only allows strings without significantly more work (eg: pickle-ing) 13 | # this is actually a limitation of puppet and vagrant, and not of omv!! 14 | $params_str = getvar("::vagrant_puppet_classes_params_${name}") 15 | if "${params_str}" != '' { 16 | $params = split("${params_str}", ',') 17 | $yaml = inline_template("<%= r = {}; @params.each {|x| r[x] = scope.lookupvar('::vagrant_puppet_classes_values_${name}_'+x) }; r.to_yaml %>") 18 | $parseyaml = parseyaml($yaml) 19 | $hash = { 20 | "${name}" => $parseyaml, 21 | } 22 | create_resources('class', $hash) 23 | 24 | } else { 25 | include "${name}" 26 | } 27 | } 28 | 29 | # puppetmaster 30 | node puppet { 31 | 32 | include ::motd 33 | 34 | class { '::puppet::server': 35 | pluginsync => true, # do we want to enable pluginsync? 36 | storeconfigs => true, # do we want to enable storeconfigs? 37 | autosign => [ 38 | '*', # FIXME: this is a temporary solution 39 | #"*.${domain}", # FIXME: this is a temporary solution 40 | ], 41 | #allow_duplicate_certs => true, # redeploy without cert clean 42 | repo => true, # automatic repos 43 | shorewall => false, 44 | start => true, 45 | } 46 | 47 | $folder = "${::vagrant_puppet_folder}" 48 | class { '::puppet::deploy': 49 | path => "/vagrant/${folder}puppet/", # puppet folder is put here... 50 | backup => false, # don't use puppet to backup... 51 | } 52 | 53 | # dynamically include the list of classes for this host from omv enc... 54 | if "${::vagrant_puppet_classes}" != '' { 55 | $classes = split("${::vagrant_puppet_classes}", ',') 56 | omv_include { $classes: # loop! 57 | } 58 | } 59 | } 60 | 61 | node default { # all the other hosts 62 | 63 | include ::motd 64 | 65 | # TODO: we could actually define the puppet classes with omv_include :) 66 | class { '::puppet::client': 67 | #start => true, 68 | start => false, # useful for testing manually... 69 | } 70 | 71 | # dynamically include the list of classes for this host from omv enc... 72 | if "${::vagrant_puppet_classes}" != '' { 73 | $classes = split("${::vagrant_puppet_classes}", ',') 74 | omv_include { $classes: # loop! 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /extras/centos-ci.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # modified from: 4 | # https://github.com/kbsingh/centos-ci-scripts/blob/master/build_python_script.py 5 | # usage: centos-ci.py giturl [branch [commands]] 6 | 7 | import os 8 | import sys 9 | import json 10 | import urllib 11 | import subprocess 12 | 13 | # static argv to be used if running script inline 14 | argv = [ 15 | #'https://github.com/purpleidea/oh-my-vagrant', # giturl 16 | #'master', 17 | #'make test', 18 | ] 19 | argv.insert(0, '') # add a fake argv[0] 20 | url_base = 'http://admin.ci.centos.org:8080' 21 | apikey = '' # put api key here if running inline 22 | if apikey == '': 23 | apikey = os.environ.get('DUFFY_API_KEY') 24 | if apikey is None or apikey == '': 25 | apikey = open('duffy.key', 'r').read().strip() 26 | ver = '7' 27 | arch = 'x86_64' 28 | count = 1 29 | 30 | if len(argv) <= 1: argv = sys.argv # use system argv because ours is empty 31 | if len(argv) <= 1: 32 | print 'Not enough arguments supplied!' 33 | sys.exit(1) 34 | 35 | git_url = argv[1] 36 | branch = 'master' 37 | if len(argv) > 2: branch = argv[2] 38 | folder = os.path.splitext(os.path.basename(__file__))[0] 39 | run = 'make vtest' # the omv vtest cmd is a good option to run from this target 40 | if len(argv) > 3: run = ' '.join(argv[3:]) 41 | 42 | get_nodes_url = "%s/Node/get?key=%s&ver=%s&arch=%s&i_count=%s" % (url_base, apikey, ver, arch, count) 43 | data = json.loads(urllib.urlopen(get_nodes_url).read()) # request host(s) 44 | hosts = data['hosts'] 45 | ssid = data['ssid'] 46 | done_nodes_url = "%s/Node/done?key=%s&ssid=%s" % (url_base, apikey, ssid) 47 | 48 | host = hosts[0] 49 | ssh = "ssh -tt -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@%s" % host 50 | yum = 'yum -y install git wget' 51 | omv = 'wget https://github.com/purpleidea/oh-my-vagrant/raw/master/extras/install-omv.sh && chmod u+x install-omv.sh && ./install-omv.sh' 52 | cmd = "%s '%s && %s'" % (ssh, yum, omv) # setup 53 | print cmd 54 | r = subprocess.call(cmd, shell=True) 55 | if r != 0: 56 | # NOTE: we don't clean up the host here, so that it can be inspected! 57 | print "Error configuring omv on: %s" % host 58 | sys.exit(r) 59 | 60 | # the second ssh call will run with the omv /etc/profile.d/ script loaded 61 | git = "git clone --recursive %s %s && cd %s && git checkout %s" % (git_url, folder, folder, branch) 62 | cmd = "%s '%s && %s'" % (ssh, git, run) # run 63 | print cmd 64 | r = subprocess.call(cmd, shell=True) 65 | if r != 0: 66 | print "Error running job on: %s" % host 67 | 68 | output = urllib.urlopen(done_nodes_url).read() # free host(s) 69 | if output != 'Done': 70 | print "Error freeing host: %s" % host 71 | 72 | sys.exit(r) 73 | -------------------------------------------------------------------------------- /bin/omv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This is: Oh My Vagrant! 4 | # Copyright (C) 2012-2015+ James Shubin and the Oh-My-Vagrant contributors 5 | # Written by James Shubin and the Oh-My-Vagrant contributors 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Affero General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Affero General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Affero General Public License 18 | # along with this program. If not, see . 19 | 20 | vagrantdir="/usr/share/oh-my-vagrant/" # this should be set at install 21 | if [ "$OHMYVAGRANT_DIR" != "" ]; then 22 | vagrantdir="$OHMYVAGRANT_DIR" # use user provided dir instead 23 | fi 24 | vagrantbase="$vagrantdir" 25 | vagrantdir="$vagrantdir""vagrant/" # append vagrant/ path postfix! 26 | projectdir="`pwd`" # default to where we are 27 | args=("$@") # save as an array 28 | 29 | if [ "$1" = '' ] || [ "$1" = '-h' ] || [ "$1" = '--help' ]; then 30 | echo -e "Usage: ./"`basename $0`" --help | init [dir] | " 31 | vagrant # display vagrant usage... 32 | exit 1 33 | fi 34 | 35 | if [ "$1" = '--version' ]; then 36 | if [ -e "${vagrantbase}VERSION" ]; then 37 | echo -e "Version: "`cat ${vagrantbase}VERSION` 38 | exit 0 39 | else 40 | echo "Can't find version file. Oh-My-Vagrant is not installed properly." 41 | exit 1 42 | fi 43 | fi 44 | 45 | # initialize a new omv project (if called with $2 it puts mess in that folder!) 46 | if [ "$1" = 'init' ]; then 47 | 48 | # install user session dependencies automatically 49 | # do this in init to avoid constant checking from normal vagrant runs 50 | # this sha matches what I expect from the plugin! 51 | if [ "`sha1sum ~/.vagrant.d/gems/gems/vagrant-hostmanager-1.5.0/README.md 2> /dev/null | awk '{print $1}'`" != 'ad4b0de54cbefdd41bdcb0d6afb9c8d48e4d3bff' ]; then 52 | echo 'Oh-My-Vagrant needs to install a modified vagrant-hostmanager plugin.' 53 | read -p 'Is this ok [y/N]: ' -r answer 54 | if [[ $answer =~ ^[Yy]$ ]] 55 | then 56 | # run hostmanager installer 57 | $vagrantbase'extras/patch-hostmanager.sh' 58 | if [ $? -ne 0 ]; then 59 | echo 'Problem installing plugin.' 60 | exit 1 61 | fi 62 | else 63 | echo "Can't continue." 64 | exit 1 65 | fi 66 | fi 67 | 68 | vagrant plugin list | grep -qF 'vagrant-reload' 69 | if [ $? -ne 0 ]; then 70 | echo 'Oh-My-Vagrant needs to install a vagrant-reload plugin for the "reboot" option to work.' 71 | read -p 'Is this ok [y/N]: ' -r answer 72 | if [[ $answer =~ ^[Yy]$ ]] 73 | then 74 | vagrant plugin install vagrant-reload 75 | else 76 | echo 'Skipping.' 77 | fi 78 | fi 79 | 80 | args=('status') 81 | if [ "$2" != '' ]; then 82 | mkdir -p "$projectdir/$2" 83 | ln -s "$2/omv.yaml" 'omv.yaml' # relative, not absolute symlink! 84 | args=("--omv-folder=$2") 85 | args+=('status') 86 | fi 87 | fi 88 | 89 | omvsearch=$projectdir 90 | # search upwards for omv.yaml 91 | while [ "$omvsearch" != "/" ]; do 92 | if [ -e "$omvsearch/omv.yaml" ]; then 93 | projectdir="$omvsearch" # found one! 94 | break 95 | fi 96 | omvsearch=`dirname "$omvsearch"` 97 | done 98 | 99 | # this is where the magic happens... 100 | VAGRANT_CWD="$vagrantdir" VAGRANT_DOTFILE_PATH="$projectdir/.vagrant/" vagrant "${args[@]}" 101 | -------------------------------------------------------------------------------- /art/omv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 63 | Oh My 75 | Vagrant! 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /art/Pacifico/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Vernon Adams (vern@newtypography.co.uk), 2 | with Reserved Font Name Pacifico. 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /art/Alfa_Slab_One/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, JM Sole (http://jmsole.cl|info@jmsole.cl), 2 | with Reserved Font Name "Alfa Slab". 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # *Oh-My-Vagrant*: This is: Oh My Vagrant! 2 | 3 | ![Oh My Vagrant!](https://raw.githubusercontent.com/purpleidea/oh-my-vagrant/master/art/omv.png) 4 | 5 | [![Build Status](https://secure.travis-ci.org/purpleidea/oh-my-vagrant.png?branch=master)](http://travis-ci.org/purpleidea/oh-my-vagrant) 6 | [![Documentation](https://img.shields.io/docs/markdown.png)](DOCUMENTATION.md) 7 | [![IRC](https://img.shields.io/irc/%23vagrant.png)](https://webchat.freenode.net/?channels=#vagrant) 8 | [![Jenkins](https://img.shields.io/jenkins/status.png)](https://ci.centos.org/job/purpleidea-oh-my-vagrant/) 9 | [![COPR](https://img.shields.io/copr/builds.png)](https://copr.fedoraproject.org/coprs/purpleidea/oh-my-vagrant/) 10 | 11 | ## Status: 12 | This project was always meant to be a useful tool for its author. Others found 13 | it helpful, and I was happy to share and help improve it. From my perspective, 14 | it's now mostly feature complete, and since I've been focusing most of my time 15 | on [mgmt](https://github.com/purpleidea/mgmt/), there aren't any major planned 16 | changes coming. As a result please use, share and enjoy it, but development is 17 | going to be limited to what the community provides. We have other maintainers, 18 | so that I'm not a bottleneck on any patch reviews or merges! Happy hacking! -- 19 | [purpleidea](https://twitter.com/purpleidea) 20 | 21 | ## Documentation: 22 | Please see: [DOCUMENTATION.md](DOCUMENTATION.md) or [PDF](https://pdfdoc-purpleidea.rhcloud.com/pdf/https://github.com/purpleidea/oh-my-vagrant/blob/master/DOCUMENTATION.md). 23 | 24 | ## Questions: 25 | Come join us in [#vagrant](https://webchat.freenode.net/?channels=#vagrant) on Freenode! 26 | 27 | ## Installation: 28 | Please read the [INSTALL](INSTALL) file for instructions on getting this installed. 29 | 30 | ## Examples: 31 | Please look in the [examples/](examples/) folder for usage. If none exist, please contribute one! 32 | 33 | ## Module specific notes: 34 | 35 | * This was born as 'vagrant-puppet-docker-template'... 36 | * I decided it could be more useful as a general project... 37 | * I renamed it because the original name was dumb... 38 | * The current name is obviously a nod to the success of the 'oh-my-zsh' project, although I'm actually a bash user :) 39 | * It is an attempt to provide a general purpose environment to make it easier to get hacking on vagrant+puppet+docker things. 40 | * There are still some unresolved issues, but it can be useful as reference, or as a starting point for a hacker to customize. 41 | * There are a number of published articles about this environment: 42 | * [https://ttboj.wordpress.com/2014/09/03/introducing-oh-my-vagrant/](https://ttboj.wordpress.com/2014/09/03/introducing-oh-my-vagrant/) 43 | * [https://ttboj.wordpress.com/2015/04/08/sharing-dev-environments-with-oh-my-vagrant/](https://ttboj.wordpress.com/2015/04/08/sharing-dev-environments-with-oh-my-vagrant/) 44 | * [https://ttboj.wordpress.com/2015/04/20/docker-containers-in-oh-my-vagrant/](https://ttboj.wordpress.com/2015/04/20/docker-containers-in-oh-my-vagrant/) 45 | * [https://ttboj.wordpress.com/2015/05/02/kubernetes-clusters-with-oh-my-vagrant/](https://ttboj.wordpress.com/2015/05/02/kubernetes-clusters-with-oh-my-vagrant/) 46 | * [https://ttboj.wordpress.com/2015/06/12/a-super-privileged-puppet-container/](https://ttboj.wordpress.com/2015/06/12/a-super-privileged-puppet-container/) 47 | * [https://ttboj.wordpress.com/2015/07/08/oh-my-vagrant-mainstream-mode-and-copr-rpms/](https://ttboj.wordpress.com/2015/07/08/oh-my-vagrant-mainstream-mode-and-copr-rpms/) 48 | * [https://ttboj.wordpress.com/2015/08/11/vagrant-and-oh-my-vagrant-on-rhel7/](https://ttboj.wordpress.com/2015/08/11/vagrant-and-oh-my-vagrant-on-rhel7/) 49 | * [https://ghantoos.org/2015/12/20/how-to-setup-run-oh-my-vagrant-on-debian-with-libvirt-and-kvm/](https://ghantoos.org/2015/12/20/how-to-setup-run-oh-my-vagrant-on-debian-with-libvirt-and-kvm/) 50 | * There are some screencasts available: 51 | * [https://dl.fedoraproject.org/pub/alt/purpleidea/screencasts/oh-my-vagrant-extern-screencast.ogv](https://dl.fedoraproject.org/pub/alt/purpleidea/screencasts/oh-my-vagrant-extern-screencast.ogv) 52 | * [https://dl.fedoraproject.org/pub/alt/purpleidea/screencasts/oh-my-vagrant-docker-screencast.ogv](https://dl.fedoraproject.org/pub/alt/purpleidea/screencasts/oh-my-vagrant-docker-screencast.ogv) 53 | * [https://dl.fedoraproject.org/pub/alt/purpleidea/screencasts/oh-my-vagrant-kubernetes-screencast.ogv](https://dl.fedoraproject.org/pub/alt/purpleidea/screencasts/oh-my-vagrant-kubernetes-screencast.ogv) 54 | 55 | ## Dependencies: 56 | * vagrant (available in Fedora 21+, Debian) 57 | * [vagrant-libvirt](https://github.com/pradels/vagrant-libvirt/) (available in Fedora 21+) 58 | * in the meantime please test: [https://copr.fedoraproject.org/coprs/jstribny/vagrant-f20/](https://copr.fedoraproject.org/coprs/jstribny/vagrant-f20/) 59 | * [vagrant-hostmanager](https://github.com/purpleidea/vagrant-hostmanager/) 60 | * you need the feat/oh-my-vagrant patches for this to work properly 61 | * to install them, run the script from: [extras/patch-hostmanager.sh](extras/patch-hostmanager.sh) 62 | * [vagrant-reload](https://github.com/aidanns/vagrant-reload) 63 | * for the "reboot" option to work 64 | * [puppetlabs-stdlib](https://github.com/puppetlabs/puppetlabs-stdlib) (optional, built-in) 65 | * [puppet-module-data](https://github.com/ripienaar/puppet-module-data/) (optional, puppet >= 3.0.0, built-in) 66 | * my [puppet-puppet](https://github.com/purpleidea/puppet-puppet) module (optional, built-in) 67 | * my [puppet-yum](https://github.com/purpleidea/puppet-yum) module (optional, built-in) 68 | * pandoc (for building a pdf of the documentation) 69 | 70 | Note: If you are using VirtualBox as hypervisor, there is no need to depend on vagrant-libvirt. 71 | 72 | ## Patches: 73 | We'd love to have your patch! Please send it by email, or as a pull request. 74 | 75 | ## 76 | 77 | Happy hacking! 78 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # This is: Oh My Vagrant! 2 | # Copyright (C) 2012-2015+ James Shubin and the Oh-My-Vagrant contributors 3 | # Written by James Shubin and the Oh-My-Vagrant contributors 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | 18 | .PHONY: all version docs rpm srpm spec tar upload upload-sources upload-srpms upload-rpms copr test vtest 19 | .SILENT: 20 | 21 | # version of the program 22 | # TODO: technically the star match should be "one or more" matches instead... 23 | VERSION := $(shell git describe --match '[0-9]*\.[0-9]*\.[0-9]*' --tags --abbrev=0) 24 | HACKED_VERSION := $(shell git describe --match '[0-9]*\.[0-9]*\.[0-9]*' --tags --dirty) 25 | ifeq ($(VERSION),$(HACKED_VERSION)) 26 | RELEASE = 1 27 | else 28 | RELEASE = untagged 29 | endif 30 | SPEC = rpmbuild/SPECS/oh-my-vagrant.spec 31 | SOURCE = rpmbuild/SOURCES/oh-my-vagrant-$(VERSION).tar.bz2 32 | SRPM = rpmbuild/SRPMS/oh-my-vagrant-$(VERSION)-$(RELEASE).src.rpm 33 | SRPM_BASE = oh-my-vagrant-$(VERSION)-$(RELEASE).src.rpm 34 | RPM = rpmbuild/RPMS/oh-my-vagrant-$(VERSION)-$(RELEASE).rpm 35 | USERNAME := $(shell cat ~/.config/copr 2>/dev/null | grep username | awk -F '=' '{print $$2}' | tr -d ' ') 36 | SERVER = 'dl.fedoraproject.org' 37 | REMOTE_PATH = 'pub/alt/$(USERNAME)/oh-my-vagrant' 38 | 39 | all: docs rpm 40 | 41 | # show the current version 42 | version: 43 | @echo $(VERSION) 44 | 45 | # 46 | # aliases 47 | # 48 | # TODO: does making an rpm depend on making a .srpm first ? 49 | rpm: $(SRPM) $(RPM) 50 | # do nothing 51 | 52 | srpm: $(SRPM) 53 | # do nothing 54 | 55 | spec: $(SPEC) 56 | # do nothing 57 | 58 | tar: $(SOURCE) 59 | # do nothing 60 | 61 | rpmbuild/SOURCES/: tar 62 | rpmbuild/SRPMS/: srpm 63 | rpmbuild/RPMS/: rpm 64 | 65 | upload: upload-sources upload-srpms upload-rpms 66 | # do nothing 67 | 68 | docs: oh-my-vagrant-documentation.pdf 69 | 70 | oh-my-vagrant-documentation.pdf: DOCUMENTATION.md 71 | pandoc DOCUMENTATION.md -o 'oh-my-vagrant-documentation.pdf' 72 | 73 | # 74 | # rpmbuild 75 | # 76 | $(RPM): $(SPEC) $(SOURCE) 77 | @echo Running rpmbuild -bb... 78 | rpmbuild --define '_topdir $(shell pwd)/rpmbuild' -bb $(SPEC) && \ 79 | mv rpmbuild/RPMS/noarch/oh-my-vagrant-$(VERSION)-$(RELEASE).*.rpm $(RPM) 80 | 81 | $(SRPM): $(SPEC) $(SOURCE) 82 | @echo Running rpmbuild -bs... 83 | rpmbuild --define '_topdir $(shell pwd)/rpmbuild' -bs $(SPEC) 84 | # renaming is not needed because we aren't using the dist variable 85 | #mv rpmbuild/SRPMS/oh-my-vagrant-$(VERSION)-$(RELEASE).*.src.rpm $(SRPM) 86 | 87 | # 88 | # spec 89 | # 90 | $(SPEC): rpmbuild/ oh-my-vagrant.spec.in 91 | @echo Running templater... 92 | #cat oh-my-vagrant.spec.in > $(SPEC) 93 | sed -e s/__VERSION__/$(VERSION)/ -e s/__RELEASE__/$(RELEASE)/ < oh-my-vagrant.spec.in > $(SPEC) 94 | # append a changelog to the .spec file 95 | git log --format="* %cd %aN <%aE>%n- (%h) %s%d%n" --date=local | sed -r 's/[0-9]+:[0-9]+:[0-9]+ //' >> $(SPEC) 96 | 97 | # 98 | # archive 99 | # 100 | $(SOURCE): rpmbuild/ 101 | @echo Running git archive... 102 | # use HEAD if tag doesn't exist yet, so that development is easier... 103 | git archive --prefix=oh-my-vagrant-$(VERSION)/ -o $(SOURCE) $(VERSION) 2> /dev/null || (echo 'Warning: $(VERSION) does not exist. Using HEAD instead.' && git archive --prefix=oh-my-vagrant-$(VERSION)/ -o $(SOURCE) HEAD) 104 | # TODO: if git archive had a --submodules flag this would easier! 105 | @echo Running git archive submodules... 106 | # i thought i would need --ignore-zeros, but it doesn't seem necessary! 107 | p=`pwd` && (echo .; git submodule foreach) | while read entering path; do \ 108 | temp="$${path%\'}"; \ 109 | temp="$${temp#\'}"; \ 110 | path=$$temp; \ 111 | [ "$$path" = "" ] && continue; \ 112 | (cd $$path && git archive --prefix=oh-my-vagrant-$(VERSION)/$$path/ HEAD > $$p/rpmbuild/tmp.tar && tar --concatenate --file=$$p/$(SOURCE) $$p/rpmbuild/tmp.tar && rm $$p/rpmbuild/tmp.tar); \ 113 | done 114 | 115 | # TODO: ensure that each sub directory exists 116 | rpmbuild/: 117 | mkdir -p rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} 118 | 119 | # 120 | # sha256sum 121 | # 122 | rpmbuild/SOURCES/SHA256SUMS: rpmbuild/SOURCES/ $(SOURCE) 123 | @echo Running SOURCES sha256sum... 124 | cd rpmbuild/SOURCES/ && sha256sum *.tar.bz2 > SHA256SUMS; cd - 125 | 126 | rpmbuild/SRPMS/SHA256SUMS: rpmbuild/SRPMS/ $(SRPM) 127 | @echo Running SRPMS sha256sum... 128 | cd rpmbuild/SRPMS/ && sha256sum *src.rpm > SHA256SUMS; cd - 129 | 130 | rpmbuild/RPMS/SHA256SUMS: rpmbuild/RPMS/ $(RPM) 131 | @echo Running RPMS sha256sum... 132 | cd rpmbuild/RPMS/ && sha256sum *.rpm > SHA256SUMS; cd - 133 | 134 | # 135 | # gpg 136 | # 137 | rpmbuild/SOURCES/SHA256SUMS.asc: rpmbuild/SOURCES/SHA256SUMS 138 | @echo Running SOURCES gpg... 139 | # the --yes forces an overwrite of the SHA256SUMS.asc if necessary 140 | gpg2 --yes --clearsign rpmbuild/SOURCES/SHA256SUMS 141 | 142 | rpmbuild/SRPMS/SHA256SUMS.asc: rpmbuild/SRPMS/SHA256SUMS 143 | @echo Running SRPMS gpg... 144 | gpg2 --yes --clearsign rpmbuild/SRPMS/SHA256SUMS 145 | 146 | rpmbuild/RPMS/SHA256SUMS.asc: rpmbuild/RPMS/SHA256SUMS 147 | @echo Running RPMS gpg... 148 | gpg2 --yes --clearsign rpmbuild/RPMS/SHA256SUMS 149 | 150 | # 151 | # upload 152 | # 153 | # upload to public server 154 | upload-sources: rpmbuild/SOURCES/ rpmbuild/SOURCES/SHA256SUMS rpmbuild/SOURCES/SHA256SUMS.asc 155 | if [ "`cat rpmbuild/SOURCES/SHA256SUMS`" != "`ssh $(SERVER) 'cd $(REMOTE_PATH)/SOURCES/ && cat SHA256SUMS'`" ]; then \ 156 | echo Running SOURCES upload...; \ 157 | rsync -avz rpmbuild/SOURCES/ $(SERVER):$(REMOTE_PATH)/SOURCES/; \ 158 | fi 159 | 160 | upload-srpms: rpmbuild/SRPMS/ rpmbuild/SRPMS/SHA256SUMS rpmbuild/SRPMS/SHA256SUMS.asc 161 | if [ "`cat rpmbuild/SRPMS/SHA256SUMS`" != "`ssh $(SERVER) 'cd $(REMOTE_PATH)/SRPMS/ && cat SHA256SUMS'`" ]; then \ 162 | echo Running SRPMS upload...; \ 163 | rsync -avz rpmbuild/SRPMS/ $(SERVER):$(REMOTE_PATH)/SRPMS/; \ 164 | fi 165 | 166 | upload-rpms: rpmbuild/RPMS/ rpmbuild/RPMS/SHA256SUMS rpmbuild/RPMS/SHA256SUMS.asc 167 | if [ "`cat rpmbuild/RPMS/SHA256SUMS`" != "`ssh $(SERVER) 'cd $(REMOTE_PATH)/RPMS/ && cat SHA256SUMS'`" ]; then \ 168 | echo Running RPMS upload...; \ 169 | rsync -avz --prune-empty-dirs rpmbuild/RPMS/ $(SERVER):$(REMOTE_PATH)/RPMS/; \ 170 | fi 171 | 172 | # 173 | # copr build 174 | # 175 | copr: upload-srpms 176 | ./extras/copr-build.py https://$(SERVER)/$(REMOTE_PATH)/SRPMS/$(SRPM_BASE) 177 | 178 | # 179 | # test 180 | # 181 | test: 182 | ./test.sh 183 | 184 | # 185 | # vtest 186 | # 187 | vtest: 188 | ./vtest.sh # run vtest+ 189 | 190 | # vim: ts=8 191 | -------------------------------------------------------------------------------- /extras/vagrant.bashrc: -------------------------------------------------------------------------------- 1 | ### VAGRANT ################################################################### 2 | # avoid needing to always add --provider=libvirt 3 | export VAGRANT_DEFAULT_PROVIDER=libvirt 4 | #alias vagrant='/opt/vagrant/bin/vagrant' 5 | 6 | # if oh-my-vagrant has the mainstream entrypoint installed, then use it instead 7 | OMV=`which omv 2> /dev/null` 8 | if [ "$OMV" != '' ] && [ "$VAGRANT" = '' ]; then 9 | VAGRANT='omv' 10 | else 11 | VAGRANT='vagrant' 12 | fi 13 | 14 | alias vs="$VAGRANT status" 15 | alias vp="$VAGRANT provision" 16 | alias vup="$VAGRANT up" 17 | alias vrsync="$VAGRANT rsync" 18 | alias vdestroy="$VAGRANT destroy" 19 | alias vrm-rf="$VAGRANT --omv-reallyrmonce=true status" 20 | function vlog { 21 | VAGRANT_LOG=info $VAGRANT "$@" 2> vagrant.log 22 | } 23 | 24 | # vagrant ssh (better than vagrant ssh) 25 | function vssh { 26 | [ "$1" = '' ] || [ "$2" != '' -a "$2" != '-c' ] || [ "$2" = '-c' -a "$3" = '' ] && echo "Usage: vssh [-c COMMAND] - vagrant screen" 1>&2 && return 1 27 | vfile='Vagrantfile' 28 | if [[ "$VAGRANT" == omv* ]]; then 29 | vfile='omv.yaml' 30 | fi 31 | wd=`pwd` # save wd, then find the Vagrant project 32 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 33 | #echo "pwd is `pwd`" 34 | cd .. 35 | done 36 | pwd=`pwd` 37 | cd $wd 38 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 39 | echo 'Vagrant project not found!' 1>&2 && return 2 40 | fi 41 | 42 | # if we find the omv.yaml file, it takes precendence for mtime lookups 43 | if [ -e "$pwd/omv.yaml" ]; then 44 | pfile="$pwd/omv.yaml" 45 | elif [ -e "$pwd/Vagrantfile" ]; then 46 | pfile="$pwd/Vagrantfile" 47 | else 48 | echo 'No vagrant definition found!' 1>&2 && return 2 49 | fi 50 | 51 | host="$1" # save variables 52 | cmd='' 53 | if [ "$2" = '-c' -a "$3" != '' ]; then 54 | shift 2 55 | cmd="$@" # join $3...last 56 | fi 57 | 58 | d="$pwd/.ssh" 59 | f="$d/$host.config" 60 | h="$host" 61 | # hostname extraction from user@host pattern 62 | p=`expr index "$host" '@'` 63 | if [ $p -gt 0 ]; then 64 | let "l = ${#h} - $p" 65 | h=${h:$p:$l} 66 | fi 67 | 68 | cdfile="$pwd/.vagrant/$h.cd" 69 | 70 | # if cd file is missing, or is older than the definition file, re-generate... 71 | # or if mtime of $f is > than 5 minutes (5 * 60 seconds), re-generate... 72 | if [ ! -e "$cdfile" ] || \ 73 | [ $(stat -c '%Y' "$pfile" 2> /dev/null) -gt $(stat -c '%Y' "$cdfile" 2> /dev/null) ] || \ 74 | [ `date -d "now - $(stat -c '%Y' "$f" 2> /dev/null) seconds" +%s` -gt 300 ]; then 75 | mkdir -p "$d" 76 | # we cache the lookup because this command is slow... 77 | $VAGRANT ssh-config "$h" > "$f" || rm "$f" 78 | fi 79 | 80 | cddir="`cat $cdfile 2>/dev/null`" 81 | if [ -e "$cdfile" ] && [ -n "$cddir" ]; then 82 | # switch into the cd dir, and then run that users shell 83 | _cmd="cd '$cddir' && exec $(getent passwd `whoami` | awk -F ':' '{print $7}')" 84 | if [ "$cmd" != '' ]; then 85 | _cmd="$_cmd -c '$cmd'" # add on the -c to bash 86 | fi 87 | cmd="$_cmd" 88 | unset _cmd 89 | fi 90 | 91 | [ -e "$f" ] && ssh -t -F "$f" "$host" "$cmd" 92 | e=$? 93 | if [ $e -eq 255 ]; then 94 | # you probably want a shorter timeout if you see this often 95 | echo 'Maybe cached connection was stale? Cleaning...' 96 | rm -f "$f" # clean stale ssh connection 97 | # TODO: recurse up to one time? 98 | else 99 | return $e 100 | fi 101 | } 102 | 103 | # vagrant sftp 104 | function vsftp { 105 | [ "$1" = '' ] || [ "$2" != '' ] && echo "Usage: vsftp - vagrant sftp" 1>&2 && return 1 106 | vfile='Vagrantfile' 107 | if [[ "$VAGRANT" == omv* ]]; then 108 | vfile='omv.yaml' 109 | fi 110 | wd=`pwd` # save wd, then find the Vagrant project 111 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 112 | #echo "pwd is `pwd`" 113 | cd .. 114 | done 115 | pwd=`pwd` 116 | cd $wd 117 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 118 | echo 'Vagrant project not found!' 1>&2 && return 2 119 | fi 120 | 121 | # if we find the omv.yaml file, it takes precendence for mtime lookups 122 | if [ -e "$pwd/omv.yaml" ]; then 123 | pfile="$pwd/omv.yaml" 124 | elif [ -e "$pwd/Vagrantfile" ]; then 125 | pfile="$pwd/Vagrantfile" 126 | else 127 | echo 'No vagrant definition found!' 1>&2 && return 2 128 | fi 129 | 130 | d="$pwd/.ssh" 131 | f="$d/$1.config" 132 | h="$1" 133 | # hostname extraction from user@host pattern 134 | p=`expr index "$1" '@'` 135 | if [ $p -gt 0 ]; then 136 | let "l = ${#h} - $p" 137 | h=${h:$p:$l} 138 | fi 139 | 140 | cdfile="$pwd/.vagrant/$h.cd" 141 | 142 | # if cd file is missing, or is older than the definition file, re-generate... 143 | # or if mtime of $f is > than 5 minutes (5 * 60 seconds), re-generate... 144 | if [ ! -e "$cdfile" ] || \ 145 | [ $(stat -c '%Y' "$pfile" 2> /dev/null) -gt $(stat -c '%Y' "$cdfile" 2> /dev/null) ] || \ 146 | [ `date -d "now - $(stat -c '%Y' "$f" 2> /dev/null) seconds" +%s` -gt 300 ]; then 147 | mkdir -p "$d" 148 | # we cache the lookup because this command is slow... 149 | $VAGRANT ssh-config "$h" > "$f" || rm "$f" 150 | fi 151 | 152 | cdstr='' # path to append to end of sftp 153 | cddir="`cat $cdfile 2>/dev/null`" 154 | if [ -e "$cdfile" ] && [ -n "$cddir" ]; then 155 | cdstr=":$cddir" 156 | fi 157 | 158 | [ -e "$f" ] && sftp -F "$f" "$1""$cdstr" 159 | } 160 | 161 | # vagrant screen 162 | function vscreen { 163 | [ "$1" = '' ] || [ "$2" != '' ] && echo "Usage: vscreen - vagrant screen" 1>&2 && return 1 164 | vfile='Vagrantfile' 165 | if [[ "$VAGRANT" == omv* ]]; then 166 | vfile='omv.yaml' 167 | fi 168 | wd=`pwd` # save wd, then find the Vagrant project 169 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 170 | #echo "pwd is `pwd`" 171 | cd .. 172 | done 173 | pwd=`pwd` 174 | cd $wd 175 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 176 | echo 'Vagrant project not found!' 1>&2 && return 2 177 | fi 178 | 179 | # if we find the omv.yaml file, it takes precendence for mtime lookups 180 | if [ -e "$pwd/omv.yaml" ]; then 181 | pfile="$pwd/omv.yaml" 182 | elif [ -e "$pwd/Vagrantfile" ]; then 183 | pfile="$pwd/Vagrantfile" 184 | else 185 | echo 'No vagrant definition found!' 1>&2 && return 2 186 | fi 187 | 188 | cmd='screen -xRR' 189 | 190 | d="$pwd/.ssh" 191 | f="$d/$1.config" 192 | h="$1" 193 | # hostname extraction from user@host pattern 194 | p=`expr index "$1" '@'` 195 | if [ $p -gt 0 ]; then 196 | let "l = ${#h} - $p" 197 | h=${h:$p:$l} 198 | fi 199 | 200 | cdfile="$pwd/.vagrant/$h.cd" 201 | 202 | # if cd file is missing, or is older than the definition file, re-generate... 203 | # or if mtime of $f is > than 5 minutes (5 * 60 seconds), re-generate... 204 | if [ ! -e "$cdfile" ] || \ 205 | [ $(stat -c '%Y' "$pfile" 2> /dev/null) -gt $(stat -c '%Y' "$cdfile" 2> /dev/null) ] || \ 206 | [ `date -d "now - $(stat -c '%Y' "$f" 2> /dev/null) seconds" +%s` -gt 300 ]; then 207 | mkdir -p "$d" 208 | # we cache the lookup because this command is slow... 209 | $VAGRANT ssh-config "$h" > "$f" || rm "$f" 210 | fi 211 | 212 | cddir="`cat $cdfile 2>/dev/null`" 213 | if [ -e "$cdfile" ] && [ -n "$cddir" ]; then 214 | cmd="cd '$cddir' && $cmd" 215 | fi 216 | 217 | [ -e "$f" ] && ssh -t -F "$f" "$1" $cmd 218 | if [ $? -eq 255 ]; then 219 | # you probably want a shorter timeout if you see this often 220 | echo 'Maybe cached connection was stale? Cleaning...' 221 | rm -f "$f" # clean stale ssh connection 222 | # TODO: recurse up to one time? 223 | fi 224 | } 225 | 226 | # vagrant cssh 227 | function vcssh { 228 | [ "$1" = '' ] && echo "Usage: vcssh [options] [user@][ [user@]vm2[ [user@]vmN...]] - vagrant cssh" 1>&2 && return 1 229 | vfile='Vagrantfile' 230 | if [[ "$VAGRANT" == omv* ]]; then 231 | vfile='omv.yaml' 232 | fi 233 | wd=`pwd` # save wd, then find the Vagrant project 234 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 235 | #echo "pwd is `pwd`" 236 | cd .. 237 | done 238 | pwd=`pwd` 239 | cd $wd 240 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 241 | echo 'Vagrant project not found!' 1>&2 && return 2 242 | fi 243 | 244 | d="$pwd/.ssh" 245 | cssh="$d/cssh" 246 | cmd='' 247 | cat='cat ' 248 | screen='' 249 | options='' 250 | 251 | multi='f' 252 | special='' 253 | for i in "$@"; do # loop through the list of hosts and arguments! 254 | #echo $i 255 | 256 | if [ "$special" = 'debug' ]; then # optional arg value... 257 | special='' 258 | if [ "$1" -ge 0 -o "$1" -le 4 ]; then 259 | cmd="$cmd $i" 260 | continue 261 | fi 262 | fi 263 | 264 | if [ "$multi" = 'y' ]; then # get the value of the argument 265 | multi='n' 266 | cmd="$cmd '$i'" 267 | continue 268 | fi 269 | 270 | if [ "${i:0:1}" = '-' ]; then # does argument start with: - ? 271 | 272 | # build a --screen option 273 | if [ "$i" = '--screen' ]; then 274 | screen=' -o RequestTTY=yes' 275 | cmd="$cmd --action 'screen -xRR'" 276 | continue 277 | fi 278 | 279 | if [ "$i" = '--debug' ]; then 280 | special='debug' 281 | cmd="$cmd $i" 282 | continue 283 | fi 284 | 285 | if [ "$i" = '--options' ]; then 286 | options=" $i" 287 | continue 288 | fi 289 | 290 | # NOTE: commented-out options are probably not useful... 291 | # match for key => value argument pairs 292 | if [ "$i" = '--action' -o "$i" = '-a' ] || \ 293 | [ "$i" = '--autoclose' -o "$i" = '-A' ] || \ 294 | #[ "$i" = '--cluster-file' -o "$i" = '-c' ] || \ 295 | #[ "$i" = '--config-file' -o "$i" = '-C' ] || \ 296 | #[ "$i" = '--evaluate' -o "$i" = '-e' ] || \ 297 | [ "$i" = '--font' -o "$i" = '-f' ] || \ 298 | #[ "$i" = '--master' -o "$i" = '-M' ] || \ 299 | #[ "$i" = '--port' -o "$i" = '-p' ] || \ 300 | #[ "$i" = '--tag-file' -o "$i" = '-c' ] || \ 301 | [ "$i" = '--term-args' -o "$i" = '-t' ] || \ 302 | [ "$i" = '--title' -o "$i" = '-T' ] || \ 303 | [ "$i" = '--username' -o "$i" = '-l' ] ; then 304 | multi='y' # loop around to get second part 305 | cmd="$cmd $i" 306 | continue 307 | else # match single argument flags... 308 | cmd="$cmd $i" 309 | continue 310 | fi 311 | fi 312 | 313 | f="$d/$i.config" 314 | h="$i" 315 | # hostname extraction from user@host pattern 316 | p=`expr index "$i" '@'` 317 | if [ $p -gt 0 ]; then 318 | let "l = ${#h} - $p" 319 | h=${h:$p:$l} 320 | fi 321 | 322 | # if mtime of $f is > than 5 minutes (5 * 60 seconds), re-generate... 323 | if [ `date -d "now - $(stat -c '%Y' "$f" 2> /dev/null) seconds" +%s` -gt 300 ]; then 324 | mkdir -p "$d" 325 | # we cache the lookup because this command is slow... 326 | $VAGRANT ssh-config "$h" > "$f" || rm "$f" 327 | fi 328 | 329 | if [ -e "$f" ]; then 330 | cmd="$cmd $i" 331 | cat="$cat $f" # append config file to list 332 | fi 333 | done 334 | 335 | cat="$cat > $cssh" 336 | #echo $cat 337 | eval "$cat" # generate combined config file 338 | 339 | #echo $cmd && return 1 340 | #[ -e "$cssh" ] && cssh --options "-F ${cssh}$options" $cmd 341 | # running: bash -c glues together --action 'foo --bar' type commands... 342 | [ -e "$cssh" ] && bash -c "cssh --options '-F ${cssh}${screen}$options' $cmd" 343 | } 344 | 345 | # vagrant forward (ssh -L) 346 | function vfwd { 347 | [ "$1" = '' ] || [ "$2" = '' ] && echo "Usage: vfwd hostport:guestport [hostport:guestport] - vagrant ssh forward" 1>&2 && return 1 348 | vfile='Vagrantfile' 349 | if [[ "$VAGRANT" == omv* ]]; then 350 | vfile='omv.yaml' 351 | fi 352 | wd=`pwd` # save wd, then find the Vagrant project 353 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 354 | #echo "pwd is `pwd`" 355 | cd .. 356 | done 357 | pwd=`pwd` 358 | cd $wd 359 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 360 | echo 'Vagrant project not found!' 1>&2 && return 2 361 | fi 362 | 363 | d="$pwd/.ssh" 364 | f="$d/$1.config" 365 | h="$1" 366 | # hostname extraction from user@host pattern 367 | p=`expr index "$1" '@'` 368 | if [ $p -gt 0 ]; then 369 | let "l = ${#h} - $p" 370 | h=${h:$p:$l} 371 | fi 372 | 373 | # if mtime of $f is > than 5 minutes (5 * 60 seconds), re-generate... 374 | if [ `date -d "now - $(stat -c '%Y' "$f" 2> /dev/null) seconds" +%s` -gt 300 ]; then 375 | mkdir -p "$d" 376 | # we cache the lookup because this command is slow... 377 | $VAGRANT ssh-config "$h" > "$f" || rm "$f" 378 | fi 379 | 380 | name="$1" 381 | shift # pop off the vmname 382 | fwd=() # array 383 | cmd='ssh' 384 | for x in "${@}" 385 | do 386 | #echo "pair: $x" 387 | port=`echo "$x" | awk -F ':' '{print $1}'` 388 | if [ "$port" -le 1024 ]; then 389 | cmd='sudo ssh' # sudo needed for < 1024 390 | fi 391 | b=`echo "$x" | awk -F ':' '{print "-L "$1":localhost:"$2}'` 392 | fwd+=("$b") # append 393 | done 394 | echo ${fwd[@]} # show the -L commands 395 | [ -e "$f" ] && $cmd -N -F "$f" root@"$name" "${fwd[@]}" 396 | } 397 | 398 | # vagrant ansible 399 | function vansible { 400 | [ "$1" = '' ] && echo "Usage: vansible [ansible args] - vagrant ansible" 1>&2 && return 1 401 | vfile='Vagrantfile' 402 | if [[ "$VAGRANT" == omv* ]]; then 403 | vfile='omv.yaml' 404 | fi 405 | wd=`pwd` # save wd, then find the Vagrant project 406 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 407 | #echo "pwd is `pwd`" 408 | cd .. 409 | done 410 | pwd=`pwd` 411 | cd $wd 412 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 413 | echo 'Vagrant project not found!' 1>&2 && return 2 414 | fi 415 | 416 | k="`echo ~/.vagrant.d/insecure_private_key`" 417 | if [ ! -e "$k" ]; then 418 | echo 'Vagrant private key not found!' 1>&2 && return 3 419 | fi 420 | 421 | i="$pwd/.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory" 422 | if [ ! -e "$i" ]; then 423 | echo 'Vagrant generated inventory not found!' 1>&2 && return 4 424 | fi 425 | 426 | ansible --private-key="$k" --inventory="$i" "$@" 427 | } 428 | 429 | # vagrant test (run tests from the `tests` omv.yaml variable) 430 | function vtest { 431 | [ "$1" != '' ] && echo "Usage: vtest - vagrant test" 1>&2 && return 1 432 | vfile='Vagrantfile' 433 | if [[ "$VAGRANT" == omv* ]]; then 434 | vfile='omv.yaml' 435 | fi 436 | wd=`pwd` # save wd, then find the Vagrant project 437 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 438 | #echo "pwd is `pwd`" 439 | cd .. 440 | done 441 | pwd=`pwd` 442 | cd $wd 443 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 444 | echo 'Vagrant project not found!' 1>&2 && return 2 445 | fi 446 | 447 | # if we find the omv.yaml file, it takes precendence for mtime lookups 448 | if [ -e "$pwd/omv.yaml" ]; then 449 | pfile="$pwd/omv.yaml" 450 | elif [ -e "$pwd/Vagrantfile" ]; then 451 | pfile="$pwd/Vagrantfile" 452 | else 453 | echo 'No vagrant definition found!' 1>&2 && return 2 454 | fi 455 | 456 | $VAGRANT status &>/dev/null # cause the tests file to be generated 457 | if [ ! -e "$pwd/.vagrant/tests.sh" ]; then 458 | echo 'No vagrant tests.sh file found!' 1>&2 && return 3 459 | fi 460 | 461 | "$pwd/.vagrant/tests.sh" # run the tests 462 | r=$? 463 | #$VAGRANT destroy # clean up! 464 | return $r 465 | } 466 | 467 | # vagrant test+ (run fancy tests from the `tests` omv.yaml variable) 468 | function vtest+ { 469 | [ "$2" != '' ] && echo "Usage: vtest+ [omv.yaml] - vagrant test plus" 1>&2 && return 1 470 | owd=`pwd` # original wd 471 | if [ "$1" != '' ]; then 472 | [[ ! "$1" == *'.yaml' ]] && echo "File: '$1' must be a .yaml file!" 1>&2 && return 1 473 | [ ! -e "$1" ] && echo "File: '$1' does not exist!" 1>&2 && return 1 474 | d=`mktemp --tmpdir -d vtest.XXX` 475 | cp "$1" "$d"/omv.yaml 476 | cd "$d" 477 | mkdir '.vagrant' 478 | fi 479 | vfile='Vagrantfile' 480 | if [[ "$VAGRANT" == omv* ]]; then 481 | vfile='omv.yaml' 482 | fi 483 | wd=`pwd` # save wd, then find the Vagrant project 484 | while [ "`pwd`" != '/' ] && [ ! -e "`pwd`/$vfile" ] && [ ! -d "`pwd`/.vagrant/" ]; do 485 | #echo "pwd is `pwd`" 486 | cd .. 487 | done 488 | pwd=`pwd` 489 | cd $wd 490 | if [ ! -e "$pwd/$vfile" ] || [ ! -d "$pwd/.vagrant/" ]; then 491 | cd $owd 492 | echo 'Vagrant project not found!' 1>&2 && return 2 493 | fi 494 | 495 | # if we find the omv.yaml file, it takes precendence for mtime lookups 496 | if [ -e "$pwd/omv.yaml" ]; then 497 | pfile="$pwd/omv.yaml" 498 | elif [ -e "$pwd/Vagrantfile" ]; then 499 | pfile="$pwd/Vagrantfile" 500 | else 501 | cd $owd 502 | echo 'No vagrant definition found!' 1>&2 && return 2 503 | fi 504 | 505 | $VAGRANT status &>/dev/null # cause the tests file to be generated 506 | if [ ! -e "$pwd/.vagrant/tests.sh" ]; then 507 | cd $owd 508 | echo 'No vagrant tests.sh file found!' 1>&2 && return 3 509 | fi 510 | 511 | LINE=$(printf '=%.0s' `seq -s ' ' $(tput cols)`) # a terminal width string 512 | count=0 513 | failures="" 514 | # loop through tests 515 | while read -r -u "$fd" i; do # http://mywiki.wooledge.org/BashFAQ/089 516 | count=`expr $count + 1` 517 | echo "$i" | grep -q '^#' && continue # ignore comments 518 | #export _TMPDIR='/tmp/oh-my-vagrant/' # we can add to env like this 519 | out="$($i 2>&1)" # run and capture stdout & stderr 520 | e=$? # save exit code 521 | if [ $e -ne 0 ]; then 522 | # store failures... 523 | failures=$( 524 | # prepend previous failures if any 525 | [ -n "${failures}" ] && echo "$failures" && echo "$LINE" 526 | echo "Lineno: $count" 527 | echo "Script: $i" 528 | # if we see 124, it might be the exit value of timeout! 529 | [ $e -eq 124 ] && echo "Exited: $e (timeout?)" || echo "Exited: $e" 530 | if [ "$out" = "" ]; then 531 | echo "Output: (empty!)" 532 | else 533 | echo "Output:" 534 | echo "$out" 535 | fi 536 | ) 537 | else 538 | echo -e "ok\t$i\t(line: $count)" # pass 539 | fi 540 | done {fd}< "$pwd/.vagrant/tests.sh" # send in the test file line by line 541 | cd $owd 542 | # display errors 543 | if [[ -n "${failures}" ]]; then 544 | echo 'FAIL' 545 | echo 'The following tests failed:' 546 | echo "${failures}" 547 | return 1 548 | fi 549 | return 0 550 | } 551 | -------------------------------------------------------------------------------- /DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | # Oh-My-Vagrant 2 | 3 | 21 | 22 | ## Oh-My-Vagrant by [James](https://ttboj.wordpress.com/) 23 | #### Available from: 24 | #### [https://github.com/purpleidea/oh-my-vagrant/](https://github.com/purpleidea/oh-my-vagrant/) 25 | 26 | #### This documentation is available in: [Markdown](https://github.com/purpleidea/oh-my-vagrant/blob/master/DOCUMENTATION.md) or [PDF](https://pdfdoc-purpleidea.rhcloud.com/pdf/https://github.com/purpleidea/oh-my-vagrant/blob/master/DOCUMENTATION.md) format. 27 | 28 | #### Table of Contents 29 | 30 | 1. [Overview](#overview) 31 | 2. [Project description - What the project does](#project-description) 32 | 3. [Setup - Getting started with Oh-My-Vagrant](#setup) 33 | * [What can Oh-My-Vagrant do?](#what-can-oh-my-vagrant-do) 34 | * [Mainstream usage](#mainstream-usage) 35 | * [Simple usage](#simple-usage) 36 | * [Complex usage](#complex-usage) 37 | * [Example modules](#example-modules) 38 | 4. [Usage/FAQ - Notes on usage and frequently asked questions](#usage-and-frequently-asked-questions) 39 | 5. [Reference - Detailed reference](#reference) 40 | * [omv.yaml](#omv.yaml) 41 | * [Command line](#command-line) 42 | * [oh-my-vagrant.yaml](#oh-my-vagrant.yaml) 43 | 6. [Examples - Example configurations](#examples) 44 | 7. [Limitations - Vagrant versions, OS compatibility, etc...](#limitations) 45 | 8. [Development - Background on module development and reporting bugs](#development) 46 | 9. [Authors - Authors and contact information](#authors) 47 | 48 | ## Overview 49 | 50 | The Oh-My-Vagrant project lets you describe your Vagrant configuration declaratively 51 | in YAML, and provides a general purpose Vagrantfile that reads that configuration 52 | and passes it to Vagrant. 53 | 54 | ## Project Description 55 | 56 | Vagrant is great, but it has some rough edges, especially if you want your Vagrant 57 | files to work across multiple local virt providers (e.g. VirtualBox, libvirt), and 58 | multiple host operating systems (whether Windows, Mac OS X, or your preferred 59 | flavour of Linux). 60 | 61 | The Oh-My-Vagrant project provides a rich Vagrantfile that avoids (or works around) 62 | many of those rough edges by reading in the desired configuration from a 63 | declarative YAML syntax that allows for dynamic lists of virtual machines, 64 | Puppet(/Ansible/Chef/Salt) integration, docker containers in each machine, 65 | automatic DNS setup, easy box downloading, and more! 66 | 67 | Instead of having to write complex, partially declarative pseudo-ruby code to 68 | create and modify a Vagrant environment, you can instead do all the manipulation 69 | simply by editing a short `omv.yaml` definition file. The provided Vagrantfile 70 | then reads this definition to dynamically configure Vagrant. Additionally, it 71 | integrates with code to help you run existing configuration management utilities, 72 | kick off docker commands, and more! 73 | 74 | For more information, start by reading and working through the introductory 75 | [blog post](https://ttboj.wordpress.com/2014/09/03/introducing-oh-my-vagrant/). 76 | 77 | ## Setup 78 | 79 | ### What can Oh-My-Vagrant do? 80 | 81 | Oh-My-Vagrant is designed to be able to deal with: 82 | 83 | * Dynamic lists of named virtual machines 84 | * Dynamic lists of numbered virtual machines 85 | * Automatic Puppet/Ansible/Chef/Salt integration 86 | * Automatic DNS setup 87 | * Easy Vagrant box downloading (for certain OS choices) 88 | * Docker container enablement in each virtual machine 89 | * Automatic Kubernetes setup 90 | * And much more... 91 | 92 | ### Mainstream usage 93 | Oh-My-Vagrant now supports a "mainstream" mode. This is the most common way to 94 | use OMV when it is installed via your package manager. You interact with it 95 | entirely with the `omv` binary. The `omv` binary works exactly like the 96 | `vagrant` command that you're used to, except that it works directly on the 97 | `omv.yaml` file, and hides the Vagrantfile complexity inside a system folder. 98 | 99 | To initialize a new OMV environment, you can run: 100 | 101 | ```bash 102 | $ omv init 103 | ``` 104 | 105 | to automatically create an `omv.yaml` file. If you supply a path as an argument 106 | to the init verb, then all OMV project specific files will be stored in this 107 | sub directory, to avoid cluttering up your project root directory. 108 | 109 | ### Simple usage 110 | 111 | For most use cases, the simple usage of Oh-My-Vagrant should fulfill all your 112 | needs. Start by recursively cloning the project, and entering the vagrant/ 113 | directory: 114 | 115 | ```bash 116 | $ git clone --recursive https://github.com/purpleidea/oh-my-vagrant 117 | $ cd oh-my-vagrant/vagrant/ 118 | ``` 119 | 120 | In this directory (or any of the children directories), you can run typical 121 | vagrant command line tools, which will use the powerful Vagrantfile provided. 122 | Instead of changing the pseudo-ruby code used in the Vagrantfile, you can 123 | instead customize the behaviour by modifying a simple omv.yaml file. 124 | 125 | Everytime you run a vagrant command, the omv.yaml file will be read in (if 126 | it exists) parsed, and then written out in the same location. As a result, any 127 | erroneous, not compliant, or non parseable data you put in this file will be 128 | lost. 129 | 130 | If you do not have a omv.yaml template, running the ```vagrant status``` 131 | command will cause one to be generated. Play around with the settings in the 132 | omv.yaml file, and forget about the days where small changes to your 133 | environment, required pasting in a mess of code. 134 | 135 | ### Complex usage 136 | 137 | The complex use case allows Oh-My-Vagrant to be used as a platform that you can 138 | build a "module" on top of. This module can provide a homework environment, a 139 | set of interactive classwork lessons, the definitions for a demonstration 140 | cluster, and perhaps much more. 141 | 142 | Steps for writing a custom module is currently undocumented. Please help 143 | improve this documentation by submitting a patch! In the meantime, you can 144 | refer to one of the existing Oh-My-Vagrant modules, if you're comfortable 145 | learning by example. It's fairly straightforward, but here are some quick 146 | pointers: 147 | 148 | * Your module should be a separate git repo with the correct format. 149 | * You'll need to set the omv.yaml "folder" parameter to match the name of your 150 | module. 151 | * Include your module folder as a git submodule, in the directory next to the 152 | omv.yaml file provided with the Oh-My-Vagrant project. You should name your 153 | branch _module/your_module_name_. You should keep a reference to the branch 154 | with your module in it in this manner, and rebase your branch against the newer 155 | git master branch as often as you can. 156 | * It's fairly straightforward once you look at an example. If you're stuck, 157 | your author would be happy to help out in exchange for code or documentation 158 | patches. 159 | 160 | ### Example modules 161 | 162 | Example modules should be added as git submodules in a branch named: 163 | _module/your_module_name_. For example, if your module is called _gluster_, 164 | then you should create a branch named: _module/gluster_. If you're looking for 165 | an example module, so that you can ascertain the format, and learn what is 166 | possible, here is a list of examples: 167 | 168 | * [p4h](https://github.com/purpleidea/p4h) 169 | * [puppet-pushing](https://github.com/purpleidea/puppet-pushing) 170 | 171 | ## Usage and frequently asked questions 172 | (Send your questions as a patch to this FAQ! I'll review it, merge it, and 173 | respond by commit with the answer.) 174 | 175 | ### Why did you start this project? 176 | 177 | I wasted enough time making custom Vagrant environments for more than one 178 | project. I took what I learnt about Vagrant, and generalized that in a single 179 | project. Now I don't have to duplicate code, or waste time when I want to make 180 | changes to my Vagrant environment. 181 | 182 | ### Why are there multiple network interfaces created on each OMV managed host? 183 | 184 | Each VM brought up by OMV and vagrant-libvirt typically has two interfaces by 185 | default. The first interface on the VM (which uses DHCP) is used to initially 186 | get a connection to vagrant, since vagrant finds the machines by looking in the 187 | DHCP leases table in Dnsmasq. This is the only way vagrant can find the IP 188 | address. It would be great if there was an out of band communication method, 189 | but nothing like this exists in vagrant-libvirt at this time. After vagrant 190 | has found the VM, it makes all of its changes over this interface using SSH. 191 | Since the first interface requires DHCP, and because many multi host clusters 192 | prefer a consistent (statically assigned) IP address across reboots, OMV adds a 193 | second interface which has this statically assigned address. It also provides 194 | DNS for this network interface via the `/etc/hosts` file. 195 | 196 | ### Why is there an extra entry in the `/etc/hosts` file on each VM? 197 | 198 | Every VM created by OMV includes an extra entry in the `/etc/hosts` file: 199 | 200 | ``` 201 | [vagrant@omv1 ~]$ cat /etc/hosts 202 | ... 203 | ## vagrant-hostmanager-start 204 | 192.168.123.100 omv1.example.com omv1 205 | 192.168.123.3 omv.example.com omv 206 | ## vagrant-hostmanager-end 207 | ... 208 | ``` 209 | 210 | The `192.168.123.3 omv.example.com omv` line represents a virtual 211 | IP address reserved on every VM in the cluster. It's unused by default and can 212 | be used by the developer for any purpose. It's commonly used by keepalived when 213 | using the VM cluster to demonstrate leader election. 214 | 215 | ### Do you have any tricks for using Vagrant and Vagrant-Libvirt? 216 | 217 | I've written a bunch about Vagrant and Vagrant-Libvirt on my 218 | [technical blog](https://ttboj.wordpress.com/). Since things have changed over 219 | the years, more recent articles are probably more relevant, and there may be 220 | old information which is no longer necessary. As a result, use your judgement, 221 | and in doubt, feel free to ask. In particular, there are a few articles which 222 | are probably still relevant, and which will be very useful. They are: 223 | 224 | * [Vagrant vsftp and other tricks](https://ttboj.wordpress.com/2013/12/21/vagrant-vsftp-and-other-tricks/) 225 | * [Vagrant clustered SSH and ‘screen’](https://ttboj.wordpress.com/2014/01/02/vagrant-clustered-ssh-and-screen/) 226 | 227 | ### Can I use this without puppet? 228 | 229 | Yes, absolutely. This provides puppet integration, but it is entirely optional. 230 | If you'd like to add integration for another configuration management system, 231 | please send a patch. 232 | 233 | ### Something isn't working correctly, and I feel I'm missing some code... 234 | 235 | This project has some useful dependencies which are included in the main 236 | project as git submodules. To ensure you get all of the code, make sure you do 237 | an initial clone with the `--recursive` flag. Example: 238 | 239 | ```git clone --recursive https://github.com/purpleidea/oh-my-vagrant/``` 240 | 241 | ### Does this work on Windows? 242 | 243 | Almost all of the code is `vagrant` specific ruby code, therefore OMV should 244 | work on anything that vagrant works on. However, there is a bit of platform 245 | specific code added to OMV that is currently known to use POSIX file system 246 | semantics, and as a result likely won't work under Windows. This means you can 247 | either use OMV with fewer features on Windows, or help by patching it and 248 | testing it on that platform. So far, few have wanted to use or develop on that 249 | platform, with most preferring GNU/Linux and sometimes OSX, which are both 250 | fully functional at this time. 251 | 252 | ### Awesome work, but it's missing support for a feature and/or platform! 253 | 254 | Since this is an Open Source / Free Software project that I also give away for 255 | free (as in beer, free as in gratis, free as in libre), I'm unable to provide 256 | unlimited support. Please consider donating funds, hardware, virtual machines, 257 | and other resources. For specific needs, you could perhaps sponsor a feature! 258 | 259 | ### I am seeing a similar error that mentions `hostmanager`. The error looks like: 260 | 261 | ``` 262 | $ vagrant status 263 | There are errors in the configuration of this machine. Please fix 264 | the following errors and try again: 265 | 266 | Vagrant: 267 | * Unknown configuration section 'hostmanager'. 268 | ``` 269 | 270 | You are seeing this error because OMV has certain requirements. One of which 271 | is a plugin that can manage hostnames. In general, we want to be able to have 272 | members of the cluster access each other via FQDN. Now, there are two ways to 273 | do this: 274 | 275 | 1. Add a real DNS server somewhere and make sure the hosts can get to it. 276 | 2. Modify the /etc/hosts file on each host in the vagrant cluster to have a record 277 | for all of the other machines 278 | 279 | So, the way we can fix this error is to install the `hostmanager` plugin. 280 | 281 | ``` 282 | $ wget https://raw.githubusercontent.com/purpleidea/oh-my-vagrant/master/extras/patch-hostmanager.sh 283 | 284 | 2015-07-01 13:11:45 (384 MB/s) - ‘patch-hostmanager.sh’ saved [1315/1315] 285 | 286 | $ chmod +x patch-hostmanager.sh && ./patch-hostmanager.sh 287 | Installing the 'vagrant-hostmanager' plugin. This can take a few minutes... 288 | Installed the plugin 'vagrant-hostmanager (1.5.0)'! 289 | Cloning into 'vagrant-hostmanager'... 290 | remote: Counting objects: 801, done. 291 | remote: Total 801 (delta 0), reused 0 (delta 0), pack-reused 801 292 | Receiving objects: 100% (801/801), 132.64 KiB | 0 bytes/s, done. 293 | Resolving deltas: 100% (465/465), done. 294 | Checking connectivity... done. 295 | 296 | sent 20,583 bytes received 319 bytes 41,804.00 bytes/sec 297 | total size is 19,533 speedup is 0.93 298 | Patched successfully! 299 | ``` 300 | Now you can run `vagrant status` successfully and utilize the function of the plug-in 301 | which allows you to modify the /etc/hosts file on each host in the cluster. 302 | 303 | ### You didn't answer my question, or I have a question! 304 | 305 | Contact me through my [technical blog](https://ttboj.wordpress.com/contact/) 306 | and I'll do my best to help. If you have a good question, please remind me to 307 | add my answer to this documentation! 308 | 309 | ## Reference 310 | Please note that there are a number of undocumented options. For more 311 | information on these options, please view the source at: 312 | [https://github.com/purpleidea/oh-my-vagrant/](https://github.com/purpleidea/oh-my-vagrant/). 313 | If you feel that a well used option needs documenting here, please contact me. 314 | 315 | ### Overview of reference 316 | * [omv.yaml](#omv.yaml): Main configuration file. 317 | * [Command line](#command-line): Command line parameters. 318 | * [oh-my-vagrant.yaml](#oh-my-vagrant.yaml): User specific configuration. 319 | 320 | ### omv.yaml 321 | Editing the omv.yaml file is the primary way of modifying your Oh-My-Vagrant 322 | environment. If you don't have a template, running the `vagrant status` command 323 | should cause one to get created with some sensible defaults. 324 | 325 | While the reference docs for OMV itself are currently incomplete, you can get a 326 | fair way given the main [Vagrant documentation](https://docs.vagrantup.com/) and 327 | the assumption that if an `omv.yaml` setting matches the name of a Vagrant box 328 | configuration setting, then that setting in the YAML provides arguments to 329 | the corresponding call in the Vagrantfile. 330 | 331 | #### `domain` 332 | Currently undocumented. 333 | 334 | #### `network` 335 | Subnet (in CIDR notation) that will be used for virtual machines. 336 | If you're using Libvirt, make sure it does not clash with the existing virtual 337 | networks on your machine. If it does - you have to set [:namespace](#namespace) 338 | parameter to be the same as existing network name, otherwise things will not 339 | work. 340 | 341 | #### `image` 342 | Vagrant box name (excluding `.box` extension) that will be used to build a 343 | virtual machine. 344 | If it does not exist on the system - it will be downloaded from [:boxurlprefix](#boxurlprefix). 345 | 346 | #### `cpus` 347 | Currently undocumented. 348 | 349 | #### `memory` 350 | Currently undocumented. 351 | 352 | #### `disks` 353 | Currently undocumented. 354 | 355 | #### `disksize` 356 | Currently undocumented. 357 | 358 | #### `boxurlprefix` 359 | URL pointing to a location that contains Vagrant box files. 360 | It points to https://dl.fedoraproject.org/pub/alt/purpleidea/vagrant/ by 361 | default. 362 | 363 | #### `sync` 364 | Sync type to use. Valid types include `rsync` and `nfs` (version 3). Other 365 | types, including `nfsv4` and `9p`, will hopefully be supported in the future. 366 | 367 | #### `syncdir` 368 | This option sets where your project folder gets synced into the machine. If you 369 | pass an absolute path, that will be used, if you pass a relative path, then that 370 | will be appended to the default path for that environment. In general, you will 371 | get appended to `/vagrant/`, however on an atomic host, this default is 372 | `/home/vagrant/sync/`. If you specify an empty string (the default) then no 373 | special path will be appended, and your working directory will get synced into 374 | the default location as specified above. Lastly, if you specify the special 375 | path of `/`, then your project will be synced into a subfolder of the same name 376 | of your project folder, and located beneath the above default location. 377 | 378 | For example, if you have a project (a git repository perhaps) named `mgmt`, and 379 | you want to sync the files into `/vagrant/mgmt/`, then the special `/` path is 380 | the magic feature you're looking for. 381 | 382 | #### `syncsrc` 383 | Set the sync source for your vm. When left with the empty string `''`, this 384 | defaults to the [`folder`](#folder) in your project directory. When 385 | [`folder`](#folder) is empty, obviously the project directory is used by itself. 386 | This option is particularly useful because you can pass it the `..` value, which 387 | will pick the parent directory. This is a common hack for projects which hide 388 | the _mess_ of their project inside the [`folder`](#folder) variable, but want 389 | the whole project to get synchronized into the machine. 390 | 391 | #### `folder` 392 | Currently undocumented. 393 | 394 | #### `extern` 395 | Currently undocumented. 396 | 397 | #### `cd` 398 | If you set this to a string, the `cd` command will run with this arg after 399 | `vscreen` connects to your vm, but before the `screen` command runs. This will 400 | have the effect of putting you in your favourite working directory 401 | automatically. This also works when using `vsftp`, but not `vcssh`. If you set 402 | the `cd` value to `$SYNCDIR` (a string literal) or to `-` (the dash) then these 403 | are magic variables which indicate you want to cd to whichever path the 404 | [`syncdir`](#syncdir) option resolves to. 405 | 406 | #### `puppet` 407 | Currently undocumented. 408 | 409 | #### `classes` 410 | Currently undocumented. 411 | 412 | #### `shell` 413 | Currently undocumented. 414 | 415 | #### `docker` 416 | Currently undocumented. 417 | 418 | #### `kubernetes` 419 | Currently undocumented. 420 | 421 | #### `ansible` 422 | Currently undocumented. 423 | 424 | #### `playbook` 425 | Currently undocumented. 426 | 427 | #### `ansible_extras` 428 | Currently undocumented. 429 | 430 | #### `cachier` 431 | Currently undocumented. 432 | 433 | #### `vms` 434 | By default, oh-my-vagrant will create [:count](#count) number of virtual 435 | machines, all with the same settings, and generated hostnames and IP addresses. 436 | Using the `:vms` array you can define different parameters for different VMs. 437 | Example: 438 | ```yaml 439 | :vms: 440 | - :name: master-vm 441 | :image: fedora-21 442 | :disks: 1 443 | :disksize: 10G 444 | :memory: 1024 445 | :cpus: 2 446 | - :name: slave-vm 447 | :image: centos-7.1 448 | :count: 0 449 | ``` 450 | The above configuration will create 2 virtual machines: first one will have 2 451 | CPUs and 1G of RAM assigned, as well as additional 10G hard disk, and will be 452 | based on the Fedora 21 image. The 2nd one will be created with the default 453 | values (1 CPU, 512MB of RAM), and will be based on centos-7.1 image. 454 | 455 | Have a look at [Ansible example](https://github.com/purpleidea/oh-my-vagrant/blob/master/examples/ansible.yaml) 456 | to get an idea about how the complete configuration looks like. 457 | 458 | **Note**: If you're using `:vms` to define custom VMs, you might want to set 459 | `:count` parameter to zero. If you don't do this, oh-my-vagrant will always 460 | create `:count` extra VMs, which you might want or not, depending on your setup. 461 | See [this comment](https://github.com/purpleidea/oh-my-vagrant/pull/122#issuecomment-136054512) 462 | for an example situation where this might be useful. 463 | 464 | #### `namespace` 465 | Free-form string that will be used as: 466 | 467 | * Libvirt/VirtualBox virtual network name 468 | * prefix for virtual machines names generation, if [:vms](#vms) array is not 469 | defined 470 | 471 | If you set this to the same string as an existing network name - make sure you 472 | also set [:network](#network) parameter correctly. 473 | 474 | #### `count` 475 | Set this to the number of virtual machines you want oh-my-vagrant to create. 476 | Hostnames and IP addresses will be generated automatically, and fair defaults 477 | will be used for the VMs. 478 | Example: 479 | ```yaml 480 | :namespace: testing-omv 481 | :count: 5 482 | ``` 483 | Above configuration will create 5 virtual machines: testing-omv1, testing-omv2 484 | ... testing-omv5. 485 | 486 | See also [:vms](#vms) parameter documentation for information about how you can 487 | define various virtual machine parameters yourself. 488 | 489 | #### `username` 490 | Currently undocumented. 491 | 492 | #### `password` 493 | Currently undocumented. 494 | 495 | #### `poolid` 496 | 497 | Array of [Red Hat Subscription Manager pool(s)](https://access.redhat.com/documentation/en-US/Red_Hat_Subscription_Management/1/html-single/RHSM/#subscr-about-pools) 498 | to attach to a system. 499 | _Note:_ even if you want to supply only one pool ID, you still have to do it 500 | with YAML list notation, like this: 501 | 502 | ```yaml 503 | :poolid: 504 | - ff8080812bc382e3012bc3845ca000cb 505 | ``` 506 | 507 | If you want to pass `--auto` parameter to subscription-manager command, set 508 | `:poolid:` to any arbitrary value (`auto` is a good choice): 509 | 510 | ```yaml 511 | :poolid: auto 512 | ``` 513 | 514 | #### `repos` 515 | 516 | Array of [Red Hat Subscription Manager repositories](https://access.redhat.com/documentation/en-US/Red_Hat_Subscription_Management/1/html-single/RHSM/#entitlements-and-yum) 517 | to add to a system. 518 | Prepending `#` sign in front of repository name will disable this repository. 519 | 520 | Usually it's desirable to disable all repositories from a pool, and then only 521 | enable the repositories that are really needed (to avoid conflicts and other 522 | related issues). To achieve this, `:repos:` array should look like this: 523 | ```yaml 524 | :repos: 525 | - '#*' 526 | - repo1 527 | - repo2 528 | - ... 529 | ``` 530 | 531 | The above YAML represents the following sequence of commands: 532 | 533 | ```bash 534 | subscription-manager repos --disable '*' 535 | subscription-manager repos --enable 'repo1' 536 | subscription-manager repos --enable 'repo2' 537 | subscription-manager repos --enable '...' 538 | ``` 539 | 540 | #### `update` 541 | Currently undocumented. 542 | 543 | #### `reboot` 544 | Currently undocumented. 545 | 546 | #### `unsafe` 547 | Set this to true if you want to use KVM's unsafe cache mode. If you do this, you 548 | will trade data integrity on your development environment's filesystem for a 549 | noticeable speed boost. See http://libvirt.org/formatdomain.html#elementsDisks 550 | 551 | #### `nested` 552 | Currently undocumented. 553 | 554 | #### `comment` 555 | A space to store a string comment of your choosing. This field is not currently 556 | used anywhere by Oh-My-Vagrant. 557 | 558 | #### `reallyrm` 559 | You probably shouldn't play with this unless you've read and understand the 560 | source. 561 | 562 | ### Command line 563 | The command line arguments are currently undocumented. If you'd like to help 564 | improve these, please send a patch. They are not critical to Oh-My-Vagrant 565 | usage, because all operations can be done by editing the omv.yaml 566 | configuration file. Using the command line does make using Oh-My-Vagrant a lot 567 | faster if you're constantly changing your environment. It also makes people say 568 | "Whoa!". 569 | 570 | #### `--vagrant-help` 571 | This option doesn't yet exist. To add it, please send in a patch! 572 | 573 | ### oh-my-vagrant.yaml 574 | This is a user specific configuration file which typically goes in 575 | `~/.oh-my-vagrant.yaml` or in `~/config/oh-my-vagrant.yaml` if using a sane 576 | default xdg configuration. 577 | 578 | #### username 579 | Currently undocumented. 580 | 581 | #### password 582 | Currently undocumented. 583 | 584 | ## Examples 585 | For example configurations, please consult the [examples/](https://github.com/purpleidea/oh-my-vagrant/tree/master/examples) directory in the git 586 | source repository. It is available from: 587 | 588 | [https://github.com/purpleidea/oh-my-vagrant/tree/master/examples](https://github.com/purpleidea/oh-my-vagrant/tree/master/examples) 589 | 590 | ## Limitations 591 | This project will work with Vagrant version 1.6.5 and greater. It may work with 592 | certain older versions of vagrant, but they are no longer tested. Hopefully new 593 | versions of Vagrant don't introduce any regressions that break this project. 594 | 595 | This project will work with Vagrant-Libvirt version 0.0.20 or greater, but 596 | using version 0.0.23 or greater is recommended. The same disclaimer about 597 | regressions in future versions apply. 598 | 599 | This project is routinely tested on: 600 | 601 | * Fedora 21+ 602 | 603 | It will probably work without incident or without major modification on: 604 | 605 | * Debian 7+ 606 | * Fedora 20 607 | * CentOS 5.x/6.x/7.x 608 | * RHEL 5.x/6.x/7.x 609 | 610 | It has not been tested by the author (but should work) on: 611 | 612 | * Ubuntu 12.04+ 613 | 614 | It will most likely work on other GNU/Linux platforms, but testing on those 615 | platforms has been minimal due to lack of time and resources. 616 | 617 | Testing is community supported! Please report any issues as there are a lot of 618 | features, and in particular, support for additional distros isn't well tested. 619 | 620 | ## Development 621 | 622 | This is my personal project that I work on in my free time. 623 | Donations of funding, hardware, virtual machines, and other resources are 624 | appreciated. Please contact me if you'd like to sponsor a feature, invite me to 625 | talk/teach or for consulting. 626 | 627 | You can follow along [on my technical blog](https://ttboj.wordpress.com/). 628 | 629 | To report any bugs, please file a ticket at: [https://github.com/purpleidea/oh-my-vagrant/issues](https://github.com/purpleidea/oh-my-vagrant/issues). 630 | 631 | ## Authors 632 | 633 | Copyright (C) 2012-2015+ James Shubin and the Oh-My-Vagrant contributors 634 | 635 | Please see the 636 | [AUTHORS](https://github.com/purpleidea/oh-my-vagrant/tree/master/AUTHORS) file 637 | for more information. 638 | 639 | * [github](https://github.com/purpleidea/) 640 | * [@purpleidea](https://twitter.com/#!/purpleidea) 641 | * [https://ttboj.wordpress.com/](https://ttboj.wordpress.com/) 642 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published by 637 | the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby noet : 3 | 4 | # This is: Oh My Vagrant! 5 | # Copyright (C) 2012-2015+ James Shubin and the Oh-My-Vagrant contributors 6 | # Written by James Shubin and the Oh-My-Vagrant contributors 7 | # 8 | # This program is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Affero General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Affero General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Affero General Public License 19 | # along with this program. If not, see . 20 | 21 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 22 | VAGRANTFILE_API_VERSION = '2' 23 | 24 | require 'ipaddr' 25 | require 'yaml' 26 | require 'erb' 27 | require 'ostruct' 28 | require 'base64' 29 | require 'fileutils' 30 | 31 | # 32 | # globals 33 | # 34 | # thanks to the gluster.org community for the public box hosting 35 | default_boxurlprefix = 'https://dl.fedoraproject.org/pub/alt/purpleidea/vagrant' 36 | really_use_rm = false # this causes the rm -rf to actually happen if set true 37 | really_use_rm_once = nil # this causes the rm -rf to happen once 38 | 39 | # 40 | # vms 41 | # 42 | # NOTE: you can specify the list of vms here, or in the omv.yaml file... 43 | # NOTE: if you set the vagrant vms array to nil, you'll default to this list 44 | vms = [ 45 | # {:name => 'example1', :docker => true, :puppet => true, }, # example1 46 | # {:name => 'example2', :docker => ['centos', 'fedora'], }, # example2 47 | # {:name => 'example3', :docker => 48 | # [ 49 | # {:name => 'centos', }, 50 | # {:name => 'fedora', }, 51 | # ], 52 | # }, # example3 53 | # {:name => 'example4', :image => 'centos-6', :puppet => true, }, # example4 54 | # {:name => 'example5', :image => 'rhel-7.0', :poolid => true, }, # example5 55 | # {:name => 'example6', :puppet => true, :classes => # example6 56 | # ['module1', 'module2', 'module3'], 57 | # }, 58 | # {:name => 'example7', :puppet => true, :classes => # example7 59 | # { 60 | # 'module1' => {'arg1' => 'val1', 'arg2' => 'val2'}, 61 | # 'module2' => nil, 62 | # }, 63 | # }, 64 | # {:name => 'example8', :puppet => true, :ip => '192.168.123.3'}, 65 | ] 66 | 67 | # mutable by ARGV and settings file 68 | domain = 'example.com' # demain domain to use (yes this *can* work) 69 | network = '192.168.123.0/24' # default network to use 70 | image = 'centos-7.1' # default image name 71 | cpus = '' # default vcpu count in int (default to undef) 72 | memory = '' # default memory size in mb (default to undef) 73 | disks = 0 # default additional disks (default to none) 74 | disksize = '40G' # default additional disk size (defaults to 20G) 75 | boxurlprefix = '' # default url prefix (useful for private boxes) 76 | sync = 'rsync' # default sync type 77 | syncdir = '' # default directory to put project folder into 78 | syncsrc = '' # default directory to get project folder from 79 | folder = '' # default folder prefix 80 | extern = [] # default external module definitions 81 | cd = '' # default directory to cd into if using vscreen 82 | puppet = false # default use of puppet or not 83 | classes = [] # default list or hash of classes to include 84 | shell = [] # default list of shell scripts to run 85 | docker = false # default use of docker or not 86 | kubernetes = false # default use of kubernetes or not 87 | ansible = [] # default ansible group list 88 | playbook = [] # default ansible playbook 89 | ansible_extras = {} # default ansible extras 90 | cachier = false # default cachier usage 91 | #vms = [] # default list of vms to build (defaults above) 92 | namespace = 'omv' # default namespace (also used as network name) 93 | count = 1 # default number of hosts to build 94 | # TODO: subscription manager needs to grow a way to generate an 'API key' that 95 | # can be used instead of a password so that it can be safely used in scripts... 96 | username = '' # default subscription manager username 97 | password = '' # default subscription manager password 98 | poolid = true # default list of poolid's (true to auto-attach) 99 | repos = [] # default list of extra repos's to enable 100 | update = false # determine whether or not to update the box on vagrant up 101 | reboot = false # reboot the box after provisioning; requires vagrant-reload plugin 102 | unsafe = false # true will trade data safety for performance gains 103 | nested = false # should we allow vm nesting 104 | tests = [] # default list of tests to run 105 | comment = '' # store a comment field in the omv.yaml file 106 | 107 | def array_values_to_array_of_hashes(l) 108 | result = l 109 | if l.is_a?(Array) and l.length > 0 110 | if not l[0].is_a?(Hash) # check the first value 111 | result = l.each_with_object([]) { |x, a| a.push({:name => x}) } 112 | end 113 | end 114 | return result 115 | end 116 | 117 | # useful for unindenting heredoc's 118 | class String 119 | def unindent 120 | gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, '') 121 | end 122 | end 123 | # eg: 124 | #test = <<-EOT.unindent 125 | # 42 126 | #EOT 127 | 128 | vagrantfiledir = File.expand_path File.dirname(__FILE__) # Vagrantfile dir 129 | projectdir = File.expand_path File.dirname(__FILE__) # vagrant project dir!! 130 | 131 | # 132 | # ~/.config/oh-my-vagrant/ parsing 133 | # 134 | # Vagrant is using it's own gem path. Using local xdg gem 135 | # Another option could be adding xdg gem directly to vagrant 136 | begin 137 | gemlibdir = File.join(vagrantfiledir, 'gems/xdg/lib') 138 | $:.unshift(gemlibdir) # add local path for gems 139 | require 'xdg' 140 | auth_config = File.join("#{XDG['CONFIG']}/oh-my-vagrant/", 'auth.yaml') 141 | 142 | rescue LoadError 143 | $stderr.puts "Warning: Can't to load 'xdg' gem - check local gem path" 144 | $stderr.puts gemlibdir 145 | auth_config = File.join("#{Dir.home}/.oh-my-vagrant/", 'auth.yaml') 146 | if not File.exist?(auth_config) 147 | auth_config = File.join("#{Dir.home}/.oh-my-vagrant.yaml") 148 | end 149 | end 150 | if File.exist?(auth_config) 151 | settings = YAML::load_file auth_config 152 | global_username = settings[:username] 153 | global_password = settings[:password] 154 | end 155 | 156 | # 157 | # mainstream mode 158 | # 159 | if "#{ENV['VAGRANT_CWD']}" != '' # if called by omv.sh, this is set... 160 | projectdir = "#{Dir.pwd}" # and we're calling from the new root 161 | omvsearch = projectdir 162 | while omvsearch != '/' # search upwards for omv.yaml 163 | if File.exist?(File.join(omvsearch, 'omv.yaml')) 164 | projectdir = omvsearch # found one! 165 | break 166 | end 167 | omvsearch = File.expand_path('..', omvsearch) 168 | end 169 | end 170 | #ENV['VAGRANT_DOTFILE_PATH'] = File.join(projectdir, '.vagrant/') 171 | 172 | basename = File.basename(projectdir) # name of dir that vagrant project is in 173 | 174 | # 175 | # ARGV parsing 176 | # 177 | f = g = File.join(projectdir, 'omv.yaml') 178 | # check for omv.yaml in folder subdirectory 179 | load_folder = false 180 | if File.exist?(f) 181 | settings = YAML::load_file f 182 | folder = settings[:folder] 183 | 184 | (0..ARGV.length-1).each do |i| 185 | if ARGV[i].start_with?(arg='--omv-folder=') 186 | v = ARGV.delete_at(i).dup 187 | v.slice! arg 188 | folder = v.to_s # set folder prefix 189 | load_folder = true 190 | break 191 | end 192 | end 193 | 194 | # if folder is '', then this doesn't do any different from the original 195 | ff = File.join(projectdir, folder, 'omv.yaml') 196 | if File.exist?(ff) 197 | f = ff 198 | end 199 | end 200 | 201 | # load settings 202 | if File.exist?(f) 203 | settings = YAML::load_file f 204 | domain = settings[:domain] 205 | network = settings[:network] 206 | image = settings[:image] 207 | cpus = settings[:cpus] 208 | memory = settings[:memory] 209 | disks = settings[:disks] 210 | disksize = settings[:disksize] 211 | boxurlprefix = settings[:boxurlprefix] 212 | sync = settings[:sync] 213 | syncdir = settings[:syncdir] 214 | syncsrc = settings[:syncsrc] 215 | folder = settings[:folder] if not(load_folder) 216 | extern = settings[:extern] 217 | cd = settings[:cd] 218 | puppet = settings[:puppet] 219 | classes = settings[:classes] 220 | shell = settings[:shell] 221 | docker = settings[:docker] 222 | kubernetes = settings [:kubernetes] 223 | ansible = settings[:ansible] 224 | playbook = settings[:playbook] 225 | ansible_extras = settings[:ansible_extras] 226 | cachier = settings[:cachier] 227 | if settings[:vms].is_a?(Array) 228 | vms = settings[:vms] 229 | end 230 | namespace = settings[:namespace] 231 | count = settings[:count] 232 | username = settings[:username] 233 | password = settings[:password] 234 | poolid = settings[:poolid] 235 | repos = settings[:repos] 236 | update = settings[:update] 237 | reboot = settings[:reboot] 238 | unsafe = settings[:unsafe] 239 | nested = settings[:nested] 240 | tests = settings[:tests] 241 | comment = settings[:comment] 242 | really_use_rm = settings[:reallyrm] 243 | if [nil, 'nil', 'null', 'none'].include?(really_use_rm.to_s.downcase) 244 | really_use_rm = nil # don't rm or bug user at all 245 | end 246 | end 247 | 248 | # ARGV parser 249 | skip = 0 250 | while skip < ARGV.length 251 | #puts "#{skip}, #{ARGV[skip]}" # debug 252 | if ARGV[skip].start_with?(arg='--omv-domain=') 253 | v = ARGV.delete_at(skip).dup 254 | v.slice! arg 255 | #puts "#{arg}, #{v}" # debug 256 | 257 | domain = v.to_s # set domain 258 | 259 | elsif ARGV[skip].start_with?(arg='--omv-network=') 260 | v = ARGV.delete_at(skip).dup 261 | v.slice! arg 262 | 263 | network = v.to_s # set network range 264 | 265 | elsif ARGV[skip].start_with?(arg='--omv-image=') 266 | v = ARGV.delete_at(skip).dup 267 | v.slice! arg 268 | 269 | image = v.to_s # set base image 270 | 271 | elsif ARGV[skip].start_with?(arg='--omv-cpus=') 272 | v = ARGV.delete_at(skip).dup 273 | v.slice! arg 274 | 275 | cpus = v.to_i # set cpus count 276 | 277 | elsif ARGV[skip].start_with?(arg='--omv-memory=') 278 | v = ARGV.delete_at(skip).dup 279 | v.slice! arg 280 | 281 | memory = v.to_i # set memory amount 282 | 283 | elsif ARGV[skip].start_with?(arg='--omv-disks=') 284 | v = ARGV.delete_at(skip).dup 285 | v.slice! arg 286 | 287 | disks = v.to_i # set extra disk amount 288 | 289 | elsif ARGV[skip].start_with?(arg='--omv-disksize=') 290 | v = ARGV.delete_at(skip).dup 291 | v.slice! arg 292 | 293 | disksize = v.to_s # set extra disk size 294 | 295 | elsif ARGV[skip].start_with?(arg='--omv-boxurlprefix=') 296 | v = ARGV.delete_at(skip).dup 297 | v.slice! arg 298 | 299 | boxurlprefix = v.to_s # set box url prefix 300 | 301 | elsif ARGV[skip].start_with?(arg='--omv-sync=') 302 | v = ARGV.delete_at(skip).dup 303 | v.slice! arg 304 | 305 | sync = v.to_s # set sync type 306 | 307 | elsif ARGV[skip].start_with?(arg='--omv-syncdir=') 308 | v = ARGV.delete_at(skip).dup 309 | v.slice! arg 310 | 311 | syncdir = v.to_s # set syncdir arg 312 | 313 | elsif ARGV[skip].start_with?(arg='--omv-syncsrc=') 314 | v = ARGV.delete_at(skip).dup 315 | v.slice! arg 316 | 317 | syncsrc = v.to_s # set syncsrc arg 318 | 319 | elsif ARGV[skip].start_with?(arg='--omv-folder=') 320 | v = ARGV.delete_at(skip).dup 321 | v.slice! arg 322 | 323 | folder = v.to_s # set folder prefix 324 | 325 | elsif ARGV[skip].start_with?(arg='--omv-extern=') 326 | v = ARGV.delete_at(skip).dup 327 | v.slice! arg 328 | 329 | if v.is_a?(String) and v.include? ',' and v.split(',').length > 0 330 | extern = v.split(',') 331 | # FIXME: further parse the chunks into hashes... 332 | else 333 | extern = [] 334 | end 335 | 336 | elsif ARGV[skip].start_with?(arg='--omv-cd=') 337 | v = ARGV.delete_at(skip).dup 338 | v.slice! arg 339 | 340 | cd = v.to_s # set cd arg 341 | 342 | elsif ARGV[skip].start_with?(arg='--omv-puppet=') 343 | v = ARGV.delete_at(skip).dup 344 | v.slice! arg 345 | 346 | puppet = v.to_s # set puppet flag 347 | if ['true', 'yes'].include?(puppet.downcase) 348 | puppet = true 349 | else 350 | puppet = false 351 | end 352 | 353 | elsif ARGV[skip].start_with?(arg='--omv-puppet-classes=') 354 | v = ARGV.delete_at(skip).dup 355 | v.slice! arg 356 | 357 | if v.is_a?(String) and v.include? ',' and v.split(',').length > 0 358 | classes = v.split(',') 359 | else 360 | classes = [] 361 | end 362 | 363 | elsif ARGV[skip].start_with?(arg='--omv-shell=') 364 | v = ARGV.delete_at(skip).dup 365 | v.slice! arg 366 | 367 | if v.is_a?(String) and v.split(',').length > 0 368 | shell = v.split(',') 369 | else 370 | shell = [] 371 | end 372 | 373 | elsif ARGV[skip].start_with?(arg='--omv-docker=') 374 | v = ARGV.delete_at(skip).dup 375 | v.slice! arg 376 | 377 | if v.is_a?(String) and v.include? ',' and v.split(',').length > 0 378 | v = v.split(',') 379 | docker = array_values_to_array_of_hashes(v) 380 | else 381 | docker = v.to_s # set docker flag 382 | if ['true', 'yes'].include?(docker.downcase) 383 | docker = true 384 | else 385 | docker = false 386 | end 387 | end 388 | 389 | elsif ARGV[skip].start_with?(arg='--omv-kubernetes=') 390 | v = ARGV.delete_at(skip).dup 391 | v.slice! arg 392 | 393 | kubernetes = v.to_s # set kubernetes flag 394 | if ['true', 'yes'].include?(kubernetes.downcase) 395 | kubernetes = true 396 | else 397 | kubernetes = false 398 | end 399 | 400 | elsif ARGV[skip].start_with?(arg='--omv-ansible=') 401 | v = ARGV.delete_at(skip).dup 402 | v.slice! arg 403 | 404 | if v.is_a?(String) and v.split(',').length > 0 405 | ansible = v.split(',') 406 | else 407 | ansible = [] 408 | end 409 | 410 | elsif ARGV[skip].start_with?(arg='--omv-playbook=') 411 | v = ARGV.delete_at(skip).dup 412 | v.slice! arg 413 | 414 | if v.is_a?(String) and v.split(',').length > 0 415 | playbook = v.split(',') 416 | else 417 | playbook = [] 418 | end 419 | 420 | elsif ARGV[skip].start_with?(arg='--omv-ansible-extras=') 421 | v = ARGV.delete_at(skip).dup 422 | v.slice! arg 423 | 424 | # TODO: support this command line arg in some way... 425 | ansible_extras = {} 426 | 427 | elsif ARGV[skip].start_with?(arg='--omv-cachier=') 428 | v = ARGV.delete_at(skip).dup 429 | v.slice! arg 430 | 431 | cachier = v.to_s # set cachier flag 432 | if ['true', 'yes'].include?(cachier.downcase) 433 | cachier = true 434 | else 435 | cachier = false 436 | end 437 | 438 | elsif ARGV[skip].start_with?(arg='--omv-vms=') 439 | v = ARGV.delete_at(skip).dup 440 | v.slice! arg 441 | 442 | if v.is_a?(String) and v.include? ',' and v.split(',').length > 0 443 | v = v.split(',') 444 | vms = array_values_to_array_of_hashes(v) 445 | end 446 | 447 | elsif ARGV[skip].start_with?(arg='--omv-namespace=') 448 | v = ARGV.delete_at(skip).dup 449 | v.slice! arg 450 | 451 | namespace = v.to_s # set namespace 452 | 453 | elsif ARGV[skip].start_with?(arg='--omv-count=') 454 | v = ARGV.delete_at(skip).dup 455 | v.slice! arg 456 | 457 | count = v.to_i # set host count 458 | 459 | elsif ARGV[skip].start_with?(arg='--omv-username=') 460 | v = ARGV.delete_at(skip).dup 461 | v.slice! arg 462 | 463 | username = v.to_s # set username 464 | 465 | elsif ARGV[skip].start_with?(arg='--omv-password=') 466 | v = ARGV.delete_at(skip).dup 467 | v.slice! arg 468 | 469 | password = v.to_s # set password 470 | 471 | elsif ARGV[skip].start_with?(arg='--omv-poolid=') 472 | v = ARGV.delete_at(skip).dup 473 | v.slice! arg 474 | 475 | if v.is_a?(String) and v.include? ',' and v.split(',').length > 0 476 | poolid = v.split(',') 477 | else 478 | poolid = v.to_s # set poolid boolean flag 479 | if ['true', 'auto'].include?(poolid.downcase) 480 | poolid = true 481 | else 482 | poolid = false 483 | end 484 | end 485 | 486 | elsif ARGV[skip].start_with?(arg='--omv-repos=') 487 | v = ARGV.delete_at(skip).dup 488 | v.slice! arg 489 | 490 | if v.is_a?(String) and v.include? ',' and v.split(',').length > 0 491 | repos = v.split(',') 492 | else 493 | repos = v.to_s # set repos boolean flag 494 | if ['true', 'all'].include?(repos.downcase) 495 | repos = true 496 | else 497 | repos = false 498 | end 499 | end 500 | 501 | elsif ARGV[skip].start_with?(arg='--omv-update=') 502 | v = ARGV.delete_at(skip).dup 503 | v.slice! arg 504 | 505 | update = v.to_s 506 | if ['true'].include?(update.downcase) 507 | update = true 508 | else 509 | update = false 510 | end 511 | 512 | elsif ARGV[skip].start_with?(arg='--omv-reboot=') 513 | v = ARGV.delete_at(skip).dup 514 | v.slice! arg 515 | 516 | reboot = v.to_s 517 | if ['true'].include?(reboot.downcase) 518 | reboot = true 519 | else 520 | reboot = false 521 | end 522 | 523 | elsif ARGV[skip].start_with?(arg='--omv-unsafe=') 524 | v = ARGV.delete_at(skip).dup 525 | v.slice! arg 526 | 527 | unsafe = v.to_s 528 | if ['true'].include?(unsafe.downcase) 529 | unsafe = true 530 | else 531 | unsafe = false 532 | end 533 | 534 | elsif ARGV[skip].start_with?(arg='--omv-nested=') 535 | v = ARGV.delete_at(skip).dup 536 | v.slice! arg 537 | 538 | nested = v.to_s 539 | if ['true'].include?(nested.downcase) 540 | nested = true 541 | else 542 | nested = false 543 | end 544 | 545 | elsif ARGV[skip].start_with?(arg='--omv-tests=') 546 | v = ARGV.delete_at(skip).dup 547 | v.slice! arg 548 | 549 | if v.is_a?(String) and v.split(',').length > 0 550 | tests = v.split(',') 551 | else 552 | tests = [] 553 | end 554 | 555 | elsif ARGV[skip].start_with?(arg='--omv-comment=') 556 | v = ARGV.delete_at(skip).dup 557 | v.slice! arg 558 | 559 | comment = v.to_s # set comment 560 | 561 | elsif ARGV[skip].start_with?(arg='--omv-reallyrm=') 562 | v = ARGV.delete_at(skip).dup 563 | v.slice! arg 564 | 565 | really_use_rm = v.to_s 566 | if ['true'].include?(really_use_rm.downcase) 567 | really_use_rm = true 568 | elsif [nil, 'nil', 'null', 'none'].include?(really_use_rm.downcase) 569 | really_use_rm = nil # don't rm or bug user at all 570 | else 571 | really_use_rm = false 572 | end 573 | 574 | elsif ARGV[skip].start_with?(arg='--omv-reallyrmonce=') 575 | v = ARGV.delete_at(skip).dup 576 | v.slice! arg 577 | 578 | really_use_rm_once = v.to_s 579 | if ['true'].include?(really_use_rm_once.downcase) 580 | really_use_rm_once = true 581 | else 582 | really_use_rm_once = false 583 | end 584 | 585 | else # skip over "official" vagrant args 586 | skip = skip + 1 587 | end 588 | end 589 | 590 | # save settings (ARGV overrides) 591 | settings = { 592 | :domain => domain, 593 | :network => network, 594 | :image => image, 595 | :cpus => cpus, 596 | :memory => memory, 597 | :disks => disks, 598 | :disksize => disksize, 599 | :boxurlprefix => boxurlprefix, 600 | :sync => sync, 601 | :syncdir => syncdir, 602 | :syncsrc => syncsrc, 603 | :folder => folder, 604 | :extern => extern, 605 | :cd => cd, 606 | :puppet => puppet, 607 | :classes => classes, 608 | :shell => shell, 609 | :docker => docker, 610 | :kubernetes => kubernetes, 611 | :ansible => ansible, 612 | :playbook => playbook, 613 | :ansible_extras => ansible_extras, 614 | :cachier => cachier, 615 | :vms => vms, 616 | :namespace => namespace, 617 | :count => count, 618 | :username => username, 619 | :password => password, 620 | :poolid => poolid, 621 | :repos => repos, 622 | :update => update, 623 | :reboot => reboot, 624 | :unsafe => unsafe, 625 | :nested => nested, 626 | :tests => tests, 627 | :comment => comment, 628 | :reallyrm => really_use_rm.nil?? 'nil' : really_use_rm, 629 | } 630 | File.open(f, 'w') do |file| 631 | file.write settings.to_yaml 632 | end 633 | File.open(g, 'w') do |file| 634 | file.write settings.to_yaml 635 | end 636 | 637 | username = global_username if "#{username}" == '' 638 | password = global_password if "#{password}" == '' 639 | username = '' if username.nil? 640 | password = '' if password.nil? 641 | #puts "ARGV: #{ARGV}" # debug 642 | 643 | # networking 644 | network_obj = IPAddr.new network 645 | range = network_obj.to_range.to_a 646 | #cidr = (32-(Math.log(range.length)/Math.log(2))).to_i 647 | offset = 100 # start hosts after here 648 | # remove reserved values 649 | range[0] = '__reserved_network_addr' # network 650 | range[1] = '__reserved_router_addr' # router (reserved) 651 | #puts range[2].to_s # puppetmaster 652 | #puts range[3].to_s # vip 653 | 654 | # prepend $count vms onto the vms list... 655 | extra = [] 656 | (1..count).each do |i| 657 | h = "#{namespace}#{i}" 658 | # generate names and add in the defaults 659 | extra.push({:name => h, :docker => docker}) 660 | end 661 | vms = extra.concat vms 662 | 663 | # add in puppet host if requested 664 | if puppet 665 | extra = [{:name => 'puppet', :ip => range[2].to_s}] 666 | range[2] = '__reserved_puppet_addr' 667 | vms = extra.concat vms 668 | 669 | if not(classes.is_a?(Hash)) and not(classes.is_a?(Array)) 670 | classes = [] 671 | end 672 | end 673 | 674 | # transform docker value if necessary 675 | docker = array_values_to_array_of_hashes(docker) 676 | 677 | # erase host information from puppet so that the user can do partial rebuilds 678 | snoop = ARGV.select { |x| !x.start_with?('-') } 679 | if snoop.length > 1 and snoop[0] == 'destroy' 680 | snoop.shift # left over array snoop should be list of hosts 681 | if snoop.include?('puppet') # doesn't matter then... 682 | snoop = [] 683 | end 684 | else 685 | # important! clear snoop because we're not using 'destroy' 686 | snoop = [] 687 | end 688 | 689 | # figure out which hosts are getting destroyed 690 | destroy = ARGV.select { |x| !x.start_with?('-') } 691 | if destroy.length > 0 and destroy[0] == 'destroy' 692 | destroy.shift # left over array destroy should be list of hosts or [] 693 | if destroy.length == 0 694 | destroy = true # destroy everything 695 | end 696 | else 697 | destroy = false # destroy nothing 698 | end 699 | 700 | # figure out which hosts are getting provisioned 701 | provision = ARGV.select { |x| !x.start_with?('-') } 702 | if provision.length > 0 and ['up', 'provision'].include?(provision[0]) 703 | provision.shift # left over array provision should be list of hosts or [] 704 | if provision.length == 0 705 | provision = true # provision everything 706 | end 707 | else 708 | provision = false # provision nothing 709 | end 710 | 711 | # XXX: workaround for: https://github.com/mitchellh/vagrant/issues/2447 712 | # only run on 'vagrant init' or if it's the first time running vagrant 713 | if sync == 'nfs' and ((ARGV.length > 0 and ARGV[0] == 'init') or not(File.exist?(f))) 714 | `sudo systemctl restart nfs-server` 715 | `firewall-cmd --permanent --zone public --add-service mountd` 716 | `firewall-cmd --permanent --zone public --add-service rpc-bind` 717 | `firewall-cmd --permanent --zone public --add-service nfs` 718 | `firewall-cmd --reload` 719 | end 720 | 721 | create_directories = true 722 | ssh_config = ARGV.select { |x| !x.start_with?('-') } 723 | if ssh_config.length > 0 and ssh_config[0] == 'ssh-config' 724 | # don't create a new Vagrant environment if the user accidentally 725 | # runs vscreen in the wrong directory. 726 | create_directories = false 727 | end 728 | 729 | # this extern code should be one of the *last* things before the big configure! 730 | folder = (folder + '/') if not(folder.end_with?('/')) # ensure trailing slash 731 | folder = '' if folder.start_with?('/') # only relative paths are allowed... 732 | #puts "folder is: #{folder}" # debug 733 | 734 | puppet_basedir = File.join(projectdir, folder, 'puppet/', 'modules/') 735 | shell_basedir = File.join(projectdir, folder, 'shell/') 736 | # NOTE: i called the ansible child dir 'modules' because i didn't know 737 | # what to call it. Suggestions welcome! It's not really 'playbooks' or 738 | # 'roles' really, so it's 'modules' until something better comes along 739 | ansible_basedir = File.join(projectdir, folder, 'ansible/', 'modules/') 740 | docker_basedir = File.join(projectdir, folder, 'docker/') 741 | kubernetes_basedir = File.join(projectdir, folder, 'kubernetes/', 'applications/') 742 | ktemplates_basedir = File.join(projectdir, folder, 'kubernetes/', 'templates/') 743 | other_basedir = File.join(projectdir, folder) # this is the root dir... 744 | 745 | if create_directories 746 | # mkdir in case these folders are missing 747 | mkdirp = 'mkdir -p' 748 | mkdirp += " #{puppet_basedir}" 749 | mkdirp += " #{shell_basedir}" 750 | mkdirp += " #{ansible_basedir}" 751 | mkdirp += " #{docker_basedir}" 752 | mkdirp += " #{kubernetes_basedir}" 753 | mkdirp += " #{ktemplates_basedir}" 754 | mkdirp += " #{other_basedir}" 755 | `#{mkdirp}` 756 | end 757 | 758 | native = [] # native files 759 | native += `cd "#{puppet_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 760 | native += `cd "#{shell_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 761 | native += `cd "#{ansible_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 762 | native += `cd "#{docker_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 763 | native += `cd "#{kubernetes_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 764 | native += `cd "#{ktemplates_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 765 | native += `cd "#{other_basedir}" && (git status &> /dev/null) && git ls-files`.strip.split("\n") 766 | 767 | if extern.length > 0 768 | extern.each do |i| 769 | t = i.fetch('type', nil) 770 | s = i.fetch('system', nil) # puppet, ansible, and so on... 771 | if s == 'puppet' 772 | basedir = puppet_basedir 773 | elsif s == 'shell' 774 | basedir = shell_basedir 775 | elsif s == 'ansible' 776 | basedir = ansible_basedir 777 | elsif s == 'docker' 778 | basedir = docker_basedir 779 | elsif s == 'kubernetes' 780 | basedir = kubernetes_basedir 781 | elsif s == 'ktemplates' 782 | basedir = ktemplates_basedir 783 | else 784 | # NOTE: this one puts code in the root vagrant dir 785 | basedir = other_basedir 786 | end 787 | if t == 'git' 788 | repository = i.fetch('repository', nil) 789 | if repository.start_with?('~/') 790 | repository = File.expand_path(repository) 791 | end 792 | directory = i.fetch('directory', nil) 793 | directory = directory[0, (directory.index('/', 1).nil?? directory.length : directory.index('/', 1))] 794 | branch = i.fetch('branch', nil) 795 | if repository.nil? or directory.nil? 796 | next 797 | end 798 | repo_okay = false 799 | bd = File.join("#{basedir}", "#{directory}") 800 | if File.exists?(bd) 801 | r = `cd "#{bd}" && git remote show -n origin | grep 'Fetch URL: ' | awk -F 'Fetch URL: ' '{print $2}'`.strip 802 | if r == repository 803 | repo_okay = true 804 | else 805 | $stderr.puts "Repository: '#{repository}' doesn't match installed." 806 | 807 | if not(really_use_rm.nil?) # if it's nil, never bug the user... 808 | if (really_use_rm_once.nil? and really_use_rm) or (not(really_use_rm_once.nil?) and really_use_rm_once) 809 | `rm -rf "#{bd}"` 810 | else 811 | $stderr.puts `echo please: rm -rf "#{bd}"` # safer for now 812 | end 813 | end 814 | end 815 | # pull latest in if it exists 816 | r = `cd "#{bd}" && [ $(git fetch --dry-run 2>&1 | wc -l) -gt 0 ] || echo already up-to-date`.strip 817 | if r == '' 818 | r = `cd "#{bd}" && git checkout master && git pull`.strip 819 | $stderr.puts r 820 | end 821 | 822 | else 823 | r = `cd "#{basedir}" && git clone --recursive #{repository} #{directory}` 824 | $stderr.puts r 825 | repo_okay = true 826 | end 827 | if repo_okay and not branch.nil? 828 | r = `cd "#{bd}" && git checkout "#{branch}"`.strip 829 | end 830 | native.push("#{directory}") 831 | else 832 | $stderr.puts "Can't process extern type: '#{t}'." 833 | end 834 | end 835 | end 836 | 837 | # clean up any directories or files that shouldn't be present 838 | ( 839 | Dir.glob(puppet_basedir+'*') + 840 | Dir.glob(shell_basedir+'*') + 841 | Dir.glob(ansible_basedir+'*') + 842 | Dir.glob(docker_basedir+'*') + 843 | Dir.glob(kubernetes_basedir+'*') + 844 | Dir.glob(ktemplates_basedir+'*') + 845 | []).uniq.each do |i| 846 | b = File.basename(i) 847 | if not native.include?(b) 848 | if not(really_use_rm.nil?) # if it's nil, never bug the user... 849 | if (really_use_rm_once.nil? and really_use_rm) or (not(really_use_rm_once.nil?) and really_use_rm_once) 850 | `rm -rf "#{i}"` 851 | else 852 | $stderr.puts `echo please: rm -rf "#{i}"` # safer for now 853 | end 854 | end 855 | end 856 | end 857 | 858 | # generate the tests to be run with `vtest` 859 | tests_file = File.join(projectdir, '.vagrant', 'tests.sh') 860 | if tests != [] 861 | File.open(tests_file, 'w') {|tests_handle| tests_handle.write("#!/bin/bash -ie\n# generated by omv, do not edit!\n#{tests.join(10.chr)}\n")} 862 | FileUtils.chmod 'u+x', tests_file 863 | else 864 | File.exists?(tests_file) and File.delete(tests_file) # delete 865 | end 866 | 867 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 868 | 869 | # workaround vagrant 1.7.2 insecure key change 870 | config.ssh.insert_key = false 871 | 872 | #config.landrush.enable # TODO ? 873 | 874 | # 875 | # cache 876 | # 877 | # NOTE: you should probably erase the cache between rebuilds if you are 878 | # installing older package versions. This is because the newer packages 879 | # will get cached, and then subsequently might get silently installed!! 880 | if cachier 881 | # TODO: this doesn't cache metadata, full offline operation not possible 882 | config.cache.auto_detect = true 883 | config.cache.enable :yum 884 | #config.cache.enable :apt 885 | if not ARGV.include?('--no-parallel') # when running in parallel, 886 | config.cache.scope = :machine # use the per machine cache 887 | end 888 | if sync == 'nfs' # TODO: support other sync types here... 889 | config.cache.enable_nfs = true # sets nfs => true on the synced_folder 890 | # the nolock option is required, otherwise the NFSv3 client will try to 891 | # access the NLM sideband protocol to lock files needed for /var/cache/ 892 | # all of this can be avoided by using NFSv4 everywhere. die NFSv3, die! 893 | config.cache.mount_options = ['rw', 'vers=3', 'tcp', 'nolock'] 894 | end 895 | end 896 | 897 | # 898 | # vip 899 | # 900 | vip_ip = range[3].to_s 901 | vip_hostname = namespace 902 | range[3] = '__reserved_vip_addr' 903 | 904 | # 905 | # hostmanager 906 | # 907 | # TODO: does this plugin still mess up the real vagrant-libvirt hostname ? 908 | config.hostmanager.enabled = true 909 | config.hostmanager.manage_host = false # don't manage local /etc/hosts 910 | config.hostmanager.ignore_private_ip = false 911 | config.hostmanager.include_offline = true # manage all the hosts! 912 | config.hostmanager.fqdn_friendly = true # fqdns need to work... 913 | config.hostmanager.domain_name = domain # use this domain name! 914 | config.hostmanager.extra_hosts = [ 915 | { 916 | :host => "#{vip_hostname}.#{domain}", 917 | :ip => "#{vip_ip}", 918 | :aliases => ["#{vip_hostname}"], 919 | } 920 | ] 921 | 922 | # 923 | # set vms ips and do other pre-processing 924 | # 925 | ansible_groups = {} 926 | kubernetes_master = false # TODO: in future allow an array of masters ? 927 | kubernetes_hosts = [] # list of every participating kubernetes host 928 | kubernetes_templates = '' 929 | kubernetes_json = [] 930 | vms.each_with_index do |x, i| 931 | h = x[:name] 932 | if not x.fetch(:ip, nil) # if vm ip was not set in omv.yaml... 933 | x[:ip] = range[offset+i].to_s # ...generate it, and set vm ip 934 | #vms[i][:ip] = range[offset+i].to_s # equivalent! 935 | end 936 | 937 | # kubernetes 938 | vm_kubernetes = x.fetch(:kubernetes, kubernetes) # get value 939 | if kubernetes.is_a?(Hash) and vm_kubernetes.is_a?(Hash) 940 | vm_kubernetes = kubernetes.merge(vm_kubernetes) # inherit from global 941 | end 942 | if vm_kubernetes 943 | kubernetes_hosts.push(h) 944 | end 945 | 946 | # build ansible_groups variable now, because needed in big loop 947 | vm_ansible = x.fetch(:ansible, ansible) # get value 948 | ansible_groups[h] = vm_ansible if vm_ansible != [] 949 | end 950 | if kubernetes_hosts.length > 0 951 | kubernetes_master = kubernetes_hosts[0] # default to first host 952 | if kubernetes.is_a?(Hash) 953 | # a master key can set which kubernetes host is the master one! 954 | tmp = kubernetes.fetch('master', nil) 955 | if kubernetes_hosts.include?(tmp) 956 | kubernetes_master = tmp 957 | end 958 | 959 | # kubernetes templates base path inside repo, eg: v0.9.0 960 | tmp = kubernetes.fetch('ktemplates', 'default/latest/') # pick! 961 | if tmp.is_a?(String) 962 | tmp = File.join(ktemplates_basedir, tmp) 963 | if File.exists?(tmp) 964 | kubernetes_templates = tmp 965 | end 966 | end 967 | 968 | # json definition file 969 | kubernetes_json = kubernetes.fetch('applications', []) # pick! 970 | if not kubernetes_json.is_a?(Array) 971 | kubernetes_json = [] 972 | end 973 | end 974 | end 975 | #$stderr.puts "Kubernetes master: #{kubernetes_master}" 976 | #$stderr.puts "Kubernetes others: #{kubernetes_hosts.join(',')}" 977 | 978 | # 979 | # vms mainloop to define all the machines 980 | # 981 | vms.each do |x| 982 | h = x[:name] 983 | ip = x.fetch(:ip) # get value 984 | vm_image = x.fetch(:image, image) # get value 985 | vm_cpus = x.fetch(:cpus, cpus) # get value 986 | vm_memory = x.fetch(:memory, memory) # get value 987 | vm_disks = x.fetch(:disks, disks) # get value 988 | vm_disksize = x.fetch(:disksize, disksize) # get value 989 | vm_sync = x.fetch(:sync, sync) # get value 990 | vm_syncdir = x.fetch(:syncdir, syncdir) # get value 991 | vm_syncdir_folder = '' 992 | if vm_syncdir == '/' # automatic folder name 993 | vm_syncdir_folder = basename 994 | elsif vm_syncdir != '' # pick whatever they asked for 995 | vm_syncdir_folder = vm_syncdir 996 | end 997 | vm_syncsrc = x.fetch(:syncsrc, syncsrc) # get value 998 | vm_cd = x.fetch(:cd, cd) # get value 999 | vm_docker = x.fetch(:docker, docker) # get value 1000 | vm_docker = array_values_to_array_of_hashes(vm_docker) 1001 | vm_puppet = x.fetch(:puppet, puppet) # get value 1002 | vm_classes = x.fetch(:classes, classes) 1003 | vm_shell = x.fetch(:shell, shell) # get value 1004 | vm_poolid = x.fetch(:poolid, poolid) # get value 1005 | vm_repos = x.fetch(:repos, repos) # get value 1006 | vm_playbook = x.fetch(:playbook, playbook) # get value 1007 | vm_ansible_extras = x.fetch(:ansible_extras, ansible_extras) # get value 1008 | vm_update = x.fetch(:update, update) # get value 1009 | vm_reboot = x.fetch(:reboot, reboot) # get value 1010 | vm_unsafe = x.fetch(:unsafe, unsafe) # get value 1011 | vm_nested = x.fetch(:nested, nested) # get value 1012 | 1013 | # sanity check the user-supplied IP addresses and gracefully fail 1014 | # puppet server is special, so we skip it here 1015 | if h != 'puppet' 1016 | error_check = range.include? IPAddr.new ip 1017 | message = "#{namespace}:#{h}: ERROR: #{ip} is not in the valid range of IPs: #{range[3].to_s}..#{range[-2].to_s}" 1018 | message += "\nConsider changing 'network:' parameter in omv.yaml, or use the correct IP address from the range above!" 1019 | raise Vagrant::Errors::VagrantError.new, message unless error_check 1020 | end 1021 | 1022 | config.vm.define h.to_sym do |vm| 1023 | vm.vm.hostname = h 1024 | #vm.hostmanager.aliases = ["#{h}.#{domain}"] 1025 | 1026 | # this is the real network that we'll use... 1027 | vm.vm.network :private_network, 1028 | :ip => ip, 1029 | :libvirt__dhcp_enabled => false, 1030 | :libvirt__network_name => "#{namespace}", 1031 | :virtualbox__intnet => "#{namespace}" 1032 | 1033 | # 1034 | # box (pre-built base image) 1035 | # 1036 | vm.vm.box = vm_image # set vm specific image 1037 | 1038 | synced_folder = '/vagrant' # default sync folder 1039 | dot = "#{File.join(projectdir, folder)}" 1040 | if vm_syncsrc.start_with?('/') 1041 | dot = vm_syncsrc 1042 | else 1043 | dot = File.expand_path(File.join(dot, vm_syncsrc)) 1044 | end 1045 | 1046 | # use a specialized vagrant box if it exists :) 1047 | if vm_docker 1048 | if `vagrant box list | awk '{print $1}' | grep -q '^#{vm_image}-docker$' && echo -n found` != '' 1049 | vm.vm.box = "#{vm_image}-docker" 1050 | end 1051 | end 1052 | 1053 | # family parsing 1054 | is_yum = (vm.vm.box.start_with? 'fedora-' or vm.vm.box.start_with? 'centos-' or vm.vm.box.start_with? 'rhel-') 1055 | is_apt = (vm.vm.box.start_with? 'debian-' or vm.vm.box.start_with? 'ubuntu-') 1056 | is_atomic = vm.vm.box.start_with? 'atomic-' 1057 | is_rhel = (vm.vm.box.start_with? 'rhel-' or vm.vm.box.start_with? 'atomic-rhel-') 1058 | is_family_redhat = (is_yum or is_atomic) 1059 | is_family_debian = is_apt 1060 | 1061 | # sync type 1062 | # this section is a bit tricky, because if you want a 1063 | # different sync other than /vagrant (which you get by 1064 | # default), then you have to disable it, and then add 1065 | # what you want... cleanups that still work are welcome 1066 | disabled = false 1067 | if is_atomic or vm_sync == '' 1068 | disabled = true 1069 | vm.vm.synced_folder '.', '/vagrant', disabled: true 1070 | else 1071 | synced_folder = vm_syncdir_folder.start_with?('/') ? vm_syncdir_folder : File.join(synced_folder, vm_syncdir_folder) 1072 | vm.vm.synced_folder "#{dot}", synced_folder, create: true, type: vm_sync # nfs, rsync 1073 | end 1074 | 1075 | if vm_syncdir_folder != '' and not(disabled) 1076 | vm.vm.synced_folder '.', '/vagrant', disabled: true 1077 | end 1078 | 1079 | if is_atomic 1080 | synced_folder = '/home/vagrant/sync' 1081 | synced_folder = vm_syncdir_folder.start_with?('/') ? vm_syncdir_folder : File.join(synced_folder, vm_syncdir_folder) 1082 | if vm_sync != '' 1083 | vm.vm.synced_folder "#{dot}", synced_folder, create: true, type: vm_sync 1084 | end 1085 | end 1086 | 1087 | # box source url's 1088 | # FIXME: boxes should be GPG signed and verified on dl! 1089 | if "#{boxurlprefix}" != '' 1090 | vm.vm.box_url = "#{boxurlprefix}#{vm.vm.box}/#{vm.vm.box}.box" 1091 | end 1092 | 1093 | # FIXME: speed up or cache (memoize) this check... 1094 | if `vagrant box list | awk '{print $1}' | grep -q '^#{vm.vm.box}$' && echo -n found` != '' 1095 | exists = true 1096 | else 1097 | if vm.vm.box_url.is_a?(String) 1098 | puts "Running wget check on: '#{vm.vm.box_url}'" 1099 | exists = `wget -q --spider #{vm.vm.box_url}` 1100 | else 1101 | exists = false 1102 | end 1103 | end 1104 | if not(exists) and not is_rhel 1105 | vm.vm.box_url = "#{default_boxurlprefix}/#{vm.vm.box}/#{vm.vm.box}.box" 1106 | end 1107 | 1108 | #vm.landrush.host h, ip # TODO ? 1109 | 1110 | fv = File.join(projectdir, '.vagrant', "#{h}-hosts.done") 1111 | if destroy.is_a?(TrueClass) or (destroy.is_a?(Array) and destroy.include?(h)) 1112 | if File.exists?(fv) # safety 1113 | puts "Unlocking shell provisioning for: #{h}..." 1114 | File.delete(fv) # delete hosts token 1115 | end 1116 | end 1117 | 1118 | # store the path to the cd directory for vscreen to see 1119 | if vm_cd == '$SYNCDIR' or vm_cd == '-' 1120 | vm_cd = synced_folder 1121 | end 1122 | cd_file = File.join(projectdir, '.vagrant', "#{h}.cd") 1123 | File.open(cd_file, 'w') {|cd_handle| cd_handle.write("#{vm_cd}\n")} 1124 | 1125 | # should we clean this puppet client machine? 1126 | if puppet and vm_puppet and h != 'puppet' and snoop.include?(h) 1127 | cmd = "puppet cert clean #{h}.#{domain}" 1128 | puts "Running 'puppet cert clean' for: #{h}..." 1129 | `vagrant ssh puppet -c 'sudo #{cmd}'` 1130 | cmd = "puppet node deactivate #{h}.#{domain}" 1131 | puts "Running 'puppet node deactivate' for: #{h}..." 1132 | `vagrant ssh puppet -c 'sudo #{cmd}'` 1133 | end 1134 | 1135 | # unsubscribe rhel machines on destroy 1136 | if destroy.is_a?(TrueClass) or (destroy.is_a?(Array) and destroy.include?(h)) 1137 | if is_rhel 1138 | # check these to know if we registered! 1139 | if username != '' and password != '' 1140 | # ssh into itself and unregister 1141 | cmd = 'subscription-manager unregister' 1142 | puts "Running '#{cmd}' on: #{h}..." 1143 | puts `vagrant ssh #{h} -c 'sudo #{cmd}'` 1144 | end 1145 | end 1146 | end 1147 | 1148 | # 1149 | # shell 1150 | # 1151 | first_run = not(File.exists?(fv)) 1152 | if first_run # only run these actions once! 1153 | if provision.is_a?(TrueClass) or (provision.is_a?(Array) and provision.include?(h)) 1154 | File.open(fv, 'w') {} # touch 1155 | end 1156 | 1157 | # add missing root password where necessary 1158 | if is_family_debian 1159 | vm.vm.provision 'shell', inline: 'usermod -p $(echo vagrant | openssl passwd -1 -stdin) root' 1160 | elsif is_family_redhat 1161 | vm.vm.provision 'shell', inline: 'echo vagrant | passwd --stdin root' 1162 | end 1163 | 1164 | # fix atomic hosts with missing authorized_keys 1165 | if is_atomic 1166 | vm.vm.provision 'shell', inline: 'test -e /root/.ssh/ || cp -r /home/vagrant/.ssh/ /root/' 1167 | end 1168 | 1169 | # subscribe rhel machines 1170 | if is_rhel 1171 | if username != '' and password != '' 1172 | vm.vm.provision 'shell', inline: "subscription-manager register --username=#{username} --password=#{password}" 1173 | 1174 | # attach correct pools 1175 | if vm_poolid.is_a?(Array) 1176 | vm_poolid.each do |j| 1177 | vm.vm.provision 'shell', inline: "subscription-manager attach --pool=#{j}" 1178 | end 1179 | elsif vm_poolid 1180 | # auto attach if value is true 1181 | vm.vm.provision 'shell', inline: 'subscription-manager attach --auto' 1182 | end 1183 | end 1184 | 1185 | # enable particular repositories 1186 | if vm_repos.is_a?(Array) 1187 | vm_repos.each do |j| 1188 | # if you start the repo name with a # 1189 | # then it will be disabled... this is 1190 | # useful to kill repos from a poolid. 1191 | if j.start_with? '#' 1192 | vm.vm.provision 'shell', inline: "subscription-manager repos --disable=#{j[1,j.length]}" 1193 | else 1194 | vm.vm.provision 'shell', inline: "subscription-manager repos --enable=#{j}" 1195 | end 1196 | end 1197 | 1198 | elsif vm_repos 1199 | # this enables all repositories 1200 | # NOTE: probably a strong edge 1201 | vm.vm.provision 'shell', inline: "for i in `subscription-manager repos --list | grep '^Repo ID:' | awk '{print $3}'`; do subscription-manager repos --enable=$i; done" 1202 | end 1203 | 1204 | end 1205 | 1206 | # update the hosts 1207 | if vm_update 1208 | if is_atomic 1209 | vm.vm.provision 'shell', inline: 'atomic host upgrade' 1210 | elsif is_yum 1211 | vm.vm.provision 'shell', inline: 'yum -y update' 1212 | elsif is_apt 1213 | vm.vm.provision 'shell', inline: 'apt-get update && apt-get -y upgrade' 1214 | end 1215 | end 1216 | 1217 | # atomic hosts lack the docker group which the 1218 | # docker provisioner expects... workaround this 1219 | if vm_docker 1220 | vm.vm.provision 'shell', inline: 'getent group docker || groupadd --system docker' 1221 | end 1222 | 1223 | # grow if root xfs file system abnormally small 1224 | # NOTE: empirically, the operating systems that 1225 | # use xfs as / also support the findmnt -b flag 1226 | vm.vm.provision 'shell', inline: '! findmnt -t xfs --target "/" || (( !(findmnt -b 2> /dev/null) || test `findmnt --output "SIZE" -t xfs --target "/" -nb` -lt `expr 1024 \* 1024 \* 1024 \* 20`) && xfs_growfs /)' 1227 | end 1228 | 1229 | # custom shell provisioner 1230 | # TODO: support running first/last as a setting 1231 | if vm_shell.is_a?(Array) 1232 | vm_shell.each do |sf| 1233 | 1234 | shell_once = false 1235 | if sf.is_a?(Hash) 1236 | shell_once = sf.fetch('once', shell_once) # get value 1237 | elsif sf.is_a?(String) # auto-detect 1238 | sx = File.join(shell_basedir, sf) 1239 | if File.exists?(sx) and not(File.directory?(sx)) and File.executable?(sx) 1240 | sf = {'path'=> sf} 1241 | else 1242 | sf = {'script'=> sf} 1243 | end 1244 | else 1245 | next 1246 | end 1247 | 1248 | # do the running... 1249 | si = sf.fetch('script', nil) 1250 | sp = sf.fetch('path', nil) 1251 | if not(shell_once) or (shell_once and first_run) 1252 | if sp.nil? 1253 | vm.vm.provision 'shell', inline: "#{si}" 1254 | elsif si.nil? 1255 | sx = File.join(shell_basedir, sp) 1256 | vm.vm.provision 'shell', path: "#{sx}" 1257 | else 1258 | next # optional 1259 | end 1260 | end 1261 | end 1262 | end 1263 | 1264 | # TODO: remove this chunk? 1265 | # ensure the $namespace module is present for provisioning... 1266 | #if (puppet and vm_puppet and h == 'puppet') and (provision.is_a?(TrueClass) or (provision.is_a?(Array) and provision.include?('puppet'))) 1267 | # cwd = `pwd` 1268 | # mod = File.join(projectdir, 'puppet', 'modules') 1269 | # #`cd #{mod} && make MODULENAME=#{namespace} #{namespace} &> /dev/null; cd #{cwd}` 1270 | #end 1271 | 1272 | # 1273 | # docker (in vm) 1274 | # 1275 | # TODO: do we need to start the docker daemon first ? 1276 | # NOTE: this docker load from file isn't needed as much 1277 | # because vagrant-builder can now docker pull directly: 1278 | # done in git: b6bd325f3a23b25441050afdd8433457278819fd 1279 | if vm_docker.is_a?(Array) 1280 | vm.vm.provision 'shell', inline: 'systemctl start docker' 1281 | vm_docker.each do |j| 1282 | # if there is a docker image already present, use that 1283 | # otherwise pull one down... 1284 | vm.vm.provision 'shell', inline: "if [ -e '/root/docker/#{j[:name]}.docker' ]; then docker load --input='/root/docker/#{j[:name]}.docker'; else docker pull '#{j[:name]}'; fi" 1285 | end 1286 | 1287 | elsif vm_docker 1288 | vm.vm.provision 'shell', inline: 'systemctl start docker' 1289 | # pull in all the docker images that the vm has 1290 | vm.vm.provision 'shell', inline: 'for i in /root/docker/*.docker; do [ -e "$i" ] || continue; docker load --input="$i"; done' 1291 | end 1292 | 1293 | # TODO: should we run the docker pull with vagrant too? 1294 | if vm_docker.is_a?(Array) 1295 | vm.vm.provision :docker, images: vm_docker.map { |y| y.fetch(:name, nil)}.compact 1296 | end 1297 | 1298 | # docker build 1299 | if vm_docker # for any value that is not false 1300 | dlist = Dir.glob(docker_basedir+'*') 1301 | if vm_docker.is_a?(Hash) 1302 | dfiles = vm_docker.fetch('files', nil) 1303 | if dfiles.is_a?(Array) 1304 | dlist = vm_docker['files'].map{|dfile| File.join(docker_basedir, dfile)} 1305 | end 1306 | end 1307 | dlist.each do |dd| 1308 | if not File.directory?(dd) 1309 | next # invalid, skip 1310 | end 1311 | # full Dockerfile path 1312 | df = File.join(dd, 'Dockerfile') 1313 | if not(File.exists?(df)) or File.directory?(df) 1314 | next # invalid, skip 1315 | end 1316 | # app directory name containing Dockerfile 1317 | b = File.basename(dd) 1318 | vm.vm.provision :docker do |d| 1319 | d.build_image "#{synced_folder}/docker/#{b}", args: "-t #{b}" 1320 | #d.run "#{b}" # use kube instead 1321 | end 1322 | end 1323 | end 1324 | 1325 | # 1326 | # kubernetes 1327 | # 1328 | # NOTE: one could rewrite this kubernetes portion as a 1329 | # vagrant plugin, but until this idea is more baked, i 1330 | # think this is a perfectly fine place to hack this in 1331 | 1332 | # if we have a master host and if i am an allowed host 1333 | if kubernetes_master and kubernetes_hosts.include?(h) 1334 | 1335 | # TODO: add support for non yum-based distros 1336 | vm.vm.provision 'shell', inline: 'which kubectl || yum install -y kubernetes' 1337 | 1338 | # templates are in the kubernetes_templates dir 1339 | ktemplates_host = ((kubernetes_master == h) ? 'master' : 'minion') 1340 | ktemplates = {} 1341 | Dir.glob(File.join(kubernetes_templates, "#{ktemplates_host}/")+'*').each do |ktemplate| 1342 | kbdir = File.basename(ktemplate) 1343 | ktemplates[kbdir] = open(ktemplate, 'r') {|ktf| ktf.read} 1344 | end 1345 | 1346 | kubernetes_ostruct = OpenStruct.new({ 1347 | :master => kubernetes_master, 1348 | :hosts => kubernetes_hosts, 1349 | :diff => (kubernetes_hosts - [kubernetes_master]), 1350 | :me => h, 1351 | }) 1352 | 1353 | ktemplates.each do |kpath, template| 1354 | if kpath.end_with?('.erb') 1355 | kpath = File.join('/etc/kubernetes/', kpath[0, kpath.length-'.erb'.length]) 1356 | value = ERB.new(template).result(kubernetes_ostruct.instance_eval {binding}) 1357 | b64 = Base64.encode64(value) 1358 | else 1359 | # copy data, don't template it! 1360 | kpath = File.join('/etc/kubernetes/', kpath) 1361 | value = template # str 1362 | b64 = Base64.encode64(value) 1363 | end 1364 | # FIXME: add a diff check so this doesn't clobber unnecessarily 1365 | vm.vm.provision 'shell' do |s| 1366 | s.inline = "echo '#{b64}' | base64 -d > '#{kpath}'" 1367 | end 1368 | end 1369 | 1370 | # systemctl changes for kubernetes 1371 | if kubernetes_master == h # master 1372 | services = ['etcd', 'kube-apiserver', 'kube-controller-manager', 'kube-scheduler'] 1373 | else 1374 | # a dirty auth hack that scollier wants 1375 | vm.vm.provision 'shell', inline: 'echo "{}" > /var/lib/kubelet/auth' 1376 | services = ['kube-proxy', 'kubelet'] 1377 | end 1378 | services.each do |service| 1379 | # a restart causes a start if stopped :) 1380 | vm.vm.provision 'shell', inline: "systemctl restart #{service}" 1381 | vm.vm.provision 'shell', inline: "systemctl enable #{service}" 1382 | end 1383 | 1384 | # scollier and purpleidea decided against 1385 | # templating the kubernetes json files... 1386 | # run from an application/ dir instead :) 1387 | if kubernetes_master == h # master 1388 | kubernetes_json.each do |jsonfile| 1389 | roll = false 1390 | if jsonfile.is_a?(Hash) 1391 | roll = jsonfile.fetch('roll', false) 1392 | roll = (['true', 'yes'].include?(roll.downcase) ? true : false) 1393 | jsonfile = jsonfile.fetch('file', '') 1394 | 1395 | if jsonfile == '' 1396 | $stderr.puts "Warning: Kubernetes application list element is an invalid hash!" 1397 | next 1398 | end 1399 | end 1400 | 1401 | if not File.exists?(File.join(kubernetes_basedir, jsonfile)) 1402 | $stderr.puts "Warning: Kubernetes .json file: '#{jsonfile}' doesn't exist!" 1403 | next 1404 | end 1405 | 1406 | # get path to json file inside vm... 1407 | jsonfile = File.join("#{synced_folder}/kubernetes/applications/", jsonfile) 1408 | $script = <<-SCRIPT.unindent 1409 | # the sed strips off the quotes from the python string output 1410 | # unescaped sed is: sed 's/\(^"\|"$\)//g' 1411 | kind="`cat '#{jsonfile}' | python -c 'import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)["kind"]))' | sed 's/\\(^"\\|"$\\)//g'`" 1412 | kid="`cat '#{jsonfile}' | python -c 'import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)["id"]))' | sed 's/\\(^"\\|"$\\)//g'`" 1413 | roll='false' 1414 | case "$kind" in 1415 | 'ReplicationController') 1416 | # remap to command arg name 1417 | kind='replicationControllers' 1418 | roll='#{roll}' 1419 | ;; 1420 | 'Service') 1421 | ;; 1422 | 'Pod') 1423 | ;; 1424 | *) 1425 | echo "Kubernetes kind: '$kind' not yet supported in Oh-My-Vagrant." 1426 | ;; 1427 | esac 1428 | echo Running kubernetes... 1429 | if [ "`kubectl get $kind | tail -n +2 | awk '{print $1}'`" = "$kid" ]; then 1430 | # exists... 1431 | # TODO: can we roll like this? 1432 | if [ "$roll" = 'true' ]; then 1433 | echo Running kubernetes: rollingupdate... 1434 | kubectl rollingupdate "$kid" -f '#{jsonfile}' 1435 | else 1436 | # update from existing json file... 1437 | echo Running kubernetes: update... 1438 | kubectl update -f '#{jsonfile}' 1439 | fi 1440 | else 1441 | # new 1442 | echo Running kubernetes: create... 1443 | kubectl create -f '#{jsonfile}' 1444 | fi 1445 | SCRIPT 1446 | vm.vm.provision 'shell', inline: $script 1447 | end 1448 | end 1449 | end 1450 | 1451 | # 1452 | # puppet agent - run on puppet client to set it up 1453 | # 1454 | if puppet and vm_puppet and h != 'puppet' 1455 | vm.vm.provision :puppet_server do |p| 1456 | #p.puppet_node = "#{h}" # redundant 1457 | #p.puppet_server = "puppet.#{domain}" 1458 | p.puppet_server = 'puppet' 1459 | #p.options = '--verbose --debug' 1460 | p.options = '--test' # see the output 1461 | 1462 | # extract a list of puppet classes... 1463 | dynamic = {} 1464 | if vm_classes.is_a?(Array) 1465 | puppet_classes = vm_classes 1466 | 1467 | elsif vm_classes.is_a?(Hash) 1468 | # here we act as a cheap enc... 1469 | puppet_classes = vm_classes.keys 1470 | puppet_classes.each do |name| 1471 | params = vm_classes.fetch(name, {}) 1472 | if params.is_a?(Hash) 1473 | keys = [] 1474 | params.keys.sort.each do |key| 1475 | dynamic["vagrant_puppet_classes_values_#{name}_#{key}"] = params[key] 1476 | keys.push(key) 1477 | end 1478 | if keys.length > 0 1479 | dynamic["vagrant_puppet_classes_params_#{name}"] = keys.join(',') 1480 | end 1481 | end 1482 | end 1483 | else 1484 | puppet_classes = [] 1485 | end 1486 | 1487 | facter = { 1488 | 'vagrant' => '1', 1489 | 'vagrant_vip' => vip_ip, 1490 | 'vagrant_vip_fqdn' => "#{vip_hostname}.#{domain}", 1491 | 'vagrant_puppet_classes' => puppet_classes.join(','), 1492 | } 1493 | facter = facter.merge(dynamic) 1494 | p.facter = facter 1495 | end 1496 | 1497 | # 1498 | # puppet apply - run on puppet master to set it up 1499 | # 1500 | elsif puppet and vm_puppet and h == 'puppet' 1501 | vm.vm.provision :puppet do |p| 1502 | p.module_path = File.join(projectdir, folder+'puppet/modules') 1503 | p.manifests_path = File.join(projectdir, folder+'puppet/manifests') 1504 | p.manifest_file = 'site.pp' 1505 | p.hiera_config_path = File.join(projectdir, folder+'puppet/hiera.yaml') 1506 | # custom fact 1507 | p.facter = { 1508 | 'vagrant' => '1', 1509 | 'vagrant_allow' => vms.each{|z| z[:ip] }, 1510 | 'vagrant_puppet_folder' => folder, 1511 | } 1512 | p.synced_folder_type = vm_sync 1513 | end 1514 | 1515 | # the puppetlabs RPM mistakenly starts the 1516 | # service on installation/upgrade. this is a 1517 | # bug, and it causes our server to break, 1518 | # because we want puppet to run with our 1519 | # environment variables, which it doesn't when 1520 | # started by itself! puppetlabs, fix your RPM 1521 | # already! 1522 | # https://tickets.puppetlabs.com/browse/CPR-128 1523 | vm.vm.provision 'shell', inline: 'service puppet stop' 1524 | end 1525 | 1526 | # 1527 | # ansible 1528 | # 1529 | if ansible_groups != {} 1530 | vm_playbook.each do |pb| 1531 | vm.vm.provision 'ansible' do |a| 1532 | # NOTE: this seems to need an absolute path spec 1533 | a.playbook = File.join(projectdir, folder+'ansible/modules/'+pb) 1534 | # reverse the mapping, so that the groups enumerate their hosts 1535 | a.groups = Hash[ansible_groups.values.flatten.uniq.map { |ai| [ai, ansible_groups.select{|_,av| not(av.nil?) and av.include?(ai) }.keys ]}] 1536 | a.host_key_checking = false 1537 | a.limit = 'all' 1538 | ansible_sudo = vm_ansible_extras.fetch(:sudo, nil) 1539 | if ansible_sudo.is_a?(TrueClass) or ansible_sudo.is_a?(FalseClass) 1540 | a.sudo = ansible_sudo 1541 | end 1542 | ansible_extra_vars = vm_ansible_extras.fetch(:extra_vars, {}) 1543 | ansible_extra_vars_hash = {} 1544 | if ansible_extra_vars.is_a?(Hash) 1545 | ansible_extra_vars.keys.sort.each do |akey| 1546 | ansible_extra_vars_hash[akey] = ansible_extra_vars[akey] 1547 | end 1548 | end 1549 | # add a default 1550 | if not ansible_extra_vars_hash.has_key?('ansible_ssh_user') 1551 | ansible_extra_vars_hash['ansible_ssh_user'] = 'root' 1552 | end 1553 | a.extra_vars = ansible_extra_vars_hash 1554 | end 1555 | end 1556 | end 1557 | 1558 | vm.vm.provider :libvirt do |libvirt| 1559 | (0..vm_disks.to_i-1).each do # if disks is 0, this passes :) 1560 | libvirt.storage :file, 1561 | #:path => '', # auto! 1562 | #:device => 'vdb', # auto! 1563 | :size => vm_disksize, 1564 | :type => 'qcow2' 1565 | end 1566 | 1567 | if vm_cpus.to_i != 0 # handles '', nil, & 0 1568 | libvirt.cpus = vm_cpus.to_i 1569 | 1570 | # make puppet server a bit fatter by default :P 1571 | elsif (puppet and vm_puppet and h == 'puppet') or vm_nested 1572 | libvirt.cpus = 2 1573 | end 1574 | 1575 | if vm_memory.to_i != 0 1576 | libvirt.memory = vm_memory.to_i 1577 | 1578 | # make puppet server a bit fatter by default :P 1579 | elsif (puppet and vm_puppet and h == 'puppet') or vm_nested 1580 | libvirt.memory = 1024 1581 | end 1582 | 1583 | # use kvm's unsafe mode 1584 | if vm_unsafe 1585 | # Configure the Vagrant environment to use kvm's unsafe cache mode. 1586 | # If you do this, you will trade data integrity on your development 1587 | # environment's filesystem for a noticeable speed boost. 1588 | # See http://libvirt.org/formatdomain.html#elementsDisks 1589 | libvirt.volume_cache = 'unsafe' 1590 | end 1591 | 1592 | # allow nesting vm's 1593 | if vm_nested 1594 | libvirt.nested = true 1595 | libvirt.cpu_mode = 'host-model' 1596 | end 1597 | end 1598 | vm.vm.provider :virtualbox do |vb| 1599 | 1600 | if vm_cpus.to_i != 0 # handles '', nil, & 0 1601 | vb.customize ["modifyvm", :id, "--cpus", "#{vm_cpus}"] 1602 | 1603 | # make puppet server a bit fatter by default :P 1604 | elsif (puppet and vm_puppet and h == 'puppet') or vm_nested 1605 | vb.customize ["modifyvm", :id, "--cpus", "2"] 1606 | end 1607 | 1608 | if vm_memory.to_i != 0 1609 | vb.customize ["modifyvm", :id, "--memory", "#{vm_memory}"] 1610 | 1611 | # make puppet server a bit fatter by default :P 1612 | elsif (puppet and vm_puppet and h == 'puppet') or vm_nested 1613 | vb.customize ["modifyvm", :id, "--memory", "1024"] 1614 | end 1615 | end 1616 | 1617 | # reboot the hosts 1618 | if vm_reboot and first_run 1619 | vm.vm.provision :reload 1620 | end 1621 | end 1622 | end 1623 | 1624 | # 1625 | # libvirt 1626 | # 1627 | config.vm.provider :libvirt do |libvirt| 1628 | libvirt.driver = 'kvm' # needed for kvm performance benefits ! 1629 | libvirt.graphics_type = 'spice' 1630 | libvirt.video_type = 'qxl' 1631 | # leave out to connect directly with qemu:///system 1632 | #libvirt.host = 'localhost' 1633 | libvirt.connect_via_ssh = false 1634 | libvirt.username = 'root' 1635 | libvirt.storage_pool_name = 'default' 1636 | #libvirt.default_network = 'default' # XXX: this does nothing 1637 | libvirt.default_prefix = "#{namespace}" # set a prefix for your vm's... 1638 | end 1639 | 1640 | # 1641 | # virtualbox 1642 | # 1643 | config.vm.provider :virtualbox do |vb| 1644 | # ref params: http://www.virtualbox.org/manual/ch08.html#vboxmanage-modifyvm 1645 | vb.customize ["modifyvm", :id, "--hwvirtex", "on"] # needed for kvm performance benefits ! 1646 | # TODO: Find corresponding params in Virtual Box 1647 | # libvirt.connect_via_ssh = false 1648 | # libvirt.username = 'root' 1649 | # libvirt.storage_pool_name = 'default' 1650 | # #libvirt.default_network = 'default' # XXX: this does nothing 1651 | # libvirt.default_prefix = "#{namespace}" # set a prefix for your vm's... 1652 | end 1653 | 1654 | end 1655 | --------------------------------------------------------------------------------