cheftacular 2.0.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 (118) hide show
  1. checksums.yaml +7 -0
  2. data/bin/cft +4 -0
  3. data/bin/cftclr +4 -0
  4. data/bin/cheftacular +4 -0
  5. data/bin/client-list +4 -0
  6. data/lib/cheftacular/README.md +416 -0
  7. data/lib/cheftacular/actions/check.rb +32 -0
  8. data/lib/cheftacular/actions/console.rb +62 -0
  9. data/lib/cheftacular/actions/database.rb +13 -0
  10. data/lib/cheftacular/actions/db_console.rb +67 -0
  11. data/lib/cheftacular/actions/deploy.rb +40 -0
  12. data/lib/cheftacular/actions/log.rb +47 -0
  13. data/lib/cheftacular/actions/migrate.rb +57 -0
  14. data/lib/cheftacular/actions/run.rb +64 -0
  15. data/lib/cheftacular/actions/scale.rb +94 -0
  16. data/lib/cheftacular/actions/tail.rb +55 -0
  17. data/lib/cheftacular/actions.rb +14 -0
  18. data/lib/cheftacular/auditor.rb +46 -0
  19. data/lib/cheftacular/chef/data_bag.rb +104 -0
  20. data/lib/cheftacular/cheftacular.rb +55 -0
  21. data/lib/cheftacular/decryptors.rb +45 -0
  22. data/lib/cheftacular/encryptors.rb +48 -0
  23. data/lib/cheftacular/getters.rb +153 -0
  24. data/lib/cheftacular/helpers.rb +296 -0
  25. data/lib/cheftacular/initializers.rb +451 -0
  26. data/lib/cheftacular/parsers.rb +199 -0
  27. data/lib/cheftacular/remote_helpers.rb +30 -0
  28. data/lib/cheftacular/stateless_action.rb +16 -0
  29. data/lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb +44 -0
  30. data/lib/cheftacular/stateless_actions/arguments.rb +68 -0
  31. data/lib/cheftacular/stateless_actions/backups.rb +116 -0
  32. data/lib/cheftacular/stateless_actions/bootstrappers/centos_bootstrap.rb +7 -0
  33. data/lib/cheftacular/stateless_actions/bootstrappers/coreos_bootstrap.rb +7 -0
  34. data/lib/cheftacular/stateless_actions/bootstrappers/fedora_bootstrap.rb +7 -0
  35. data/lib/cheftacular/stateless_actions/bootstrappers/redhat_bootstrap.rb +7 -0
  36. data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +102 -0
  37. data/lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap.rb +7 -0
  38. data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +40 -0
  39. data/lib/cheftacular/stateless_actions/chef_environment.rb +21 -0
  40. data/lib/cheftacular/stateless_actions/clean_cookbooks.rb +104 -0
  41. data/lib/cheftacular/stateless_actions/clean_sensu_plugins.rb +19 -0
  42. data/lib/cheftacular/stateless_actions/clean_server_passwords.rb +14 -0
  43. data/lib/cheftacular/stateless_actions/cleanup_log_files.rb +14 -0
  44. data/lib/cheftacular/stateless_actions/client_list.rb +89 -0
  45. data/lib/cheftacular/stateless_actions/cloud.rb +107 -0
  46. data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +109 -0
  47. data/lib/cheftacular/stateless_actions/compile_audit_log.rb +60 -0
  48. data/lib/cheftacular/stateless_actions/compile_readme.rb +41 -0
  49. data/lib/cheftacular/stateless_actions/create_git_key.rb +67 -0
  50. data/lib/cheftacular/stateless_actions/disk_report.rb +75 -0
  51. data/lib/cheftacular/stateless_actions/environment.rb +100 -0
  52. data/lib/cheftacular/stateless_actions/fetch_file.rb +24 -0
  53. data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +70 -0
  54. data/lib/cheftacular/stateless_actions/full_bootstrap.rb +30 -0
  55. data/lib/cheftacular/stateless_actions/get_active_ssh_connections.rb +18 -0
  56. data/lib/cheftacular/stateless_actions/get_haproxy_log.rb +55 -0
  57. data/lib/cheftacular/stateless_actions/get_log_from_bag.rb +38 -0
  58. data/lib/cheftacular/stateless_actions/get_pg_pass.rb +61 -0
  59. data/lib/cheftacular/stateless_actions/help.rb +71 -0
  60. data/lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb +220 -0
  61. data/lib/cheftacular/stateless_actions/knife_upload.rb +23 -0
  62. data/lib/cheftacular/stateless_actions/pass.rb +49 -0
  63. data/lib/cheftacular/stateless_actions/reinitialize.rb +46 -0
  64. data/lib/cheftacular/stateless_actions/remove_client.rb +81 -0
  65. data/lib/cheftacular/stateless_actions/replication_status.rb +103 -0
  66. data/lib/cheftacular/stateless_actions/restart_swap.rb +55 -0
  67. data/lib/cheftacular/stateless_actions/rvm.rb +14 -0
  68. data/lib/cheftacular/stateless_actions/server_update.rb +99 -0
  69. data/lib/cheftacular/stateless_actions/service.rb +14 -0
  70. data/lib/cheftacular/stateless_actions/test_env.rb +82 -0
  71. data/lib/cheftacular/stateless_actions/update_split_branches.rb +64 -0
  72. data/lib/cheftacular/stateless_actions/update_tld.rb +62 -0
  73. data/lib/cheftacular/stateless_actions/upload_nodes.rb +120 -0
  74. data/lib/cheftacular/stateless_actions/upload_roles.rb +24 -0
  75. data/lib/cheftacular/version.rb +5 -0
  76. data/lib/cheftacular.rb +4 -0
  77. data/lib/cloud_interactor/authentication.rb +56 -0
  78. data/lib/cloud_interactor/cloud_interactor.rb +23 -0
  79. data/lib/cloud_interactor/domain/create.rb +17 -0
  80. data/lib/cloud_interactor/domain/create_record.rb +27 -0
  81. data/lib/cloud_interactor/domain/destroy.rb +17 -0
  82. data/lib/cloud_interactor/domain/destroy_record.rb +23 -0
  83. data/lib/cloud_interactor/domain/list.rb +9 -0
  84. data/lib/cloud_interactor/domain/list_records.rb +22 -0
  85. data/lib/cloud_interactor/domain/read.rb +23 -0
  86. data/lib/cloud_interactor/domain/read_record.rb +27 -0
  87. data/lib/cloud_interactor/domain/update.rb +18 -0
  88. data/lib/cloud_interactor/domain/update_record.rb +42 -0
  89. data/lib/cloud_interactor/domain.rb +18 -0
  90. data/lib/cloud_interactor/flavor.rb +27 -0
  91. data/lib/cloud_interactor/helpers.rb +70 -0
  92. data/lib/cloud_interactor/image.rb +27 -0
  93. data/lib/cloud_interactor/parser.rb +37 -0
  94. data/lib/cloud_interactor/server/attach_volume.rb +33 -0
  95. data/lib/cloud_interactor/server/create.rb +39 -0
  96. data/lib/cloud_interactor/server/destroy.rb +11 -0
  97. data/lib/cloud_interactor/server/detach_volume.rb +21 -0
  98. data/lib/cloud_interactor/server/list.rb +7 -0
  99. data/lib/cloud_interactor/server/list_volumes.rb +25 -0
  100. data/lib/cloud_interactor/server/poll.rb +22 -0
  101. data/lib/cloud_interactor/server/read.rb +9 -0
  102. data/lib/cloud_interactor/server/read_volume.rb +24 -0
  103. data/lib/cloud_interactor/server.rb +17 -0
  104. data/lib/cloud_interactor/version.rb +4 -0
  105. data/lib/cloud_interactor/volume/create.rb +13 -0
  106. data/lib/cloud_interactor/volume/destroy.rb +11 -0
  107. data/lib/cloud_interactor/volume/list.rb +7 -0
  108. data/lib/cloud_interactor/volume/read.rb +9 -0
  109. data/lib/cloud_interactor/volume.rb +20 -0
  110. data/lib/ridley/monkeypatches.rb +11 -0
  111. data/lib/sshkit/actions/start_commit_check.rb +19 -0
  112. data/lib/sshkit/actions/start_deploy.rb +25 -0
  113. data/lib/sshkit/actions/start_log_fetch.rb +91 -0
  114. data/lib/sshkit/actions/start_task.rb +29 -0
  115. data/lib/sshkit/getters.rb +67 -0
  116. data/lib/sshkit/helpers.rb +13 -0
  117. data/lib/sshkit/monkeypatches.rb +19 -0
  118. metadata +375 -0
@@ -0,0 +1,24 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def fetch_file
4
+ @config['documentation']['stateless_action'] << [
5
+ "`cft fetch_file NODE_NAME LOCATION_ALIAS FILE_NAME` fetches a file from the remote node. ",
6
+
7
+ [
8
+ " 1. `LOCATION_ALIAS` will be parsed as a path if it has backslash characters. Otherwise it will be parsed from your " +
9
+ "location_aliases hash in your cheftacular.yml",
10
+
11
+ " 2. `FILE_NAME` is the actual name of the file to be fetched. If no value is passed or the file does not exist in the " +
12
+ "LOCATION_ALIAS, the command will return the entries in LOCATION_ALIAS"
13
+ ]
14
+ ]
15
+ end
16
+ end
17
+
18
+ class StatelessAction
19
+ def fetch_file out=[]
20
+ #TODO
21
+ raise "Not yet implemented"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,70 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def fix_known_hosts
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft fix_known_hosts [HOSTNAME]` this command will delete entries in your known_hosts file " +
7
+ "for all the servers that are in our system (ip addresses AND dns names)",
8
+
9
+ [
10
+ " 1. Passing in a hostname will make the command only remove entries with that hostname / ip specifically"
11
+ ]
12
+ ]
13
+
14
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
15
+ end
16
+ end
17
+
18
+ class StatelessAction
19
+ def fix_known_hosts
20
+ include Config
21
+
22
+ targets = ["all"]
23
+
24
+ if ARGV[1].class == String
25
+ targets = [ARGV[1]]
26
+ end
27
+
28
+ if targets.first == 'all'
29
+ nodes = @config['getter'].get_true_node_objects(true)
30
+ arr = []
31
+ environments = (nodes.map { |n| n.chef_environment }).uniq
32
+
33
+ environments.delete("_default")
34
+
35
+ environments.each do |env|
36
+ @config[env]['addresses_bag_hash'].each do |serv_hash|
37
+ arr << serv_hash['dn'].split('.').first
38
+ arr << serv_hash['public']
39
+ end
40
+ end
41
+
42
+ targets = arr.uniq
43
+ end
44
+
45
+ targets.each do |target|
46
+ case CONFIG['host_os']
47
+ when /mswin|windows/i
48
+ raise "#{ __method__ } does not support this operating system at this time"
49
+ when /linux|arch/i
50
+ cleanup_known_hosts_for_BSD_linux_architecture target
51
+ when /sunos|solaris/i
52
+ raise "#{ __method__ } does not support this operating system at this time"
53
+ when /darwin/i
54
+ cleanup_known_hosts_for_BSD_linux_architecture target
55
+ else
56
+ raise "#{ __method__ } does not support this operating system at this time"
57
+ end
58
+ end
59
+ end
60
+ private
61
+
62
+ def cleanup_known_hosts_for_BSD_linux_architecture target
63
+ #Removes the entire line containing the string
64
+ `sed -i '' "s/#{ target }.*//g" ~/.ssh/known_hosts`
65
+
66
+ #remove empty lines
67
+ `sed -i '' "/^$/d" ~/.ssh/known_hosts`
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,30 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def full_bootstrap
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft full_bootstrap ADDRESS ROOT_PASS NODE_NAME` This command performs both " +
7
+ "#{ @config['cheftacular']['preferred_cloud_os'] }_bootstrap and chef_bootstrap."
8
+ ]
9
+ end
10
+ end
11
+
12
+ class StatelessAction
13
+ def full_bootstrap
14
+ raise "This action can only be performed if the mode is set to devops" if !@config['helper'].running_in_mode?('devops') && !@options['in_scaling']
15
+
16
+ @options['address'] = ARGV[1] unless @options['address']
17
+ @options['client_pass'] = ARGV[2] unless @options['client_pass']
18
+ @options['node_name'] = ARGV[3] unless @options['node_name']
19
+
20
+ case @config['cheftacular']['preferred_cloud_os']
21
+ when 'ubuntu' || 'debian' then @config['stateless_action'].ubuntu_bootstrap
22
+ else @config['stateless_action'].instance_eval("#{ @config['cheftacular']['preferred_cloud_os'] }_bootstrap")
23
+ end
24
+
25
+ @config['initializer'].initialize_passwords @options['env'] #reset the passwords var to contain the new deploy pass set in ubuntu_bootstrap
26
+
27
+ @config['stateless_action'].chef_bootstrap
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def get_active_ssh_connections
4
+ @config['documentation']['stateless_action'] << [
5
+ "`cft get_active_ssh_connections` will fetch the active ssh connections from every server and output it into your log directory."
6
+ ]
7
+
8
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
9
+ end
10
+ end
11
+
12
+ class StatelessAction
13
+ def get_active_ssh_connections
14
+ # netstat -atn | grep ':22'
15
+ raise "Not yet implemented"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,55 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def get_haproxy_log
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft get_haproxy_log` this command will generate a haproxy html file for the load balancer(s) associated with a repository in the log directory. " +
7
+ "Opening this log file in the browser will show the status of that haproxy at the time of the log. ",
8
+
9
+ [
10
+ " 1. In devops mode, this command will not do anything without the -R repository passed."
11
+ ]
12
+ ]
13
+
14
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
15
+ end
16
+ end
17
+
18
+ class StatelessAction
19
+ def get_haproxy_log
20
+ nodes = @config['getter'].get_true_node_objects true
21
+
22
+ nodes = @config['parser'].exclude_nodes( nodes, [{ unless: "role[#{ @config['cheftacular']['haproxy_config']['role_name'] }]" }, { if: { not_env: @options['env'] } }])
23
+
24
+ #this must always precede on () calls so they have the instance variables they need
25
+ options, locs, ridley, logs_bag_hash, pass_bag_hash, bundle_command, cheftacular, passwords = @config['helper'].set_local_instance_vars
26
+
27
+ #on is namespaced to SSHKit::Backend::Netssh.on
28
+ on ( nodes.map { |n| "deploy@" + n.public_ipaddress } ) do |host|
29
+ n = get_node_from_address(nodes, host.hostname)
30
+
31
+ puts("Beginning haproxy log generation run for #{ n.name } (#{ n.public_ipaddress })") unless options['quiet']
32
+
33
+ start_haproxy_log_generator( n.name, n.public_ipaddress, options, locs, cheftacular, passwords)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ module SSHKit
40
+ module Backend
41
+ class Netssh
42
+ def start_haproxy_log_generator name, ip_address, options, locs, cheftacular, passwords, out=[]
43
+ log_loc, timestamp = set_log_loc_and_timestamp(locs)
44
+
45
+ puts("Generating log file for haproxy for #{ name } (#{ ip_address }) at #{ log_loc }/#{ name }-haproxy-#{ timestamp }.html") unless options['quiet']
46
+
47
+ out << sudo_capture( passwords[ip_address], :curl, "localhost:#{ cheftacular['haproxy_config']['default_port'] }" )
48
+
49
+ ::File.open("#{ log_loc }/#{ name }-haproxy-#{ timestamp }.html", "w") { |f| f.write(out.join("\n").scrub_pretty_text.gsub('[sudo] password for deploy: ', '')) } unless options['no_logs']
50
+
51
+ puts(out) if options['output'] || options['verbose']
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,38 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def get_log_from_bag
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft get_log_from_bag <NODE_NAME-COMMAND_TYPE>` this command grabs the latest command run log from the data bags " +
7
+ "and saves it to your log directory. There are different types of logs saved per server depending on command."
8
+ ]
9
+
10
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
11
+ end
12
+ end
13
+
14
+ class StatelessAction
15
+ def get_log_from_bag
16
+ #TODO https://stackoverflow.com/questions/17882463/compressing-large-string-in-ruby
17
+ log_loc, timestamp = @config['helper'].set_log_loc_and_timestamp
18
+
19
+ @options['role'] = 'all' unless @options['role']
20
+
21
+ nodes = @config['getter'].get_true_node_objects(true)
22
+
23
+ nodes = @config['parser'].exclude_nodes( nodes, [{ unless: { env: @options['env'] }}])
24
+
25
+ nodes.each do |node|
26
+ if @config[@options['env']]['logs_bag_hash'].has_key?("#{ node.name }-deploy")
27
+ puts("Found log data in logs bag. Outputting to #{ log_loc }/#{ node.name }-deploystash-#{ @config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:timestamp] }.txt") unless @options['quiet']
28
+
29
+ File.open("#{ log_loc }/#{ node.name }-deploystash-#{@config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:timestamp] }.txt", "w") do |f|
30
+ f.write(@config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:text])
31
+ end
32
+
33
+ puts(@config[@options['env']]['logs_bag_hash']["#{ node.name }-deploy"][:text]) if @options['verbose']
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,61 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def get_pg_pass
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft get_pg_pass ['clip']` command will output the current environment's pg_password to your terminal. " +
7
+ "Optionally you can pass in clip like `cft get_pg_pass clip` to have it also copy the pass to your clipboard."
8
+ ]
9
+
10
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
11
+ end
12
+ end
13
+
14
+ class StatelessAction
15
+ def get_pg_pass clip=false, target_repos=[]
16
+
17
+ @config['parser'].parse_role(@options['role'])
18
+
19
+ clip = ARGV[1] == 'clip'
20
+
21
+ if @options['role']
22
+ target_repos << @config['cheftacular']['repositories'][@options['role']]
23
+ else
24
+ @config['cheftacular']['repositories'].each_pair do |short_repo_name, repo_hash|
25
+ target_repos << repo_hash if repo_hash['database'] == 'postgresql'
26
+ end
27
+ end
28
+
29
+ target_repos.each do |repo_hash|
30
+ db_user = repo_hash['application_database_user']
31
+ database = repo_hash.has_key?('custom_database_name') ? repo_hash['custom_database_name'] : repo_hash['repo_name']
32
+ password = @config[@options['env']]['chef_passwords_bag_hash']['pg_pass']
33
+
34
+ ap @config[@options['env']]['chef_passwords_bag_hash']
35
+
36
+ if @config[@options['env']]['chef_passwords_bag_hash'].has_key?(repo_hash['repo_name']) && @config[@options['env']]['chef_passwords_bag_hash'][repo_hash['repo_name']].has_key?('pg_pass')
37
+ password = @config[@options['env']]['chef_passwords_bag_hash'][repo_hash['repo_name']]['pg_pass'] unless @config[@options['env']]['chef_passwords_bag_hash'][repo_hash['repo_name']]['pg_pass'].empty?
38
+ end
39
+
40
+ puts "postgres password for user #{ db_user } in database #{ database }_#{ @options['env'] } is #{ password }"
41
+ end
42
+
43
+ if clip && target_repos.count == 1
44
+ case CONFIG['host_os']
45
+ when /mswin|windows/i
46
+ raise "#{ __method__ } does not support this operating system at this time"
47
+ when /linux|arch/i
48
+ raise "#{ __method__ } does not support this operating system at this time"
49
+ when /sunos|solaris/i
50
+ raise "#{ __method__ } does not support this operating system at this time"
51
+ when /darwin/i
52
+ `echo '#{ password }' | pbcopy`
53
+ else
54
+ raise "#{ __method__ } does not support this operating system at this time"
55
+ end
56
+ elsif clip && target_repos.count > 1
57
+ puts "Unable to insert database string into clipboard, please copy paste as normal"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,71 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def help
4
+ @config['documentation']['stateless_action'] << [
5
+ "`cft help COMMAND|MODE` this command returns the documentation for a specific command if COMMAND matches the name of a command. " +
6
+ "Alternatively, it can be passed `action|arguments|application|current|devops|stateless_action` to fetch the commands for a specific mode." +
7
+ "Misspellings of commands will display near hits."
8
+ ]
9
+
10
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
11
+ end
12
+ end
13
+
14
+ class StatelessAction
15
+ def help inference_modes=[]
16
+ target_command = @options['command'] == 'help' ? ARGV[1] : ARGV[0]
17
+ target_command = @config['cheftacular']['mode'] if target_command == 'current'
18
+
19
+ case target_command
20
+ when 'action' then inference_modes << 'action'
21
+ when 'application' || 'devops' then inference_modes << 'both'
22
+ when 'stateless_action' then inference_modes << 'stateless_action'
23
+ end
24
+
25
+ if @config['helper'].is_command? target_command
26
+ @config['action_documentation'].send(target_command)
27
+
28
+ puts @config['documentation']['action'].flatten.join("\n\n")
29
+
30
+ elsif @config['helper'].is_stateless_command? target_command
31
+ @config['stateless_action_documentation'].send(target_command)
32
+
33
+ puts @config['documentation']['stateless_action'].flatten.join("\n\n")
34
+ end
35
+
36
+ @config['action_documentation'].public_methods(false).each do |method|
37
+ @config['action_documentation'].send(method)
38
+
39
+ end if inference_modes.include?('action') || inference_modes.include?('both')
40
+
41
+ @config['stateless_action_documentation'].instance_methods(false).each do |method|
42
+ @config['stateless_action_documentation'].send(method)
43
+
44
+ end if inference_modes.include?('stateless_action') || inference_modes.include?('both')
45
+
46
+ puts @config['helper'].compile_documentation_lines('action').flatten.join("\n\n") if target_command == 'action'
47
+
48
+ puts @config['documentation']['arguments'].flatten.join("\n\n") if target_command == 'arguments'
49
+
50
+ puts @config['helper'].compile_documentation_lines('stateless_action').flatten.join("\n\n") if target_command == 'stateless_action'
51
+
52
+ puts @config['helper'].compile_documentation_lines('application').flatten.join("\n\n") if target_command == 'application'
53
+
54
+ puts @config['helper'].compile_documentation_lines('devops').flatten.join("\n\n") if target_command == 'devops'
55
+
56
+ if inference_modes.empty? && @config['helper'].is_not_command_or_stateless_command?(target_command)
57
+ methods = @config['action_documentation'].public_methods(false) + @config['action_documentation'].public_methods(false)
58
+
59
+ puts methods.sort
60
+
61
+ sorted_methods = methods.uniq.sort_by { |method| @config['helper'].compare_strings(target_command, method.to_s)}
62
+
63
+ puts "Unable to find documentation for #{ target_command }, did you mean:"
64
+ puts " #{ sorted_methods.at(0) }"
65
+ puts " #{ sorted_methods.at(1) }"
66
+ puts " #{ sorted_methods.at(2) }\n"
67
+ puts "If so, please run 'cft help COMMAND' with one of the above commands or run 'hip help application' to see a list of commands"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,220 @@
1
+ class Cheftacular
2
+ class StatelessActionDocumentation
3
+ def initialize_data_bag_contents
4
+ @config['documentation']['stateless_action'] << [
5
+ "`cft initialize_data_bag_contents ENVIRONMENT_NAME` will ensure the data bags always have the correct structure before each run. " +
6
+ "This command is run every time the gem is started and if called directly, will exit after completion."
7
+ ]
8
+ end
9
+ end
10
+
11
+ class StatelessAction
12
+ def initialize_data_bag_contents env
13
+ raise "Environment does not exist on chef server!" unless @config['chef_environments'].include?(env)
14
+
15
+ @config['initializer'].initialize_audit_bag_contents env
16
+
17
+ @config['initializer'].initialize_authentication_bag_contents
18
+
19
+ @config['initializer'].initialize_chef_passwords_bag_contents env
20
+
21
+ @config['initializer'].initialize_config_bag_contents env
22
+
23
+ #@config['initializer'].initialize_server_passwords_bag_contents env
24
+
25
+ @config['initializer'].initialize_addresses_bag_contents env
26
+
27
+ #@config['initializer'].initialize_logs_bag_contents env
28
+
29
+ #@config['ChefDataBag'].initialize_node_roles_bag_contents env
30
+ end
31
+ end
32
+
33
+ class Initializer
34
+ def initialize_authentication_bag_contents save_on_finish=false, exit_on_finish=false
35
+ hash = @config['default']['authentication_bag_hash']
36
+
37
+ auth_fix_message = "\n\n knife data bag edit default authentication --secret-file " +
38
+ "#{ @config['locs']['chef'] }/#{ @config['cheftacular']['data_bag_key_file'] } \n\n"
39
+
40
+ unless hash.has_key?('authorized_keys')
41
+ hash['authorized_keys'] = []
42
+
43
+ puts "Critical! No Authorized Keys for ssh detected in the default authentication bag! " +
44
+ "These must be created. Use cft add_ssh_key_to_bag \"YOUR_SSH_KEY\"."
45
+
46
+ save_on_finish, exit_on_finish = true,true
47
+ end
48
+
49
+ hash['specific_repository_authorized_keys'] = {} unless hash.has_key?('specific_repository_authorized_keys')
50
+
51
+ @config['getter'].get_repo_names_for_repositories.each_key do |repo_name|
52
+ unless hash['specific_repository_authorized_keys'].has_key?(repo_name)
53
+ hash['specific_repository_authorized_keys'][repo_name] = []
54
+
55
+ save_on_finish = true
56
+ end
57
+ end
58
+
59
+ hash['cloud_auth'] = {} unless hash.has_key?('cloud_auth')
60
+
61
+ unless hash['cloud_auth'].has_key?(@options['preferred_cloud'])
62
+ hash['cloud_auth'][@options['preferred_cloud']] = {}
63
+
64
+ puts "Critical! No Cloud credentials detected for cloud #{ @options['preferred_cloud'] }, " +
65
+ "Someone will need to edit the authentication data bag with the command " +
66
+ auth_fix_message +
67
+ "And add the correct cloud credentials to the hash for your preferred cloud!"
68
+
69
+ save_on_finish, exit_on_finish = true,true
70
+ end
71
+
72
+ if hash['cloud_auth'].has_key?('rackspace')
73
+ if !( hash['cloud_auth']['rackspace'].has_key?('username') || hash['cloud_auth']['rackspace'].has_key?('api_key') || hash['cloud_auth']['rackspace'].has_key?('email'))
74
+
75
+ hash['cloud_auth']['rackspace']['username'] = "" unless hash['cloud_auth']['rackspace'].has_key?('username')
76
+ hash['cloud_auth']['rackspace']['api_key'] = "" unless hash['cloud_auth']['rackspace'].has_key?('api_key')
77
+ hash['cloud_auth']['rackspace']['email'] = "" unless hash['cloud_auth']['rackspace'].has_key?('email')
78
+
79
+
80
+ puts "Critical! No cloud credentials detected for the rackspace cloud_auth hash! There must be both a valid username and an api_key in this hash!"
81
+ puts "Please run #{ auth_fix_message }Fill in the blank strings with your rackspace credentials."
82
+
83
+ save_on_finish, exit_on_finish = true,true
84
+ elsif hash['cloud_auth']['rackspace']['username'].empty? || hash['cloud_auth']['rackspace']['api_key'].empty? || hash['cloud_auth']['rackspace']['api_key'].empty?
85
+ puts "Critical! Cloud credentials detected for the rackspace cloud_auth hash are blank!"
86
+ puts "Please run #{ auth_fix_message }Fill in the blank strings with your rackspace credentials."
87
+
88
+ exit_on_finish = true
89
+ end
90
+ end
91
+
92
+ @config['ChefDataBag'].save_authentication_bag if save_on_finish
93
+
94
+ exit if exit_on_finish
95
+ end
96
+
97
+ #User Action Generated: {"1.2.3.4-deploy-pass": "S325DSAGBCVfg5", "1.2.3.4-root-pass": "7dfDSFgb5%231", "1.2.3.4-name": "test"}
98
+ def initialize_server_passwords_bag_contents env
99
+
100
+ end
101
+
102
+ #User Action Generated: {"name": "api1", "public": "1.2.3.4", "address": "10.208.1.2", "dn":"api1.example.com", "descriptor": "lb:my-backend-codebase"}
103
+ def initialize_addresses_bag_contents env, save_on_finish=false
104
+ hash = @config[env]['addresses_bag_hash']
105
+
106
+ unless hash.has_key?('addresses')
107
+ hash['addresses'] = []
108
+
109
+ save_on_finish = true
110
+ end
111
+
112
+ @config['ChefDataBag'].save_addresses_bag(env) if save_on_finish
113
+ end
114
+
115
+ #User Action Generated: {"#{ NODE_NAME }-#{ COMMAND }": "CONTENT FROM RUN"}
116
+ def initialize_log_bag_contents env
117
+
118
+ end
119
+
120
+ #TODO Reexamine, this might cause issues with the nested hash on encrypted saves
121
+ def initialize_chef_passwords_bag_contents env, save_on_finish=false, exit_on_finish=false
122
+ hash = @config[env]['chef_passwords_bag_hash']
123
+
124
+ @config['cheftacular']['global_chef_passwords'].each_pair do |pass_key, pass_length|
125
+ hash[pass_key] = @config['helper'].gen_pass(pass_length) unless hash.has_key?(pass_key)
126
+
127
+ save_on_finish = true
128
+ end
129
+
130
+ @config['getter'].get_repo_names_for_repositories.each_pair do |repo_name, repo_hash|
131
+ hash[repo_name] = {} unless hash.has_key?(repo_name)
132
+
133
+ if repo_hash.has_key?('specific_chef_passwords')
134
+ repo_hash['specific_chef_passwords'].each_pair do |pass_key, pass_length|
135
+ unless hash[repo_name].has_key?(pass_key)
136
+ hash[repo_name][pass_key] = @config['helper'].gen_pass(pass_length)
137
+
138
+ save_on_finish = true
139
+ end
140
+ end
141
+ end
142
+
143
+ save_on_finish = true unless hash[repo_name].has_key?(repo_name)
144
+ end
145
+
146
+ @config['ChefDataBag'].save_chef_passwords_bag(env) if save_on_finish
147
+ end
148
+
149
+ def initialize_config_bag_contents main_env, save_on_finish=false, exit_on_finish=false
150
+ hash = @config[main_env]['config_bag_hash']
151
+
152
+ envs_to_build_in_hash = [main_env]
153
+
154
+ config_fix_message = "\n\n knife data bag edit #{ main_env } config\n\n"
155
+
156
+ if @config['cheftacular']['split_environments'].has_key?(main_env)
157
+ @config['cheftacular']['split_environments'][main_env].each_key do |sub_env|
158
+ envs_to_build_in_hash << sub_env
159
+ end
160
+ end
161
+
162
+ envs_to_build_in_hash.each do |env|
163
+ if !hash[env].has_key?('tld') || ( hash[env].has_key?('tld') && hash[env]['tld'].blank? )
164
+ hash[env]['tld'] = "" unless hash[env].has_key?('tld')
165
+
166
+ puts "WARNING! The config bag in environment: #{ main_env }(sub-env: #{ env }) does not have a top level domain set!"
167
+ puts "Please run #{ config_fix_message }And update the tld key!"
168
+
169
+ save_on_finish, exit_on_finish = true,true
170
+ end
171
+
172
+ unless hash[env].has_key?('restore_backups')
173
+ hash[env]['restore_backups'] = false
174
+
175
+ save_on_finish = true
176
+ end
177
+
178
+ unless hash[env].has_key?('fetch_backups')
179
+ hash[env]['fetch_backups'] = false
180
+
181
+ save_on_finish = true
182
+ end
183
+
184
+ unless hash[env].has_key?('app_revisions')
185
+ hash[env]['app_revisions'] = {}
186
+
187
+ save_on_finish = true
188
+ end
189
+ end
190
+
191
+ @config['ChefDataBag'].save_config_bag(main_env) if save_on_finish
192
+ end
193
+
194
+ # User Action Generated (see Cheftacular::StatelessAction.upload_nodes)
195
+ def initialize_node_roles_bag_contents env
196
+ hash = @config[env]['node_roles_bag_hash']
197
+
198
+ unless hash.has_key?('node_roles')
199
+ hash['node_roles'] = {}
200
+
201
+ save_on_finish = true
202
+ end
203
+
204
+ @config['ChefDataBag'].save_node_roles_bag(env) if save_on_finish
205
+ end
206
+
207
+ # User Action Generated (see Cheftacular::StatelessAction.compile_audit_log)
208
+ def initialize_audit_bag_contents env, save_on_finish=false
209
+ hash = @config[env]['audit_bag_hash']
210
+
211
+ unless hash.has_key?('audit_log')
212
+ hash['audit_log'] = {}
213
+
214
+ save_on_finish = true
215
+ end
216
+
217
+ @config['ChefDataBag'].save_audit_bag(env) if save_on_finish
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,23 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def knife_upload
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft knife_upload` will resync the chef-server with the local chef-repo code. " +
7
+ "This command is analog for `knife upload /`"
8
+ ]
9
+ end
10
+ end
11
+
12
+ class StatelessAction
13
+ def knife_upload
14
+ raise "This action can only be performed if the mode is set to devops" unless @config['helper'].running_in_mode?('devops')
15
+
16
+ puts("Starting upload...") unless @options['quiet']
17
+
18
+ out = `knife upload / --chef-repo-path #{ @config['locs']['chef-repo'] }`
19
+
20
+ puts out
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+
2
+ class Cheftacular
3
+ class StatelessActionDocumentation
4
+ def pass
5
+ @config['documentation']['stateless_action'] << [
6
+ "`cft pass NODE_NAME` will drop the server's sudo password into your clipboard. " +
7
+ "Useful for when you need to ssh into the server itself and try advanced linux commands"
8
+ ]
9
+
10
+ @config['documentation']['application'] << @config['documentation']['stateless_action'].last
11
+ end
12
+ end
13
+
14
+ class StatelessAction
15
+ def pass
16
+ @options['node_name'] = ARGV[1] unless @options['node_name']
17
+
18
+ raise "Too few arguments, please supply a node name" if ARGV.length < 2
19
+
20
+ nodes = @config['getter'].get_true_node_objects(true)
21
+
22
+ nodes = @config['parser'].exclude_nodes( nodes, [{ if: { not_node: @options["node_name"] } }], true )
23
+
24
+ raise "Node not found for #{ @options['node_name'] }" if nodes.empty?
25
+
26
+ if nodes.first.chef_environment != @options['env']
27
+ @config['initializer'].initialize_data_bags_for_environment nodes.first.chef_environment, false, ['server_passwords']
28
+ end
29
+
30
+ puts "The password for #{ nodes.first.name }(#{ nodes.first.public_ipaddress }) for env #{ nodes.first.chef_environment }" +
31
+ " is #{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }"
32
+
33
+ case CONFIG['host_os']
34
+ when /mswin|windows/i
35
+ raise "#{ __method__ } does not support this operating system at this time"
36
+ when /linux|arch/i
37
+ raise "#{ __method__ } does not support this operating system at this time"
38
+ when /sunos|solaris/i
39
+ raise "#{ __method__ } does not support this operating system at this time"
40
+ when /darwin/i
41
+ puts "Copying #{ nodes.first.name } (#{ nodes.first.public_ipaddress }) sudo password into your clipboard"
42
+
43
+ `echo '#{ @config[nodes.first.chef_environment]['server_passwords_bag_hash']["#{ nodes.first.public_ipaddress }-deploy-pass"] }' | pbcopy`
44
+ else
45
+ raise "#{ __method__ } does not support this operating system at this time"
46
+ end
47
+ end
48
+ end
49
+ end