olympe 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/LICENSE +24 -0
  2. data/README.md +103 -0
  3. data/Rakefile +101 -0
  4. data/bin/olympe +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/commands/admin.rb +80 -0
  13. data/lib/cli/commands/apps.rb +1208 -0
  14. data/lib/cli/commands/base.rb +233 -0
  15. data/lib/cli/commands/manifest.rb +56 -0
  16. data/lib/cli/commands/micro.rb +115 -0
  17. data/lib/cli/commands/misc.rb +140 -0
  18. data/lib/cli/commands/services.rb +217 -0
  19. data/lib/cli/commands/user.rb +65 -0
  20. data/lib/cli/config.rb +170 -0
  21. data/lib/cli/console_helper.rb +163 -0
  22. data/lib/cli/core_ext.rb +122 -0
  23. data/lib/cli/errors.rb +19 -0
  24. data/lib/cli/file_helper.rb +123 -0
  25. data/lib/cli/frameworks.rb +265 -0
  26. data/lib/cli/manifest_helper.rb +316 -0
  27. data/lib/cli/runner.rb +568 -0
  28. data/lib/cli/services_helper.rb +104 -0
  29. data/lib/cli/tunnel_helper.rb +336 -0
  30. data/lib/cli/usage.rb +125 -0
  31. data/lib/cli/version.rb +7 -0
  32. data/lib/cli/zip_util.rb +77 -0
  33. data/lib/cli.rb +48 -0
  34. data/lib/vmc/client.rb +558 -0
  35. data/lib/vmc/const.rb +27 -0
  36. data/lib/vmc/micro/switcher/base.rb +97 -0
  37. data/lib/vmc/micro/switcher/darwin.rb +19 -0
  38. data/lib/vmc/micro/switcher/dummy.rb +15 -0
  39. data/lib/vmc/micro/switcher/linux.rb +16 -0
  40. data/lib/vmc/micro/switcher/windows.rb +31 -0
  41. data/lib/vmc/micro/vmrun.rb +158 -0
  42. data/lib/vmc/micro.rb +56 -0
  43. data/lib/vmc.rb +3 -0
  44. metadata +279 -0
