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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +1 -1
  5. data/fhcap-cli.gemspec +2 -1
  6. data/lib/cookbooks/provision/libraries/provision.rb +26 -11
  7. data/lib/cookbooks/provision/recipes/aws_cluster_create.rb +7 -0
  8. data/lib/cookbooks/provision/recipes/aws_cluster_create_elb.rb +6 -1
  9. data/lib/cookbooks/provision/recipes/aws_cluster_destroy.rb +17 -16
  10. data/lib/cookbooks/provision/recipes/cluster_bootstrap.rb +4 -0
  11. data/lib/cookbooks/provision/recipes/cluster_bootstrap_instances.rb +37 -0
  12. data/lib/cookbooks/provision/recipes/cluster_create_instances.rb +11 -9
  13. data/lib/cookbooks/provision/recipes/cluster_provision_instances.rb +12 -11
  14. data/lib/cookbooks/provision/recipes/galera_reset_cluster.rb +40 -36
  15. data/lib/cookbooks/provision/recipes/mongo_reset_cluster.rb +10 -9
  16. data/lib/cookbooks/provision/recipes/rabbitmq_reset_cluster.rb +3 -1
  17. data/lib/extensions/chef/solr/query/regexpable_query.rb +17 -0
  18. data/lib/fhcap/chef-dk/chef_runner.rb +4 -1
  19. data/lib/fhcap/cluster.rb +66 -14
  20. data/lib/fhcap/cookbook.rb +1 -0
  21. data/lib/fhcap/kitchen.rb +27 -4
  22. data/lib/fhcap/provider.rb +1 -1
  23. data/lib/fhcap/repos_helper.rb +1 -1
  24. data/lib/fhcap/tasks/chef/chef_task_base.rb +3 -1
  25. data/lib/fhcap/tasks/chef/chef_zero_server.rb +1 -0
  26. data/lib/fhcap/tasks/chef/cookbook/update_version.rb +1 -2
  27. data/lib/fhcap/tasks/chef/provisioning/chef_provisioning_task_base.rb +19 -4
  28. data/lib/fhcap/tasks/chef/provisioning/create.rb +6 -3
  29. data/lib/fhcap/tasks/cluster/cluster_task_base.rb +1 -0
  30. data/lib/fhcap/tasks/cluster/create.rb +4 -201
  31. data/lib/fhcap/tasks/cluster/create_dns_records.rb +108 -0
  32. data/lib/fhcap/tasks/cluster/create_environment.rb +1 -0
  33. data/lib/fhcap/tasks/cluster/generate.rb +135 -0
  34. data/lib/fhcap/tasks/provider/add.rb +11 -0
  35. data/lib/fhcap/version.rb +1 -1
  36. data/spec/fhcap/tasks/cluster/create_dns_records_spec.rb +64 -0
  37. data/spec/fhcap/tasks/cluster/create_spec.rb +34 -13
  38. data/spec/fhcap/tasks/cluster/generate_spec.rb +44 -0
  39. data/templates/chef/environment_core.json.erb +8 -3
  40. data/templates/chef/environment_farm.json.erb +5 -0
  41. data/templates/chef/environment_mbaas.json.erb +11 -2
  42. data/templates/chef/environment_single.json.erb +17 -8
  43. data/templates/cluster/aws/common.json.erb +1 -1
  44. data/templates/cluster/aws/core-3node.json.erb +14 -2
  45. data/templates/cluster/aws/core-small-9node.json.erb +13 -1
  46. data/templates/cluster/aws/mbaas-3node.json.erb +14 -2
  47. data/templates/cluster/aws/single-blank.json.erb +6 -0
  48. data/templates/cluster/aws/single.json.erb +13 -1
  49. data/templates/cluster/openstack/core-3node.json.erb +1 -1
  50. data/templates/kitchen/kitchen.docker.yml.erb +0 -3
  51. data/templates/kitchen/kitchen.generate.yml.erb +0 -1
  52. data/templates/kitchen/kitchen.vagrant.yml.erb +37 -0
  53. 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 'template', :type => :string, :desc => "Cluster template i.e. [1, 3 , 5 node cluster setup, core or mbaas]", :enum => cluster_template_names
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 "provision", "Provision a cluster"
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
- shared_options :verbose
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'
@@ -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'] = '--concurrency=10'
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
@@ -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"
@@ -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
- run_knife_cmd("ssh \"#{query}\" \"#{cmd}\" -x #{user} -a #{attr} #{knife_options}", server, false)
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)
@@ -1,4 +1,5 @@
1
1
  require 'chef_zero/server'
2
+ require 'extensions/chef/solr/query/regexpable_query'
2
3
 
3
4
  module Fhcap
4
5
  module Tasks
@@ -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 "Successfully bumped #{cookbook.name} to v#{new_version}!"
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: provider_credentials(@cluster_config[:provider_id]),
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 do_chef_run(run_list)
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
- Fhcap::ChefRunner.new(cookbook_path, run_list, cluster_config, private_key_paths).converge
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
@@ -1,4 +1,5 @@
1
1
  require 'fhcap/tasks/task_base'
2
+ require 'erubis'
2
3
 
3
4
  module Fhcap
4
5
  module Tasks
@@ -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/dns/create_record"
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, false)
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
- create_dns_record unless @skip_dns_record
76
- end
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