tunnel-vmc-plugin 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1 +1,47 @@
1
- require "bundler/gem_tasks"
1
+ require "rake"
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
4
+ require "tunnel-vmc-plugin/version"
5
+
6
+ task :default => :spec
7
+
8
+ desc "Run specs"
9
+ task :spec => ["bundler:install", "test:spec"]
10
+
11
+ desc "Run integration tests"
12
+ task :test => ["bundler:install", "test:integration"]
13
+
14
+ task :build do
15
+ sh "gem build tunnel-vmc-plugin.gemspec"
16
+ end
17
+
18
+ task :install => :build do
19
+ sh "gem install --local tunnel-vmc-plugin-#{VMCTunnel::VERSION}.gem"
20
+ end
21
+
22
+ task :uninstall do
23
+ sh "gem uninstall tunnel-vmc-plugin"
24
+ end
25
+
26
+ task :reinstall => [:uninstall, :install]
27
+
28
+ task :release => :build do
29
+ sh "gem push tunnel-vmc-plugin-#{VMCTunnel::VERSION}.gem"
30
+ end
31
+
32
+ namespace "bundler" do
33
+ desc "Install gems"
34
+ task "install" do
35
+ sh("bundle install")
36
+ end
37
+ end
38
+
39
+ namespace "test" do
40
+ task "spec" do |t|
41
+ # nothing
42
+ end
43
+
44
+ task "integration" do |t|
45
+ sh("cd spec && bundle exec rake spec")
46
+ end
47
+ end
@@ -12,7 +12,7 @@ GEM
12
12
  em-websocket (= 0.3.1)
13
13
  json (= 1.6.1)
14
14
  uuidtools (= 2.1.2)
15
- daemons (1.1.4)
15
+ daemons (1.1.8)
16
16
  em-http-request (0.3.0)
17
17
  addressable (>= 2.0.0)
18
18
  escape_utils
@@ -23,11 +23,11 @@ GEM
23
23
  escape_utils (0.2.4)
24
24
  eventmachine (0.12.10)
25
25
  json (1.6.1)
26
- rack (1.2.4)
27
- sinatra (1.2.7)
26
+ rack (1.2.5)
27
+ sinatra (1.2.8)
28
28
  rack (~> 1.1)
29
29
  tilt (>= 1.2.2, < 2.0)
30
- thin (1.2.11)
30
+ thin (1.4.1)
31
31
  daemons (>= 1.0.9)
32
32
  eventmachine (>= 0.12.6)
33
33
  rack (>= 1.0.0)
@@ -1,69 +1,178 @@
1
- require "vmc/plugin"
1
+ require "vmc/cli"
2
2
  require "tunnel-vmc-plugin/tunnel"
3
3
 
4
- VMC.Plugin(VMC::Service) do
5
- include VMCTunnel
4
+ module VMCTunnel
5
+ class Tunnel < VMC::CLI
6
+ CLIENTS_FILE = "#{VMC::CONFIG_DIR}/tunnel-clients.yml"
7
+ STOCK_CLIENTS = File.expand_path("../../../config/clients.yml", __FILE__)
6
8
 
7
- desc "tunnel [SERVICE] [CLIENT]", "Create a local tunnel to a service."
8
- group :services, :manage
9
- flag(:service) { |choices|
10
- ask("Which service?", :choices => choices)
11
- }
12
- flag(:client)
13
- flag(:port, :default => 10000)
14
- def tunnel(service = nil, client_name = nil)
15
- client_name ||= input(:client)
16
-
17
- services = client.services
9
+ desc "Create a local tunnel to a service."
10
+ group :services, :manage
11
+ input(:instance, :argument => :optional,
12
+ :from_given => find_by_name("service instance"),
13
+ :desc => "Service instance to tunnel to") { |instances|
14
+ ask("Which service instance?", :choices => instances,
15
+ :display => proc(&:name))
16
+ }
17
+ input(:client, :argument => :optional,
18
+ :desc => "Client to automatically launch") { |clients|
19
+ if clients.empty?
20
+ "none"
21
+ else
22
+ ask("Which client would you like to start?",
23
+ :choices => clients.keys.unshift("none"))
24
+ end
25
+ }
26
+ input(:port, :default => 10000, :desc => "Port to bind the tunnel to")
27
+ def tunnel(input)
28
+ instances = client.service_instances
29
+ fail "No services available for tunneling." if instances.empty?
18
30
 
19
- fail "No services available for tunneling." if services.empty?
31
+ instance = input[:instance, instances.sort_by(&:name)]
32
+ clients = tunnel_clients[instance.vendor] || {}
33
+ client_name = input[:client, clients]
20
34
 
21
- service ||= input(:service, services.collect(&:name).sort)
35
+ tunnel = CFTunnel.new(client, instance)
36
+ port = tunnel.pick_port!(input[:port])
22
37
 
