cheftacular 2.8.0 → 2.9.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cheftacular/README.md +92 -70
  3. data/lib/cheftacular/actions/check.rb +3 -2
  4. data/lib/cheftacular/actions/console.rb +8 -2
  5. data/lib/cheftacular/actions/db_console.rb +28 -4
  6. data/lib/cheftacular/actions/deploy.rb +6 -8
  7. data/lib/cheftacular/actions/log.rb +7 -2
  8. data/lib/cheftacular/actions/migrate.rb +16 -5
  9. data/lib/cheftacular/actions/run.rb +10 -3
  10. data/lib/cheftacular/actions/scale.rb +4 -1
  11. data/lib/cheftacular/actions/tail.rb +8 -3
  12. data/lib/cheftacular/cheftacular.rb +1 -1
  13. data/lib/cheftacular/cloud_provider.rb +5 -1
  14. data/lib/cheftacular/dns.rb +1 -1
  15. data/lib/cheftacular/error.rb +2 -2
  16. data/lib/cheftacular/file_system.rb +50 -0
  17. data/lib/cheftacular/getter.rb +1 -1
  18. data/lib/cheftacular/helper.rb +34 -5
  19. data/lib/cheftacular/initializer.rb +15 -25
  20. data/lib/cheftacular/parser.rb +2 -0
  21. data/lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb +4 -1
  22. data/lib/cheftacular/stateless_actions/arguments.rb +8 -3
  23. data/lib/cheftacular/stateless_actions/backups.rb +5 -2
  24. data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +8 -5
  25. data/lib/cheftacular/stateless_actions/check_cheftacular_yml_keys.rb +15 -1
  26. data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +9 -2
  27. data/lib/cheftacular/stateless_actions/chef_server.rb +5 -2
  28. data/lib/cheftacular/stateless_actions/cheftacular_config.rb +26 -4
  29. data/lib/cheftacular/stateless_actions/cheftacular_yml_help.rb +31 -0
  30. data/lib/cheftacular/stateless_actions/clean_cookbooks.rb +6 -37
  31. data/lib/cheftacular/stateless_actions/clear_caches.rb +9 -2
  32. data/lib/cheftacular/stateless_actions/client_list.rb +5 -2
  33. data/lib/cheftacular/stateless_actions/cloud.rb +4 -1
  34. data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +4 -1
  35. data/lib/cheftacular/stateless_actions/compile_audit_log.rb +4 -1
  36. data/lib/cheftacular/stateless_actions/compile_readme.rb +10 -1
  37. data/lib/cheftacular/stateless_actions/create_git_key.rb +4 -1
  38. data/lib/cheftacular/stateless_actions/disk_report.rb +5 -2
  39. data/lib/cheftacular/stateless_actions/environment.rb +5 -2
  40. data/lib/cheftacular/stateless_actions/file.rb +5 -2
  41. data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +5 -2
  42. data/lib/cheftacular/stateless_actions/full_bootstrap.rb +10 -2
  43. data/lib/cheftacular/stateless_actions/get_active_ssh_connections.rb +3 -2
  44. data/lib/cheftacular/stateless_actions/get_haproxy_log.rb +5 -2
  45. data/lib/cheftacular/stateless_actions/get_log_from_bag.rb +5 -2
  46. data/lib/cheftacular/stateless_actions/get_pg_pass.rb +5 -2
  47. data/lib/cheftacular/stateless_actions/get_shorewall_allowed_connections.rb +2 -1
  48. data/lib/cheftacular/stateless_actions/help.rb +28 -16
  49. data/lib/cheftacular/stateless_actions/initialize_cheftacular_yml.rb +4 -1
  50. data/lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb +4 -1
  51. data/lib/cheftacular/stateless_actions/knife_upload.rb +4 -1
  52. data/lib/cheftacular/stateless_actions/list_toggleable_roles.rb +5 -2
  53. data/lib/cheftacular/stateless_actions/location_aliases.rb +5 -2
  54. data/lib/cheftacular/stateless_actions/pass.rb +5 -2
  55. data/lib/cheftacular/stateless_actions/reinitialize.rb +4 -1
  56. data/lib/cheftacular/stateless_actions/remove_client.rb +9 -2
  57. data/lib/cheftacular/stateless_actions/replication_status.rb +4 -1
  58. data/lib/cheftacular/stateless_actions/reset_bag.rb +4 -1
  59. data/lib/cheftacular/stateless_actions/restart_swap.rb +4 -1
  60. data/lib/cheftacular/stateless_actions/role_toggle.rb +7 -4
  61. data/lib/cheftacular/stateless_actions/rvm.rb +4 -1
  62. data/lib/cheftacular/stateless_actions/server_update.rb +5 -2
  63. data/lib/cheftacular/stateless_actions/service.rb +4 -1
  64. data/lib/cheftacular/stateless_actions/slack.rb +4 -1
  65. data/lib/cheftacular/stateless_actions/test_env.rb +4 -1
  66. data/lib/cheftacular/stateless_actions/update_chef_client.rb +2 -1
  67. data/lib/cheftacular/stateless_actions/update_cloudflare_dns_from_cloud.rb +4 -1
  68. data/lib/cheftacular/stateless_actions/update_split_branches.rb +4 -1
  69. data/lib/cheftacular/stateless_actions/update_thecheftacularcookbook.rb +38 -0
  70. data/lib/cheftacular/stateless_actions/update_tld.rb +4 -1
  71. data/lib/cheftacular/stateless_actions/upload_nodes.rb +6 -3
  72. data/lib/cheftacular/stateless_actions/upload_roles.rb +4 -1
  73. data/lib/cheftacular/version.rb +1 -1
  74. data/lib/cloud_interactor/authentication.rb +3 -4
  75. data/lib/cloud_interactor/flavor.rb +7 -2
  76. data/lib/cloud_interactor/helpers.rb +5 -1
  77. data/lib/cloud_interactor/server/create.rb +7 -2
  78. data/lib/sshkit/actions/start_task.rb +9 -1
  79. metadata +6 -7
  80. data/bin/client-list +0 -4
  81. data/lib/cheftacular/stateless_actions/clean_sensu_plugins.rb +0 -19
