cheftacular 2.10.2 → 2.11.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cheftacular/README.md +119 -77
  3. data/lib/cheftacular/actions/check.rb +58 -24
  4. data/lib/cheftacular/actions/deploy.rb +5 -3
  5. data/lib/cheftacular/auditor.rb +4 -3
  6. data/lib/cheftacular/cheftacular.rb +1 -0
  7. data/lib/cheftacular/cloud_provider.rb +17 -12
  8. data/lib/cheftacular/file_system.rb +20 -0
  9. data/lib/cheftacular/getter.rb +1 -1
  10. data/lib/cheftacular/helper.rb +41 -28
  11. data/lib/cheftacular/initializer.rb +5 -3
  12. data/lib/cheftacular/parser.rb +10 -6
  13. data/lib/cheftacular/queue_master.rb +24 -0
  14. data/lib/cheftacular/stateless_actions/backups.rb +2 -2
  15. data/lib/cheftacular/stateless_actions/bootstrappers/{centos_bootstrap.rb → centos_bootstrap_from_queue.rb} +1 -1
  16. data/lib/cheftacular/stateless_actions/bootstrappers/{coreos_bootstrap.rb → coreos_bootstrap_from_queue.rb} +1 -1
  17. data/lib/cheftacular/stateless_actions/bootstrappers/{fedora_bootstrap.rb → fedora_bootstrap_from_queue.rb} +1 -1
  18. data/lib/cheftacular/stateless_actions/bootstrappers/{redhat_bootstrap.rb → redhat_bootstrap_from_queue.rb} +1 -1
  19. data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap_from_queue.rb +203 -0
  20. data/lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap_from_queue.rb +7 -0
  21. data/lib/cheftacular/stateless_actions/check_cheftacular_yml_keys.rb +30 -0
  22. data/lib/cheftacular/stateless_actions/chef_bootstrap_from_queue.rb +89 -0
  23. data/lib/cheftacular/stateless_actions/cheftacular_yml_help.rb +55 -6
  24. data/lib/cheftacular/stateless_actions/client_list.rb +1 -3
  25. data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +24 -15
  26. data/lib/cheftacular/stateless_actions/cloud_bootstrap_from_queue.rb +37 -0
  27. data/lib/cheftacular/stateless_actions/environment.rb +80 -31
  28. data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +1 -22
  29. data/lib/cheftacular/stateless_actions/{full_bootstrap.rb → full_bootstrap_from_queue.rb} +8 -15
  30. data/lib/cheftacular/stateless_actions/knife_upload.rb +14 -3
  31. data/lib/cheftacular/stateless_actions/reinitialize.rb +1 -1
  32. data/lib/cheftacular/stateless_actions/remove_client.rb +3 -3
  33. data/lib/cheftacular/stateless_actions/restart_swap.rb +0 -1
  34. data/lib/cheftacular/stateless_actions/test_env.rb +24 -18
  35. data/lib/cheftacular/stateless_actions/update_thecheftacularcookbook.rb +1 -1
  36. data/lib/cheftacular/stateless_actions/upload_nodes.rb +2 -2
  37. data/lib/cheftacular/version.rb +1 -1
  38. data/lib/cloud_interactor/domain/create.rb +2 -2
  39. data/lib/cloud_interactor/domain/create_record.rb +1 -1
  40. data/lib/cloud_interactor/domain/destroy.rb +2 -2
  41. data/lib/cloud_interactor/domain/destroy_record.rb +1 -1
  42. data/lib/cloud_interactor/domain/list_records.rb +1 -1
  43. data/lib/cloud_interactor/domain/read.rb +1 -1
  44. data/lib/cloud_interactor/domain/read_record.rb +1 -1
  45. data/lib/cloud_interactor/domain/update.rb +2 -2
  46. data/lib/cloud_interactor/domain/update_record.rb +2 -2
  47. data/lib/cloud_interactor/helpers.rb +11 -6
  48. data/lib/cloud_interactor/server/attach_volume.rb +1 -1
  49. data/lib/cloud_interactor/server/create.rb +4 -4
  50. data/lib/cloud_interactor/server/detach_volume.rb +2 -2
  51. data/lib/cloud_interactor/server/list_volumes.rb +1 -1
  52. data/lib/cloud_interactor/server/poll.rb +2 -2
  53. data/lib/cloud_interactor/server/read_volume.rb +1 -1
  54. data/lib/cloud_interactor/version.rb +1 -1
  55. data/lib/cloud_interactor/volume/create.rb +1 -1
  56. data/lib/sshkit/getters.rb +9 -1
  57. metadata +25 -10
  58. data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +0 -116
  59. data/lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap.rb +0 -7
  60. data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +0 -63