23
- info = services.find { |s| s.name == service }
38
+ conn_info =
39
+ with_progress("Opening tunnel on port #{c(port, :name)}") do
40
+ tunnel.open!
41
+ end
24
42
 
25
- fail "Unknown service '#{service}'" unless info
43
+ if client_name == "none"
44
+ unless simple_output?
45
+ line
46
+ display_tunnel_connection_info(conn_info)
26
47
 
27
- clients = tunnel_clients[info.vendor] || {}
48
+ line
49
+ line "Open another shell to run command-line clients or"
50
+ line "use a UI tool to connect using the displayed information."
51
+ line "Press Ctrl-C to exit..."
52
+ end
28
53
 
29
- unless client_name
30
- if clients.empty?
31
- client_name = "none"
54
+ tunnel.wait_for_end
32
55
  else
33
- client_name = ask(
34
- "Which client would you like to start?",
35
- :choices => ["none"] + clients.keys)
56
+ with_progress("Waiting for local tunnel to become available") do
57
+ tunnel.wait_for_start
58
+ end
59
+
60
+ unless start_local_prog(clients, client_name, conn_info, port)
61
+ fail "'#{client_name}' execution failed; is it in your $PATH?"
62
+ end
36
63
  end
37
64
  end
38
65
 
39
- tunnel = CFTunnel.new(client, info)
40
- port = tunnel.pick_port!(input(:port))
66
+ private
67
+
68
+ def display_tunnel_connection_info(info)
69
+ line "Service connection info:"
41
70
 
42
- conn_info =
43
- with_progress("Opening tunnel on port #{c(port, :name)}") do
44
- tunnel.open!
71
+ to_show = [nil, nil, nil] # reserved for user, pass, db name
72
+ info.keys.each do |k|
73
+ case k
74
+ when "host", "hostname", "port", "node_id"
75
+ # skip
76
+ when "user", "username"
77
+ # prefer "username" over "user"
78
+ to_show[0] = k unless to_show[0] == "username"
79
+ when "password"
80
+ to_show[1] = k
81
+ when "name"
82
+ to_show[2] = k
83
+ else
84
+ to_show << k
85
+ end
45
86
  end
87
+ to_show.compact!
46
88
 
47
- if client_name == "none"
48
- unless simple_output?
49
- puts ""
50
- display_tunnel_connection_info(conn_info)
89
+ align_len = to_show.collect(&:size).max + 1
51
90
 
52
- puts ""
53
- puts "Open another shell to run command-line clients or"
54
- puts "use a UI tool to connect using the displayed information."
55
- puts "Press Ctrl-C to exit..."
91
+ indented do
92
+ to_show.each do |k|
93
+ # TODO: modify the server services rest call to have explicit knowledge
94
+ # about the items to return. It should return all of them if
95
+ # the service is unknown so that we don't have to do this weird
96
+ # filtering.
97
+ line "#{k.ljust align_len}: #{b(info[k])}"
98
+ end
56
99
  end
57
100
 