@@ -1,10 +1,17 @@
1
1
  class Cheftacular
2
2
  class ActionDocumentation
3
3
  def migrate
4
- @config['documentation']['action'] << [
4
+ @config['documentation']['action'][__method__] ||= {}
5
+ @config['documentation']['action'][__method__]['long_description'] = [
5
6
  "`cft migrate` this command will grab the first alphabetical node for a repository " +
6
- "and run a migration that will hit the database primary server."
7
+ "and run a migration that will hit the database primary server.",
8
+
9
+ [
10
+ " 1. Currently only supports rails stacks."
11
+ ]
7
12
  ]
13
+
14
+ @config['documentation']['action'][__method__]['short_description'] = 'Creates a database migration on the current environment'
8
15
  end
9
16
  end
10
17
 
@@ -29,13 +36,15 @@ class Cheftacular
29
36
 
30
37
  puts("Beginning migration run for #{ n.name } (#{ n.public_ipaddress }) on role #{ options['role'] }") unless options['quiet']
31
38
 
32
- log_data, timestamp = start_task( n.name, n.public_ipaddress, n.run_list, "#{ bundle_command } exec rake db:migrate", options, locs, cheftacular)
39
+ log_data, timestamp, exit_status = start_task( n.name, n.public_ipaddress, n.run_list, "#{ bundle_command } exec rake db:migrate", options, locs, cheftacular)
33
40
 
34
- logs_bag_hash["#{ n.name }-migrate"] = { text: log_data.scrub_pretty_text, timestamp: timestamp }
41
+ logs_bag_hash["#{ n.name }-#{ __method__ }"] = { "text" => log_data.scrub_pretty_text, "timestamp" => timestamp, "exit_status" => exit_status }
35
42
  end
36
43
 
37
44
  @config['ChefDataBag'].save_logs_bag
38
45
 
46
+ @config['helper'].send_log_bag_hash_slack_notification(logs_bag_hash, __method__, 'Failing migration detected, please fix this and deploy again, exiting...')
47
+
39
48
  @options['run_migration_already'] = true
40
49
 
41
50
  #restart the servers again after a deploy with a migration just in case
@@ -49,7 +58,9 @@ class Cheftacular
49
58
  end
50
59
 
51
60
  def migrate_nodejs nodes=[]
52
- raise "Not yet implemented"
61
+ puts "Method #{ __method__ } is not yet implemented"
62
+
63
+ exit
53
64
  end
54
65
 
55
66
  def migrate_all nodes=[]
@@ -1,7 +1,8 @@
1
1
  class Cheftacular
2
2
  class ActionDocumentation
3
3
  def run
4
- @config['documentation']['action'] << [
4
+ @config['documentation']['action'][__method__] ||= {}
5
+ @config['documentation']['action'][__method__]['long_description'] = [
5
6
  "`cft run COMMAND [--all]` will trigger the command on the first server in the role. " +
6
7
  "Can be used to run rake commands or anything else.",
7
8
 
@@ -18,6 +19,8 @@ class Cheftacular
18
19
  'arguments in quotes like `cft run "rake -T"`'
19
20
  ]
20
21
  ]
22
+
23
+ @config['documentation']['action'][__method__]['short_description'] = 'Runs a command on the current environment for the current repository'
21
24
  end
22
25
  end
23
26
 
@@ -33,6 +36,8 @@ class Cheftacular
33
36
  #must have rails stack to run migrations and not be a db, only want ONE node
34
37
  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: "role[#{ @options['role'] }]" }], !@options['run_on_all'] )
35
38
 
39
+ nodes = @config['parser'].exclude_nodes( nodes, [{ if: "role[#{ @options['negative_role'] }]" }]) if @options['negative_role']
40
+
36
41
  #this must always precede on () calls so they have the instance variables they need
37
42
  options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars
38
43
 
@@ -41,12 +46,14 @@ class Cheftacular
41
46
 
42
47
  puts("Beginning task run for #{ n.name } (#{ n.public_ipaddress }) on role #{ options['role'] }") unless options['quiet']
