com.proofpoint.galaxy.cli 0.5 → 0.6

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