@@ -1,6 +1,6 @@
1
1
  class Cheftacular
2
2
  class StatelessAction
3
- def redhat_bootstrap out=[]
3
+ def redhat_bootstrap_from_queue out=[]
4
4
  raise "Not yet implemented!"
5
5
  end
6
6
  end
@@ -1,6 +1,6 @@
1
1
  class Cheftacular
2
2
  class StatelessAction
3
- def coreos_bootstrap out=[]
3
+ def coreos_bootstrap_from_queue out=[]
4
4
  raise "Not yet implemented!"
5
5
  end
6
6
  end
@@ -1,6 +1,6 @@
1
1
  class Cheftacular
2
2
  class StatelessAction
3
- def fedora_bootstrap out=[]
3
+ def fedora_bootstrap_from_queue out=[]
4
4
  raise "Not yet implemented!"
5
5
  end
6
6
  end
@@ -1,6 +1,6 @@
1
1
  class Cheftacular
2
2
  class StatelessAction
3
- def redhat_bootstrap out=[]
3
+ def redhat_bootstrap_from_queue out=[]
4
4
  raise "Not yet implemented!"
5
5
  end
6
6
  end
@@ -0,0 +1,203 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def ubuntu_bootstrap_from_queue
4
+ @config['documentation']['stateless_action'][__method__] ||= {}
5
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
6
+ "`cft ubuntu_bootstrap_from_queue` This command will bring a fresh server to a state " +
7
+ "where chef-client can be run on it via `cft chef-bootstrap`. It should be noted that it is in "+
8
+ "this step where a server's randomized deploy_user sudo password is generated."
9
+ ]
10
+
11
+ @config['documentation']['stateless_action'][__method__]['short_description'] = '[Not Directly Callable]'
12
+ end
13
+ end
14
+
15
+ class StatelessAction
16
+ def ubuntu_bootstrap_from_queue threads=[], execution_hash_array=[]
17
+ raise "This action is not meant to be called directly!" if !@options['in_scaling'] && !@options['in_single_server_creation']
18
+
19
+ if `which sshpass`.empty?
20
+ raise "sshpass not installed! Please run brew install https://raw.github.com/eugeneoden/homebrew/eca9de1/Library/Formula/sshpass.rb (or get it from your repo for linux)"
21
+ end
22
+
23
+ @config['bootstrap_timestamp'] ||= Time.now.strftime("%Y%m%d%H%M%S")
24
+
25
+ @config['queue_master'].generate_passwords_for_each_server_hash_in_queue
26
+
27
+ execution_hash_array << compile_root_execute_hash
28
+ execution_hash_array << compile_deploy_execute_hash
29
+ execution_hash_array << compile_rvm_execute_hash if @config['cheftacular']['install_rvm_on_boot']
30
+ execution_hash_array << compile_install_rvm_sh_file_hashes if @config['cheftacular']['install_rvm_on_boot']
31
+ execution_hash_array = execution_hash_array.flatten(1)
32
+
33
+ @config['server_creation_queue'].each do |server_hash|
34
+ puts("#{ server_name_output(server_hash) }_Starting initial setup for server...") if @options['in_scaling']
35
+
36
+ threads << Thread.new { execute_execution_hash_array(server_hash, execution_hash_array) }
37
+ end
38
+
39
+ threads.each { |thread| thread.join }
40
+
41
+ @config['server_creation_queue'].each do |server_hash|
42
+ @config[@options['env']]['server_passwords_bag_hash']["#{ server_hash['address'] }-root-pass"] = server_hash['client_pass']
43
+ @config[@options['env']]['server_passwords_bag_hash']["#{ server_hash['address'] }-deploy-pass"] = server_hash['deploy_password']
44
+ @config[@options['env']]['server_passwords_bag_hash']["#{ server_hash['address'] }-name"] = server_hash['node_name']
45
+ end
46
+
47
+ @config['ChefDataBag'].save_server_passwords_bag unless @config['in_server_creation_queue']
48
+ end
49
+
50
+ private
51
+
52
+ def compile_root_execute_hash
53
+ deploy_user = @config['cheftacular']['deploy_user']
54
+
55
+ root_commands = [
56
+ "cd /home",
57
+ "adduser #{ deploy_user } --gecos \",,,,\" --disabled-password",
58
+ "echo #{ deploy_user }:NEW_DEPLOY_PASS | chpasswd",
59
+ "adduser #{ deploy_user } www-data",
60
+ "adduser #{ deploy_user } sudo",
61
+ "mkdir -p /home/#{ deploy_user }/.ssh",
62
+ "touch /home/#{ deploy_user }/.ssh/authorized_keys && touch /home/#{ deploy_user }/.ssh/known_hosts",
63
+ "chown -R #{ deploy_user }:www-data /home/#{ deploy_user }/.ssh",
64
+ 'sed -i "s/StrictModes yes/StrictModes yes\nPasswordAuthentication no\nUseDNS no\nAllowUsers deploy postgres\n/" /etc/ssh/sshd_config'.gsub('deploy', deploy_user),
65
+ 'sed -i "s/PermitRootLogin yes/PermitRootLogin no/" /etc/ssh/sshd_config'
66
+ ]
67
+
68
+ @config['default']['authentication_bag_hash']['authorized_keys'].each do |line|
69
+ root_commands << "echo \"#{ line }\" >> /home/#{ deploy_user }/.ssh/authorized_keys"
70
+ end
71
+
72
+ {
73
+ run_as: 'ssh',
74
+ command: root_commands.join(' && ').insert(-1, ' && service ssh restart'),
75
+ retries: @config['cheftacular']['server_creation_tries'].to_i,
76
+ use_root_pass: true
77
+ }
78
+ end
79
+
80
+ def compile_deploy_execute_hash
81
+ sudo = "echo NEW_DEPLOY_PASS | sudo -S"
82
+
83
+ deploy_commands = [
84
+ "#{ sudo } apt-get update",
85
+ "#{ sudo } apt-get install curl #{ @config['cheftacular']['pre_install_packages'] } -y",
86
+ "#{ sudo } apt-get upgrade -y"
87
+ ]
88
+
89
+ if @config['cheftacular']['install_rvm_on_boot']
90
+ deploy_commands << "gpg --keyserver hkp://keys.gnupg.net --recv-keys #{ @config['cheftacular']['rvm_gpg_key'] }"
91
+ deploy_commands << "curl -L https://get.rvm.io | bash -s stable"
92
+ end
93
+
94
+ { run_as: 'ssh', command_array: deploy_commands }
95
+ end
96
+
97
+ def compile_rvm_execute_hash
98
+ rvm_source = "source /home/#{ @config['cheftacular']['deploy_user'] }/.rvm/bin/rvm &&"
99
+
100
+ final_commands = [
101
+ "#{ rvm_source } echo NEW_DEPLOY_PASS | rvmsudo -S rvm requirements",
102
+ "#{ rvm_source } rvm install #{ @config['cheftacular']['ruby_version'] }",
103
+ "#{ rvm_source } rvm alias create default #{ @config['cheftacular']['ruby_version'] }",
104
+ "#{ rvm_source } rvm gemset empty --force"
105
+ ]
106
+
107
+ final_commands << "#{ rvm_source } rvm install 1.9.3-p327" if @config['cheftacular']['chef_version'].to_i < 12
108
+
109
+ { run_as: 'ssh', command_array: final_commands }
110
+ end
111
+
112
+ def compile_install_rvm_sh_file_hashes ret_array=[]
113
+ sudo = "echo NEW_DEPLOY_PASS | sudo -S"
114
+
115
+ ssh_commands = [
116
+ "#{ sudo } mv /home/#{ @config['cheftacular']['deploy_user'] }/rvm.sh /etc/profile.d",
117
+ "#{ sudo } chmod 755 /etc/profile.d/rvm.sh",
118
+ "#{ sudo } chown root:root /etc/profile.d/rvm.sh"
119
+ ]
120
+
121
+ ret_array << { run_as: 'scp', upload: "#{ @config['locs']['cheftacular-lib-files'] }/rvm.sh", to: "/home/#{ @config['cheftacular']['deploy_user'] }"}
122
+ ret_array << { run_as: 'ssh', command: ssh_commands.join(' && ') }
123
+ ret_array
124
+ end
125
+
126
+ def execute_execution_hash_array server_hash, execution_array, output=[], create_logs=true, log_sub_dir='initial-setup'
127
+ execution_array.each do |execution_hash|
128
+ ssh_arguments = [server_hash['address']]
129
+ ssh_arguments << ( execution_hash.has_key?(:use_root_pass) ? 'root' : @config['cheftacular']['deploy_user'] )
130
+ ssh_arguments << [{ password: server_hash['client_pass'] }] if execution_hash.has_key?(:use_root_pass)
131
+ begin
132
+ case execution_hash[:run_as]
133
+ when 'ssh'
134
+ if execution_hash.has_key?(:command)
135
+ Net::SSH.start(*ssh_arguments.flatten) do |ssh|
136
+ output << ssh.exec!(replace_placeholders_in_command(server_hash, execution_hash[:command]))
137
+ end
138
+ end
139
+
140
+ if execution_hash.has_key?(:command_array)
141
+ execution_hash[:command_array].each do |command|
142
+ puts("#{ server_name_output(server_hash) }_Preparing to execute #{ command }")
143
+
144
+ Net::SSH.start(*ssh_arguments.flatten) do |ssh|
145
+ output << ssh.exec!(replace_placeholders_in_command(server_hash, command))
146
+ end
147
+ end
148
+ end
149
+ when 'scp'
150
+ if execution_hash.has_key?(:upload) && execution_hash.has_key?(:to)
151
+ puts("#{ server_name_output(server_hash) }_Preparing to upload #{ execution_hash[:upload] } to #{ execution_hash[:to] }")
152
+
153
+ Net::SCP.upload!(server_hash['address'], @config['cheftacular']['deploy_user'], execution_hash[:upload], execution_hash[:to])
154
+ end
155
+ when 'raw'
156
+ if execution_hash.has_key?(:command)
157
+ output << `#{ replace_placeholders_in_command(server_hash, execution_hash[:command]) }`
158
+ end
159
+
160
+ if execution_hash.has_key?(:command_array)
161
+ execution_hash[:command_array].each do |command|
162
+ puts("#{ server_name_output(server_hash) }_Preparing to execute #{ command }")
163
+
164
+ output << `#{ replace_placeholders_in_command(server_hash, command) }`
165
+ end
166
+ end
167
+ end
168
+ rescue Net::SSH::HostKeyMismatch => e
169
+ puts "#{ server_name_output(server_hash) }_Has a host key mismatch! Rewriting known_hosts file..."
170
+
171
+ @config['filesystem'].scrub_from_known_hosts(server_hash['address'])
172
+
173
+ sleep 15
174
+
175
+ retry
176
+ rescue StandardError => e
177
+ puts "#{ server_name_output(server_hash) }_@@@@@@@@@@@ Failing execution hash because of #{ e }!@@@@@@@@@@"
178
+ puts "#{ e.backtrace.join("\n") }" if @options['verbose']
179
+
180
+ if execution_hash.has_key?(:retries)
181
+ execution_hash[:retries] = execution_hash[:retries] -= 1
182
+ puts "There are #{ execution_hash[:retries] } tries left to evaluate the command."
183
+
184
+ sleep 60
185
+
186
+ raise "#{ server_name_output(server_hash) }_@@@@@@@@@@@ Unable to complete setup process!@@@@@@@@@@" if execution_hash[:retries] <= 0
187
+ retry
188
+ end
189
+ end
190
+ end
191
+
192
+ File.open("#{ @config['locs']['chef-log'] }/server-setup/#{ server_hash['node_name'] }-#{ log_sub_dir }-#{ @config['bootstrap_timestamp'] }.txt", 'a+') { |f| f.write(output.join("\n").scrub_pretty_text) }
193
+ end
194
+
195
+ def server_name_output server_hash
196
+ "#{ server_hash['node_name'] }".ljust(17,'_') + "#{ server_hash['address'] }".ljust(18,'_')
197
+ end
198
+
199
+ def replace_placeholders_in_command server_hash, command
200
+ command.gsub('NEW_DEPLOY_PASS', server_hash['deploy_password']).gsub('ADDRESS', server_hash['address']).gsub('CLIENT_PASS', server_hash['client_pass']).gsub('NODE_NAME', server_hash['node_name'])
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,7 @@
1
+ class Cheftacular
2
+ class StatelessAction
3
+ def vyatta_bootstrap_from_queue out=[]
4
+ raise "Not yet implemented!"
5
+ end
6
+ end
7
+ end
@@ -16,6 +16,36 @@ class Cheftacular
16
16
  def check_cheftacular_yml_keys out=[], exit_on_missing=false, warn_on_missing=false