43
48
 
44
- log_data, timestamp = start_task( n.name, n.public_ipaddress, n.run_list, "#{ bundle_command } exec #{ command }", options, locs, cheftacular)
49
+ log_data, timestamp, exit_status = start_task( n.name, n.public_ipaddress, n.run_list, "#{ bundle_command } exec #{ command }", options, locs, cheftacular)
45
50
 
46
- logs_bag_hash["#{ n.name }-run"] = { text: log_data.scrub_pretty_text, timestamp: timestamp }
51
+ logs_bag_hash["#{ n.name }-#{ __method__ }"] = { "text" => log_data.scrub_pretty_text, "timestamp" => timestamp, "exit_status" => exit_status }
47
52
  end
48
53
 
49
54
  @config['ChefDataBag'].save_logs_bag
55
+
56
+ @config['helper'].send_log_bag_hash_slack_notification(logs_bag_hash, __method__, 'Failing command detected, exiting...')
50
57
  end
51
58
 
52
59
  def run_nodejs
@@ -3,7 +3,8 @@
3
3
  class Cheftacular
4
4
  class ActionDocumentation
5
5
  def scale
6
- @config['documentation']['action'] << [
6
+ @config['documentation']['action'][__method__] ||= {}
7
+ @config['documentation']['action'][__method__]['long_description'] = [
7
8
  "`cft scale up|down [NUM_TO_SCALE]` will add (or remove) NUM_TO_SCALE servers from the server array. " +
8
9
  "This command will not let you scale down below 1 server.",
9
10
 
@@ -13,6 +14,8 @@ class Cheftacular
13
14
  "A failed build may require the server to be destroyed / examined by a DevOps engineer."
14
15
  ]
15
16
  ]
17
+
18
+ @config['documentation']['action'][__method__]['short_description'] = 'Scales an environment up or down (relies on roles)'
16
19
  end
17
20
  end
18
21
 
@@ -1,7 +1,8 @@
1
1
  class Cheftacular
2
2
  class ActionDocumentation
3
3
  def tail
4
- @config['documentation']['action'] << [
4
+ @config['documentation']['action'][__method__] ||= {}
5
+ @config['documentation']['action'][__method__]['long_description'] = [
5
6
  "`cft tail [PATTERN_TO_MATCH]` will tail the logs (return continuous output) of the first node if finds " +
6
7
  "that has an application matching the repository running on it. Currently only supports rails stacks",
7
8
 
@@ -15,6 +16,8 @@ class Cheftacular
15
16
  " 3. if the `PATTERN_TO_MATCH` argument exists, the tail will only return entries that have that pattern rather than everything written to the file."
16
17
  ]
17
18
  ]
19
+
20
+ @config['documentation']['action'][__method__]['short_description'] = 'Tails the logs of the first node found for the current repository'
18
21
  end
19
22
  end
20
23
 
@@ -26,6 +29,8 @@ class Cheftacular
26
29
 
27
30
  nodes = @config['parser'].exclude_nodes( nodes, [{ unless: "role[#{ @options['role'] }]" }], true )
28
31
 
32
+ nodes = @config['parser'].exclude_nodes( nodes, [{ if: "role[#{ @options['negative_role'] }]" }], true) if @options['negative_role']
33
+
29
34
  nodes.each do |n|
30
35
  puts("Beginning tail run for #{ n.name } (#{ n.public_ipaddress }) on role #{ @options['role'] }") unless @options['quiet']
31
36
 
@@ -50,12 +55,12 @@ class Cheftacular
50
55
 
51
56
  #special servers should be listed first as most of them will have web role
52
57
  log_loc = "#{ @config['cheftacular']['base_file_path'] }/#{ @options['repository'] }/current/log/#{ true_env }.log"
53
-
58
+
54
59
  `ssh -oStrictHostKeyChecking=no -tt #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } "#{ @config['helper'].sudo(ip_address) } tail -f #{ log_loc } #{ get_tail_grep_string(pattern_to_match) }" > /dev/tty`
55
60
  end
56
61
 
57
62
  def get_tail_grep_string pattern_to_match=''
58
- "| grep -i -E #{ pattern_to_match }" unless pattern_to_match.blank?
63
+ "| grep -i -E \\\"#{ pattern_to_match }\\\"" unless pattern_to_match.blank?
59
64
  end
60
65
  end
61
66
  end
@@ -39,7 +39,7 @@ class Cheftacular
39
39
  if @config['helper'].is_initialization_command?(ARGV[0])
40
40
  @options['command'] = ARGV[0] #this is normally set by parse_context but that is not run for initialization commands
41
41
  else
42
- @config['stateless_action'].cheftacular_config('sync') unless @config['helper'].running_on_chef_node?
42
+ #@config['stateless_action'].cheftacular_config('sync') unless @config['helper'].running_on_chef_node?
43
43
 
44
44
  @config['stateless_action'].initialize_data_bag_contents(@options['env']) #ensure basic structure are always maintained before each run
45
45
 
@@ -7,11 +7,15 @@ class Cheftacular
7
7
 
8
8
  #public address, private address
