vmc 0.3.13 → 0.3.14.beta.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -62,6 +62,8 @@ MIT license, please see the LICENSE file. All rights reserved._
62
62
  bind-service <servicename> <appname> Bind a service to an application
63
63
  unbind-service <servicename> <appname> Unbind service from the application
64
64
  clone-services <src-app> <dest-app> Clone service bindings from <src-app> application to <dest-app>
65
+ tunnel <servicename> [--port] Create a local tunnel to a service
66
+ tunnel <servicename> <clientcmd> Create a local tunnel to a service and start a local client
65
67
 
66
68
  Administration
67
69
  user Display user account information
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rack', '~> 1.2.0'
4
+ gem 'caldecott', '= 0.0.3'
5
+ gem 'bundler'
6
+ gem 'em-websocket'
7
+ gem 'async_sinatra'
8
+ gem 'thin'
9
+ gem 'json'
10
+ gem 'uuidtools'
@@ -0,0 +1,48 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.6)
5
+ async_sinatra (0.5.0)
6
+ rack (>= 1.2.1)
7
+ sinatra (>= 1.0)
8
+ caldecott (0.0.3)
9
+ addressable (= 2.2.6)
10
+ async_sinatra (= 0.5.0)
11
+ em-http-request (= 0.3.0)
12
+ em-websocket (= 0.3.1)
13
+ json (= 1.6.1)
14
+ uuidtools (= 2.1.2)
15
+ daemons (1.1.4)
16
+ em-http-request (0.3.0)
17
+ addressable (>= 2.0.0)
18
+ escape_utils
19
+ eventmachine (>= 0.12.9)
20
+ em-websocket (0.3.1)
21
+ addressable (>= 2.1.1)
22
+ eventmachine (>= 0.12.9)
23
+ escape_utils (0.2.4)
24
+ eventmachine (0.12.10)
25
+ json (1.6.1)
26
+ rack (1.2.4)
27
+ sinatra (1.2.7)
28
+ rack (~> 1.1)
29
+ tilt (>= 1.2.2, < 2.0)
30
+ thin (1.2.11)
31
+ daemons (>= 1.0.9)
32
+ eventmachine (>= 0.12.6)
33
+ rack (>= 1.0.0)
34
+ tilt (1.3.3)
35
+ uuidtools (2.1.2)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ async_sinatra
42
+ bundler
43
+ caldecott (= 0.0.3)
44
+ em-websocket
45
+ json
46
+ rack (~> 1.2.0)
47
+ thin
48
+ uuidtools
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2009-2011 VMware, Inc.
3
+ $:.unshift(File.dirname(__FILE__) + '/lib')
4
+
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+
8
+ require 'caldecott'
9
+ require 'sinatra'
10
+ require 'json'
11
+ require 'eventmachine'
12
+
13
+ port = ENV['VMC_APP_PORT']
14
+ port ||= 8081
15
+
16
+ # add vcap specific stuff to Caldecott
17
+ class VcapHttpTunnel < Caldecott::Server::HttpTunnel
18
+ get '/info' do
19
+ { "version" => '0.0.4' }.to_json
20
+ end
21
+
22
+ def self.get_tunnels
23
+ super
24
+ end
25
+
26
+ get '/services' do
27
+ services_env = ENV['VMC_SERVICES']
28
+ return "no services env" if services_env.nil? or services_env.empty?
29
+ services_env
30
+ end
31
+
32
+ get '/services/:service' do |service_name|
33
+ services_env = ENV['VMC_SERVICES']
34
+ not_found if services_env.nil?
35
+
36
+ services = JSON.parse(services_env)
37
+ service = services.find { |s| s["name"] == service_name }
38
+ not_found if service.nil?
39
+ service["options"].to_json
40
+ end
41
+ end
42
+
43
+ VcapHttpTunnel.run!(:port => port, :auth_token => ENV["CALDECOTT_AUTH"])
@@ -0,0 +1,11 @@
1
+ redis:
2
+ redis-cli: redis-cli -h ${host} -p ${port} -a ${password}
3
+
4
+ mysql:
5
+ mysql: mysql --protocol=TCP --host=${host} --port=${port} --user=${user} --password=${password} ${name}
6
+
7
+ mongodb:
8
+ mongo: mongo --host ${host} --port ${port} -u ${user} -p ${password} ${name}
9
+
10
+ postgresql:
11
+ psql: PGPASSWORD='${password}' psql -h ${host} -p ${port} -d ${name} -U ${user} -w
data/lib/cli.rb CHANGED
@@ -11,6 +11,7 @@ module VMC
11
11
  autoload :Runner, "#{ROOT}/cli/runner"
