cheftacular 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|