9
9
  def parse_addresses_from_server_create_hash server_hash
10
+ ap server_hash
10
11
  case @options['preferred_cloud']
11
12
  when 'rackspace'
12
13
  [server_hash['ipv4_address'], server_hash['addresses']['private'][0]['addr']]
13
14
  when 'digitalocean'
14
- [server_hash['public_ip_address'], server_hash['private_ip_address']]
15
+ [
16
+ server_hash['networks']['v4'].select { |hash| hash['type'] == 'public' }.first['ip_address'],
17
+ server_hash['networks']['v4'].select { |hash| hash['type'] == 'private' }.first['ip_address']
18
+ ]
15
19
  else raise "CRITICAL! Encountered unsupported preferred cloud #{ @options['preferred_cloud'] }"
16
20
  end
17
21
  end
@@ -62,7 +62,7 @@ class Cheftacular
62
62
  record_hash['SRV_weight'],
63
63
  record_hash['SRV_port'],
64
64
  record_hash['SRV_target'],
65
- (record_hash['activate_cloudflare'] ? 0 : 1) #service_mode
65
+ (record_hash['activate_cloudflare'] ? 1 : 0) #service_mode
66
66
  )
67
67
 
68
68
  print 'create'.ljust(20, '_')
@@ -20,10 +20,10 @@ class Cheftacular
20
20
  nodes
21
21
  end
22
22
 
23
- def exception_output message, exception='', exit_on_call=true, suppress_error_output=false
23
+ def exception_output message, exception=nil, exit_on_call=true, suppress_error_output=false
24
24
  puts "#{ message }\n"
25
25
 
26
- puts("Error message: #{ exception }\n#{ exception.backtrace.join("\n") }") unless suppress_error_output
26
+ puts("Error message: #{ exception }\n#{ exception.backtrace.join("\n") }") if !exception.nil? && !suppress_error_output
27
27
 
28
28
  exit if exit_on_call
29
29
  end
@@ -89,6 +89,8 @@ class Cheftacular
89
89
  FileUtils.rm_rf("#{ base_dir }/#{ entry }") if File.exists?("#{ base_dir }/#{ entry }") && File.directory?("#{ base_dir }/#{ entry }")
90
90
  when 'current-audit-only'
91
91
  FileUtils.rm("#{ base_dir }/#{ entry }") if File.file?("#{ base_dir }/#{ entry }") && entry.include?(Time.now.strftime("%Y%m%d"))
92
+ else
93
+ puts "Warning, received unknown mode (#{ mode })! Please post your logs as an issue on github!"
92
94
  end
93
95
 
94
96
  if File.exists?("#{ base_dir }/#{ entry }") && File.directory?("#{ base_dir }/#{ entry }")
@@ -135,6 +137,54 @@ class Cheftacular
135
137
  File.open( File.join(@config['locs']['chef-repo'], "config", to_be_created_filename), "w") { |f| f.write(File.read(File.join(@config['locs']['examples'], example_filename))) }
136
138
  end
137
139
 
140
+ def parse_latest_berkshelf_cookbook_versions berkshelf_cookbooks={}
141
+
142
+ Dir.foreach(@config['locs']['berks']) do |berkshelf_cookbook|
143
+ next if is_junk_filename?(berkshelf_cookbook)
144
+ use_current_cookbook = false
145
+
146
+ true_cookbook_name = berkshelf_cookbook.rpartition('-').first
147
+ cookbook_version = parse_version_from_berkshelf_cookbook(berkshelf_cookbook)
148
+
149
+ #get only the latest version, berkshelf pulls in multiple commits from git repos for SOME REASON
150
+ use_current_cookbook = !berkshelf_cookbooks.has_key?(true_cookbook_name)
151
+ use_current_cookbook = @config['helper'].is_higher_version?(cookbook_version, berkshelf_cookbooks[true_cookbook_name]['version']) if berkshelf_cookbooks.has_key?(true_cookbook_name)
152
+
153
+ if use_current_cookbook
154
+ berkshelf_cookbooks[true_cookbook_name] ||= {}
155
+ berkshelf_cookbooks[true_cookbook_name]['version'] = cookbook_version
156
+ berkshelf_cookbooks[true_cookbook_name]['location'] = berkshelf_cookbook
157
+ berkshelf_cookbooks[true_cookbook_name]['mtime'] = File.mtime(File.expand_path("#{ @config['locs']['berks'] }/#{ berkshelf_cookbook }"))
158
+ end
159
+ end
160
+
161
+ berkshelf_cookbooks
162
+ end
163
+
164
+ def parse_chef_repo_cookbook_versions chef_repo_cookbooks={}
165
+ Dir.foreach(@config['locs']['cookbooks']) do |chef_repo_cookbook|
166
+ next if is_junk_filename?(chef_repo_cookbook)
167
+
168
+ new_name = chef_repo_cookbook.rpartition('-').first
169
+
170
+ chef_repo_cookbooks[chef_repo_cookbook] = if File.exists?(File.expand_path("#{ @config['locs']['cookbooks'] }/#{ chef_repo_cookbook }/metadata.rb"))
171
+ File.read(File.expand_path("#{ @config['locs']['cookbooks'] }/#{ chef_repo_cookbook }/metadata.rb")).gsub('"',"'").gsub(/^version[\s]*('\d[.\d]+')/).peek[/('\d[.\d]+')/].gsub("'",'')
172
+ else
173
+ JSON.parse(File.read(File.expand_path("#{ @config['locs']['cookbooks'] }/#{ chef_repo_cookbook }/metadata.json"))).to_hash['version']
174
+ end
175
+ end
176
+
177
+ chef_repo_cookbooks
178
+ end
179
+
180
+ def parse_version_from_berkshelf_cookbook berkshelf_cookbook
181
+ if File.exists?(File.expand_path("#{ @config['locs']['berks'] }/#{ berkshelf_cookbook }/metadata.rb"))
182
+ File.read(File.expand_path("#{ @config['locs']['berks'] }/#{ berkshelf_cookbook }/metadata.rb")).gsub('"',"'").gsub(/^version[\s]*('\d[.\d]+')/).peek[/('\d[.\d]+')/].gsub("'",'')
183
+ else
184
+ berkshelf_cookbook.split('-').last
185
+ end
186
+ end
187
+
138
188
  private
