fhcap-cli 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/fhcap-cli.gemspec +2 -1
- data/lib/cookbooks/provision/libraries/provision.rb +26 -11
- data/lib/cookbooks/provision/recipes/aws_cluster_create.rb +7 -0
- data/lib/cookbooks/provision/recipes/aws_cluster_create_elb.rb +6 -1
- data/lib/cookbooks/provision/recipes/aws_cluster_destroy.rb +17 -16
- data/lib/cookbooks/provision/recipes/cluster_bootstrap.rb +4 -0
- data/lib/cookbooks/provision/recipes/cluster_bootstrap_instances.rb +37 -0
- data/lib/cookbooks/provision/recipes/cluster_create_instances.rb +11 -9
- data/lib/cookbooks/provision/recipes/cluster_provision_instances.rb +12 -11
- data/lib/cookbooks/provision/recipes/galera_reset_cluster.rb +40 -36
- data/lib/cookbooks/provision/recipes/mongo_reset_cluster.rb +10 -9
- data/lib/cookbooks/provision/recipes/rabbitmq_reset_cluster.rb +3 -1
- data/lib/extensions/chef/solr/query/regexpable_query.rb +17 -0
- data/lib/fhcap/chef-dk/chef_runner.rb +4 -1
- data/lib/fhcap/cluster.rb +66 -14
- data/lib/fhcap/cookbook.rb +1 -0
- data/lib/fhcap/kitchen.rb +27 -4
- data/lib/fhcap/provider.rb +1 -1
- data/lib/fhcap/repos_helper.rb +1 -1
- data/lib/fhcap/tasks/chef/chef_task_base.rb +3 -1
- data/lib/fhcap/tasks/chef/chef_zero_server.rb +1 -0
- data/lib/fhcap/tasks/chef/cookbook/update_version.rb +1 -2
- data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task_base.rb +19 -4
- data/lib/fhcap/tasks/chef/provisioning/create.rb +6 -3
- data/lib/fhcap/tasks/cluster/cluster_task_base.rb +1 -0
- data/lib/fhcap/tasks/cluster/create.rb +4 -201
- data/lib/fhcap/tasks/cluster/create_dns_records.rb +108 -0
- data/lib/fhcap/tasks/cluster/create_environment.rb +1 -0
- data/lib/fhcap/tasks/cluster/generate.rb +135 -0
- data/lib/fhcap/tasks/provider/add.rb +11 -0
- data/lib/fhcap/version.rb +1 -1
- data/spec/fhcap/tasks/cluster/create_dns_records_spec.rb +64 -0
- data/spec/fhcap/tasks/cluster/create_spec.rb +34 -13
- data/spec/fhcap/tasks/cluster/generate_spec.rb +44 -0
- data/templates/chef/environment_core.json.erb +8 -3
- data/templates/chef/environment_farm.json.erb +5 -0
- data/templates/chef/environment_mbaas.json.erb +11 -2
- data/templates/chef/environment_single.json.erb +17 -8
- data/templates/cluster/aws/common.json.erb +1 -1
- data/templates/cluster/aws/core-3node.json.erb +14 -2
- data/templates/cluster/aws/core-small-9node.json.erb +13 -1
- data/templates/cluster/aws/mbaas-3node.json.erb +14 -2
- data/templates/cluster/aws/single-blank.json.erb +6 -0
- data/templates/cluster/aws/single.json.erb +13 -1
- data/templates/cluster/openstack/core-3node.json.erb +1 -1
- data/templates/kitchen/kitchen.docker.yml.erb +0 -3
- data/templates/kitchen/kitchen.generate.yml.erb +0 -1
- data/templates/kitchen/kitchen.vagrant.yml.erb +37 -0
- metadata +29 -5
data/lib/fhcap/cluster.rb
CHANGED
@@ -8,34 +8,70 @@ module Fhcap
|
|
8
8
|
add_shared_option :verbose, :aliases => "-v", :desc => "Verbose output", :type => :boolean, :required => false, :default => false
|
9
9
|
add_shared_option :name, :type => :string, :required => true, :desc => "Cluster name"
|
10
10
|
add_shared_option :interactive, :aliases => "-i", :desc => "Interactive mode (Stops for input)", :type => :boolean, :required => false, :default => false
|
11
|
+
add_shared_option :'dry-run', :desc => "Dry Run only, nothing will be modified, but instead will display things that would be changed if this command was executed.", :type => :boolean, :required => false, :default => false
|
12
|
+
add_shared_option :'run-options', :type => :hash, :required => false, :desc => 'Run specific options, will be set as attributes on the node during the chef provisioning run!'
|
13
|
+
|
14
|
+
#Generate options
|
15
|
+
add_shared_option :template, :type => :string, :desc => "Cluster template i.e. [1, 3 , 5 node cluster setup, core or mbaas]", :enum => cluster_template_names
|
16
|
+
add_shared_option :domain, :type => :string, :desc => "host names to register with DNS / base host name"
|
17
|
+
add_shared_option :'ssl-cert', :type => :string, :desc => "ssl cert to use"
|
18
|
+
add_shared_option :'dns-provider-id', :type => :string, :desc => "DNS Provider Id"
|
19
|
+
add_shared_option :'repo', :type => :string, :desc => "Fhcap Repo where all config should be saved", :enum => repo_names
|
20
|
+
add_shared_option :'chef-server', :type => :string, :desc => "Chef Server to use", :enum => chef_server_names
|
21
|
+
add_shared_option :'provider-id', :type => :string, :desc => "Provider Id", :enum => provider_names_for('compute')
|
22
|
+
add_shared_option :'provider-config', :type => :hash, :desc => "Provider specific config"
|
23
|
+
|
24
|
+
desc "generate", "Generate/Update cluster configuration"
|
25
|
+
long_desc <<-LONGDESC
|
26
|
+
Generate/Update cluster configuration.
|
27
|
+
|
28
|
+
This task will generate/update all the configuration and chef files required to create a new cluster using the create task.
|
29
|
+
LONGDESC
|
30
|
+
|
31
|
+
shared_options :verbose, :name, :interactive, :'dry-run', :'run-options',
|
32
|
+
:template, :domain, :'ssl-cert', :'dns-provider-id', :'repo', :'chef-server', :'provider-id', :'provider-config'
|
33
|
+
|
34
|
+
def generate
|
35
|
+
require "fhcap/tasks/cluster/generate"
|
36
|
+
Tasks::Cluster::Generate.new(task_options(options.dup)).run
|
37
|
+
end
|
11
38
|
|
12
39
|
desc "create", "Create a new cluster"
|
13
40
|
|
14
|
-
shared_options :verbose, :name, :interactive
|
41
|
+
shared_options :verbose, :name, :interactive, :'dry-run',
|
42
|
+
:template, :domain, :'ssl-cert', :'dns-provider-id', :'repo', :'chef-server', :'provider-id', :'provider-config'
|
15
43
|
|
16
|
-
method_option
|
17
|
-
method_option 'git-ref', :type => :string, :desc => "fhcap git ref, can be a branch, tag or commit hash"
|
18
|
-
method_option 'git-remote', :type => :string, :desc => "git remote to use, default is the remote for the configured repos url"
|
19
|
-
method_option 'domain', :type => :string, :desc => "host names to register with DNS / base host name"
|
20
|
-
method_option 'ssl-cert', :type => :string, :desc => "ssl cert to use"
|
21
|
-
method_option 'dns-provider-id', :type => :string, :desc => "DNS Provider Id"
|
22
|
-
method_option 'repo', :type => :string, :desc => "Fhcap Repo where all config should be saved", :enum => repo_names
|
23
|
-
method_option 'chef-server', :type => :string, :desc => "Chef Server to use", :enum => chef_server_names
|
24
|
-
method_option 'provider-id', :type => :string, :desc => "Provider Id", :enum => provider_names_for('compute')
|
25
|
-
method_option 'provider-config', :type => :hash, :desc => "Provider specific config"
|
44
|
+
method_option :generate, :type => :boolean, :default => true, :desc => "Run generate task before create"
|
45
|
+
method_option :'git-ref', :type => :string, :desc => "fhcap git ref, can be a branch, tag or commit hash"
|
46
|
+
method_option :'git-remote', :type => :string, :desc => "git remote to use, default is the remote for the configured repos url"
|
26
47
|
create_steps = %w{repo-checkout cookbook-promote server-bootstrap create provision dns-record}
|
27
48
|
create_steps.each do |step|
|
28
49
|
method_option :"skip-#{step}", :type => :boolean, :default => false, :desc => "Skip #{step}"
|
29
50
|
end
|
30
51
|
|
31
52
|
def create
|
53
|
+
require "fhcap/tasks/cluster/generate"
|
32
54
|
require "fhcap/tasks/cluster/create"
|
55
|
+
Tasks::Cluster::Generate.new(task_options(options.dup)).run if options[:generate]
|
33
56
|
Tasks::Cluster::Create.new(task_options(options.dup)).run
|
34
57
|
end
|
35
58
|
|
36
|
-
desc "
|
59
|
+
desc "create_dns_records", "Create/Update a clusters DNS records"
|
60
|
+
long_desc <<-LONGDESC
|
61
|
+
Create/Update a clusters DNS records.
|
62
|
+
LONGDESC
|
37
63
|
|
38
64
|
shared_options :verbose, :name
|
65
|
+
|
66
|
+
def create_dns_records
|
67
|
+
require "fhcap/tasks/cluster/create_dns_records"
|
68
|
+
Tasks::Cluster::CreateDNSRecords.new(task_options(options.dup)).run
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "provision", "Provision a cluster"
|
72
|
+
|
73
|
+
shared_options :verbose, :name, :'dry-run', :'run-options'
|
74
|
+
|
39
75
|
method_option 'git-ref', :type => :string, :desc => "fhcap git ref, can be a branch, tag or commit hash"
|
40
76
|
method_option 'git-remote', :type => :string, :desc => "git remote to use, default is the remote for the configured repos url"
|
41
77
|
method_option 'nodes', :type => :string, :desc => "Query to pass to name"
|
@@ -74,7 +110,7 @@ module Fhcap
|
|
74
110
|
|
75
111
|
desc "destroy", "Destroy a cluster"
|
76
112
|
|
77
|
-
shared_options :verbose
|
113
|
+
shared_options :verbose, :'dry-run'
|
78
114
|
|
79
115
|
method_option 'name', :type => :string, :required => true, :desc => "Cluster name"
|
80
116
|
|
@@ -109,8 +145,24 @@ module Fhcap
|
|
109
145
|
end
|
110
146
|
|
111
147
|
desc "chef_provision", "[ADVANCED USAGE] Run a chef provisioning task against a particular cluster"
|
148
|
+
long_desc <<-LONGDESC
|
149
|
+
Allows the execution of any chef provisioning recipe on the given cluster.
|
150
|
+
Available recipes can be viewed here https://github.com/fheng/fhcap-cli/tree/master/lib/cookbooks/provision/recipes
|
112
151
|
|
113
|
-
|
152
|
+
With --run-options option, allows advanced configuration to be applied during the chef provisioning run.
|
153
|
+
These key:value pairs are added as attributes to the provisioning node and can alter the behaviour of the run.
|
154
|
+
|
155
|
+
env-regexp: Filter environments e.g. --run-options env-regexp:farm - Only environments with farm in the name will be acted upon (qed1-farm)
|
156
|
+
|
157
|
+
node-regexp: Filter nodes e.g. --run-options node-regexp:app - Only nodes with app in the name will be acted upon (qed1-core-app1, qed1-core-app2)
|
158
|
+
|
159
|
+
Examples:
|
160
|
+
|
161
|
+
fhcap cluster chef_provision --name qed1 --run-list provision::cluster_provision_instances
|
162
|
+
|
163
|
+
fhcap cluster chef_provision --name qed1 --run-list provision::cluster_provision_instances --run-options env-regexp:farm node-regexp:linux
|
164
|
+
LONGDESC
|
165
|
+
shared_options :verbose, :'dry-run', :'run-options'
|
114
166
|
|
115
167
|
method_option 'name', :type => :string, :required => true, :desc => 'Cluster name'
|
116
168
|
method_option 'run-list', :type => :array, :required => true, :desc => 'Chef Provisioning Run List i.e provision::cluster_provision'
|
data/lib/fhcap/cookbook.rb
CHANGED
@@ -35,6 +35,7 @@ module Fhcap
|
|
35
35
|
|
36
36
|
method_option 'level', :type => :string, :aliases => "-l", :desc => "Cookbook Bump level", :default => 'minor', :enum => %w{major minor patch}
|
37
37
|
method_option 'version', :type => :string, :aliases => "-v", :desc => "Version to set manually"
|
38
|
+
method_option 'base-branch', :type => :string, :default => 'origin/master', :desc => "Base branch to check modified cookbooks against"
|
38
39
|
|
39
40
|
def update
|
40
41
|
require "fhcap/tasks/chef/cookbook/update_version"
|
data/lib/fhcap/kitchen.rb
CHANGED
@@ -13,14 +13,16 @@ module Fhcap
|
|
13
13
|
|
14
14
|
add_shared_option :cookbooks, :aliases => "-c", :desc => "Apply to these Cookbooks", :type => :array
|
15
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}
|
16
|
+
add_shared_option :driver, :aliases => "-d", :desc => "Kitchen Driver", :type => :string, :default => 'openstack', :enum => %w{aws openstack docker vagrant}
|
17
17
|
add_shared_option :modified, :aliases => "-m", :desc => "Apply only to modified Cookbooks", :type => :boolean, :required => false, :default => false
|
18
18
|
add_shared_option :provisioner, :aliases => "-p", :desc => "Kitchen Provisioner", :type => :string, :default => 'chef_solo', :enum => %w{chef_solo chef_zero}
|
19
|
+
add_shared_option :'base-branch', :type => :string, :default => 'origin/master', :desc => "Base branch to check modified cookbooks against"
|
20
|
+
add_shared_option :'kitchen-options', :type => :hash, :default => {}, :desc => "Options to pass to kitchen command i.e. concurrency:10 = --concurrency=10 "
|
19
21
|
|
20
22
|
|
21
23
|
desc "generate", "Generate"
|
22
24
|
|
23
|
-
shared_options :cookbooks, :roles, :modified, :driver, :provisioner
|
25
|
+
shared_options :cookbooks, :roles, :modified, :driver, :provisioner, :'base-branch', :'kitchen-options'
|
24
26
|
method_option 'only', :type => :array, :default => nil, :desc => "Only include tests for cookbooks matching these names."
|
25
27
|
method_option 'exclude', :type => :array, :default => nil, :desc => "Exclude tests for cookbooks matching these names, takes precedence over 'only' option."
|
26
28
|
method_option 'clean', :type => :boolean, :default => true, :desc => "Clean the current generated kitchen prior to creating the new one"
|
@@ -128,16 +130,24 @@ module Fhcap
|
|
128
130
|
%w{create converge setup verify test list login destroy diagnose}.each do |cmd|
|
129
131
|
|
130
132
|
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
|
133
|
+
shared_options :cookbooks, :roles, :modified, :driver, :provisioner, :'base-branch', :'kitchen-options' if %w{create converge setup verify test list}.include? cmd
|
134
|
+
method_option :'log-level', :aliases => "-l", :desc => "Set the log level", :type => :string, :default => 'info', :enum => %w{debug info warn error fatal}
|
132
135
|
|
133
136
|
define_method(cmd) do |instance='all'|
|
137
|
+
kitchen_options = options[:'kitchen-options'] || {}
|
134
138
|
Fhcap::CLI::Kitchen.new.invoke(:generate, [], options) if options[:cookbooks] || options[:modified] || options[:roles]
|
135
139
|
if is_kitchen_generated?
|
136
140
|
Dir.chdir test_suite_dir do
|
137
141
|
cmd_options = options.dup
|
138
142
|
cmd_options['instance'] = instance
|
139
143
|
cmd_options['kitchen-yaml'] = test_suite_kitchen_yml
|
140
|
-
cmd_options['kitchen-options'] =
|
144
|
+
cmd_options['kitchen-options'] = kitchen_options_for(
|
145
|
+
default_kitchen_options.merge(
|
146
|
+
{:'log-level' => options[:'log-level']}
|
147
|
+
).merge(
|
148
|
+
JSON.parse(kitchen_options.to_json, {:symbolize_names => true})
|
149
|
+
)
|
150
|
+
)
|
141
151
|
run_kitchen_cmd(cmd, cmd_options)
|
142
152
|
end
|
143
153
|
else
|
@@ -149,6 +159,19 @@ module Fhcap
|
|
149
159
|
|
150
160
|
protected
|
151
161
|
|
162
|
+
def kitchen_options_for(opts)
|
163
|
+
opts.collect do |key,val|
|
164
|
+
"--#{key}=#{val}"
|
165
|
+
end.join(' ')
|
166
|
+
end
|
167
|
+
|
168
|
+
def default_kitchen_options
|
169
|
+
{
|
170
|
+
:concurrency => 10,
|
171
|
+
:'log-level' => 'info'
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
152
175
|
def test_suite_dir
|
153
176
|
File.join(config.default_dir, 'tmp', 'kitchen')
|
154
177
|
end
|
data/lib/fhcap/provider.rb
CHANGED
@@ -8,7 +8,7 @@ module Fhcap
|
|
8
8
|
add_shared_option :verbose, :aliases => "-v", :desc => "Verbose output", :type => :boolean, :required => false, :default => false
|
9
9
|
add_shared_option :interactive, :aliases => "-i", :desc => "Interactive mode (Stops for input)", :type => :boolean, :required => false, :default => false
|
10
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}
|
11
|
+
add_shared_option :type, :type => :string, :required => true, :desc => "Provider Type", :enum => %w{aws openstack dnsmadeeasy}
|
12
12
|
add_shared_option :credentials, :type => :hash, :desc => "Provider specific credentials"
|
13
13
|
|
14
14
|
desc "add", "Add a provider"
|
data/lib/fhcap/repos_helper.rb
CHANGED
@@ -134,7 +134,7 @@ module Fhcap
|
|
134
134
|
modified = []
|
135
135
|
cookbook_loader(paths).cookbook_names.each do |name|
|
136
136
|
cookbook_dir = cookbook_loader.cookbooks_by_name[name].root_dir
|
137
|
-
modified << name if modified?(cookbook_dir)
|
137
|
+
modified << name if modified?(cookbook_dir, options[:'base-branch'] || 'origin/master')
|
138
138
|
end
|
139
139
|
modified
|
140
140
|
end
|
@@ -21,7 +21,9 @@ module Fhcap
|
|
21
21
|
user = options[:knife_user] || 'hadmin'
|
22
22
|
attr = options[:knife_attr] || 'cloud.public_ipv4'
|
23
23
|
knife_options = options[:knife_options]
|
24
|
-
|
24
|
+
ssh_cmd = ["ssh \"#{query}\" \"#{cmd}\" -x #{user} -a #{attr} #{knife_options}"]
|
25
|
+
ssh_cmd << "--concurrency 1" if options[:series]
|
26
|
+
run_knife_cmd(ssh_cmd.join(' '), server, false)
|
25
27
|
end
|
26
28
|
|
27
29
|
def run_knife_cmd(cmd, server, capture=true)
|
@@ -16,7 +16,6 @@ module Fhcap
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def run
|
19
|
-
thor.say "Chef::Cookbook::UpdateVersion cookbook = #{name}", :yellow
|
20
19
|
cookbook = cookbook_loader.cookbooks_by_name[name]
|
21
20
|
metadata_file = cookbook.metadata_filenames.first
|
22
21
|
|
@@ -51,7 +50,7 @@ module Fhcap
|
|
51
50
|
new_contents = File.read(metadata_file).gsub(/(version\s+['"])[0-9\.]+(['"])/, "\\1#{new_version}\\2")
|
52
51
|
File.open(metadata_file, 'w') { |f| f.write(new_contents) }
|
53
52
|
|
54
|
-
thor.say "
|
53
|
+
thor.say "Updated #{cookbook.name} cookbook version to v#{new_version}!"
|
55
54
|
end
|
56
55
|
|
57
56
|
def bump_type
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fhcap/tasks/chef/chef_server_task'
|
2
2
|
require 'fhcap/tasks/chef/cookbook/archive'
|
3
3
|
require 'fhcap/chef-dk/chef_runner'
|
4
|
+
require 'deep_merge'
|
4
5
|
|
5
6
|
module Fhcap
|
6
7
|
module Tasks
|
@@ -8,7 +9,7 @@ module Fhcap
|
|
8
9
|
module Provisioning
|
9
10
|
class ChefProvisioningTaskBase < ChefServerTask
|
10
11
|
|
11
|
-
attr_reader :name, :cluster_config, :cluster_filepath
|
12
|
+
attr_reader :name, :cluster_config, :cluster_filepath, :run_options
|
12
13
|
|
13
14
|
def initialize(options)
|
14
15
|
super
|
@@ -20,12 +21,13 @@ module Fhcap
|
|
20
21
|
local_repo_path: repo_dir(@chef_repo),
|
21
22
|
local_repo_clusters_dir: repo_clusters_dir(@chef_repo),
|
22
23
|
chef_server_config: chef_server_config_hash_for(@chef_server),
|
23
|
-
provider_credentials:
|
24
|
+
provider_credentials: provider_credentials(@cluster_config[:provider_id]),
|
24
25
|
max_simultaneous: options[:series] ? 1 : nil
|
25
26
|
})
|
26
27
|
else
|
27
28
|
exit_with_error("Unknown cluster #{@name}")
|
28
29
|
end
|
30
|
+
@run_options = options[:'run-options']
|
29
31
|
end
|
30
32
|
|
31
33
|
def seed_cookbooks
|
@@ -35,10 +37,23 @@ module Fhcap
|
|
35
37
|
do_chef_run("provision::seed_cookbooks")
|
36
38
|
end
|
37
39
|
|
38
|
-
def
|
40
|
+
def default_run_options
|
41
|
+
{
|
42
|
+
max_simultaneous: options[:series] ? 1 : nil,
|
43
|
+
"env-regexp" => '.',
|
44
|
+
"node-regexp" => '.'
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_run_options(opts)
|
49
|
+
default_run_options.deep_merge!(opts)
|
50
|
+
end
|
51
|
+
|
52
|
+
def do_chef_run(run_list, dry_run=options[:'dry-run'])
|
39
53
|
cookbook_path = File.join(Fhcap.source_root, 'lib', 'cookbooks')
|
40
54
|
private_key_paths = [File.join(cluster_config[:local_repo_path], cluster_config[:local_repo_clusters_dir], 'key_pairs')]
|
41
|
-
|
55
|
+
node_attrs = cluster_config.deep_merge(get_run_options(run_options))
|
56
|
+
Fhcap::ChefRunner.new(cookbook_path, run_list, dry_run, node_attrs, private_key_paths).converge
|
42
57
|
end
|
43
58
|
|
44
59
|
end
|
@@ -14,8 +14,13 @@ module Fhcap
|
|
14
14
|
knife_download(repo_dir(chef_repo), chef_server, ['/nodes']) if local_chef_server?
|
15
15
|
|
16
16
|
unless options[:'skip-provision']
|
17
|
+
do_chef_run("provision::cluster_bootstrap")
|
17
18
|
seed_cookbooks if local_chef_server?
|
18
19
|
do_chef_run("provision::post_create_instances")
|
20
|
+
|
21
|
+
#Need to set run list correctly here after post create stuff since provision no longer does it
|
22
|
+
do_chef_run("provision::cluster_bootstrap")
|
23
|
+
|
19
24
|
do_chef_run("provision::cluster_provision")
|
20
25
|
end
|
21
26
|
end
|
@@ -25,6 +30,4 @@ module Fhcap
|
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
28
|
-
end
|
29
|
-
|
30
|
-
|
33
|
+
end
|
@@ -5,7 +5,7 @@ require 'fhcap/tasks/chef/environments/promote_cookbooks'
|
|
5
5
|
require 'fhcap/tasks/chef/environments/create'
|
6
6
|
require 'fhcap/tasks/chef/server/bootstrap'
|
7
7
|
require 'fhcap/tasks/repo/checkout'
|
8
|
-
require "fhcap/tasks/
|
8
|
+
require "fhcap/tasks/cluster/create_dns_records"
|
9
9
|
|
10
10
|
module Fhcap
|
11
11
|
module Tasks
|
@@ -15,35 +15,14 @@ module Fhcap
|
|
15
15
|
attr_reader :name, :cluster_config
|
16
16
|
|
17
17
|
def initialize(options)
|
18
|
-
super(options
|
19
|
-
@template = options[:template]
|
20
|
-
@repo = options[:'repo']
|
21
|
-
@provider_config = options[:'provider-config'] || {}
|
18
|
+
super(options)
|
22
19
|
@gitref = options[:'git-ref']
|
23
|
-
@domain = options[:domain]
|
24
|
-
@ssl_cert = options[:'ssl-cert']
|
25
|
-
@dns_provider_id = options[:'dns-provider-id']
|
26
|
-
@chef_server = options[:'chef-server']
|
27
|
-
@provider_id = options[:'provider-id']
|
28
20
|
@skip_repo_checkout = options[:'skip-repo-checkout']
|
29
21
|
@skip_cookbook_promote = options[:'skip-cookbook-promote']
|
30
22
|
@skip_server_bootstrap = options[:'skip-server-bootstrap']
|
31
23
|
@skip_dns_record = options[:'skip-dns-record']
|
32
24
|
@skip_create = options[:'skip-create']
|
33
25
|
@skip_provision = options[:'skip-provision']
|
34
|
-
|
35
|
-
@cluster_config = {
|
36
|
-
id: @name,
|
37
|
-
template: @template,
|
38
|
-
driver: "",
|
39
|
-
domain: @domain,
|
40
|
-
repo: @repo,
|
41
|
-
chef_server: @chef_server,
|
42
|
-
provider_id: @provider_id
|
43
|
-
}.merge(@cluster_config)
|
44
|
-
|
45
|
-
@cluster_config[:provider_config] = @cluster_config[:provider_config] || {}
|
46
|
-
@cluster_config[:provider_config].merge!(@provider_config)
|
47
26
|
end
|
48
27
|
|
49
28
|
def run
|
@@ -52,16 +31,6 @@ module Fhcap
|
|
52
31
|
#Checkout repos
|
53
32
|
checkout_repos unless @skip_repo_checkout
|
54
33
|
|
55
|
-
#Generate cluster config
|
56
|
-
generate_cluster_config
|
57
|
-
|
58
|
-
#Create environment files
|
59
|
-
create_cluster_environments
|
60
|
-
|
61
|
-
#Write config to disk
|
62
|
-
cluster_file = find_cluster(name) || File.join(repo_dir(cluster_config[:repo]), repo_clusters_dir(cluster_config[:repo]), "#{name}.json")
|
63
|
-
thor.create_file(cluster_file, JSON.pretty_generate(cluster_config))
|
64
|
-
|
65
34
|
#Chef Stuff
|
66
35
|
#Promote cookbooks
|
67
36
|
Chef::Environments::PromoteCookbooks.new(@options.dup.merge({:environments => cluster_environments})).run unless @skip_cookbook_promote
|
@@ -72,176 +41,10 @@ module Fhcap
|
|
72
41
|
#Provisioning create
|
73
42
|
Chef::Provisioning::Create.new(@options.dup.merge(chef_task_options)).run unless @skip_create
|
74
43
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def required_config
|
81
|
-
{
|
82
|
-
repo: {
|
83
|
-
msg: "In which repo should this clusters config and environment files be stored?",
|
84
|
-
options: {:limited_to => repo_names}
|
85
|
-
},
|
86
|
-
domain: {
|
87
|
-
msg: "Base domain/hostname (e.g. foo.skunkhenry.com) for this cluster?",
|
88
|
-
},
|
89
|
-
chef_server: {
|
90
|
-
options: {:limited_to => chef_server_names}
|
91
|
-
},
|
92
|
-
provider_id: {
|
93
|
-
options: {:limited_to => provider_names_for('compute')}
|
94
|
-
},
|
95
|
-
template: {
|
96
|
-
options: {:limited_to => cluster_template_names}
|
97
|
-
}
|
98
|
-
}
|
99
|
-
end
|
100
|
-
|
101
|
-
def aws_required_config
|
102
|
-
aws_regions = provider_config(@cluster_config[:provider_id])[:regions]
|
103
|
-
{
|
104
|
-
region: {
|
105
|
-
options: {:limited_to => aws_regions.keys.collect { |k| k.to_s }}
|
106
|
-
},
|
107
|
-
cidr: {
|
108
|
-
msg: "CIDR block for AWS VPC (e.g. 10.123.0.0/16)?",
|
109
|
-
}
|
110
|
-
}
|
44
|
+
#Create/Update DNS Records
|
45
|
+
Cluster::CreateDNSRecords.new(@options.dup.merge(chef_task_options)).run unless @skip_dns_record
|
111
46
|
end
|
112
47
|
|
113
|
-
def generate_cluster_config
|
114
|
-
ask_config(required_config, cluster_config)
|
115
|
-
cluster_config[:driver] = provider_type(cluster_config[:provider_id])
|
116
|
-
send(:"generate_cluster_config_#{cluster_config[:driver]}")
|
117
|
-
driver_template_file = File.join(Fhcap.source_root, 'templates', 'cluster', cluster_config[:driver], "common.json.erb")
|
118
|
-
driver_template_config = template_as_object(driver_template_file, cluster_config)
|
119
|
-
cluster_config.merge!(driver_template_config)
|
120
|
-
end
|
121
|
-
|
122
|
-
def generate_cluster_config_aws
|
123
|
-
ask_config(aws_required_config, cluster_config[:provider_config])
|
124
|
-
aws_regions = provider_config(cluster_config[:provider_id])[:regions]
|
125
|
-
cluster_config[:default_instance_options] = cluster_config[:default_instance_options] || {}
|
126
|
-
cluster_config[:default_instance_options][:image_id] = aws_regions[cluster_config[:provider_config][:region].to_sym][:base_image]
|
127
|
-
end
|
128
|
-
|
129
|
-
def generate_cluster_config_openstack
|
130
|
-
cluster_config[:default_instance_options] = cluster_config[:default_instance_options] || {}
|
131
|
-
cluster_config[:default_instance_options][:image_ref] = provider_config(@cluster_config[:provider_id])[:image_ref]
|
132
|
-
cluster_config[:default_instance_options][:flavor_ref] = provider_config(@cluster_config[:provider_id])[:flavor_ref]
|
133
|
-
cluster_config[:default_instance_options][:floating_ip_pool] = provider_config(@cluster_config[:provider_id])[:floating_ip_pool]
|
134
|
-
cluster_config[:default_instance_options][:ssh_username] = provider_config(@cluster_config[:provider_id])[:ssh_username]
|
135
|
-
end
|
136
|
-
|
137
|
-
def create_cluster_environments
|
138
|
-
env_template_file = File.join(Fhcap.source_root, 'templates', 'cluster', "#{cluster_config[:template]}.json.erb")
|
139
|
-
template_config = template_as_object(env_template_file, cluster_config)
|
140
|
-
|
141
|
-
template_config[:environments].each do |env|
|
142
|
-
env_template_file = File.join(Fhcap.source_root, 'templates', 'cluster', cluster_config[:driver], "#{env[:template]}.json.erb")
|
143
|
-
template_config = template_as_object(env_template_file, cluster_config)
|
144
|
-
|
145
|
-
env_domain = [env[:'domain-prefix'], cluster_config[:domain]].compact.join('.')
|
146
|
-
env_cfg = {
|
147
|
-
:name => name,
|
148
|
-
:'environment-name' => env[:name],
|
149
|
-
:domain => env_domain,
|
150
|
-
:template => env[:template],
|
151
|
-
:'cluster-config' => cluster_config,
|
152
|
-
:'skip-create-cluster-file' => true
|
153
|
-
}
|
154
|
-
|
155
|
-
CreateEnvironment.new(@options.dup.merge(env_cfg)).run
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def create_dns_record
|
160
|
-
send(:"create_dns_record_#{cluster_config[:driver]}")
|
161
|
-
end
|
162
|
-
|
163
|
-
def create_dns_record_aws
|
164
|
-
cluster_config[:environments].each do |env_name, env_cfg|
|
165
|
-
env_cfg[:load_balancers].each do |lb_name, lb_cfg|
|
166
|
-
if lb_cfg[:scheme] == "internet-facing"
|
167
|
-
begin
|
168
|
-
require 'aws-sdk'
|
169
|
-
|
170
|
-
cfg = provider_config(cluster_config[:provider_id])
|
171
|
-
creds = cfg[:credentials]
|
172
|
-
|
173
|
-
elb = Aws::ElasticLoadBalancing::Client.new(
|
174
|
-
region: cluster_config[:provider_config][:region],
|
175
|
-
access_key_id: creds[:'aws-access-key'],
|
176
|
-
secret_access_key: creds[:'aws-secret-key']
|
177
|
-
)
|
178
|
-
|
179
|
-
lb = load_balancer_name_for(name, env_name, lb_name)
|
180
|
-
resp = elb.describe_load_balancers({
|
181
|
-
load_balancer_names: [lb],
|
182
|
-
page_size: 1,
|
183
|
-
})
|
184
|
-
|
185
|
-
elb = resp.load_balancer_descriptions.first
|
186
|
-
thor.say "Found ELB name: #{elb.load_balancer_name}, dns_name: #{elb.dns_name}, zone_id: #{elb.canonical_hosted_zone_name_id}"
|
187
|
-
|
188
|
-
dns_record_cfg = {
|
189
|
-
domain: "*.#{env_cfg[:domain]}",
|
190
|
-
:"alias-target" => {
|
191
|
-
dns_name: elb.dns_name,
|
192
|
-
hosted_zone_id: elb.canonical_hosted_zone_name_id
|
193
|
-
}
|
194
|
-
}
|
195
|
-
Dns::CreateRecord.new(@options.dup.merge(dns_record_cfg)).run
|
196
|
-
rescue Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound => e
|
197
|
-
thor.say_status 'error', "LoadBalancer #{lb} not found, unable to create DNS Entry", :red
|
198
|
-
rescue Aws::ElasticLoadBalancing::Errors::ServiceError => e
|
199
|
-
thor.say_status 'error', e.message, :red
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end if env_cfg[:load_balancers]
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
def create_dns_record_openstack
|
207
|
-
cluster_config[:environments].each do |env_name, env_cfg|
|
208
|
-
env_name = "#{name}-#{env_name}"
|
209
|
-
knife_config_file = knife_config_file_for(cluster_config[:chef_server])
|
210
|
-
#ToDo [RHMAP-2898] Use knife object
|
211
|
-
nodes = JSON.parse(`knife search "chef_environment:#{env_name} AND recipes:nginx_feedhenry\\:\\:loadbalancer" -c #{knife_config_file} -F json -a name -a cloud.public_ipv4`)
|
212
|
-
|
213
|
-
lb_node = nodes['rows'].collect do |row|
|
214
|
-
name, attrs = row.first
|
215
|
-
attrs
|
216
|
-
end.first
|
217
|
-
|
218
|
-
if lb_node
|
219
|
-
if lb_node['cloud.public_ipv4']
|
220
|
-
dns_record_cfg = {
|
221
|
-
domain: "*.#{env_cfg[:domain]}",
|
222
|
-
ipaddress: lb_node['cloud.public_ipv4']
|
223
|
-
}
|
224
|
-
Dns::CreateRecord.new(@options.dup.merge(dns_record_cfg)).run
|
225
|
-
else
|
226
|
-
thor.say "Found lb node '#{lb_node['name']}', but was unable to retrieve it's IP!!}"
|
227
|
-
end
|
228
|
-
else
|
229
|
-
thor.say "Unable to locate lb node in cluster!!"
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def load_balancer_name_for(org_name, environment, lb_name)
|
235
|
-
fh_name_for('fh-lb', org_name, environment, lb_name)[0..31] #elb names have a max length of 32
|
236
|
-
end
|
237
|
-
|
238
|
-
def fh_name_for(*args)
|
239
|
-
args.collect do |str|
|
240
|
-
str.to_s.split('-')
|
241
|
-
end.flatten.uniq.join('-')
|
242
|
-
end
|
243
|
-
|
244
|
-
|
245
48
|
end
|
246
49
|
end
|
247
50
|
end
|