udn 0.3.23.0.pre

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.
Files changed (43) hide show
  1. data/LICENSE +24 -0
  2. data/README.md +113 -0
  3. data/Rakefile +101 -0
  4. data/bin/udn +6 -0
  5. data/caldecott_helper/Gemfile +10 -0
  6. data/caldecott_helper/Gemfile.lock +48 -0
  7. data/caldecott_helper/server.rb +43 -0
  8. data/config/clients.yml +17 -0
  9. data/config/micro/offline.conf +2 -0
  10. data/config/micro/paths.yml +22 -0
  11. data/config/micro/refresh_ip.rb +20 -0
  12. data/lib/cli.rb +47 -0
  13. data/lib/cli/commands/admin.rb +80 -0
  14. data/lib/cli/commands/apps.rb +1129 -0
  15. data/lib/cli/commands/base.rb +228 -0
  16. data/lib/cli/commands/manifest.rb +56 -0
  17. data/lib/cli/commands/micro.rb +115 -0
  18. data/lib/cli/commands/misc.rb +129 -0
  19. data/lib/cli/commands/services.rb +259 -0
  20. data/lib/cli/commands/user.rb +65 -0
  21. data/lib/cli/config.rb +173 -0
  22. data/lib/cli/console_helper.rb +170 -0
  23. data/lib/cli/core_ext.rb +122 -0
  24. data/lib/cli/errors.rb +19 -0
  25. data/lib/cli/frameworks.rb +266 -0
  26. data/lib/cli/manifest_helper.rb +323 -0
  27. data/lib/cli/runner.rb +556 -0
  28. data/lib/cli/services_helper.rb +109 -0
  29. data/lib/cli/tunnel_helper.rb +332 -0
  30. data/lib/cli/usage.rb +124 -0
  31. data/lib/cli/version.rb +7 -0
  32. data/lib/cli/zip_util.rb +77 -0
  33. data/lib/vmc.rb +3 -0
  34. data/lib/vmc/client.rb +562 -0
  35. data/lib/vmc/const.rb +23 -0
  36. data/lib/vmc/micro.rb +56 -0
  37. data/lib/vmc/micro/switcher/base.rb +97 -0
  38. data/lib/vmc/micro/switcher/darwin.rb +19 -0
  39. data/lib/vmc/micro/switcher/dummy.rb +15 -0
  40. data/lib/vmc/micro/switcher/linux.rb +16 -0
  41. data/lib/vmc/micro/switcher/windows.rb +31 -0
  42. data/lib/vmc/micro/vmrun.rb +168 -0
  43. metadata +310 -0