139
189
  def current_file_path file_name, use_timestamp=true
140
190
  File.join( @config['locs']['app-root'], 'tmp', @config['helper'].declassify, ( use_timestamp ? "#{ Time.now.strftime("%Y%m%d") }-#{ file_name }" : file_name ))
@@ -23,7 +23,7 @@ class Cheftacular
23
23
  true_obj = if !file_cache_nodes.empty? && @config['parser'].array_of_nodes_contains_node_name?(file_cache_nodes, n.name)
24
24
  file_cache_nodes[@config['parser'].index_of_node_name_in_array_of_nodes(file_cache_nodes, n.name)]
25
25
  else
26
- @config['filesystem'].cleanup_file_caches('current')
26
+ @config['filesystem'].cleanup_file_caches('current-nodes')
27
27
 
28
28
  @config['ridley'].node.find(n.name)
29
29
  end
@@ -30,8 +30,8 @@ class Cheftacular
30
30
 
31
31
  def is_initialization_command? command=''
32
32
  command ||= ''
33
-
34
- @config['initialization_action'].public_methods(false).include?(command.to_sym)
33
+
34
+ @config['initialization_action'].public_methods(false).include?(command.to_sym) || command.blank?
35
35
  end
36
36
 
37
37
  def running_on_chef_node? ret = false
@@ -140,12 +140,13 @@ class Cheftacular
140
140
  def compile_documentation_lines mode, out=[]
141
141
  doc_arr = case mode
142
142
  when 'action' then @config['documentation']['action']
143
- when 'application' then @config['documentation']['action'] + @config['documentation']['application']
143
+ when 'application' then @config['documentation']['application'].merge(@config['documentation']['action'])
144
144
  when 'stateless_action' then @config['documentation']['stateless_action']
145
- when 'devops' then @config['documentation']['action'] + @config['documentation']['stateless_action']
145
+ when 'devops' then @config['documentation']['stateless_action'].merge(@config['documentation']['action'])
146
146
  end
147
147
 
148
- count = 1
148
+ doc_arr = doc_arr.to_a.map { |doc| doc[1]['long_description'] }
149
+ count = 1
149
150
 
150
151
  doc_arr.sort {|a, b| a[0] <=> b[0]}.flatten(1).each do |line|
151
152
  out << "#{ count }. #{ line }" if line.class.to_s == 'String'
@@ -158,6 +159,12 @@ class Cheftacular
158
159
  out
159
160
  end
160
161
 
162
+ def compile_short_context_descriptions documentation_hash, padding_length=25, out=[]
163
+ out << documentation_hash.to_a.map { |doc| "#{ doc[0].to_s.ljust(padding_length, '_') }_#{ doc[1]['short_description'] }" }
164
+
165
+ out.flatten.sort {|a, b| a[0] <=> b[0]}.join("\n\n")
166
+ end
167
+
161
168
  #compares how close str1 is to str2
162
169
  def compare_strings str1, str2
163
170
  str1_chars = str1.split('').uniq
@@ -260,6 +267,28 @@ class Cheftacular
260
267
 
261
268
  puts("Completed rvm.sh installation into /etc/profile.d/rvm.sh") unless @options['quiet']
262
269
  end
270
+
271
+ def send_log_bag_hash_slack_notification logs_bag_hash, method, on_failing_exit_status_message=''
272
+ if @config['cheftacular']['slack']['webhook']
273
+ logs_bag_hash.each_pair do |key, hash|
274
+ next unless key.include?(method.to_s)
275
+
276
+ if hash['exit_status'] && hash['exit_status'] == 1
277
+ @config['stateless_action'].slack(hash['text'].prepend('```').insert(-1, '```'))
278
+
279
+ @config['error'].exception_output(on_failing_exit_status_message) if !on_failing_exit_status_message.blank?
280
+ end
281
+ end
282
+ end
283
+ end
284
+
285
+ def slack_current_deploy_arguments
286
+ msg = "#{ Socket.gethostname } just set for the repository #{ @config['getter'].get_repository_from_role_name(@options['role']) }:\n"
287
+ msg << "the organization to #{ @options['deploy_organization'] }\n" if @options['deploy_organization']
288
+ msg << "the revision to #{ @options['target_revision'] }" if @options['target_revision']
289
+
290
+ @config['stateless_action'].slack(msg.prepend('```').insert(-1, '```'), @config['cheftacular']['slack']['notify_on_deployment_args'])
291
+ end
263
292
  end
