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,451 @@
1
+
2
+ class Cheftacular
3
+ class Initializer
4
+ def initialize options, config
5
+ @options, @config = options, config
6
+
7
+ initialize_yaml_configuration
8
+
9
+ initialize_environment
10
+
11
+ initialize_locations
12
+
13
+ initialize_monkeypatches unless @config['helper'].running_on_chef_node?
14
+
15
+ initialize_arguments
16
+
17
+ initialize_sub_environment
18
+
19
+ initialize_cloud_options
20
+
21
+ initialize_documentation_hash
22
+
23
+ @config['helper'].completion_rate? 0, 'initializer'
24
+
25
+ initialize_ridley
26
+
27
+ @config['helper'].completion_rate? 10, 'initializer'
28
+
29
+ initialize_ridley_environments
30
+
31
+ @config['helper'].completion_rate? 20, 'initializer'
32
+
33
+ initialize_ridley_roles_and_nodes
34
+
35
+ @config['helper'].completion_rate? 30, 'initializer'
36
+
37
+ initialize_data_bags_for_environment @options['env'], true
38
+
39
+ @config['helper'].completion_rate? 90, 'initializer'
40
+
41
+ initialize_ruby_config
42
+
43
+ initialize_passwords @options['env']
44
+
45
+ initialize_classes
46
+
47
+ initialize_directories
48
+
49
+ @config['helper'].completion_rate? 100, 'initializer'
50
+
51
+ initialize_version_check if @config['cheftacular']['strict_version_checks'] == 'true'
52
+
53
+ initialize_auditing_checks if @config['cheftacular']['auditing'] == 'true'
54
+ end
55
+
56
+ #changes to arguments should show up in the documentation methods in their appropriate method file
57
+ def initialize_arguments
58
+ OptionParser.new do |opts|
59
+ opts.banner = "Usage: cft command [repository] [opts]"
60
+
61
+ # Environment arguments
62
+
63
+ opts.on('-b', '--datastaging', 'Set the environment to datastaging') do
64
+ @options['env'] = 'datastaging'
65
+ end
66
+
67
+ opts.on('-d', '--dev-remote', "Set the environment to devremote") do
68
+ @options['env'] = 'devremote'
69
+ end
70
+
71
+ opts.on('--env ENV', 'Set the environment to one you specify') do |env|
72
+ @options['env'] = env
73
+ end
74
+
75
+ opts.on('-p', '--prod', "Set the environment to production") do
76
+ @options['env'] = 'production'
77
+ end
78
+
79
+ opts.on('-Q','--qa', 'Set the environment to QA') do
80
+ @options['env'] = 'qa'
81
+ end
82
+
83
+ opts.on('-s', '--staging', "Set the environment to staging (this is the default)") do
84
+ @options['env'] = 'staging'
85
+ end
86
+
87
+ opts.on('--split-env SPLIT_ENV_NAME', "Set the sub-environment to the specified split_env") do |sub_env|
88
+ @options['sub_env'] = sub_env
89
+ end
90
+
91
+ opts.on('-t', '--test', 'Set the environment to test') do
92
+ @options['env'] = 'test'
93
+ end
94
+
95
+ # General arguments
96
+
97
+ opts.on('-a', '--address ADDRESS', "Run your command against this address") do |addr|
98
+ @options['address'] = addr
99
+ end
100
+
101
+ opts.on('-D', '--debug', "Activate extremely verbose logging") do
102
+ @options['debug'] = true
103
+ @options['verbose'] = true
104
+ end
105
+
106
+ opts.on('-n', '--node-name NAME', "Run your command against this node_name") do |name|
107
+ @options['node_name'] = name
108
+ end
109
+
110
+ opts.on('-q', '--quiet', "Deactivates most forms of output") do
111
+ @options['quiet'] = true
112
+ end
113
+
114
+ opts.on('-r', '--role-name NAME', "Run your command against this role_name") do |name|
115
+ @options['role'] = name
116
+ end
117
+
118
+ opts.on('-R', '--repository NAME', 'Run your command against this repository / context') do |name|
119
+ @options['repository'] = name
120
+ end
121
+
122
+ opts.on('-v', '--verbose', "Activates slightly more verbose logging, also causes commands to output to terminal and logs") do
123
+ @options['verbose'] = true
124
+ end
125
+
126
+ opts.on('--no-logs', "Do not make logs for any command") do
127
+ @options['no_logs'] = true
128
+ end
129
+
130
+ opts.on('-h', '--help', 'Displays the README') do
131
+ @config['helper'].display_readme
132
+
133
+ puts "Remember, you can also utilize the cft help command!"
134
+
135
+ exit
136
+ end
137
+
138
+ # Action Arguments
139
+
140
+ opts.on('-e', '--except-role NAME', 'For deployments, will prevent the deploy from triggering on servers with this role') do |name|
141
+ @options['negative_role'] = name
142
+ end
143
+
144
+ opts.on('-z', '--unset-revision', 'Tells the chef-server that we want to return to using the default revision for a repository') do
145
+ @options['unset_revision'] = true
146
+ end
147
+
148
+ opts.on('-Z REVISION', '--revision REVISION', "Tells the chef-server what branch / revision it should deploy for a repository") do |revision|
149
+ @options['target_revision'] = revision
150
+ end
151
+
152
+ # client-list
153
+ opts.on('-W', '--with-priv', "On client-list this will show each server's private addresses") do
154
+ @options['with_private'] = true
155
+ end
156
+
157
+ # cft log options
158
+ opts.on('--nginx', "On cft log pass this argument to fetch nginx logs as well as application logs") do
159
+ @options['get_nginx_logs'] = true
160
+ end
161
+
162
+ opts.on('--full', "On cft log pass this argument to fetch the FULL log") do
163
+ @options['get_full_logs'] = true
164
+ end
165
+
166
+ opts.on('-l INTEGER', '--lines INTEGER', "On cft log pass this argument to fetch the last X lines of logs") do |num|
167
+ @options['get_log_lines'] = num
168
+ end
169
+
170
+ opts.on('--num INTEGER', "On cft log pass this argument to fetch the last X lines of logs") do |num|
171
+ @options['get_log_lines'] = num
172
+ end
173
+
174
+ #cft run
175
+ opts.on('--all', "On cft run COMMAND you can pass --all to run the command on multiple nodes") do
176
+ @options['run_on_all'] = true
177
+ end
178
+
179
+ #cloud_bootstrap
180
+
181
+ opts.on('--with-dn DOMAIN_NAME', "On hip rax_bootstrap allows you to specify a domain structure other than the default environment one") do |domain|
182
+ @options['with_dn'] = domain
183
+ end
184
+
185
+ #cloud
186
+
187
+ opts.on('-o', '--cloud CLOUD_NAME', "On cft cloud calls, set the cloud to the one you specify") do |cloud_name|
188
+ @options['preferred_cloud'] = cloud_name
189
+ end
190
+
191
+ opts.on('--rax', "On cft cloud calls, set the cloud to Rackspace") do
192
+ @options['preferred_cloud'] = 'rackspace'
193
+ end
194
+
195
+ opts.on('--aws', "On cft cloud calls, set the cloud to Amazon Web Services") do
196
+ @options['preferred_cloud'] = 'aws'
197
+ end
198
+
199
+ opts.on('--region REGION', 'On cft cloud calls, set the cloud region to perform operations on to this region') do |region|
200
+ @options['preferred_cloud_region'] = region
201
+ end
202
+
203
+ opts.on('--image IMAGE', 'On cft cloud calls, set the default image to this image (can be shorthand like "Ubuntu 14.04"') do |image|
204
+ @options['preferred_cloud_image'] = image
205
+ end
206
+
207
+ opts.on('--virtualization-mode MODE', 'On cft cloud calls, set the default virtualization mode to this (On rackspace, only PV or PVHVM are supported)') do |v_mode|
208
+ @options['virtualization_mode'] = v_mode
209
+ end
210
+
211
+ end.parse!
212
+ end
213
+
214
+ def initialize_yaml_configuration
215
+ config_location = if File.exist?(File.join( Dir.getwd, 'config', 'cheftacular.yml' ))
216
+ File.join( Dir.getwd, 'config', 'cheftacular.yml' )
217
+ elsif File.exist?('/root/cheftacular.yml')
218
+ '/root/cheftacular.yml'
219
+ else
220
+ raise "cheftacular.yml configuration file could not be found in either #{ File.join( Dir.getwd, 'config', 'cheftacular.yml' ) } or /root/cheftacular.yml"
221
+ end
222
+
223
+ @config['cheftacular'] = YAML::load(ERB.new(IO.read(File.open(config_location))).result)
224
+ rescue StandardError => e
225
+ puts "The cheftacular.yml configuration file could not be parsed."
226
+ puts "Error message: #{ e }\n#{ e.backtrace.join("\n") }"
227
+
228
+ exit
229
+ end
230
+
231
+ def initialize_environment
232
+ @options['env'] = @config['cheftacular']['initial_environment'] if @config['cheftacular'].has_key?('initial_environment')
233
+ end
234
+
235
+ def initialize_monkeypatches
236
+ if File.exists?(File.expand_path("#{ @config['locs']['app-root'] }/config/initializers/cheftacular.rb"))
237
+ puts "Cheftacular Monkeypatch file detected! Preparing to require..."
238
+
239
+ require "#{ @config['locs']['app-root'] }/config/initializers/cheftacular"
240
+ end
241
+ end
242
+
243
+ def initialize_cloud_options
244
+ @config['helper'].set_cloud_options
245
+ end
246
+
247
+ #only matters to the config_bag and it's hash. Used to fetch keys within the bag for certain commands
248
+ def initialize_sub_environment
249
+ @options['sub_env'] ||= @options['env']
250
+ end
251
+
252
+ def initialize_documentation_hash
253
+ @config['documentation'] ||= {}
254
+ @config['documentation']['arguments'] ||= []
255
+ @config['documentation']['action'] ||= []
256
+ @config['documentation']['stateless_action'] ||= []
257
+ @config['documentation']['application'] ||= []
258
+ @config['documentation']['devops'] ||= []
259
+ end
260
+
261
+ def initialize_locations
262
+ locs ||= {}
263
+
264
+ if @config['helper'].running_in_mode? 'application'
265
+ locs['root'] = Dir.getwd
266
+ locs['chef-log'] = File.join( locs['root'], 'log')
267
+ locs['app-root'] = locs['root']
268
+ elsif @config['helper'].running_on_chef_node?
269
+ locs['chef-log'] = File.expand_path("/root/sensu_log")
270
+ locs['chef'] = File.expand_path("/etc/chef")
271
+ locs['ssh'] = File.expand_path('/home/deploy/.ssh')
272
+ end
273
+
274
+ locs['chef-repo'] = Dir.getwd
275
+ locs['roles'] = File.expand_path("#{ locs['chef-repo'] }/roles")
276
+ locs['nodes'] = File.expand_path("#{ locs['chef-repo'] }/nodes_dir") #DO NOT RENAME THIS TO NODES
277
+ locs['root'] = locs['chef-repo'] unless locs['root']
278
+ locs['app-root'] = locs['chef-repo'] unless locs['app-root']
279
+ locs['chef'] = File.expand_path("~/.chef") unless locs['chef']
280
+ locs['cookbooks'] = File.expand_path("#{ locs['chef-repo'] }/cookbooks")
281
+ locs['berks'] = File.expand_path('~/.berkshelf/cookbooks')
282
+ locs['wrapper-cookbooks'] = @config['cheftacular']['wrapper-cookbooks']
283
+ locs['ssh'] = File.expand_path('~/.ssh')
284
+ locs['chef-log'] = File.expand_path("#{ locs['root']}/log") unless locs['chef-log']
285
+
286
+ @config['locs'] = locs
287
+ end
288
+
289
+ def initialize_ridley
290
+ return unless @config['ridley'].nil?
291
+
292
+ @config['data_bag_secret'] = File.read(File.expand_path("#{ @config['locs']['chef'] }/#{ @config['cheftacular']['data_bag_key_file'] }")).chomp
293
+
294
+ Ridley::Logging.logger.level = Logger.const_get 'ERROR'
295
+
296
+ @config['ridley'] = Ridley.new(
297
+ server_url: @config['cheftacular']['chef_server_url'],
298
+ client_name: (@config['helper'].running_on_chef_node? ? parse_node_name_from_client_file : @config['cheftacular']['cheftacular_chef_user']),
299
+ client_key: File.expand_path("#{ @config['locs']['chef'] }/#{ @config['helper'].running_on_chef_node? ? 'client.pem' : @config['cheftacular']['cheftacular_chef_user'] }.pem"),
300
+ encrypted_data_bag_secret: @config['data_bag_secret'],
301
+ ssl: { verify: @config['cheftacular']['ssl_verify'] == 'true' }
302
+ )
303
+ end
304
+
305
+ def initialize_ridley_environments
306
+ @config['chef_environments'] ||= @config['ridley'].environment.all.map { |env| env.name }.delete_if { |env| env == '_default' }
307
+ end
308
+
309
+ def initialize_ridley_roles_and_nodes
310
+ @config['chef_nodes'] ||= @config['ridley'].node.all
311
+ @config['chef_roles'] ||= @config['ridley'].role.all
312
+ end
313
+
314
+ def initialize_data_bags_for_environment env, in_initializer=false, bags_to_load=[]
315
+ @config['ChefDataBag'] ||= Cheftacular::ChefDataBag.new(@options, @config)
316
+
317
+ puts("Loading additional data bag data from chef server for environment \"#{ env }\" for bags: #{ bags_to_load.join(', ') }") if !in_initializer && !@options['quiet']
318
+
319
+ @config['ChefDataBag'].init_bag('default', 'authentication', false) if bags_to_load.empty? || bags_to_load.include?('authentication')
320
+
321
+ @config['helper'].completion_rate?(38, 'initializer') if in_initializer
322
+
323
+ @config['ChefDataBag'].init_bag(env, 'addresses', false) if bags_to_load.empty? || bags_to_load.include?('addresses')
324
+
325
+ @config['helper'].completion_rate?(46, 'initializer') if in_initializer
326
+
327
+ @config['ChefDataBag'].init_bag(env, 'audit', false) if bags_to_load.empty? || bags_to_load.include?('audit')
328
+
329
+ @config['helper'].completion_rate?(54, 'initializer') if in_initializer
330
+
331
+ @config['ChefDataBag'].init_bag(env, 'chef_passwords') if bags_to_load.empty? || bags_to_load.include?('chef_passwords')
332
+
333
+ @config['helper'].completion_rate?(62, 'initializer') if in_initializer
334
+
335
+ @config['ChefDataBag'].init_bag(env, 'config', false) if bags_to_load.empty? || bags_to_load.include?('config')
336
+
337
+ @config['helper'].completion_rate?(70, 'initializer') if in_initializer
338
+
339
+ @config['ChefDataBag'].init_bag(env, 'logs', false) if bags_to_load.empty? || bags_to_load.include?('logs')
340
+
341
+ @config['helper'].completion_rate?(78, 'initializer') if in_initializer
342
+
343
+ @config['ChefDataBag'].init_bag(env, 'node_roles', false) if bags_to_load.empty? || bags_to_load.include?('node_roles')
344
+
345
+ @config['helper'].completion_rate?(86, 'initializer') if in_initializer
346
+
347
+ @config['ChefDataBag'].init_bag(env, 'server_passwords') if bags_to_load.empty? || bags_to_load.include?('server_passwords')
348
+ end
349
+
350
+ def initialize_ruby_config
351
+ @config['ruby_string'] = @config['cheftacular']['ruby_version']
352
+
353
+ begin
354
+ @config['ruby_string'] = File.read(File.expand_path("#{ locs['app-root'] }/.ruby-version")) unless @config['ruby_string']
355
+ rescue StandardError => e
356
+ msg = [
357
+ "Please run this in the root of your application directory,",
358
+ " a ruby string to run commands against was not found in either your cheftacular.yml file or your .ruby-version file."
359
+ ]
360
+
361
+ @config['helper'].exception_output msg, e
362
+ end
363
+
364
+ @config['ruby_string'] = "ruby-" + @config['ruby_string'] unless @config['ruby_string'].include?('ruby-')
365
+
366
+ #TODO Reevaluate for non-rvm setups
367
+ @config['bundle_command'] = "/home/#{ @config['cheftacular']['deploy_user'] }/.rvm/gems/#{ @config['ruby_string'].chomp }@global/bin/bundle"
368
+ end
369
+
370
+ def initialize_passwords env, refresh_bag=false
371
+ @config['server_passwords'] ||= {}
372
+
373
+ @config[env]['server_passwords_bag'].reload if refresh_bag
374
+
375
+ @config[env]['server_passwords_bag_hash'] = @config[env]['server_passwords_bag'].decrypt.to_hash if refresh_bag
376
+
377
+ #data_hash will be { server_name: 'SERVER_NAME', password: 'PASSWORD_STRING' }
378
+ @config[env]['server_passwords_bag_hash'].each_pair do |key, data_hash|
379
+ if key.include?('-deploy-pass')
380
+ addr = key.split('-deploy-pass').first
381
+
382
+ @config['server_passwords'][addr] = data_hash
383
+ end
384
+ end
385
+ end
386
+
387
+ def initialize_version_check detected_version=""
388
+ current_version = Cheftacular::VERSION
389
+
390
+ detected_version = File.exists?( @config['helper'].current_version_file_path ) ? File.read( @config['helper'].current_version_file_path ) : @config['helper'].fetch_remote_version
391
+
392
+ if @config['helper'].is_higher_version? detected_version, current_version
393
+ puts "\n Your Cheftacular is out of date. Currently #{ current_version } and remote version is #{ detected_version }.\n"
394
+
395
+ puts "Please update the gemfile to #{ detected_version } and restart this process.\n"
396
+
397
+ exit
398
+ else
399
+ unless File.exists?( current_version_file_path )
400
+ puts "Creating file cache for #{ Time.now.strftime("%Y%m%d") } (#{ detected_version }). No new version detected."
401
+
402
+ @config['helper'].write_version_file detected_version
403
+ end
404
+ end
405
+ end
406
+
407
+ def initialize_auditing_checks
408
+ unless File.exists? @config['helper'].current_audit_file_path
409
+ puts "Creating file cache for #{ Time.now.strftime("%Y%m%d") } audit data..."
410
+
411
+ @config['auditor'].write_audit_cache_file
412
+ end
413
+ end
414
+
415
+ def initialize_classes
416
+ @config['auditor'] = Cheftacular::Auditor.new(@options, @config)
417
+ @config['parser'] = Cheftacular::Parser.new(@options, @config)
418
+ @config['getter'] = Cheftacular::Getter.new(@options, @config)
419
+ @config['action'] = Cheftacular::Action.new(@options, @config)
420
+ @config['stateless_action'] = Cheftacular::StatelessAction.new(@options, @config)
421
+ @config['encryptor'] = Cheftacular::Encryptor.new(@config['data_bag_secret'])
422
+ @config['decryptor'] = Cheftacular::Decryptor.new(@config['data_bag_secret'])
423
+ @config['action_documentation'] = Cheftacular::ActionDocumentation.new(@options, @config)
424
+ @config['stateless_action_documentation'] = Cheftacular::StatelessActionDocumentation.new(@options, @config)
425
+ @config['dummy_sshkit'] = SSHKit::Backend::Netssh.new(SSHKit::Host.new('127.0.0.1'))
426
+ end
427
+
428
+ def initialize_directories
429
+ FileUtils.mkdir_p @config['locs']['chef-log']
430
+
431
+ FileUtils.mkdir_p File.join( @config['locs']['app-root'], 'tmp', @config['helper'].declassify)
432
+
433
+ FileUtils.mkdir_p @config['helper'].current_nodes_file_cache_path
434
+
435
+ @config['helper'].cleanup_file_caches
436
+ end
437
+
438
+ def initialize_bag_for_all_environments bag_name, total_percent=100
439
+ total_bags = @config['chef_environments'].count
440
+ current_bags = 1
441
+
442
+ @config['chef_environments'].each do |env|
443
+ @config['ChefDataBag'].init_bag env, bag_name
444
+
445
+ @config['helper'].completion_rate? (percent + (( (current_bags).to_f / total_bags.to_f ) * 100) / ( 100.to_f / total_percent.to_f ) ), __method__
446
+
447
+ current_bags += 1
448
+ end
449
+ end
450
+ end
451
+ end
@@ -0,0 +1,199 @@
1
+
2
+ class Cheftacular
3
+ class Parser
4
+ def initialize options, config
5
+ @options, @config = options, config
6
+ end
7
+
8
+ #parses and *validates* the inputs from the initializer
9
+ def parse_context
10
+ return if @config['repository'] && @config['command'] && @config['role']
11
+
12
+ roles ||= []
13
+
14
+ @config['chef_roles'].each {|r| roles << r.name }
15
+
16
+ @options['command'] = ARGV[0] unless @options['command']
17
+
18
+ unless @config['helper'].is_stateless_command?(@options['command'])
19
+ parse_repository(@options['repository'])
20
+
21
+ parse_role(@options['role'])
22
+ end
23
+
24
+ parse_node_name(@options['node_name']) if @options['node_name']
25
+
26
+ parse_address(@options['address']) if @options['address']
27
+
28
+ parse_and_set_revision if @options['target_revision'] || @options['unset_revision']
29
+ end
30
+
31
+ #try and get the most accurate name of the repo
32
+ def parse_application_context
33
+ working_dir = Dir.getwd.split('/').last
34
+
35
+ #if there is no mapping setup for the directory, try and parse it from the .ruby-gemset file
36
+ if File.exist?(File.expand_path("#{ @config['locs']['app-root'] }/.ruby-gemset")) && !@config['getter'].get_repository_from_role_name(working_dir, "has_value?")
37
+ working_dir = File.read(File.expand_path("#{ @config['locs']['app-root'] }/.ruby-gemset")).chomp
38
+ end
39
+
40
+ if @config['getter'].get_repository_from_role_name(working_dir, "has_value?")
41
+ parse_repository(working_dir)
42
+
43
+ @options['repository'] = working_dir
44
+
45
+ @options['command'] = ARGV[0] unless @config['helper'].is_not_command_or_stateless_command?(ARGV[0])
46
+ end
47
+
48
+ return if !@options['codebase'].nil? && !@options['role'].nil? && !@options['command'].nil?
49
+ return if !@options['command'].nil? && @config['helper'].is_stateless_command?(ARGV[0])
50
+ end
51
+
52
+ def parse_repository repository, set_variables=true
53
+ repo_check_array = []
54
+
55
+ @config['cheftacular']['repositories'].each_value do |h|
56
+ repo_check_array << h['repo_name'].include?(repository) unless repository.nil?
57
+ end
58
+
59
+ if repository.nil? && @config['helper'].running_in_mode?('devops')
60
+ raise "Unable to parse a repository, please pass in the argument -c REPOSITORY to pass a repo"
61
+
62
+ elsif repo_check_array.include?(true)
63
+ @config['cheftacular']['repositories'].each_pair do |key, repo_hash|
64
+ @options['role'] = key if repo_hash['repo_name'] == repository && set_variables
65
+ end
66
+ else
67
+ raise "Unable to parse repository: #{ repository }, the repository you're referring to does not exist in your cheftacular.yml."
68
+ end
69
+ end
70
+
71
+ def parse_role role, mode="set"
72
+ roles ||= []
73
+ @config['chef_roles'].each {|r| roles << r.name }
74
+
75
+ case mode
76
+ when 'set'
77
+ if role.nil? then raise "Unable to parse a role, please pass in the argument -r ROLE_NAME to pass a role"
78
+ elsif roles.include?(role) then @options['role'] = role
79
+ else raise "Unable to parse role: #{ role }, #{ role } does not represent a valid role"
80
+ end
81
+ when 'boolean'
82
+ roles.include?(role)
83
+ end
84
+ end
85
+
86
+ def parse_node_name name
87
+ nodes ||= []
88
+ @config['chef_nodes'].each {|n| nodes << n.name }
89
+
90
+ if name.nil? then raise "You attempted to specify a node_name but did not pass one, please use -n NODE_NAME"
91
+ elsif nodes.include?(name) then @options['node_name'] = name
92
+ else raise "Unable to parse node_name: #{ name }, the node you're referring to does not exist."
93
+ end
94
+ end
95
+
96
+ def parse_address address
97
+ addresses ||= []
98
+ @config['chef_nodes'].each {|n| addresses << n.public_ipaddress }
99
+
100
+ if address.nil? then raise "You attempted to specify an address but did not pass one, please use -a IP_ADDRESS"
101
+ elsif addresses.include?(address) then @options['address'] = address
102
+ else raise "Unable to parse address: #{ address }, the address you're referring to is not part of any environment"
103
+ end
104
+ end
105
+
106
+ def parse_and_set_revision
107
+ raise "Cannot set or unset target_revision without a role" unless @options['role']
108
+
109
+ if @options['target_revision']
110
+ @config[@options['env']]['config_bag_hash'][@options['sub_env']]['app_revisions'][@config['getter'].get_codebase_from_role_name(@options['role'])] = @options['target_revision']
111
+
112
+ elsif @options['unset_revision']
113
+ @config[@options['env']]['config_bag_hash'][@options['sub_env']]['app_revisions'][@config['getter'].get_codebase_from_role_name(@options['role'])] = "<use_default>"
114
+
115
+ end
116
+
117
+ @config['ChefDataBag'].save_config_bag
118
+ end
119
+
120
+ def array_of_nodes_contains_node_name? nodes, node_name, names=[]
121
+ nodes.each { |node| names << node['name'] }
122
+
123
+ names.include? node_name
124
+ end
125
+
126
+ def index_of_node_name_in_array_of_nodes nodes, node_name, names=[]
127
+ nodes.each { |node| names << node['name'] }
128
+
129
+ names.index node_name
130
+ end
131
+
132
+ #parse nodes out of array based on hash, ex: [{ unless: 'role[rails]'}, {if: 'role[worker]'}, { if: { run_list: 'role[db]', role: 'pg_data' } }]
133
+ def exclude_nodes nodes, statement_arr, only_one_node = false, ret_arr = []
134
+ nodes.each do |n|
135
+ go_next = false
136
+
137
+ statement_arr.each do |statement_hash|
138
+ statement_hash.each_pair do |if_key, statement|
139
+ if statement.is_a?(String)
140
+ self.instance_eval("go_next = true #{ if_key.to_s } n.run_list.include?('#{ statement }')")
141
+
142
+ elsif statement.is_a?(Hash)
143
+ eval_string = "go_next = true #{ if_key.to_s } "
144
+ eval_list = []
145
+
146
+ statement.each_pair do |run_key, check_val|
147
+ eval_list << "n.run_list.include?('#{ check_val }')" if run_key == :run_list
148
+ eval_list << "!n.run_list.include?('#{ check_val }')" if run_key == :not_run_list
149
+ eval_list << "n.chef_environment == '#{ check_val }'" if run_key == :env
150
+ eval_list << "n.chef_environment != '#{ check_val }'" if run_key == :not_env
151
+ eval_list << "@options['role'] == '#{ check_val }'" if run_key == :role
152
+ eval_list << "@options['role'] != '#{ check_val }'" if run_key == :not_role
153
+ eval_list << "n.name == '#{ check_val }'" if run_key == :node
154
+ eval_list << "n.name != '#{ check_val }'" if run_key == :not_node
155
+ eval_list << "#{ check_val }" if run_key == :eval #careful with this, you need to pass in an already parsed string
156
+ end
157
+
158
+ self.instance_eval(eval_string + eval_list.join(' && '))
159
+ else
160
+ raise "Invalid statement type (#{ statement.class }) - Statement must be string or hash"
161
+ end
162
+ end
163
+ end
164
+
165
+ next if go_next
166
+
167
+ ret_arr << n
168
+
169
+ break if only_one_node
170
+ end
171
+
172
+ if @options['verbose'] && @options['command'] != "client_list"
173
+ puts("Parsed #{ ret_arr.count } nodes. Preparing to run on #{ ret_arr.map { |n| n.name }.join(',') } in env #{ @options['env'] } on role #{ @options['role'] }")
174
+ end
175
+
176
+ ret_arr
177
+ end
178
+
179
+ def parse_runtime_arguments num_of_args=0, mode='normal'
180
+ case mode
181
+ when 'normal'
182
+ case num_of_args
183
+ when 0 then raise "You attempted to run #{ __method__ } with 0 args! Look up this method from the stacktrace!"
184
+ when 1 then ARGV[num_of_args-1]
185
+ when 2..100 then ARGV[0..(num_of_args-1)]
186
+ end
187
+ when 'range' then ARGV[1..ARGV.length-1].join(' ')
188
+ else raise "You passed #{ mode }. This is not yet implemented for #{ __method__ }"
189
+ end
190
+ end
191
+
192
+ def parse_to_dns dns_string
193
+ raise "Unable to parse DNS without @option['node_name'] for #{ dns_string }!" if dns_string.include?('NODE_NAME') && @options['node_name'].nil?
194
+ raise "Unable to parse DNS without a tld set in the config bag for #{ @options['env'] }!" if dns_string.include?('ENV_TLD') && @config[@options['env']]['config_bag_hash']['tld'].nil?
195
+
196
+ dns_string.gsub('NODE_NAME', @options['node_name']).gsub('ENV_TLD', @config[@options['env']]['config_bag_hash']['tld'])
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,30 @@
1
+
2
+ class Cheftacular
3
+ module RemoteHelpers
4
+ def set_log_loc_and_timestamp
5
+ @dummy_sshkit.set_log_loc_and_timestamp( @locs )
6
+ end
7
+
8
+ def start_tail_log ip_address, run_list
9
+ true_env = @config['dummy_sshkit'].get_true_environment run_list, @config['cheftacular']['run_list_environments'], @options['env']
10
+
11
+ #special servers should be listed first as most of them will have web role
12
+ log_loc = case
13
+ when run_list.include?('role[sensu_server]')
14
+ "/var/log/sensu/sensu-server.log"
15
+ when run_list.include?('role[graphite_server]')
16
+ "/var/log/carbon-cache/current"
17
+ when run_list.include?('role[web]') && !run_list.include?('nodejs')
18
+ "/var/www/vhosts/#{ get_codebase_from_role_name( @options['role']) }/current/log/#{ true_env }.log"
19
+ when run_list.include?('role[worker]') || run_list.include?('nodejs')
20
+ "/var/log/syslog"
21
+ else
22
+ puts "This gem is not currently configured to handle tailing this case"
23
+ return 0
24
+ end
25
+
26
+
27
+ `ssh -oStrictHostKeyChecking=no -tt deploy@#{ ip_address } "#{ sudo(ip_address) } tail -f #{ log_loc }" > /dev/tty`
28
+ end
29
+ end
30
+ end