appfog-tunnel-vmc-plugin 0.0.1.1 → 0.0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OWNjYTczMmEwYTU5ZTdiOGE5OWM0OWFiNmFmYWRjMjFjZGZhOGFiZQ==
4
+ YTk5ZTgwOTI3YTc4MDkwMDAwYzMyZGJmOWUwMzEzMzFhMDE5ZTU3Yw==
5
5
  data.tar.gz: !binary |-
6
- YmVlY2QxOWMwZjM1OWVkNzJlN2ZkYWNlNzVkYmQ4NWNiMTdlYWI4Yg==
6
+ NGZiMmM1YWM4ZjA3MWZjZjJlOWE1OTBmY2QzNmM1NjZiNWJjNDk0Zg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MjI1ZjNiYjBlMTg2NWU5ZGIyZjRmNzZjM2U2MTVlNWZlZTcyZGE0YmYyZjE5
10
- YTM2ODEwMTFjMDg5Nzk0ZWI4NTdlMzUzYjBmZTA3M2E3NWE1NmUwNjJiNDNm
11
- Y2RkNzhiMTVkNjBlM2QzODEzYWVlYzJhOGM4ODRkZTlhM2Q0MmQ=
9
+ YmU5YTYwMWRlYTk3MTY5ZDlmOWNkY2Q1MGUwMzNiYmQ5ZTg2YzYwNDdjMGI4
10
+ OGFkZTA4MzU0ZmVlZDQ2NDNkNWJiNzFkMjljNGJkZWMzMThlZjQ1MTg1MDgy
11
+ YmVhOWNiNjVlNzBhMWUzNjhlNWY5NDA1ZThlMWUxZTkwMTFmMTI=
12
12
  data.tar.gz: !binary |-
13
- MDdlZjk0ODhiNWJkOWJmNThjYmQyNjUwMjU0ODAyNmI5MDRmODY5MzdkZGIw
14
- OWRlNjU3OTg5MmVmZDg5ZmI5Mzc4Y2RiNDhiMDk2NDdlMWUxYzM2OGEwOWM1
15
- OTI3MTY3YTI4MjQ2MGU2ZWM5NjQyMjZlZDVjMTZhYzNjZjNhYzI=
13
+ ZTgwZmQxN2E2YzAyNjgxYTVjZGFkZTMwMGI5ODg4NjA3ZDY5NDRhNjQ0MmFk
14
+ ZTJhNTliNmNmZmE1YWJlNDgyMWM3OTYwNmUwNTNmNDllYWY1MWFhY2M3NGNl
15
+ ZDIxMmRhYWNjNjQxNDg3NTkwODcwZGYzYmRkZmIxZmQwMjJmZWE=
@@ -1,5 +1,5 @@
1
1
  require "vmc/cli"
2
- require "tunnel-vmc-plugin/tunnel"
2
+ require "appfog-tunnel-vmc-plugin/tunnel"
3
3
 
4
4
  module VMCTunnel
5
5
  class Tunnel < VMC::CLI
@@ -1,3 +1,3 @@
1
1
  module VMCTunnel
2
- VERSION = "0.0.1.1".freeze
2
+ VERSION = "0.0.1.2".freeze
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -6,7 +6,7 @@ require "cfoundry/test_support"
6
6
  require "vmc"
7
7
  require "vmc/test_support"
8
8
 
9
- require "#{SPEC_ROOT}/../lib/tunnel-vmc-plugin/plugin"
9
+ require "#{SPEC_ROOT}/../lib/appfog-tunnel-vmc-plugin/plugin"
10
10
 
11
11
  RSpec.configure do |c|
12
12
  c.include Fake::FakeMethods
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appfog-tunnel-vmc-plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.1
4
+ version: 0.0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Suraci, Tim Santeford
@@ -147,9 +147,6 @@ files:
147
147
  - lib/appfog-tunnel-vmc-plugin/plugin.rb
148
148
  - lib/appfog-tunnel-vmc-plugin/tunnel.rb
149
149
  - lib/appfog-tunnel-vmc-plugin/version.rb
150
- - lib/tunnel-vmc-plugin/plugin.rb
151
- - lib/tunnel-vmc-plugin/tunnel.rb
152
- - lib/tunnel-vmc-plugin/version.rb
153
150
  - helper-app/Gemfile