264
293
  end
265
294
 
@@ -253,25 +253,9 @@ class Cheftacular
253
253
 
254
254
  @config['ChefDataBag'].init_bag('default', 'cheftacular', false)
255
255
 
256
- diff_hash = @config['cheftacular'].deep_diff(@config['default']['cheftacular_bag_hash'], true).except('mode', 'default_repository').compact
256
+ @config['initial_cheftacular_yml'] = @config['cheftacular'].deep_dup
257
257
 
258
- diff_hash.each_pair do |key, value|
259
- diff_hash.delete(key) if value.empty? || value.nil?
260
- end
261
-
262
- if @config['helper'].running_in_mode?('devops') && !diff_hash.empty?
263
- puts "Difference detected between local cheftacular.yml and data bag cheftacular.yml! Displaying..."
264
-
265
- ap diff_hash
266
- elsif @config['helper'].running_in_mode?('application') && @config['default']['cheftacular_bag_hash']['slack']['webhook'] && !diff_hash.empty?
267
- @config['slack_queue'] << diff_hash.awesome_inspect({plain: true, indent: 2}).prepend('```').insert(-1, '```')
268
- end
269
-
270
- @config['cheftacular'] = if @config['default']['cheftacular_bag_hash']['sync_application_cheftacular_yml']
271
- @config['default']['cheftacular_bag_hash'].deep_merge(@config['cheftacular'])
272
- else
273
- @config['cheftacular'].deep_merge(@config['default']['cheftacular_bag_hash'].except('default_repository', 'mode'))
274
- end
258
+ @config['cheftacular'] = @config['default']['cheftacular_bag_hash'].deep_merge(@config['cheftacular'])
275
259
  end
276
260
 
277
261
  def initialize_default_cheftacular_options
@@ -299,10 +283,10 @@ class Cheftacular
299
283
  def initialize_documentation_hash
300
284
  @config['documentation'] ||= {}
301
285
  @config['documentation']['arguments'] ||= []
302
- @config['documentation']['action'] ||= []
303
- @config['documentation']['stateless_action'] ||= []
304
- @config['documentation']['application'] ||= []
305
- @config['documentation']['devops'] ||= []
286
+ @config['documentation']['action'] ||= {}
287
+ @config['documentation']['stateless_action'] ||= {}
288
+ @config['documentation']['application'] ||= {}
289
+ @config['documentation']['devops'] ||= {}
306
290
  end
307
291
 
308
292
  def initialize_locations
@@ -419,8 +403,10 @@ class Cheftacular
419
403
  @config['ruby_string'] = "ruby-" + @config['ruby_string'] unless @config['ruby_string'].include?('ruby-')
420
404
 
421
405
  #TODO Reevaluate for non-rvm setups
422
- @config['bundle_command'] = "/home/#{ @config['cheftacular']['deploy_user'] }/.rvm/gems/#{ @config['ruby_string'].chomp }@global/bin/bundle"
423
- @config['ruby_command'] = "/home/#{ @config['cheftacular']['deploy_user'] }/.rvm/rubies/#{ @config['ruby_string'].chomp }/bin/ruby"
406
+ @config['bundle_command'] = "/home/#{ @config['cheftacular']['deploy_user'] }/.rvm/gems/#{ @config['ruby_string'].chomp }@global/bin/bundle"
407
+ @config['ruby_command'] = "/home/#{ @config['cheftacular']['deploy_user'] }/.rvm/rubies/#{ @config['ruby_string'].chomp }/bin/ruby"
408
+ @config['internal_ruby_config'] = File.expand_path(__FILE__)[/(ruby\-[\d\.@\w]+)/]
409
+ #@config['internal_ruby_version'] = @config['internal_ruby_config'][/([\d\.]+)/] #reactivate when needed
424
410
  end
425
411
 
426
412
  def initialize_passwords env, refresh_bag=false
@@ -448,7 +434,11 @@ class Cheftacular
448
434
  if @config['helper'].is_higher_version? detected_version, current_version
449
435
  puts "\n Your Cheftacular is out of date. Currently #{ current_version } and remote version is #{ detected_version }.\n"
450
436
 
451
- puts "Please update the gemfile to #{ detected_version }, bundle install and then restart this process.\n"
437
+ if @config['internal_ruby_config'].include?('@global')
438
+ puts "Please run rvm #{ @config['internal_ruby_config'] } do gem update cheftacular to update to the latest version"
439
+ else
440
+ puts "Please update the gemfile to #{ detected_version }, bundle install and then restart this process.\n"
441
+ end
452
442
 
453
443
  exit
454
444
  else
@@ -113,6 +113,8 @@ class Cheftacular
113
113
  repo_state_hash['deploy_organization'] = nil
114
114
  end
115
115
 
116
+ @config['helper'].slack_current_deploy_arguments unless @config['cheftacular']['slack']['notify_on_deployment_args'].blank?
117
+
116
118
  @config['ChefDataBag'].save_config_bag
117
119
  end
118
120
 
@@ -2,7 +2,8 @@
2
2
  class Cheftacular
3
3
  class StatelessActionDocumentation
4
4
  def add_ssh_key_to_bag
5
- @config['documentation']['stateless_action'] << [
5
+ @config['documentation']['stateless_action'][__method__] ||= {}
6
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
6
7
  "`cft add_ssh_key_to_bag \"<NEW SSH PUB KEY>\" [SPECIFIC_REPOSITORY]` this command will add the given ssh key to the default authentication data bag. " +
7
8
  "After this your server recipes should read the contents of the 'default' 'authentication' bag for the authorized_keys array.",
8
9
 
@@ -12,6 +13,8 @@ class Cheftacular
12
13
  "does not exist in the cheftacular.yml respositories hash. You can then use this data to give users selective ssh access to certain servers."
13
14
  ]
14
15
  ]
16
+
17
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Adds an ssh key to your authentication bag'
15
18
  end
16
19
  end
17
20
 
@@ -1,7 +1,7 @@
1
1
  class Cheftacular
2
2
  class StatelessActionDocumentation
3
3
  def arguments
4
- @config['documentation']['arguments'] << [
4
+ @config['documentation']['arguments'] << [
5
5
  '## Arguments and flags for cheftacular',
6
6
 
7
7
  '### Environment flags',
@@ -46,11 +46,16 @@ class Cheftacular
46
46
 
47
47
  '1. `-e|--except-role ROLE_NAME` will *prevent* any server with this role from being *deployed to* for the deploy command. Other commands will ignore this argument.',
48
48
 
49
- '2. `-z|--unset-revision` will unset a custom revision specified in the arg below and make the codebase utilize the default.',
49
+ '2. `-z|--unset-github-deploy-args` will unset a custom revision specified in the arg below and make the codebase utilize the default.',
50
50
 
51
51
  "3. `-Z|--revision REVISION` will force the role you're deploying to to utilize the revision specified here. This can be a specific commit, a branch name or even a tag.",
52
52
 
53
- ' 1. Note: The system does not check if the revision exists, if you pass a non-existent revision no one will be able to deploy to that role until -Z with a correction revision or -z is passed.'
53
+ ' 1. Note: The system does not check if the revision exists, if you pass a non-existent revision no one will be able to deploy to that role until -Z with a correction revision or -z is passed.',
54
+
55
+ "4. The `-O ORGANIZATION` flag can be used with TheCheftacularCookbook to set an *organization* your app can try " +
56
+ "deploying from, your git user needs access to these forks / organization(s).",
57
+
58
+ " 3. The `-z|--unset-github-deploy-args` option will clear your current `-Z` and `-O` flags."
54
59
  ]
55
60
  end
56
61
  end
@@ -2,7 +2,8 @@
2
2
  class Cheftacular
3
3
  class StatelessActionDocumentation
4
4
  def backups
5
- @config['documentation']['stateless_action'] << [
5
+ @config['documentation']['stateless_action'][__method__] ||= {}
6
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
6
7
  "`cft backups [activate|deactivate|load|restore]` this command " +
7
8
  "sets the fetch_backups and restore_backups flags in your config data bag for an environment. " +
8
9
  "These can be used to give application developers a way to trigger / untrigger restores in an environment",
@@ -19,7 +20,9 @@ class Cheftacular
19
20
  ]
20
21
  ]
21
22
 
22
- @config['documentation']['application'] << @config['documentation']['stateless_action'].last
23
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Runs various backup commands on your current environment'
24
+
25
+ @config['documentation']['application'][__method__] = @config['documentation']['stateless_action'][__method__]
23
26
  end
24
27
  end
25
28
 
@@ -1,11 +1,14 @@
1
1
  class Cheftacular
2
2
  class StatelessActionDocumentation
3
3
  def ubuntu_bootstrap
4
- @config['documentation']['stateless_action'] << [
4
+ @config['documentation']['stateless_action'][__method__] ||= {}
5
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
5
6
  "`cft ubuntu_bootstrap ADDRESS ROOT_PASS` This command will bring a fresh server to a state " +
6
7
  "where chef-client can be run on it via `cft chef-bootstrap`. It should be noted that it is in "+
7
8
  "this step where a server's randomized deploy_user sudo password is generated."
8
9
  ]
10
+
11
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Updates an ubuntu server to have more secure defaults'
9
12
  end
10
13
  end
11
14
 
@@ -85,6 +88,7 @@ class Cheftacular
85
88
 
86
89
  deploy_commands.each do |cmnd|
