cheftacular 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/cft +4 -0
- data/bin/cftclr +4 -0
- data/bin/cheftacular +4 -0
- data/bin/client-list +4 -0
- data/lib/cheftacular/README.md +416 -0
- data/lib/cheftacular/actions/check.rb +32 -0
- data/lib/cheftacular/actions/console.rb +62 -0
- data/lib/cheftacular/actions/database.rb +13 -0
- data/lib/cheftacular/actions/db_console.rb +67 -0
- data/lib/cheftacular/actions/deploy.rb +40 -0
- data/lib/cheftacular/actions/log.rb +47 -0
- data/lib/cheftacular/actions/migrate.rb +57 -0
- data/lib/cheftacular/actions/run.rb +64 -0
- data/lib/cheftacular/actions/scale.rb +94 -0
- data/lib/cheftacular/actions/tail.rb +55 -0
- data/lib/cheftacular/actions.rb +14 -0
- data/lib/cheftacular/auditor.rb +46 -0
- data/lib/cheftacular/chef/data_bag.rb +104 -0
- data/lib/cheftacular/cheftacular.rb +55 -0
- data/lib/cheftacular/decryptors.rb +45 -0
- data/lib/cheftacular/encryptors.rb +48 -0
- data/lib/cheftacular/getters.rb +153 -0
- data/lib/cheftacular/helpers.rb +296 -0
- data/lib/cheftacular/initializers.rb +451 -0
- data/lib/cheftacular/parsers.rb +199 -0
- data/lib/cheftacular/remote_helpers.rb +30 -0
- data/lib/cheftacular/stateless_action.rb +16 -0
- data/lib/cheftacular/stateless_actions/add_ssh_key_to_bag.rb +44 -0
- data/lib/cheftacular/stateless_actions/arguments.rb +68 -0
- data/lib/cheftacular/stateless_actions/backups.rb +116 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/centos_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/coreos_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/fedora_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/redhat_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/ubuntu_bootstrap.rb +102 -0
- data/lib/cheftacular/stateless_actions/bootstrappers/vyatta_bootstrap.rb +7 -0
- data/lib/cheftacular/stateless_actions/chef_bootstrap.rb +40 -0
- data/lib/cheftacular/stateless_actions/chef_environment.rb +21 -0
- data/lib/cheftacular/stateless_actions/clean_cookbooks.rb +104 -0
- data/lib/cheftacular/stateless_actions/clean_sensu_plugins.rb +19 -0
- data/lib/cheftacular/stateless_actions/clean_server_passwords.rb +14 -0
- data/lib/cheftacular/stateless_actions/cleanup_log_files.rb +14 -0
- data/lib/cheftacular/stateless_actions/client_list.rb +89 -0
- data/lib/cheftacular/stateless_actions/cloud.rb +107 -0
- data/lib/cheftacular/stateless_actions/cloud_bootstrap.rb +109 -0
- data/lib/cheftacular/stateless_actions/compile_audit_log.rb +60 -0
- data/lib/cheftacular/stateless_actions/compile_readme.rb +41 -0
- data/lib/cheftacular/stateless_actions/create_git_key.rb +67 -0
- data/lib/cheftacular/stateless_actions/disk_report.rb +75 -0
- data/lib/cheftacular/stateless_actions/environment.rb +100 -0
- data/lib/cheftacular/stateless_actions/fetch_file.rb +24 -0
- data/lib/cheftacular/stateless_actions/fix_known_hosts.rb +70 -0
- data/lib/cheftacular/stateless_actions/full_bootstrap.rb +30 -0
- data/lib/cheftacular/stateless_actions/get_active_ssh_connections.rb +18 -0
- data/lib/cheftacular/stateless_actions/get_haproxy_log.rb +55 -0
- data/lib/cheftacular/stateless_actions/get_log_from_bag.rb +38 -0
- data/lib/cheftacular/stateless_actions/get_pg_pass.rb +61 -0
- data/lib/cheftacular/stateless_actions/help.rb +71 -0
- data/lib/cheftacular/stateless_actions/initialize_data_bag_contents.rb +220 -0
- data/lib/cheftacular/stateless_actions/knife_upload.rb +23 -0
- data/lib/cheftacular/stateless_actions/pass.rb +49 -0
- data/lib/cheftacular/stateless_actions/reinitialize.rb +46 -0
- data/lib/cheftacular/stateless_actions/remove_client.rb +81 -0
- data/lib/cheftacular/stateless_actions/replication_status.rb +103 -0
- data/lib/cheftacular/stateless_actions/restart_swap.rb +55 -0
- data/lib/cheftacular/stateless_actions/rvm.rb +14 -0
- data/lib/cheftacular/stateless_actions/server_update.rb +99 -0
- data/lib/cheftacular/stateless_actions/service.rb +14 -0
- data/lib/cheftacular/stateless_actions/test_env.rb +82 -0
- data/lib/cheftacular/stateless_actions/update_split_branches.rb +64 -0
- data/lib/cheftacular/stateless_actions/update_tld.rb +62 -0
- data/lib/cheftacular/stateless_actions/upload_nodes.rb +120 -0
- data/lib/cheftacular/stateless_actions/upload_roles.rb +24 -0
- data/lib/cheftacular/version.rb +5 -0
- data/lib/cheftacular.rb +4 -0
- data/lib/cloud_interactor/authentication.rb +56 -0
- data/lib/cloud_interactor/cloud_interactor.rb +23 -0
- data/lib/cloud_interactor/domain/create.rb +17 -0
- data/lib/cloud_interactor/domain/create_record.rb +27 -0
- data/lib/cloud_interactor/domain/destroy.rb +17 -0
- data/lib/cloud_interactor/domain/destroy_record.rb +23 -0
- data/lib/cloud_interactor/domain/list.rb +9 -0
- data/lib/cloud_interactor/domain/list_records.rb +22 -0
- data/lib/cloud_interactor/domain/read.rb +23 -0
- data/lib/cloud_interactor/domain/read_record.rb +27 -0
- data/lib/cloud_interactor/domain/update.rb +18 -0
- data/lib/cloud_interactor/domain/update_record.rb +42 -0
- data/lib/cloud_interactor/domain.rb +18 -0
- data/lib/cloud_interactor/flavor.rb +27 -0
- data/lib/cloud_interactor/helpers.rb +70 -0
- data/lib/cloud_interactor/image.rb +27 -0
- data/lib/cloud_interactor/parser.rb +37 -0
- data/lib/cloud_interactor/server/attach_volume.rb +33 -0
- data/lib/cloud_interactor/server/create.rb +39 -0
- data/lib/cloud_interactor/server/destroy.rb +11 -0
- data/lib/cloud_interactor/server/detach_volume.rb +21 -0
- data/lib/cloud_interactor/server/list.rb +7 -0
- data/lib/cloud_interactor/server/list_volumes.rb +25 -0
- data/lib/cloud_interactor/server/poll.rb +22 -0
- data/lib/cloud_interactor/server/read.rb +9 -0
- data/lib/cloud_interactor/server/read_volume.rb +24 -0
- data/lib/cloud_interactor/server.rb +17 -0
- data/lib/cloud_interactor/version.rb +4 -0
- data/lib/cloud_interactor/volume/create.rb +13 -0
- data/lib/cloud_interactor/volume/destroy.rb +11 -0
- data/lib/cloud_interactor/volume/list.rb +7 -0
- data/lib/cloud_interactor/volume/read.rb +9 -0
- data/lib/cloud_interactor/volume.rb +20 -0
- data/lib/ridley/monkeypatches.rb +11 -0
- data/lib/sshkit/actions/start_commit_check.rb +19 -0
- data/lib/sshkit/actions/start_deploy.rb +25 -0
- data/lib/sshkit/actions/start_log_fetch.rb +91 -0
- data/lib/sshkit/actions/start_task.rb +29 -0
- data/lib/sshkit/getters.rb +67 -0
- data/lib/sshkit/helpers.rb +13 -0
- data/lib/sshkit/monkeypatches.rb +19 -0
- 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
|