12
12
  autoload :ZipUtil, "#{ROOT}/cli/zip_util"
13
13
  autoload :ServicesHelper, "#{ROOT}/cli/services_helper"
14
+ autoload :TunnelHelper, "#{ROOT}/cli/tunnel_helper"
14
15
 
15
16
  module Command
16
17
  autoload :Base, "#{ROOT}/cli/commands/base"
@@ -185,7 +185,7 @@ module VMC::Cli::Command
185
185
  uris << url
186
186
  app[:uris] = uris
187
187
  client.update_app(appname, app)
188
- display "Succesfully mapped url".green
188
+ display "Successfully mapped url".green
189
189
  end
190
190
 
191
191
  def unmap(appname, url)
@@ -196,7 +196,7 @@ module VMC::Cli::Command
196
196
  err "Invalid url" unless deleted
197
197
  app[:uris] = uris
198
198
  client.update_app(appname, app)
199
- display "Succesfully unmapped url".green
199
+ display "Successfully unmapped url".green
200
200
 
201
201
  end
202
202
 
@@ -268,6 +268,8 @@ module VMC::Cli::Command
268
268
  end
269
269
 
270
270
  def logs(appname)
271
+ # Check if we have an app before progressing further
272
+ client.app_info(appname)
271
273
  return grab_all_logs(appname) if @options[:all] && !@options[:instance]
272
274
  instance = @options[:instance] || '0'
273
275
  grab_logs(appname, instance)
@@ -686,7 +688,7 @@ module VMC::Cli::Command
686
688
 
687
689
  display "The following provisioned services are available"