58
- tunnel.wait_for_end
59
- else
60
- with_progress("Waiting for local tunnel to become available") do
61
- tunnel.wait_for_start
101
+ line
102
+ end
103
+
104
+ def start_local_prog(clients, command, info, port)
105
+ client = clients[File.basename(command)]
106
+
107
+ cmdline = "#{command} "
108
+
109
+ case client
110
+ when Hash
111
+ cmdline << resolve_symbols(client["command"], info, port)
112
+ client["environment"].each do |e|
113
+ if e =~ /([^=]+)=(["']?)([^"']*)\2/
114
+ ENV[$1] = resolve_symbols($3, info, port)
115
+ else
116
+ fail "Invalid environment variable: #{e}"
117
+ end
118
+ end
119
+ when String
120
+ cmdline << resolve_symbols(client, info, port)
121
+ else
122
+ raise "Unknown client info: #{client.inspect}."
62
123
  end
63
124
 
64
- unless start_local_prog(clients, client_name, conn_info, port)
65
- fail "'#{client_name}' execution failed; is it in your $PATH?"
125
+ if verbose?
126
+ line
127
+ line "Launching '#{cmdline}'"
66
128
  end
129
+
130
+ system(cmdline)
131
+ end
132
+
133
+ def tunnel_clients
134
+ return @tunnel_clients if @tunnel_clients
135
+
136
+ stock = YAML.load_file(STOCK_CLIENTS)
137
+ clients = File.expand_path CLIENTS_FILE
138
+ if File.exists? clients
139
+ user = YAML.load_file(clients)
140
+ @tunnel_clients = deep_merge(stock, user)
141
+ else
142
+ @tunnel_clients = stock
143
+ end
144
+ end
145
+
146
+ def resolve_symbols(str, info, local_port)
147
+ str.gsub(/\$\{\s*([^\}]+)\s*\}/) do
148
+ sym = $1
149
+
150
+ case sym
151
+ when "host"
152
+ # TODO: determine proper host
153
+ "localhost"
154
+ when "port"
155
+ local_port
156
+ when "user", "username"
157
+ info["username"]
158
+ when /^ask (.+)/
159
+ ask($1)
160
+ else
161
+ info[sym] || raise("Unknown symbol in config: #{sym}")
162
+ end
163
+ end
164
+ end
165
+
166
+ def deep_merge(a, b)
167
+ merge = proc { |old, new|
168
+ if old === Hash && new === Hash
169
+ old.merge(new, &merge)
170
+ else
171
+ new
172
+ end
173
+ }
174
+
175
+ a.merge(b, &merge)
67
176
  end
68
177
  end
69
178
  end
@@ -1,4 +1,5 @@
1
1
  require "addressable/uri"
2
+ require "restclient"
2
3
 
3
4
  require "caldecott"
4
5
 
@@ -89,12 +90,7 @@ class CFTunnel
89
90
  end
90
91
 
91
92
  def helper_auth
92
- helper.env.each do |e|
93
- name, val = e.split("=", 2)
94
- return val if name == "CALDECOTT_AUTH"
95
- end
96
-
97
- nil
93
+ helper.env["CALDECOTT_AUTH"]
98
94
  end
99
95
 
100
96
  def helper_healthy?(token)
@@ -120,7 +116,7 @@ class CFTunnel
120
116
  end
121
117
 
122
118
  def helper_already_binds?
123
- helper.services.include? @service.name
119
+ helper.binds? @service
124
120
  end
125
121
 
126
122
  def push_helper(token)
@@ -131,8 +127,8 @@ class CFTunnel
131
127
  app.url = "#{random_helper_url}.#{target_base}"
132
128
  app.total_instances = 1
133
129
  app.memory = 64
134
- app.env = ["CALDECOTT_AUTH=#{token}"]
135
- app.services = [@service.name] if @service
130
+ app.env = { "CALDECOTT_AUTH" => token }
131
+ app.services = [@service] if @service
136
132
  app.create!
137
133
 
138
134
  begin
@@ -171,7 +167,7 @@ class CFTunnel
171
167
  end
172
168
 
173
169
  def bind_to_helper
174
- helper.bind(@service.name)
170
+ helper.bind(@service)
175
171
  helper.restart!
176
172
  end
177
173
 
@@ -213,7 +209,6 @@ class CFTunnel
213
209
 
214
210
  break
215
211
  rescue RestClient::Exception => e
216
- p [e, e.to_s]
217
212
  sleep 1
218
213
  end
219
214
  end
@@ -288,116 +283,3 @@ class CFTunnel
288
283
  socket.close
289
284
  end
290
285
  end
291
-
292
- module VMCTunnel
293
- CLIENTS_FILE = "#{VMC::CONFIG_DIR}/tunnel-clients.yml"
294
- STOCK_CLIENTS = File.expand_path("../../../config/clients.yml", __FILE__)
295
-
296
- def display_tunnel_connection_info(info)
297
- puts "Service connection info:"
298
-
299
- to_show = [nil, nil, nil] # reserved for user, pass, db name
300
- info.keys.each do |k|
301
- case k
302
- when "host", "hostname", "port", "node_id"
303
- # skip
304
- when "user", "username"
305
- # prefer "username" over "user"
306
- to_show[0] = k unless to_show[0] == "username"
307
- when "password"
308
- to_show[1] = k
309
- when "name"
310
- to_show[2] = k
311
- else
312
- to_show << k
313
- end
314
- end
315
- to_show.compact!
316
-
317
- align_len = to_show.collect(&:size).max + 1
318
-
319
- to_show.each do |k|
320
- # TODO: modify the server services rest call to have explicit knowledge
321
- # about the items to return. It should return all of them if
322
- # the service is unknown so that we don't have to do this weird
323
- # filtering.
324
- print " #{k.ljust align_len}: #{b(info[k])}"
325
- end
326
-
327
- puts ""
328
- end
329
-
330
- def start_local_prog(clients, command, info, port)
331
- client = clients[File.basename(command)]
332
-
333
- cmdline = "#{command} "
334
-
335
- case client
336
- when Hash
337
- cmdline << resolve_symbols(client["command"], info, port)
338
- client["environment"].each do |e|
339
- if e =~ /([^=]+)=(["']?)([^"']*)\2/
340
- ENV[$1] = resolve_symbols($3, info, port)
341
- else
342
- raise "Invalid environment variable: #{e}"
343
- end
344
- end
345
- when String
346
- cmdline << resolve_symbols(client, info, port)
347
- else
348
- raise "Unknown client info: #{client.inspect}."
349
- end
350
-
351
- if verbose?
352
- puts ""
353
- puts "Launching '#{cmdline}'"
354
- end
355
-
356
- system(cmdline)
357
- end
358
-
359
- def tunnel_clients
360
- return @tunnel_clients if @tunnel_clients
361
-
362
- stock = YAML.load_file(STOCK_CLIENTS)
363
- clients = File.expand_path CLIENTS_FILE
364
- if File.exists? clients
365
- user = YAML.load_file(clients)
366
- @tunnel_clients = deep_merge(stock, user)
367
- else
368
- @tunnel_clients = stock
369
- end
370
- end
371
-
372
- def resolve_symbols(str, info, local_port)
373
- str.gsub(/\$\{\s*([^\}]+)\s*\}/) do
374
- sym = $1
375
-
376
- case sym
377
- when "host"
378
- # TODO: determine proper host
379
- "localhost"
380
- when "port"
381
- local_port
382
- when "user", "username"
383
- info["username"]
384
- when /^ask (.+)/
385
- ask($1)
386
- else
387
- info[sym] || raise("Unknown symbol in config: #{sym}")
388
- end
389
- end
390
- end
391
-
392
- def deep_merge(a, b)
393
- merge = proc { |old, new|
394
- if old === Hash && new === Hash
395
- old.merge(new, &merge)
396
- else
397
- new
398
- end
399
- }
400
-
401
- a.merge(b, &merge)
402
- end
403
- end
@@ -1,3 +1,3 @@
1
1
  module VMCTunnel
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
metadata CHANGED
@@ -1,81 +1,87 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: tunnel-vmc-plugin
3
- version: !ruby/object:Gem::Version
4
- hash: 29
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 3
10
- version: 0.1.3
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Alex Suraci
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-06-27 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: addressable
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cfoundry
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.3.18
22
+ type: :runtime
22
23
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
24
25
  none: false
25
- requirements:
26
+ requirements:
26
27
  - - ~>
27
- - !ruby/object:Gem::Version
28
- hash: 11
29
- segments:
30
- - 2
31
- - 2
32
- - 6
28
+ - !ruby/object:Gem::Version
29
+ version: 0.3.18
30
+ - !ruby/object:Gem::Dependency
31
+ name: addressable
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
33
37
  version: 2.2.6
34
38
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: eventmachine
38
39
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
40
+ version_requirements: !ruby/object:Gem::Requirement
40
41
  none: false
41
- requirements:
42
+ requirements:
42
43
  - - ~>
43
- - !ruby/object:Gem::Version
44
- hash: 31098193
45
- segments:
46
- - 1
47
- - 0
48
- - 0
49
- - beta
44
+ - !ruby/object:Gem::Version
45
+ version: 2.2.6
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
50
53
  version: 1.0.0.beta
51
54
  type: :runtime
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: caldecott
55
55
  prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.0.beta
62
+ - !ruby/object:Gem::Dependency
63
+ name: caldecott
64
+ requirement: !ruby/object:Gem::Requirement
57
65
  none: false
58
- requirements:
66
+ requirements:
59
67
  - - ~>
60
- - !ruby/object:Gem::Version
61
- hash: 21
62
- segments:
63
- - 0
64
- - 0
65
- - 5
68
+ - !ruby/object:Gem::Version
66
69
  version: 0.0.5
67
70
  type: :runtime
68
- version_requirements: *id003
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.0.5
69
78
  description:
70
- email:
79
+ email:
71
80
  - asuraci@vmware.com
72
81
  executables: []
73
-
74
82
  extensions: []
75
-
76
83
  extra_rdoc_files: []
77
-
78
- files:
84
+ files:
79
85
  - Rakefile
80
86
  - lib/tunnel-vmc-plugin/plugin.rb
81
87
  - lib/tunnel-vmc-plugin/tunnel.rb
@@ -86,36 +92,26 @@ files:
86
92
  - config/clients.yml
87
93
  homepage: http://cloudfoundry.com/
88
94
  licenses: []
89
-
90
95
  post_install_message:
91
96
  rdoc_options: []
92
-
93
- require_paths:
97
+ require_paths:
94
98
  - lib
95
- required_ruby_version: !ruby/object:Gem::Requirement
99
+ required_ruby_version: !ruby/object:Gem::Requirement
96
100
  none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- hash: 3
101
- segments:
102
- - 0
103
- version: "0"
104
- required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
106
  none: false
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- hash: 3
110
- segments:
111
- - 0
112
- version: "0"
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
113
111
  requirements: []
114
-
115
112
  rubyforge_project: tunnel-vmc-plugin
116
113
  rubygems_version: 1.8.23
117
114
  signing_key:
118
115
  specification_version: 3
119
116
  summary: External access to your services on Cloud Foundry via a Caldecott HTTP tunnel.
120
117
  test_files: []
121
-