prism-marauder 0.6.1

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.
data/bin/marauder ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ruby 1.9.2 removed '.' from LOAD_PATH
4
+ $LOAD_PATH << '.'
5
+
6
+ require 'marauder/commands'
data/bin/prism ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ruby 1.9.2 removed '.' from LOAD_PATH
4
+ $LOAD_PATH << '.'
5
+
6
+ require 'marauder/commands'
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # FIXME: use bundler?
4
+ require 'marauder/marauder'
5
+ require 'httparty'
6
+ require 'net/ssh'
7
+ require 'commander/import'
8
+
9
+ program :version, Marauder::VERSION
10
+ program :description, 'command-line tool to locate infrastructure'
11
+
12
+ PRISM_URL = 'http://prism.gutools.co.uk'
13
+
14
+ class Api
15
+ include HTTParty
16
+ #debug_output $stderr
17
+ disable_rails_query_string_format
18
+ end
19
+
20
+ # If you're sshing into too many hosts, you might be doing something wrong
21
+ MAX_SSH_HOSTS = 4
22
+
23
+ LOGGED_IN_USER = ENV['USER']
24
+
25
+ def table(rows)
26
+ lengths = rows.map { |row| row.map { |value| value.nil? ? 0 : value.size } }
27
+ col_widths = lengths.transpose.map { |column| column.max }
28
+ rows.map { |row|
29
+ col_widths.each_with_index.map { |width, index|
30
+ (row[index] || "").ljust(width)
31
+ }.join("\t")
32
+ }.join("\n")
33
+ end
34
+
35
+ def tokenize(s)
36
+ separators = ['-', '_', '::']
37
+ separators.inject([s]) do |tokens, sep|
38
+ tokens.map {|t| t.split(sep)}.flatten
39
+ end
40
+ end
41
+
42
+ def prism_query(path, filter)
43
+ prism_filters = filter.select{ |f| f =~ /=/ }
44
+
45
+ api_query = Hash[prism_filters.map { |f|
46
+ param = f.split('=')
47
+ [param[0], param[1]]
48
+ }.group_by { |pair|
49
+ pair[0]
50
+ }.map { |key, kvs|
51
+ [key, kvs.map{|v| v[1]}]
52
+ }]
53
+
54
+ data = Api.get("#{PRISM_URL}#{path}", :query => {:_expand => true}.merge(api_query))
55
+
56
+ if data["stale"]
57
+ update_time = data["lastUpdated"]
58
+ STDERR.puts "WARNING: Prism reports that the data returned from #{path} is stale, it was last updated at #{update_time}"
59
+ end
60
+
61
+ data
62
+ end
63
+
64
+ def token_filter(things_to_filter, filter)
65
+ dumb_filters = filter.reject{ |f| f =~ /=/ }
66
+ query = dumb_filters.map(&:downcase).map{|s| Regexp.new("^#{s}.*")}
67
+
68
+ things_to_filter.select do |thing|
69
+ query.all? do |phrase|
70
+ tokens = yield thing
71
+ tokens.compact.any? {|token| phrase.match(token.downcase)}
72
+ end
73
+ end
74
+ end
75
+
76
+ def find_hosts(filter)
77
+ find_instances(filter) + find_hardware(filter)
78
+ end
79
+
80
+ def find_instances(filter)
81
+ data = prism_query('/instances', filter)
82
+ hosts = data["data"]["instances"]
83
+ token_filter(hosts, filter){ |host|
84
+ host["mainclasses"].map{|mc| tokenize(mc)}.flatten + host["mainclasses"] + [host["stage"], host["stack"]] + host["app"]
85
+ }
86
+ end
87
+
88
+ def find_hardware(filter)
89
+ data = prism_query('/hardware', filter)
90
+ hardware = data["data"]["hardware"]
91
+ token_filter(hardware, filter){ |h| [h["dnsName"], h["stage"], h["stack"]] + h["app"] }
92
+ end
93
+
94
+ def user_for_host(hostname)
95
+ Net::SSH.configuration_for(hostname)[:user]
96
+ end
97
+
98
+ def display_results(matching, short, noun)
99
+ if matching.empty?
100
+ STDERR.puts "No #{noun} found"
101
+ else
102
+ if short
103
+ matching.each { |host| puts host['dnsName'] }
104
+ else
105
+ puts table(matching.map { |host|
106
+ app = host['app'].join(',')
107
+ app = host['mainclasses'].join(',') if app.length == 0
108
+ [host['stage'], host['stack'], app, host['dnsName'], host['createdAt']]
109
+ })
110
+ end
111
+ end
112
+ end
113
+
114
+ ###### COMMANDS ######
115
+
116
+ command :hosts do |c|
117
+ c.description = 'List all hosts (hardware or instances) that match the search filter'
118
+ c.syntax = 'marauder hosts <filter>'
119
+ c.option '-s', '--short', 'Only return hostnames'
120
+ c.action do |args, options|
121
+ display_results(find_hosts(args), options.short, 'hosts')
122
+ end
123
+ end
124
+
125
+ command :instances do |c|
126
+ c.description = 'List instances that match the search filter'
127
+ c.syntax = 'marauder instances <filter>'
128
+ c.option '-s', '--short', 'Only return hostnames'
129
+ c.action do |args, options|
130
+ display_results(find_instances(args), options.short, 'instances')
131
+ end
132
+ end
133
+
134
+ command :hardware do |c|
135
+ c.description = 'List hardware that matches the search filter'
136
+ c.syntax = 'marauder hardware <filter>'
137
+ c.option '-s', '--short', 'Only return hostnames'
138
+ c.action do |args, options|
139
+ display_results(find_hardware(args), options.short, 'hardware')
140
+ end
141
+ end
142
+
143
+ command :ssh do |c|
144
+ c.syntax = 'marauder ssh <filter>'
145
+ c.description = 'Execute command on matching hosts'
146
+ c.option '-u', '--user STRING', String, 'Remote username'
147
+ c.option '-c', '--cmd STRING', String, 'Command to execute (quote this if it contains a space)'
148
+ c.action do |args, options|
149
+
150
+ STDERR.puts "#{args}"
151
+
152
+ query = args.take_while {|s| s != '--'}
153
+ cmd = options.cmd
154
+
155
+ STDERR.puts "Query: #{query}"
156
+ STDERR.puts "Command: #{cmd}"
157
+
158
+ matching = find_hosts(query)
159
+
160
+ if cmd.nil?
161
+ puts "Please provide a command."
162
+ usage
163
+ exit 1
164
+ else if matching.size > MAX_SSH_HOSTS
165
+ exit 1 unless agree("Do you really want to SSH into #{matching.size} hosts?")
166
+ end
167
+
168
+ puts "ssh into #{matching.size} hosts and run `#{cmd}`..."
169
+ puts
170
+
171
+ matching.each do |host|
172
+ hostname = host['dnsName']
173
+ user = options.user || user_for_host(hostname) || LOGGED_IN_USER
174
+ Net::SSH.start(hostname, user) do |ssh|
175
+ puts "== #{hostname} as #{user} =="
176
+ puts ssh.exec!(cmd)
177
+ puts
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ default_command :hosts
@@ -0,0 +1,3 @@
1
+ class Marauder
2
+ VERSION="0.6.1"
3
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: prism-marauder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sébastien Cevey
9
+ - Simon Hildrew
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-02-20 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: commander
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: net-ssh
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: httparty
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ description: Command line tool to find services in Prism based on simple queries
64
+ email: seb@cine7.net
65
+ executables:
66
+ - marauder
67
+ - prism
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - bin/marauder
72
+ - bin/prism
73
+ - lib/marauder/commands.rb
74
+ - lib/marauder/marauder.rb
75
+ homepage: https://github.com/guardian/prism/tree/master/marauder#readme
76
+ licenses:
77
+ - GPL
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.23
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: service locator based on prism
100
+ test_files: []