openshift 0.60.3

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.
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person
5
+ # obtaining a copy of this software and associated documentation files
6
+ # (the "Software"), to deal in the Software without restriction,
7
+ # including without limitation the rights to use, copy, modify, merge,
8
+ # publish, distribute, sublicense, and/or sell copies of the Software,
9
+ # and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'openshift'
25
+
26
+ def usage
27
+ puts <<USAGE
28
+ == Synopsis
29
+
30
+ os-tail-logs: Tail or download log files from an environment
31
+
32
+ == Usage
33
+
34
+ os tail-logs [options] [NAME]
35
+
36
+ -u|--username
37
+ Redhat Login (RHN or OpenShift login with OpenShift Express access)
38
+
39
+ -p|--password
40
+ Redhat Password
41
+
42
+ -t|--target flex|express
43
+ The cloud platform the environment is running on.
44
+
45
+ -h|--help
46
+ Prints this message
47
+
48
+ NAME: The name or GUID of the environment to get logs from.
49
+ USAGE
50
+ end
51
+
52
+ opts = GetoptLong.new(
53
+ ["--username", "-u", GetoptLong::REQUIRED_ARGUMENT],
54
+ ["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
55
+ ["--sso", GetoptLong::REQUIRED_ARGUMENT],
56
+ ["--debug", GetoptLong::NO_ARGUMENT],
57
+ ["--help", GetoptLong::NO_ARGUMENT],
58
+ ["--porcelin", GetoptLong::NO_ARGUMENT]
59
+ )
60
+
61
+ args = {}
62
+ begin
63
+ opts.each{ |k,v| args[k]=v }
64
+ rescue GetoptLong::Error => e
65
+ usage
66
+ exit -100
67
+ end
68
+
69
+ @debug = true if args['--debug']
70
+ args['--target'] = conf('default_target') || 'flex' if args['--target'].nil? or args['--target']==""
71
+ debug "Target platform #{args['--target']}"
72
+
73
+ if args['--help']
74
+ usage
75
+ exit
76
+ end
77
+
78
+ if args['--target'] == 'flex'
79
+ flex_server = conf('flex_server')
80
+ cookie = args['--sso']
81
+ if !cookie
82
+ username = args['--username'] || conf("username") || Openshift::IO.prompt("Redhat username",[],Openshift::Validation.method(:check_login))
83
+ password = args['--password'] || Openshift::IO.prompt("Redhat password",nil,nil,true,false)
84
+ csay("Logging into Openshift Flex as #{username}\n",:message)
85
+ cookie=Openshift.login(@http,username,password)
86
+ end
87
+
88
+ environment_id = ARGV.shift
89
+ debug "Tailing environment: #{environment_id}"
90
+ if not environment_id
91
+ csay("No environment specified.",:error)
92
+ exit
93
+ end
94
+
95
+ csay("Fetching environment list... ")
96
+ environments=nil
97
+ begin
98
+ environments=`os-list-environments --sso "#{cookie}" --porcelin`
99
+ environments = JSON.parse(environments)
100
+ csay("[OK]",:conf)
101
+ rescue Exception => e
102
+ debug environments
103
+ debug e
104
+ csay("[ERROR]",:error)
105
+ csay("Error retrieving environment list.")
106
+ exit -400
107
+ end
108
+ candidates = environments.find_all{ |c| c["name"]==environment_id or c["id"]==environment_id }
109
+
110
+ if candidates.size == 0
111
+ csay("Unable to find environment identified by #{environment_id}",:error)
112
+ exit -200
113
+ end
114
+
115
+ if candidates.size > 1
116
+ csay("Multiple environments are named #{environment_id}. Please provide the environment Id",:error)
117
+ exit -201
118
+ end
119
+
120
+ environment = candidates[0]
121
+ csay("Tailing logs for environment ")
122
+ csay("#{environment["name"]} ",:emphasis)
123
+ csay("...")
124
+ lastEntry = nil
125
+ params = nil
126
+ while(true)
127
+ params = { "start-time" => lastEntry['timestamp'].to_i, "start-index" => lastEntry['index'].to_i} if not lastEntry.nil?
128
+ uri = URI.parse("https://#{environment['dns']}:4242/monitoring/logs")
129
+ response = Openshift::Rest.get(@http, uri, params,
130
+ nil, {'user' => environment['username'], 'password' => environment['password']})
131
+ case response
132
+ when Net::HTTPSuccess
133
+
134
+ else
135
+ debug "HTTP code: #{response.code}"
136
+ debug response.body
137
+ csay("[ERROR]",:error) if not @porcelin
138
+ csay("Unable to retrieve application logs for environment.",:error)
139
+ end
140
+ logs = JSON.parse(response.body)
141
+ logs = logs['logs']
142
+ lastEntry = logs['last-entry']
143
+ entries = logs['entries']
144
+
145
+ if entries.size ==0
146
+ csay("No more logs..sleeping 5 sec..")
147
+ sleep(5)
148
+ end
149
+ entries.each{ |entry|
150
+ csay("[#{Time.at(entry['timestamp']).utc}] ")
151
+ csay("[#{entry['app_id']}] ")
152
+ csay(entry['text'])
153
+ }
154
+ lastEntry['index'] = lastEntry['index'].to_i + 1
155
+ debug lastEntry
156
+ end
157
+ else
158
+ csay("This feature is currently not implemented for Openshift Express applications.\n",:red)
159
+ end
@@ -0,0 +1,5 @@
1
+ debug=false
2
+ login_server=https://www.redhat.com
3
+ flex_server=https://openshift.redhat.com/flex
4
+ libra_server=openshift.redhat.com
5
+ domain=prod.rhcloud.com
@@ -0,0 +1,666 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright 2010 Red Hat, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person
5
+ # obtaining a copy of this software and associated documentation files
6
+ # (the "Software"), to deal in the Software without restriction,
7
+ # including without limitation the rights to use, copy, modify, merge,
8
+ # publish, distribute, sublicense, and/or sell copies of the Software,
9
+ # and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'rubygems'
25
+ require 'fileutils'
26
+ require 'getoptlong'
27
+ require 'json'
28
+ require 'net/http'
29
+ require 'net/https'
30
+ require 'net/http/post/multipart'
31
+ require 'parseconfig'
32
+ require 'resolv'
33
+ require 'uri'
34
+ require 'highline/import'
35
+ require 'cgi'
36
+
37
+ @libra_kfile = "#{ENV['HOME']}/.ssh/libra_id_rsa"
38
+ @libra_kpfile = "#{ENV['HOME']}/.ssh/libra_id_rsa.pub"
39
+ @conf_name = 'openshift.conf'
40
+
41
+ _linux_cfg = '/etc/openshift/' + @conf_name
42
+ _gem_cfg = File.join(File.expand_path(File.dirname(__FILE__) + "/../conf"), @conf_name)
43
+ _home_conf = File.expand_path('~/.openshift')
44
+ @local_config_path = File.join(_home_conf, @conf_name)
45
+ @config_path = File.exists?(_linux_cfg) ? _linux_cfg : _gem_cfg
46
+
47
+ FileUtils.mkdir_p _home_conf unless File.directory?(_home_conf)
48
+ local_config_path = File.expand_path(@local_config_path)
49
+ if !File.exists? local_config_path
50
+ FileUtils.touch local_config_path
51
+ puts ""
52
+ puts "Created local config file: " + local_config_path
53
+ puts "openshift.conf contains user configuration and can be transferred across clients."
54
+ puts ""
55
+ end
56
+
57
+ begin
58
+ $global_config = ParseConfig.new(@config_path)
59
+ $local_config = ParseConfig.new(File.expand_path(@local_config_path))
60
+ rescue Errno::EACCES => e
61
+ puts "Could not open config file: #{e.message}"
62
+ exit 253
63
+ end
64
+
65
+ # Check for proxy environment
66
+ if ENV['http_proxy']
67
+ host, port = ENV['http_proxy'].split(':')
68
+ @http = Net::HTTP::Proxy(host, port)
69
+ else
70
+ @http = Net::HTTP
71
+ end
72
+
73
+ def conf(name)
74
+ val = $local_config.get_value(name) ? $local_config.get_value(name) : $global_config.get_value(name)
75
+ val.gsub!(/\\:/,":") if not val.nil?
76
+ #print "CONF #{name} => #{val}\n\n"
77
+ val
78
+ end
79
+
80
+ def setconf(name,value)
81
+ $local_config.add(name,value)
82
+ $local_config.write(File.open(File.expand_path(@local_config_path),"w"))
83
+ end
84
+
85
+ HighLine.track_eof=false
86
+ HighLine.color_scheme = HighLine::ColorScheme.new do |cs|
87
+ cs[:emphasis] = [ :blue, :bold ]
88
+ cs[:error] = [ :red ]
89
+ cs[:warn] = [ :red ]
90
+ cs[:debug] = [ :red, :on_white, :bold ]
91
+ cs[:conf] = [ :green ]
92
+ cs[:question] = [ :magenta, :bold ]
93
+ cs[:table] = [ :blue ]
94
+ cs[:table_header] = [ :bold ]
95
+ cs[:message] = [ :bold ]
96
+ end
97
+
98
+ @h = HighLine.new
99
+ def csay(str,*options)
100
+ lastChar = str[-1..-1]
101
+ h = HighLine.new
102
+ if lastChar == ' ' or lastChar == '\t'
103
+ str=h.color(str[0..-2],*options)+lastChar
104
+ else
105
+ str=h.color(str,*options)
106
+ end
107
+ h.say(str)
108
+ end
109
+
110
+ def debug(*s)
111
+ @h = HighLine.new if @h.nil?
112
+ if @debug or conf('debug') == "true"
113
+ str = "DEBUG"
114
+ str += " "*(@h.output_cols()-str.length) if str.length < @h.output_cols()
115
+ csay(str,:debug)
116
+ s.each{ |line|
117
+ str = line.to_s
118
+ str += " "*(@h.output_cols()-str.length) + "\n" if str.length < @h.output_cols()
119
+ csay(str,:debug)
120
+ }
121
+ end
122
+ end
123
+
124
+ module Openshift
125
+ module SSH
126
+ def self.gen_ssh_keys(libra_kfile, libra_kpfile)
127
+ if File.readable?(libra_kfile)
128
+ puts "OpenShift ssh key found at #{libra_kfile}. Reusing..."
129
+ else
130
+ puts "Generating OpenShift ssh key to #{libra_kfile}"
131
+ # Use system for interaction
132
+ system("ssh-keygen -t rsa -f '#{libra_kfile}'")
133
+ end
134
+ ssh_key = File.open(libra_kpfile).gets.chomp.split(' ')[1]
135
+ end
136
+
137
+ def self.setup_ssh_config(domain)
138
+ ssh_config = "#{ENV['HOME']}/.ssh/config"
139
+ ssh_config_d = "#{ENV['HOME']}/.ssh/"
140
+ # Check / add new host to ~/.ssh/config
141
+ puts "Checking ~/.ssh/config"
142
+
143
+ found = false
144
+ begin
145
+ File.open(ssh_config, "r") do |sline|
146
+ while(line = sline.gets)
147
+ if line.to_s.start_with? "Host *.#{domain}"
148
+ found = true
149
+ break
150
+ end
151
+ end
152
+ end
153
+ rescue Errno::EACCES
154
+ puts "Could not read from #{ssh_config}"
155
+ puts "Reason: " + $!
156
+ puts
157
+ puts "Please correct this first. Then run rerun."
158
+ puts
159
+ exit 213
160
+ rescue Errno::ENOENT
161
+ puts "Could not find #{ssh_config}. This is ok, continuing"
162
+ end
163
+ if found
164
+ puts "Found #{domain} in ~/.ssh/config... No need to adjust"
165
+ else
166
+ puts " Adding #{domain} to ~/.ssh/config"
167
+ begin
168
+ f = File.open(ssh_config, "a")
169
+ f.puts <<SSH
170
+
171
+ # Added by rhc-create-application on #{`date`}
172
+ Host *.#{domain}
173
+ IdentityFile ~/.ssh/libra_id_rsa
174
+ VerifyHostKeyDNS yes
175
+ StrictHostKeyChecking no
176
+ UserKnownHostsFile ~/.ssh/libra_known_hosts
177
+
178
+ SSH
179
+ f.close
180
+ rescue Errno::EACCES
181
+ puts "Could not write to #{ssh_config}"
182
+ puts "Reason: " + $!
183
+ puts
184
+ puts "Please correct this first. Then run rerun."
185
+ puts
186
+ exit 214
187
+ rescue Errno::ENOENT
188
+ # Make directory and config if they do not exist
189
+ puts "Could not find directory: " + $!
190
+ puts "creating"
191
+ FileUtils.mkdir_p ssh_config_d
192
+ file = File.open(ssh_config, 'w')
193
+ file.close
194
+ retry
195
+ end
196
+ end
197
+ File.chmod(0700, ssh_config_d)
198
+ File.chmod(0600, ssh_config)
199
+ end
200
+ end
201
+
202
+ module Validation
203
+ Maxdlen = 16
204
+
205
+ TYPES = {
206
+ 'php-5.3' => :php,
207
+ 'perl-5.10' => :perl,
208
+ 'rack-1.1' => :rack,
209
+ 'wsgi-3.2' => :wsgi,
210
+ 'jbossas-7.0' => :jbossas
211
+ }
212
+
213
+ EXPRESS_SUPPORTED_TYPES = {
214
+ 'php-5.3' => :php,
215
+ 'rack-1.1' => :rack,
216
+ 'wsgi-3.2' => :wsgi
217
+ }
218
+
219
+ def self.get_supportted_templates(sep=', ', target="express")
220
+ if target == "express"
221
+ return get_cartridge_types(EXPRESS_SUPPORTED_TYPES)
222
+ else
223
+ return get_cartridge_types(FLEX_SUPPORTED_TYPES)
224
+ end
225
+ end
226
+
227
+ def self.check_login(login)
228
+ if login
229
+ if login.length < 6
230
+ csay('Login must be at least 6 characters\n',:error)
231
+ return false
232
+ elsif login =~ /["\$\^<>\|%\/;:,\\\*=~]/
233
+ csay('Login may not contain any of these characters: (\") ($) (^) (<) (>) (|) (%) (/) (;) (:) (,) (\) (*) (=) (~)\n',:error)
234
+ return false
235
+ end
236
+ else
237
+ csay("Login is required\n",:error)
238
+ return false
239
+ end
240
+ true
241
+ end
242
+
243
+ def self.check_field(field, type, max=0, space_ok=false)
244
+ if field
245
+ if space_ok
246
+ if field =~ /[^0-9a-zA-Z ]/
247
+ csay("#{type} contains non-alphanumeric characters!\n",:error)
248
+ return false
249
+ end
250
+ else
251
+ if field =~ /[^0-9a-zA-Z]/
252
+ csay("#{type} contains non-alphanumeric characters!\n",:error)
253
+ return false
254
+ end
255
+ end
256
+ if max != 0 && field.length > max
257
+ csay("maximum #{type} size is #{max} characters\n",:error)
258
+ return false
259
+ end
260
+ if field.strip.length == 0
261
+ csay("#{type} is required",:error)
262
+ return false
263
+ end
264
+ else
265
+ csay("#{type} is required",:error)
266
+ return false
267
+ end
268
+ true
269
+ end
270
+ end
271
+
272
+ module IO
273
+ def self.prompt(prompt, options=nil,func=nil,required=false,echo=true,limit=nil)
274
+ input = nil
275
+ while input == nil
276
+ if options.nil? or options.length == 0
277
+ csay("#{prompt}? ",:question)
278
+ input = ask(""){ |q|
279
+ q.echo = "*" if !echo
280
+ q.limit = limit if !limit.nil?
281
+ }
282
+ else
283
+ csay("#{prompt} [#{options.join(',')}]? default: ",:question)
284
+ input = ask(""){ |q|
285
+ q.default = options[0] if !options.nil? and options.length > 0
286
+ }
287
+ if options.index(input).nil?
288
+ csay("Invalid value: #{input}. Please choose from ",:error)
289
+ csay("[#{options.join(',')}]",:emphasis)
290
+ input = nil
291
+ end
292
+ end
293
+
294
+ if func and not func.call(input)
295
+ input = nil
296
+ end
297
+
298
+ if required and (input.nil? or input.strip == "")
299
+ csay("This is required field. Please enter a value.",:error)
300
+ input = nil
301
+ end
302
+ end
303
+ input
304
+ end
305
+ end
306
+
307
+ module Formatter
308
+ def self.table( col_names, col_keys, col_sizes, rows, indent=0)
309
+ self.print_row_delim(col_sizes,indent)
310
+ print (" " * 4 * indent)
311
+ csay("| ",:table)
312
+ (0...col_names.size).each{ |i|
313
+ csay(sprintf("%#{col_sizes[i]}s ",col_names[i]),:table_header)
314
+ csay("| ",:table)
315
+ }
316
+ print "\n"
317
+ self.print_row_delim(col_sizes,indent)
318
+ rows.each{ |r|
319
+ print (" " * 4 * indent)
320
+ csay("| ",:table)
321
+ (0...col_names.size).each{ |i|
322
+ if not r[col_keys[i]].nil?
323
+ printf "%#{col_sizes[i]}s ", r[col_keys[i]]
324
+ else
325
+ printf "%#{col_sizes[i]}s ", " "
326
+ end
327
+ csay("| ", :table)
328
+ }
329
+ print "\n"
330
+ }
331
+ self.print_row_delim(col_sizes,indent)
332
+ end
333
+
334
+ def self.print_row_delim(col_sizes,indent)
335
+ print(" " * 4 * indent)
336
+ str = "+"
337
+ col_sizes.each{ |s|
338
+ str += "-"*(s+2)
339
+ str += "+"
340
+ }
341
+ csay(str,:table)
342
+ end
343
+ end
344
+
345
+ module Rest
346
+ def self.execute(http, req, url, params=nil, cookies=nil, auth=nil)
347
+ cookies ||= ''
348
+
349
+ req['cookie']=""
350
+ cookies.each{ |cookie|
351
+ req['cookie'] += cookie
352
+ }
353
+
354
+ debug "---cookie---"
355
+ debug req['cookie']
356
+ debug "------------"
357
+
358
+ req.set_form_data(params) if params
359
+ req.basic_auth(auth['user'], auth['password']) if auth != nil
360
+
361
+ http = http.new(url.host, url.port)
362
+ #http.set_debug_output $stderr
363
+ if url.scheme == "https"
364
+ http.use_ssl = true
365
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
366
+ http.timeout = 60*10
367
+ end
368
+ http.open_timeout = 10
369
+ http.read_timeout = 60*10
370
+ begin
371
+ response = http.start {|http| http.request(req)}
372
+ response.each{|k,v|
373
+ debug "Header: #{k}:#{v}"
374
+ }
375
+ debug "Response code:#{response.code} body:#{response.body}"
376
+ response
377
+ rescue Exception => e
378
+ puts "There was a problem communicating with the server. Response message: #{e.message}"
379
+ exit 219
380
+ end
381
+
382
+ end
383
+
384
+ def self.doHttp(http, method, url, params=nil, cookies=nil, auth=nil)
385
+ case method
386
+ when "POST"
387
+ post(http, url, params, cookies, auth)
388
+ when "PUT"
389
+ put(http, url, params, cookies, auth)
390
+ when "GET"
391
+ get(http, url, params, cookies, auth)
392
+ when "DELETE"
393
+ delete(http, url, params, cookies, auth)
394
+ else
395
+ get(http, url, params, cookies, auth)
396
+ end
397
+ end
398
+
399
+ def self.put(http, url, params=nil, cookies=nil, auth=nil)
400
+ req = http::Put.new(url.path)
401
+ execute(http, req, url, params, cookies, auth)
402
+ end
403
+
404
+ def self.get(http, url, params=nil, cookies='', auth=nil)
405
+ path = url.path
406
+ path += "?" + params.collect { |k,v| "#{k}=#{CGI::escape(v.to_s)}" }.join('&') if not params.nil?
407
+ req = http::Get.new(path)
408
+ execute(http, req, url, nil, cookies, auth)
409
+ end
410
+
411
+ def self.postFile(http, url, params, fileParam, cookies=nil, auth=nil)
412
+ paramName=fileParam.keys[0]
413
+ fileName=fileParam[paramName]
414
+ response=nil
415
+ File.open(fileName) do |file|
416
+ params[paramName] = UploadIO.new(file, "application/octet-stream", File.basename(fileName))
417
+ req = Net::HTTP::Post::Multipart.new(url.path, params)
418
+ response = execute(http, req, url, nil, cookies, auth)
419
+ end
420
+ response
421
+ end
422
+
423
+ def self.post(http, url, params, cookies=nil, auth=nil)
424
+ req = http::Post.new(url.path)
425
+ execute(http, req, url, params, cookies, auth)
426
+ end
427
+
428
+ def self.delete(http, url, params, cookies=nil, auth=nil)
429
+ req = http::Delete.new(url.path)
430
+ execute(http, req, url, params, cookies, auth)
431
+ end
432
+ end
433
+
434
+ def self.login(http, username, password)
435
+ login_server = conf('login_server')
436
+ login_url = URI.parse("#{login_server}/wapps/streamline/login.html")
437
+ response = Rest.post(http, login_url, {'login' => username, 'password' => password})
438
+ case response
439
+ when Net::HTTPUnauthorized:
440
+ csay("Invalid username or password.\n", :red, :bold)
441
+ exit -1
442
+ end
443
+ debug response
444
+ response['Set-Cookie'].split("\; ")[0] + "\; "
445
+ end
446
+
447
+ def self.add_rhlogin_config(rhlogin, uuid=nil)
448
+ f = open(File.expand_path(@local_config_path), 'a')
449
+
450
+ unless @local_config.get_value('username')
451
+ f.puts("# Default rhlogin to use if none is specified")
452
+ f.puts("username=#{rhlogin}")
453
+ end
454
+ f.puts("#{rhlogin}=#{uuid}") unless @local_config.get_value('uuid') or uuid.nil?
455
+ f.close
456
+ end
457
+
458
+ module Flex
459
+ TEMPLATES = {
460
+ 'php' => ['php-5', 'www-dynamic'],
461
+ 'zend' => ['zend-server-php', 'www-dynamic'],
462
+ 'zend_ce' => ['zend-server-ce', 'www-dynamic'],
463
+ 'tomcat' => ['tomcat', 'jdk6'],
464
+ 'jboss6' => ['jboss-6', 'jdk6'],
465
+ 'jboss7' => ['jboss-7', 'jdk6']
466
+ }
467
+
468
+ def self.templates
469
+ return TEMPLATES
470
+ end
471
+ end
472
+
473
+ module Git
474
+ def self.git_repo?
475
+ `git rev-parse --show-toplevel 2> /dev/null`.strip != ""
476
+ end
477
+
478
+ def self.get_git_base_dir
479
+ `git rev-parse --show-toplevel 2> /dev/null`.strip
480
+ end
481
+
482
+ def self.add_remote(uri,remote_name)
483
+ system("git remote add #{remote_name} #{uri}")
484
+ end
485
+
486
+ def self.clone(uri,dirName,remote_name="origin")
487
+ system("git clone #{uri} #{dirName} --origin #{remote_name} --quiet")
488
+ end
489
+
490
+ def self.pull(remote_name="origin")
491
+ system("git pull #{remote_name} master --quiet")
492
+ end
493
+
494
+ def self.push(uri,remote_name)
495
+ system("git push #{remote_name} master --quiet")
496
+ end
497
+ end
498
+
499
+ module Debug
500
+ def self.print_post_data(h)
501
+ debug 'DEBUG: Submitting form:'
502
+ h.each do |k,v|
503
+ if k.to_s != 'password'
504
+ debug "#{k.to_s}: #{v.to_s}"
505
+ else
506
+ debug 'password: ' + ("X" * v.length)
507
+ end
508
+ end
509
+ end
510
+ end
511
+
512
+ module Express
513
+ Maxdlen = 16
514
+ Maxretries = 10
515
+ Defaultdelay = 2
516
+
517
+ def self.delay(time, adj=Defaultdelay)
518
+ (time*=adj).to_int
519
+ end
520
+
521
+ def self.get_cartridges_list(libra_server, net_http, cart_type="standalone", debug=true, print_result=nil)
522
+ puts "Contacting https://#{libra_server} to obtain list of cartridges..."
523
+ puts " (please excuse the delay)"
524
+ data = {'cart_type' => cart_type}
525
+ if debug
526
+ data['debug'] = "true"
527
+ end
528
+ print_post_data(data, debug)
529
+ json_data = JSON.generate(data)
530
+
531
+ url = URI.parse("https://#{libra_server}/broker/cartlist")
532
+ response = http_post(net_http, url, json_data, "none")
533
+
534
+ unless response.code == '200'
535
+ print_response_err(response, debug)
536
+ return []
537
+ end
538
+ json_resp = JSON.parse(response.body)
539
+ if print_result
540
+ print_response_success(json_resp, debug)
541
+ end
542
+ begin
543
+ carts = (JSON.parse(json_resp['data']))['carts']
544
+ rescue JSON::ParserError
545
+ exit 254
546
+ end
547
+ carts
548
+ end
549
+
550
+ def self.get_cartridge_listing(carts, sep, libra_server, net_http, cart_type="standalone", debug=true, print_result=nil)
551
+ carts = get_cartridges_list(libra_server, net_http, cart_type, debug, print_result) if carts.nil?
552
+ carts.join(sep)
553
+ end
554
+
555
+ def self.get_password
556
+ password = nil
557
+ begin
558
+ print "Password: "
559
+ system "stty -echo"
560
+ password = gets.chomp
561
+ ensure
562
+ system "stty echo"
563
+ end
564
+ puts "\n"
565
+ password
566
+ end
567
+
568
+ def self.http_post(http, url, json_data, password)
569
+ req = http::Post.new(url.path)
570
+
571
+ req.set_form_data({'json_data' => json_data, 'password' => password})
572
+ http = http.new(url.host, url.port)
573
+ http.open_timeout = 10
574
+ if url.scheme == "https"
575
+ http.use_ssl = true
576
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
577
+ end
578
+ begin
579
+ response = http.start {|http| http.request(req)}
580
+ if response.code == '404' && response.content_type == 'text/html'
581
+ # TODO probably want to remove this at some point
582
+ puts "!!!! WARNING !!!! WARNING !!!! WARNING !!!!"
583
+ puts "RHCloud server not found. You might want to try updating your rhc client tools."
584
+ exit 218
585
+ end
586
+ response
587
+ rescue Exception => e
588
+ puts "There was a problem communicating with the server. Response message: #{e.message}"
589
+ puts "If you were disconnected it is possible the operation finished without being able to report success."
590
+ puts "You can use rhc-user-info and rhc-ctl-app to learn about the status of your user and application(s)."
591
+ exit 219
592
+ end
593
+ end
594
+
595
+ def self.print_response_err(response)
596
+ puts "Problem reported from server. Response code was #{response.code}."
597
+ exit_code = 254
598
+ if response.content_type == 'application/json'
599
+ exit_code = print_json_body(response, debug)
600
+ elsif debug
601
+ debug "HTTP response from server is #{response.body}"
602
+ end
603
+ exit exit_code.nil? ? 666 : exit_code
604
+ end
605
+
606
+ def self.print_response_messages(json_resp)
607
+ messages = json_resp['messages']
608
+ if (messages && !messages.empty?)
609
+ puts ''
610
+ puts 'MESSAGES:'
611
+ puts messages
612
+ puts ''
613
+ end
614
+ end
615
+
616
+ def self.print_response_success(response, debug, always_print_result=false)
617
+ if debug
618
+ puts "Response from server:"
619
+ print_json_body(response, debug)
620
+ elsif always_print_result
621
+ print_json_body(response, debug)
622
+ else
623
+ json_resp = JSON.parse(response.body)
624
+ print_response_messages(json_resp)
625
+ end
626
+ end
627
+
628
+ def self.print_json_body(response, debug)
629
+ json_resp = JSON.parse(response.body)
630
+ print_response_messages(json_resp)
631
+ exit_code = json_resp['exit_code']
632
+ if debug
633
+ if json_resp['debug']
634
+ puts ''
635
+ puts 'DEBUG:'
636
+ puts json_resp['debug']
637
+ puts ''
638
+ puts "Exit Code: #{exit_code}"
639
+ if (json_resp.length > 3)
640
+ json_resp.each do |k,v|
641
+ if (k != 'result' && k != 'debug' && k != 'exit_code' && k != 'messages')
642
+ puts "#{k.to_s}: #{v.to_s}"
643
+ end
644
+ end
645
+ end
646
+ end
647
+ end
648
+ if json_resp['result']
649
+ puts ''
650
+ puts 'RESULT:'
651
+ puts json_resp['result']
652
+ puts ''
653
+ end
654
+ exit_code
655
+ end
656
+
657
+ #
658
+ # Check if host exists
659
+ #
660
+ def self.hostexist?(host)
661
+ dns = Resolv::DNS.new
662
+ resp = dns.getresources(host, Resolv::DNS::Resource::IN::A)
663
+ return resp.any?
664
+ end
665
+ end
666
+ end