souschef 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +177 -0
- data/Rakefile +1 -0
- data/bin/souschef +33 -0
- data/data/chefspec/chefspec.erb +6 -0
- data/data/chefspec/spec_helper.rb +8 -0
- data/data/gemfile.yml +23 -0
- data/data/license.erb +3 -0
- data/data/metadata.erb +7 -0
- data/data/rakefile.erb +39 -0
- data/data/readme.erb +47 -0
- data/data/recipe/recipe.erb +6 -0
- data/data/rubocop/rubocop.yml +19 -0
- data/data/serverspec/serverspec.erb +2 -0
- data/data/serverspec/serverspec_helper.rb +10 -0
- data/data/testkitchen/kitchen.default.erb +22 -0
- data/lib/souschef.rb +16 -0
- data/lib/souschef/berkshelf.rb +93 -0
- data/lib/souschef/config.rb +20 -0
- data/lib/souschef/configure/file.rb +46 -0
- data/lib/souschef/gemfile.rb +42 -0
- data/lib/souschef/print.rb +40 -0
- data/lib/souschef/runner.rb +104 -0
- data/lib/souschef/scaffold.rb +145 -0
- data/lib/souschef/template.rb +26 -0
- data/lib/souschef/template/base.rb +69 -0
- data/lib/souschef/template/chefspec.rb +26 -0
- data/lib/souschef/template/license.rb +25 -0
- data/lib/souschef/template/metadata.rb +30 -0
- data/lib/souschef/template/rakefile.rb +23 -0
- data/lib/souschef/template/readme.rb +24 -0
- data/lib/souschef/template/rubocop.rb +22 -0
- data/lib/souschef/template/serverspec.rb +27 -0
- data/lib/souschef/testkitchen.rb +135 -0
- data/lib/souschef/testkitchen/docker.rb +97 -0
- data/lib/souschef/testkitchen/solusvm.rb +101 -0
- data/lib/souschef/testkitchen/virtualbox.rb +66 -0
- data/lib/souschef/version.rb +4 -0
- data/souschef.gemspec +33 -0
- metadata +254 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
---
|
2
|
+
driver:
|
3
|
+
name: vagrant
|
4
|
+
customize:
|
5
|
+
memory: 1024
|
6
|
+
|
7
|
+
provisioner:
|
8
|
+
name: chef_zero
|
9
|
+
require_chef_omnibus: latest
|
10
|
+
|
11
|
+
platforms:
|
12
|
+
- name: centos-5.10
|
13
|
+
driver_config:
|
14
|
+
box: centos-5.10-min-x86_64
|
15
|
+
- name: centos-6.4
|
16
|
+
driver_config:
|
17
|
+
box: centos-6.5-x86_64
|
18
|
+
suites:
|
19
|
+
- name: default
|
20
|
+
run_list:
|
21
|
+
- recipe[<%= @cookbook %>::default]
|
22
|
+
attributes:
|
data/lib/souschef.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
require 'open3'
|
4
|
+
require 'trollop'
|
5
|
+
require 'colorize'
|
6
|
+
require 'ruth'
|
7
|
+
require 'souschef/runner'
|
8
|
+
require 'souschef/configure/file'
|
9
|
+
require 'souschef/config'
|
10
|
+
require 'souschef/berkshelf'
|
11
|
+
require 'souschef/scaffold'
|
12
|
+
require 'souschef/gemfile'
|
13
|
+
require 'souschef/testkitchen'
|
14
|
+
require 'souschef/template'
|
15
|
+
require 'souschef/print'
|
16
|
+
require 'souschef/version'
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Souschef
|
2
|
+
# Includes slave functions that do all the work
|
3
|
+
class Berkshelf
|
4
|
+
attr_accessor :opts, :cookbook_dir
|
5
|
+
|
6
|
+
def initialize(opts)
|
7
|
+
@opts = opts
|
8
|
+
end
|
9
|
+
|
10
|
+
# Public - Tell Berkshelf to create a cookbook
|
11
|
+
#
|
12
|
+
# Returns nil
|
13
|
+
def berks_create
|
14
|
+
remove_old_readme
|
15
|
+
Souschef::Print.info 'Creating cookbook structure' if @opts[:verbose]
|
16
|
+
|
17
|
+
i, o, e, w = Open3.popen3(berks_cmd)
|
18
|
+
print_open3_stdout(o) if @opts[:verbose]
|
19
|
+
remove_vagrantfile
|
20
|
+
print_open3_stdout(e)
|
21
|
+
i.close
|
22
|
+
fail 'Berks failed' unless w.value == 0
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Private - Returns berkshelf command depending on the path
|
28
|
+
#
|
29
|
+
# Returns String
|
30
|
+
def berks_cmd
|
31
|
+
if @opts[:path] == Dir.pwd
|
32
|
+
"#{which_berks} cookbook #{@opts[:cookbook]} ."
|
33
|
+
else
|
34
|
+
path = @opts[:path].gsub("#{Dir.pwd}/", '')
|
35
|
+
"#{which_berks} cookbook #{@opts[:cookbook]} #{path}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Private - Remove README from cookbook dir
|
40
|
+
#
|
41
|
+
# Returns nil
|
42
|
+
def remove_old_readme
|
43
|
+
readme = File.join(@opts[:path], 'README.md')
|
44
|
+
File.delete(readme) if File.exist?(readme)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Private - Remove README from cookbook dir
|
48
|
+
#
|
49
|
+
# Returns nil
|
50
|
+
def remove_vagrantfile
|
51
|
+
vagrantfile = File.join(@opts[:path], 'Vagrantfile')
|
52
|
+
File.delete(vagrantfile) if File.exist?(vagrantfile)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Private - Obtain berks executable full path
|
56
|
+
#
|
57
|
+
# Returns String
|
58
|
+
def which_berks
|
59
|
+
i, o, e, w = Open3.popen3('which berks')
|
60
|
+
fail 'berks executable not found on system' if w.value.to_i > 0
|
61
|
+
i.close
|
62
|
+
e.close
|
63
|
+
o.read.chomp
|
64
|
+
end
|
65
|
+
|
66
|
+
# Private - Print out Open3 STDOUT stream
|
67
|
+
#
|
68
|
+
# stdout - Open3 stdout stream
|
69
|
+
#
|
70
|
+
# Return nil
|
71
|
+
def print_open3_stdout(stdout)
|
72
|
+
stdout.read.split("\n").each { |msg| puts msg.colorize(:green) }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Private - Print out a colorized message
|
76
|
+
#
|
77
|
+
# msg - String message
|
78
|
+
#
|
79
|
+
# Returns nil
|
80
|
+
def colour(msg)
|
81
|
+
puts msg.colorize(:red)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Private - Print out info message
|
85
|
+
#
|
86
|
+
# msg - String message
|
87
|
+
#
|
88
|
+
# Returns nil
|
89
|
+
def info_msg(msg)
|
90
|
+
puts msg.colorize(:yellow)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Souschef
|
2
|
+
# Loads Souschef configuration YAML
|
3
|
+
class Config
|
4
|
+
# Public - Reads the configuration file
|
5
|
+
#
|
6
|
+
# Returns Hash
|
7
|
+
def self.read
|
8
|
+
verify_file
|
9
|
+
YAML.load_file(File.expand_path('~/.souschef.yml'))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Private - Checks if we have a configuraiton file
|
13
|
+
#
|
14
|
+
# Returns nil
|
15
|
+
def self.verify_file
|
16
|
+
conf = File.expand_path('~/.souschef.yml')
|
17
|
+
fail "'~/.souschef.yml' missing!" unless File.exist?(conf)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Souschef
|
2
|
+
class Configure
|
3
|
+
# Create Configuration file
|
4
|
+
class Yaml
|
5
|
+
attr_accessor :opts, :data
|
6
|
+
|
7
|
+
def initialize(opts)
|
8
|
+
@opts = opts
|
9
|
+
@souschef = File.expand_path('~/.souschef.yml')
|
10
|
+
read_configuration
|
11
|
+
add_values
|
12
|
+
write_configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Private - Add CLI passed data into the configuration
|
18
|
+
#
|
19
|
+
# Return nil
|
20
|
+
def add_values
|
21
|
+
@data[@opts[:profile]] = { maintainer: @opts[:maintainer],
|
22
|
+
maintainer_email: @opts[:maintainer_email],
|
23
|
+
license: @opts[:license] }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Private - Read configuration file, if it exists, otherwise define @data
|
27
|
+
# as a empty Hash
|
28
|
+
#
|
29
|
+
# Returns Hash
|
30
|
+
def read_configuration
|
31
|
+
if File.exist?(@souschef)
|
32
|
+
@data ||= YAML.load_file(@souschef)
|
33
|
+
else
|
34
|
+
@data = {}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Private - Write down configuration file
|
39
|
+
#
|
40
|
+
# Returns nil
|
41
|
+
def write_configuration
|
42
|
+
File.open(@souschef, 'w+') { |fd| fd.write(@data.to_yaml) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Souschef
|
2
|
+
# Gemfile generator
|
3
|
+
class Gemfile < Ruth::Gemfile::Yaml
|
4
|
+
attr_accessor :opts
|
5
|
+
|
6
|
+
def initialize(opts)
|
7
|
+
@opts = opts
|
8
|
+
super(yaml_file_location)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Public - Writes down the Gemfile location
|
12
|
+
#
|
13
|
+
# Returns nil
|
14
|
+
def write
|
15
|
+
Souschef::Print.info 'Populating Gemfile' if @opts[:verbose]
|
16
|
+
write_gemfile
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Private - Return location of YAML file
|
22
|
+
#
|
23
|
+
# Returns String
|
24
|
+
def yaml_file_location
|
25
|
+
File.expand_path('../../../data/gemfile.yml', __FILE__)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Private - Return location of Gemfile
|
29
|
+
#
|
30
|
+
# Returns string
|
31
|
+
def gemfile_location
|
32
|
+
File.join(@opts[:path], 'Gemfile')
|
33
|
+
end
|
34
|
+
|
35
|
+
# Private - Write Gemfile data
|
36
|
+
#
|
37
|
+
# Returns nil
|
38
|
+
def write_gemfile
|
39
|
+
File.open(gemfile_location, 'w') { |file| file.write(output) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Souschef
|
2
|
+
# Prit out colorized information
|
3
|
+
class Print
|
4
|
+
# Public - Print info messate
|
5
|
+
#
|
6
|
+
# msg - String message
|
7
|
+
#
|
8
|
+
# Returns nil
|
9
|
+
def self.info(msg)
|
10
|
+
puts "~> #{msg}".colorize(:green)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Public - Print header message
|
14
|
+
#
|
15
|
+
# msg - String message
|
16
|
+
#
|
17
|
+
# Returns nil
|
18
|
+
def self.header(msg)
|
19
|
+
puts "[*] #{msg}".colorize(:cyan)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public - Print error messate
|
23
|
+
#
|
24
|
+
# msg - String message
|
25
|
+
#
|
26
|
+
# Returns nil
|
27
|
+
def self.error(msg)
|
28
|
+
puts "#{msg}".colorize(:red)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public - Print warning messate
|
32
|
+
#
|
33
|
+
# msg - String message
|
34
|
+
#
|
35
|
+
# Returns nil
|
36
|
+
def self.warning(msg)
|
37
|
+
puts "#{msg}".colorize(:orange)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Souschef
|
2
|
+
# Runner library that does all the hard work
|
3
|
+
class Runner
|
4
|
+
attr_accessor :opts
|
5
|
+
|
6
|
+
def initialize(opts)
|
7
|
+
@opts = opts
|
8
|
+
adjust_cb_path
|
9
|
+
load_configuration unless @opts[:configure]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Public - Run Souschef
|
13
|
+
#
|
14
|
+
# Returns nil
|
15
|
+
def run
|
16
|
+
Souschef::Print.header "Using Souschef profile: #{opts[:profile]}"
|
17
|
+
|
18
|
+
if @opts[:scaffold]
|
19
|
+
Souschef::Scaffold.new(@opts).start
|
20
|
+
elsif @opts[:configure]
|
21
|
+
verify_configure_input
|
22
|
+
Souschef::Configure::Yaml.new(@opts)
|
23
|
+
else
|
24
|
+
Souschef::Print.header "Starting cookbook creation...\n"
|
25
|
+
cookbook_runlist
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Private - Create cookbook run list
|
32
|
+
#
|
33
|
+
# Returns nil
|
34
|
+
def cookbook_runlist
|
35
|
+
verify_cookbook_creation
|
36
|
+
|
37
|
+
Souschef::Print.header 'Berkshelf configuration'
|
38
|
+
Souschef::Berkshelf.new(@opts).berks_create
|
39
|
+
Souschef::Print.header 'Configure gemfile'
|
40
|
+
Souschef::Gemfile.new(@opts).write
|
41
|
+
Souschef::Print.header 'Create essential template files'
|
42
|
+
Souschef::Template.run(@opts)
|
43
|
+
# Mock Scaffold to generate default recipe and tests
|
44
|
+
|
45
|
+
Souschef::Print.header 'Create default recipe and tests'
|
46
|
+
Souschef::Scaffold.new(path: @opts[:path],
|
47
|
+
recipe: 'default',
|
48
|
+
profile: @opts[:profile],
|
49
|
+
force: true,
|
50
|
+
verbose: @opts[:verbose]).start
|
51
|
+
|
52
|
+
Souschef::Print.header 'Testkitchen configuration'
|
53
|
+
Souschef::Testkitchen.new(@opts).setup
|
54
|
+
|
55
|
+
Souschef::Print.header "Don't forget to run bundle install!"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Private - Verify @opts values
|
59
|
+
#
|
60
|
+
# Return nil
|
61
|
+
def verify_configure_input
|
62
|
+
if @opts[:maintainer_given] || @opts[:maintainer_email_given] ||
|
63
|
+
@opts[:license_given]
|
64
|
+
unless @opts[:configure]
|
65
|
+
fail 'Please check Souschef options, you are missing --configure'
|
66
|
+
end
|
67
|
+
else
|
68
|
+
fail 'Please check if you have all options for configuration selected'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Private - Verify cookbook creation options
|
73
|
+
#
|
74
|
+
# Return nil
|
75
|
+
def verify_cookbook_creation
|
76
|
+
fail 'You need to specify the cookbook name' if @opts[:cookbook].nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
# Private - Verify Scaffold input
|
80
|
+
#
|
81
|
+
# Return nil
|
82
|
+
def verify_scaffold_input
|
83
|
+
fail 'Recipe name is missing for scaffold creation' if @opts[:recipe].nil?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Private - Adjust cookbook path
|
87
|
+
#
|
88
|
+
# Return nil
|
89
|
+
def adjust_cb_path
|
90
|
+
if @opts[:path]
|
91
|
+
@opts[path] = File.join(Dir.pwd, @opts[:path])
|
92
|
+
else
|
93
|
+
@opts[:path] = Dir.pwd
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Private - Load contents of .souschef.yml configuration
|
98
|
+
#
|
99
|
+
# Returns nil
|
100
|
+
def load_configuration
|
101
|
+
@opts[:souschef] = Souschef::Config.read[@opts[:profile]]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'chef/cookbook/metadata'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Souschef
|
5
|
+
# Automagically create needed files
|
6
|
+
class Scaffold
|
7
|
+
attr_accessor :opts, :dir, :recipe, :recipe_file, :cookbook, :metadata
|
8
|
+
|
9
|
+
def initialize(opts)
|
10
|
+
@opts = opts
|
11
|
+
@dir = Dir.pwd
|
12
|
+
metadata_info
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
check_cookbook_name
|
17
|
+
check_for_metadata unless @opts[:force]
|
18
|
+
process_templates
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Private - Chef if cookbook name is set
|
24
|
+
#
|
25
|
+
# Returns nil
|
26
|
+
def check_cookbook_name
|
27
|
+
fail 'Please specify the recipe name' if @opts[:recipe].nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Private - Read Chef metadata
|
31
|
+
#
|
32
|
+
# Returns String
|
33
|
+
def metadata_info
|
34
|
+
meta = File.join(@opts[:path], 'metadata.rb')
|
35
|
+
@metadata = Chef::Cookbook::Metadata.new
|
36
|
+
@metadata.from_file(meta)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Private - Process tempaltes
|
40
|
+
#
|
41
|
+
# Return inl
|
42
|
+
def process_templates
|
43
|
+
%w( recipe serverspec chefspec ).each { |type| create_recipe_file(type) }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Private - Creates recipe file based on the input
|
47
|
+
#
|
48
|
+
# Retunrns nil
|
49
|
+
def create_recipe_file(type)
|
50
|
+
source = template_location(type)
|
51
|
+
Souschef::Print.info("Create #{@opts[:recipe]}[#{type}] from #{source}"
|
52
|
+
) if @opts[:verbose]
|
53
|
+
check_for_directories(type)
|
54
|
+
write_file(return_file_location(type), generate_template(source))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Private - Generate the template
|
58
|
+
#
|
59
|
+
# Return String
|
60
|
+
def generate_template(source)
|
61
|
+
rfile = ERB.new(File.read(source))
|
62
|
+
@recipe = @opts[:recipe]
|
63
|
+
@cookbook = @metadata.name
|
64
|
+
@maintainer = @metadata.maintainer
|
65
|
+
@license = @metadata.license
|
66
|
+
@year = Time.now.year
|
67
|
+
|
68
|
+
rfile.result(binding)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Private - Return location of the template file, depending if custom
|
72
|
+
# configuration is set under ~/.souschef/%profile%/ or use the default
|
73
|
+
# template provided by Souschef gem.
|
74
|
+
#
|
75
|
+
# Returns String
|
76
|
+
def template_location(type)
|
77
|
+
local = File.expand_path(
|
78
|
+
"~/.souschef/#{@opts[:profile]}/#{type}/#{type}.erb", __FILE__)
|
79
|
+
bundled = File.expand_path("../../../data/#{type}/#{type}.erb", __FILE__)
|
80
|
+
File.exist?(local) ? local : bundled
|
81
|
+
end
|
82
|
+
|
83
|
+
# Private - Return location of directories
|
84
|
+
#
|
85
|
+
# Returns Hash
|
86
|
+
def return_directories
|
87
|
+
{ recipe: File.join(@opts[:path], 'recipes'),
|
88
|
+
serverspec: File.join(@opts[:path], 'test', 'integration', 'default',
|
89
|
+
'serverspec', 'localhost'),
|
90
|
+
chefspec: File.join(@opts[:path], 'spec', 'unit') }
|
91
|
+
end
|
92
|
+
|
93
|
+
# Private - Get path to the recipes file
|
94
|
+
#
|
95
|
+
# Return String
|
96
|
+
def return_file_location(type)
|
97
|
+
case type
|
98
|
+
when 'recipe'
|
99
|
+
File.join(return_directories[:recipe], "#{@opts[:recipe]}.rb")
|
100
|
+
when 'serverspec'
|
101
|
+
File.join(return_directories[:serverspec], "#{opts[:recipe]}_spec.rb")
|
102
|
+
when 'chefspec'
|
103
|
+
File.join(return_directories[:chefspec], "#{@opts[:recipe]}_spec.rb")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Private - Check if directories exist
|
108
|
+
#
|
109
|
+
# Return nil
|
110
|
+
def check_for_directories(type)
|
111
|
+
dir = return_directories[type.to_sym]
|
112
|
+
|
113
|
+
if @opts[:versbose]
|
114
|
+
unless File.directory?(dir)
|
115
|
+
Souschef::Print.info "Creating missing directory #{dir}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
FileUtils.mkdir_p dir unless File.directory?(dir)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Private - Locate metadata.rb
|
122
|
+
#
|
123
|
+
# Return nil
|
124
|
+
def check_for_metadata
|
125
|
+
meta = File.join(@opts[:path], 'metadata.rb')
|
126
|
+
fail 'Please return to the root of your cookbook' unless File.exist?(meta)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Private - Write file
|
130
|
+
#
|
131
|
+
# Returns nil
|
132
|
+
def write_file(file, data)
|
133
|
+
check_for_file(file) unless @opts[:force]
|
134
|
+
fd = File.open(file, 'w')
|
135
|
+
fd.write(data)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Private - Exit if file exists
|
139
|
+
#
|
140
|
+
# Returns nil
|
141
|
+
def check_for_file(file)
|
142
|
+
fail "#{file} already exists. Frozen in fear!" if File.exist?(file)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|