daptiv-chef-ci 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +8 -0
- data/README.md +2 -0
- data/Rakefile +25 -0
- data/daptiv-chef-ci.gemspec +58 -0
- data/lib/daptiv-chef-ci/logger.rb +33 -0
- data/lib/daptiv-chef-ci/shell.rb +54 -0
- data/lib/daptiv-chef-ci/templates/Vagrantfile.erb +41 -0
- data/lib/daptiv-chef-ci/vagrant_driver.rb +95 -0
- data/lib/daptiv-chef-ci/vagrant_task.rb +115 -0
- data/lib/daptiv-chef-ci/virtualbox_driver.rb +48 -0
- data/spec/daptiv-chef-ci/logger_spec.rb +41 -0
- data/spec/daptiv-chef-ci/shell_spec.rb +36 -0
- data/spec/daptiv-chef-ci/vagrant_driver_spec.rb +93 -0
- data/spec/daptiv-chef-ci/virtualbox_driver_spec.rb +32 -0
- metadata +215 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
# Change to the directory of this file.
|
6
|
+
Dir.chdir(File.expand_path("../", __FILE__))
|
7
|
+
|
8
|
+
# For gem creation and bundling
|
9
|
+
require "bundler/gem_tasks"
|
10
|
+
|
11
|
+
# Run the unit test suite
|
12
|
+
RSpec::Core::RakeTask.new do |task|
|
13
|
+
task.pattern = "spec/**/*_spec.rb"
|
14
|
+
task.rspec_opts = [ '--color', '-f documentation' ]
|
15
|
+
task.rspec_opts << '-tunit'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Default task is to run tests
|
19
|
+
task :default => "spec"
|
20
|
+
|
21
|
+
desc 'Run foodcritic with default rule set.'
|
22
|
+
task :path do
|
23
|
+
puts ENV['PATH']
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.authors = ["Shawn Neal"]
|
5
|
+
gem.email = ["sneal@daptiv.com"]
|
6
|
+
gem.description = %q{Vagrant automation for CI}
|
7
|
+
gem.summary = %q{A small gem to reduce Rake duplication}
|
8
|
+
gem.homepage = ""
|
9
|
+
|
10
|
+
# The following block of code determines the files that should be included
|
11
|
+
# in the gem. It does this by reading all the files in the directory where
|
12
|
+
# this gemspec is, and parsing out the ignored files from the gitignore.
|
13
|
+
# Note that the entire gitignore(5) syntax is not supported, specifically
|
14
|
+
# the "!" syntax, but it should mostly work correctly.
|
15
|
+
root_path = File.dirname(__FILE__)
|
16
|
+
all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
|
17
|
+
all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
|
18
|
+
gitignore_path = File.join(root_path, ".gitignore")
|
19
|
+
gitignore = File.readlines(gitignore_path)
|
20
|
+
gitignore.map! { |line| line.chomp.strip }
|
21
|
+
gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
|
22
|
+
|
23
|
+
unignored_files = all_files.reject do |file|
|
24
|
+
# Ignore any directories, the gemspec only cares about files
|
25
|
+
next true if File.directory?(file)
|
26
|
+
|
27
|
+
# Ignore any paths that match anything in the gitignore. We do
|
28
|
+
# two tests here:
|
29
|
+
#
|
30
|
+
# - First, test to see if the entire path matches the gitignore.
|
31
|
+
# - Second, match if the basename does, this makes it so that things
|
32
|
+
# like '.DS_Store' will match sub-directories too (same behavior
|
33
|
+
# as git).
|
34
|
+
#
|
35
|
+
gitignore.any? do |ignore|
|
36
|
+
File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
|
37
|
+
File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
gem.files = unignored_files
|
42
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
43
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
44
|
+
gem.name = "daptiv-chef-ci"
|
45
|
+
gem.require_paths = ["lib"]
|
46
|
+
gem.version = '0.0.1'
|
47
|
+
|
48
|
+
gem.add_runtime_dependency "mixlib-shellout", "~> 1.2.0"
|
49
|
+
gem.add_runtime_dependency "log4r", "~> 1.1.10"
|
50
|
+
gem.add_runtime_dependency "erubis", "~> 2.7.0"
|
51
|
+
|
52
|
+
gem.add_development_dependency "rake"
|
53
|
+
gem.add_development_dependency "rspec-core", "~> 2.12.2"
|
54
|
+
gem.add_development_dependency "rspec-expectations", "~> 2.12.1"
|
55
|
+
gem.add_development_dependency "rspec-mocks", "~> 2.12.1"
|
56
|
+
gem.add_development_dependency "simplecov"
|
57
|
+
gem.add_development_dependency "mocha", "~> 0.14.0"
|
58
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DaptivChefCI
|
2
|
+
class Logger
|
3
|
+
|
4
|
+
# Initializes and enables logging to the given environments level
|
5
|
+
# By default logging only occurs at ERROR level or higher.
|
6
|
+
# Set CHEF_CI_LOG env var to change logging levels
|
7
|
+
def self.init()
|
8
|
+
require 'log4r'
|
9
|
+
|
10
|
+
# Set the logging level on all "chef-ci" namespaced
|
11
|
+
# logs as long as we have a valid level.
|
12
|
+
logger = Log4r::Logger.new("daptiv_chef_ci")
|
13
|
+
logger.outputters = Log4r::Outputter.stderr
|
14
|
+
logger.level = log_level()
|
15
|
+
logger = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# LogLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
|
19
|
+
# DEBUG = 1
|
20
|
+
# INFO = 2
|
21
|
+
# WARN = 3
|
22
|
+
# ERROR = 4
|
23
|
+
# FATAL = 5
|
24
|
+
def self.log_level()
|
25
|
+
level = ENV['CHEF_CI_LOG'].upcase().to_s()
|
26
|
+
level_i = Log4r::Log4rConfig::LogLevels.index(level)
|
27
|
+
level_i + 1
|
28
|
+
rescue
|
29
|
+
return 4 # error
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'mixlib/shellout'
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
module DaptivChefCI
|
6
|
+
class Shell
|
7
|
+
|
8
|
+
def initialize()
|
9
|
+
@logger = Log4r::Logger.new("daptiv_chef_ci::shell")
|
10
|
+
end
|
11
|
+
|
12
|
+
# Executes the specified shell command and returns the stdout.
|
13
|
+
#
|
14
|
+
# This method ensure that any invoked command use the same PATH environment
|
15
|
+
# that the user has outside Ruby/Bundler.
|
16
|
+
#
|
17
|
+
# @param [String] The command line to execute
|
18
|
+
# @return [Array] Each entry represents a line from the stdout
|
19
|
+
def exec_cmd(command)
|
20
|
+
@logger.info("Calling command [#{command}]")
|
21
|
+
path_at_start = ENV['PATH']
|
22
|
+
begin
|
23
|
+
ENV['PATH'] = path_without_gem_dir()
|
24
|
+
@logger.debug("Temporarily setting PATH: #{ENV['PATH']}")
|
25
|
+
out = `#{command}`
|
26
|
+
@logger.debug(out)
|
27
|
+
out.split("\n")
|
28
|
+
ensure
|
29
|
+
@logger.debug("Resetting PATH: #{path_at_start}")
|
30
|
+
ENV['PATH'] = path_at_start
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the PATH environment variable as it was before Bundler prepended
|
35
|
+
# the system gem directory to it.
|
36
|
+
#
|
37
|
+
# This can happen if the user has invoked "require 'bundler/setup'" somewhere,
|
38
|
+
# like in this gems Rakefile.
|
39
|
+
#
|
40
|
+
# This is needed because sometimes a user will have the Vagrant gem installed
|
41
|
+
# on their system and we don't want to use it, we should use the one that's in
|
42
|
+
# their PATH as if they invoked vagrant themselves (i.e. the installed version)
|
43
|
+
#
|
44
|
+
# @return [String] The ENV['PATH] without the Bundler system gem dir prepended
|
45
|
+
def path_without_gem_dir
|
46
|
+
paths = ENV['PATH'].split(':')
|
47
|
+
system_gem_dir = "#{Bundler.bundle_path}/bin"
|
48
|
+
@logger.debug("System gem dir: #{system_gem_dir}")
|
49
|
+
paths.delete_if { |p| p.downcase() == system_gem_dir.downcase() }
|
50
|
+
paths.join(':')
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure("2") do |config|
|
5
|
+
chef_repo_dir = '<%= chef_repo_dir %>'
|
6
|
+
|
7
|
+
config.berkshelf.enabled = true
|
8
|
+
|
9
|
+
config.vm.box = '<%= box_name %>'
|
10
|
+
<% if !box_url.nil? %>
|
11
|
+
config.vm.box_url = '<%= box_url %>'
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<% if guest_os == :windows %>
|
15
|
+
config.vm.guest = :windows
|
16
|
+
|
17
|
+
config.windows.halt_timeout = 15
|
18
|
+
config.winrm.username = "vagrant"
|
19
|
+
config.winrm.password = "vagrant"
|
20
|
+
|
21
|
+
config.vm.network :forwarded_port, guest: 3389, host: 3389
|
22
|
+
config.vm.network :forwarded_port, guest: 5985, host: 5985
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
config.vm.provision :chef_solo do |chef|
|
26
|
+
chef.node_name = '<%= node_name %>'
|
27
|
+
chef.log_level = :info
|
28
|
+
chef.roles_path = File.join(chef_repo_dir, 'roles')
|
29
|
+
chef.data_bags_path = File.join(chef_repo_dir, 'data_bags')
|
30
|
+
chef.encrypted_data_bag_secret_key_path = '/etc/chef/encrypted_data_bag_secret'
|
31
|
+
chef.add_recipe 'minitest-handler'
|
32
|
+
<% run_list.each do |recipe| %>
|
33
|
+
chef.add_recipe '<%= recipe %>'
|
34
|
+
<% end %>
|
35
|
+
<% if !chef_json.nil? %>
|
36
|
+
chef.json = {
|
37
|
+
<%= chef_json %>
|
38
|
+
}
|
39
|
+
<% end %>
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'socket'
|
3
|
+
require 'erubis'
|
4
|
+
require_relative 'shell'
|
5
|
+
|
6
|
+
module DaptivChefCI
|
7
|
+
class VagrantDriver
|
8
|
+
|
9
|
+
# Constructs a new Vagrant management instance
|
10
|
+
#
|
11
|
+
# @param [Shell] The CLI
|
12
|
+
# @param [Hash] The options to pass to the Vagrantfile
|
13
|
+
#
|
14
|
+
# options[:guest_os] - defaults to :linux
|
15
|
+
# options[:chef_repo_dir] - The chef-repo root directory, defaults to ~/src/chef-repo
|
16
|
+
# options[:box_name] - defaults to 'Vagrant-hostname'
|
17
|
+
# options[:node_name] - The chef node name, defaults to 'Vagrant-hostname'
|
18
|
+
# options[:box_url] - URL to the box download location, this is optional.
|
19
|
+
# options[:run_list] - The Chef run list, defaults to empty.
|
20
|
+
# options[:chef_json] - Any additional Chef attributes in json format.
|
21
|
+
def initialize(shell, options)
|
22
|
+
@logger = Log4r::Logger.new("daptiv_chef_ci::vagrant")
|
23
|
+
@shell = shell
|
24
|
+
|
25
|
+
options[:guest_os] ||= :linux
|
26
|
+
options[:box_name] ||= "Vagrant-#{Socket.gethostname}"
|
27
|
+
options[:box_url] ||= nil
|
28
|
+
options[:node_name] ||= options[:box_name]
|
29
|
+
options[:run_list] ||= []
|
30
|
+
options[:chef_repo_dir] = "#{ENV['HOME']}/src/chef-repo"
|
31
|
+
options[:chef_json] ||= nil
|
32
|
+
@options = options
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_vagrantfile()
|
36
|
+
@logger.debug('Creating Vagrantfile')
|
37
|
+
File.open('Vagrantfile', 'w') do |f|
|
38
|
+
f.write render_vagrantfile()
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_vagrantfile()
|
43
|
+
Erubis::Eruby.new(vagrantfile_erb()).result(@options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy()
|
47
|
+
@shell.exec_cmd('vagrant destroy -f')
|
48
|
+
end
|
49
|
+
|
50
|
+
def halt()
|
51
|
+
@shell.exec_cmd('vagrant halt')
|
52
|
+
end
|
53
|
+
|
54
|
+
def up()
|
55
|
+
@shell.exec_cmd('vagrant up')
|
56
|
+
end
|
57
|
+
|
58
|
+
def provision()
|
59
|
+
@shell.exec_cmd('vagrant provision')
|
60
|
+
end
|
61
|
+
|
62
|
+
def reload()
|
63
|
+
@shell.exec_cmd('vagrant reload')
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def vagrantfile_erb()
|
70
|
+
path = vagrantfile_erb_path()
|
71
|
+
@logger.info("Using #{path} to render Vangrantfile")
|
72
|
+
File.read(vagrantfile_erb_path())
|
73
|
+
end
|
74
|
+
|
75
|
+
def vagrantfile_erb_path()
|
76
|
+
erbs = [
|
77
|
+
File.join(Dir.pwd, 'Vagrantfile.erb'),
|
78
|
+
File.join(Dir.pwd, 'build/Vagrantfile.erb'),
|
79
|
+
File.expand_path('Vagrantfile.erb', template_dir())
|
80
|
+
]
|
81
|
+
|
82
|
+
erbs.each do |erb|
|
83
|
+
@logger.debug("Searching for #{erb}")
|
84
|
+
return erb if File.exists?(erb)
|
85
|
+
end
|
86
|
+
# This should never happen
|
87
|
+
raise 'Couldn\'t find a Vagrantfile.erb!'
|
88
|
+
end
|
89
|
+
|
90
|
+
def template_dir()
|
91
|
+
File.join(File.expand_path(File.dirname(__FILE__)), 'templates')
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require_relative 'vagrant_driver'
|
4
|
+
require_relative 'virtualbox_driver'
|
5
|
+
require_relative 'shell'
|
6
|
+
require_relative 'logger'
|
7
|
+
|
8
|
+
begin
|
9
|
+
# Support Rake > 0.8.7
|
10
|
+
require 'rake/dsl_definition'
|
11
|
+
rescue LoadError
|
12
|
+
end
|
13
|
+
|
14
|
+
DaptivChefCI::Logger.init()
|
15
|
+
|
16
|
+
class Vagrant
|
17
|
+
|
18
|
+
# This class lets you define Rake tasks to drive Vagrant.
|
19
|
+
#
|
20
|
+
# @example Run the Python and NGinx cookbooks on a Linux guest
|
21
|
+
# Vagrant::RakeTask.new do |task|
|
22
|
+
# task.box_name = 'vagrant-FreeBSD'
|
23
|
+
# task.run_list = [ 'python', 'nginx' ]
|
24
|
+
# task.chef_repo_dir = '/Users/me/chef-repo'
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @example Run the Python and NGinx cookbooks on a Windows guest
|
28
|
+
# Vagrant::RakeTask.new do |task|
|
29
|
+
# task.guest_os = :windows
|
30
|
+
# task.box_name = 'vagrant-windows-server-r2'
|
31
|
+
# task.box_url = 'http://example.com/boxes/vagrant-windows-server-r2.box'
|
32
|
+
# task.run_list = [ 'python', 'nginx' ]
|
33
|
+
# task.chef_repo_dir = '/Users/me/chef-repo'
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
class RakeTask < ::Rake::TaskLib
|
37
|
+
include ::Rake::DSL if defined? ::Rake::DSL
|
38
|
+
|
39
|
+
attr_accessor :guest_os
|
40
|
+
attr_accessor :box_url
|
41
|
+
attr_accessor :box_name
|
42
|
+
attr_accessor :run_list
|
43
|
+
attr_accessor :node_name
|
44
|
+
attr_accessor :chef_repo_dir
|
45
|
+
attr_accessor :chef_json
|
46
|
+
|
47
|
+
# @param [String] name The task name.
|
48
|
+
# @param [String] desc Description of the task.
|
49
|
+
def initialize(name = 'vagrant', desc = 'Daptiv Vagrant Tasks')
|
50
|
+
@name, @desc = name, desc
|
51
|
+
@guest_os = nil
|
52
|
+
@box_url = nil
|
53
|
+
@box_name = nil
|
54
|
+
@run_list = []
|
55
|
+
@node_name = nil
|
56
|
+
@chef_repo_dir = nil
|
57
|
+
@chef_json = nil
|
58
|
+
|
59
|
+
yield self if block_given?
|
60
|
+
|
61
|
+
define_task
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def define_task
|
68
|
+
desc @desc
|
69
|
+
task @name do
|
70
|
+
|
71
|
+
options = {
|
72
|
+
:guest_os => @guest_os,
|
73
|
+
:box_url => @box_url,
|
74
|
+
:box_name => @box_name,
|
75
|
+
:run_list => @run_list,
|
76
|
+
:node_name => @node_name,
|
77
|
+
:chef_repo_dir => @chef_repo_dir,
|
78
|
+
:chef_json => @chef_json }
|
79
|
+
|
80
|
+
shell = DaptivChefCI::Shell.new()
|
81
|
+
vagrant = DaptivChefCI::VagrantDriver.new(shell, options)
|
82
|
+
|
83
|
+
vagrant.create_vagrantfile()
|
84
|
+
|
85
|
+
begin
|
86
|
+
vagrant.destroy()
|
87
|
+
rescue SystemExit => ex
|
88
|
+
exit(ex.status)
|
89
|
+
rescue Exception => ex
|
90
|
+
print_err(ex)
|
91
|
+
end
|
92
|
+
|
93
|
+
begin
|
94
|
+
vagrant.up()
|
95
|
+
rescue SystemExit => ex
|
96
|
+
exit(ex.status)
|
97
|
+
rescue Exception => ex
|
98
|
+
print_err(ex)
|
99
|
+
exit(1)
|
100
|
+
ensure
|
101
|
+
vagrant.halt()
|
102
|
+
vagrant.destroy()
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def print_err(ex)
|
109
|
+
STDERR.puts("#{ex.message} (#{ex.class})")
|
110
|
+
STDERR.puts(ex.backtrace.join("\n"))
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require_relative 'shell'
|
3
|
+
|
4
|
+
module DaptivChefCI
|
5
|
+
class VirtualBoxDriver
|
6
|
+
|
7
|
+
def initialize(shell)
|
8
|
+
@logger = Log4r::Logger.new("daptiv_chef_ci::virtual_box")
|
9
|
+
@shell = shell
|
10
|
+
end
|
11
|
+
|
12
|
+
# Remove any running vms that have the same name as this box
|
13
|
+
def cleanup_vms(box_name)
|
14
|
+
list_all_running_vms().each do |vm|
|
15
|
+
if vm.include?(box_name)
|
16
|
+
machine_name = vm.split[0]
|
17
|
+
@logger.debug("Found matching VBox #{machine_name} - Running")
|
18
|
+
poweroff(machine_name)
|
19
|
+
unregister(machine_name)
|
20
|
+
else
|
21
|
+
@logger.debug("Found no matching VBox #{machine_name}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Power off the named virtual box
|
30
|
+
def poweroff(machine_name)
|
31
|
+
@logger.info("Powering off VM: #{machine_name}")
|
32
|
+
@shell.exec_cmd("vboxmanage controlvm #{machine_name} poweroff")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Unregister the virtual box. Must be powered off first.
|
36
|
+
def unregister(machine_name)
|
37
|
+
@logger.info("Unregistering VM: #{machine_name}")
|
38
|
+
@shell.exec_cmd("vboxmanage unregistervm #{machine_name}")
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get a list of running vms
|
42
|
+
def list_all_running_vms()
|
43
|
+
@logger.info("List running VMs")
|
44
|
+
@shell.exec_cmd('vboxmanage list runningvms') || ''
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mocha/api'
|
2
|
+
require 'daptiv-chef-ci/logger'
|
3
|
+
require 'log4r'
|
4
|
+
|
5
|
+
describe DaptivChefCI::Logger, :unit => true do
|
6
|
+
|
7
|
+
describe 'init' do
|
8
|
+
|
9
|
+
# get logging level before running any of these tests
|
10
|
+
before(:all) do
|
11
|
+
@chef_ci_log = ENV['CHEF_CI_LOG']
|
12
|
+
end
|
13
|
+
|
14
|
+
# reset logging back to starting state before this fixture
|
15
|
+
after(:all) do
|
16
|
+
ENV['CHEF_CI_LOG'] = @chef_ci_log
|
17
|
+
DaptivChefCI::Logger.init()
|
18
|
+
end
|
19
|
+
|
20
|
+
# reset logging back to default state before every test
|
21
|
+
before(:each) do
|
22
|
+
ENV['CHEF_CI_LOG'] = ''
|
23
|
+
DaptivChefCI::Logger.init()
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should initialize logging to error by default' do
|
27
|
+
DaptivChefCI::Logger.init()
|
28
|
+
logger = Log4r::Logger.new("daptiv_chef_ci::logger_spec")
|
29
|
+
expect(logger.level).to eq(4)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should initialize logging to the specified level' do
|
33
|
+
ENV['CHEF_CI_LOG'] = 'DEBUG'
|
34
|
+
DaptivChefCI::Logger.init()
|
35
|
+
logger = Log4r::Logger.new("daptiv_chef_ci::logger_spec")
|
36
|
+
expect(logger.level).to eq(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'mocha/api'
|
2
|
+
require 'daptiv-chef-ci/virtualbox_driver'
|
3
|
+
require 'daptiv-chef-ci/logger'
|
4
|
+
require 'bundler'
|
5
|
+
|
6
|
+
describe DaptivChefCI::Shell, :unit => true do
|
7
|
+
|
8
|
+
describe 'exec_cmd' do
|
9
|
+
|
10
|
+
it 'should split output by line' do
|
11
|
+
shell = DaptivChefCI::Shell.new()
|
12
|
+
out = shell.exec_cmd('ls -l')
|
13
|
+
expect(out.count).to be > 1
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should revert path when method returns' do
|
17
|
+
path_before = ENV['PATH']
|
18
|
+
shell = DaptivChefCI::Shell.new()
|
19
|
+
shell.exec_cmd('ls -l')
|
20
|
+
expect(ENV['PATH']).to eq(path_before)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'path_without_gem_dir' do
|
26
|
+
|
27
|
+
it 'should not be prefixed by the system gem dir' do
|
28
|
+
shell = DaptivChefCI::Shell.new()
|
29
|
+
path = shell.path_without_gem_dir()
|
30
|
+
expect(path).not_to include(Bundler.bundle_path.to_s())
|
31
|
+
expect(ENV['PATH']).to include(path)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'mocha/api'
|
2
|
+
require 'daptiv-chef-ci/vagrant_driver'
|
3
|
+
require 'daptiv-chef-ci/logger'
|
4
|
+
|
5
|
+
describe DaptivChefCI::VagrantDriver, :unit => true do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@shell = mock()
|
9
|
+
@options = {}
|
10
|
+
@vagrant = DaptivChefCI::VagrantDriver.new(@shell, @options)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'render_vagrantfile' do
|
14
|
+
it 'should default chef-repo dir to ~/src/chef-repo' do
|
15
|
+
vagrantfile = @vagrant.render_vagrantfile()
|
16
|
+
expect(vagrantfile).to include("chef_repo_dir = '#{ENV['HOME']}/src/chef-repo'")
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should not include box url when not set' do
|
20
|
+
vagrantfile = @vagrant.render_vagrantfile()
|
21
|
+
expect(vagrantfile).not_to include("config.vm.box_url")
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should include box url when set' do
|
25
|
+
@options[:box_url] = 'http://example.com/boxes/freebsd.box'
|
26
|
+
vagrantfile = @vagrant.render_vagrantfile()
|
27
|
+
expect(vagrantfile).to include("config.vm.box_url = 'http://example.com/boxes/freebsd.box'")
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should include windows section when guest is set to windows' do
|
31
|
+
@options[:guest_os] = :windows
|
32
|
+
vagrantfile = @vagrant.render_vagrantfile()
|
33
|
+
expect(vagrantfile).to include('config.vm.guest = :windows')
|
34
|
+
expect(vagrantfile).to include('config.windows.halt_timeout = 15')
|
35
|
+
expect(vagrantfile).to include('config.winrm.username = "vagrant"')
|
36
|
+
expect(vagrantfile).to include('config.winrm.password = "vagrant"')
|
37
|
+
expect(vagrantfile).to include('config.vm.network :forwarded_port, guest: 5985, host: 5985')
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should expand runlist' do
|
41
|
+
@options[:run_list] = ['python', 'nginx']
|
42
|
+
vagrantfile = @vagrant.render_vagrantfile()
|
43
|
+
expect(vagrantfile).to include("chef.add_recipe 'python'")
|
44
|
+
expect(vagrantfile).to include("chef.add_recipe 'nginx'")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'destroy' do
|
49
|
+
it 'should force shutdown vagrant' do
|
50
|
+
@shell.expects(:exec_cmd).with do |cmd|
|
51
|
+
expect(cmd).to eq('vagrant destroy -f')
|
52
|
+
end
|
53
|
+
@vagrant.destroy()
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'halt' do
|
58
|
+
it 'should halt vagrant' do
|
59
|
+
@shell.expects(:exec_cmd).with do |cmd|
|
60
|
+
expect(cmd).to eq('vagrant halt')
|
61
|
+
end
|
62
|
+
@vagrant.halt()
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'up' do
|
67
|
+
it 'should up vagrant' do
|
68
|
+
@shell.expects(:exec_cmd).with do |cmd|
|
69
|
+
expect(cmd).to eq('vagrant up')
|
70
|
+
end
|
71
|
+
@vagrant.up()
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'provision' do
|
76
|
+
it 'should provision vagrant' do
|
77
|
+
@shell.expects(:exec_cmd).with do |cmd|
|
78
|
+
expect(cmd).to eq('vagrant provision')
|
79
|
+
end
|
80
|
+
@vagrant.provision()
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'reload' do
|
85
|
+
it 'should reload vagrant' do
|
86
|
+
@shell.expects(:exec_cmd).with do |cmd|
|
87
|
+
expect(cmd).to eq('vagrant reload')
|
88
|
+
end
|
89
|
+
@vagrant.reload()
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'mocha/api'
|
2
|
+
require 'daptiv-chef-ci/virtualbox_driver'
|
3
|
+
require 'daptiv-chef-ci/logger'
|
4
|
+
|
5
|
+
describe DaptivChefCI::VirtualBoxDriver, :unit => true do
|
6
|
+
|
7
|
+
describe 'cleanup_vms' do
|
8
|
+
it 'should poweroff and unregister all machines with a matching name' do
|
9
|
+
boxes = [
|
10
|
+
'"aspnet_1372120179" {b1937a1c-c6c4-4777-88d0-dfa9066fb126}',
|
11
|
+
'"aspnet_1379346156" {7bb1bbce-c6cc-47a2-9c51-57ede42e02b5}',
|
12
|
+
'"python_1372120178" {c1937a1c-c6c4-4777-88d0-dfa9066fb156}'
|
13
|
+
]
|
14
|
+
@shell = mock()
|
15
|
+
@vbox = DaptivChefCI::VirtualBoxDriver.new(@shell)
|
16
|
+
|
17
|
+
@shell.expects(:exec_cmd).with('vboxmanage list runningvms').returns(boxes)
|
18
|
+
|
19
|
+
@shell.expects(:exec_cmd).with('vboxmanage controlvm "aspnet_1372120179" poweroff').once()
|
20
|
+
@shell.expects(:exec_cmd).with('vboxmanage unregistervm "aspnet_1372120179"').once()
|
21
|
+
|
22
|
+
@shell.expects(:exec_cmd).with('vboxmanage controlvm "aspnet_1379346156" poweroff').once()
|
23
|
+
@shell.expects(:exec_cmd).with('vboxmanage unregistervm "aspnet_1379346156"').once()
|
24
|
+
|
25
|
+
@shell.expects(:exec_cmd).with('vboxmanage controlvm "python_1372120178" poweroff').never()
|
26
|
+
@shell.expects(:exec_cmd).with('vboxmanage unregistervm "python_1372120178"').never()
|
27
|
+
|
28
|
+
@vbox.cleanup_vms('aspnet')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: daptiv-chef-ci
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Shawn Neal
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mixlib-shellout
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.2.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: log4r
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.1.10
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.1.10
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: erubis
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.7.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.7.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec-core
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 2.12.2
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 2.12.2
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec-expectations
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.12.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.12.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec-mocks
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.12.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 2.12.1
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: simplecov
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: mocha
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.14.0
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 0.14.0
|
158
|
+
description: Vagrant automation for CI
|
159
|
+
email:
|
160
|
+
- sneal@daptiv.com
|
161
|
+
executables: []
|
162
|
+
extensions: []
|
163
|
+
extra_rdoc_files: []
|
164
|
+
files:
|
165
|
+
- daptiv-chef-ci.gemspec
|
166
|
+
- Gemfile
|
167
|
+
- lib/daptiv-chef-ci/logger.rb
|
168
|
+
- lib/daptiv-chef-ci/shell.rb
|
169
|
+
- lib/daptiv-chef-ci/templates/Vagrantfile.erb
|
170
|
+
- lib/daptiv-chef-ci/vagrant_driver.rb
|
171
|
+
- lib/daptiv-chef-ci/vagrant_task.rb
|
172
|
+
- lib/daptiv-chef-ci/virtualbox_driver.rb
|
173
|
+
- pkg/daptiv-chef-ci-0.0.1.gem
|
174
|
+
- Rakefile
|
175
|
+
- README.md
|
176
|
+
- spec/daptiv-chef-ci/logger_spec.rb
|
177
|
+
- spec/daptiv-chef-ci/shell_spec.rb
|
178
|
+
- spec/daptiv-chef-ci/vagrant_driver_spec.rb
|
179
|
+
- spec/daptiv-chef-ci/virtualbox_driver_spec.rb
|
180
|
+
- .gitignore
|
181
|
+
homepage: ''
|
182
|
+
licenses: []
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
require_paths:
|
186
|
+
- lib
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
188
|
+
none: false
|
189
|
+
requirements:
|
190
|
+
- - ! '>='
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
segments:
|
194
|
+
- 0
|
195
|
+
hash: -2620113271490867274
|
196
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
|
+
none: false
|
198
|
+
requirements:
|
199
|
+
- - ! '>='
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
segments:
|
203
|
+
- 0
|
204
|
+
hash: -2620113271490867274
|
205
|
+
requirements: []
|
206
|
+
rubyforge_project:
|
207
|
+
rubygems_version: 1.8.23
|
208
|
+
signing_key:
|
209
|
+
specification_version: 3
|
210
|
+
summary: A small gem to reduce Rake duplication
|
211
|
+
test_files:
|
212
|
+
- spec/daptiv-chef-ci/logger_spec.rb
|
213
|
+
- spec/daptiv-chef-ci/shell_spec.rb
|
214
|
+
- spec/daptiv-chef-ci/vagrant_driver_spec.rb
|
215
|
+
- spec/daptiv-chef-ci/virtualbox_driver_spec.rb
|