688
690
  name = ask(
689
- "Please select one you which to prevision",
691
+ "Please select one you wish to use",
690
692
  { :indexed => true,
691
693
  :choices => user_services.collect { |s| s[:name] }
692
694
  }
@@ -38,7 +38,7 @@ module VMC::Cli::Command
38
38
  exit(false)
39
39
  else
40
40
  VMC::Cli::Config.store_target(target_url)
41
- say "Succesfully targeted to [#{target_url}]".green
41
+ say "Successfully targeted to [#{target_url}]".green
42
42
  end
43
43
  end
44
44
 
@@ -2,6 +2,7 @@ module VMC::Cli::Command
2
2
 
3
3
  class Services < Base
4
4
  include VMC::Cli::ServicesHelper
5
+ include VMC::Cli::TunnelHelper
5
6
 
6
7
  def services
7
8
  ss = client.services_info
@@ -81,5 +82,96 @@ module VMC::Cli::Command
81
82
  check_app_for_restart(dest_app)
82
83
  end
83
84
 
85
+ def tunnel(service=nil, client_name=nil)
86
+ unless defined? Caldecott
87
+ display "To use `vmc tunnel', you must first install Caldecott:"
88
+ display ""
89
+ display "\tgem install caldecott"
90
+ display ""
91
+ display "Note that you'll need a C compiler. If you're on OS X, Xcode"
92
+ display "will provide one. If you're on Windows, try DevKit."
93
+ display ""
94
+ display "This manual step will be removed in the future."
95
+ display ""
96
+ err "Caldecott is not installed."
97
+ end
98
+
99
+ ps = client.services
100
+ err "No services available to tunnel to" if ps.empty?
101
+
102
+ unless service
103
+ choices = ps.collect { |s| s[:name] }.sort
104
+ service = ask(
105
+ "Which service to tunnel to?",
106
+ :choices => choices,
107
+ :indexed => true
108
+ )
109
+ end
110
+
111
+ info = ps.select { |s| s[:name] == service }.first
112
+
113
+ err "Unknown service '#{service}'" unless info
114
+
115
+ # TODO: rather than default to a particular port, we should get
116
+ # the defaults based on the service name.. i.e. known services should
117
+ # have known local default ports for this side of the tunnel.
118
+ port = pick_tunnel_port(@options[:port] || 10000)
119
+
120
+ raise VMC::Client::AuthError unless client.logged_in?
121
+
122
+ if not tunnel_pushed?
123
+ display "Deploying tunnel application '#{tunnel_appname}'."
124
+ auth = ask("Create a password", :echo => "*")
125
+ push_caldecott(auth)
126
+ bind_service_banner(service, tunnel_appname, false)
127
+ start_caldecott
128
+ else
129
+ auth = ask("Password", :echo => "*")
130
+ end
131
+
132
+ if not tunnel_healthy?(auth)
133
+ display "Redeploying tunnel application '#{tunnel_appname}'."
134
+
135
+ # We don't expect caldecott not to be running, so take the
136
+ # most aggressive restart method.. delete/re-push
137
+ client.delete_app(tunnel_appname)
138
+ invalidate_tunnel_app_info
139
+
140
+ push_caldecott(auth)
141
+ bind_service_banner(service, tunnel_appname, false)
142
+ start_caldecott
143
+ end
144
+
145
+ if not tunnel_bound?(service)
146
+ bind_service_banner(service, tunnel_appname)
147
+ end
148
+
149
+ conn_info = tunnel_connection_info info[:vendor], service, auth
150
+ display_tunnel_connection_info(conn_info)
151
+ start_tunnel(service, port, conn_info, auth)
152
+
153
+ clients = get_clients_for(info[:vendor])
154
+ if clients.empty?
155
+ which = "none"
156
+ else
157
+ which = client_name || ask(
158
+ "Which client would you like to start?",
159
+ :choices => ["none"] + clients.keys,
160
+ :indexed => true
161
+ )
162
+ end
163
+
164
+ if which == "none"
165
+ wait_for_tunnel_end
166
+ else
167
+ wait_for_tunnel_start(port)
168
+ start_local_prog(which, local_prog_cmdline(clients[which], port, conn_info))
169
+ end
170
+ end
171
+
172
+ def get_clients_for(type)
173
+ conf = VMC::Cli::Config.clients
174
+ conf[type] || {}
175
+ end
84
176
  end
85
177
  end
@@ -15,6 +15,7 @@ module VMC::Cli::Command
15
15
  tries ||= 0
16
16
 
17
17
  unless no_prompt
18
+ display "Attempting login to [#{target_url}]" if target_url
18
19
  email ||= ask("Email")
19
20
  password ||= ask("Password", :echo => "*")
20
21
  end
data/lib/cli/config.rb CHANGED
@@ -14,6 +14,9 @@ module VMC::Cli
14
14
  TOKEN_FILE = '~/.vmc_token'
15
15
  INSTANCES_FILE = '~/.vmc_instances'
16
16
  ALIASES_FILE = '~/.vmc_aliases'
17
+ CLIENTS_FILE = '~/.vmc_clients'
18
+
19
+ STOCK_CLIENTS = File.expand_path("../../../config/clients.yml", __FILE__)
17
20
 
18
21
  class << self
19
22
  attr_accessor :colorize
@@ -102,6 +105,30 @@ module VMC::Cli
102
105
  File.open(aliases_file, 'wb') {|f| f.write(aliases.to_yaml)}
103
106
  end
104
107
 
108
+ def deep_merge(a, b)
109
+ merge = proc do |_, old, new|
110
+ if new.is_a?(Hash) and old.is_a?(Hash)
111
+ old.merge(new, &merge)
112
+ else
113
+ new
114
+ end
115
+ end
116
+
117
+ a.merge(b, &merge)
118
+ end
119
+
120
+ def clients
121
+ return @clients if @clients
122
+
123
+ stock = YAML.load_file(STOCK_CLIENTS)
124
+ if File.exists? CLIENTS_FILE
125
+ user = YAML.load_file(CLIENTS_FILE)
126
+ @clients = deep_merge(stock, user)
127
+ else
128
+ @clients = stock
129
+ end
130
+ end
131
+
105
132
  def lock_and_read(file)
106
133
  File.open(file, "r") {|f|
107
134
  f.flock(File::LOCK_EX)
data/lib/cli/runner.rb CHANGED
@@ -77,6 +77,8 @@ class VMC::Cli::Runner
77
77
  opts.on('-v', '--version') { set_cmd(:misc, :version) }
78
78
  opts.on('-h', '--help') { puts "#{command_usage}\n"; exit }
79
79
 
80
+ opts.on('--port PORT') { |port| @options[:port] = port }
81
+
80
82
  opts.on('--runtime RUNTIME') { |rt| @options[:runtime] = rt }
81
83
 
82
84
  # deprecated
@@ -367,6 +369,12 @@ class VMC::Cli::Runner
367
369
  usage('vmc unalias <alias>')
368
370
  set_cmd(:misc, :unalias, 1)
369
371
 
372
+ when 'tunnel'
373
+ usage('vmc tunnel [servicename] [clientcmd] [--port port]')
374
+ set_cmd(:services, :tunnel, 0) if @args.size == 0
375
+ set_cmd(:services, :tunnel, 1) if @args.size == 1
376
+ set_cmd(:services, :tunnel, 2) if @args.size == 2
377
+
370
378
  when 'help'
371
379
  display_help if @args.size == 0
372
380
  @help_only = true
@@ -0,0 +1,289 @@
1
+ # Copyright (c) 2009-2011 VMware, Inc.
2
+
3
+ require 'addressable/uri'
4
+
5
+ begin
6
+ require 'caldecott'
7
+ rescue LoadError
8
+ end
9
+
10
+ module VMC::Cli
11
+ module TunnelHelper
12
+ PORT_RANGE = 10
13
+
14
+ HELPER_APP = File.expand_path("../../../caldecott_helper", __FILE__)
15
+
16
+ # bump this AND the version info reported by HELPER_APP/server.rb
17
+ # this is to keep the helper in sync with any updates here
18
+ HELPER_VERSION = '0.0.4'
19
+
20
+ def tunnel_uniquename
21
+ random_service_name(tunnel_appname)
22
+ end
23
+
24
+ def tunnel_appname
25
+ "caldecott"
26
+ end
27
+
28
+ def tunnel_app_info
29
+ return @tun_app_info if @tunnel_app_info
30
+ begin
31
+ @tun_app_info = client.app_info(tunnel_appname)
32
+ rescue => e
33
+ @tun_app_info = nil
34
+ end
35
+ end
36
+
37
+ def tunnel_url
38
+ return @tunnel_url if @tunnel_url
39
+
40
+ tun_url = tunnel_app_info[:uris][0]
41
+
42
+ ["https", "http"].each do |scheme|
43
+ url = "#{scheme}://#{tun_url}"
44
+ begin
45
+ RestClient.get(url)
46
+
47
+ # https failed
48
+ rescue Errno::ECONNREFUSED
49
+
50
+ # we expect a 404 since this request isn't auth'd
51
+ rescue RestClient::ResourceNotFound
52
+ return @tunnel_url = url
53
+ end
54
+ end
55
+
56
+ err "Cannot determine URL for #{tun_url}"
57
+ end
58
+
59
+ def invalidate_tunnel_app_info
60
+ @tunnel_url = nil
61
+ @tunnel_app_info = nil
62
+ end
63
+
64
+ def tunnel_pushed?
65
+ not tunnel_app_info.nil?
66
+ end
67
+
68
+ def tunnel_healthy?(token)
69
+ return false unless tunnel_app_info[:state] == 'STARTED'
70
+
71
+ begin
72
+ response = RestClient.get(
73
+ "#{tunnel_url}/info",
74
+ "Auth-Token" => token
75
+ )
76
+
77
+ info = JSON.parse(response)
78
+ if info["version"] == HELPER_VERSION
79
+ true
80
+ else
81
+ stop_caldecott
82
+ false
83
+ end
84
+ rescue RestClient::Exception
85
+ stop_caldecott
86
+ false
87
+ end
88
+ end
89
+
90
+ def tunnel_bound?(service)
91
+ tunnel_app_info[:services].include?(service)
92
+ end
93
+
94
+ def tunnel_connection_info(type, service, token)
95
+ display "Getting tunnel connection info: ", false
96
+ response = nil
97
+ 10.times do
98
+ begin
99
+ response = RestClient.get("#{tunnel_url}/services/#{service}", "Auth-Token" => token)
100
+ break
101
+ rescue RestClient::Exception
102
+ sleep 1
103
+ end
104
+
105
+ display ".", false
106
+ end
107
+
108
+ unless response
109
+ err "Expected remote tunnel to know about #{service}, but it doesn't"
110
+ end
111
+
112
+ display "OK".green
113
+
114
+ info = JSON.parse(response)
115
+ case type
116
+ when "rabbitmq"
117
+ uri = Addressable::URI.parse info["url"]
118
+ info["hostname"] = uri.host
119
+ info["port"] = uri.port
120
+ info["vhost"] = uri.path[1..-1]
121
+ info["user"] = uri.user
122
+ info["password"] = uri.password
123
+ info.delete "url"
124
+
125
+ # we use "db" as the "name" for mongo
126
+ # existing "name" is junk
127
+ when "mongodb"
128
+ info["name"] = info["db"]
129
+ info.delete "db"
130
+
131
+ # our "name" is irrelevant for redis
132
+ when "redis"
133
+ info.delete "name"
134
+ end
135
+
136
+ ['hostname', 'port', 'password'].each do |k|
137
+ err "Could not determine #{k} for #{service}" if info[k].nil?
138
+ end
139
+
140
+ info
141
+ end
142
+
143
+ def display_tunnel_connection_info(info)
144
+ display ''
145
+ display "Service connection info: "
146
+
147
+ to_show = [nil, nil, nil] # reserved for user, pass, db name
148
+ info.keys.each do |k|
149
+ case k
150
+ when "host", "hostname", "port", "node_id"
151
+ # skip
152
+ when "user", "username"
153
+ # prefer "username" over "user"
154
+ to_show[0] = k unless to_show[0] == "username"
155
+ when "password"
156
+ to_show[1] = k
157
+ when "name"
158
+ to_show[2] = k
159
+ else
160
+ to_show << k
161
+ end
162
+ end
163
+ to_show.compact!
164
+
165
+ align_len = to_show.collect(&:size).max + 1
166
+
167
+ to_show.each do |k|
168
+ # TODO: modify the server services rest call to have explicit knowledge
169
+ # about the items to return. It should return all of them if
170
+ # the service is unknown so that we don't have to do this weird
171
+ # filtering.
172
+ display " #{k.ljust align_len}: ", false
173
+ display "#{info[k]}".yellow
174
+ end
175
+ display ''
176
+ end
177
+
178
+ def start_tunnel(service, local_port, conn_info, auth)
179
+ display "Starting tunnel to #{service.bold} on port #{local_port.to_s.bold}."
180
+
181
+ @local_tunnel_thread = Thread.new do
182
+ Caldecott::Client.start({
183
+ :local_port => local_port,
184
+ :tun_url => tunnel_url,
185
+ :dst_host => conn_info['hostname'],
186
+ :dst_port => conn_info['port'],
187
+ :log_file => STDOUT,
188
+ :log_level => "ERROR",
189
+ :auth_token => auth,
190
+ :quiet => true
191
+ })
192
+ end
193
+
194
+ at_exit { @local_tunnel_thread.kill }
195
+ end
196
+
197
+ def pick_tunnel_port(port)
198
+ original = port
199
+
200
+ PORT_RANGE.times do |n|
201
+ begin
202
+ TCPSocket.open('localhost', port)
203
+ port += 1
204
+ rescue => e
205
+ return port
206
+ end
207
+ end
208
+
209
+ err "Could not pick a port between #{original} and #{original + PORT_RANGE - 1}"
210
+ end
211
+
212
+ def wait_for_tunnel_start(port)
213
+ 10.times do |n|
214
+ begin
215
+ TCPSocket.open('localhost', port)
216
+ display '' if n > 0
217
+ return true
218
+ rescue => e
219
+ display "Waiting for local tunnel to become available", false if n == 0
220
+ display '.', false
221
+ sleep 1
222
+ end
223
+ end
224
+ err "Could not connect to local tunnel."
225
+ end
226
+
227
+ def wait_for_tunnel_end
228
+ display "Open another shell to run command-line clients or"
229
+ display "use a UI tool to connect using the displayed information."
230
+ display "Press Ctrl-C to exit..."
231
+ @local_tunnel_thread.join
232
+ end
233
+
234
+ def local_prog_cmdline(command, local_port, tunnel_info)
235
+ cmd = command.dup
236
+ cmd.gsub!(/\$\{\s*([^\}]+)\s*\}/) do
237
+ case $1
238
+ when "host"
239
+ # TODO: determine proper host
240
+ "localhost"
241
+ when "port"
242
+ local_port
243
+ when "user", "username"
244
+ tunnel_info["username"]
245
+ else
246
+ tunnel_info[$1] || err("Unknown symbol '#{$1}'")
247
+ end
248
+ end
249
+ cmd
250
+ end
251
+
252
+ def start_local_prog(which, cmdline)
253
+ display "Launching '#{cmdline}'"
254
+ display ''
255
+ unless system(cmdline)
256
+ err "Failed to start '#{which}' client; is it in your $PATH?"
257
+ end
258
+ end
259
+
260
+ def push_caldecott(token)
261
+ client.create_app(
262
+ tunnel_appname,
263
+ { :name => tunnel_appname,
264
+ :staging => {:framework => "sinatra"},
265
+ :uris => ["#{tunnel_uniquename}.#{VMC::Cli::Config.suggest_url}"],
266
+ :instances => 1,
267
+ :resources => {:memory => 64},
268
+ :env => ["CALDECOTT_AUTH=#{token}"]
269
+ }
270
+ )
271
+
272
+ Command::Apps.new({}).send(:upload_app_bits, tunnel_appname, HELPER_APP)
273
+
274
+ invalidate_tunnel_app_info
275
+ end
276
+
277
+ def stop_caldecott
278
+ Command::Apps.new({}).stop(tunnel_appname)
279
+
280
+ invalidate_tunnel_app_info
281
+ end
282
+
283
+ def start_caldecott
284
+ Command::Apps.new({}).start(tunnel_appname)
285
+
286
+ invalidate_tunnel_app_info
287
+ end
288
+ end
289
+ end
data/lib/cli/usage.rb CHANGED
@@ -78,6 +78,8 @@ Currently available vmc commands are:
78
78
  bind-service <servicename> <appname> Bind a service to an application
79
79
  unbind-service <servicename> <appname> Unbind service from the application
80
80
  clone-services <src-app> <dest-app> Clone service bindings from <src-app> application to <dest-app>
81
+ tunnel <servicename> [--port] Create a local tunnel to a service
82
+ tunnel <servicename> <clientcmd> Create a local tunnel to a service and start a local client
81
83
 
82
84
  Administration
83
85
  user Display user account information
data/lib/cli/version.rb CHANGED
@@ -2,6 +2,6 @@ module VMC
2
2
  module Cli
3
3
  # This version number is used as the RubyGem release version.
4
4
  # The internal VMC version number is VMC::VERSION.
5
- VERSION = '0.3.13'
5
+ VERSION = '0.3.14.beta.3'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vmc
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.3.13
4
+ prerelease: 7
5
+ version: 0.3.14.beta.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - VMware
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-11-02 00:00:00 -07:00
13
+ date: 2011-11-14 00:00:00 -08:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -68,42 +68,53 @@ dependencies:
68
68
  requirements:
69
69
  - - ~>
70
70
  - !ruby/object:Gem::Version
71
- version: 0.2.0
71
+ version: 0.3.0
72
72
  type: :runtime
73
73
  version_requirements: *id005
74
74
  - !ruby/object:Gem::Dependency
75
- name: rake
75
+ name: addressable
76
76
  prerelease: false
77
77
  requirement: &id006 !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: 2.2.6
83
+ type: :runtime
84
+ version_requirements: *id006
85
+ - !ruby/object:Gem::Dependency
86
+ name: rake
87
+ prerelease: false
88
+ requirement: &id007 !ruby/object:Gem::Requirement
78
89
  none: false
79
90
  requirements:
80
91
  - - ">="
81
92
  - !ruby/object:Gem::Version
82
93
  version: "0"
83
94
  type: :development
84
- version_requirements: *id006
95
+ version_requirements: *id007
85
96
  - !ruby/object:Gem::Dependency
86
97
  name: rspec
87
98
  prerelease: false
88
- requirement: &id007 !ruby/object:Gem::Requirement
99
+ requirement: &id008 !ruby/object:Gem::Requirement
89
100
  none: false
90
101
  requirements:
91
102
  - - ~>
92
103
  - !ruby/object:Gem::Version
93
104
  version: 1.3.0
94
105
  type: :development
95
- version_requirements: *id007
106
+ version_requirements: *id008
96
107
  - !ruby/object:Gem::Dependency
97
108
  name: webmock
98
109
  prerelease: false
99
- requirement: &id008 !ruby/object:Gem::Requirement
110
+ requirement: &id009 !ruby/object:Gem::Requirement
100
111
  none: false
101
112
  requirements:
102
113
  - - "="
103
114
  - !ruby/object:Gem::Version
104
115
  version: 1.5.0
105
116
  type: :development
106
- version_requirements: *id008
117
+ version_requirements: *id009
107
118
  description: Client library and CLI that provides access to the VMware Cloud Application Platform.
108
119
  email: support@vmware.com
109
120
  executables:
@@ -117,6 +128,7 @@ files:
117
128
  - LICENSE
118
129
  - README.md
119
130
  - Rakefile
131
+ - config/clients.yml
120
132
  - lib/cli/commands/admin.rb
121
133
  - lib/cli/commands/apps.rb
122
134
  - lib/cli/commands/base.rb
@@ -129,6 +141,7 @@ files:
129
141
  - lib/cli/frameworks.rb
130
142
  - lib/cli/runner.rb
131
143
  - lib/cli/services_helper.rb
144
+ - lib/cli/tunnel_helper.rb
132
145
  - lib/cli/usage.rb
133
146
  - lib/cli/version.rb
134
147
  - lib/cli/zip_util.rb
@@ -136,6 +149,9 @@ files:
136
149
  - lib/vmc/client.rb
137
150
  - lib/vmc/const.rb
138
151
  - lib/vmc.rb
152
+ - caldecott_helper/Gemfile
153
+ - caldecott_helper/Gemfile.lock
154
+ - caldecott_helper/server.rb
139
155
  - bin/vmc
140
156
  has_rdoc: true
141
157
  homepage: http://vmware.com
@@ -155,9 +171,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
155
171
  required_rubygems_version: !ruby/object:Gem::Requirement
156
172
  none: false
157
173
  requirements:
158
- - - ">="
174
+ - - ">"
159
175
  - !ruby/object:Gem::Version
160
- version: "0"
176
+ version: 1.3.1
161
177
  requirements: []
162
178
 
163
179
  rubyforge_project: