gaptool-client 0.8.0.pre.alpha3 → 0.8.0.pre.alpha4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/gt +1 -0
  4. data/lib/gaptool_client.rb +2 -597
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cb7da2336580dbd7f63b160a83bbd066b0c9b5aa
4
- data.tar.gz: 2ac19b1d8a8d2c70620b3b943477197514f2c850
3
+ metadata.gz: 3528f94e83fb0e8209a053b24683729e830b61ef
4
+ data.tar.gz: 1f768dc1e8b37c94b289d00cce7e5935506adf13
5
5
  SHA512:
6
- metadata.gz: e72b4610e2fc678c8a998583368b43c445a429bb8c4efd0ae18e6b1c55b28e0e81ccfaa75d0c52ae6d01c673eb1bbaba33de8597e32e8b6956732a50b1259bd0
7
- data.tar.gz: b34660bb638816dfac2a64051daa9e0af012afdb865ad961eb47db2dbfccf61e731af913cefe716916db3f3dcc95fbcba090d40ffa2cbe8737f24c35ca3e3617
6
+ metadata.gz: 55aaebc78a856cfd8b3d92789507855c3b394a04c3d66ce2d6c3ad1283a80a5b5ab73773747a502b01f28f661a1574d36d199affb7f59855301c3f964a9d5310
7
+ data.tar.gz: 63fbd7d33485fba03a7de11c19db639bf096cd6286ffa31085481fedeed1c62016ae616ad5da7ed2f2363455eaef24618163bc1ff215b51a672eae5a7f506886
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.0-alpha3
1
+ 0.8.0-alpha4
data/bin/gt CHANGED
@@ -15,3 +15,4 @@ end
15
15
  # Run client
16
16
  require File.realpath(File.join(File.dirname(__FILE__),
17
17
  '..', 'lib', 'gaptool_client.rb'))
18
+ Gaptool::MainCommand.run
@@ -1,604 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  # coding: utf-8
3
- # rubocop:disable Metrics/LineLength, Lint/Eval
3
+ # rubocop:disable Metrics/LineLength
4
4
 
5
- require 'rainbow'
6
- require 'json'
7
5
  require 'clamp'
8
- require 'sshkit'
9
- require 'sshkit/dsl'
10
- require 'set'
11
- require 'gaptool-api'
12
- require 'logger'
6
+ require 'gaptool_client/commands'
13
7
 
14
8
  module Gaptool
15
- START_MARKER = '###### GAPTOOL ######'
16
- STOP_MARKER = '###### END GAPTOOL ######'
17
-
18
- def self.api
19
- @api ||= GTAPI::GaptoolServer.new(
20
- ENV['GT_USER'], ENV['GT_KEY'],
21
- ENV['GT_URL'], ENV['GT_AWS_ZONE']
22
- )
23
- end
24
-
25
- def self.infohelper(nodes, parseable, grepable, short = false)
26
- if parseable && !short
27
- puts({ nodes: nodes }.to_json)
28
- elsif parseable
29
- puts({ nodes: nodes.map { |node| node.select { |k, _v| %w(role environment instance).include?(k) } } }.to_json)
30
- else
31
- nodes.each do |node|
32
- host = "#{node['role']}:#{node['environment']}:#{node['instance']}"
33
- if grepable && short
34
- puts host
35
- elsif !grepable
36
- puts Rainbow(host).green
37
- end
38
- next if short
39
- keys = node.keys.sort
40
- keys.each do |key|
41
- value = node[key]
42
- if grepable
43
- puts "#{host}|#{key}|#{value}"
44
- else
45
- value = Time.at(node[key].to_i) if key == 'launch_time'
46
- if key == keys.last
47
- puts " ┖ #{Rainbow(key).cyan}: #{value}\n\n"
48
- else
49
- puts " ┠ #{Rainbow(key).cyan}: #{value}"
50
- end
51
- end
52
- end
53
- end
54
- end
55
- end
56
-
57
- def self.error(message, opts = {})
58
- code = opts[:code] || 1
59
- color = opts[:color] || :red
60
- STDERR.puts(Rainbow(message).send(color))
61
- exit code
62
- end
63
-
64
- def self.get_host(node)
65
- "#{node['role']}-#{node['environment']}-#{node['instance']}"
66
- end
67
-
68
- def self.ssh_snip_for_node(node)
69
- host = Gaptool.get_host(node)
70
- <<-EOF
71
- # -- #{node['instance']}
72
- Host #{host} #{node['instance']}
73
- Hostname #{node['hostname']}
74
- User #{ENV['GT_USER']}
75
- LogLevel FATAL
76
- PreferredAuthentications publickey
77
- CheckHostIP no
78
- StrictHostKeyChecking no
79
- UserKnownHostsFile /dev/null
80
- # -- end #{node['instance']}
81
- EOF
82
- end
83
-
84
- def self.ssh_config
85
- config = File.join(Dir.home, '.ssh', 'config')
86
- dir = File.dirname(config)
87
- parent = File.join(dir, '..')
88
- if File.exist?(config)
89
- Gaptool.error "#{config}: not writable" unless File.writable?(config)
90
- content = File.read(config)
91
- # puts Rainbow("Creating backup file at #{config}.bck").green
92
- File.open("#{config}.bck", 'w') { |f| f.write(content) }
93
- else
94
- if !File.exist?(dir)
95
- Gaptool.error "Home directory #{parent} does not exists"\
96
- unless Dir.exist?(parent)
97
- Dir.mkdir(dir, 0700)
98
- elsif !File.directory?(dir)
99
- Gaptool.error "#{dir}: not a directory"
100
- end
101
- content = ''
102
- end
103
- [config, content]
104
- end
105
-
106
- def self.update_ssh_config_for(nodes, verbose=true)
107
- nodes = [nodes] unless nodes.is_a?(Array)
108
- config, content = Gaptool.ssh_config
109
- nodes.each do |node|
110
- snip = Gaptool.ssh_snip_for_node(node)
111
- mark = "# -- #{node['instance']}"
112
- emark = "# -- end #{node['instance']}"
113
-
114
- if Regexp.new(mark).match(content)
115
- puts Rainbow("Updating ssh config for #{get_host(node)}").green if verbose
116
- content.gsub!(/#{mark}.*?#{emark}/m, snip.strip)
117
- elsif Regexp.new(Gaptool::STOP_MARKER).match(content)
118
- puts Rainbow("Adding ssh config for #{get_host(node)}").green if verbose
119
- content.gsub!(/#{Gaptool::STOP_MARKER}/m, snip + "\n" + Gaptool::STOP_MARKER)
120
- else
121
- puts Rainbow('No gt ssh config found: please run gt ssh-config').yellow
122
- puts Rainbow("Adding ssh config for #{get_host(node)}").green if verbose
123
- content = <<-EOF
124
- #{content}
125
- #{Gaptool::START_MARKER}
126
- #{snip}
127
- #{Gaptool::STOP_MARKER}
128
- EOF
129
- end
130
- end
131
- File.open(config, 'w') { |f| f.write(content) }
132
- end
133
-
134
- def self.configure_sshkit
135
- SSHKit.config.output_verbosity = Logger::WARN
136
- SSHKit::Backend::Netssh.configure do |ssh|
137
- ssh.connection_timeout = 30
138
- ssh.ssh_options = {
139
- forward_agent: true,
140
- global_known_hosts_file: '/dev/null',
141
- keys_only: true,
142
- port: 22,
143
- user: ENV['GT_USER']
144
- }
145
- end
146
- end
147
-
148
- def self.query_nodes(opts)
149
- instance = opts[:instance]
150
- role = opts[:role]
151
- environment = opts[:environment]
152
- params = opts[:params]
153
-
154
- if instance
155
- puts Rainbow('Ignoring role and environment as instance is set').red if role || environment
156
- [Gaptool.api.getonenode(instance)]
157
- elsif role && environment
158
- Gaptool.api.getenvroles(role, environment, params)
159
- elsif role
160
- Gaptool.api.getrolenodes(role, params)
161
- elsif environment
162
- Gaptool.api.getenvnodes(environment, params)
163
- else
164
- Gaptool.api.getallnodes(params)
165
- end
166
- end
167
-
168
- def self.remote_exec(nodes, commands, opts = {})
169
- serial = opts[:serial]
170
- group_size = opts[:group_size] || 10
171
- if opts[:update_ssh_config].nil? || opts[:update_ssh_config]
172
- nodes.each { |n| Gaptool.update_ssh_config_for(n, false) }
173
- end
174
- pre = opts[:pre_hooks] || []
175
- post = opts[:post_hooks] || []
176
- nodes = Hash[nodes.map { |n| [n['hostname'], n] }]
177
- handlers = Hash[nodes.map { |hostname, node| [hostname, InteractionHandler.new(Gaptool.get_host(node))] }]
178
- opts = { in: :groups, limit: group_size }
179
- opts = { in: :sequence } if serial
180
- Gaptool.configure_sshkit
181
- on(nodes.keys, opts) do |host|
182
- pre.each { |h| instance_exec(nodes[host.hostname], &h) }
183
- commands.each do |cmd|
184
- execute(:bash, "-l -c '#{cmd}'", interaction_handler: handlers[host.hostname])
185
- end
186
- post.each { |h| instance_exec(nodes[host.hostname], &h) }
187
- end
188
- end
189
-
190
- def self.split_attrs(attribute_list)
191
- opts = {}
192
- attribute_list.each do |attr_|
193
- key, value = attr_.split('=', 2)
194
- split = key.split('.')
195
- cur = opts
196
- split.each_with_index do |part, idx|
197
- if idx == split.size - 1
198
- # leaf, add the value
199
- cur[part] = value
200
- else
201
- cur[part] ||= {}
202
- end
203
- cur = cur[part]
204
- end
205
- end
206
- opts
207
- end
208
-
209
- class InteractionHandler
210
- attr_reader :host
211
- def initialize(host)
212
- @host = host
213
- end
214
-
215
- def on_data(_command, stream_name, data, _channel)
216
- case stream_name
217
- when :stdout
218
- puts "#{Rainbow("#{@host}").yellow}> #{data}"
219
- when :stderr
220
- STDERR.puts "#{Rainbow("#{@host}").red}> #{data}"
221
- end
222
- end
223
- end
224
-
225
- class InitCommand < Clamp::Command
226
- option ['-r', '--role'], 'ROLE', 'Resource name to initilize', required: true
227
- option ['-e', '--environment'], 'ENVIRONMENT', 'Which environment, e.g. production', required: true
228
- option ['-z', '--zone'], 'ZONE', 'AWS availability zone to put node in', default: 'us-west-2c'
229
- option ['-t', '--type'], 'TYPE', 'Type of instance, e.g. m1.large', required: true
230
- option ['-s', '--security-group'], 'SECURITY_GROUP', 'Security group name. Defaults to $role-$environment'
231
- option ['-a', '--ami'], 'AMI_ID', 'Use a specific AMI for the instance (i.e. ami-xxxxxxx)'
232
- option ['-C', '--chef-repo'], 'GITURL', 'git url for the chef repository'
233
- option ['-b', '--chef-branch'], 'BRANCH', 'branch of the chef repository to use'
234
- option(['-R', '--chef_runlist'], 'RECIPE|ROLE',
235
- 'override chef run_list. recipe[cb::recipe] or role[myrole]. Can be specified multiple times',
236
- multivalued: true, attribute_name: 'chef_runlist')
237
- option ['--no-terminate'], :flag, 'Add terminate protection'
238
- def execute
239
- no_terminate = no_terminate? ? true : nil
240
- Gaptool.api.addnode(zone, type, role, environment, nil, security_group,
241
- ami, chef_repo, chef_branch, chef_runlist,
242
- no_terminate)
243
- end
244
- end
245
-
246
- class TerminateCommand < Clamp::Command
247
- option ['-i', '--instance'], 'INSTANCE', 'Instance ID, e.g. i-12345678', required: true
248
- option ['-z', '--zone'], 'ZONE', 'AWS region of the node (deprecated/ignored)'
249
- option ['-r', '--role'], 'ROLE', 'Resource name to initilize', required: true
250
- option ['-e', '--environment'], 'ENVIRONMENT', 'Which environment, e.g. production', required: true
251
-
252
- def execute
253
- node = Gaptool.api.getonenode(instance)
254
- nodes = [node]
255
- Gaptool.infohelper(nodes, false, false)
256
- zone = node['zone'][0..-2]
257
- if node['environment'] != environment || node['role'] != role
258
- puts Rainbow("'#{node['role']}-#{node['environment']}' do not match provided value (#{role}-#{environment})").red
259
- exit 1
260
- end
261
- if node['terminate'] == 'false'
262
- puts Rainbow('"terminate" command is disabled for this instance').red
263
- exit 2
264
- end
265
- print Rainbow('Terminate instance? [type yes to confirm]: ').green
266
- res = $stdin.gets.chomp
267
- return 0 unless res.downcase == 'yes'
268
- puts "Terminating instance #{node['role']}:#{node['environment']}:#{node['instance']} in region #{zone}"
269
- begin
270
- Gaptool.api.terminatenode(instance, zone)
271
- rescue
272
- puts Rainbow('Cannot terminate instance').red
273
- end
274
- end
275
- end
276
-
277
- class RuncmdCommand < Clamp::Command
278
- option ['-r', '--role'], 'ROLE', 'Instance role'
279
- option ['-e', '--environment'], 'ENVIRONMENT', 'Instance environment'
280
- option ['-i', '--instance'], 'INSTANCE', 'Instance id (i-xxxxxxxx)'
281
- option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.'
282
- option ['-x', '--exclude-hidden'], :flag, 'Exclude hidden hosts'
283
- parameter 'COMMAND ...', 'Command to run', attribute_name: :commands
284
-
285
- def execute
286
- params = exclude_hidden? ? {} : { hidden: true }
287
- nodes = Gaptool.query_nodes(params.merge(instance: instance,
288
- role: role, environment: environment))
289
- Gaptool.remote_exec(nodes, [commands.join(' ')], serial: serial?)
290
- end
291
- end
292
-
293
- class SSHConfigCommand < Clamp::Command
294
- option ['-r', '--remove'], :flag, 'Remove ssh configuration'
295
-
296
- def execute
297
- config, content = Gaptool.ssh_config
298
-
299
- if remove?
300
- data = ''
301
- else
302
- puts Rainbow('Getting nodes from API').green
303
- data = [Gaptool::START_MARKER, '# to remove this block, run gt ssh-config --remove']
304
- Gaptool.api.getallnodes(hidden: true).sort_by { |n| n['instance'] }.each do |node|
305
- host = Gaptool.get_host(node)
306
- puts " - #{Rainbow(host).blue}"
307
- data << Gaptool.ssh_snip_for_node(node)
308
- end
309
- data << Gaptool::STOP_MARKER
310
- data = data.join("\n")
311
- end
312
-
313
- if Regexp.new(Gaptool::START_MARKER).match(content)
314
- content.gsub!(/#{Gaptool::START_MARKER}.*?#{Gaptool::STOP_MARKER}/m, data)
315
- elsif !remove?
316
- content = content + "\n" + data
317
- end
318
- File.open(config, 'w') { |f| f.write(content) }
319
- end
320
- end
321
-
322
- class SSHCommand < Clamp::Command
323
- option ['-r', '--role'], 'ROLE', 'Instance role'
324
- option ['-e', '--environment'], 'ENVIRONMENT', 'Instance environment'
325
- option ['-i', '--instance'], 'INSTANCE', 'Instance id (i-xxxxxxxx)'
326
- option ['-f', '--first'], :flag, 'Just connect to first available instance'
327
- option ['-t', '--tmux'], :flag, 'No-op, DEPRECATED'
328
-
329
- def execute
330
- puts Rainbow('tmux support has been removed').yellow if tmux?
331
- nodes = Gaptool.query_nodes(hidden: true,
332
- instance: instance,
333
- environment: environment,
334
- role: role)
335
-
336
- if first? || (nodes.length == 1 && !instance)
337
- puts Rainbow('No instance specified, but only one instance in cluster or first forced').green
338
- node = nodes.first
339
- elsif !instance
340
- nodes.each_index do |i|
341
- puts "#{i}: #{nodes[i]['instance']}"
342
- end
343
- print Rainbow('Select a node: ').cyan
344
- node = nodes[$stdin.gets.chomp.to_i]
345
- error 'Invalid selection' if node.nil?
346
- else
347
- node = nodes.first
348
- end
349
- Gaptool.update_ssh_config_for(node)
350
- system "ssh #{node['instance']}"
351
- end
352
- end
353
-
354
- class InfoCommand < Clamp::Command
355
- option ['-r', '--role'], 'ROLE', 'Role name, e.g. frontend'
356
- option ['-e', '--environment'], 'ENVIRONMENT', 'Which environment, e.g. production'
357
- option ['-i', '--instance'], 'INSTANCE', 'Node instance, leave blank to query avilable nodes'
358
- option ['-s', '--short'], :flag, 'Only show summary for hosts'
359
- option ['-p', '--parseable'], :flag, 'Display in non-pretty parseable JSON'
360
- option ['-g', '--grepable'], :flag, 'Display in non-pretty grep-friendly text'
361
- option ['-H', '--hidden'], :flag, 'Display hidden hosts'
362
-
363
- def execute
364
- nodes = []
365
- params = hidden? ? { hidden: true } : {}
366
- nodes = Gaptool.query_nodes(params.merge(instance: instance,
367
- role: role,
368
- environment: environment))
369
- Gaptool.infohelper(nodes, parseable?, grepable?, short?)
370
- end
371
- end
372
-
373
- class SetCommand < Clamp::Command
374
- option ['-i', '--instance'], 'INSTANCE', 'Node instance, required', required: true
375
- option ['-p', '--parseable'], :flag, 'Display in non-pretty parseable JSON'
376
- option ['-g', '--grepable'], :flag, 'Display in non-pretty grep-friendly text'
377
- option ['-k', '--parameter'], 'NAME', 'Set parameter for the node', required: true, multivalued: true
378
- option ['-v', '--value'], 'VALUE', 'Value for parameter', required: true, multivalued: true
379
-
380
- def convert_bool(v)
381
- case v.downcase
382
- when 'true'
383
- true
384
- when 'false'
385
- false
386
- else
387
- v
388
- end
389
- end
390
-
391
- def execute
392
- if parameter_list.length != value_list.length
393
- puts Rainbow('parameter and value length mismatch').red
394
- end
395
- params = Hash[parameter_list.each_with_index.map { |p, i| [p, convert_bool(value_list[i])] }]
396
- Gaptool.infohelper([Gaptool.api.setparameters(instance, params)], parseable?, grepable?)
397
- end
398
- end
399
-
400
- class ChefrunCommand < Clamp::Command
401
- option ['-r', '--role'], 'ROLE', 'Role name to ssh to'
402
- option ['-e', '--environment'], 'ENVIRONMENT', 'Which environment, e.g. production'
403
- option ['-i', '--instance'], 'INSTANCE', 'Instance ID, e.g. i-12345678'
404
- option ['-H', '--hidden'], :flag, 'Include hidden hosts'
405
- option(['-A', '--attribute'], 'ATTRIBUTE',
406
- 'Pass one or more parameters to the deploy recipe in recipe.attr=value format',
407
- multivalued: true)
408
- option(['-b', '--chef-branch'], 'BRANCH',
409
- 'branch of the chef repository to use (defaults to last branch used during init/chefrun)',
410
- default: nil)
411
- option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.'
412
- option ['-W', '--whyrun'], :flag, 'Whyrun, like dry-run but different.'
413
-
414
- def execute
415
- attrs = Gaptool.split_attrs(attribute_list)
416
- nodes = Gaptool.query_nodes(hidden: hidden? ? true : nil,
417
- role: role,
418
- instance: instance,
419
- environment: environment)
420
-
421
- nodes = nodes.map do |x|
422
- x['whyrun'] = whyrun?
423
- x['chef_branch'] = chef_branch
424
- x['attrs'] = attrs
425
- x
426
- end
427
-
428
- pre_hook = Proc.new do |node|
429
- if node['chef_runlist'].nil?
430
- runlist = ['recipe[main]']
431
- elsif node['chef_runlist'].is_a? Array
432
- runlist = node['chef_runlist']
433
- else
434
- runlist = eval(node['chef_runlist'])
435
- end
436
- json = {
437
- 'this_server' => "#{node['role']}-#{node['environment']}-#{node['instance']}",
438
- 'role' => node['role'],
439
- 'environment' => node['environment'],
440
- 'app_user' => node['appuser'],
441
- 'run_list' => runlist,
442
- 'hostname' => node['hostname'],
443
- 'instance' => node['instance'],
444
- 'zone' => node['zone'],
445
- 'itype' => node['itype'],
446
- 'apps' => eval(node['apps'] || '[]'),
447
- 'gaptool' => {
448
- 'user' => ENV['GT_USER'],
449
- 'key' => ENV['GT_KEY'],
450
- 'url' => ENV['GT_URL']
451
- }
452
- }.merge(node['attrs'])
453
- git = 'sudo -u admin git'
454
- pull = "#{git} fetch --all; #{git} reset --hard origin/`#{git} rev-parse --abbrev-ref HEAD`"
455
- wopts = node['whyrun'] ? ' -W ' : ''
456
-
457
- unless node['chef_branch'].nil?
458
- json['chefbranch'] = node['chef_branch']
459
- pull = "#{git} checkout -f #{node['chef_branch']}; #{git} fetch --all; #{git} reset --hard origin/#{node['chef_branch']}"
460
- end
461
- upload!(StringIO.new(json.to_json), '/tmp/chef.json')
462
- script = <<-EOS
463
- cd /var/data/admin/ops
464
- #{pull}
465
- sudo chef-solo -c /var/data/admin/ops/cookbooks/solo.rb -j /tmp/chef.json -E #{node['environment']}#{wopts}
466
- rm -f /tmp/chef.json
467
- EOS
468
- upload!(StringIO.new(script), '/tmp/chef.sh')
469
- end
470
- Gaptool.remote_exec(nodes,
471
- ['chmod +x /tmp/chef.sh', '/tmp/chef.sh', 'rm -f /tmp/chef.sh'],
472
- pre_hooks: [pre_hook], serial: serial?)
473
- end
474
- end
475
-
476
- class DeployCommand < Clamp::Command
477
- option(['-a', '--app'], 'APP',
478
- 'Application(s) to deploy (can be set multiple times)',
479
- required: true, multivalued: true)
480
- option ['-m', '--migrate'], :flag, 'Toggle running migrations'
481
- option ['-e', '--environment'], 'ENVIRONMENT', 'Which environment, e.g. production', required: true
482
- option ['-b', '--branch'], 'BRANCH', 'Git branch to deploy, default is master'
483
- option ['-r', '--rollback'], :flag, 'Toggle this to rollback last deploy'
484
- option ['-i', '--instance'], 'INSTANCE', 'Instance ID, e.g. i-12345678. If set, all applications MUST be hosted on this node.'
485
- option ['-A', '--attribute'], 'ATTRIBUTE', 'Pass one or more parameters to the deploy recipe in recipe.attr=value format', multivalued: true
486
- option ['-H', '--hidden'], :flag, 'Display hidden hosts'
487
- option ['-s', '--serial'], :flag, 'Run command serially. Order of execution is unknown.'
488
-
489
- def execute # rubocop:disable Metrics/MethodLength
490
- attrs = Gaptool.split_attrs(attribute_list)
491
- if instance
492
- n = Gaptool.api.getonenode(instance)
493
- if n['environment'] != environment
494
- Gaptool.error "Instance #{instance} is not in environment #{environment}"
495
- else
496
- app_list.each do |app|
497
- Gaptool.error "Instance #{instance} does not host #{app} in env #{environment}" \
498
- unless n['apps'].include?(app)
499
- end
500
- end
501
- nodes = [n]
502
-
503
- else
504
- params = hidden? ? { hidden: true } : {}
505
- nodes = []
506
- app_list.each do |app|
507
- nodes.concat(Gaptool.api.getappnodes(app, environment, params))
508
- end
509
- end
510
-
511
- # dedup nodes
512
- seen = Set.new
513
- app_set = Set.new(app_list)
514
- nodes = nodes.select do |x|
515
- res = !seen.include?(x['instance'])
516
- seen << x['instance']
517
- res
518
- end
519
- nodes = nodes.map do |x|
520
- x['apps'] = eval(x['apps'])
521
- x['apps_to_deploy'] = (Set.new(x['apps']) & app_set).to_a
522
- x['rollback'] = rollback?
523
- x['branch'] = branch || 'master'
524
- x['migrate'] = migrate?
525
- x['attrs'] = attrs
526
- x
527
- end
528
-
529
- pre_hook = Proc.new do |node|
530
- host = "#{node['role']}:#{node['environment']}:#{node['instance']}"
531
- puts "#{Rainbow('Deploying apps').cyan} '" + \
532
- Rainbow(node['apps_to_deploy'].join(' ')).green + \
533
- "' #{Rainbow('on').cyan} " + \
534
- Rainbow(host).green
535
-
536
- if node['chef_runlist'].nil?
537
- runlist = ['recipe[deploy]']
538
- elsif node['chef_runlist'].is_a? Array
539
- runlist = node['chef_runlist']
540
- else
541
- runlist = eval(node['chef_runlist'])
542
- end
543
- json = {
544
- 'this_server' => "#{node['role']}-#{node['environment']}-#{node['instance']}",
545
- 'role' => node['role'],
546
- 'environment' => node['environment'],
547
- 'app_user' => node['appuser'],
548
- 'run_list' => runlist,
549
- 'hostname' => node['hostname'],
550
- 'instance' => node['instance'],
551
- 'zone' => node['zone'],
552
- 'itype' => node['itype'],
553
- 'apps' => node['apps'],
554
- 'deploy_apps' => node['apps_to_deploy'],
555
- 'rollback' => node['rollback'],
556
- 'branch' => node['branch'],
557
- 'migrate' => node['migrate'],
558
- 'gaptool' => {
559
- 'user' => ENV['GT_USER'],
560
- 'key' => ENV['GT_KEY'],
561
- 'url' => ENV['GT_URL']
562
- }
563
- }.merge(node['attrs']).to_json
564
- upload!(StringIO.new(json), '/tmp/chef.json')
565
- script = <<-EOS
566
- cd /var/data/admin/ops
567
- sudo -u admin git pull
568
- sudo chef-solo -c /var/data/admin/ops/cookbooks/solo.rb -j /tmp/chef.json -E #{node['environment']}
569
- rm -f /tmp/chef.json
570
- EOS
571
- upload!(StringIO.new(script), '/tmp/deploy.sh')
572
- end
573
-
574
- Gaptool.remote_exec(nodes,
575
- ['chmod +x /tmp/deploy.sh', '/tmp/deploy.sh', 'rm -f /tmp/deploy.sh'],
576
- pre_hooks: [pre_hook], serial: serial?)
577
- end
578
- end
579
-
580
- class RehashCommand < Clamp::Command
581
- option ['-y', '--yes'], :flag, 'YES I REALLY WANT TO DO THIS'
582
- def execute
583
- if yes?
584
- puts Gaptool.api.rehash
585
- else
586
- puts "You need to run this with -y\nIf you don't know what this does or aren't sure, DO NOT RUN IT\nThis will regenerate all host metadata on gaptool-server\nand can break in-progress operations."
587
- end
588
- end
589
- end
590
-
591
- class VersionCommand < Clamp::Command
592
- option ['-r', '--remote'], :flag, 'Include remote API version'
593
- def execute
594
- version = File.read(File.realpath(File.join(File.dirname(__FILE__), '..', 'VERSION'))).strip
595
- puts "gaptool-client #{version} using gaptool-api #{Gaptool.api.version}"
596
- return 0 unless remote?
597
- vinfo = Gaptool.api.api_version
598
- puts "gaptool-server #{vinfo['server_version']}"
599
- end
600
- end
601
-
602
9
  class MainCommand < Clamp::Command
603
10
  subcommand 'info', 'Displays information about nodes', InfoCommand
604
11
  subcommand 'init', 'Create new application cluster', InitCommand
@@ -613,5 +20,3 @@ EOS
613
20
  subcommand 'version', 'Show version', VersionCommand
614
21
  end
615
22
  end
616
-
617
- Gaptool::MainCommand.run
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gaptool-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0.pre.alpha3
4
+ version: 0.8.0.pre.alpha4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Laurita
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-12-30 00:00:00.000000000 Z
13
+ date: 2015-12-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json