com.proofpoint.galaxy.cli 0.2
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/galaxy +3 -0
- data/lib/galaxy.rb +323 -0
- data/lib/galaxy/version.rb +3 -0
- metadata +91 -0
data/bin/galaxy
ADDED
data/lib/galaxy.rb
ADDED
@@ -0,0 +1,323 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'httpclient'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
GALAXY_VERSION = "0.1"
|
6
|
+
|
7
|
+
exit_codes = {
|
8
|
+
:success => 0,
|
9
|
+
:no_slots => 1,
|
10
|
+
:unsupported => 3,
|
11
|
+
:invalid_usage => 64
|
12
|
+
}
|
13
|
+
|
14
|
+
#
|
15
|
+
# Slot Information
|
16
|
+
#
|
17
|
+
class Slot
|
18
|
+
attr_reader :id, :name, :host, :ip, :url, :binary, :config, :status
|
19
|
+
|
20
|
+
def initialize(id, name, url, binary, config, status)
|
21
|
+
@id = id
|
22
|
+
@name = name
|
23
|
+
@url = url
|
24
|
+
@binary = binary
|
25
|
+
@config = config
|
26
|
+
@status = status
|
27
|
+
uri = URI.parse(url)
|
28
|
+
@host = uri.host
|
29
|
+
@ip = IPSocket::getaddress(host)
|
30
|
+
end
|
31
|
+
|
32
|
+
def print_col
|
33
|
+
puts "#{id}\t#{host}\t#{name}\t#{status}\t#{binary}\t#{config}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def strip(string)
|
38
|
+
space = /(\s+)/.match(string)[1]
|
39
|
+
string.gsub(/^#{space}/, '')
|
40
|
+
end
|
41
|
+
|
42
|
+
class CommandError < RuntimeError
|
43
|
+
attr_reader :code
|
44
|
+
attr_reader :message
|
45
|
+
|
46
|
+
def initialize(code, message)
|
47
|
+
@code = code
|
48
|
+
@message = message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
#
|
54
|
+
# Commands
|
55
|
+
#
|
56
|
+
|
57
|
+
def show(filter, options, args)
|
58
|
+
if !args.empty? then
|
59
|
+
raise CommandError.new(:invalid_usage, "You can not pass arguments to show.")
|
60
|
+
end
|
61
|
+
coordinator_request(filter, options, :get)
|
62
|
+
end
|
63
|
+
|
64
|
+
def assign(filter, options, args)
|
65
|
+
if args.size != 2 then
|
66
|
+
raise CommandError.new(:invalid_usage, "You must specify a binary and config to assign.")
|
67
|
+
end
|
68
|
+
if filter.empty? then
|
69
|
+
raise CommandError.new(:invalid_usage, "You must specify a filter when for assign.")
|
70
|
+
end
|
71
|
+
if args[0].start_with? '@'
|
72
|
+
config = args[0]
|
73
|
+
binary = args[1]
|
74
|
+
else
|
75
|
+
binary = args[0]
|
76
|
+
config = args[1]
|
77
|
+
|
78
|
+
end
|
79
|
+
assignment = {
|
80
|
+
:binary => binary,
|
81
|
+
:config => config
|
82
|
+
}
|
83
|
+
coordinator_request(filter, options, :put, 'assignment', assignment, true)
|
84
|
+
end
|
85
|
+
|
86
|
+
def clear(filter, options, args)
|
87
|
+
if !args.empty? then
|
88
|
+
raise CommandError.new(:invalid_usage, "You can not pass arguments to clear.")
|
89
|
+
end
|
90
|
+
if filter.empty? then
|
91
|
+
raise CommandError.new(:invalid_usage, "You must specify a filter when for clear.")
|
92
|
+
end
|
93
|
+
coordinator_request(filter, options, :delete, 'assignment')
|
94
|
+
end
|
95
|
+
|
96
|
+
def start(filter, options, args)
|
97
|
+
if !args.empty? then
|
98
|
+
raise CommandError.new(:invalid_usage, "You can not pass arguments to start.")
|
99
|
+
end
|
100
|
+
if filter.empty? then
|
101
|
+
raise CommandError.new(:invalid_usage, "You must specify a filter when for start.")
|
102
|
+
end
|
103
|
+
coordinator_request(filter, options, :put, 'lifecycle', 'running')
|
104
|
+
end
|
105
|
+
|
106
|
+
def stop(filter, options, args)
|
107
|
+
if !args.empty? then
|
108
|
+
raise CommandError.new(:invalid_usage, "You can not pass arguments to stop.")
|
109
|
+
end
|
110
|
+
if filter.empty? then
|
111
|
+
raise CommandError.new(:invalid_usage, "You must specify a filter when for stop.")
|
112
|
+
end
|
113
|
+
coordinator_request(filter, options, :put, 'lifecycle', 'stopped')
|
114
|
+
end
|
115
|
+
|
116
|
+
def restart(filter, options, args)
|
117
|
+
if !args.empty? then
|
118
|
+
raise CommandError.new(:invalid_usage, "You can not pass arguments to restart.")
|
119
|
+
end
|
120
|
+
if filter.empty? then
|
121
|
+
raise CommandError.new(:invalid_usage, "You must specify a filter when for restart.")
|
122
|
+
end
|
123
|
+
coordinator_request(filter, options, :put, 'lifecycle', 'restarting')
|
124
|
+
end
|
125
|
+
|
126
|
+
def ssh(filter, options, args)
|
127
|
+
if !args.empty? then
|
128
|
+
raise CommandError.new(:invalid_usage, "You can not pass arguments to ssh.")
|
129
|
+
end
|
130
|
+
if filter.empty? then
|
131
|
+
raise CommandError.new(:invalid_usage, "You must specify a filter when for ssh.")
|
132
|
+
end
|
133
|
+
slots = show(filter, options, args)
|
134
|
+
if slots.empty?
|
135
|
+
return []
|
136
|
+
end
|
137
|
+
|
138
|
+
slot = slots.first
|
139
|
+
command = ENV['GALAXY_SSH_COMMAND'] || "ssh"
|
140
|
+
Kernel.system "#{command} #{slot.host}"
|
141
|
+
[]
|
142
|
+
end
|
143
|
+
|
144
|
+
def coordinator_request(filter, options, method, sub_path = nil, value = nil, is_json = false)
|
145
|
+
# build the uri
|
146
|
+
uri = options[:coordinator_url]
|
147
|
+
uri += '/' unless uri.end_with? '/'
|
148
|
+
uri += 'v1/slot/'
|
149
|
+
uri += sub_path unless sub_path.nil?
|
150
|
+
|
151
|
+
# create filter query
|
152
|
+
query = filter.map { |k, v| "#{URI.escape(k.to_s)}=#{URI.escape(v)}" }.join('&')
|
153
|
+
|
154
|
+
# encode body as json if necessary
|
155
|
+
body = value
|
156
|
+
headers = {}
|
157
|
+
if is_json
|
158
|
+
body = value.to_json
|
159
|
+
headers['Content-Type'] = 'application/json'
|
160
|
+
end
|
161
|
+
|
162
|
+
# log request in as a valid curl command if in debug mode
|
163
|
+
if options[:debug]
|
164
|
+
if value then
|
165
|
+
puts "curl -H 'Content-Type: application/json' -X#{method.to_s.upcase} '#{uri}?#{query}' -d '"
|
166
|
+
puts body
|
167
|
+
puts "'"
|
168
|
+
else
|
169
|
+
puts "curl -X#{method.to_s.upcase} '#{uri}?#{query}'"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# execute request
|
174
|
+
response = HTTPClient.new.request(method, uri, query, body, headers).body
|
175
|
+
|
176
|
+
# parse response as json
|
177
|
+
slots_json = JSON.parse(response)
|
178
|
+
|
179
|
+
# log response if in debug mode
|
180
|
+
if options[:debug]
|
181
|
+
puts slots_json
|
182
|
+
end
|
183
|
+
|
184
|
+
# convert parsed json into slot objects
|
185
|
+
slots = slots_json.map do |slot_json|
|
186
|
+
Slot.new(slot_json['id'], slot_json['name'], slot_json['self'], slot_json['binary'], slot_json['config'], slot_json['status'])
|
187
|
+
end
|
188
|
+
|
189
|
+
# verify response
|
190
|
+
if slots.empty? then
|
191
|
+
raise CommandError.new(:no_slots, "No slots match the provided filters.")
|
192
|
+
end
|
193
|
+
|
194
|
+
slots
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Parse Command Line
|
199
|
+
#
|
200
|
+
commands = [:show, :assign, :clear, :start, :stop, :restart, :ssh]
|
201
|
+
options = {
|
202
|
+
:coordinator_url => ENV['GALAXY_COORDINATOR']
|
203
|
+
}
|
204
|
+
filter = {}
|
205
|
+
|
206
|
+
option_parser = OptionParser.new do |opts|
|
207
|
+
opts.banner = "Usage: #{File.basename($0)} [options] <command>"
|
208
|
+
|
209
|
+
opts.separator ''
|
210
|
+
opts.separator 'Options:'
|
211
|
+
|
212
|
+
opts.on('-h', '--help', 'Display this screen') do
|
213
|
+
puts opts
|
214
|
+
exit exit_codes[:success]
|
215
|
+
end
|
216
|
+
|
217
|
+
opts.on("-v", "--version", "Display the Galaxy version number and exit") do
|
218
|
+
puts "Galaxy version #{GALAXY_VERSION}"
|
219
|
+
exit exit_codes[:success]
|
220
|
+
end
|
221
|
+
|
222
|
+
opts.on("--coordinator COORDINATOR", "Galaxy coordinator host (overrides GALAXY_COORDINATOR)") do |v|
|
223
|
+
options[:coordinator_url] = v
|
224
|
+
end
|
225
|
+
|
226
|
+
opts.on('--debug', 'Enable debug messages') do
|
227
|
+
options[:debug] = true
|
228
|
+
end
|
229
|
+
|
230
|
+
opts.separator ''
|
231
|
+
opts.separator 'Filters:'
|
232
|
+
|
233
|
+
opts.on("-b", "--binary BINARY", "Select slots with a given binary") do |arg|
|
234
|
+
filter[:binary] = arg
|
235
|
+
end
|
236
|
+
|
237
|
+
opts.on("-c", "--config CONFIG", "Select slots with given configuration") do |arg|
|
238
|
+
filter[:config] = arg
|
239
|
+
end
|
240
|
+
|
241
|
+
opts.on("-i", "--host HOST", "Select slots on the given hostname") do |arg|
|
242
|
+
filter[:host] = arg
|
243
|
+
end
|
244
|
+
|
245
|
+
opts.on("-I", "--ip IP", "Select slots at the given IP address") do |arg|
|
246
|
+
filter[:ip] = arg
|
247
|
+
end
|
248
|
+
|
249
|
+
opts.on("-n", "--name SLOT_NAME", "Select slots with given slot name") do |arg|
|
250
|
+
filter[:name] = arg
|
251
|
+
end
|
252
|
+
|
253
|
+
opts.on("-s", "--state STATE", "Select 'r{unning}', 's{topped}', 'u{assigned}' or 'unknown' slots", [:running, :r, :stopped, :s, :unassigned, :u, :unknown]) do |arg|
|
254
|
+
case arg
|
255
|
+
when :running, :r then
|
256
|
+
filter[:state] = 'running'
|
257
|
+
when :stopped, :s then
|
258
|
+
filter[:state] = 'stopped'
|
259
|
+
when :unassigned, :u then
|
260
|
+
filter[:state] = 'unassigned'
|
261
|
+
when :unknown then
|
262
|
+
filter[:state] = 'unknown'
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
notes = <<-NOTES
|
267
|
+
Notes:
|
268
|
+
- A filter is required for all commands except for show
|
269
|
+
- Filters are evaluated as: set | host | ip | state | (binary & config)
|
270
|
+
- The HOST, BINARY, and CONFIG arguments are globs
|
271
|
+
- BINARY format is groupId:artifactId[:packaging[:classifier]]:version
|
272
|
+
- CONFIG format is @env:component[:pools]:version
|
273
|
+
- The default filter selects all hosts
|
274
|
+
NOTES
|
275
|
+
opts.separator ''
|
276
|
+
opts.separator strip(notes)
|
277
|
+
opts.separator ''
|
278
|
+
opts.separator 'Commands:'
|
279
|
+
opts.separator " #{commands.join("\n ")}"
|
280
|
+
end
|
281
|
+
|
282
|
+
option_parser.parse!(ARGV)
|
283
|
+
|
284
|
+
puts options.map { |k, v| "#{k}=#{v}" }.join("\n") if options[:debug]
|
285
|
+
puts filter.map { |k, v| "#{k}=#{v}" }.join("\n") if options[:debug]
|
286
|
+
|
287
|
+
if ARGV.length == 0
|
288
|
+
puts option_parser
|
289
|
+
exit exit_codes[:success]
|
290
|
+
end
|
291
|
+
|
292
|
+
command = ARGV[0].to_sym
|
293
|
+
|
294
|
+
#
|
295
|
+
# Execute Command
|
296
|
+
#
|
297
|
+
begin
|
298
|
+
if !commands.include?(command)
|
299
|
+
raise CommandError.new(:invalid_usage, "Unsupported command: #{command}")
|
300
|
+
end
|
301
|
+
|
302
|
+
if options[:coordinator_url].nil? || options[:coordinator_url].empty?
|
303
|
+
raise CommandError.new(:invalid_usage, "You must set Galaxy coordinator host by passing --coordinator COORDINATOR or by setting the GALAXY_COORDINATOR environment variable.")
|
304
|
+
end
|
305
|
+
|
306
|
+
slots = send(command, filter, options, ARGV.drop(1))
|
307
|
+
slots = slots.sort_by { |slot| slot.name + slot.id }
|
308
|
+
puts '' if options[:debug]
|
309
|
+
slots.each { |slot| slot.print_col } unless slots.nil?
|
310
|
+
exit exit_codes[:success]
|
311
|
+
rescue CommandError => e
|
312
|
+
puts e.message
|
313
|
+
if e.code == :invalid_usage
|
314
|
+
puts ''
|
315
|
+
puts option_parser
|
316
|
+
end
|
317
|
+
if options[:debug]
|
318
|
+
puts ''
|
319
|
+
puts "exit: #{e.code}"
|
320
|
+
end
|
321
|
+
exit exit_codes[e.code]
|
322
|
+
end
|
323
|
+
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: com.proofpoint.galaxy.cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
version: "0.2"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Dain Sundstrom
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2011-05-02 00:00:00 -07:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: httpclient
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 2
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
version: 2.2.0
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: json_pure
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 1
|
42
|
+
- 5
|
43
|
+
- 1
|
44
|
+
version: 1.5.1
|
45
|
+
type: :runtime
|
46
|
+
version_requirements: *id002
|
47
|
+
description: Galaxy command line interface
|
48
|
+
email:
|
49
|
+
- dain@iq80.com
|
50
|
+
executables:
|
51
|
+
- galaxy
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files: []
|
55
|
+
|
56
|
+
files:
|
57
|
+
- bin/galaxy
|
58
|
+
- lib/galaxy.rb
|
59
|
+
- lib/galaxy/version.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: https://github.com/dain/galaxy-server
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project: galaxy
|
86
|
+
rubygems_version: 1.3.6
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: galaxy
|
90
|
+
test_files: []
|
91
|
+
|