154
151
  - helper-app/Gemfile.lock
155
152
  - helper-app/server.rb
@@ -1,178 +0,0 @@
1
- require "vmc/cli"
2
- require "tunnel-vmc-plugin/tunnel"
3
-
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__)
8
-
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
28
- instances = client.service_instances
29
- fail "No services available for tunneling." if instances.empty?
30
-
31
- instance = input[:instance, instances.sort_by(&:name)]
32
- vendor = v2? ? instance.service_plan.service.label : instance.vendor
33
- clients = tunnel_clients[vendor] || {}
34
- client_name = input[:client, clients]
35
-
36
- tunnel = CFTunnel.new(client, instance)
37
- port = tunnel.pick_port!(input[:port])
38
-
39
- conn_info =
40
- with_progress("Opening tunnel on port #{c(port, :name)}") do
41
- tunnel.open!
42
- end
43
-
44
- if client_name == "none"
45
- unless quiet?
46
- line
47
- display_tunnel_connection_info(conn_info)
48
-
49
- line
50
- line "Open another shell to run command-line clients or"
51
- line "use a UI tool to connect using the displayed information."
52
- line "Press Ctrl-C to exit..."
53
- end
54
-
55
- tunnel.wait_for_end
56
- else
57
- with_progress("Waiting for local tunnel to become available") do
58
- tunnel.wait_for_start
59
- end
60
-
61
- unless start_local_prog(clients, client_name, conn_info, port)
62
- fail "'#{client_name}' execution failed; is it in your $PATH?"
63
- end
64
- end
65
- end
66
-
67
- def tunnel_clients
68
- return @tunnel_clients if @tunnel_clients
69
- stock_config = YAML.load_file(STOCK_CLIENTS)
70
- custom_config_file = File.expand_path(CLIENTS_FILE)
71
- if File.exists?(custom_config_file)
72
- custom_config = YAML.load_file(custom_config_file)
73
- @tunnel_clients = deep_merge(stock_config, custom_config)
74
- else
75
- @tunnel_clients = stock_config
76
- end
77
- end
78
-
79
- private
80
-
81
- def display_tunnel_connection_info(info)
82
- line "Service connection info:"
83
-
84
- to_show = [nil, nil, nil] # reserved for user, pass, db name
85
- info.keys.each do |k|
86
- case k
87
- when "host", "hostname", "port", "node_id"
88
- # skip
89
- when "user", "username"
90
- # prefer "username" over "user"
91
- to_show[0] = k unless to_show[0] == "username"
92
- when "password"
93
- to_show[1] = k
94
- when "name"
95
- to_show[2] = k
96
- else
97
- to_show << k
98
- end
99
- end
100
- to_show.compact!
101
-
102
- align_len = to_show.collect(&:size).max + 1
103
-
104
- indented do
105
- to_show.each do |k|
106
- # TODO: modify the server services rest call to have explicit knowledge
107
- # about the items to return. It should return all of them if
108
- # the service is unknown so that we don't have to do this weird
109
- # filtering.
110
- line "#{k.ljust align_len}: #{b(info[k])}"
111
- end
112
- end
113
-
114
- line
115
- end
116
-
117
- def start_local_prog(clients, command, info, port)
118
- client = clients[File.basename(command)]
119
-
120
- cmdline = "#{command} "
121
-
122
- case client
123
- when Hash
124
- cmdline << resolve_symbols(client["command"], info, port)
125
- client["environment"].each do |e|
126
- if e =~ /([^=]+)=(["']?)([^"']*)\2/
127
- ENV[$1] = resolve_symbols($3, info, port)
128
- else
129
- fail "Invalid environment variable: #{e}"
130
- end
131
- end
132
- when String
133
- cmdline << resolve_symbols(client, info, port)
134
- else
135
- raise "Unknown client info: #{client.inspect}."
136
- end
137
-
138
- if verbose?
139
- line
140
- line "Launching '#{cmdline}'"
141
- end
142
-
143
- system(cmdline)
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.is_a?(Hash) && new.is_a?(Hash)
169
- old.merge(new, &merge)
170
- else
171
- new
172
- end
173
- }
174
-
175
- a.merge(b, &merge)
176
- end
177
- end
178
- end
@@ -1,306 +0,0 @@
1
- require "addressable/uri"
2
- require "restclient"
3
- require "uuidtools"
4
-
5
- require "caldecott-client"
6
-
7
-
8
- class CFTunnel
9
- HELPER_NAME = "caldecott"
10
- HELPER_APP = File.expand_path("../../../helper-app", __FILE__)
11
-
12
- # bump this AND the version info reported by HELPER_APP/server.rb
13
- # this is to keep the helper in sync with any updates here
14
- HELPER_VERSION = "0.0.4"
15
-
16
- def initialize(client, service, port = 10000)
17
- @client = client
18
- @service = service
19
- @port = port
20
- end
21
-
22
- def open!
23
- if helper
24
- auth = helper_auth
25
-
26
- unless helper_healthy?(auth)
27
- delete_helper
28
- auth = create_helper
29
- end
30
- else
31
- auth = create_helper
32
- end
33
-
34
- bind_to_helper if @service && !helper_already_binds?
35
-
36
- info = get_connection_info(auth)
37
-
38
- start_tunnel(info, auth)
39
-
40
- info
41
- end
42
-
43
- def wait_for_start
44
- 10.times do |n|
45
- begin
46
- TCPSocket.open("localhost", @port).close
47
- return true
48
- rescue => e
49
- sleep 1
50
- end
51
- end
52
-
53
- raise "Could not connect to local tunnel."
54
- end
55
-
56
- def wait_for_end
57
- if @local_tunnel_thread
58
- @local_tunnel_thread.join
59
- else
60
- raise "Tunnel wasn't started!"
61
- end
62
- end
63
-
64
- PORT_RANGE = 10
65
- def pick_port!(port = @port)
66
- original = port
67
-
68
- PORT_RANGE.times do |n|
69
- begin
70
- TCPSocket.open("localhost", port)
71
- port += 1
72
- rescue
73
- return @port = port
74
- end
75
- end
76
-
77
- @port = grab_ephemeral_port
78
- end
79
-
80
- private
81
-
82
- def helper
83
- @helper ||= @client.app_by_name("#{HELPER_NAME}-#{@service.infra.name}")
84
- end
85
-
86
- def create_helper
87
- auth = UUIDTools::UUID.random_create.to_s
88
- push_helper(auth)
89
- start_helper
90
- auth
91
- end
92
-
93
- def helper_auth
94
- helper.env["CALDECOTT_AUTH"]
95
- end
96
-
97
- def helper_healthy?(token)
98
- return false unless helper.healthy?
99
-
100
- begin
101
- response = RestClient.get(
102
- "#{helper_url}/info",
103
- "Auth-Token" => token
104
- )
105
-
106
- info = JSON.parse(response)
107
- if info["version"] == HELPER_VERSION
108
- true
109
- else
110
- stop_helper
111
- false
112
- end
113
- rescue RestClient::Exception
114
- stop_helper
115
- false
116
- end
117
- end
118
-
119
- def helper_already_binds?
120
- helper.binds? @service
121
- end
122
-
123
- def push_helper(token)
124
- url = "#{random_helper_url}.#{@service.infra.name}.af.cm"
125
- is_v2 = @client.is_a?(CFoundry::V2::Client)
126
-
127
- app = @client.app
128
- app.name = "#{HELPER_NAME}-#{@service.infra.name}"
129
- app.infra = @service.infra
130
- app.framework = @client.framework_by_name("sinatra")
131
- app.runtime = @client.runtime_by_name("ruby192")
132
- app.total_instances = 1
133
- app.memory = 64
134
- app.env = { "CALDECOTT_AUTH" => token }
135
-
136
- if is_v2
137
- app.space = @client.current_space
138
- else
139
- app.services = [@service] if @service
140
- app.url = url
141
- end
142
-
143
- app.create!
144
-
145
- if is_v2
146
- app.bind(@service) if @service
147
- app.create_route(url)
148
- end
149
-
150
- begin
151
- app.upload(HELPER_APP)
152
- invalidate_tunnel_app_info
153
- rescue
154
- app.delete!
155
- raise
156
- end
157
- end
158
-
159
- def delete_helper
160
- helper.delete!
161
- invalidate_tunnel_app_info
162
- end
163
-
164
- def stop_helper
165
- helper.stop!
166
- invalidate_tunnel_app_info
167
- end
168
-
169
- TUNNEL_CHECK_LIMIT = 60
170
- def start_helper
171
- helper.start!
172
-
173
- seconds = 0
174
- until helper.healthy?
175
- sleep 1
176
- seconds += 1
177
- if seconds == TUNNEL_CHECK_LIMIT
178
- raise "Helper application failed to start."
179
- end
180
- end
181
-
182
- invalidate_tunnel_app_info
183
- end
184
-
185
- def bind_to_helper
186
- helper.bind(@service)
187
- helper.restart!
188
- end
189
-
190
- def invalidate_tunnel_app_info
191
- @helper_url = nil
192
- @helper = nil
193
- end
194
-
195
- def helper_url
196
- return @helper_url if @helper_url
197
-
198
- tun_url = helper.url
199
-
200
- ["https", "http"].each do |scheme|
201
- url = "#{scheme}://#{tun_url}"
202
- begin
203
- RestClient.get(url)
204
-
205
- # https failed
206
- rescue Errno::ECONNREFUSED
207
-
208
- # we expect a 404 since this request isn't auth'd
209
- rescue RestClient::ResourceNotFound
210
- return @helper_url = url
211
- end
212
- end
213
-
214
- raise "Cannot determine URL for #{tun_url}"
215
- end
216
-
217
- def get_connection_info(token)
218
- response = nil
219
- 10.times do
220
- begin
221
- response =
222
- RestClient.get(
223
- helper_url + "/" + safe_path("services", @service.name),
224
- "Auth-Token" => token)
225
-
226
- break
227
- rescue RestClient::Exception => e
228
- sleep 1
229
- end
230
- end
231
-
232
- unless response
233
- raise "Remote tunnel helper is unaware of #{@service.name}!"
234
- end
235
-
236
- is_v2 = @client.is_a?(CFoundry::V2::Client)
237
-
238
- info = JSON.parse(response)
239
- case (is_v2 ? @service.service_plan.service.label : @service.vendor)
240
- when "rabbitmq"
241
- uri = Addressable::URI.parse info["url"]
242
- info["hostname"] = uri.host
243
- info["port"] = uri.port
244
- info["vhost"] = uri.path[1..-1]
245
- info["user"] = uri.user
246
- info["password"] = uri.password
247
- info.delete "url"
248
-
249
- # we use "db" as the "name" for mongo
250
- # existing "name" is junk
251
- when "mongodb"
252
- info["name"] = info["db"]
253
- info.delete "db"
254
-
255
- # our "name" is irrelevant for redis
256
- when "redis"
257
- info.delete "name"
258
-
259
- when "filesystem"
260
- raise "Tunneling is not supported for this type of service"
261
- end
262
-
263
- ["hostname", "port", "password"].each do |k|
264
- raise "Could not determine #{k} for #{@service.name}" if info[k].nil?
265
- end
266
-
267
- info
268
- end
269
-
270
- def start_tunnel(conn_info, auth)
271
- @local_tunnel_thread = Thread.new do
272
- Caldecott::Client.start({
273
- :local_port => @port,
274
- :tun_url => helper_url,
275
- :dst_host => conn_info["hostname"],
276
- :dst_port => conn_info["port"],
277
- :log_file => STDOUT,
278
- :log_level => ENV["VMC_TUNNEL_DEBUG"] || "ERROR",
279
- :auth_token => auth,
280
- :quiet => true
281
- })
282
- end
283
-
284
- at_exit { @local_tunnel_thread.kill }
285
- end
286
-
287
- def random_helper_url
288
- random = sprintf("%x", rand(1000000))
289
- "caldecott-#{random}"
290
- end
291
-
292
- def safe_path(*segments)
293
- segments.flatten.collect { |x|
294
- URI.encode x.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
295
- }.join("/")
296
- end
297
-
298
- def grab_ephemeral_port
299
- socket = TCPServer.new("0.0.0.0", 0)
300
- socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
301
- Socket.do_not_reverse_lookup = true
302
- socket.addr[1]
303
- ensure
304
- socket.close
305
- end
306
- end
@@ -1,3 +0,0 @@
1
- module VMCTunnel
2
- VERSION = "0.0.1".freeze
3
- end