@@ -0,0 +1,336 @@
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(infra)
21
+ random_service_name(tunnel_appname(infra))
22
+ end
23
+
24
+ def tunnel_appname(infra)
25
+ infra ? "caldecott-#{infra}" : "caldecott"
26
+ end
27
+
28
+ def tunnel_app_info(infra)
29
+ begin
30
+ client.app_info(tunnel_appname(infra))
31
+ rescue => e
32
+ nil
33
+ end
34
+ end
35
+
36
+ def tunnel_auth(infra)
37
+ tunnel_app_info(infra)[:env].each do |e|
38
+ name, val = e.split("=", 2)
39
+ return val if name == "CALDECOTT_AUTH"
40
+ end
41
+ nil
42
+ end
43
+
44
+ def tunnel_url(infra)
45
+
46
+ tun_url = tunnel_app_info(infra)[:uris][0]
47
+
48
+ ["https", "http"].each do |scheme|
49
+ url = "#{scheme}://#{tun_url}"
50
+ begin
51
+ RestClient.get(url)
52
+
53
+ # https failed
54
+ rescue Errno::ECONNREFUSED
55
+
56
+ # we expect a 404 since this request isn't auth'd
57
+ rescue RestClient::ResourceNotFound
58
+ return url
59
+ end
60
+ end
61
+
62
+ err "Cannot determine URL for #{tun_url}"
63
+ end
64
+
65
+ def invalidate_tunnel_app_info(infra)
66
+ end
67
+
68
+ def tunnel_pushed?(infra)
69
+ not tunnel_app_info(infra).nil?
70
+ end
71
+
72
+ def tunnel_healthy?(token,infra)
73
+ return false unless tunnel_app_info(infra)[:state] == 'STARTED'
74
+
75
+ begin
76
+ response = RestClient.get(
77
+ "#{tunnel_url(infra)}/info",
78
+ "Auth-Token" => token
79
+ )
80
+ info = JSON.parse(response)
81
+ if info["version"] == HELPER_VERSION
82
+ true
83
+ else
84
+ stop_caldecott(infra)
85
+ false
86
+ end
87
+ rescue RestClient::Exception
88
+ stop_caldecott(infra)
89
+ false
90
+ end
91
+ end
92
+
93
+ def tunnel_bound?(service,infra)
94
+ tunnel_app_info(infra)[:services].include?(service)
95
+ end
96
+
97
+ def tunnel_connection_info(type, service, token, infra)
98
+ display "Getting tunnel connection info: ", false
99
+ response = nil
100
+ 10.times do
101
+ begin
102
+ response = RestClient.get(tunnel_url(infra) + "/" + VMC::Client.path("services", service), "Auth-Token" => token)
103
+ break
104
+ rescue RestClient::Exception => e
105
+ puts "Error infra: #{infra}, url: #{tunnel_url(infra)}"
106
+ display tunnel_url(infra)
107
+ puts e.message.red
108
+ sleep 1
109
+ end
110
+
111
+ display ".", false
112
+ end
113
+
114
+ unless response
115
+ err "Expected remote tunnel to know about #{service}, but it doesn't"
116
+ end
117
+
118
+ display "OK".green
119
+
120
+ info = JSON.parse(response)
121
+ info["infra"] = infra
122
+ case type
123
+ when "rabbitmq"
124
+ uri = Addressable::URI.parse info["url"]
125
+ info["hostname"] = uri.host
126
+ info["port"] = uri.port
127
+ info["vhost"] = uri.path[1..-1]
128
+ info["user"] = uri.user
129
+ info["password"] = uri.password
130
+ info.delete "url"
131
+
132
+ # we use "db" as the "name" for mongo
133
+ # existing "name" is junk
134
+ when "mongodb"
135
+ info["name"] = info["db"]
136
+ info.delete "db"
137
+
138
+ # our "name" is irrelevant for redis
139
+ when "redis"
140
+ info.delete "name"
141
+ end
142
+
143
+ ['hostname', 'port', 'password'].each do |k|
144
+ err "Could not determine #{k} for #{service}" if info[k].nil?
145
+ end
146
+
147
+ info
148
+ end
149
+
150
+ def display_tunnel_connection_info(info)
151
+ display ''
152
+ display "Service connection info: "
153
+
154
+ to_show = [nil, nil, nil] # reserved for user, pass, db name
155
+ info.keys.each do |k|
156
+ case k
157
+ when "host", "hostname", "port", "node_id"
158
+ # skip
159
+ when "user", "username"
160
+ # prefer "username" over "user"
161
+ to_show[0] = k unless to_show[0] == "username"
162
+ when "password"
163
+ to_show[1] = k
164
+ when "name"
165
+ to_show[2] = k
166
+ else
167
+ to_show << k
168
+ end
169
+ end
170
+ to_show.compact!
171
+
172
+ align_len = to_show.collect(&:size).max + 1
173
+
174
+ to_show.each do |k|
175
+ # TODO: modify the server services rest call to have explicit knowledge
176
+ # about the items to return. It should return all of them if
177
+ # the service is unknown so that we don't have to do this weird
178
+ # filtering.
179
+ display " #{k.ljust align_len}: ", false
180
+ display "#{info[k]}".yellow
181
+ end
182
+ display ''
183
+ end
184
+
185
+ def start_tunnel(local_port, conn_info, auth, infra)
186
+ @local_tunnel_thread = Thread.new do
187
+ Caldecott::Client.start({
188
+ :local_port => local_port,
189
+ :tun_url => tunnel_url(infra),
190
+ :dst_host => conn_info['hostname'],
191
+ :dst_port => conn_info['port'],
192
+ :log_file => STDOUT,
193
+ :log_level => ENV["VMC_TUNNEL_DEBUG"] || "ERROR",
194
+ :auth_token => auth,
195
+ :quiet => true
196
+ })
197
+ end
198
+
199
+ at_exit { @local_tunnel_thread.kill }
200
+ end
201
+
202
+
203
+
204
+ def pick_tunnel_port(port)
205
+ original = port
206
+
207
+ PORT_RANGE.times do |n|
208
+ begin
209
+ TCPSocket.open('localhost', port)
210
+ port += 1
211
+ rescue
212
+ return port
213
+ end
214
+ end
215
+
216
+ grab_ephemeral_port
217
+ end
218
+
219
+ def grab_ephemeral_port
220
+ socket = TCPServer.new('0.0.0.0', 0)
221
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
222
+ Socket.do_not_reverse_lookup = true
223
+ port = socket.addr[1]
224
+ socket.close
225
+ return port
226
+ end
227
+
228
+ def wait_for_tunnel_start(port)
229
+ 10.times do |n|
230
+ begin
231
+ client = TCPSocket.open('localhost', port)
232
+ display '' if n > 0
233
+ client.close
234
+ return true
235
+ rescue => e
236
+ display "Waiting for local tunnel to become available", false if n == 0
237
+ display '.', false
238
+ sleep 1
239
+ end
240
+ end
241
+ err "Could not connect to local tunnel."
242
+ end
243
+
244
+ def wait_for_tunnel_end
245
+ display "Open another shell to run command-line clients or"
246
+ display "use a UI tool to connect using the displayed information."
247
+ display "Press Ctrl-C to exit..."
248
+ @local_tunnel_thread.join
249
+ end
250
+
251
+ def resolve_symbols(str, info, local_port)
252
+ str.gsub(/\$\{\s*([^\}]+)\s*\}/) do
253
+ case $1
254
+ when "host"
255
+ # TODO: determine proper host
256
+ "localhost"
257
+ when "port"
258
+ local_port
259
+ when "user", "username"
260
+ info["username"]
261
+ else
262
+ info[$1] || ask($1)
263
+ end
264
+ end
265
+ end
266
+
267
+ def start_local_prog(clients, command, info, port)
268
+ client = clients[File.basename(command)]
269
+
270
+ cmdline = "#{command} "
271
+
272
+ case client
273
+ when Hash
274
+ cmdline << resolve_symbols(client["command"], info, port)
275
+ client["environment"].each do |e|
276
+ if e =~ /([^=]+)=(["']?)([^"']*)\2/
277
+ ENV[$1] = resolve_symbols($3, info, port)
278
+ else
279
+ err "Invalid environment variable: #{e}"
280
+ end
281
+ end
282
+ when String
283
+ cmdline << resolve_symbols(client, info, port)
284
+ else
285
+ err "Unknown client info: #{client.inspect}."
286
+ end
287
+
288
+ display "Launching '#{cmdline}'"
289
+ display ''
290
+
291
+ system(cmdline)
292
+ end
293
+
294
+ def push_caldecott(token,infra)
295
+ manifest = {
296
+ :name => tunnel_appname(infra),
297
+ :staging => {:framework => "sinatra", :runtime => "ruby18" },
298
+ :uris => ["#{tunnel_uniquename(infra)}.#{client.base_for_infra(infra)}"],
299
+ :instances => 1,
300
+ :resources => {:memory => 64},
301
+ :env => ["CALDECOTT_AUTH=#{token}"]
302
+ }
303
+ manifest[:infra] = { :provider => infra } if infra
304
+
305
+ client.create_app(
306
+ tunnel_appname(infra),
307
+ manifest
308
+ )
309
+
310
+ apps_cmd.send(:upload_app_bits, tunnel_appname(infra), HELPER_APP, infra)
311
+
312
+ invalidate_tunnel_app_info(infra)
313
+ end
314
+
315
+ def stop_caldecott(infra)
316
+ apps_cmd.stop(tunnel_appname(infra))
317
+
318
+ invalidate_tunnel_app_info(infra)
319
+ end
320
+
321
+ def start_caldecott(infra)
322
+ apps_cmd.start(tunnel_appname(infra))
323
+
324
+ invalidate_tunnel_app_info(infra)
325
+ end
326
+
327
+ private
328
+
329
+ def apps_cmd
330
+ a = Command::Apps.new(@options)
331
+ a.client client
332
+ a
333
+ end
334
+
335
+ end
336
+ end
data/lib/cli/usage.rb ADDED
@@ -0,0 +1,125 @@
1
+ class VMC::Cli::Runner
2
+
3
+ def basic_usage
4
+ "Usage: olympe [options] command [<args>] [command_options]\n" +
5
+ "Try 'olympe help [command]' or 'olympe 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 olympe 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] --infra Push application to specified infrastructure
38
+ push [appname] --path Push application from specified path
39
+ push [appname] --url Set the url for the application
40
+ push [appname] --instances <N> Set the expected number <N> of instances
41
+ push [appname] --mem M Set the memory reservation for the application
42
+ push [appname] --runtime RUNTIME Set the runtime 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
+ clone <src-app> <dest-app> [infra] Clone the application and services
52
+
53
+ Application Updates
54
+ update <appname> [--path,--debug [MODE]] Update the application bits
55
+ mem <appname> [memsize] Update the memory reservation for an application
56
+ map <appname> <url> Register the application to the url
57
+ unmap <appname> <url> Unregister the application from the url
58
+ instances <appname> <num|delta> Scale the application instances up or down
59
+
60
+ Application Information
61
+ crashes <appname> List recent application crashes
62
+ crashlogs <appname> Display log information for crashed applications
63
+ logs <appname> [--all] Display log information for the application
64
+ files <appname> [path] [--all] Display directory listing or file download for [path]
65
+ stats <appname> Display resource usage for the application
66
+ instances <appname> List application instances
67
+
68
+ Application Download
69
+ pull <appname> [path] Downloads last pushed source to <appname> or [path]
70
+ download <appname> [path] Downloads last pushed source to zipfile
71
+
72
+ Application Environment
73
+ env <appname> List application environment variables
74
+ env-add <appname> <variable[=]value> Add an environment variable to an application
75
+ env-del <appname> <variable> Delete an environment variable to an application
76
+
77
+ Services
78
+ services Lists of services available and provisioned
79
+ create-service <service> [--name,--bind] Create a provisioned service
80
+ create-service <service> --infra Create a provisioned service on a specified infrastructure
81
+ create-service <service> <name> Create a provisioned service and assign it <name>
82
+ create-service <service> <name> <app> Create a provisioned service and assign it <name>, and bind to <app>
83
+ delete-service [servicename] Delete a provisioned service
84
+ bind-service <servicename> <appname> Bind a service to an application
85
+ unbind-service <servicename> <appname> Unbind service from the application
86
+ clone-services <src-app> <dest-app> Clone service bindings from <src-app> application to <dest-app>
87
+ export-service <service> Export the data from a service
88
+ import-service <service> <url> Import data into a service
89
+ tunnel <servicename> [--port] Create a local tunnel to a service
90
+ tunnel <servicename> <clientcmd> Create a local tunnel to a service and start a local client
91
+
92
+ Administration
93
+ user Display user account information
94
+ passwd Change the password for the current user
95
+ logout Logs current user out of the target system
96
+ add-user [--email, --passwd] Register a new user (requires admin privileges)
97
+ delete-user <user> Delete a user and all apps and services (requires admin privileges)
98
+
99
+ System
100
+ runtimes Display the supported runtimes of the target system
101
+ frameworks Display the recognized frameworks of the target system
102
+ infras Display the available infrastructures
103
+
104
+ Micro Cloud Foundry
105
+ micro status Display Micro Cloud Foundry VM status
106
+ micro offline Configure Micro Cloud Foundry VM for offline mode
107
+ micro online Configure Micro Cloud Foundry VM for online mode
108
+ [--vmx file] Path to micro.vmx
109
+ [--vmrun executable] Path to vmrun executable
110
+ [--password cleartext] Cleartext password for guest VM vcap user
111
+ [--save] Save cleartext password in ~/.olympe_micro
112
+
113
+ Misc
114
+ aliases List aliases
115
+ alias <alias[=]command> Create an alias for a command
116
+ unalias <alias> Remove an alias
117
+ targets List known targets and associated authorization tokens
118
+
119
+ Help
120
+ help [command] Get general help or help on a specific command
121
+ help options Get help on available options
122
+ USAGE
123
+
124
+ end
125
+ end
@@ -0,0 +1,7 @@
1
+ module VMC
2
+ module Cli
3
+ # This version number is used as the RubyGem release version.
4
+ # The internal VMC version number is VMC::VERSION.
5
+ VERSION = '0.3.18.11'
6
+ end
7
+ end
@@ -0,0 +1,77 @@
1
+
2
+ require 'zip/zipfilesystem'
3
+
4
+ module VMC::Cli
5
+
6
+ class ZipUtil
7
+
8
+ PACK_EXCLUSION_GLOBS = ['..', '.', '*~', '#*#', '*.log']
9
+
10
+ class << self
11
+
12
+ def to_dev_null
13
+ if WINDOWS
14
+ 'nul'
15
+ else
16
+ '/dev/null'
17
+ end
18
+ end
19
+
20
+ def entry_lines(file)
21
+ contents = nil
22
+ unless VMC::Cli::Config.nozip
23
+ contents = `unzip -l #{file} 2> #{to_dev_null}`
24
+ contents = nil if $? != 0
25
+ end
26
+ # Do Ruby version if told to or native version failed
27
+ unless contents
28
+ entries = []
29
+ Zip::ZipFile.foreach(file) { |zentry| entries << zentry }
30
+ contents = entries.join("\n")
31
+ end
32
+ contents
33
+ end
34
+
35
+ def unpack(file, dest)
36
+ unless VMC::Cli::Config.nozip
37
+ FileUtils.mkdir(dest)
38
+ `unzip -q #{file} -d #{dest} 2> #{to_dev_null}`
39
+ return unless $? != 0
40
+ end
41
+ # Do Ruby version if told to or native version failed
42
+ Zip::ZipFile.foreach(file) do |zentry|
43
+ epath = "#{dest}/#{zentry}"
44
+ dirname = File.dirname(epath)
45
+ FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
46
+ zentry.extract(epath) unless File.exists?(epath)
47
+ end
48
+ end
49
+
50
+ def get_files_to_pack(dir)
51
+ Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).select do |f|
52
+ process = true
53
+ PACK_EXCLUSION_GLOBS.each { |e| process = false if File.fnmatch(e, File.basename(f)) }
54
+ process && File.exists?(f)
55
+ end
56
+ end
57
+
58
+ def pack(dir, zipfile)
59
+ unless VMC::Cli::Config.nozip
60
+ excludes = PACK_EXCLUSION_GLOBS.map { |e| "\\#{e}" }
61
+ excludes = excludes.join(' ')
62
+ Dir.chdir(dir) do
63
+ `zip -y -q -r #{zipfile} . -x #{excludes} 2> #{to_dev_null}`
64
+ return unless $? != 0
65
+ end
66
+ end
67
+ # Do Ruby version if told to or native version failed
68
+ Zip::ZipFile::open(zipfile, true) do |zf|
69
+ get_files_to_pack(dir).each do |f|
70
+ zf.add(f.sub("#{dir}/",''), f)
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
data/lib/cli.rb ADDED
@@ -0,0 +1,48 @@
1
+ require "rbconfig"
2
+
3
+ ROOT = File.expand_path(File.dirname(__FILE__))
4
+ WINDOWS = !!(RbConfig::CONFIG['host_os'] =~ /mingw|mswin32|cygwin/)
5
+
6
+ module VMC
7
+ autoload :Client, "#{ROOT}/vmc/client"
8
+ autoload :Micro, "#{ROOT}/vmc/micro"
9
+
10
+ module Micro
11
+ module Switcher
12
+ autoload :Base, "#{ROOT}/vmc/micro/switcher/base"
13
+ autoload :Darwin, "#{ROOT}/vmc/micro/switcher/darwin"
14
+ autoload :Dummy, "#{ROOT}/vmc/micro/switcher/dummy"
15
+ autoload :Linux, "#{ROOT}/vmc/micro/switcher/linux"
16
+ autoload :Windows, "#{ROOT}/vmc/micro/switcher/windows"
17
+ end
18
+ autoload :VMrun, "#{ROOT}/vmc/micro/vmrun"
19
+ end
20
+
21
+ module Cli
22
+ autoload :Config, "#{ROOT}/cli/config"
23
+ autoload :Framework, "#{ROOT}/cli/frameworks"
24
+ autoload :Runner, "#{ROOT}/cli/runner"
25
+ autoload :ZipUtil, "#{ROOT}/cli/zip_util"
26
+ autoload :ServicesHelper, "#{ROOT}/cli/services_helper"
27
+ autoload :TunnelHelper, "#{ROOT}/cli/tunnel_helper"
28
+ autoload :ManifestHelper, "#{ROOT}/cli/manifest_helper"
29
+ autoload :ConsoleHelper, "#{ROOT}/cli/console_helper"
30
+ autoload :FileHelper, "#{ROOT}/cli/file_helper"
31
+
32
+ module Command
33
+ autoload :Base, "#{ROOT}/cli/commands/base"
34
+ autoload :Admin, "#{ROOT}/cli/commands/admin"
35
+ autoload :Apps, "#{ROOT}/cli/commands/apps"
36
+ autoload :Micro, "#{ROOT}/cli/commands/micro"
37
+ autoload :Misc, "#{ROOT}/cli/commands/misc"
38
+ autoload :Services, "#{ROOT}/cli/commands/services"
39
+ autoload :User, "#{ROOT}/cli/commands/user"
40
+ autoload :Manifest, "#{ROOT}/cli/commands/manifest"
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ require "#{ROOT}/cli/version"
47
+ require "#{ROOT}/cli/core_ext"
48
+ require "#{ROOT}/cli/errors"