17
17
  base_message = "Your cheftacular.yml is missing the key KEY, its default value is being set to DEFAULT for this run."
18
18
 
19
+ #############################2.11.0################################################
20
+
21
+ unless @config['cheftacular'].has_key?('server_creation_tries')
22
+ @config['cheftacular']['server_creation_tries'] = 2
23
+ end
24
+
25
+ unless @config['cheftacular']['backup_config'].has_key?('db_primary_role')
26
+ puts base_message.gsub('KEY', 'backup_config:db_primary_role').gsub('DEFAULT', 'db_primary')
27
+
28
+ @config['cheftacular']['backup_config']['db_primary_role'] = 'db_primary'
29
+
30
+ warn_on_missing = true
31
+ end
32
+
33
+ unless @config['cheftacular'].has_key?('git')
34
+ puts(base_message.gsub('KEY', 'git').split(',').first + ', Please add the git high level key to your cheftacular.yml.')
35
+
36
+ @config['cheftacular']['git'] ||= {}
37
+
38
+ warn_on_missing = true
39
+ end
40
+
41
+ unless @config['cheftacular']['git'].has_key?('check_remote_for_branch_existence')
42
+ puts base_message.gsub('KEY', 'git:check_remote_for_branch_existence').gsub('DEFAULT', 'false')
43
+
44
+ @config['cheftacular']['git']['check_remote_for_branch_existence'] = false
45
+
46
+ warn_on_missing = true
47
+ end
48
+
19
49
  #############################2.10.0################################################
20
50
 
21
51
  unless @config['cheftacular'].has_key?('self_update_repository')
@@ -0,0 +1,89 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def chef_bootstrap_from_queue
5
+ @config['documentation']['stateless_action'][__method__] ||= {}
6
+ @config['documentation']['stateless_action'][__method__]['long_description'] = [
7
+ "`cft chef_bootstrap_from_queue` allows you to register a node in the chef system, " +
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 and cannot be called directly"
12
+ ]
13
+ ]
14
+
15
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Bootstraps basic chef properties on the target server'
16
+ end
17
+ end
18
+
19
+ class StatelessAction
20
+ def chef_bootstrap_from_queue threads=[]
21
+ raise "This action is not meant to be called directly!" if !@options['in_scaling'] && !@options['in_single_server_creation']
22
+
23
+ #@config['stateless_action'].remove_client #just in case
24
+
25
+ execution_hash_array = compile_chef_bootstrap_commands
26
+
27
+ @config['bootstrap_timestamp'] ||= Time.now.strftime("%Y%m%d%H%M%S")
28
+
29
+ @config['server_creation_queue'].each do |server_hash|
30
+ puts("(#{ server_hash['node_name'] })[#{ server_hash['address'] }] Starting chef-client installation...") unless @options['quiet']
31
+
32
+ threads << Thread.new { execute_execution_hash_array(server_hash, execution_hash_array) }
33
+ end
34
+
35
+ threads.each { |thread| thread.join }
36
+
37
+ @options['force_yes'] = true # have the upload_nodes grab the new nodes
38
+
39
+ @config['stateless_action'].upload_nodes(true)
40
+ end
41
+
42
+ private
43
+
44
+ def compile_chef_bootstrap_commands final_command=[]
45
+ sudo = "echo NEW_DEPLOY_PASS | sudo -S"
46
+
47
+ if @config['cheftacular']['chef_version'].to_i >= 12
48
+ commands = [
49
+ "curl -L https://www.opscode.com/chef/install.sh > ~/chef-install.sh",
50
+ "#{ sudo } bash /home/#{ @config['cheftacular']['deploy_user'] }/chef-install.sh",
51
+ "rm ~/chef-install.sh"
52
+ ]
53
+
54
+ final_command << { run_as: 'ssh', command_array: commands }
55
+ end
56
+
57
+ final_command << knife_bootstrap_command
58
+ final_command << export_data_bag_key_file_command
59
+ final_command << move_data_bag_key_file_command
60
+
61
+ final_command
62
+ end
63
+
64
+ def knife_bootstrap_command
65
+ user = @config['cheftacular']['deploy_user']
66
+ chef_ver = @config['cheftacular']['chef_version'].to_i >= 12 ? '12.4.0' : '11.16.4'
67
+
68
+ { run_as: 'raw', command: "knife bootstrap ADDRESS -x #{ user } -P NEW_DEPLOY_PASS -N NODE_NAME --sudo --use-sudo-password --bootstrap-version #{ chef_ver }" }
69
+ end
70
+
71
+ def export_data_bag_key_file_command
72
+ chef_loc, key_file, user, address = set_data_bag_key_variables
73
+
74
+ #"scp -oStrictHostKeyChecking=no #{ chef_loc }/#{ key_file } #{ user }@#{ address }:/home/#{ user }"
75
+ { run_as: 'scp', upload: "#{ chef_loc }/#{ key_file }", to: "/home/#{ user }" }
76
+ end
77
+
78
+ def move_data_bag_key_file_command
79
+ chef_loc, key_file, user, address = set_data_bag_key_variables
80
+
81
+ #"ssh -t -oStrictHostKeyChecking=no #{ user }@#{ address } \"#{ @config['helper'].sudo(address) } mv -f /home/#{ user }/#{ key_file } /etc/chef\""
82
+ { run_as: 'ssh', command: "echo NEW_DEPLOY_PASS | sudo -S mv -f /home/#{ user }/#{ key_file } /etc/chef" }
83
+ end
84
+
85
+ def set_data_bag_key_variables
86
+ [ @config['locs']['chef'], @config['cheftacular']['data_bag_key_file'], @config['cheftacular']['deploy_user'], 'ADDRESS' ]
87
+ end
88
+ end
89
+ end
@@ -4,28 +4,77 @@ class Cheftacular
4
4
  def cheftacular_yml_help
5
5
  @config['documentation']['stateless_action'][__method__] ||= {}
6
6
  @config['documentation']['stateless_action'][__method__]['long_description'] = [
7
- "[NYI]`cft cheftacular_yml_help KEY` this command" +
7
+ "`cft cheftacular_yml_help KEY` this command" +
8
8
  "allows you to get help on the meaning of each key in your cheftacular.yml overall config.",
9
9
 
10
10
  [
11
- " 1. This command can also by run with `cft yaml_help`."
11
+ " 1. This command can also by run with `cft yaml_help`.",
12
+
13
+ " 2. To examine nested keys, you can use colons inbetween the keys like cloud_authentication:rackspace:email"
12
14
  ]
13
15
  ]
14
16
 
15
- @config['documentation']['stateless_action'][__method__]['short_description'] = '[NYI]Gives help on the keys in your cheftacular.yml'
17
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Gives help on the keys in your cheftacular.yml'
16
18
 
17
19
  @config['documentation']['application'][__method__] = @config['documentation']['stateless_action'][__method__]
18
20
  end
21
+
22
+ alias_method :yml_help, :cheftacular_yml_help
23
+ end
24
+
25
+ class InitializationAction
26
+ def cheftacular_yml_help
27
+
28
+ end
29
+
30
+ alias_method :yml_help, :cheftacular_yml_help
19
31
  end
20
32
 
21
33
  class StatelessAction
22
- def cheftacular_yml_help command=''
23
- raise "Not Yet Implemented"
34
+ def cheftacular_yml_help command='', key_nesting_array=[]
35
+ key_to_check = ARGV[1]
24
36
 
37
+ raise "This command requires a key to check the documentation, please enter one as the first argument" if key_to_check.nil?
38
+
39
+ key_to_check.split(':').each { |key| key_nesting_array << key }
40
+
41
+ doc_hash = YAML::load(ERB.new(IO.read(File.open(File.expand_path("#{ @config['locs']['doc'] }/cheftacular_yml_help.yml")))).result)
42
+
43
+ traverse_documentation_hash(doc_hash, key_nesting_array)
25
44
  end
26
45
 
27
- alias_method :yaml_help, :cheftacular_yml_help
46
+ alias_method :yml_help, :cheftacular_yml_help
28
47
 
29
48
  private
49
+
50
+ def traverse_documentation_hash doc_hash, key_array, index=0
51
+ if doc_hash.has_key?(key_array[index])
52
+ if doc_hash[key_array[index]].class == Hash && key_array.length-1 == index
53
+ if doc_hash[key_array[index]]['key_description'].nil?
54
+ puts "Missing documentation for key #{ key_array[index] }!"
55
+ else
56
+ puts doc_hash[key_array[index]]['key_description']
57
+ end
58
+ elsif doc_hash[key_array[index]].class != Hash && key_array.length-1 == index
59
+ puts doc_hash[key_array[index]]
60
+ elsif doc_hash[key_array[index]].class == Hash && key_array.length-1 != index
61
+ traverse_documentation_hash(doc_hash[key_array[index]], key_array, index+1)
62
+ else
63
+ puts "You attempted to traverse the documentation with a value that was not a key to a hash (#{ key_array[index] }), the value of this key is:"
64
+
65
+ puts doc_hash[key_array[index]]
66
+
67
+ puts "If this is not what you were searching for, please verify your config tree with `cft cheftacular_config display`"
68
+ end
69
+ elsif doc_hash.has_key?('STAR_MATCHER') && key_array.length-1 != index
70
+ traverse_documentation_hash(doc_hash['STAR_MATCHER'], key_array, index+1)
71
+ elsif doc_hash.has_key?('STAR_MATCHER') && key_array.length-1 == index
72
+ puts doc_hash['STAR_MATCHER']['key_description']
73
+ else
74
+ puts "The documentation hash does not have the key #{ key_array[index] }, the keys available here are:"
75
+
76
+ ap doc_hash.keys
77
+ end
78
+ end
30
79
  end
31
80
  end