daptiv-chef-ci 0.0.15 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/daptiv-chef-ci.gemspec +21 -20
- data/lib/daptiv-chef-ci/clone_environment_task.rb +69 -0
- data/lib/daptiv-chef-ci/logger.rb +9 -10
- data/lib/daptiv-chef-ci/raketask_helper.rb +5 -6
- data/lib/daptiv-chef-ci/shell.rb +50 -28
- data/lib/daptiv-chef-ci/upload_cookbook_task.rb +62 -0
- data/lib/daptiv-chef-ci/vagrant_destroy_task.rb +11 -12
- data/lib/daptiv-chef-ci/vagrant_driver.rb +47 -56
- data/lib/daptiv-chef-ci/vagrant_provision_task.rb +12 -15
- data/lib/daptiv-chef-ci/vagrant_task.rb +34 -57
- data/lib/daptiv-chef-ci/vagrant_up_task.rb +14 -16
- data/lib/daptiv-chef-ci/version_cookbook_task.rb +69 -0
- data/lib/daptiv-chef-ci/virtualbox_driver.rb +11 -12
- data/spec/daptiv-chef-ci/logger_spec.rb +11 -15
- data/spec/daptiv-chef-ci/shell_spec.rb +23 -27
- data/spec/daptiv-chef-ci/vagrant_destroy_task_spec.rb +5 -7
- data/spec/daptiv-chef-ci/vagrant_driver_spec.rb +34 -72
- data/spec/daptiv-chef-ci/vagrant_provision_task_spec.rb +9 -13
- data/spec/daptiv-chef-ci/vagrant_task_spec.rb +29 -21
- data/spec/daptiv-chef-ci/vagrant_up_task_spec.rb +9 -12
- data/spec/daptiv-chef-ci/virtualbox_driver_spec.rb +21 -16
- data/spec/shared_contexts/rake.rb +7 -7
- metadata +21 -14
- data/lib/daptiv-chef-ci/basebox_builder_factory.rb +0 -19
- data/lib/daptiv-chef-ci/virtualbox_basebox_builder.rb +0 -33
- data/lib/daptiv-chef-ci/vmware_basebox_builder.rb +0 -103
- data/spec/daptiv-chef-ci/basebox_builder_factory_spec.rb +0 -25
- data/spec/daptiv-chef-ci/virtualbox_basebox_builder_spec.rb +0 -20
- data/spec/daptiv-chef-ci/vmware_basebox_builder_spec.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfeeac6ae1094f6d486f92af9fca0fc1a1915ec9
|
4
|
+
data.tar.gz: 489147267747924a25c9e1f6e350881f01996a35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5707f54b532a6299e7f446add8ceaef337840207d337190cd8a7c9772e7e87362cbf922ee7f92342506d015459fa9d30f9601def5dee61ba93d1d8450eb5374b
|
7
|
+
data.tar.gz: 41db757953a4c6ce7100eff2217719354d71667763367b4969acb1d87e344f904c56ac0e7bd98759f1358c514df8d146ac37bb8d5e6f82be7ab213089f5b4b0f
|
data/daptiv-chef-ci.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
|
-
gem.authors = [
|
5
|
-
gem.email = [
|
6
|
-
gem.description =
|
7
|
-
gem.summary =
|
8
|
-
gem.homepage =
|
4
|
+
gem.authors = ['Shawn Neal']
|
5
|
+
gem.email = ['sneal@daptiv.com']
|
6
|
+
gem.description = 'Vagrant automation for CI'
|
7
|
+
gem.summary = 'A small gem to reduce Rake duplication'
|
8
|
+
gem.homepage = ''
|
9
9
|
|
10
10
|
# The following block of code determines the files that should be included
|
11
11
|
# in the gem. It does this by reading all the files in the directory where
|
@@ -13,9 +13,9 @@ Gem::Specification.new do |gem|
|
|
13
13
|
# Note that the entire gitignore(5) syntax is not supported, specifically
|
14
14
|
# the "!" syntax, but it should mostly work correctly.
|
15
15
|
root_path = File.dirname(__FILE__)
|
16
|
-
all_files = Dir.chdir(root_path) { Dir.glob(
|
17
|
-
all_files.reject! { |file| [
|
18
|
-
gitignore_path = File.join(root_path,
|
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
19
|
gitignore = File.readlines(gitignore_path)
|
20
20
|
gitignore.map! { |line| line.chomp.strip }
|
21
21
|
gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
|
@@ -34,22 +34,23 @@ Gem::Specification.new do |gem|
|
|
34
34
|
#
|
35
35
|
gitignore.any? do |ignore|
|
36
36
|
File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
|
37
|
-
|
37
|
+
File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
gem.files = unignored_files
|
42
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
42
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
43
43
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
44
|
-
gem.name =
|
45
|
-
gem.require_paths = [
|
46
|
-
gem.version = '0.0
|
47
|
-
|
48
|
-
gem.add_runtime_dependency "log4r", "~> 1.1.10"
|
49
|
-
gem.add_runtime_dependency "mixlib-shellout", "~> 1.6.0"
|
44
|
+
gem.name = 'daptiv-chef-ci'
|
45
|
+
gem.require_paths = ['lib']
|
46
|
+
gem.version = '0.1.0'
|
50
47
|
|
51
|
-
gem.
|
52
|
-
gem.
|
53
|
-
gem.
|
54
|
-
|
48
|
+
gem.add_runtime_dependency 'log4r', '~> 1.1.10'
|
49
|
+
gem.add_runtime_dependency 'mixlib-shellout', '~> 1.2'
|
50
|
+
gem.add_runtime_dependency 'versionomy', '~> 0.4.4'
|
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'
|
55
56
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'rake/dsl_definition'
|
4
|
+
require 'json'
|
5
|
+
require 'tempfile'
|
6
|
+
require_relative 'raketask_helper'
|
7
|
+
require_relative 'shell'
|
8
|
+
|
9
|
+
class CloneEnvironment
|
10
|
+
# Example usage, copies a Chef environment definition to another
|
11
|
+
# environment.
|
12
|
+
#
|
13
|
+
# CloneEnvironment::RakeTask.new do |t|
|
14
|
+
# t.src_env = 'dev'
|
15
|
+
# t.dest_env = "vagrant-#{ENV['LOGNAME']}-dotnetframework"
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# This class lets you define Rake tasks to clone Chef environments.
|
19
|
+
class RakeTask < ::Rake::TaskLib
|
20
|
+
include ::Rake::DSL if defined? ::Rake::DSL
|
21
|
+
include DaptivChefCI::RakeTaskHelpers
|
22
|
+
|
23
|
+
attr_accessor :src_env
|
24
|
+
attr_accessor :dest_env
|
25
|
+
|
26
|
+
# @param [String] name The task name.
|
27
|
+
# @param [String] desc Description of the task.
|
28
|
+
def initialize(name = 'clone_environment', desc = 'Clone environment task')
|
29
|
+
@logger = Log4r::Logger.new('daptiv_chef_ci::clone_environment_task')
|
30
|
+
@shell = DaptivChefCI::Shell.new
|
31
|
+
@name, @desc = name, desc
|
32
|
+
yield self if block_given?
|
33
|
+
define_task
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def define_task
|
39
|
+
desc @desc
|
40
|
+
task @name do
|
41
|
+
execute do
|
42
|
+
fail 'src_env must be specified' unless @src_env
|
43
|
+
fail 'dest_env must be specified' unless @dest_env
|
44
|
+
clone_environment
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def clone_environment
|
50
|
+
out = @shell.exec_cmd_in_context(
|
51
|
+
"knife environment show #{@src_env} -F json").join(' ')
|
52
|
+
|
53
|
+
env = JSON.parse(out)
|
54
|
+
env['name'] = @dest_env
|
55
|
+
env['description'] = "The #{dest_env} environment"
|
56
|
+
|
57
|
+
env_file = Tempfile.new([@dest_env, '.json'])
|
58
|
+
begin
|
59
|
+
IO.write(env_file.path, JSON.pretty_generate(env))
|
60
|
+
|
61
|
+
@shell.exec_cmd_in_context(
|
62
|
+
"knife environment from file '#{env_file.path}'")
|
63
|
+
ensure
|
64
|
+
env_file.close
|
65
|
+
env_file.unlink
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,35 +1,34 @@
|
|
1
1
|
module DaptivChefCI
|
2
|
+
# Chef CI logger class
|
2
3
|
class Logger
|
3
|
-
|
4
4
|
# Initializes and enables logging to the given environments level
|
5
5
|
# By default logging only occurs at ERROR level or higher.
|
6
6
|
# Set CHEF_CI_LOG env var to change logging levels
|
7
|
-
def self.init
|
7
|
+
def self.init
|
8
8
|
require 'log4r'
|
9
|
-
|
9
|
+
|
10
10
|
# Set the logging level on all "chef-ci" namespaced
|
11
11
|
# logs as long as we have a valid level.
|
12
|
-
logger = Log4r::Logger.new(
|
12
|
+
logger = Log4r::Logger.new('daptiv_chef_ci')
|
13
13
|
logger.outputters = Log4r::Outputter.stderr
|
14
|
-
logger.level = log_level
|
14
|
+
logger.level = log_level
|
15
15
|
logger = nil
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
# LogLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']
|
19
19
|
# DEBUG = 1
|
20
20
|
# INFO = 2
|
21
21
|
# WARN = 3
|
22
22
|
# ERROR = 4
|
23
23
|
# FATAL = 5
|
24
|
-
def self.log_level
|
25
|
-
level = ENV['CHEF_CI_LOG'].upcase
|
24
|
+
def self.log_level
|
25
|
+
level = ENV['CHEF_CI_LOG'].upcase.to_s
|
26
26
|
level_i = Log4r::Log4rConfig::LogLevels.index(level)
|
27
27
|
level_i + 1
|
28
28
|
rescue
|
29
29
|
return 2 # info
|
30
30
|
end
|
31
|
-
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
DaptivChefCI::Logger.init
|
34
|
+
DaptivChefCI::Logger.init
|
@@ -1,17 +1,17 @@
|
|
1
1
|
module DaptivChefCI
|
2
2
|
module RakeTaskHelpers
|
3
3
|
extend self
|
4
|
-
|
4
|
+
|
5
5
|
@@exit_on_failure = true
|
6
|
-
|
6
|
+
|
7
7
|
def exit_on_failure
|
8
8
|
@@exit_on_failure
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def exit_on_failure=(exit_on_failure)
|
12
12
|
@@exit_on_failure = exit_on_failure
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def execute(&block)
|
16
16
|
begin
|
17
17
|
block.call()
|
@@ -31,6 +31,5 @@ module DaptivChefCI
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
35
34
|
end
|
36
|
-
end
|
35
|
+
end
|
data/lib/daptiv-chef-ci/shell.rb
CHANGED
@@ -3,61 +3,83 @@ require 'bundler'
|
|
3
3
|
require 'mixlib/shellout'
|
4
4
|
|
5
5
|
module DaptivChefCI
|
6
|
+
# Command shell wrapper
|
6
7
|
class Shell
|
7
|
-
|
8
|
-
|
9
|
-
@logger = Log4r::Logger.new("daptiv_chef_ci::shell")
|
8
|
+
def initialize
|
9
|
+
@logger = Log4r::Logger.new('daptiv_chef_ci::shell')
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
# Executes the specified shell command and returns the stdout.
|
13
13
|
#
|
14
14
|
# This method ensure that any invoked command use the same PATH environment
|
15
15
|
# that the user has outside Ruby/Bundler.
|
16
16
|
#
|
17
17
|
# @param [String] The command line to execute
|
18
|
-
# @param [Int] The number of seconds to wait for the command to finish,
|
19
|
-
#
|
18
|
+
# @param [Int] The number of seconds to wait for the command to finish,
|
19
|
+
# defaults to 600
|
20
|
+
# @param [Hash] Key value pairs of environment variables to pass to the
|
21
|
+
# command's environment.
|
20
22
|
# @return [Array] Each entry represents a line from the stdout
|
21
|
-
def
|
23
|
+
def exec_cmd_in_context(command, timeout = nil, environment = {})
|
22
24
|
timeout ||= 600
|
23
25
|
environment = Hash[ environment.map{ |k, v| [k.to_s, v.to_s] } ]
|
24
|
-
environment['LC_ALL'] = ENV['LC_ALL']
|
26
|
+
environment['LC_ALL'] = ENV['LC_ALL'] unless environment.key?('LC_ALL')
|
27
|
+
|
28
|
+
@logger.info("Executing: '#{command}'")
|
29
|
+
@logger.debug("\n\ttimeout: #{timeout}\n\tenvironment: #{environment}")
|
30
|
+
|
31
|
+
shell_out = Mixlib::ShellOut.new(
|
32
|
+
command, timeout: timeout, environment: environment)
|
33
|
+
shell_out.live_stream = STDOUT
|
34
|
+
|
35
|
+
shell_out.run_command
|
36
|
+
shell_out.invalid! if shell_out.exitstatus != 0
|
37
|
+
@logger.info(shell_out.stdout)
|
38
|
+
shell_out.stdout.split("\n")
|
39
|
+
end
|
40
|
+
|
41
|
+
# Executes the specified shell command and returns the stdout.
|
42
|
+
#
|
43
|
+
# This method ensure that any invoked command use the same PATH environment
|
44
|
+
# that the user has outside Ruby/Bundler.
|
45
|
+
#
|
46
|
+
# @param [String] The command line to execute
|
47
|
+
# @param [Int] The number of seconds to wait for the command to finish,
|
48
|
+
# defaults to 600
|
49
|
+
# @param [Hash] Key value pairs of environment variables to pass to the
|
50
|
+
# command's environment.
|
51
|
+
# @return [Array] Each entry represents a line from the stdout
|
52
|
+
def exec_cmd(command, timeout = nil, environment = {})
|
25
53
|
path_at_start = ENV['PATH']
|
26
54
|
begin
|
27
|
-
ENV['PATH'] = path_without_gem_dir
|
28
|
-
@logger.debug("
|
29
|
-
|
30
|
-
@logger.info("Executing: '#{command}'\n\ttimeout: #{timeout}\n\tenvironment: #{environment}")
|
31
|
-
shell_out = Mixlib::ShellOut.new(command, :timeout => timeout, :environment => environment)
|
32
|
-
shell_out.run_command()
|
33
|
-
shell_out.invalid! if shell_out.exitstatus != 0
|
34
|
-
|
35
|
-
@logger.info(shell_out.stdout)
|
36
|
-
shell_out.stdout.split("\n")
|
55
|
+
ENV['PATH'] = path_without_gem_dir
|
56
|
+
@logger.debug("Setting PATH: #{ENV['PATH']}")
|
57
|
+
exec_cmd_in_context(command, timeout, environment)
|
37
58
|
ensure
|
38
59
|
@logger.debug("Resetting PATH: #{path_at_start}")
|
39
60
|
ENV['PATH'] = path_at_start
|
40
61
|
end
|
41
62
|
end
|
42
|
-
|
63
|
+
|
43
64
|
# Returns the PATH environment variable as it was before Bundler prepended
|
44
65
|
# the system gem directory to it.
|
45
66
|
#
|
46
|
-
# This can happen if the user has invoked "require 'bundler/setup'"
|
47
|
-
# like in this gems Rakefile.
|
67
|
+
# This can happen if the user has invoked "require 'bundler/setup'"
|
68
|
+
# somewhere, like in this gems Rakefile.
|
48
69
|
#
|
49
|
-
# This is needed because sometimes a user will have the Vagrant gem
|
50
|
-
# on their system and we don't want to use it, we should use the
|
51
|
-
# their PATH as if they invoked vagrant themselves
|
70
|
+
# This is needed because sometimes a user will have the Vagrant gem
|
71
|
+
# installed on their system and we don't want to use it, we should use the
|
72
|
+
# one that's in their PATH as if they invoked vagrant themselves
|
73
|
+
# (i.e. the installed version)
|
52
74
|
#
|
53
|
-
# @return [String] The ENV['PATH] without the Bundler system gem dir
|
75
|
+
# @return [String] The ENV['PATH] without the Bundler system gem dir
|
76
|
+
# prepended
|
54
77
|
def path_without_gem_dir
|
55
78
|
paths = ENV['PATH'].split(':')
|
56
79
|
system_gem_dir = "#{Bundler.bundle_path}/bin"
|
57
80
|
@logger.debug("System gem dir: #{system_gem_dir}")
|
58
|
-
paths.delete_if { |p| p.downcase
|
81
|
+
paths.delete_if { |p| p.downcase == system_gem_dir.downcase }
|
59
82
|
paths.join(':')
|
60
83
|
end
|
61
|
-
|
62
84
|
end
|
63
|
-
end
|
85
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'rake/dsl_definition'
|
4
|
+
require_relative 'raketask_helper'
|
5
|
+
require_relative 'shell'
|
6
|
+
|
7
|
+
class UploadCookbook
|
8
|
+
# Example usage, uploads the current cookbook to the Chef server freezing
|
9
|
+
# it to the Canary environment.
|
10
|
+
#
|
11
|
+
# UploadCookbook::RakeTask.new do |t|
|
12
|
+
# t.environment = 'canary'
|
13
|
+
# t.freeze = true
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# This class lets you define Rake tasks to upload cookbooks to Chef.
|
17
|
+
class RakeTask < ::Rake::TaskLib
|
18
|
+
include ::Rake::DSL if defined? ::Rake::DSL
|
19
|
+
include DaptivChefCI::RakeTaskHelpers
|
20
|
+
|
21
|
+
attr_accessor :environment
|
22
|
+
attr_accessor :freeze
|
23
|
+
|
24
|
+
# @param [String] name The task name.
|
25
|
+
# @param [String] desc Description of the task.
|
26
|
+
def initialize(name = 'upload_cookbook', desc = 'Upload cookbook task')
|
27
|
+
@logger = Log4r::Logger.new('daptiv_chef_ci::upload_cookbook_task')
|
28
|
+
@shell = DaptivChefCI::Shell.new
|
29
|
+
@name, @desc = name, desc
|
30
|
+
@freeze = false
|
31
|
+
yield self if block_given?
|
32
|
+
define_task
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def define_task
|
38
|
+
desc @desc
|
39
|
+
task @name do
|
40
|
+
execute do
|
41
|
+
upload_cookbook
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def upload_cookbook
|
47
|
+
cmd = "knife cookbook upload #{cookbook_name} -o ../"
|
48
|
+
cmd << " -E #{environment}" if @environment
|
49
|
+
@shell.exec_cmd_in_context(cmd)
|
50
|
+
end
|
51
|
+
|
52
|
+
def cookbook_name
|
53
|
+
unless @cookbook_name
|
54
|
+
metadata = IO.read(File.join(Dir.pwd, 'metadata.rb'))
|
55
|
+
@cookbook_name = /name\s+['|"](\w+)/.match(metadata)[1]
|
56
|
+
fail 'Cannot find cookbook name in metadata.rb' unless @cookbook_name
|
57
|
+
@logger.debug("found cookbook name: #{@cookbook_name}")
|
58
|
+
end
|
59
|
+
@cookbook_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -6,7 +6,6 @@ require_relative 'raketask_helper'
|
|
6
6
|
require_relative 'logger'
|
7
7
|
|
8
8
|
class VagrantDestroy
|
9
|
-
|
10
9
|
# Example usage, destroys a Vagrant box.
|
11
10
|
#
|
12
11
|
# VagrantUp::RakeTask.new 'up' do |t|
|
@@ -17,11 +16,11 @@ class VagrantDestroy
|
|
17
16
|
class RakeTask < ::Rake::TaskLib
|
18
17
|
include ::Rake::DSL if defined? ::Rake::DSL
|
19
18
|
include DaptivChefCI::RakeTaskHelpers
|
20
|
-
|
19
|
+
|
21
20
|
attr_accessor :vagrant_driver
|
22
21
|
attr_accessor :destroy_timeout_in_seconds
|
23
22
|
attr_accessor :environment
|
24
|
-
|
23
|
+
|
25
24
|
# @param [String] name The task name.
|
26
25
|
# @param [String] desc Description of the task.
|
27
26
|
def initialize(name = 'vagrant_destroy', desc = 'Vagrant destroy task')
|
@@ -31,22 +30,22 @@ class VagrantDestroy
|
|
31
30
|
yield self if block_given?
|
32
31
|
define_task
|
33
32
|
end
|
34
|
-
|
33
|
+
|
35
34
|
private
|
36
35
|
|
37
36
|
def define_task
|
38
37
|
desc @desc
|
39
38
|
task @name do
|
40
|
-
execute
|
41
|
-
|
42
|
-
:
|
39
|
+
execute do
|
40
|
+
vagrant_driver.destroy(
|
41
|
+
cmd_timeout_in_seconds: @destroy_timeout_in_seconds,
|
42
|
+
environment: @environment)
|
43
|
+
end
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
|
-
def vagrant_driver()
|
47
|
-
@vagrant_driver ||= DaptivChefCI::VagrantDriver.new()
|
48
|
-
end
|
49
46
|
|
47
|
+
def vagrant_driver
|
48
|
+
@vagrant_driver ||= DaptivChefCI::VagrantDriver.new
|
49
|
+
end
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|