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,41 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'fhcap/thor_base'
|
|
3
|
+
|
|
4
|
+
module Fhcap
|
|
5
|
+
module CLI
|
|
6
|
+
class Provider < Fhcap::ThorBase
|
|
7
|
+
|
|
8
|
+
add_shared_option :verbose, :aliases => "-v", :desc => "Verbose output", :type => :boolean, :required => false, :default => false
|
|
9
|
+
add_shared_option :interactive, :aliases => "-i", :desc => "Interactive mode (Stops for input)", :type => :boolean, :required => false, :default => false
|
|
10
|
+
add_shared_option :name, :type => :string, :required => true, :desc => "Provider Name"
|
|
11
|
+
add_shared_option :type, :type => :string, :required => true, :desc => "Provider Type", :enum => %w{aws openstack}
|
|
12
|
+
add_shared_option :credentials, :type => :hash, :desc => "Provider specific credentials"
|
|
13
|
+
|
|
14
|
+
desc "add", "Add a provider"
|
|
15
|
+
|
|
16
|
+
shared_options :verbose, :name, :type, :credentials, :interactive
|
|
17
|
+
|
|
18
|
+
def add
|
|
19
|
+
require "fhcap/tasks/provider/add"
|
|
20
|
+
Tasks::Provider::Add.new(task_options(options.dup)).run
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc "remove", "Remove a provider"
|
|
24
|
+
|
|
25
|
+
shared_options :verbose, :name, :type
|
|
26
|
+
|
|
27
|
+
def remove
|
|
28
|
+
require "fhcap/tasks/provider/remove"
|
|
29
|
+
Tasks::Provider::Remove.new(task_options(options.dup)).run
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "list", "List configured providers"
|
|
33
|
+
|
|
34
|
+
def list
|
|
35
|
+
require "fhcap/tasks/provider/list"
|
|
36
|
+
Tasks::Provider::List.new(task_options(options.dup)).run
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Fhcap
|
|
2
|
+
module ProvidersHelper
|
|
3
|
+
|
|
4
|
+
def providers_config
|
|
5
|
+
config.exists? && config[:providers] ? config[:providers] : {}
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def provider_names
|
|
9
|
+
providers_config.collect do |provider, cfg|
|
|
10
|
+
cfg.collect do |id, pcfg|
|
|
11
|
+
"#{provider}:#{id}"
|
|
12
|
+
end
|
|
13
|
+
end.flatten
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def provider_type(id)
|
|
17
|
+
provider_type, provider_id = id.split(':')
|
|
18
|
+
provider_type
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def provider_config(id)
|
|
22
|
+
provider_type, provider_id = id.split(':')
|
|
23
|
+
providers_config[provider_type.to_sym][provider_id.to_sym]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def provider_credentials(id)
|
|
27
|
+
provider_config(id)[:credentials]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def provider_regions(id)
|
|
31
|
+
provider_config(id)[:regions] || {}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def provider_availability_zones(id, region)
|
|
35
|
+
return [] unless region && provider_regions(id)[region.to_sym]
|
|
36
|
+
provider_regions(id)[region.to_sym][:availability_zones] || []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def provider_names_for(service)
|
|
40
|
+
providers_config.collect do |provider, cfg|
|
|
41
|
+
cfg.reject do |id, pcfg|
|
|
42
|
+
!pcfg[:provides] || !pcfg[:provides].include?(service)
|
|
43
|
+
end.collect do |id, pcfg|
|
|
44
|
+
"#{provider}:#{id}"
|
|
45
|
+
end
|
|
46
|
+
end.flatten
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def provider_for(domain)
|
|
50
|
+
providers_config.collect do |provider, cfg|
|
|
51
|
+
cfg.reject do |id, pcfg|
|
|
52
|
+
!pcfg[:provides] || !pcfg[:provides].include?('dns') || !pcfg[:domains].include?(domain)
|
|
53
|
+
end.collect do |id, pcfg|
|
|
54
|
+
"#{provider}:#{id}"
|
|
55
|
+
end
|
|
56
|
+
end.flatten.first
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/fhcap/repo.rb
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'fhcap/thor_base'
|
|
3
|
+
|
|
4
|
+
module Fhcap
|
|
5
|
+
module CLI
|
|
6
|
+
class Repo < 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 => "Repo name i.e. fhcap-dev"
|
|
10
|
+
add_shared_option :interactive, :aliases => "-i", :desc => "Interactive mode (Stops for input)", :type => :boolean, :required => false, :default => false
|
|
11
|
+
|
|
12
|
+
desc "add", "Add an fhcap repo"
|
|
13
|
+
|
|
14
|
+
shared_options :verbose, :name, :interactive
|
|
15
|
+
method_option 'url', :type => :string, :desc => "Repo url i.e. git@github.com:fheng/fhcap-dev.git"
|
|
16
|
+
method_option 'clusters-dir', :type => :string, :default => 'clusters', :desc => "Directlory in repo where cluster configs are stored i.e. organisations"
|
|
17
|
+
|
|
18
|
+
def add
|
|
19
|
+
require "fhcap/tasks/repo/add"
|
|
20
|
+
Tasks::Repo::Add.new(task_options(options.dup)).run
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc "remove", "Remove an fhcap repo"
|
|
24
|
+
|
|
25
|
+
shared_options :verbose, :name
|
|
26
|
+
|
|
27
|
+
def remove
|
|
28
|
+
require "fhcap/tasks/repo/remove"
|
|
29
|
+
Tasks::Repo::Remove.new(task_options(options.dup)).run
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "checkout", "Checkout a configured repo"
|
|
33
|
+
|
|
34
|
+
shared_options :verbose, :name
|
|
35
|
+
method_option 'git-ref', :type => :string, :desc => "fhcap git ref, can be a branch, tag or commit hash"
|
|
36
|
+
method_option 'remote', :type => :string, :default => 'origin', :desc => "Git remote to pull from"
|
|
37
|
+
|
|
38
|
+
def checkout
|
|
39
|
+
require 'fhcap/tasks/repo/checkout'
|
|
40
|
+
Tasks::Repo::Checkout.new(task_options(options.dup)).run
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc "list", "List configured repos"
|
|
44
|
+
|
|
45
|
+
def list
|
|
46
|
+
require 'fhcap/tasks/repo/list'
|
|
47
|
+
Tasks::Repo::List.new(task_options(options.dup)).run
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
module Fhcap
|
|
2
|
+
module ReposHelper
|
|
3
|
+
|
|
4
|
+
def repos_config
|
|
5
|
+
config.exists? && config[:repos] ? config[:repos] : {}
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def repos_dir
|
|
9
|
+
config[:repos_dir] || config.default_dir
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def repo_dir(name)
|
|
13
|
+
name = name.to_sym
|
|
14
|
+
if repos_config[name]
|
|
15
|
+
File.join(repos_dir, name.to_s)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def repo_cfg(name)
|
|
20
|
+
name = name.to_sym
|
|
21
|
+
repos_config[name]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def repo_paths
|
|
25
|
+
repos_config.collect do |name, cfg|
|
|
26
|
+
repo_dir(name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def repo_names
|
|
31
|
+
repos_config.collect do |name, cfg|
|
|
32
|
+
name.to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def repo_clusters_dir(name)
|
|
37
|
+
name = name.to_sym
|
|
38
|
+
if repos_config[name]
|
|
39
|
+
repos_config[name][:clusters_dir] || 'clusters'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def run_inside_repo_dir(repo_dir, cmd)
|
|
44
|
+
status = -1
|
|
45
|
+
thor.inside(repo_dir) do
|
|
46
|
+
thor.run(cmd, :capture => !@verbose)
|
|
47
|
+
status = $?.exitstatus
|
|
48
|
+
end
|
|
49
|
+
status == 0
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def find_data_bag(data_bag_name)
|
|
53
|
+
find_repo_item('data_bags', data_bag_name).first
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def find_data_bag_item(data_bag_name, data_bag_item)
|
|
57
|
+
find_repo_item('data_bags', data_bag_name, ensure_json_extension(data_bag_item)).first
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def find_environment(environment)
|
|
61
|
+
find_repo_item('environments', ensure_json_extension(environment)).first
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def find_role(role)
|
|
65
|
+
find_repo_item('roles', ensure_json_extension(role)).first
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def find_cluster(name)
|
|
69
|
+
find_cluster_with_repo(name).first
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def find_cluster_with_repo(name)
|
|
73
|
+
find_repo_item('clusters', ensure_json_extension(name)) || []
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def find_cluster_pwds(name)
|
|
77
|
+
find_cluster_pwds_with_repo(name).first
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def find_cluster_pwds_with_repo(name)
|
|
81
|
+
name = "#{name}_passwords"
|
|
82
|
+
find_repo_item('clusters', ensure_json_extension(name)) || []
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def find_repo_item(*args)
|
|
86
|
+
repo_names.each do |repo|
|
|
87
|
+
repo_args = args.dup
|
|
88
|
+
repo_item_dir_method = :"repo_#{repo_args.first}_dir"
|
|
89
|
+
repo_args[0] = respond_to?(repo_item_dir_method) ? send(repo_item_dir_method, repo) : repo_args.first
|
|
90
|
+
item_path = File.join(repo_dir(repo), repo_args)
|
|
91
|
+
if Dir.exists?(item_path) || File.exists?(item_path)
|
|
92
|
+
return item_path, repo
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def repo_cookbook_paths(dir_query='cookbooks')
|
|
99
|
+
@repo_cookbook_paths = {} unless @repo_cookbook_paths
|
|
100
|
+
unless @repo_cookbook_paths[dir_query]
|
|
101
|
+
@repo_cookbook_paths[dir_query] = []
|
|
102
|
+
repo_paths.each do |repo_dir|
|
|
103
|
+
thor.inside(repo_dir) do
|
|
104
|
+
Dir.glob('*').each do |f|
|
|
105
|
+
if f && File.directory?(f) && f =~ /#{dir_query}/
|
|
106
|
+
@repo_cookbook_paths[dir_query] << File.join(repo_dir, f)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
@repo_cookbook_paths[dir_query]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def get_cookbook_versions(options)
|
|
116
|
+
cookbook_versions = {}
|
|
117
|
+
get_cookbooks(options).each do |name|
|
|
118
|
+
version = get_cookbook_meta(name).version
|
|
119
|
+
cookbook_versions[name] = version
|
|
120
|
+
yield name, version if block_given?
|
|
121
|
+
end
|
|
122
|
+
cookbook_versions
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def get_cookbooks(options, default=nil, paths=repo_cookbook_paths)
|
|
126
|
+
if options[:modified]
|
|
127
|
+
get_modified_cookbooks(options, paths)
|
|
128
|
+
else
|
|
129
|
+
options[:cookbooks] || (default || cookbook_loader(paths).cookbook_names)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def get_modified_cookbooks(options, paths=repo_cookbook_paths)
|
|
134
|
+
modified = []
|
|
135
|
+
cookbook_loader(paths).cookbook_names.each do |name|
|
|
136
|
+
cookbook_dir = cookbook_loader.cookbooks_by_name[name].root_dir
|
|
137
|
+
modified << name if modified?(cookbook_dir)
|
|
138
|
+
end
|
|
139
|
+
modified
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def get_cookbook_meta(name, paths=repo_cookbook_paths)
|
|
143
|
+
cookbook_loader(paths).metadata[name]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def get_cookbook_deps(name, dependencies, options)
|
|
147
|
+
unless dependencies[name]
|
|
148
|
+
require_chef_deps
|
|
149
|
+
Dir.chdir(cookbook_loader.cookbooks_by_name[name].root_dir) do
|
|
150
|
+
::Chef::Knife::Deps.load_deps
|
|
151
|
+
knife_deps = ::Chef::Knife::Deps.new(["."])
|
|
152
|
+
knife_deps.configure_chef
|
|
153
|
+
Chef::Config[:cookbook_path] = repo_cookbook_paths
|
|
154
|
+
|
|
155
|
+
entries = ::Chef::ChefFS::FileSystem.list(knife_deps.local_fs, ::Chef::ChefFS::FilePattern.new("/cookbooks/#{name}/."))
|
|
156
|
+
entries.each do |entry|
|
|
157
|
+
get_entry_dependencies(entry, dependencies, knife_deps, options)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
dependencies
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def get_entry_dependencies(entry, dependencies, knife_deps, options)
|
|
165
|
+
unless dependencies[entry.name]
|
|
166
|
+
cwd = Pathname.new(options[:cwd] || Dir.pwd)
|
|
167
|
+
dependencies[entry.name] = Pathname.new(entry.file_path).relative_path_from(cwd)
|
|
168
|
+
child_deps = knife_deps.get_dependencies(entry)
|
|
169
|
+
child_deps.each do |child|
|
|
170
|
+
child_entry = ::Chef::ChefFS::FileSystem.resolve_path(knife_deps.local_fs, child)
|
|
171
|
+
get_entry_dependencies(child_entry, dependencies, knife_deps, options)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def modified?(path, since='origin/master')
|
|
177
|
+
stat = Dir.chdir(path) do
|
|
178
|
+
`git diff #{since} -- #{path}`
|
|
179
|
+
end
|
|
180
|
+
!stat.empty?
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def is_dirty?(file)
|
|
184
|
+
stat = Dir.chdir(File.dirname(file)) do
|
|
185
|
+
`git status #{file} --porcelain`
|
|
186
|
+
end
|
|
187
|
+
!stat.empty?
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
def cookbook_loader(paths=repo_cookbook_paths)
|
|
193
|
+
@cookbook_loader = {} unless @cookbook_loader
|
|
194
|
+
unless @cookbook_loader[paths]
|
|
195
|
+
require_chef_deps
|
|
196
|
+
@cookbook_loader[paths] = ::Chef::CookbookLoader.new(paths)
|
|
197
|
+
@cookbook_loader[paths].load_cookbooks
|
|
198
|
+
end
|
|
199
|
+
@cookbook_loader[paths]
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def ensure_json_extension(item)
|
|
203
|
+
"#{item.split('.').first}.json"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def require_chef_deps
|
|
207
|
+
unless @chef_deps_loaded
|
|
208
|
+
require 'chef/knife'
|
|
209
|
+
require 'chef/knife/deps'
|
|
210
|
+
require 'chef/chef_fs/config'
|
|
211
|
+
require 'chef/cookbook_loader'
|
|
212
|
+
@chef_deps_loaded = true
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'fhcap/tasks/task_base'
|
|
2
|
+
require 'chef'
|
|
3
|
+
require 'chef/knife'
|
|
4
|
+
|
|
5
|
+
module Fhcap
|
|
6
|
+
module Tasks
|
|
7
|
+
module Chef
|
|
8
|
+
class ChefTaskBase < TaskBase
|
|
9
|
+
|
|
10
|
+
def select_chef_server(environment, chef_server, fail_on_missing=true)
|
|
11
|
+
#ToDo Look at a better way of doing this rather than using a global variable
|
|
12
|
+
$selected_chef_server = {} unless $selected_chef_server
|
|
13
|
+
unless $selected_chef_server[environment]
|
|
14
|
+
if chef_server
|
|
15
|
+
$selected_chef_server[environment] = chef_server
|
|
16
|
+
else
|
|
17
|
+
chef_servers = chef_servers_for_environment(environment)
|
|
18
|
+
if chef_servers.empty?
|
|
19
|
+
exit_with_error("Unable to locate chef server for #{environment}") if fail_on_missing
|
|
20
|
+
elsif chef_servers.length == 1
|
|
21
|
+
$selected_chef_server[environment] = chef_servers.first
|
|
22
|
+
else
|
|
23
|
+
server = thor.ask("Multiple servers configured for environment '#{environment}'. Which one should be used?", {:limited_to => chef_servers})
|
|
24
|
+
$selected_chef_server[environment] = server
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
$selected_chef_server[environment]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def chef_servers_for_environment(environment)
|
|
32
|
+
chef_server_environments.collect do |server, environments|
|
|
33
|
+
server.to_s if environments.include? environment
|
|
34
|
+
end.compact
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def chef_server_environments
|
|
38
|
+
unless @chef_server_environments
|
|
39
|
+
@chef_server_environments = {}
|
|
40
|
+
config[:knife].each do |name, cfg|
|
|
41
|
+
cmd = "environment list -F json"
|
|
42
|
+
resp = run_knife_cmd(cmd, name)
|
|
43
|
+
envs = JSON.parse(resp)
|
|
44
|
+
@chef_server_environments[name] = envs
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
@chef_server_environments
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def knife_config_dir
|
|
51
|
+
config[:knife_dir] || File.join(config.default_dir, '.chef')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def knife_config_file_for(name)
|
|
55
|
+
File.join(knife_config_dir, "knife-#{name}.rb")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def run_knife_ssh_cmd(query, cmd, server, options)
|
|
59
|
+
user = options[:knife_user] || 'hadmin'
|
|
60
|
+
attr = options[:knife_attr] || 'cloud.public_ipv4'
|
|
61
|
+
knife_options = options[:knife_options]
|
|
62
|
+
run_knife_cmd("ssh \"#{query}\" \"#{cmd}\" -x #{user} -a #{attr} #{knife_options}", server, false)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run_knife_cmd(cmd, server, capture=true)
|
|
66
|
+
cmd = "cd #{File.expand_path("..", knife_config_dir)} && knife #{cmd} -c #{knife_config_file_for(server)}"
|
|
67
|
+
resp = thor.run(cmd, :capture => capture)
|
|
68
|
+
thor.say resp if verbose && !capture
|
|
69
|
+
resp
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def run_chef_client_cmd(cmd, server, capture=false)
|
|
73
|
+
cmd = "cd #{File.expand_path("..", knife_config_dir)} && chef-client -z #{cmd} -c #{knife_config_file_for(server)}"
|
|
74
|
+
resp = thor.run(cmd, :capture => capture)
|
|
75
|
+
thor.say resp if verbose && !capture
|
|
76
|
+
resp
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|