af 0.3.16.5 → 0.3.18.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/lib/cli.rb +4 -2
- data/lib/cli/commands/apps.rb +35 -17
- data/lib/cli/commands/base.rb +6 -1
- data/lib/cli/commands/services.rb +26 -19
- data/lib/cli/config.rb +2 -1
- data/lib/cli/console_helper.rb +29 -23
- data/lib/cli/frameworks.rb +42 -11
- data/lib/cli/infra_helper.rb +29 -0
- data/lib/cli/manifest_helper.rb +1 -1
- data/lib/cli/runner.rb +6 -2
- data/lib/cli/services_helper.rb +10 -3
- data/lib/cli/tunnel_helper.rb +46 -45
- data/lib/cli/version.rb +1 -1
- data/lib/cli/zip_util.rb +1 -1
- data/lib/vmc/client.rb +7 -3
- data/lib/vmc/const.rb +1 -1
- metadata +35 -25
data/README.md
CHANGED
@@ -4,7 +4,7 @@ The AppFog CLI. This is the command line interface to AppFog.com
|
|
4
4
|
|
5
5
|
af is based on vmc but will have features specific to the AppFog service as well as having the default target set to AppFog's service
|
6
6
|
|
7
|
-
_Copyright 2010-
|
7
|
+
_Copyright 2010-2012, VMware, Inc. Licensed under the
|
8
8
|
MIT license, please see the LICENSE file. All rights reserved._
|
9
9
|
|
10
10
|
Usage: af [options] command [<args>] [command_options]
|
data/lib/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
WINDOWS = !!(RUBY_PLATFORM =~ /mingw|mswin32|cygwin/)
|
1
|
+
require "rbconfig"
|
3
2
|
|
3
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
4
|
+
WINDOWS = !!(RbConfig::CONFIG['host_os'] =~ /mingw|mswin32|cygwin/)
|
4
5
|
|
5
6
|
module VMC
|
6
7
|
autoload :Client, "#{ROOT}/vmc/client"
|
@@ -26,6 +27,7 @@ module VMC
|
|
26
27
|
autoload :TunnelHelper, "#{ROOT}/cli/tunnel_helper"
|
27
28
|
autoload :ManifestHelper, "#{ROOT}/cli/manifest_helper"
|
28
29
|
autoload :ConsoleHelper, "#{ROOT}/cli/console_helper"
|
30
|
+
autoload :InfraHelper, "#{ROOT}/cli/infra_helper"
|
29
31
|
|
30
32
|
module Command
|
31
33
|
autoload :Base, "#{ROOT}/cli/commands/base"
|
data/lib/cli/commands/apps.rb
CHANGED
@@ -22,11 +22,18 @@ module VMC::Cli::Command
|
|
22
22
|
|
23
23
|
display "\n"
|
24
24
|
return display "No Applications" if apps.nil? || apps.empty?
|
25
|
+
|
26
|
+
infra_supported = !apps.detect { |a| a[:infra] }.nil?
|
25
27
|
|
26
28
|
apps_table = table do |t|
|
27
29
|
t.headings = 'Application', '# ', 'Health', 'URLS', 'Services'
|
30
|
+
t.headings << 'In' if infra_supported
|
28
31
|
apps.each do |app|
|
29
|
-
|
32
|
+
a = [app[:name], app[:instances], health(app), app[:uris].join(', '), app[:services].join(', ')]
|
33
|
+
if infra_supported
|
34
|
+
a << ( app[:infra] ? app[:infra][:provider] : " " )
|
35
|
+
end
|
36
|
+
t << a
|
30
37
|
end
|
31
38
|
end
|
32
39
|
display apps_table
|
@@ -48,6 +55,10 @@ module VMC::Cli::Command
|
|
48
55
|
end
|
49
56
|
|
50
57
|
def console(appname, interactive=true)
|
58
|
+
|
59
|
+
app = client.app_info(appname)
|
60
|
+
infra_name = app[:infra] ? app[:infra][:name] : 'aws' # FIXME
|
61
|
+
|
51
62
|
unless defined? Caldecott
|
52
63
|
display "To use `vmc rails-console', you must first install Caldecott:"
|
53
64
|
display ""
|
@@ -68,26 +79,27 @@ module VMC::Cli::Command
|
|
68
79
|
|
69
80
|
raise VMC::Client::AuthError unless client.logged_in?
|
70
81
|
|
71
|
-
if not tunnel_pushed?
|
72
|
-
display "Deploying tunnel application '#{tunnel_appname}'."
|
82
|
+
if not tunnel_pushed?(infra_name)
|
83
|
+
display "Deploying tunnel application '#{tunnel_appname(infra_name)}'."
|
73
84
|
auth = UUIDTools::UUID.random_create.to_s
|
74
|
-
push_caldecott(auth)
|
75
|
-
start_caldecott
|
85
|
+
push_caldecott(auth,infra_name)
|
86
|
+
start_caldecott(infra_name)
|
76
87
|
else
|
77
|
-
auth = tunnel_auth
|
88
|
+
auth = tunnel_auth(infra_name)
|
78
89
|
end
|
79
90
|
|
80
|
-
|
81
|
-
|
91
|
+
|
92
|
+
if not tunnel_healthy?(auth,infra_name)
|
93
|
+
display "Redeploying tunnel application '#{tunnel_appname(infra_name)}'."
|
82
94
|
# We don't expect caldecott not to be running, so take the
|
83
95
|
# most aggressive restart method.. delete/re-push
|
84
|
-
client.delete_app(tunnel_appname)
|
85
|
-
invalidate_tunnel_app_info
|
86
|
-
push_caldecott(auth)
|
87
|
-
start_caldecott
|
96
|
+
client.delete_app(tunnel_appname(infra_name))
|
97
|
+
invalidate_tunnel_app_info(infra_name)
|
98
|
+
push_caldecott(auth,infra_name)
|
99
|
+
start_caldecott(infra_name)
|
88
100
|
end
|
89
101
|
|
90
|
-
start_tunnel(port, conn_info, auth)
|
102
|
+
start_tunnel(port, conn_info, auth, infra_name)
|
91
103
|
wait_for_tunnel_start(port)
|
92
104
|
start_local_console(port, appname) if interactive
|
93
105
|
port
|
@@ -894,6 +906,7 @@ module VMC::Cli::Command
|
|
894
906
|
end
|
895
907
|
|
896
908
|
def do_push(appname=nil)
|
909
|
+
|
897
910
|
unless @app_info || no_prompt
|
898
911
|
@manifest = { "applications" => { @path => { "name" => appname } } }
|
899
912
|
|
@@ -920,6 +933,11 @@ module VMC::Cli::Command
|
|
920
933
|
memswitch = normalize_mem(memswitch) if memswitch
|
921
934
|
command = info(:command)
|
922
935
|
runtime = info(:runtime)
|
936
|
+
infra = info(:infra)
|
937
|
+
|
938
|
+
if infra
|
939
|
+
err "Infra '#{infra}' is not valid" unless VMC::Cli::InfraHelper.valid?(infra)
|
940
|
+
end
|
923
941
|
|
924
942
|
# Check app existing upfront if we have appname
|
925
943
|
app_checked = false
|
@@ -968,7 +986,6 @@ module VMC::Cli::Command
|
|
968
986
|
default_url = "None"
|
969
987
|
default_url = "#{appname}.#{VMC::Cli::Config.suggest_url}" if framework.require_url?
|
970
988
|
|
971
|
-
|
972
989
|
unless no_prompt || url || !framework.require_url?
|
973
990
|
url = ask(
|
974
991
|
"Application Deployed URL",
|
@@ -1015,18 +1032,19 @@ module VMC::Cli::Command
|
|
1015
1032
|
}
|
1016
1033
|
}
|
1017
1034
|
manifest[:staging][:command] = command if command
|
1018
|
-
|
1035
|
+
manifest[:infra] = { :provider => infra } if infra
|
1036
|
+
|
1019
1037
|
# Send the manifest to the cloud controller
|
1020
1038
|
client.create_app(appname, manifest)
|
1021
1039
|
display 'OK'.green
|
1022
1040
|
|
1023
|
-
|
1041
|
+
|
1024
1042
|
existing = Set.new(client.services.collect { |s| s[:name] })
|
1025
1043
|
|
1026
1044
|
if @app_info && services = @app_info["services"]
|
1027
1045
|
services.each do |name, info|
|
1028
1046
|
unless existing.include? name
|
1029
|
-
create_service_banner(info["type"], name, true)
|
1047
|
+
create_service_banner(info["type"], name, true, infra)
|
1030
1048
|
end
|
1031
1049
|
|
1032
1050
|
bind_service_banner(name, appname)
|
data/lib/cli/commands/base.rb
CHANGED
@@ -27,7 +27,7 @@ module VMC::Cli
|
|
27
27
|
|
28
28
|
load_manifest manifest_file if manifest_file
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def manifest_file
|
32
32
|
return @options[:manifest] if @options[:manifest]
|
33
33
|
return @manifest_file if @manifest_file
|
@@ -221,6 +221,11 @@ module VMC::Cli
|
|
221
221
|
end
|
222
222
|
@frameworks
|
223
223
|
end
|
224
|
+
|
225
|
+
def default_infra
|
226
|
+
"aws"
|
227
|
+
end
|
228
|
+
|
224
229
|
end
|
225
230
|
end
|
226
231
|
end
|
@@ -38,7 +38,7 @@ module VMC::Cli::Command
|
|
38
38
|
name = random_service_name(service)
|
39
39
|
picked_name = true
|
40
40
|
end
|
41
|
-
create_service_banner(service, name, picked_name)
|
41
|
+
create_service_banner(service, name, picked_name, @options[:infra])
|
42
42
|
appname = @options[:bind] unless appname
|
43
43
|
bind_service_banner(name, appname) if appname
|
44
44
|
end
|
@@ -118,37 +118,44 @@ module VMC::Cli::Command
|
|
118
118
|
|
119
119
|
raise VMC::Client::AuthError unless client.logged_in?
|
120
120
|
|
121
|
-
|
122
|
-
|
121
|
+
infra_name = info[:infra] ? info[:infra][:name] : default_infra
|
122
|
+
|
123
|
+
if infra_name
|
124
|
+
err "Infra '#{infra_name}' is not valid" unless VMC::Cli::InfraHelper.valid?(infra_name)
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
if not tunnel_pushed?(infra_name)
|
129
|
+
display "Deploying tunnel application '#{tunnel_appname(infra_name)}'."
|
123
130
|
auth = UUIDTools::UUID.random_create.to_s
|
124
|
-
push_caldecott(auth)
|
125
|
-
bind_service_banner(service, tunnel_appname, false)
|
126
|
-
start_caldecott
|
131
|
+
push_caldecott(auth,infra_name)
|
132
|
+
bind_service_banner(service, tunnel_appname(infra_name), false)
|
133
|
+
start_caldecott(infra_name)
|
127
134
|
else
|
128
|
-
auth = tunnel_auth
|
135
|
+
auth = tunnel_auth(infra_name)
|
129
136
|
end
|
130
137
|
|
131
|
-
if not tunnel_healthy?(auth)
|
132
|
-
display "Redeploying tunnel application '#{tunnel_appname}'."
|
138
|
+
if not tunnel_healthy?(auth,infra_name)
|
139
|
+
display "Redeploying tunnel application '#{tunnel_appname(infra_name)}'."
|
133
140
|
|
134
141
|
# We don't expect caldecott not to be running, so take the
|
135
142
|
# most aggressive restart method.. delete/re-push
|
136
|
-
client.delete_app(tunnel_appname)
|
137
|
-
invalidate_tunnel_app_info
|
143
|
+
client.delete_app(tunnel_appname(infra_name))
|
144
|
+
invalidate_tunnel_app_info(infra_name)
|
138
145
|
|
139
|
-
push_caldecott(auth)
|
140
|
-
bind_service_banner(service, tunnel_appname, false)
|
141
|
-
start_caldecott
|
146
|
+
push_caldecott(auth,infra_name)
|
147
|
+
bind_service_banner(service, tunnel_appname(infra_name), false)
|
148
|
+
start_caldecott(infra_name)
|
142
149
|
end
|
143
150
|
|
144
|
-
if not tunnel_bound?(service)
|
145
|
-
bind_service_banner(service, tunnel_appname)
|
151
|
+
if not tunnel_bound?(service,infra_name)
|
152
|
+
bind_service_banner(service, tunnel_appname(infra_name))
|
146
153
|
end
|
147
154
|
|
148
|
-
conn_info = tunnel_connection_info info[:vendor], service, auth
|
155
|
+
conn_info = tunnel_connection_info info[:vendor], service, auth, infra_name
|
149
156
|
display_tunnel_connection_info(conn_info)
|
150
157
|
display "Starting tunnel to #{service.bold} on port #{port.to_s.bold}."
|
151
|
-
start_tunnel(port, conn_info, auth)
|
158
|
+
start_tunnel(port, conn_info, auth, infra_name)
|
152
159
|
|
153
160
|
clients = get_clients_for(info[:vendor])
|
154
161
|
|
@@ -167,7 +174,7 @@ module VMC::Cli::Command
|
|
167
174
|
else
|
168
175
|
wait_for_tunnel_start(port)
|
169
176
|
unless start_local_prog(clients, client_name, conn_info, port)
|
170
|
-
err "'#{client_name}'
|
177
|
+
err "'#{client_name}' execution failed; is it in your $PATH?"
|
171
178
|
end
|
172
179
|
end
|
173
180
|
end
|
data/lib/cli/config.rb
CHANGED
@@ -23,6 +23,7 @@ module VMC::Cli
|
|
23
23
|
attr_accessor :output
|
24
24
|
attr_accessor :trace
|
25
25
|
attr_accessor :nozip
|
26
|
+
attr_accessor :infra
|
26
27
|
|
27
28
|
def target_url
|
28
29
|
return @target_url if @target_url
|
@@ -42,7 +43,7 @@ module VMC::Cli
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def suggest_url
|
45
|
-
@suggest_url ||=
|
46
|
+
@suggest_url ||= VMC::Cli::InfraHelper.base_for_infra(@infra)
|
46
47
|
end
|
47
48
|
|
48
49
|
def store_target(target_host)
|
data/lib/cli/console_helper.rb
CHANGED
@@ -27,7 +27,10 @@ module VMC::Cli
|
|
27
27
|
"Please redeploy your app to enable support."
|
28
28
|
end
|
29
29
|
end
|
30
|
-
conn_info = {
|
30
|
+
conn_info = {
|
31
|
+
'hostname' => entry[:console_ip],
|
32
|
+
'port' => entry[:console_port]
|
33
|
+
}
|
31
34
|
end
|
32
35
|
|
33
36
|
def start_local_console(port, appname)
|
@@ -50,13 +53,14 @@ module VMC::Cli
|
|
50
53
|
5.times do
|
51
54
|
begin
|
52
55
|
results = @telnet_client.login("Name"=>auth_info["username"],
|
53
|
-
"Password"=>auth_info["password"])
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
"Password"=>auth_info["password"])
|
57
|
+
lines = results.sub("Login: Password: ", "").split("\n")
|
58
|
+
last_line = lines.pop
|
59
|
+
if last_line =~ /[$%#>] \z/n
|
60
|
+
prompt = last_line
|
61
|
+
elsif last_line =~ /Login failed/
|
62
|
+
err_msg = last_line
|
63
|
+
end
|
60
64
|
break
|
61
65
|
rescue TimeoutError
|
62
66
|
sleep 1
|
@@ -104,29 +108,31 @@ module VMC::Cli
|
|
104
108
|
end
|
105
109
|
|
106
110
|
def readline_with_history(prompt)
|
107
|
-
line = Readline
|
108
|
-
return ''
|
109
|
-
|
110
|
-
if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
|
111
|
-
Readline::HISTORY.pop
|
112
|
-
end
|
111
|
+
line = Readline::readline(prompt)
|
112
|
+
return nil if line == nil || line == 'quit' || line == 'exit'
|
113
|
+
Readline::HISTORY.push(line) if not line =~ /^\s*$/ and Readline::HISTORY.to_a[-1] != line
|
113
114
|
line
|
114
115
|
end
|
115
116
|
|
116
117
|
def run_console(prompt)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
118
|
+
prev = trap("INT") { |x| exit_console; prev.call(x); exit }
|
119
|
+
prev = trap("TERM") { |x| exit_console; prev.call(x); exit }
|
120
|
+
loop do
|
121
|
+
cmd = readline_with_history(prompt)
|
122
|
+
if(cmd == nil)
|
123
|
+
exit_console
|
122
124
|
break
|
123
125
|
end
|
124
|
-
|
125
|
-
prompt = send_console_command_display_results(cmd, prompt)
|
126
|
-
end
|
126
|
+
prompt = send_console_command_display_results(cmd, prompt)
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
+
def exit_console
|
131
|
+
#TimeoutError expected, as exit doesn't return anything
|
132
|
+
@telnet_client.cmd("String"=>"exit","Timeout"=>1) rescue TimeoutError
|
133
|
+
close_console
|
134
|
+
end
|
135
|
+
|
130
136
|
def send_console_command_display_results(cmd, prompt)
|
131
137
|
begin
|
132
138
|
lines = send_console_command cmd
|
@@ -154,4 +160,4 @@ module VMC::Cli
|
|
154
160
|
}
|
155
161
|
end
|
156
162
|
end
|
157
|
-
end
|
163
|
+
end
|
data/lib/cli/frameworks.rb
CHANGED
@@ -18,13 +18,19 @@ module VMC::Cli
|
|
18
18
|
'Erlang/OTP Rebar' => ['otp_rebar', { :mem => '64M', :description => 'Erlang/OTP Rebar Application'}],
|
19
19
|
'WSGI' => ['wsgi', { :mem => '64M', :description => 'Python WSGI Application'}],
|
20
20
|
'Django' => ['django', { :mem => '128M', :description => 'Python Django Application'}],
|
21
|
-
'
|
21
|
+
'dotNet' => ['dotNet', { :mem => '128M', :description => '.Net Web Application'}],
|
22
|
+
'Rack' => ['rack', { :mem => '128M', :description => 'Rack Application'}],
|
23
|
+
'Play' => ['play', { :mem => '256M', :description => 'Play Framework Application'}]
|
22
24
|
}
|
23
25
|
|
24
26
|
class << self
|
25
27
|
|
26
|
-
def known_frameworks
|
27
|
-
|
28
|
+
def known_frameworks(available_frameworks)
|
29
|
+
frameworks = []
|
30
|
+
FRAMEWORKS.each do |key,fw|
|
31
|
+
frameworks << key if available_frameworks.include? [fw[0]]
|
32
|
+
end
|
33
|
+
frameworks
|
28
34
|
end
|
29
35
|
|
30
36
|
def lookup(name)
|
@@ -49,6 +55,8 @@ module VMC::Cli
|
|
49
55
|
if !File.directory? path
|
50
56
|
if path.end_with?('.war')
|
51
57
|
return detect_framework_from_war path
|
58
|
+
elsif path.end_with?('.zip')
|
59
|
+
return detect_framework_from_zip path, available_frameworks
|
52
60
|
elsif available_frameworks.include?(["standalone"])
|
53
61
|
return Framework.lookup('Standalone')
|
54
62
|
else
|
@@ -78,7 +86,7 @@ module VMC::Cli
|
|
78
86
|
next if matched_file
|
79
87
|
File.open(fname, 'r') do |f|
|
80
88
|
str = f.read # This might want to be limited
|
81
|
-
matched_file = fname if (str && str.match(/^\s*require
|
89
|
+
matched_file = fname if (str && str.match(/^\s*\#?\s*require\s*\(?\s*['"]sinatra['"]/))
|
82
90
|
end
|
83
91
|
end
|
84
92
|
if matched_file
|
@@ -87,11 +95,7 @@ module VMC::Cli
|
|
87
95
|
f.exec = "ruby #{matched_file}"
|
88
96
|
return f
|
89
97
|
end
|
90
|
-
|
91
|
-
elsif !Dir.glob('*.js').empty?
|
92
|
-
if File.exist?('server.js') || File.exist?('app.js') || File.exist?('index.js') || File.exist?('main.js')
|
93
|
-
return Framework.lookup('Node')
|
94
|
-
end
|
98
|
+
|
95
99
|
# PHP
|
96
100
|
elsif !Dir.glob('*.php').empty?
|
97
101
|
return Framework.lookup('PHP')
|
@@ -108,6 +112,21 @@ module VMC::Cli
|
|
108
112
|
# Python
|
109
113
|
elsif !Dir.glob('wsgi.py').empty?
|
110
114
|
return Framework.lookup('WSGI')
|
115
|
+
|
116
|
+
# .Net
|
117
|
+
elsif !Dir.glob('web.config').empty?
|
118
|
+
return Framework.lookup('dotNet')
|
119
|
+
|
120
|
+
# Node.js
|
121
|
+
elsif !Dir.glob('*.js').empty?
|
122
|
+
if File.exist?('server.js') || File.exist?('app.js') || File.exist?('index.js') || File.exist?('main.js')
|
123
|
+
return Framework.lookup('Node')
|
124
|
+
end
|
125
|
+
|
126
|
+
# Play or Standalone Apps
|
127
|
+
elsif Dir.glob('*.zip').first
|
128
|
+
zip_file = Dir.glob('*.zip').first
|
129
|
+
return detect_framework_from_zip zip_file, available_frameworks
|
111
130
|
end
|
112
131
|
|
113
132
|
# Default to Standalone if no other match was made
|
@@ -115,7 +134,6 @@ module VMC::Cli
|
|
115
134
|
end
|
116
135
|
end
|
117
136
|
|
118
|
-
private
|
119
137
|
def detect_framework_from_war(war_file=nil)
|
120
138
|
if war_file
|
121
139
|
contents = ZipUtil.entry_lines(war_file)
|
@@ -139,6 +157,19 @@ module VMC::Cli
|
|
139
157
|
return Framework.lookup('JavaWeb')
|
140
158
|
end
|
141
159
|
end
|
160
|
+
|
161
|
+
def detect_framework_from_zip(zip_file, available_frameworks)
|
162
|
+
contents = ZipUtil.entry_lines(zip_file)
|
163
|
+
detect_framework_from_zip_contents(contents, available_frameworks)
|
164
|
+
end
|
165
|
+
|
166
|
+
def detect_framework_from_zip_contents(contents, available_frameworks)
|
167
|
+
if available_frameworks.include?(["play"]) && contents =~ /lib\/play\..*\.jar/
|
168
|
+
return Framework.lookup('Play')
|
169
|
+
elsif available_frameworks.include?(["standalone"])
|
170
|
+
return Framework.lookup('Standalone')
|
171
|
+
end
|
172
|
+
end
|
142
173
|
end
|
143
174
|
|
144
175
|
attr_reader :name, :description, :console
|
@@ -218,7 +249,7 @@ module VMC::Cli
|
|
218
249
|
def memory(runtime=nil)
|
219
250
|
default_mem = @memory
|
220
251
|
default_mem = '128M' if runtime =~ /\Aruby/ || runtime == "php"
|
221
|
-
default_mem = '512M' if runtime == "java"
|
252
|
+
default_mem = '512M' if runtime == "java" || runtime == "java7"
|
222
253
|
default_mem
|
223
254
|
end
|
224
255
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module VMC::Cli
|
4
|
+
module InfraHelper
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def base_for_infra(infra)
|
9
|
+
infras.has_key?(infra) ? infras[infra][:base] : "aws.af.cm"
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(infra)
|
13
|
+
infra && infras.has_key?(infra)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def infras
|
18
|
+
{
|
19
|
+
"ap-aws" => { :base => "ap01.aws.af.cm" },
|
20
|
+
"eu-aws" => { :base => "eu01.aws.af.cm" },
|
21
|
+
"rs" => { :base => "rs.af.cm" },
|
22
|
+
"aws" => { :base => "aws.af.cm" }
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/cli/manifest_helper.rb
CHANGED
@@ -197,7 +197,7 @@ module VMC::Cli::ManifestHelper
|
|
197
197
|
"Select Application Type",
|
198
198
|
:indexed => true,
|
199
199
|
:default => framework,
|
200
|
-
:choices => VMC::Cli::Framework.known_frameworks
|
200
|
+
:choices => VMC::Cli::Framework.known_frameworks(frameworks_info)
|
201
201
|
)
|
202
202
|
)
|
203
203
|
display "Selected #{framework}"
|
data/lib/cli/runner.rb
CHANGED
@@ -98,6 +98,9 @@ class VMC::Cli::Runner
|
|
98
98
|
|
99
99
|
# Proxying for another user, requires admin privileges
|
100
100
|
opts.on('-u PROXY') { |proxy| @options[:proxy] = proxy }
|
101
|
+
|
102
|
+
# Select infrastructure
|
103
|
+
opts.on('--infra INFRA') { |infra| @options[:infra] = infra }
|
101
104
|
|
102
105
|
opts.on_tail('--options') { puts "#{opts}\n"; exit }
|
103
106
|
end
|
@@ -301,7 +304,7 @@ class VMC::Cli::Runner
|
|
301
304
|
set_cmd(:apps, :crashlogs, 1)
|
302
305
|
|
303
306
|
when 'push'
|
304
|
-
usage('af push [appname] [--path PATH] [--url URL] [--instances N] [--mem] [--runtime RUNTIME] [--no-start]')
|
307
|
+
usage('af push [appname] [--path PATH] [--url URL] [--instances N] [--mem] [--runtime RUNTIME] [--no-start] [--infra infraname]')
|
305
308
|
if @args.size == 1
|
306
309
|
set_cmd(:apps, :push, 1)
|
307
310
|
else
|
@@ -333,7 +336,7 @@ class VMC::Cli::Runner
|
|
333
336
|
set_cmd(:apps, :environment_del, 2)
|
334
337
|
|
335
338
|
when 'create-service', 'create_service'
|
336
|
-
usage('af create-service [service] [servicename] [appname] [--name servicename] [--bind appname]')
|
339
|
+
usage('af create-service [service] [servicename] [appname] [--name servicename] [--bind appname] [--infra infraname]')
|
337
340
|
set_cmd(:services, :create_service) if @args.size == 0
|
338
341
|
set_cmd(:services, :create_service, 1) if @args.size == 1
|
339
342
|
set_cmd(:services, :create_service, 2) if @args.size == 2
|
@@ -456,6 +459,7 @@ class VMC::Cli::Runner
|
|
456
459
|
VMC::Cli::Config.nozip = @options.delete(:nozip)
|
457
460
|
VMC::Cli::Config.trace = @options.delete(:trace)
|
458
461
|
VMC::Cli::Config.output ||= STDOUT unless @options[:quiet]
|
462
|
+
VMC::Cli::Config.infra = @options[:infra]
|
459
463
|
|
460
464
|
process_aliases!
|
461
465
|
parse_command!
|
data/lib/cli/services_helper.rb
CHANGED
@@ -33,19 +33,26 @@ module VMC::Cli
|
|
33
33
|
|
34
34
|
def display_provisioned_services_table(services)
|
35
35
|
return unless services && !services.empty?
|
36
|
+
|
37
|
+
infra_supported = !services.detect { |a| a[:infra] }.nil?
|
36
38
|
services_table = table do |t|
|
37
39
|
t.headings = 'Name', 'Service'
|
40
|
+
t.headings << 'In' if infra_supported
|
38
41
|
services.each do |service|
|
39
|
-
|
42
|
+
s = [ service[:name], service[:vendor] ]
|
43
|
+
if infra_supported
|
44
|
+
s << ( service[:infra] ? service[:infra][:provider] : " " )
|
45
|
+
end
|
46
|
+
t << s
|
40
47
|
end
|
41
48
|
end
|
42
49
|
display services_table
|
43
50
|
end
|
44
51
|
|
45
|
-
def create_service_banner(service, name, display_name=false)
|
52
|
+
def create_service_banner(service, name, display_name=false, infra=nil)
|
46
53
|
sn = " [#{name}]" if display_name
|
47
54
|
display "Creating Service#{sn}: ", false
|
48
|
-
client.create_service(service, name)
|
55
|
+
client.create_service(infra,service, name)
|
49
56
|
display 'OK'.green
|
50
57
|
end
|
51
58
|
|
data/lib/cli/tunnel_helper.rb
CHANGED
@@ -17,35 +17,33 @@ module VMC::Cli
|
|
17
17
|
# this is to keep the helper in sync with any updates here
|
18
18
|
HELPER_VERSION = '0.0.4'
|
19
19
|
|
20
|
-
def tunnel_uniquename
|
21
|
-
random_service_name(tunnel_appname)
|
20
|
+
def tunnel_uniquename(infra)
|
21
|
+
random_service_name(tunnel_appname(infra))
|
22
22
|
end
|
23
23
|
|
24
|
-
def tunnel_appname
|
25
|
-
"caldecott"
|
24
|
+
def tunnel_appname(infra)
|
25
|
+
infra ? "caldecott-#{infra}" : "caldecott"
|
26
26
|
end
|
27
27
|
|
28
|
-
def tunnel_app_info
|
29
|
-
return @tun_app_info if @tunnel_app_info
|
28
|
+
def tunnel_app_info(infra)
|
30
29
|
begin
|
31
|
-
|
30
|
+
client.app_info(tunnel_appname(infra))
|
32
31
|
rescue => e
|
33
|
-
|
32
|
+
nil
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
def tunnel_auth
|
38
|
-
tunnel_app_info[:env].each do |e|
|
36
|
+
def tunnel_auth(infra)
|
37
|
+
tunnel_app_info(infra)[:env].each do |e|
|
39
38
|
name, val = e.split("=", 2)
|
40
39
|
return val if name == "CALDECOTT_AUTH"
|
41
40
|
end
|
42
41
|
nil
|
43
42
|
end
|
44
43
|
|
45
|
-
def tunnel_url
|
46
|
-
return @tunnel_url if @tunnel_url
|
44
|
+
def tunnel_url(infra)
|
47
45
|
|
48
|
-
tun_url = tunnel_app_info[:uris][0]
|
46
|
+
tun_url = tunnel_app_info(infra)[:uris][0]
|
49
47
|
|
50
48
|
["https", "http"].each do |scheme|
|
51
49
|
url = "#{scheme}://#{tun_url}"
|
@@ -57,54 +55,51 @@ module VMC::Cli
|
|
57
55
|
|
58
56
|
# we expect a 404 since this request isn't auth'd
|
59
57
|
rescue RestClient::ResourceNotFound
|
60
|
-
return
|
58
|
+
return url
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
62
|
err "Cannot determine URL for #{tun_url}"
|
65
63
|
end
|
66
64
|
|
67
|
-
def invalidate_tunnel_app_info
|
68
|
-
@tunnel_url = nil
|
69
|
-
@tunnel_app_info = nil
|
65
|
+
def invalidate_tunnel_app_info(infra)
|
70
66
|
end
|
71
67
|
|
72
|
-
def tunnel_pushed?
|
73
|
-
not tunnel_app_info.nil?
|
68
|
+
def tunnel_pushed?(infra)
|
69
|
+
not tunnel_app_info(infra).nil?
|
74
70
|
end
|
75
71
|
|
76
|
-
def tunnel_healthy?(token)
|
77
|
-
return false unless tunnel_app_info[:state] == 'STARTED'
|
72
|
+
def tunnel_healthy?(token,infra)
|
73
|
+
return false unless tunnel_app_info(infra)[:state] == 'STARTED'
|
78
74
|
|
79
75
|
begin
|
80
76
|
response = RestClient.get(
|
81
|
-
"#{tunnel_url}/info",
|
77
|
+
"#{tunnel_url(infra)}/info",
|
82
78
|
"Auth-Token" => token
|
83
79
|
)
|
84
|
-
|
85
80
|
info = JSON.parse(response)
|
86
81
|
if info["version"] == HELPER_VERSION
|
87
82
|
true
|
88
83
|
else
|
89
|
-
stop_caldecott
|
84
|
+
stop_caldecott(infra)
|
90
85
|
false
|
91
86
|
end
|
92
87
|
rescue RestClient::Exception
|
93
|
-
stop_caldecott
|
88
|
+
stop_caldecott(infra)
|
94
89
|
false
|
95
90
|
end
|
96
91
|
end
|
97
92
|
|
98
|
-
def tunnel_bound?(service)
|
99
|
-
tunnel_app_info[:services].include?(service)
|
93
|
+
def tunnel_bound?(service,infra)
|
94
|
+
tunnel_app_info(infra)[:services].include?(service)
|
100
95
|
end
|
101
96
|
|
102
|
-
def tunnel_connection_info(type, service, token)
|
97
|
+
def tunnel_connection_info(type, service, token, infra)
|
103
98
|
display "Getting tunnel connection info: ", false
|
104
99
|
response = nil
|
105
100
|
10.times do
|
106
101
|
begin
|
107
|
-
response = RestClient.get(tunnel_url + "/" + VMC::Client.path("services", service), "Auth-Token" => token)
|
102
|
+
response = RestClient.get(tunnel_url(infra) + "/" + VMC::Client.path("services", service), "Auth-Token" => token)
|
108
103
|
break
|
109
104
|
rescue RestClient::Exception
|
110
105
|
sleep 1
|
@@ -120,6 +115,7 @@ module VMC::Cli
|
|
120
115
|
display "OK".green
|
121
116
|
|
122
117
|
info = JSON.parse(response)
|
118
|
+
info["infra"] = infra
|
123
119
|
case type
|
124
120
|
when "rabbitmq"
|
125
121
|
uri = Addressable::URI.parse info["url"]
|
@@ -183,11 +179,11 @@ module VMC::Cli
|
|
183
179
|
display ''
|
184
180
|
end
|
185
181
|
|
186
|
-
def start_tunnel(local_port, conn_info, auth)
|
182
|
+
def start_tunnel(local_port, conn_info, auth, infra)
|
187
183
|
@local_tunnel_thread = Thread.new do
|
188
184
|
Caldecott::Client.start({
|
189
185
|
:local_port => local_port,
|
190
|
-
:tun_url => tunnel_url,
|
186
|
+
:tun_url => tunnel_url(infra),
|
191
187
|
:dst_host => conn_info['hostname'],
|
192
188
|
:dst_port => conn_info['port'],
|
193
189
|
:log_file => STDOUT,
|
@@ -292,33 +288,37 @@ module VMC::Cli
|
|
292
288
|
system(cmdline)
|
293
289
|
end
|
294
290
|
|
295
|
-
def push_caldecott(token)
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
:
|
300
|
-
:uris => ["#{tunnel_uniquename}.#{target_base}"],
|
291
|
+
def push_caldecott(token,infra)
|
292
|
+
manifest = {
|
293
|
+
:name => tunnel_appname(infra),
|
294
|
+
:staging => {:framework => "sinatra", :runtime => "ruby18" },
|
295
|
+
:uris => ["#{tunnel_uniquename(infra)}.#{VMC::Cli::InfraHelper.base_for_infra(infra)}"],
|
301
296
|
:instances => 1,
|
302
297
|
:resources => {:memory => 64},
|
303
298
|
:env => ["CALDECOTT_AUTH=#{token}"]
|
304
299
|
}
|
300
|
+
manifest[:infra] = { :provider => infra } if infra
|
301
|
+
|
302
|
+
client.create_app(
|
303
|
+
tunnel_appname(infra),
|
304
|
+
manifest
|
305
305
|
)
|
306
306
|
|
307
|
-
apps_cmd.send(:upload_app_bits, tunnel_appname, HELPER_APP)
|
307
|
+
apps_cmd.send(:upload_app_bits, tunnel_appname(infra), HELPER_APP)
|
308
308
|
|
309
|
-
invalidate_tunnel_app_info
|
309
|
+
invalidate_tunnel_app_info(infra)
|
310
310
|
end
|
311
311
|
|
312
|
-
def stop_caldecott
|
313
|
-
apps_cmd.stop(tunnel_appname)
|
312
|
+
def stop_caldecott(infra)
|
313
|
+
apps_cmd.stop(tunnel_appname(infra))
|
314
314
|
|
315
|
-
invalidate_tunnel_app_info
|
315
|
+
invalidate_tunnel_app_info(infra)
|
316
316
|
end
|
317
317
|
|
318
|
-
def start_caldecott
|
319
|
-
apps_cmd.start(tunnel_appname)
|
318
|
+
def start_caldecott(infra)
|
319
|
+
apps_cmd.start(tunnel_appname(infra))
|
320
320
|
|
321
|
-
invalidate_tunnel_app_info
|
321
|
+
invalidate_tunnel_app_info(infra)
|
322
322
|
end
|
323
323
|
|
324
324
|
private
|
@@ -328,5 +328,6 @@ module VMC::Cli
|
|
328
328
|
a.client client
|
329
329
|
a
|
330
330
|
end
|
331
|
+
|
331
332
|
end
|
332
333
|
end
|
data/lib/cli/version.rb
CHANGED
data/lib/cli/zip_util.rb
CHANGED
data/lib/vmc/client.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# client = VMC::Client.new('api.vcap.me')
|
7
7
|
# client.login(:user, :pass)
|
8
8
|
# client.create('myapplication', manifest)
|
9
|
-
# client.create_service('redis', 'my_redis_service', opts);
|
9
|
+
# client.create_service('aws', 'redis', 'my_redis_service', opts);
|
10
10
|
#
|
11
11
|
|
12
12
|
require 'rubygems'
|
@@ -27,6 +27,9 @@ class VMC::Client
|
|
27
27
|
# Error codes
|
28
28
|
VMC_HTTP_ERROR_CODES = [ 400, 500 ]
|
29
29
|
|
30
|
+
HTTP_TIMEOUT = ENV['TIMEOUT'].to_i if ENV['TIMEOUT']
|
31
|
+
HTTP_TIMEOUT ||= 10*60
|
32
|
+
|
30
33
|
# Errors
|
31
34
|
class BadTarget < RuntimeError; end
|
32
35
|
class AuthError < RuntimeError; end
|
@@ -167,7 +170,7 @@ class VMC::Client
|
|
167
170
|
json_get(VMC::SERVICES_PATH)
|
168
171
|
end
|
169
172
|
|
170
|
-
def create_service(service, name)
|
173
|
+
def create_service(infra,service, name)
|
171
174
|
check_login_status
|
172
175
|
services = services_info
|
173
176
|
services ||= []
|
@@ -184,6 +187,7 @@ class VMC::Client
|
|
184
187
|
:type => service_descr[:type], :tier => 'free',
|
185
188
|
:vendor => service, :version => version_str
|
186
189
|
}
|
190
|
+
service_hash[:infra] = { :provider => infra } if infra
|
187
191
|
break
|
188
192
|
end
|
189
193
|
end
|
@@ -382,7 +386,7 @@ class VMC::Client
|
|
382
386
|
req = {
|
383
387
|
:method => method, :url => "#{@target}/#{path}",
|
384
388
|
:payload => payload, :headers => headers, :multipart => true,
|
385
|
-
:timeout =>
|
389
|
+
:timeout => HTTP_TIMEOUT, :open_timeout => HTTP_TIMEOUT
|
386
390
|
}
|
387
391
|
status, body, response_headers = perform_http_request(req)
|
388
392
|
|
data/lib/vmc/const.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: af
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.18.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
-
default_executable:
|
12
|
+
date: 2012-08-07 00:00:00.000000000Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: json_pure
|
17
|
-
requirement: &
|
16
|
+
requirement: &70266170534240 !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ! '>='
|
@@ -25,10 +24,10 @@ dependencies:
|
|
25
24
|
version: 1.7.0
|
26
25
|
type: :runtime
|
27
26
|
prerelease: false
|
28
|
-
version_requirements: *
|
27
|
+
version_requirements: *70266170534240
|
29
28
|
- !ruby/object:Gem::Dependency
|
30
29
|
name: rubyzip
|
31
|
-
requirement: &
|
30
|
+
requirement: &70266170533480 !ruby/object:Gem::Requirement
|
32
31
|
none: false
|
33
32
|
requirements:
|
34
33
|
- - ~>
|
@@ -36,10 +35,10 @@ dependencies:
|
|
36
35
|
version: 0.9.4
|
37
36
|
type: :runtime
|
38
37
|
prerelease: false
|
39
|
-
version_requirements: *
|
38
|
+
version_requirements: *70266170533480
|
40
39
|
- !ruby/object:Gem::Dependency
|
41
40
|
name: rest-client
|
42
|
-
requirement: &
|
41
|
+
requirement: &70266170533000 !ruby/object:Gem::Requirement
|
43
42
|
none: false
|
44
43
|
requirements:
|
45
44
|
- - ! '>='
|
@@ -50,10 +49,10 @@ dependencies:
|
|
50
49
|
version: 1.7.0
|
51
50
|
type: :runtime
|
52
51
|
prerelease: false
|
53
|
-
version_requirements: *
|
52
|
+
version_requirements: *70266170533000
|
54
53
|
- !ruby/object:Gem::Dependency
|
55
54
|
name: terminal-table
|
56
|
-
requirement: &
|
55
|
+
requirement: &70266170532280 !ruby/object:Gem::Requirement
|
57
56
|
none: false
|
58
57
|
requirements:
|
59
58
|
- - ~>
|
@@ -61,10 +60,10 @@ dependencies:
|
|
61
60
|
version: 1.4.2
|
62
61
|
type: :runtime
|
63
62
|
prerelease: false
|
64
|
-
version_requirements: *
|
63
|
+
version_requirements: *70266170532280
|
65
64
|
- !ruby/object:Gem::Dependency
|
66
65
|
name: interact
|
67
|
-
requirement: &
|
66
|
+
requirement: &70266170531820 !ruby/object:Gem::Requirement
|
68
67
|
none: false
|
69
68
|
requirements:
|
70
69
|
- - ~>
|
@@ -72,10 +71,10 @@ dependencies:
|
|
72
71
|
version: 0.4.0
|
73
72
|
type: :runtime
|
74
73
|
prerelease: false
|
75
|
-
version_requirements: *
|
74
|
+
version_requirements: *70266170531820
|
76
75
|
- !ruby/object:Gem::Dependency
|
77
76
|
name: addressable
|
78
|
-
requirement: &
|
77
|
+
requirement: &70266170531360 !ruby/object:Gem::Requirement
|
79
78
|
none: false
|
80
79
|
requirements:
|
81
80
|
- - ~>
|
@@ -83,10 +82,10 @@ dependencies:
|
|
83
82
|
version: 2.2.6
|
84
83
|
type: :runtime
|
85
84
|
prerelease: false
|
86
|
-
version_requirements: *
|
85
|
+
version_requirements: *70266170531360
|
87
86
|
- !ruby/object:Gem::Dependency
|
88
87
|
name: uuidtools
|
89
|
-
requirement: &
|
88
|
+
requirement: &70266170530900 !ruby/object:Gem::Requirement
|
90
89
|
none: false
|
91
90
|
requirements:
|
92
91
|
- - ~>
|
@@ -94,10 +93,21 @@ dependencies:
|
|
94
93
|
version: 2.1.0
|
95
94
|
type: :runtime
|
96
95
|
prerelease: false
|
97
|
-
version_requirements: *
|
96
|
+
version_requirements: *70266170530900
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rb-readline
|
99
|
+
requirement: &70266170530440 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 0.4.2
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: *70266170530440
|
98
108
|
- !ruby/object:Gem::Dependency
|
99
109
|
name: rake
|
100
|
-
requirement: &
|
110
|
+
requirement: &70266170550520 !ruby/object:Gem::Requirement
|
101
111
|
none: false
|
102
112
|
requirements:
|
103
113
|
- - ! '>='
|
@@ -105,10 +115,10 @@ dependencies:
|
|
105
115
|
version: '0'
|
106
116
|
type: :development
|
107
117
|
prerelease: false
|
108
|
-
version_requirements: *
|
118
|
+
version_requirements: *70266170550520
|
109
119
|
- !ruby/object:Gem::Dependency
|
110
120
|
name: rspec
|
111
|
-
requirement: &
|
121
|
+
requirement: &70266170549980 !ruby/object:Gem::Requirement
|
112
122
|
none: false
|
113
123
|
requirements:
|
114
124
|
- - ~>
|
@@ -116,10 +126,10 @@ dependencies:
|
|
116
126
|
version: 1.3.0
|
117
127
|
type: :development
|
118
128
|
prerelease: false
|
119
|
-
version_requirements: *
|
129
|
+
version_requirements: *70266170549980
|
120
130
|
- !ruby/object:Gem::Dependency
|
121
131
|
name: webmock
|
122
|
-
requirement: &
|
132
|
+
requirement: &70266170549480 !ruby/object:Gem::Requirement
|
123
133
|
none: false
|
124
134
|
requirements:
|
125
135
|
- - ~>
|
@@ -127,7 +137,7 @@ dependencies:
|
|
127
137
|
version: 1.5.0
|
128
138
|
type: :development
|
129
139
|
prerelease: false
|
130
|
-
version_requirements: *
|
140
|
+
version_requirements: *70266170549480
|
131
141
|
description: AppFog.com CLI
|
132
142
|
email: support@appfog.com
|
133
143
|
executables:
|
@@ -157,6 +167,7 @@ files:
|
|
157
167
|
- lib/cli/core_ext.rb
|
158
168
|
- lib/cli/errors.rb
|
159
169
|
- lib/cli/frameworks.rb
|
170
|
+
- lib/cli/infra_helper.rb
|
160
171
|
- lib/cli/manifest_helper.rb
|
161
172
|
- lib/cli/runner.rb
|
162
173
|
- lib/cli/services_helper.rb
|
@@ -179,7 +190,6 @@ files:
|
|
179
190
|
- caldecott_helper/Gemfile.lock
|
180
191
|
- caldecott_helper/server.rb
|
181
192
|
- bin/af
|
182
|
-
has_rdoc: true
|
183
193
|
homepage: http://appfog.com
|
184
194
|
licenses: []
|
185
195
|
post_install_message:
|
@@ -200,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
210
|
version: '0'
|
201
211
|
requirements: []
|
202
212
|
rubyforge_project:
|
203
|
-
rubygems_version: 1.6
|
213
|
+
rubygems_version: 1.8.6
|
204
214
|
signing_key:
|
205
215
|
specification_version: 3
|
206
216
|
summary: AppFog.com CLI
|