-
-
Save mitsururike/d8952388f2abbc7ae706ffb6a2225833 to your computer and use it in GitHub Desktop.
my init script to create an ansible role
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
set -e | |
usage() { | |
cat <<'__EOF__' | |
ansible-role-init [ directory ] | |
initialize ansible role git repo | |
__EOF__ | |
} | |
args=`getopt h $*` | |
if [ $? -ne 0 ]; then | |
usage | |
exit 2 | |
fi | |
set -- $args | |
while true; do | |
case "$1" in | |
-h) | |
usage | |
exit 2 | |
;; | |
--) | |
shift; break | |
;; | |
esac | |
done | |
DEST=$1 | |
if [ -z "${DEST}" ]; then | |
echo "requires role dir name" | |
usage | |
exit 2 | |
fi | |
if [ -d "${DEST}" ]; then | |
echo "target directory ${DEST} exists" | |
exit 1 | |
fi | |
ROLENAME=`echo $DEST | sed -e 's/^ansible-role-//' -e 's/-/_/g'` | |
if [ -z ${ROLENAME} ]; then | |
echo "invalid role name: ${DEST}" | |
echo "valid role name is: ansible-role-\$ROLENAME" | |
echo "\$ROLENAME should be [0-9a-zA-Z-_]+" | |
exit 1 | |
fi | |
BOXNAME_WITHOUT_USERNAME="freebsd-10.3-amd64" | |
BOXNAME="trombik\/ansible-${BOXNAME_WITHOUT_USERNAME}" | |
YYYY=`date +%Y` | |
MYID=`whoami` | |
PLATFORM=`uname -s` | |
if [ "${PLATFORM}" = 'Darwin' ]; then | |
MYNAME=`finger ${MYID} | awk -F: '{ print $3 }' | head -n1 | sed 's/^ //'` | |
else | |
MYNAME=`getent passwd ${MYID} | cut -d ':' -f 5 | cut -d ',' -f 1` | |
fi | |
mkdir "${DEST}" | |
cd "${DEST}" | |
required_directories="defaults files handlers tasks templates vars extra_modules extra_roles filter_plugins library meta tests" | |
for i in ${required_directories}; do | |
mkdir "${i}" | |
touch "${i}/.keepme" | |
done | |
required_sub_directories="tests/integration tests/serverspec tests/travisci tests/integration/example/group_vars tests/integration/example/host_vars tests/integration/example/inventories tests/integration/example/roles tests/integration/example/spec" | |
for i in ${required_sub_directories}; do | |
mkdir -p "${i}" | |
touch "${i}/.keepme" | |
done | |
touch tests/integration/example/inventories/staging | |
cat > Rakefile <<'__EOF__' | |
require 'pathname' | |
root_dir = Pathname.new(__FILE__).dirname | |
integration_test_dir = root_dir + 'tests' + 'integration' | |
integration_test_dirs = Pathname.new(integration_test_dir).children.select { |c| c.directory? } | |
task default: %w[ test ] | |
desc 'run all tests' | |
task :test do | |
integration_test_dirs.each do |d| | |
rakefile = d + 'Rakefile' | |
if rakefile.exist? and rakefile.file? | |
Dir.chdir(d) do | |
puts "entering to %s" % [ d ] | |
begin | |
puts 'running rake' | |
sh 'rake' | |
ensure | |
sh 'rake clean' | |
end | |
end | |
else | |
puts 'Rakefile does not exist, skipping' | |
end | |
end | |
end | |
task :clean do | |
integration_test_dirs.each do |d| | |
rakefile = d + 'Rakefile' | |
if rakefile.exist? and rakefile.file? | |
Dir.chdir(d) do | |
puts "entering to %s" % [ d ] | |
begin | |
puts 'running rake clean' | |
sh 'rake clean' | |
rescue Exception => e | |
puts 'rake clean clean failed:' | |
puts e.message | |
puts e.backtrace.inspect | |
end | |
end | |
end | |
end | |
end | |
__EOF__ | |
cat > .kitchen.yml <<'__EOF__' | |
--- | |
driver: | |
name: vagrant | |
transport: | |
name: rsync | |
provisioner: | |
hosts: test-kitchen | |
name: ansible_playbook | |
require_chef_for_busser: false | |
require_ruby_for_busser: false | |
ansible_verbosity: 1 | |
ansible_verbose: true | |
ansible_extra_flags: <%= ENV['ANSIBLE_EXTRA_FLAGS'] %> | |
http_proxy: <%= ENV['ANSIBLE_PROXY'] %> | |
additional_copy_path: | |
- extra_modules | |
- filter_plugins | |
- extra_roles | |
ansible_vault_password_file: <%= File.expand_path(ENV['ANSIBLE_VAULT_PASSWORD_FILE'] || '') %> | |
platforms: | |
- name: BOXNAME_WITHOUT_USERNAME | |
driver: | |
box: BOXNAME | |
box_check_update: false | |
driver_config: | |
ssh: | |
shell: '/bin/sh' | |
provisioner: | |
extra_vars: | |
ansible_python_interpreter: '/usr/local/bin/python' | |
suites: | |
- name: default | |
provisioner: | |
name: ansible_playbook | |
playbook: tests/serverspec/default.yml | |
verifier: | |
name: shell | |
command: rspec -c -f d -I tests/serverspec tests/serverspec/default_spec.rb | |
__EOF__ | |
# https://gist.github.com/fnichol/7551540 | |
cat > .kitchen.local.yml <<'__EOF__' | |
<% | |
require 'socket' | |
# @return [String] public IP address of workstation used for egress traffic | |
def local_ip | |
@local_ip ||= begin | |
# turn off reverse DNS resolution temporarily | |
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true | |
# open UDP socket so that it never send anything over the network | |
UDPSocket.open do |s| | |
s.connect '8.8.8.8', 1 # any global IP address works here | |
s.addr.last | |
end | |
ensure | |
Socket.do_not_reverse_lookup = orig | |
end | |
end | |
# @return [Integer] default listening port | |
def local_port ; 8080 ; end | |
# @return [String] the proxy URL | |
def http_proxy_url ; "http://#{local_ip}:#{local_port}" ; end | |
# @return [TrueClass,FalseClass] whether or not the port is listening | |
def proxy_running? | |
socket = TCPSocket.new(local_ip, local_port) | |
true | |
rescue SocketError, Errno::ECONNREFUSED, | |
Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError | |
false | |
rescue Errno::EPERM, Errno::ETIMEDOUT | |
false | |
ensure | |
socket && socket.close | |
end | |
%> | |
--- | |
<% if proxy_running? %> | |
provisioner: | |
http_proxy: <%= http_proxy_url %> | |
https_proxy: <%= http_proxy_url %> | |
<% end %> | |
__EOF__ | |
cat > defaults/main.yml <<'__EOF__' | |
CHANGEME_user: CHANGEME | |
CHANGEME_group: CHANGEME | |
CHANGEME_log_dir: /var/log/CHANGEME | |
CHANGEME_db_dir: "{{ __CHANGEME_db_dir }}" | |
CHANGEME_service: CHANGEME | |
CHANGEME_conf_dir: "{{ __CHANGEME_conf_dir }}" | |
CHANGEME_conf_file: "{{ __CHANGEME_conf_dir }}/CHANGEME.conf" | |
CHANGEME_flags: "" | |
__EOF__ | |
cat > vars/FreeBSD.yml <<'__EOF__' | |
__CHANGEME_db_dir: /var/db/CHANGEME | |
__CHANGEME_conf_dir: /usr/local/etc/CHANGEME | |
__EOF__ | |
cat > tasks/main.yml <<'__EOF__' | |
--- | |
# tasks file for ansible-role-CHANGEME | |
- include_vars: "{{ ansible_os_family }}.yml" | |
- include: "install-{{ ansible_os_family }}.yml" | |
- name: Create log directory | |
file: | |
path: "{{ CHANGEME_log_dir }}" | |
mode: 0755 | |
owner: "{{ CHANGEME_user }}" | |
group: "{{ CHANGEME_group }}" | |
state: directory | |
notify: Restart CHANGEME | |
- name: Create db directory | |
file: | |
path: "{{ CHANGEME_db_dir }}" | |
mode: 0755 | |
owner: "{{ CHANGEME_user }}" | |
group: "{{ CHANGEME_group }}" | |
state: directory | |
notify: Restart CHANGEME | |
- name: Create CHANGEME.conf | |
template: | |
src: CHANGEME.conf.j2 | |
dest: "{{ CHANGEME_conf_file }}" | |
notify: Restart CHANGEME | |
- name: Start CHANGEME | |
service: | |
name: "{{ CHANGEME_service }}" | |
enabled: true | |
state: started | |
__EOF__ | |
cat > tests/serverspec/default.yml <<'__EOF__' | |
- hosts: localhost | |
roles: | |
- ansible-role-CHANGEME | |
vars: | |
CHANGEME_config: "" | |
__EOF__ | |
cat > handlers/main.yml <<'__EOF__' | |
--- | |
- name: Restart CHANGEME | |
service: | |
name: CHANGEME | |
state: restarted | |
__EOF__ | |
cat > tasks/install-FreeBSD.yml <<'__EOF__' | |
--- | |
- name: Install CHANGEME | |
pkgng: | |
name: CHANGEME | |
state: present | |
__EOF__ | |
cat > .travis.yml <<'__EOF__' | |
--- | |
language: python | |
python: "2.7" | |
# Use the new container infrastructure | |
sudo: false | |
# Install ansible | |
addons: | |
apt: | |
packages: | |
- python-pip | |
- wget | |
install: | |
# Install ansible | |
- pip install ansible | |
# Check ansible version | |
- ansible --version | |
# Create ansible.cfg with correct roles_path | |
- printf '[defaults]\nroles_path=../:extra_roles' >ansible.cfg | |
script: | |
# Basic role syntax check | |
- ansible-playbook tests/travisci/tests.yml -i tests/travisci/inventory --syntax-check | |
# download the QA scripts | |
- mkdir bin | |
- wget -O bin/ansible-role-qa https://gist.githubusercontent.com/trombik/047364853d2f8070da9d4f360b4b9da9/raw | |
- wget -O bin/ansible-role-init https://gist.githubusercontent.com/trombik/d01e280f02c78618429e334d8e4995c0/raw | |
- chmod +x bin/* | |
# use recent ruby, instead of default ruby 1.9 | |
- rvm install ruby-2.1.10 | |
- rvm use 2.1.10 | |
# git complains if user and email are not set | |
- git config --global user.name "Your Name" | |
- git config --global user.email "you@example.com" | |
# surpress a warning from `ansible-role-qa` | |
- touch .kitchen.local.yml | |
# run the QA test | |
- export PATH="${PATH}:${PWD}/bin" | |
- ansible-role-qa | |
notifications: | |
webhooks: https://galaxy.ansible.com/api/v1/notifications/ | |
__EOF__ | |
cat > tests/travisci/tests.yml <<'__EOF__' | |
--- | |
- hosts: localhost | |
remote_user: root | |
roles: | |
- ansible-role-CHANGEME | |
__EOF__ | |
cat > tests/travisci/inventory <<'__EOF__' | |
localhost | |
__EOF__ | |
cat > tests/serverspec/spec_helper.rb <<'__EOF__' | |
require 'serverspec' | |
set :backend, :ssh | |
options = Net::SSH::Config.for(host) | |
options[:host_name] = ENV['KITCHEN_HOSTNAME'] | |
options[:user] = ENV['KITCHEN_USERNAME'] | |
options[:port] = ENV['KITCHEN_PORT'] | |
options[:keys] = ENV['KITCHEN_SSH_KEY'] | |
set :host, options[:host_name] | |
set :ssh_options, options | |
set :env, :LANG => 'C', :LC_ALL => 'C' | |
__EOF__ | |
cat > tests/serverspec/default_spec.rb <<'__EOF__' | |
require 'spec_helper' | |
require 'serverspec' | |
package = 'CHANGEME' | |
service = 'CHANGEME' | |
config = '/etc/CHANGEME/CHANGEME.conf' | |
user = 'CHANGEME' | |
group = 'CHANGEME' | |
ports = [ PORTS ] | |
log_dir = '/var/log/CHANGEME' | |
db_dir = '/var/lib/CHANGEME' | |
case os[:family] | |
when 'freebsd' | |
config = '/usr/local/etc/CHANGEME.conf' | |
db_dir = '/var/db/CHANGEME' | |
end | |
describe package(package) do | |
it { should be_installed } | |
end | |
describe file(config) do | |
it { should be_file } | |
its(:content) { should match Regexp.escape('CHANGEME') } | |
end | |
describe file(log_dir) do | |
it { should exist } | |
it { should be_mode 755 } | |
it { should be_owned_by user } | |
it { should be_grouped_into group } | |
end | |
describe file(db_dir) do | |
it { should exist } | |
it { should be_mode 755 } | |
it { should be_owned_by user } | |
it { should be_grouped_into group } | |
end | |
case os[:family] | |
when 'freebsd' | |
describe file('/etc/rc.conf.d/CHANGEME') do | |
it { should be_file } | |
end | |
end | |
describe service(service) do | |
it { should be_running } | |
it { should be_enabled } | |
end | |
ports.each do |p| | |
describe port(p) do | |
it { should be_listening } | |
end | |
end | |
__EOF__ | |
cat > .gitignore <<'__EOF__' | |
/.kitchen/ | |
.kitchen.local.yml | |
*.swp | |
.bundle/ | |
vendor/ | |
Gemfile.lock | |
__EOF__ | |
cat > .ackrc <<'__EOF__' | |
--ignore-dir=vendor | |
--ignore-dir=.kitchen | |
__EOF__ | |
cat > meta/main.yml <<'__EOF__' | |
--- | |
galaxy_info: | |
author: MYNAME | |
description: Configures something | |
company: Reallyenglish | |
license: BSD | |
min_ansible_version: 2.0 | |
platforms: | |
- name: FreeBSD | |
versions: | |
- 10.3 | |
# - name: OpenBSD | |
# versions: | |
# - 6.0 | |
# - name: Ubuntu | |
# versions: | |
# - trusty | |
# - name: EL | |
# versions: | |
# - 7 | |
galaxy_tags: [] | |
#dependencies: | |
# - { role: username.common, some_parameter: 3 } | |
__EOF__ | |
cat > CHANGELOG.md <<'__EOF__' | |
# Release 0.0.0 | |
* Initail release | |
__EOF__ | |
cat > README.md <<'__EOF__' | |
# ansible-role-CHANGEME | |
A brief description of the role goes here. | |
# Requirements | |
None | |
# Role Variables | |
| variable | description | default | | |
|----------|-------------|---------| | |
# Dependencies | |
None | |
# Example Playbook | |
```yaml | |
``` | |
# License | |
``` | |
Copyright (c) YYYY MYNAME <MYID@reallyenglish.com> | |
Permission to use, copy, modify, and distribute this software for any | |
purpose with or without fee is hereby granted, provided that the above | |
copyright notice and this permission notice appear in all copies. | |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
``` | |
# Author Information | |
MYNAME <MYID@reallyenglish.com> | |
This README was created by [ansible-role-init](https://gist.github.com/trombik/d01e280f02c78618429e334d8e4995c0) | |
__EOF__ | |
cat > LICENSE <<'__EOF__' | |
Copyright (c) YYYY MYNAME <MYID@reallyenglish.com> | |
Permission to use, copy, modify, and distribute this software for any | |
purpose with or without fee is hereby granted, provided that the above | |
copyright notice and this permission notice appear in all copies. | |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
__EOF__ | |
cat > Jenkinsfile <<'__EOF__' | |
node ('virtualbox') { | |
def directory = "DESTNAME" | |
env.ANSIBLE_VAULT_PASSWORD_FILE = "~/.ansible_vault_key" | |
stage 'Clean up' | |
deleteDir() | |
stage 'Checkout' | |
sh "mkdir $directory" | |
dir("$directory") { | |
try { | |
checkout scm | |
sh "git submodule update --init" | |
} catch (e) { | |
currentBuild.result = 'FAILURE' | |
notifyBuild(currentBuild.result) | |
throw e | |
} | |
} | |
dir("$directory") { | |
stage 'bundle' | |
try { | |
sh "bundle install --path ${env.JENKINS_HOME}/vendor/bundle" | |
} catch (e) { | |
currentBuild.result = 'FAILURE' | |
notifyBuild(currentBuild.result) | |
throw e | |
} | |
stage 'bundle exec kitchen test' | |
try { | |
sh 'bundle exec kitchen test' | |
} catch (e) { | |
currentBuild.result = 'FAILURE' | |
notifyBuild(currentBuild.result) | |
throw e | |
} finally { | |
sh 'bundle exec kitchen destroy' | |
} | |
/* if you have integration tests, uncomment the stage below | |
stage 'integration' | |
try { | |
// use native rake instead of bundle exec rake | |
// https://github.com/docker-library/ruby/issues/73 | |
sh 'rake test' | |
} catch (e) { | |
currentBuild.result = 'FAILURE' | |
notifyBuild(currentBuild.result) | |
throw e | |
} finally { | |
sh 'rake clean' | |
} | |
*/ | |
stage 'Notify' | |
notifyBuild(currentBuild.result) | |
step([$class: 'GitHubCommitNotifier', resultOnFailure: 'FAILURE']) | |
} | |
} | |
def notifyBuild(String buildStatus = 'STARTED') { | |
// build status of null means successful | |
buildStatus = buildStatus ?: 'SUCCESSFUL' | |
// Default values | |
def colorName = 'RED' | |
def colorCode = '#FF0000' | |
def subject = "${buildStatus}: Job '${env.JOB_NAME} build #${env.BUILD_NUMBER}'" | |
def summary = "${subject} <a href='${env.BUILD_URL}'>${env.BUILD_URL}</a>" | |
def details = """<p>STARTED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':</p> | |
<p>Check console output at "<a href='${env.BUILD_URL}'>${env.JOB_NAME} [${env.BUILD_NUMBER}]</a>"</p>""" | |
// Override default values based on build status | |
if (buildStatus == 'STARTED') { | |
color = 'YELLOW' | |
colorCode = '#FFFF00' | |
} else if (buildStatus == 'SUCCESSFUL') { | |
color = 'GREEN' | |
colorCode = '#00FF00' | |
} else { | |
color = 'RED' | |
colorCode = '#FF0000' | |
} | |
hipchatSend (color: color, notify: true, message: summary) | |
} | |
/* vim: ft=groovy */ | |
__EOF__ | |
cat > Gemfile <<'__EOF__' | |
source 'https://rubygems.org' | |
# rack 2.x requires ruby >= 2.2.2 | |
gem 'rack', '~> 1.6.4' | |
gem 'rake', '~> 11.1.2' | |
gem 'rspec', '~> 3.4.0' | |
gem "test-kitchen", '~> 1.6.0' | |
gem "kitchen-vagrant", '~> 0.20.0' | |
# use patched kitchen-ansible | |
gem "kitchen-ansible", '~> 0.40.1', :git => 'https://github.com/trombik/kitchen-ansible.git', :branch => 'freebsd_support' | |
gem "kitchen-sync", '~> 2.1.1', :git => 'https://github.com/trombik/kitchen-sync.git', :branch => 'without_full_path_to_rsync' | |
gem 'kitchen-verifier-shell', '~> 0.2.0' | |
gem 'kitchen-verifier-serverspec', '~> 0.3.0' | |
gem 'infrataster', '~> 0.3.2', :git => 'https://github.com/trombik/infrataster.git', :branch => 'reallyenglish' | |
gem 'serverspec', '~> 2.37.2' | |
gem 'specinfra', '>= 2.63.2' # OpenBSD's `port` is fixed in this version | |
__EOF__ | |
cat > tests/integration/example/site.yml <<'__EOF__' | |
- include: server.yml | |
- include: client.yml | |
__EOF__ | |
cat > tests/integration/example/.gitignore <<'__EOF__' | |
*.retry | |
roles/*/ | |
.vagrant/ | |
__EOF__ | |
cat > tests/integration/example/.rspec <<'__EOF__' | |
--format documentation | |
__EOF__ | |
cat > tests/integration/example/Rakefile <<'__EOF__' | |
require 'tempfile' | |
require 'pathname' | |
require 'net/http' | |
require 'tempfile' | |
test_dir = Pathname.new(__FILE__).dirname | |
role_dir = Pathname.new(test_dir).parent.parent.parent | |
role_name = Pathname.new(role_dir).basename | |
required_roles = %w[ | |
] | |
def fetch(uri_str, limit = 10) | |
raise ArgumentError, 'too many HTTP redirects' if limit == 0 | |
response = Net::HTTP.get_response(URI(uri_str)) | |
case response | |
when Net::HTTPSuccess then | |
response | |
when Net::HTTPRedirection then | |
location = response['location'] | |
warn "redirected to #{location}" | |
fetch(location, limit - 1) | |
else | |
raise "HTTP response is not success nor redirect (value: #{response.value})" | |
end | |
end | |
task default: %w[ test ] | |
desc 'run rspec' | |
task :test => [ :clean, :prepare, :do_test, :ensure_clean ] do | |
end | |
desc 'clean' | |
task :clean => [ :clean_vagrant, :clean_roles, :clean_role ] do | |
end | |
desc 'destroy vagrant nodes' | |
task :clean_vagrant do | |
sh 'vagrant destroy -f' | |
end | |
desc 'rm roles/*' | |
task :clean_role do | |
sh 'rm -rf roles/*' | |
sh 'rm -f *.retry' | |
end | |
desc 'prepare the test environment' | |
task :prepare => [ :prepare_role, :prepare_roles, :vagrant_up ] do | |
end | |
desc 'import required roles' | |
task :prepare_roles do | |
required_roles.each do |r| | |
Dir.chdir('roles') do | |
res = fetch "https://github.com/reallyenglish/#{r}/archive/master.tar.gz" | |
file = Tempfile.new('tar') | |
file.write(res.body) | |
file.close | |
sh "tar xf #{file.path}" | |
file.unlink | |
sh "mv #{r}-master #{r}" | |
end | |
end | |
end | |
desc 'clean up required roles' | |
task :clean_roles do | |
required_roles.each do |r| | |
Dir.chdir('roles') do | |
sh "rm -rf #{r}" | |
end | |
end | |
end | |
desc 'prepare role' | |
task :prepare_role do | |
ignore_files = %w[ vendor .kitchen .git tests spec ].map { |f| "#{role_name}/#{f}" } | |
tmpfile = Tempfile.new('.tarignore') | |
tmpfile.write ignore_files.join("\n") | |
tmpfile.close | |
sh "tar -c -X #{tmpfile.path} -C #{role_dir.parent} -f - #{role_name} | tar -x -C #{test_dir}/roles -f -" | |
end | |
desc 'vagrant up' | |
task :vagrant_up do | |
sh 'vagrant up' | |
end | |
desc 'do clean task even if it has been executed' | |
task :ensure_clean do | |
Rake::Task["clean"].all_prerequisite_tasks.each do |task| | |
task.reenable | |
end | |
Rake::Task["clean"].reenable | |
Rake::Task["clean"].invoke | |
end | |
desc 'Do the test' | |
task :do_test do | |
sh 'bundle exec rspec' | |
end | |
__EOF__ | |
cat > tests/integration/example/spec/spec_helper.rb <<'__EOF__' | |
require 'infrataster/rspec' | |
require 'capybara' | |
ENV['VAGRANT_CWD'] = File.dirname(__FILE__) | |
ENV['LANG'] = 'C' | |
if ENV['JENKINS_HOME'] | |
# XXX "bundle exec vagrant" fails to load. | |
# https://github.com/bundler/bundler/issues/4602 | |
# | |
# > bundle exec vagrant --version | |
# bundler: failed to load command: vagrant (/usr/local/bin/vagrant) | |
# Gem::Exception: can't find executable vagrant | |
# /usr/local/lib/ruby/gems/2.2/gems/bundler-1.12.1/lib/bundler/rubygems_integration.rb:373:in `block in replace_bin_path' | |
# /usr/local/lib/ruby/gems/2.2/gems/bundler-1.12.1/lib/bundler/rubygems_integration.rb:387:in `block in replace_bin_path' | |
# /usr/local/bin/vagrant:23:in `<top (required)>' | |
# | |
# this causes "vagrant ssh-config" to fail, invoked in a spec file, i.e. when | |
# you need to ssh to a vagrant host. | |
# | |
# include the path of bin to vagrant | |
vagrant_real_path = `pkg info -l vagrant | grep -v '/usr/local/bin/vagrant' | grep -E 'bin\/vagrant$'| sed -e 's/^[[:space:]]*//'` | |
vagrant_bin_dir = File.dirname(vagrant_real_path) | |
ENV['PATH'] = "#{vagrant_bin_dir}:#{ENV['PATH']}" | |
end | |
Infrataster::Server.define( | |
:client1, | |
'192.168.21.100', | |
vagrant: true | |
) | |
Infrataster::Server.define( | |
:server1, | |
'192.168.21.200', | |
vagrant: true | |
) | |
def fetch(uri_str, limit = 10) | |
raise ArgumentError, 'too many HTTP redirects' if limit == 0 | |
response = Net::HTTP.get_response(URI(uri_str)) | |
case response | |
when Net::HTTPSuccess then | |
response | |
when Net::HTTPRedirection then | |
location = response['location'] | |
warn "redirected to #{location}" | |
fetch(location, limit - 1) | |
else | |
raise "HTTP response is not success nor redirect (value: #{response.value})" | |
end | |
end | |
def retry_and_sleep(options = {}, &block) | |
opts = { | |
:tries => 60, | |
:sec => 10, | |
:on => [ Exception ], | |
:verbose => false | |
}.merge(options) | |
tries, sec, on, verbose = opts[:tries], opts[:sec], opts[:on], opts[:verbose] | |
i = 1 | |
begin | |
yield | |
rescue *on => e | |
warn "rescue an excpetion %s" % [ e.class ] if verbose | |
warn e.message if verbose | |
if (tries -= 1) > 0 | |
warn "retrying (remaining: %d)" % [ tries ] | |
warn "sleeping %d sec" % [ sec ] if verbose | |
sleep sec | |
i += 1 | |
retry | |
end | |
end | |
end | |
require 'shellwords' | |
class Vagrant | |
def initialize | |
@status # Process::Status | |
@out | |
@err | |
end | |
def up(server) | |
execute('up', '', server) | |
end | |
def boot(server) | |
execute('up', '--no-provision', server) | |
end | |
def provision(server) | |
execute('provision', '', server) | |
end | |
def destroy(server) | |
execute('destroy', '--force', server) | |
end | |
def execute(command, opt, server) | |
begin | |
command = "vagrant #{Shellwords.escape(command)}" + ' ' | |
command += "#{Shellwords.escape(opt)}" + ' ' if not opt.empty? | |
command += "#{Shellwords.escape(server)}" | |
@out, @err, @status = Open3.capture3(command) | |
rescue SystemCallError => e | |
@status = e | |
end | |
status | |
end | |
def status | |
@status | |
end | |
def stdout | |
@out | |
end | |
def stdout_lines | |
@out.split("\n").to_a | |
end | |
def stderr | |
@err | |
end | |
def stderr_lines | |
@err.split("\n").to_a | |
end | |
def status | |
@status | |
end | |
def success? | |
return false if @success.nil? | |
return false if @status.is_a?(Exception) | |
@status.success? | |
end | |
end | |
RSpec.configure do |config| | |
config.expect_with :rspec do |expectations| | |
expectations.include_chain_clauses_in_custom_matcher_descriptions = true | |
end | |
config.mock_with :rspec do |mocks| | |
mocks.verify_partial_doubles = true | |
end | |
end | |
__EOF__ | |
cat > tests/integration/example/spec/default_spec.rb <<'__EOF__' | |
require 'spec_helper' | |
class ServiceNotReady < StandardError | |
end | |
sleep 10 if ENV['JENKINS_HOME'] | |
context 'after provisioning finished' do | |
describe server(:client1) do | |
it 'should be able to ping server' do | |
result = current_server.ssh_exec("ping -c 1 #{ server(:server1).server.address } && echo OK") | |
expect(result).to match(/OK/) | |
end | |
end | |
describe server(:server1) do | |
it 'should be able to ping client' do | |
result = current_server.ssh_exec("ping -c 1 #{ server(:client1).server.address } && echo OK") | |
expect(result).to match(/OK/) | |
end | |
end | |
end | |
__EOF__ | |
cat > tests/integration/example/Vagrantfile <<'__EOF__' | |
require 'socket' | |
# @return [String] public IP address of workstation used for egress traffic | |
def local_ip | |
@local_ip ||= begin | |
# turn off reverse DNS resolution temporarily | |
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true | |
# open UDP socket so that it never send anything over the network | |
UDPSocket.open do |s| | |
s.connect '8.8.8.8', 1 # any global IP address works here | |
s.addr.last | |
end | |
ensure | |
Socket.do_not_reverse_lookup = orig | |
end | |
end | |
# @return [Integer] default listening port | |
def local_port ; 8080 ; end | |
# @return [String] the proxy URL | |
def http_proxy_url ; "http://#{local_ip}:#{local_port}" ; end | |
# @return [TrueClass,FalseClass] whether or not the port is listening | |
def proxy_running? | |
socket = TCPSocket.new(local_ip, local_port) | |
true | |
rescue SocketError, Errno::ECONNREFUSED, | |
Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError | |
false | |
rescue Errno::EPERM, Errno::ETIMEDOUT | |
false | |
ensure | |
socket && socket.close | |
end | |
http_proxy = proxy_running? ? http_proxy_url : '' | |
# Vagrantfile | |
Vagrant.configure("2") do |config| | |
config.ssh.shell = "/bin/sh" | |
config.vm.provider "virtualbox" do |v| | |
v.memory = 256 | |
v.cpus = 1 | |
end | |
config.vm.box = "trombik/ansible-freebsd-10.3-amd64" | |
config.vm.define "client1" do |c| | |
c.vm.network "private_network", ip: "192.168.21.100" | |
c.vm.hostname = "client1.virtualbox.reallyenglish.com" | |
c.vm.provision :ansible do |ansible| | |
ansible.limit = '192.168.21.100' | |
ansible.playbook = "site.yml" | |
ansible.extra_vars = { | |
ansible_python_interpreter: '/usr/local/bin/python', | |
http_proxy: http_proxy, | |
https_proxy: http_proxy, | |
no_proxy: 'localhost,127.0.0.1,.example.com' | |
} | |
ansible.inventory_path = 'inventories/staging' | |
ansible.verbose = 'v' | |
end | |
end | |
config.vm.define "server1" do |c| | |
c.vm.network "private_network", ip: "192.168.21.200" | |
c.vm.hostname = "server1.virtualbox.reallyenglish.com" | |
c.vm.provision :ansible do |ansible| | |
ansible.limit = '192.168.21.200' | |
ansible.playbook = "site.yml" | |
ansible.extra_vars = { | |
ansible_python_interpreter: '/usr/local/bin/python', | |
http_proxy: http_proxy, | |
https_proxy: http_proxy, | |
no_proxy: 'localhost,127.0.0.1,.example.com' | |
} | |
ansible.inventory_path = 'inventories/staging' | |
ansible.verbose = 'v' | |
end | |
end | |
end | |
# vim: ft=ruby | |
__EOF__ | |
cat > tests/integration/example/server.yml <<'__EOF__' | |
--- | |
- hosts: server | |
become: yes | |
become_method: sudo | |
environment: | |
http_proxy: "{{ http_proxy | default() }}" | |
https_proxy: "{{ https_proxy | default() }}" | |
no_proxy: "{{ no_proxy | default() }}" | |
pre_tasks: | |
roles: | |
- CHANGEME | |
__EOF__ | |
cat > tests/integration/example/client <<'__EOF__' | |
--- | |
- hosts: client | |
become: yes | |
become_method: sudo | |
environment: | |
http_proxy: "{{ http_proxy | default() }}" | |
https_proxy: "{{ https_proxy | default() }}" | |
no_proxy: "{{ no_proxy | default() }}" | |
pre_tasks: | |
roles: | |
- CHANGEME | |
__EOF__ | |
cat > tests/integration/example/inventories/staging <<'__EOF__' | |
[client] | |
192.168.21.100 | |
[server] | |
192.168.21.200 | |
[all:children] | |
server | |
client | |
__EOF__ | |
cat > tests/integration/example/example.yml <<'__EOF__' | |
--- | |
- hosts: example | |
become: yes | |
become_method: sudo | |
environment: | |
http_proxy: "{{ http_proxy | default() }}" | |
https_proxy: "{{ https_proxy | default() }}" | |
no_proxy: "{{ no_proxy | default() }}" | |
pre_tasks: | |
roles: | |
- CHANGEME | |
__EOF__ | |
find . -type f -print0 | \ | |
xargs -0 sed -i'' \ | |
-e "s/CHANGEME/${ROLENAME}/g" \ | |
-e "s/YYYY/${YYYY}/g" \ | |
-e "s/DESTNAME/${DEST}/g" \ | |
-e "s/MYNAME/${MYNAME}/g" \ | |
-e "s/MYID/${MYID}/g" \ | |
-e "s/BOXNAME_WITHOUT_USERNAME/${BOXNAME_WITHOUT_USERNAME}/g" \ | |
-e "s/BOXNAME/${BOXNAME}/g" | |
git init . | |
git add . | |
git commit -m 'initial import' | |
echo "Successfully created ${ROLENAME}." | |
echo "You need to run bundle install." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment