cheftacular 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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