fhcap-cli 0.3.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 +10 -0
- data/.rakeTasks +7 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +150 -0
- data/Rakefile +2 -0
- data/bin/fhcap +6 -0
- data/fhcap-cli.gemspec +44 -0
- data/lib/cookbooks/provision/libraries/provision.rb +140 -0
- data/lib/cookbooks/provision/metadata.rb +7 -0
- data/lib/cookbooks/provision/recipes/aws.rb +15 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_create.rb +59 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_create_elb.rb +61 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_destroy.rb +52 -0
- data/lib/cookbooks/provision/recipes/cluster_create.rb +2 -0
- data/lib/cookbooks/provision/recipes/cluster_destroy.rb +2 -0
- data/lib/cookbooks/provision/recipes/cluster_destroy_instances.rb +11 -0
- data/lib/cookbooks/provision/recipes/cluster_provision.rb +4 -0
- data/lib/cookbooks/provision/recipes/cluster_provision_instances.rb +55 -0
- data/lib/cookbooks/provision/recipes/cluster_status.rb +24 -0
- data/lib/cookbooks/provision/recipes/common.rb +9 -0
- data/lib/cookbooks/provision/recipes/default.rb +5 -0
- data/lib/cookbooks/provision/recipes/openstack.rb +11 -0
- data/lib/cookbooks/provision/recipes/openstack_cluster_create.rb +11 -0
- data/lib/cookbooks/provision/recipes/openstack_cluster_destroy.rb +4 -0
- data/lib/cookbooks/provision/recipes/reset_rabbitmq.rb +49 -0
- data/lib/cookbooks/provision/recipes/restart_services.rb +24 -0
- data/lib/extensions/chef/provisioning.rb +21 -0
- data/lib/extensions/chef/provisioning/aws_driver/driver.rb +46 -0
- data/lib/extensions/chef/provisioning/chef_run_data.rb +18 -0
- data/lib/extensions/cheffish/merged_config.rb +9 -0
- data/lib/fhcap.rb +14 -0
- data/lib/fhcap/chef-dk/chef_runner.rb +94 -0
- data/lib/fhcap/cli.rb +75 -0
- data/lib/fhcap/cluster.rb +112 -0
- data/lib/fhcap/config.rb +104 -0
- data/lib/fhcap/cookbook.rb +75 -0
- data/lib/fhcap/dummy_node.rb +80 -0
- data/lib/fhcap/fhcap_helper.rb +9 -0
- data/lib/fhcap/kitchen.rb +235 -0
- data/lib/fhcap/knife.rb +74 -0
- data/lib/fhcap/knife_helper.rb +38 -0
- data/lib/fhcap/misc.rb +103 -0
- data/lib/fhcap/provider.rb +41 -0
- data/lib/fhcap/providers_helper.rb +60 -0
- data/lib/fhcap/repo.rb +52 -0
- data/lib/fhcap/repos_helper.rb +217 -0
- data/lib/fhcap/tasks/chef/chef_task_base.rb +82 -0
- data/lib/fhcap/tasks/chef/cookbook/list.rb +37 -0
- data/lib/fhcap/tasks/chef/cookbook/update_changelog.rb +63 -0
- data/lib/fhcap/tasks/chef/cookbook/update_metadata.rb +57 -0
- data/lib/fhcap/tasks/chef/cookbook/update_readme.rb +30 -0
- data/lib/fhcap/tasks/chef/cookbook/update_version.rb +90 -0
- data/lib/fhcap/tasks/chef/environments/create.rb +115 -0
- data/lib/fhcap/tasks/chef/environments/destroy.rb +37 -0
- data/lib/fhcap/tasks/chef/environments/promote_cookbooks.rb +47 -0
- data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task.rb +27 -0
- data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task_base.rb +38 -0
- data/lib/fhcap/tasks/chef/provisioning/create.rb +22 -0
- data/lib/fhcap/tasks/chef/provisioning/destroy.rb +21 -0
- data/lib/fhcap/tasks/chef/provisioning/provision.rb +19 -0
- data/lib/fhcap/tasks/chef/server/bootstrap.rb +165 -0
- data/lib/fhcap/tasks/chef/server/create_user.rb +97 -0
- data/lib/fhcap/tasks/chef/server/info.rb +82 -0
- data/lib/fhcap/tasks/chef/server/provision.rb +45 -0
- data/lib/fhcap/tasks/clean.rb +34 -0
- data/lib/fhcap/tasks/cluster/cluster_task_base.rb +57 -0
- data/lib/fhcap/tasks/cluster/create.rb +243 -0
- data/lib/fhcap/tasks/cluster/create_environment.rb +171 -0
- data/lib/fhcap/tasks/cluster/destroy.rb +30 -0
- data/lib/fhcap/tasks/cluster/destroy_environment.rb +28 -0
- data/lib/fhcap/tasks/cluster/info.rb +67 -0
- data/lib/fhcap/tasks/cluster/list.rb +40 -0
- data/lib/fhcap/tasks/cluster/provision.rb +46 -0
- data/lib/fhcap/tasks/cluster/status.rb +17 -0
- data/lib/fhcap/tasks/cluster/test.rb +15 -0
- data/lib/fhcap/tasks/knife/add.rb +111 -0
- data/lib/fhcap/tasks/knife/list.rb +22 -0
- data/lib/fhcap/tasks/knife/remove.rb +39 -0
- data/lib/fhcap/tasks/misc/create_dns_record.rb +100 -0
- data/lib/fhcap/tasks/misc/create_ssl_cert.rb +82 -0
- data/lib/fhcap/tasks/provider/add.rb +136 -0
- data/lib/fhcap/tasks/provider/list.rb +31 -0
- data/lib/fhcap/tasks/provider/remove.rb +28 -0
- data/lib/fhcap/tasks/repo/add.rb +57 -0
- data/lib/fhcap/tasks/repo/checkout.rb +144 -0
- data/lib/fhcap/tasks/repo/list.rb +22 -0
- data/lib/fhcap/tasks/repo/remove.rb +34 -0
- data/lib/fhcap/tasks/setup.rb +59 -0
- data/lib/fhcap/tasks/task_base.rb +89 -0
- data/lib/fhcap/thor_base.rb +121 -0
- data/lib/fhcap/version.rb +3 -0
- data/spec/fhcap/cli_spec.rb +6 -0
- data/spec/fhcap/tasks/cluster/create_spec.rb +46 -0
- data/spec/fhcap/tasks/knife/add_spec.rb +35 -0
- data/spec/fhcap/tasks/knife/remove_spec.rb +25 -0
- data/spec/fhcap/tasks/provider/add_spec.rb +61 -0
- data/spec/fhcap/tasks/provider/remove_spec.rb +25 -0
- data/spec/fhcap/tasks/repo/add_spec.rb +32 -0
- data/spec/fhcap/tasks/repo/remove_spec.rb +25 -0
- data/spec/fhcap/tasks/task_base_spec.rb +51 -0
- data/spec/fhcap/thor_base_spec.rb +9 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/dummy_config.rb +7 -0
- data/spec/support/dummy_thor.rb +3 -0
- data/templates/chef/cookbook/changelog.md.erb +12 -0
- data/templates/chef/cookbook/metadata.erb +45 -0
- data/templates/chef/environment_core.json.erb +278 -0
- data/templates/chef/environment_empty.json.erb +10 -0
- data/templates/chef/environment_mbaas.json.erb +120 -0
- data/templates/chef/environment_single.json.erb +300 -0
- data/templates/cluster/aws/common.json.erb +43 -0
- data/templates/cluster/aws/core-3node.json.erb +106 -0
- data/templates/cluster/aws/core-small-9node.json.erb +333 -0
- data/templates/cluster/aws/mbaas-3node.json.erb +116 -0
- data/templates/cluster/aws/nginx-test.json.erb +93 -0
- data/templates/cluster/aws/single-blank.json.erb +41 -0
- data/templates/cluster/aws/single.json.erb +88 -0
- data/templates/cluster/core-3node.json.erb +8 -0
- data/templates/cluster/core-mbaas-6node.json.erb +13 -0
- data/templates/cluster/core-small-9node.json.erb +8 -0
- data/templates/cluster/mbaas-3node.json.erb +9 -0
- data/templates/cluster/nginx-test.json.erb +8 -0
- data/templates/cluster/openstack/common.json.erb +7 -0
- data/templates/cluster/openstack/core-3node.json.erb +14 -0
- data/templates/cluster/openstack/core-small-9node.json.erb +32 -0
- data/templates/cluster/openstack/mbaas-3node.json.erb +14 -0
- data/templates/cluster/openstack/nginx-test.json.erb +11 -0
- data/templates/cluster/openstack/single-blank.json.erb +10 -0
- data/templates/cluster/openstack/single.json.erb +10 -0
- data/templates/cluster/single-blank.json.erb +8 -0
- data/templates/cluster/single.json.erb +8 -0
- data/templates/init/knife.rb.erb +13 -0
- data/templates/kitchen/Cheffile.erb +11 -0
- data/templates/kitchen/kitchen.aws.yml.erb +35 -0
- data/templates/kitchen/kitchen.docker.yml.erb +24 -0
- data/templates/kitchen/kitchen.generate.yml.erb +2 -0
- data/templates/kitchen/kitchen.openstack.yml.erb +31 -0
- metadata +506 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'chef/node'
|
|
2
|
+
|
|
3
|
+
module Fhcap
|
|
4
|
+
class DummyNode < Chef::Node
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
attr_accessor :included_recipe_attributes
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
super
|
|
11
|
+
@included_recipe_attributes = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def include_attribute(recipe)
|
|
15
|
+
@included_recipe_attributes << recipe
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def from_file(filename)
|
|
19
|
+
if File.exists?(filename) && File.readable?(filename)
|
|
20
|
+
#Convert any references to node['blah'] to a string so instance_eval doesn't try to evaluate it
|
|
21
|
+
text = ""
|
|
22
|
+
ignore_lines = false
|
|
23
|
+
File.open(filename).each_line do |line|
|
|
24
|
+
key, value = line.split(/ = /, 2)
|
|
25
|
+
if key && value
|
|
26
|
+
ignore_lines = false
|
|
27
|
+
if ignore_key? key
|
|
28
|
+
value = "\"Ignored\""
|
|
29
|
+
ignore_lines = true
|
|
30
|
+
else
|
|
31
|
+
value.gsub!(/node(\[['a-zA-Z0-9_-]*\])+/, '"\&"')
|
|
32
|
+
value.gsub!(/node.chef_environment/, '"\&"')
|
|
33
|
+
if value =~ /\.* \| "node\[/
|
|
34
|
+
value.gsub!(/"/, '')
|
|
35
|
+
value = "\"#{value.chomp}\"\n"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
line = "#{key} = #{value}"
|
|
39
|
+
end
|
|
40
|
+
text += line unless ignore_lines
|
|
41
|
+
end
|
|
42
|
+
self.instance_eval(text, filename, 1)
|
|
43
|
+
else
|
|
44
|
+
raise IOError, "Cannot open or read #{filename}!"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def ignore_key?(key)
|
|
49
|
+
key =~ /\['cron_jobs'\]/
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def metadata_attributes
|
|
53
|
+
self.get_attributes(node.default_attrs)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_attributes(hash, attrs=nil, keys=nil)
|
|
57
|
+
keys ||= []
|
|
58
|
+
attrs ||= {}
|
|
59
|
+
hash.sort.each() do |k, v|
|
|
60
|
+
keys << k.to_s
|
|
61
|
+
if v.is_a? Hash
|
|
62
|
+
self.get_attributes(v, attrs, keys)
|
|
63
|
+
else
|
|
64
|
+
attrs[keys.join("/")] = {:default => parse_value(v)}
|
|
65
|
+
end
|
|
66
|
+
keys.pop
|
|
67
|
+
end
|
|
68
|
+
attrs
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse_value(value)
|
|
72
|
+
if value.is_a? Array
|
|
73
|
+
value
|
|
74
|
+
else
|
|
75
|
+
value.to_s
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'fhcap/thor_base'
|
|
3
|
+
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
|
|
7
|
+
module Fhcap
|
|
8
|
+
module CLI
|
|
9
|
+
class Kitchen < Fhcap::ThorBase
|
|
10
|
+
|
|
11
|
+
TEST_SUITE_NAME='default'
|
|
12
|
+
DEFAULT_INSTANCE='default'
|
|
13
|
+
|
|
14
|
+
add_shared_option :cookbooks, :aliases => "-c", :desc => "Apply to these Cookbooks", :type => :array
|
|
15
|
+
add_shared_option :roles, :aliases => "-r", :desc => "Roles to generate kitchen for", :type => :array
|
|
16
|
+
add_shared_option :driver, :aliases => "-d", :desc => "Kitchen Driver", :type => :string, :default => 'openstack', :enum => %w{aws openstack docker}
|
|
17
|
+
add_shared_option :modified, :aliases => "-m", :desc => "Apply only to modified Cookbooks", :type => :boolean, :required => false, :default => false
|
|
18
|
+
add_shared_option :provisioner, :aliases => "-p", :desc => "Kitchen Provisioner", :type => :string, :default => 'chef_solo', :enum => %w{chef_solo chef_zero}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
desc "generate", "Generate"
|
|
22
|
+
|
|
23
|
+
shared_options :cookbooks, :roles, :modified, :driver, :provisioner
|
|
24
|
+
method_option 'only', :type => :array, :default => nil, :desc => "Only include tests for cookbooks matching these names."
|
|
25
|
+
method_option 'exclude', :type => :array, :default => nil, :desc => "Exclude tests for cookbooks matching these names, takes precedence over 'only' option."
|
|
26
|
+
method_option 'clean', :type => :boolean, :default => true, :desc => "Clean the current generated kitchen prior to creating the new one"
|
|
27
|
+
|
|
28
|
+
def generate
|
|
29
|
+
require 'chef'
|
|
30
|
+
cookbooks = get_cookbooks(options, nil, repo_cookbook_paths('-cookbooks'))
|
|
31
|
+
roles = options[:roles] || []
|
|
32
|
+
driver = options[:driver]
|
|
33
|
+
provisioner = options[:provisioner]
|
|
34
|
+
say("Kitchen Generate: Cookbooks = #{cookbooks} : Roles = #{roles}: Driver = #{driver} : Provisioner = #{provisioner}", :yellow)
|
|
35
|
+
|
|
36
|
+
Fhcap::CLI::Kitchen.new.invoke(:clean, [], {}) if is_kitchen_generated? && options[:clean]
|
|
37
|
+
empty_directory test_suite_dir
|
|
38
|
+
|
|
39
|
+
kitchen_config = YAML.load_file(File.join(Fhcap.source_root, "templates", "kitchen", "kitchen.#{driver}.yml.erb"))
|
|
40
|
+
kitchen_config['suites'] = []
|
|
41
|
+
kitchen_config['provisioner']['name'] = provisioner
|
|
42
|
+
kitchen_config['provisioner']['data_bags_path'] = File.join(repo_dir(:fhcap), 'data_bags')
|
|
43
|
+
kitchen_config['provisioner']['environments_path'] = File.join(repo_dir(:fhcap), 'environments')
|
|
44
|
+
kitchen_config['provisioner']['roles_path'] = File.join(repo_dir(:fhcap), 'roles')
|
|
45
|
+
|
|
46
|
+
cookbook_dependencies = {}
|
|
47
|
+
|
|
48
|
+
cookbooks.each do |cookbook|
|
|
49
|
+
meta = cookbook_loader.cookbooks_by_name[cookbook]
|
|
50
|
+
if meta
|
|
51
|
+
cookbook_kitchen_yaml = File.join(meta.root_dir, ".kitchen.yml")
|
|
52
|
+
if File.exists? cookbook_kitchen_yaml
|
|
53
|
+
cookbook_kitchen_config = YAML.load_file(cookbook_kitchen_yaml)
|
|
54
|
+
cookbook_kitchen_config['suites'].each do |suite|
|
|
55
|
+
suite['name'] = "#{suite['name']}_#{cookbook}"
|
|
56
|
+
suite['run_list'].unshift 'recipe[feedhenry_utils::kitchen_docker]' if driver == 'docker'
|
|
57
|
+
suite['run_list'].unshift 'recipe[apt::default]'
|
|
58
|
+
suite['run_list'].unshift 'recipe[chef-solo-search]' if provisioner == 'chef_solo'
|
|
59
|
+
suite['run_list'].unshift 'role[test-kitchen_server]'
|
|
60
|
+
suite['run_list'].uniq!
|
|
61
|
+
|
|
62
|
+
suite_cookbooks = [cookbook] | suite['run_list'].collect do |item|
|
|
63
|
+
recipe_match = /recipe\[(.+?(?=::)|.+?(?=\]))/.match item
|
|
64
|
+
recipe_match ? recipe_match[1] : nil
|
|
65
|
+
end.compact.uniq
|
|
66
|
+
|
|
67
|
+
kitchen_config['suites'] << suite
|
|
68
|
+
|
|
69
|
+
suite_cookbooks.each do |c|
|
|
70
|
+
get_cookbook_deps(c, cookbook_dependencies, {cwd: test_suite_dir})
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
say_status("ERROR", "No test suites found for #{cookbook}", :red)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
else
|
|
79
|
+
say_status("ERROR", "No cookbook found for #{cookbook}", :red)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
roles.each do |r|
|
|
84
|
+
role_file = find_role(r)
|
|
85
|
+
if File.exists? role_file
|
|
86
|
+
::Chef::Config[:role_path] = File.join(repo_dir(:fhcap), 'roles')
|
|
87
|
+
role = ::Chef::Role.from_disk r
|
|
88
|
+
run_list = role.run_list.expand('development')
|
|
89
|
+
|
|
90
|
+
role_cookbooks = run_list.recipes.collect do |recipe|
|
|
91
|
+
recipe.split('::').first
|
|
92
|
+
end.compact.uniq
|
|
93
|
+
|
|
94
|
+
suite = {}
|
|
95
|
+
suite['name'] = "default_#{r}"
|
|
96
|
+
suite['run_list'] = ["role[#{r}]"]
|
|
97
|
+
kitchen_config['suites'] << suite
|
|
98
|
+
|
|
99
|
+
role_cookbooks.each do |c|
|
|
100
|
+
get_cookbook_deps(c, cookbook_dependencies, {cwd: test_suite_dir})
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
link_cookbook_tests(role_cookbooks, options, r)
|
|
104
|
+
|
|
105
|
+
else
|
|
106
|
+
say "Unknown Role #{role_file}"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# 1. Create kitchen.yml
|
|
111
|
+
template(File.join("templates", "kitchen", "kitchen.generate.yml.erb"), test_suite_kitchen_yml, :kitchen_yaml => kitchen_config.to_yaml, :force => true)
|
|
112
|
+
|
|
113
|
+
#2. Create Cheffile
|
|
114
|
+
template(File.join("templates", "kitchen", "Cheffile.erb"), File.join(test_suite_dir, "Cheffile"), :cookbooks => cookbook_dependencies.to_h, :name => "Combined Cheffile for #{cookbooks}", :force => true)
|
|
115
|
+
|
|
116
|
+
#3. Configure tests
|
|
117
|
+
link_cookbook_tests(cookbooks, options)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
desc "clean", "Clean"
|
|
121
|
+
|
|
122
|
+
def clean
|
|
123
|
+
say("Clean Test Suite", :yellow)
|
|
124
|
+
Fhcap::CLI::Kitchen.new.invoke(:destroy, ['all'], {}) if is_kitchen_generated?
|
|
125
|
+
remove_file test_suite_dir
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
%w{create converge setup verify test list login destroy diagnose}.each do |cmd|
|
|
129
|
+
|
|
130
|
+
desc "#{cmd} [INSTANCE|REGEXP|all]", "Run '#{cmd}' command against current kitchen instances."
|
|
131
|
+
shared_options :cookbooks, :roles, :modified, :driver, :provisioner if %w{create converge setup verify test}.include? cmd
|
|
132
|
+
|
|
133
|
+
define_method(cmd) do |instance='all'|
|
|
134
|
+
Fhcap::CLI::Kitchen.new.invoke(:generate, [], options) if options[:cookbooks] || options[:modified] || options[:roles]
|
|
135
|
+
if is_kitchen_generated?
|
|
136
|
+
Dir.chdir test_suite_dir do
|
|
137
|
+
cmd_options = options.dup
|
|
138
|
+
cmd_options['instance'] = instance
|
|
139
|
+
cmd_options['kitchen-yaml'] = test_suite_kitchen_yml
|
|
140
|
+
cmd_options['kitchen-options'] = '--concurrency=10'
|
|
141
|
+
run_kitchen_cmd(cmd, cmd_options)
|
|
142
|
+
end
|
|
143
|
+
else
|
|
144
|
+
say "Please generate a test kitchen first! i.e fhcap kitchen generate -c <cookbooks>", :yellow
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
protected
|
|
151
|
+
|
|
152
|
+
def test_suite_dir
|
|
153
|
+
File.join(config.default_dir, 'tmp', 'kitchen')
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_suite_kitchen_yml
|
|
157
|
+
File.join(test_suite_dir, 'kitchen.yml')
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def is_kitchen_generated?
|
|
161
|
+
File.exists? test_suite_kitchen_yml
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def include_cookbook_tests?(cookbook, options)
|
|
165
|
+
if options['exclude']
|
|
166
|
+
!options['exclude'].include?(cookbook)
|
|
167
|
+
elsif options['only']
|
|
168
|
+
options['only'].include?(cookbook)
|
|
169
|
+
else
|
|
170
|
+
true
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def link_cookbook_tests(cookbooks, options, role=nil)
|
|
175
|
+
tests_parent_dir = File.join(test_suite_dir, 'test', 'integration')
|
|
176
|
+
test_helpers_dir = File.join(repo_dir(:fhcap), 'test', 'helpers')
|
|
177
|
+
|
|
178
|
+
cookbooks.each do |cookbook|
|
|
179
|
+
if include_cookbook_tests?(cookbook, options)
|
|
180
|
+
meta = cookbook_loader.cookbooks_by_name[cookbook]
|
|
181
|
+
cookbook_dir = File.dirname(meta.root_filenames.first)
|
|
182
|
+
cookbook_test_suite_dir = File.join(cookbook_dir, '/test/integration')
|
|
183
|
+
|
|
184
|
+
if Dir.exists? cookbook_test_suite_dir
|
|
185
|
+
Dir.entries(cookbook_test_suite_dir).select { |f| !File.directory? f }.each() do |test_suite|
|
|
186
|
+
|
|
187
|
+
cookbook_test_dir = File.join(cookbook_test_suite_dir, test_suite)
|
|
188
|
+
Dir.entries(cookbook_test_dir).select { |f| !File.directory? f }.each() do |test_type|
|
|
189
|
+
tests_dir = File.join(tests_parent_dir, "#{test_suite}_#{role || cookbook}")
|
|
190
|
+
|
|
191
|
+
test_type_dir = "#{tests_dir}/#{test_type}"
|
|
192
|
+
empty_directory test_type_dir
|
|
193
|
+
|
|
194
|
+
if Dir.exists? "#{test_helpers_dir}/#{test_type}"
|
|
195
|
+
FileUtils.cp_r(Dir["#{test_helpers_dir}/#{test_type}/*"], test_type_dir)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
Dir.chdir("#{cookbook_test_dir}/#{test_type}") do
|
|
199
|
+
Dir["*_spec.rb"].each do |test|
|
|
200
|
+
link_src = "#{cookbook_test_dir}/#{test_type}/#{test}"
|
|
201
|
+
link_dest = "#{test_type_dir}/#{cookbook}_#{test}"
|
|
202
|
+
create_link link_dest, link_src
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
say_status("warning", "No tests suites found for #{cookbook}", :yellow)
|
|
209
|
+
end
|
|
210
|
+
else
|
|
211
|
+
say_status("exclude", "Excluding tests for #{cookbook}", :yellow)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def _get_config(options)
|
|
217
|
+
opts = []
|
|
218
|
+
opts << "KITCHEN_YAML=#{options['kitchen-yaml']}" if options['kitchen-yaml']
|
|
219
|
+
opts.join(' ')
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def run_kitchen_cmd(cmd, options)
|
|
223
|
+
suite = options['instance'] || DEFAULT_INSTANCE
|
|
224
|
+
kitchen_cmd_options = [options['kitchen-options']] || []
|
|
225
|
+
cmd = ([_get_config(options), 'kitchen', cmd, suite] + kitchen_cmd_options).join(' ')
|
|
226
|
+
run_cmd(cmd, options)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def run_cmd(cmd, options)
|
|
230
|
+
run(cmd)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
data/lib/fhcap/knife.rb
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'fhcap/thor_base'
|
|
3
|
+
|
|
4
|
+
module Fhcap
|
|
5
|
+
module CLI
|
|
6
|
+
class Knife < Fhcap::ThorBase
|
|
7
|
+
|
|
8
|
+
add_shared_option :verbose, :aliases => "-v", :desc => "Verbose output", :type => :boolean, :required => false, :default => false
|
|
9
|
+
add_shared_option :name, :type => :string, :required => true, :desc => "Chef Server name i.e. bob"
|
|
10
|
+
add_shared_option :interactive, :aliases => "-i", :desc => "Interactive mode (Stops for input)", :type => :boolean, :required => false, :default => false
|
|
11
|
+
|
|
12
|
+
desc "add", "Add a chef server"
|
|
13
|
+
|
|
14
|
+
shared_options :verbose, :name, :interactive
|
|
15
|
+
method_option 'url', :type => :string, :required => false, :desc => "Chef Server url i.e. https://bob.feedhenry.net:8443"
|
|
16
|
+
method_option 'node-name', :type => :string, :desc => "Node name, defaults to current users ID i.e. echo $USER"
|
|
17
|
+
method_option 'validation-client-name', :type => :string, :desc => "Validation client name, defaults to 'chef-validator'"
|
|
18
|
+
method_option 'import-file', :type => :string, :desc => "Path to import file"
|
|
19
|
+
long_desc <<-LONGDESC
|
|
20
|
+
Add a chef server to your local fhcap configuration.
|
|
21
|
+
|
|
22
|
+
With --import-file option, if an admin sent you an import-file you can pass this in here and all config, keys etc.. will be created for you
|
|
23
|
+
LONGDESC
|
|
24
|
+
|
|
25
|
+
def add
|
|
26
|
+
require "fhcap/tasks/knife/add"
|
|
27
|
+
Tasks::Knife::Add.new(task_options(options.dup)).run
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc "remove", "Remove a chef server"
|
|
31
|
+
|
|
32
|
+
shared_options :verbose, :name
|
|
33
|
+
|
|
34
|
+
def remove
|
|
35
|
+
require "fhcap/tasks/knife/remove"
|
|
36
|
+
Tasks::Knife::Remove.new(task_options(options.dup)).run
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
desc "list", "List configured chef servers"
|
|
40
|
+
|
|
41
|
+
def list
|
|
42
|
+
require "fhcap/tasks/knife/list"
|
|
43
|
+
Tasks::Knife::List.new(task_options(options.dup)).run
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
desc "create_user", "Create a new user on a given chef server."
|
|
47
|
+
long_desc <<-LONGDESC
|
|
48
|
+
Create a new user on a given chef server.
|
|
49
|
+
|
|
50
|
+
To create users on a chef server the user running this command must have the appropriate permissions to do so i.e. admin
|
|
51
|
+
|
|
52
|
+
By default an import-file is generated that can be sent to the new user to make there local setup easier by passing it directly into the add command
|
|
53
|
+
|
|
54
|
+
i.e. fhcap knife add --name <NAME> --import-file <IMPORT_FILE>
|
|
55
|
+
LONGDESC
|
|
56
|
+
|
|
57
|
+
shared_options :verbose, :interactive
|
|
58
|
+
method_option 'chef-server', :type => :string, :desc => "Chef Server", :required => false, :enum => chef_server_names
|
|
59
|
+
method_option :username, :type => :string, :desc => "Username", :required => true
|
|
60
|
+
method_option 'display-name', :type => :string, :desc => "Display Name", :required => false
|
|
61
|
+
method_option 'first-name', :type => :string, :desc => "First Name", :required => false
|
|
62
|
+
method_option 'last-name', :type => :string, :desc => "Last Name", :required => false
|
|
63
|
+
method_option :email, :type => :string, :desc => "Email", :required => false
|
|
64
|
+
method_option :password, :type => :string, :desc => "Password", :required => false
|
|
65
|
+
|
|
66
|
+
def create_user
|
|
67
|
+
require "fhcap/tasks/chef/server/create_user"
|
|
68
|
+
Tasks::Chef::Server::CreateUser.new(task_options(options.dup)).run
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'chef/config'
|
|
2
|
+
|
|
3
|
+
module Fhcap
|
|
4
|
+
module KnifeHelper
|
|
5
|
+
|
|
6
|
+
def knife_config
|
|
7
|
+
config.exists? && config[:knife] ? config[:knife] : {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def knife_config_dir
|
|
11
|
+
config[:knife_dir] || File.join(config.default_dir, '.chef')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def knife_config_file_for(name)
|
|
15
|
+
File.join(knife_config_dir, "knife-#{name}.rb")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def chef_server_names
|
|
19
|
+
knife_config.collect do |server_name, cfg|
|
|
20
|
+
server_name.to_s
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def chef_server_config_for(name)
|
|
25
|
+
Chef::Config.from_file(knife_config_file_for(name))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def chef_server_config_hash_for(name)
|
|
29
|
+
chef_server_config_for(name)
|
|
30
|
+
chef_server_config = {
|
|
31
|
+
chef_server_url: Chef::Config[:chef_server_url],
|
|
32
|
+
node_name: Chef::Config[:node_name],
|
|
33
|
+
client_key: Chef::Config[:client_key],
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/fhcap/misc.rb
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'fhcap/thor_base'
|
|
3
|
+
|
|
4
|
+
module Fhcap
|
|
5
|
+
module CLI
|
|
6
|
+
class Misc < Fhcap::ThorBase
|
|
7
|
+
|
|
8
|
+
add_shared_option :verbose, :aliases => "-v", :desc => "Verbose output", :type => :boolean, :required => false, :default => false
|
|
9
|
+
|
|
10
|
+
desc "create_ssl_cert", "Create an SSL Cert"
|
|
11
|
+
|
|
12
|
+
shared_options :verbose
|
|
13
|
+
|
|
14
|
+
method_option 'name', :type => :string, :required => true, :desc => "SSL Cert name"
|
|
15
|
+
method_option 'domain', :type => :string, :required => true, :desc => "SSL Cert Domain i.e. *.feedhenry.me"
|
|
16
|
+
method_option 'directory', :type => :string, :required => true, :desc => "Destination directory"
|
|
17
|
+
method_option 'format', :type => :string, :required => true, :default => 'pem', :desc => "Format to save cert in", :enum => %w{pem json}
|
|
18
|
+
|
|
19
|
+
def create_ssl_cert
|
|
20
|
+
require "fhcap/tasks/misc/create_ssl_cert"
|
|
21
|
+
Tasks::Misc::CreateSslCert.new(task_options(options.dup)).run
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "create_chef_environment", "Create a Chef Environment"
|
|
25
|
+
|
|
26
|
+
shared_options :verbose
|
|
27
|
+
|
|
28
|
+
method_option 'name', :type => :string, :required => true, :desc => 'Environment name'
|
|
29
|
+
method_option 'type', :type => :string, :required => true, :enum => %w{core mbaas}, :desc => 'Environment type'
|
|
30
|
+
method_option 'domain', :type => :string, :required => true, :desc => 'Environment domain'
|
|
31
|
+
method_option 'repo', :type => :string, :required => true, :desc => "Fhcap Repo where environment should be saved", :enum => repo_names
|
|
32
|
+
|
|
33
|
+
def create_chef_environment
|
|
34
|
+
require "fhcap/tasks/chef/environments/create"
|
|
35
|
+
Tasks::Chef::Environments::Create.new(task_options(options.dup)).run
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "destroy_chef_environment", "Create a Chef Environment"
|
|
39
|
+
|
|
40
|
+
shared_options :verbose
|
|
41
|
+
|
|
42
|
+
method_option 'name', :type => :string, :required => true, :desc => 'Environment name'
|
|
43
|
+
|
|
44
|
+
def destroy_chef_environment
|
|
45
|
+
require "fhcap/tasks/chef/environments/destroy"
|
|
46
|
+
Tasks::Chef::Environments::Destroy.new(task_options(options.dup)).run
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
desc "chef_provision", "Run a chef provisioning task against a particular cluster"
|
|
50
|
+
|
|
51
|
+
shared_options :verbose
|
|
52
|
+
|
|
53
|
+
method_option 'name', :type => :string, :required => true, :desc => 'Cluster name'
|
|
54
|
+
method_option 'run-list', :type => :array, :required => true, :desc => 'Chef Provisioning Run List i.e provision::cluster_provision'
|
|
55
|
+
|
|
56
|
+
def chef_provision
|
|
57
|
+
require 'fhcap/tasks/chef/provisioning/chef_provisioning_task'
|
|
58
|
+
Tasks::Chef::Provisioning::ChefProvisioningTask.new(task_options(options.dup)).run
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
desc "create_cluster_environment", "Add an environment to a cluster"
|
|
62
|
+
|
|
63
|
+
shared_options :verbose
|
|
64
|
+
|
|
65
|
+
method_option 'name', :type => :string, :required => true, :desc => 'Cluster name'
|
|
66
|
+
method_option 'environment-name', :type => :string, :required => true, :desc => 'Environment name'
|
|
67
|
+
method_option 'domain', :type => :string, :required => true, :desc => 'Environment domain'
|
|
68
|
+
method_option 'template', :type => :string, :required => true, :desc => 'Environment template'
|
|
69
|
+
|
|
70
|
+
def create_cluster_environment
|
|
71
|
+
require "fhcap/tasks/cluster/create_environment"
|
|
72
|
+
Tasks::Cluster::CreateEnvironment.new(task_options(options.dup)).run
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
desc "destroy_cluster_environment", "Add an environment to a cluster"
|
|
76
|
+
|
|
77
|
+
shared_options :verbose
|
|
78
|
+
|
|
79
|
+
method_option 'name', :type => :string, :required => true, :desc => 'Cluster name'
|
|
80
|
+
method_option 'environment-name', :type => :string, :required => true, :desc => 'Environment name'
|
|
81
|
+
|
|
82
|
+
def destroy_cluster_environment
|
|
83
|
+
require "fhcap/tasks/cluster/destroy_environment"
|
|
84
|
+
Tasks::Cluster::DestroyEnvironment.new(task_options(options.dup)).run
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
desc "create_dns_record", "Create a new DNS Record"
|
|
88
|
+
|
|
89
|
+
shared_options :verbose
|
|
90
|
+
|
|
91
|
+
method_option 'domain', :type => :string, :required => true, :desc => 'Domain'
|
|
92
|
+
method_option 'ipaddress', :type => :string, :desc => 'IP Address'
|
|
93
|
+
method_option 'alias-target', :type => :hash, :desc => 'Alias Target'
|
|
94
|
+
method_option 'ttl', :type => :numeric, :default => 300, :desc => 'Time To Live'
|
|
95
|
+
|
|
96
|
+
def create_dns_record
|
|
97
|
+
require "fhcap/tasks/misc/create_dns_record"
|
|
98
|
+
Tasks::Misc::CreateDNSRecord.new(task_options(options.dup)).run
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|