@@ -0,0 +1,109 @@
1
+
2
+ module VMC::Cli
3
+ module ServicesHelper
4
+ def display_system_services(services=nil)
5
+ services ||= client.services_info
6
+
7
+ display "\n============== System Services ==============\n\n"
8
+
9
+ return display "No system services available" if services.empty?
10
+
11
+ displayed_services = []
12
+ services.each do |service_type, value|
13
+ value.each do |vendor, version|
14
+ version.each do |version_str, service|
15
+ plans_str = ""
16
+ plans_str = service[:tiers].keys.join(', ') if service[:tiers]
17
+ default_plan = service[:default_plan] ? service[:default_plan] : ""
18
+ plans_str.sub!(/#{default_plan}/, "#{default_plan}(default)") unless default_plan.empty?
19
+ displayed_services << [ vendor, version_str, plans_str, service[:description] ]
20
+ end
21
+ end
22
+ end
23
+ displayed_services.sort! { |a, b| a.first.to_s <=> b.first.to_s}
24
+
25
+ services_table = table do |t|
26
+ t.headings = 'Service', 'Version', 'Plans', 'Description'
27
+ displayed_services.each { |s| t << s }
28
+ end
29
+ display services_table
30
+ end
31
+
32
+ def display_provisioned_services(services=nil)
33
+ services ||= client.services
34
+ display "\n=========== Provisioned Services ============\n\n"
35
+ display_provisioned_services_table(services)
36
+ end
37
+
38
+ def display_provisioned_services_table(services)
39
+ return unless services && !services.empty?
40
+ services_table = table do |t|
41
+ t.headings = 'Name', 'Service', 'Plan'
42
+ services.each do |service|
43
+ t << [ service[:name], service[:vendor], service[:tier] ]
44
+ end
45
+ end
46
+ display services_table
47
+ end
48
+
49
+ def create_service_banner(service, name, display_name=false, plan=nil)
50
+ sn = " [#{name}]" if display_name
51
+ display "Creating Service#{sn}: ", false
52
+ client.create_service(service, name, plan)
53
+ display 'OK'.green
54
+ end
55
+
56
+ def bind_service_banner(service, appname, check_restart=true)
57
+ display "Binding Service [#{service}]: ", false
58
+ client.bind_service(service, appname)
59
+ display 'OK'.green
60
+ check_app_for_restart(appname) if check_restart
61
+ end
62
+
63
+ def unbind_service_banner(service, appname, check_restart=true)
64
+ display "Unbinding Service [#{service}]: ", false
65
+ client.unbind_service(service, appname)
66
+ display 'OK'.green
67
+ check_app_for_restart(appname) if check_restart
68
+ end
69
+
70
+ def delete_service_banner(service)
71
+ display "Deleting service [#{service}]: ", false
72
+ client.delete_service(service)
73
+ display 'OK'.green
74
+ end
75
+
76
+ def register_service_banner(service, instance, name, options, display_name=false)
77
+ sn = " [#{name}]" if display_name
78
+ display "Register Service#{sn}: ", false
79
+ client.register_service(service, instance, name, options)
80
+ display 'OK'.green
81
+ end
82
+
83
+ def random_service_name(service)
84
+ r = "%04x" % [rand(0x0100000)]
85
+ "#{service.to_s}-#{r}"
86
+ end
87
+
88
+ def check_app_for_restart(appname)
89
+ app = client.app_info(appname)
90
+ cmd = VMC::Cli::Command::Apps.new(@options)
91
+ cmd.restart(appname) if app[:state] == 'STARTED'
92
+ end
93
+
94
+ def service_plans(service, services_info=nil)
95
+ services_info ||= client.services_info
96
+ services_info.values.map { |subset1|
97
+ subset1.select { |service_name|
98
+ service_name == service.to_sym
99
+ }
100
+ .values.map { |subset2|
101
+ subset2.values.map { |service_details|
102
+ service_details[:tiers].keys.map(&:to_s)
103
+ }
104
+ }
105
+ }.flatten
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,332 @@
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_auth
38
+ tunnel_app_info[:env].each do |e|
39
+ name, val = e.split("=", 2)
40
+ return val if name == "CALDECOTT_AUTH"
41
+ end
42
+ nil
43
+ end
44
+
45
+ def tunnel_url
46
+ return @tunnel_url if @tunnel_url
47
+
48
+ tun_url = tunnel_app_info[:uris][0]
49
+
50
+ ["https", "http"].each do |scheme|
51
+ url = "#{scheme}://#{tun_url}"
52
+ begin
53
+ RestClient.get(url)
54
+
55
+ # https failed
56
+ rescue Errno::ECONNREFUSED
57
+
58
+ # we expect a 404 since this request isn't auth'd
59
+ rescue RestClient::ResourceNotFound
60
+ return @tunnel_url = url
61
+ end
62
+ end
63
+
64
+ err "Cannot determine URL for #{tun_url}"
65
+ end
66
+
67
+ def invalidate_tunnel_app_info
68
+ @tunnel_url = nil
69
+ @tunnel_app_info = nil
70
+ end
71
+
72
+ def tunnel_pushed?
73
+ not tunnel_app_info.nil?
74
+ end
75
+
76
+ def tunnel_healthy?(token)
77
+ return false unless tunnel_app_info[:state] == 'STARTED'
78
+
79
+ begin
80
+ response = RestClient.get(
81
+ "#{tunnel_url}/info",
82
+ "Auth-Token" => token
83
+ )
84
+
85
+ info = JSON.parse(response)
86
+ if info["version"] == HELPER_VERSION
87
+ true
88
+ else
89
+ stop_caldecott
90
+ false
91
+ end
92
+ rescue RestClient::Exception
93
+ stop_caldecott
94
+ false
95
+ end
96
+ end
97
+
98
+ def tunnel_bound?(service)
99
+ tunnel_app_info[:services].include?(service)
100
+ end
101
+
102
+ def tunnel_connection_info(type, service, token)
103
+ display "Getting tunnel connection info: ", false
104
+ response = nil
105
+ 10.times do
106
+ begin
107
+ response = RestClient.get(tunnel_url + "/" + VMC::Client.path("services", service), "Auth-Token" => token)
108
+ break
109
+ rescue RestClient::Exception
110
+ sleep 1
111
+ end
112
+
113
+ display ".", false
114
+ end
115
+
116
+ unless response
117
+ err "Expected remote tunnel to know about #{service}, but it doesn't"
118
+ end
119
+
120
+ display "OK".green
121
+
122
+ info = JSON.parse(response)
123
+ case type
124
+ when "rabbitmq"
125
+ uri = Addressable::URI.parse info["url"]
126
+ info["hostname"] = uri.host
127
+ info["port"] = uri.port
128
+ info["vhost"] = uri.path[1..-1]
129
+ info["user"] = uri.user
130
+ info["password"] = uri.password
131
+ info.delete "url"
132
+
133
+ # we use "db" as the "name" for mongo
134
+ # existing "name" is junk
135
+ when "mongodb"
136
+ info["name"] = info["db"]
137
+ info.delete "db"
138
+
139
+ # our "name" is irrelevant for redis
140
+ when "redis"
141
+ info.delete "name"
142
+ end
143
+
144
+ ['hostname', 'port', 'password'].each do |k|
145
+ err "Could not determine #{k} for #{service}" if info[k].nil?
146
+ end
147
+
148
+ info
149
+ end
150
+
151
+ def display_tunnel_connection_info(info)
152
+ display ''
153
+ display "Service connection info: "
154
+
155
+ to_show = [nil, nil, nil] # reserved for user, pass, db name
156
+ info.keys.each do |k|
157
+ case k
158
+ when "host", "hostname", "port", "node_id"
159
+ # skip
160
+ when "user", "username"
161
+ # prefer "username" over "user"
162
+ to_show[0] = k unless to_show[0] == "username"
163
+ when "password"
164
+ to_show[1] = k
165
+ when "name"
166
+ to_show[2] = k
167
+ else
168
+ to_show << k
169
+ end
170
+ end
171
+ to_show.compact!
172
+
173
+ align_len = to_show.collect(&:size).max + 1
174
+
175
+ to_show.each do |k|
176
+ # TODO: modify the server services rest call to have explicit knowledge
177
+ # about the items to return. It should return all of them if
178
+ # the service is unknown so that we don't have to do this weird
179
+ # filtering.
180
+ display " #{k.ljust align_len}: ", false
181
+ display "#{info[k]}".yellow
182
+ end
183
+ display ''
184
+ end
185
+
186
+ def start_tunnel(local_port, conn_info, auth)
187
+ @local_tunnel_thread = Thread.new do
188
+ Caldecott::Client.start({
189
+ :local_port => local_port,
190
+ :tun_url => tunnel_url,
191
+ :dst_host => conn_info['hostname'],
192
+ :dst_port => conn_info['port'],
193
+ :log_file => STDOUT,
194
+ :log_level => ENV["VMC_TUNNEL_DEBUG"] || "ERROR",
195
+ :auth_token => auth,
196
+ :quiet => true
197
+ })
198
+ end
199
+
200
+ at_exit { @local_tunnel_thread.kill }
201
+ end
202
+
203
+
204
+
205
+ def pick_tunnel_port(port)
206
+ original = port
207
+
208
+ PORT_RANGE.times do |n|
209
+ begin
210
+ TCPSocket.open('localhost', port)
211
+ port += 1
212
+ rescue
213
+ return port
214
+ end
215
+ end
216
+
217
+ grab_ephemeral_port
218
+ end
219
+
220
+ def grab_ephemeral_port
221
+ socket = TCPServer.new('0.0.0.0', 0)
222
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
223
+ Socket.do_not_reverse_lookup = true
224
+ port = socket.addr[1]
225
+ socket.close
226
+ return port
227
+ end
228
+
229
+ def wait_for_tunnel_start(port)
230
+ 10.times do |n|
231
+ begin
232
+ client = TCPSocket.open('localhost', port)
233
+ display '' if n > 0
234
+ client.close
235
+ return true
236
+ rescue => e
237
+ display "Waiting for local tunnel to become available", false if n == 0
238
+ display '.', false
239
+ sleep 1
240
+ end
241
+ end
242
+ err "Could not connect to local tunnel."
243
+ end
244
+
245
+ def wait_for_tunnel_end
246
+ display "Open another shell to run command-line clients or"
247
+ display "use a UI tool to connect using the displayed information."
248
+ display "Press Ctrl-C to exit..."
249
+ @local_tunnel_thread.join
250
+ end
251
+
252
+ def resolve_symbols(str, info, local_port)
253
+ str.gsub(/\$\{\s*([^\}]+)\s*\}/) do
254
+ case $1
255
+ when "host"
256
+ # TODO: determine proper host
257
+ "localhost"
258
+ when "port"
259
+ local_port
260
+ when "user", "username"
261
+ info["username"]
262
+ else
263
+ info[$1] || ask($1)
264
+ end
265
+ end
266
+ end
267
+
268
+ def start_local_prog(clients, command, info, port)
269
+ client = clients[File.basename(command)]
270
+
271
+ cmdline = "#{command} "
272
+
273
+ case client
274
+ when Hash
275
+ cmdline << resolve_symbols(client["command"], info, port)
276
+ client["environment"].each do |e|
277
+ if e =~ /([^=]+)=(["']?)([^"']*)\2/
278
+ ENV[$1] = resolve_symbols($3, info, port)
279
+ else
280
+ err "Invalid environment variable: #{e}"
281
+ end
282
+ end
283
+ when String
284
+ cmdline << resolve_symbols(client, info, port)
285
+ else
286
+ err "Unknown client info: #{client.inspect}."
287
+ end
288
+
289
+ display "Launching '#{cmdline}'"
290
+ display ''
291
+
292
+ system(cmdline)
293
+ end
294
+
295
+ def push_caldecott(token)
296
+ client.create_app(
297
+ tunnel_appname,
298
+ { :name => tunnel_appname,
299
+ :staging => {:framework => "sinatra"},
300
+ :uris => ["#{tunnel_uniquename}.#{target_base}"],
301
+ :instances => 1,
302
+ :resources => {:memory => 64},
303
+ :env => ["CALDECOTT_AUTH=#{token}"]
304
+ }
305
+ )
306
+
307
+ apps_cmd.send(:upload_app_bits, tunnel_appname, HELPER_APP)
308
+
309
+ invalidate_tunnel_app_info
310
+ end
311
+
312
+ def stop_caldecott
313
+ apps_cmd.stop(tunnel_appname)
314
+
315
+ invalidate_tunnel_app_info
316
+ end
317
+
318
+ def start_caldecott
319
+ apps_cmd.start(tunnel_appname)
320
+
321
+ invalidate_tunnel_app_info
322
+ end
323
+
324
+ private
325
+
326
+ def apps_cmd
327
+ a = Command::Apps.new(@options)
328
+ a.client client
329
+ a
330
+ end
331
+ end
332
+ end
data/lib/cli/usage.rb ADDED
@@ -0,0 +1,124 @@
1
+ class VMC::Cli::Runner
2
+
3
+ def basic_usage
4
+ "Usage: vmc [options] command [<args>] [command_options]\n" +
5
+ "Try 'vmc help [command]' or 'vmc help options' for more information."
6
+ end
7
+
8
+ def display_usage
9
+ if @usage
10
+ say @usage_error if @usage_error
11
+ say "Usage: #{@usage}"
12
+ return
13
+ elsif @verb_usage
14
+ say @verb_usage
15
+ return
16
+ end
17
+ say command_usage
18
+ end
19
+
20
+ def command_usage
21
+ <<-USAGE
22
+
23
+ #{basic_usage}
24
+
25
+ Currently available vmc commands are:
26
+
27
+ Getting Started
28
+ target [url] Reports current target or sets a new target
29
+ login [email] [--email, --passwd] Login
30
+ info System and account information
31
+
32
+ Applications
33
+ apps List deployed applications
34
+
35
+ Application Creation
36
+ push [appname] Create, push, map, and start a new application
37
+ push [appname] --path Push application from specified path
38
+ push [appname] --url Set the url for the application
39
+ push [appname] --instances <N> Set the expected number <N> of instances
40
+ push [appname] --mem M Set the memory reservation for the application
41
+ push [appname] --runtime RUNTIME Set the runtime to use for the application
42
+ push [appname] --framework Framework Set the framework to use for the application
43
+ push [appname] --debug [MODE] Push application and start in a debug mode
44
+ push [appname] --no-start Do not auto-start the application
45
+
46
+ Application Operations
47
+ start <appname> [--debug [MODE]] Start the application
48
+ stop <appname> Stop the application
49
+ restart <appname> [--debug [MODE]] Restart the application
50
+ delete <appname> Delete the application
51
+
52
+ Application Updates
53
+ update <appname> [--path,--debug [MODE]] Update the application bits
54
+ mem <appname> [memsize] Update the memory reservation for an application
55
+ map <appname> <url> Register the application to the url
56
+ unmap <appname> <url> Unregister the application from the url
57
+ instances <appname> <num|delta> Scale the application instances up or down
58
+
59
+ Application Information
60
+ crashes <appname> List recent application crashes
61
+ crashlogs <appname> Display log information for crashed applications
62
+ logs <appname> [--all] Display log information for the application
63
+ files <appname> [path] [--all] Display directory listing or file download for [path]
64
+ stats <appname> Display resource usage for the application
65
+ instances <appname> List application instances
66
+
67
+ Application Environment
68
+ env <appname> List application environment variables
69
+ env-add <appname> <variable[=]value> Add an environment variable to an application
70
+ env-del <appname> <variable> Delete an environment variable to an application
71
+
72
+ Services
73
+ services Lists of services available and provisioned
74
+ create-service <service> [--name,--bind] Create a provisioned service
75
+ create-service <service> <name> Create a provisioned service and assign it <name>
76
+ create-service <service> <name> <app> Create a provisioned service and assign it <name>, and bind to <app>
77
+ create-service <service> <name> <app> <plan> Create a provisioned service on specified plan and assign it <name>, and bind to <app>
78
+ delete-service [servicename] Delete a provisioned service
79
+ bind-service <servicename> <appname> Bind a service to an application
80
+ unbind-service <servicename> <appname> Unbind service from the application
81
+ clone-services <src-app> <dest-app> Clone service bindings from <src-app> application to <dest-app>
82
+ tunnel <servicename> [--port] Create a local tunnel to a service
83
+ tunnel <servicename> <clientcmd> Create a local tunnel to a service and start a local client
84
+ register-service <external> Register a external service (e.g. Cloudn RDB)
85
+ register-service <external> <type> Register a external service and assign it <type>
86
+ register-service <external> <type> <credential> Register a external service and assign it <type> with <credentials>
87
+
88
+ Administration
89
+ user Display user account information
90
+ passwd Change the password for the current user
91
+ logout Logs current user out of the target system
92
+ add-user [--email, --passwd] Register a new user (requires admin privileges)
93
+ delete-user <user> Delete a user and all apps and services (requires admin privileges)
94
+
95
+ System
96
+ runtimes Display the supported runtimes of the target system
97
+ frameworks Display the recognized frameworks of the target system
98
+
99
+ Micro Cloud Foundry
100
+ micro status Display Micro Cloud Foundry VM status
101
+ micro offline Configure Micro Cloud Foundry VM for offline mode
102
+ micro online Configure Micro Cloud Foundry VM for online mode
103
+ [--vmx file] Path to micro.vmx
104
+ [--vmrun executable] Path to vmrun executable
105
+ [--password cleartext] Cleartext password for guest VM vcap user
106
+ [--save] Save cleartext password in ~/.udn_micro
107
+
108
+ Misc
109
+ aliases List aliases
110
+ alias <alias[=]command> Create an alias for a command
111
+ unalias <alias> Remove an alias
112
+ targets List known targets and associated authorization tokens
113
+
114
+ Help
115
+ help [command] Get general help or help on a specific command
116
+ help options Get help on available options
117
+
118
+ Timeout
119
+ * --timeout timeout Set the timeout seconds for any requests
120
+
121
+ USAGE
122
+
123
+ end
124
+ end