cheftacular 2.8.0 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cheftacular/README.md +92 -70
- data/lib/cheftacular/actions/check.rb +3 -2
- data/lib/cheftacular/actions/console.rb +8 -2
- data/lib/cheftacular/actions/db_console.rb +28 -4
- data/lib/cheftacular/actions/deploy.rb +6 -8
- data/lib/cheftacular/actions/log.rb +7 -2
- data/lib/cheftacular/actions/migrate.rb +16 -5
- data/lib/cheftacular/actions/run.rb +10 -3
- data/lib/cheftacular/actions/scale.rb +4 -1
- data/lib/cheftacular/actions/tail.rb +8 -3
- data/lib/cheftacular/cheftacular.rb +1 -1
- data/lib/cheftacular/cloud_provider.rb +5 -1
- data/lib/cheftacular/dns.rb +1 -1
- data/lib/cheftacular/error.rb +2 -2
- data/lib/cheftacular/file_system.rb +50 -0
- data/lib/cheftacular/getter.rb +1 -1
- data/lib/cheftacular/helper.rb +34 -5
- data/lib/cheftacular/initializer.rb +15 -25
- data/lib/cheftacular/parser.rb +2 -0
- data/lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb +4 -1
- data/lib/cheftacular/stateless_actions/arguments.rb +8 -3
- data/lib/cheftacular/stateless_actions/backups.rb +5 -2
- data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +8 -5
- data/lib/cheftacular/stateless_actions/check_cheftacular_yml_keys.rb +15 -1
- data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +9 -2
- data/lib/cheftacular/stateless_actions/chef_server.rb +5 -2
- data/lib/cheftacular/stateless_actions/cheftacular_config.rb +26 -4
- data/lib/cheftacular/stateless_actions/cheftacular_yml_help.rb +31 -0
- data/lib/cheftacular/stateless_actions/clean_cookbooks.rb +6 -37
- data/lib/cheftacular/stateless_actions/clear_caches.rb +9 -2
- data/lib/cheftacular/stateless_actions/client_list.rb +5 -2
- data/lib/cheftacular/stateless_actions/cloud.rb +4 -1
- data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +4 -1
- data/lib/cheftacular/stateless_actions/compile_audit_log.rb +4 -1
- data/lib/cheftacular/stateless_actions/compile_readme.rb +10 -1
- data/lib/cheftacular/stateless_actions/create_git_key.rb +4 -1
- data/lib/cheftacular/stateless_actions/disk_report.rb +5 -2
- data/lib/cheftacular/stateless_actions/environment.rb +5 -2
- data/lib/cheftacular/stateless_actions/file.rb +5 -2
- data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +5 -2
- data/lib/cheftacular/stateless_actions/full_bootstrap.rb +10 -2
- data/lib/cheftacular/stateless_actions/get_active_ssh_connections.rb +3 -2
- data/lib/cheftacular/stateless_actions/get_haproxy_log.rb +5 -2
- data/lib/cheftacular/stateless_actions/get_log_from_bag.rb +5 -2
- data/lib/cheftacular/stateless_actions/get_pg_pass.rb +5 -2
- data/lib/cheftacular/stateless_actions/get_shorewall_allowed_connections.rb +2 -1
- data/lib/cheftacular/stateless_actions/help.rb +28 -16
- data/lib/cheftacular/stateless_actions/initialize_cheftacular_yml.rb +4 -1
- data/lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb +4 -1
- data/lib/cheftacular/stateless_actions/knife_upload.rb +4 -1
- data/lib/cheftacular/stateless_actions/list_toggleable_roles.rb +5 -2
- data/lib/cheftacular/stateless_actions/location_aliases.rb +5 -2
- data/lib/cheftacular/stateless_actions/pass.rb +5 -2
- data/lib/cheftacular/stateless_actions/reinitialize.rb +4 -1
- data/lib/cheftacular/stateless_actions/remove_client.rb +9 -2
- data/lib/cheftacular/stateless_actions/replication_status.rb +4 -1
- data/lib/cheftacular/stateless_actions/reset_bag.rb +4 -1
- data/lib/cheftacular/stateless_actions/restart_swap.rb +4 -1
- data/lib/cheftacular/stateless_actions/role_toggle.rb +7 -4
- data/lib/cheftacular/stateless_actions/rvm.rb +4 -1
- data/lib/cheftacular/stateless_actions/server_update.rb +5 -2
- data/lib/cheftacular/stateless_actions/service.rb +4 -1
- data/lib/cheftacular/stateless_actions/slack.rb +4 -1
- data/lib/cheftacular/stateless_actions/test_env.rb +4 -1
- data/lib/cheftacular/stateless_actions/update_chef_client.rb +2 -1
- data/lib/cheftacular/stateless_actions/update_cloudflare_dns_from_cloud.rb +4 -1
- data/lib/cheftacular/stateless_actions/update_split_branches.rb +4 -1
- data/lib/cheftacular/stateless_actions/update_thecheftacularcookbook.rb +38 -0
- data/lib/cheftacular/stateless_actions/update_tld.rb +4 -1
- data/lib/cheftacular/stateless_actions/upload_nodes.rb +6 -3
- data/lib/cheftacular/stateless_actions/upload_roles.rb +4 -1
- data/lib/cheftacular/version.rb +1 -1
- data/lib/cloud_interactor/authentication.rb +3 -4
- data/lib/cloud_interactor/flavor.rb +7 -2
- data/lib/cloud_interactor/helpers.rb +5 -1
- data/lib/cloud_interactor/server/create.rb +7 -2
- data/lib/sshkit/actions/start_task.rb +9 -1
- metadata +6 -7
- data/bin/client-list +0 -4
- 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 }
|
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
|
-
|
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 }
|
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
|
-
|
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
|
-
[
|
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
|
data/lib/cheftacular/dns.rb
CHANGED
@@ -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'] ?
|
65
|
+
(record_hash['activate_cloudflare'] ? 1 : 0) #service_mode
|
66
66
|
)
|
67
67
|
|
68
68
|
print 'create'.ljust(20, '_')
|
data/lib/cheftacular/error.rb
CHANGED
@@ -20,10 +20,10 @@ class Cheftacular
|
|
20
20
|
nodes
|
21
21
|
end
|
22
22
|
|
23
|
-
def exception_output message, exception=
|
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") }")
|
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 ))
|
data/lib/cheftacular/getter.rb
CHANGED
@@ -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
|
data/lib/cheftacular/helper.rb
CHANGED
@@ -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']['
|
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']['
|
145
|
+
when 'devops' then @config['documentation']['stateless_action'].merge(@config['documentation']['action'])
|
146
146
|
end
|
147
147
|
|
148
|
-
|
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
|
-
|
256
|
+
@config['initial_cheftacular_yml'] = @config['cheftacular'].deep_dup
|
257
257
|
|
258
|
-
|
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']
|
423
|
-
@config['ruby_command']
|
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
|
-
|
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
|
data/lib/cheftacular/parser.rb
CHANGED
@@ -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-
|
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']['
|
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"]
|
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']['
|
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
|
|