tunnel-vmc-plugin 0.1.3 → 0.1.4

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/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
-