87
90
  puts("(#{ @options['address'] }) Running #{ cmnd.gsub("#{ new_deploy_pass }", "sudo password") }") unless @options['quiet'] || @options['in_scaling']
91
+
88
92
  out << `ssh -t -oStrictHostKeyChecking=no #{ deploy_user }@#{ @options['address'] } "#{ cmnd }"`
89
93
 
90
94
  puts(out.last) unless @options['quiet'] || @options['in_scaling']
@@ -94,6 +98,7 @@ class Cheftacular
94
98
 
95
99
  final_commands.each do |cmnd|
96
100
  puts "(#{ @options['address'] }) Running #{ cmnd.gsub("#{ new_deploy_pass }", "sudo password") }"
101
+
97
102
  out << `ssh -t -oStrictHostKeyChecking=no #{ deploy_user }@#{ @options['address'] } "#{ cmnd }"`
98
103
 
99
104
  puts(out.last) unless @options['quiet'] || @options['in_scaling']
@@ -101,11 +106,9 @@ class Cheftacular
101
106
 
102
107
  puts("Finished ruby setup......stage 3 of 3 for server #{ @options['address'] }") if @options['in_scaling']
103
108
 
104
- @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-root-pass"] = @options['client_pass']
105
-
109
+ @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-root-pass"] = @options['client_pass']
106
110
  @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-deploy-pass"] = new_deploy_pass
107
-
108
- @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-name"] = @options['node_name'] if @options['node_name']
111
+ @config[@options['env']]['server_passwords_bag_hash']["#{ @options['address'] }-name"] = @options['node_name'] if @options['node_name']
109
112
 
110
113
  @config['ChefDataBag'].save_server_passwords_bag unless @options['in_scaling']
111
114
  end
@@ -2,10 +2,13 @@
2
2
  class Cheftacular
3
3
  class StatelessActionDocumentation
4
4
  def check_cheftacular_yml_keys
5
- @config['documentation']['stateless_action'] << [
5
+ @config['documentation']['stateless_action'][__method__] ||= {}
6
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
6
7
  "`cft check_cheftacular_yml_keys` allows you to check to see if your cheftacular yml keys are valid to the current version of cheftacular. " +
7
8
  "It will also set your missing keys to their likely default and let you know to update the cheftacular.yml file."
8
9
  ]
10
+
11
+ @config['documentation']['stateless_action'][__method__]['short_description'] = "Makes sure your cheftacular.yml has up-to-date keys for #{ Cheftacular::VERSION }"
9
12
  end
10
13
  end
11
14
 
@@ -13,6 +16,17 @@ class Cheftacular
13
16
  def check_cheftacular_yml_keys out=[], exit_on_missing=false, warn_on_missing=false
14
17
  base_message = "Your cheftacular.yml is missing the key KEY, its default value is being set to DEFAULT for this run."
15
18
 
19
+ #############################2.9.0################################################
20
+
21
+ unless @config['cheftacular']['slack'].has_key?('notify_on_deployment_args')
22
+ #backup_config:global_backup_role_name
23
+ base_message.gsub('KEY', 'notify_on_deployment_args').gsub('DEFAULT', 'false')
24
+
25
+ @config['cheftacular']['slack']['notify_on_deployment_args'] = false
26
+
27
+ warn_on_missing = true
28
+ end
29
+
16
30
  #############################2.7.0################################################
17
31
 
18
32
  unless @config['cheftacular'].has_key?('backup_config')
@@ -2,10 +2,17 @@
2
2
  class Cheftacular
3
3
  class StatelessActionDocumentation
4
4
  def chef_bootstrap
5
- @config['documentation']['stateless_action'] << [
5
+ @config['documentation']['stateless_action'][__method__] ||= {}
6
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
6
7
  "`cft chef_bootstrap ADDRESS NODE_NAME` allows you to register a node in the chef system, " +
7
- "remove any lingering data that may be associated with it and update the node's runlist if it has an entry in nodes_dir for its NODE_NAME."
8
+ "remove any lingering data that may be associated with it and update the node's runlist if it has an entry in nodes_dir for its NODE_NAME.",
9
+
10
+ [
11
+ " 1. This command is part of the `cft full_bootstrap` command"
12
+ ]
8
13
  ]
14
+
15
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Bootstraps basic chef properties on the target server'
9
16
  end
10
17
  end
11
18
 
@@ -1,7 +1,8 @@
1
1
  class Cheftacular
2
2
  class StatelessActionDocumentation
3
3
  def chef_server
4
- @config['documentation']['stateless_action'] << [
4
+ @config['documentation']['stateless_action'][__method__] ||= {}
5
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
5
6
  "`cft chef_server [restart|processes|memory]` this command can be used to query the chef server for stats if the cheftacular.yml " +
6
7
  "has the chef_server key filled out. Useful for low resource chef-servers.",
7
8
 
@@ -20,7 +21,9 @@ class Cheftacular
20
21
  ]
21
22
  ]
22
23
 
23
- @config['documentation']['application'] << @config['documentation']['stateless_action'].last
24
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Allows you to check the state of the primary Chef server'
25
+
26
+ @config['documentation']['application'][__method__] = @config['documentation']['stateless_action'][__method__]
24
27
  end
25
28
  end
26
29