vmc 0.3.16.beta.2 → 0.3.16.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +0 -1
- data/lib/cli.rb +1 -0
- data/lib/cli/commands/apps.rb +79 -33
- data/lib/cli/commands/base.rb +4 -7
- data/lib/cli/commands/services.rb +2 -1
- data/lib/cli/config.rb +4 -9
- data/lib/cli/console_helper.rb +157 -0
- data/lib/cli/frameworks.rb +9 -2
- data/lib/cli/manifest_helper.rb +32 -8
- data/lib/cli/runner.rb +5 -4
- data/lib/cli/tunnel_helper.rb +17 -9
- data/lib/cli/usage.rb +0 -1
- data/lib/cli/version.rb +1 -1
- data/lib/vmc/client.rb +3 -3
- metadata +4 -3
data/README.md
CHANGED
@@ -31,7 +31,6 @@ MIT license, please see the LICENSE file. All rights reserved._
|
|
31
31
|
stop <appname> Stop the application
|
32
32
|
restart <appname> Restart the application
|
33
33
|
delete <appname> Delete the application
|
34
|
-
rename <appname> <newname> Rename the application
|
35
34
|
|
36
35
|
Application Updates
|
37
36
|
update <appname> [--path] Update the application bits
|
data/lib/cli.rb
CHANGED
@@ -13,6 +13,7 @@ module VMC
|
|
13
13
|
autoload :ServicesHelper, "#{ROOT}/cli/services_helper"
|
14
14
|
autoload :TunnelHelper, "#{ROOT}/cli/tunnel_helper"
|
15
15
|
autoload :ManifestHelper, "#{ROOT}/cli/manifest_helper"
|
16
|
+
autoload :ConsoleHelper, "#{ROOT}/cli/console_helper"
|
16
17
|
|
17
18
|
module Command
|
18
19
|
autoload :Base, "#{ROOT}/cli/commands/base"
|
data/lib/cli/commands/apps.rb
CHANGED
@@ -4,12 +4,16 @@ require 'pathname'
|
|
4
4
|
require 'tempfile'
|
5
5
|
require 'tmpdir'
|
6
6
|
require 'set'
|
7
|
+
require "uuidtools"
|
8
|
+
require 'socket'
|
7
9
|
|
8
10
|
module VMC::Cli::Command
|
9
11
|
|
10
12
|
class Apps < Base
|
11
13
|
include VMC::Cli::ServicesHelper
|
12
14
|
include VMC::Cli::ManifestHelper
|
15
|
+
include VMC::Cli::TunnelHelper
|
16
|
+
include VMC::Cli::ConsoleHelper
|
13
17
|
|
14
18
|
def list
|
15
19
|
apps = client.apps
|
@@ -43,6 +47,52 @@ module VMC::Cli::Command
|
|
43
47
|
@options[what] || (@app_info && @app_info[what.to_s]) || default
|
44
48
|
end
|
45
49
|
|
50
|
+
def console(appname, interactive=true)
|
51
|
+
unless defined? Caldecott
|
52
|
+
display "To use `vmc rails-console', you must first install Caldecott:"
|
53
|
+
display ""
|
54
|
+
display "\tgem install caldecott"
|
55
|
+
display ""
|
56
|
+
display "Note that you'll need a C compiler. If you're on OS X, Xcode"
|
57
|
+
display "will provide one. If you're on Windows, try DevKit."
|
58
|
+
display ""
|
59
|
+
display "This manual step will be removed in the future."
|
60
|
+
display ""
|
61
|
+
err "Caldecott is not installed."
|
62
|
+
end
|
63
|
+
|
64
|
+
#Make sure there is a console we can connect to first
|
65
|
+
conn_info = console_connection_info appname
|
66
|
+
|
67
|
+
port = pick_tunnel_port(@options[:port] || 20000)
|
68
|
+
|
69
|
+
raise VMC::Client::AuthError unless client.logged_in?
|
70
|
+
|
71
|
+
if not tunnel_pushed?
|
72
|
+
display "Deploying tunnel application '#{tunnel_appname}'."
|
73
|
+
auth = UUIDTools::UUID.random_create.to_s
|
74
|
+
push_caldecott(auth)
|
75
|
+
start_caldecott
|
76
|
+
else
|
77
|
+
auth = tunnel_auth
|
78
|
+
end
|
79
|
+
|
80
|
+
if not tunnel_healthy?(auth)
|
81
|
+
display "Redeploying tunnel application '#{tunnel_appname}'."
|
82
|
+
# We don't expect caldecott not to be running, so take the
|
83
|
+
# 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
|
88
|
+
end
|
89
|
+
|
90
|
+
start_tunnel(port, conn_info, auth)
|
91
|
+
wait_for_tunnel_start(port)
|
92
|
+
start_local_console(port, appname) if interactive
|
93
|
+
port
|
94
|
+
end
|
95
|
+
|
46
96
|
def start(appname=nil, push=false)
|
47
97
|
if appname
|
48
98
|
do_start(appname, push)
|
@@ -73,14 +123,6 @@ module VMC::Cli::Command
|
|
73
123
|
start(appname)
|
74
124
|
end
|
75
125
|
|
76
|
-
def rename(appname, newname)
|
77
|
-
app = client.app_info(appname)
|
78
|
-
app[:name] = newname
|
79
|
-
display 'Renaming Appliction: '
|
80
|
-
client.update_app(newname, app)
|
81
|
-
display 'OK'.green
|
82
|
-
end
|
83
|
-
|
84
126
|
def mem(appname, memsize=nil)
|
85
127
|
app = client.app_info(appname)
|
86
128
|
mem = current_mem = mem_quota_to_choice(app[:resources][:memory])
|
@@ -136,7 +178,7 @@ module VMC::Cli::Command
|
|
136
178
|
def delete(appname=nil)
|
137
179
|
force = @options[:force]
|
138
180
|
if @options[:all]
|
139
|
-
if no_prompt || force || ask("Delete ALL applications
|
181
|
+
if no_prompt || force || ask("Delete ALL applications?", :default => false)
|
140
182
|
apps = client.apps
|
141
183
|
apps.each { |app| delete_app(app[:name], force) }
|
142
184
|
end
|
@@ -151,7 +193,7 @@ module VMC::Cli::Command
|
|
151
193
|
instance = @options[:instance] || '0'
|
152
194
|
content = client.app_files(appname, path, instance)
|
153
195
|
display content
|
154
|
-
rescue VMC::Client::
|
196
|
+
rescue VMC::Client::TargetError
|
155
197
|
err 'No such file or directory'
|
156
198
|
end
|
157
199
|
|
@@ -651,7 +693,7 @@ module VMC::Cli::Command
|
|
651
693
|
begin
|
652
694
|
content = client.app_files(appname, path, instance)
|
653
695
|
display_logfile(path, content, instance)
|
654
|
-
rescue VMC::Client::
|
696
|
+
rescue VMC::Client::TargetError
|
655
697
|
end
|
656
698
|
end
|
657
699
|
end
|
@@ -665,13 +707,14 @@ module VMC::Cli::Command
|
|
665
707
|
instance = map[instance] if map[instance]
|
666
708
|
|
667
709
|
%w{
|
668
|
-
/logs/err.log /logs/staging.log /
|
669
|
-
/app/logs/
|
710
|
+
/logs/err.log /logs/staging.log /logs/migration.log
|
711
|
+
/app/logs/stderr.log /app/logs/stdout.log /app/logs/startup.log
|
712
|
+
/app/logs/migration.log
|
670
713
|
}.each do |path|
|
671
714
|
begin
|
672
715
|
content = client.app_files(appname, path, instance)
|
673
716
|
display_logfile(path, content, instance)
|
674
|
-
rescue VMC::Client::
|
717
|
+
rescue VMC::Client::TargetError
|
675
718
|
end
|
676
719
|
end
|
677
720
|
end
|
@@ -689,6 +732,8 @@ module VMC::Cli::Command
|
|
689
732
|
display tail.join("\n") if new_lines > 0
|
690
733
|
end
|
691
734
|
since + new_lines
|
735
|
+
rescue VMC::Client::TargetError
|
736
|
+
0
|
692
737
|
end
|
693
738
|
|
694
739
|
def provisioned_services_apps_hash
|
@@ -744,10 +789,11 @@ module VMC::Cli::Command
|
|
744
789
|
|
745
790
|
def do_start(appname, push=false)
|
746
791
|
app = client.app_info(appname)
|
747
|
-
|
748
792
|
return display "Application '#{appname}' could not be found".red if app.nil?
|
749
793
|
return display "Application '#{appname}' already started".yellow if app[:state] == 'STARTED'
|
750
794
|
|
795
|
+
|
796
|
+
|
751
797
|
if @options[:debug]
|
752
798
|
runtimes = client.runtimes_info
|
753
799
|
return display "Cannot get runtime information." unless runtimes
|
@@ -784,6 +830,7 @@ module VMC::Cli::Command
|
|
784
830
|
|
785
831
|
app[:state] = 'STARTED'
|
786
832
|
app[:debug] = @options[:debug]
|
833
|
+
app[:console] = VMC::Cli::Framework.lookup_by_framework(app[:staging][:model]).console
|
787
834
|
client.update_app(appname, app)
|
788
835
|
|
789
836
|
Thread.kill(t)
|
@@ -800,24 +847,23 @@ module VMC::Cli::Command
|
|
800
847
|
loop do
|
801
848
|
display '.', false unless count > TICKER_TICKS
|
802
849
|
sleep SLEEP_TIME
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
failed = true
|
814
|
-
break
|
815
|
-
elsif count > TAIL_TICKS
|
816
|
-
log_lines_displayed = grab_startup_tail(appname, log_lines_displayed)
|
850
|
+
|
851
|
+
break if app_started_properly(appname, count > HEALTH_TICKS)
|
852
|
+
|
853
|
+
if !crashes(appname, false, start_time).empty?
|
854
|
+
# Check for the existance of crashes
|
855
|
+
display "\nError: Application [#{appname}] failed to start, logs information below.\n".red
|
856
|
+
grab_crash_logs(appname, '0', true)
|
857
|
+
if push and !no_prompt
|
858
|
+
display "\n"
|
859
|
+
delete_app(appname, false) if ask "Delete the application?", :default => true
|
817
860
|
end
|
818
|
-
|
819
|
-
|
861
|
+
failed = true
|
862
|
+
break
|
863
|
+
elsif count > TAIL_TICKS
|
864
|
+
log_lines_displayed = grab_startup_tail(appname, log_lines_displayed)
|
820
865
|
end
|
866
|
+
|
821
867
|
count += 1
|
822
868
|
if count > GIVEUP_TICKS # 2 minutes
|
823
869
|
display "\nApplication is taking too long to start, check your logs".yellow
|
@@ -889,7 +935,7 @@ module VMC::Cli::Command
|
|
889
935
|
err "Application '#{appname}' already exists, use update or delete."
|
890
936
|
end
|
891
937
|
|
892
|
-
default_url = "#{appname}.#{
|
938
|
+
default_url = "#{appname}.#{target_base}"
|
893
939
|
|
894
940
|
unless no_prompt || url
|
895
941
|
url = ask(
|
@@ -1018,7 +1064,7 @@ module VMC::Cli::Command
|
|
1018
1064
|
entry[:index],
|
1019
1065
|
"====> [#{entry[:index]}: #{path}] <====\n".bold
|
1020
1066
|
)
|
1021
|
-
rescue VMC::Client::
|
1067
|
+
rescue VMC::Client::TargetError
|
1022
1068
|
end
|
1023
1069
|
end
|
1024
1070
|
end
|
data/lib/cli/commands/base.rb
CHANGED
@@ -8,7 +8,6 @@ module VMC::Cli
|
|
8
8
|
|
9
9
|
class Base
|
10
10
|
include Interactive
|
11
|
-
disable_rewind
|
12
11
|
|
13
12
|
attr_reader :no_prompt, :prompt_ok
|
14
13
|
|
@@ -173,15 +172,13 @@ module VMC::Cli
|
|
173
172
|
end
|
174
173
|
|
175
174
|
def target_url(ctx = [])
|
176
|
-
find_symbol("target", ctx) ||
|
175
|
+
find_symbol("target", ctx) ||
|
176
|
+
(@client && @client.target) ||
|
177
|
+
VMC::Cli::Config.target_url
|
177
178
|
end
|
178
179
|
|
179
180
|
def target_base(ctx = [])
|
180
|
-
|
181
|
-
VMC::Cli::Config.base_of(tgt)
|
182
|
-
else
|
183
|
-
VMC::Cli::Config.suggest_url
|
184
|
-
end
|
181
|
+
VMC::Cli::Config.base_of(find_symbol("target", ctx) || target_url)
|
185
182
|
end
|
186
183
|
|
187
184
|
# Inject a client to help in testing.
|
@@ -147,7 +147,8 @@ module VMC::Cli::Command
|
|
147
147
|
|
148
148
|
conn_info = tunnel_connection_info info[:vendor], service, auth
|
149
149
|
display_tunnel_connection_info(conn_info)
|
150
|
-
|
150
|
+
display "Starting tunnel to #{service.bold} on port #{port.to_s.bold}."
|
151
|
+
start_tunnel(port, conn_info, auth)
|
151
152
|
|
152
153
|
clients = get_clients_for(info[:vendor])
|
153
154
|
|
data/lib/cli/config.rb
CHANGED
@@ -8,7 +8,6 @@ module VMC::Cli
|
|
8
8
|
class Config
|
9
9
|
|
10
10
|
DEFAULT_TARGET = 'api.vcap.me'
|
11
|
-
DEFAULT_SUGGEST = 'vcap.me'
|
12
11
|
|
13
12
|
TARGET_FILE = '~/.vmc_target'
|
14
13
|
TOKEN_FILE = '~/.vmc_token'
|
@@ -42,12 +41,7 @@ module VMC::Cli
|
|
42
41
|
end
|
43
42
|
|
44
43
|
def suggest_url
|
45
|
-
|
46
|
-
ha = target_url.split('.')
|
47
|
-
ha.shift
|
48
|
-
@suggest_url = ha.join('.')
|
49
|
-
@suggest_url = DEFAULT_SUGGEST if @suggest_url.empty?
|
50
|
-
@suggest_url
|
44
|
+
@suggest_url ||= base_of(target_url)
|
51
45
|
end
|
52
46
|
|
53
47
|
def store_target(target_host)
|
@@ -124,8 +118,9 @@ module VMC::Cli
|
|
124
118
|
return @clients if @clients
|
125
119
|
|
126
120
|
stock = YAML.load_file(STOCK_CLIENTS)
|
127
|
-
|
128
|
-
|
121
|
+
clients = File.expand_path CLIENTS_FILE
|
122
|
+
if File.exists? clients
|
123
|
+
user = YAML.load_file(clients)
|
129
124
|
@clients = deep_merge(stock, user)
|
130
125
|
else
|
131
126
|
@clients = stock
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'net/telnet'
|
2
|
+
require 'readline'
|
3
|
+
|
4
|
+
module VMC::Cli
|
5
|
+
module ConsoleHelper
|
6
|
+
|
7
|
+
def console_connection_info(appname)
|
8
|
+
app = client.app_info(appname)
|
9
|
+
fw = VMC::Cli::Framework.lookup_by_framework(app[:staging][:model])
|
10
|
+
if !fw.console
|
11
|
+
err "'#{appname}' is a #{fw.name} application. " +
|
12
|
+
"Console access is not supported for #{fw.name} applications."
|
13
|
+
end
|
14
|
+
instances_info_envelope = client.app_instances(appname)
|
15
|
+
instances_info_envelope = {} if instances_info_envelope.is_a?(Array)
|
16
|
+
|
17
|
+
instances_info = instances_info_envelope[:instances] || []
|
18
|
+
err "No running instances for [#{appname}]" if instances_info.empty?
|
19
|
+
|
20
|
+
entry = instances_info[0]
|
21
|
+
if !entry[:console_port]
|
22
|
+
begin
|
23
|
+
client.app_files(appname, '/app/cf-rails-console')
|
24
|
+
err "Console port not provided for [#{appname}]. Try restarting the app."
|
25
|
+
rescue VMC::Client::TargetError, VMC::Client::NotFound
|
26
|
+
err "Console access not supported for [#{appname}]. " +
|
27
|
+
"Please redeploy your app to enable support."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
conn_info = {'hostname' => entry[:console_ip], 'port' => entry[:console_port]}
|
31
|
+
end
|
32
|
+
|
33
|
+
def start_local_console(port, appname)
|
34
|
+
auth_info = console_credentials(appname)
|
35
|
+
display "Connecting to '#{appname}' console: ", false
|
36
|
+
prompt = console_login(auth_info, port)
|
37
|
+
display "OK".green
|
38
|
+
display "\n"
|
39
|
+
initialize_readline
|
40
|
+
run_console prompt
|
41
|
+
end
|
42
|
+
|
43
|
+
def console_login(auth_info, port)
|
44
|
+
if !auth_info["username"] || !auth_info["password"]
|
45
|
+
err "Unable to verify console credentials."
|
46
|
+
end
|
47
|
+
@telnet_client = telnet_client(port)
|
48
|
+
prompt = nil
|
49
|
+
err_msg = "Login attempt timed out."
|
50
|
+
5.times do
|
51
|
+
begin
|
52
|
+
results = @telnet_client.login("Name"=>auth_info["username"],
|
53
|
+
"Password"=>auth_info["password"]) {|line|
|
54
|
+
if line =~ /[$%#>] \z/n
|
55
|
+
prompt = line
|
56
|
+
elsif line =~ /Login failed/
|
57
|
+
err_msg = line
|
58
|
+
end
|
59
|
+
}
|
60
|
+
break
|
61
|
+
rescue TimeoutError
|
62
|
+
sleep 1
|
63
|
+
rescue EOFError
|
64
|
+
#This may happen if we login right after app starts
|
65
|
+
close_console
|
66
|
+
sleep 5
|
67
|
+
@telnet_client = telnet_client(port)
|
68
|
+
end
|
69
|
+
display ".", false
|
70
|
+
end
|
71
|
+
unless prompt
|
72
|
+
close_console
|
73
|
+
err err_msg
|
74
|
+
end
|
75
|
+
prompt
|
76
|
+
end
|
77
|
+
|
78
|
+
def send_console_command(cmd)
|
79
|
+
results = @telnet_client.cmd(cmd)
|
80
|
+
results.split("\n")
|
81
|
+
end
|
82
|
+
|
83
|
+
def console_credentials(appname)
|
84
|
+
content = client.app_files(appname, '/app/cf-rails-console/.consoleaccess', '0')
|
85
|
+
YAML.load(content)
|
86
|
+
end
|
87
|
+
|
88
|
+
def close_console
|
89
|
+
@telnet_client.close
|
90
|
+
end
|
91
|
+
|
92
|
+
def console_tab_completion_data(cmd)
|
93
|
+
begin
|
94
|
+
results = @telnet_client.cmd("String"=> cmd + "\t", "Match"=>/\S*\n$/, "Timeout"=>10)
|
95
|
+
results.chomp.split(",")
|
96
|
+
rescue TimeoutError
|
97
|
+
[] #Just return empty results if timeout occurred on tab completion
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
def telnet_client(port)
|
103
|
+
Net::Telnet.new({"Port"=>port, "Prompt"=>/[$%#>] \z|Login failed/n, "Timeout"=>30, "FailEOF"=>true})
|
104
|
+
end
|
105
|
+
|
106
|
+
def readline_with_history(prompt)
|
107
|
+
line = Readline.readline(prompt, true)
|
108
|
+
return '' if line.nil?
|
109
|
+
#Don't keep blank or repeat commands in history
|
110
|
+
if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
|
111
|
+
Readline::HISTORY.pop
|
112
|
+
end
|
113
|
+
line
|
114
|
+
end
|
115
|
+
|
116
|
+
def run_console(prompt)
|
117
|
+
while(cmd = readline_with_history(prompt))
|
118
|
+
if(cmd == "exit" || cmd == "quit")
|
119
|
+
#TimeoutError expected, as exit doesn't return anything
|
120
|
+
@telnet_client.cmd("String"=>cmd,"Timeout"=>1) rescue TimeoutError
|
121
|
+
close_console
|
122
|
+
break
|
123
|
+
end
|
124
|
+
if !cmd.empty?
|
125
|
+
prompt = send_console_command_display_results(cmd, prompt)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def send_console_command_display_results(cmd, prompt)
|
131
|
+
begin
|
132
|
+
lines = send_console_command cmd
|
133
|
+
#Assumes the last line is a prompt
|
134
|
+
prompt = lines.pop
|
135
|
+
lines.each {|line| display line if line != cmd}
|
136
|
+
rescue TimeoutError
|
137
|
+
display "Timed out sending command to server.".red
|
138
|
+
rescue EOFError
|
139
|
+
err "The console connection has been terminated. Perhaps the app was stopped or deleted?"
|
140
|
+
end
|
141
|
+
prompt
|
142
|
+
end
|
143
|
+
|
144
|
+
def initialize_readline
|
145
|
+
if Readline.respond_to?("basic_word_break_characters=")
|
146
|
+
Readline.basic_word_break_characters= " \t\n`><=;|&{("
|
147
|
+
end
|
148
|
+
Readline.completion_append_character = nil
|
149
|
+
#Assumes that sending a String ending with tab will return a non-empty
|
150
|
+
#String of comma-separated completion options, terminated by a new line
|
151
|
+
#For example, "app.\t" might result in "to_s,nil?,etc\n"
|
152
|
+
Readline.completion_proc = proc {|s|
|
153
|
+
console_tab_completion_data s
|
154
|
+
}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/lib/cli/frameworks.rb
CHANGED
@@ -6,7 +6,7 @@ module VMC::Cli
|
|
6
6
|
DEFAULT_MEM = '256M'
|
7
7
|
|
8
8
|
FRAMEWORKS = {
|
9
|
-
'Rails' => ['rails3', { :mem => '256M', :description => 'Rails Application'}],
|
9
|
+
'Rails' => ['rails3', { :mem => '256M', :description => 'Rails Application', :console=>true}],
|
10
10
|
'Spring' => ['spring', { :mem => '512M', :description => 'Java SpringSource Spring Application'}],
|
11
11
|
'Grails' => ['grails', { :mem => '512M', :description => 'Java SpringSource Grails Application'}],
|
12
12
|
'Lift' => ['lift', { :mem => '512M', :description => 'Scala Lift Application'}],
|
@@ -29,6 +29,12 @@ module VMC::Cli
|
|
29
29
|
return Framework.new(*FRAMEWORKS[name])
|
30
30
|
end
|
31
31
|
|
32
|
+
def lookup_by_framework(name)
|
33
|
+
FRAMEWORKS.each do |key,fw|
|
34
|
+
return Framework.new(fw[0], fw[1]) if fw[0] == name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
32
38
|
def detect(path)
|
33
39
|
Dir.chdir(path) do
|
34
40
|
|
@@ -106,7 +112,7 @@ module VMC::Cli
|
|
106
112
|
|
107
113
|
end
|
108
114
|
|
109
|
-
attr_reader :name, :description, :memory
|
115
|
+
attr_reader :name, :description, :memory, :console
|
110
116
|
attr_accessor :exec
|
111
117
|
|
112
118
|
alias :mem :memory
|
@@ -116,6 +122,7 @@ module VMC::Cli
|
|
116
122
|
@memory = opts[:mem] || DEFAULT_MEM
|
117
123
|
@description = opts[:description] || 'Unknown Application Type'
|
118
124
|
@exec = opts[:exec]
|
125
|
+
@console = opts[:console] || false
|
119
126
|
end
|
120
127
|
|
121
128
|
def to_s
|
data/lib/cli/manifest_helper.rb
CHANGED
@@ -125,10 +125,20 @@ module VMC::Cli::ManifestHelper
|
|
125
125
|
), "instances"
|
126
126
|
|
127
127
|
unless manifest "services"
|
128
|
+
user_services = client.services
|
129
|
+
user_services.sort! {|a, b| a[:name] <=> b[:name] }
|
130
|
+
|
131
|
+
unless user_services.empty?
|
132
|
+
if ask "Bind existing services to '#{name}'?", :default => false
|
133
|
+
bind_services(user_services)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
128
137
|
services = client.services_info
|
129
138
|
unless services.empty?
|
130
|
-
|
131
|
-
|
139
|
+
if ask "Create services to bind to '#{name}'?", :default => false
|
140
|
+
create_services(services.values.collect(&:keys).flatten)
|
141
|
+
end
|
132
142
|
end
|
133
143
|
end
|
134
144
|
|
@@ -174,20 +184,34 @@ module VMC::Cli::ManifestHelper
|
|
174
184
|
framework
|
175
185
|
end
|
176
186
|
|
177
|
-
def bind_services(
|
187
|
+
def bind_services(user_services, chosen = 0)
|
188
|
+
svcname = ask(
|
189
|
+
"Which one?",
|
190
|
+
:indexed => true,
|
191
|
+
:choices => user_services.collect { |p| p[:name] })
|
192
|
+
|
193
|
+
svc = user_services.find { |p| p[:name] == svcname }
|
194
|
+
|
195
|
+
set svc[:vendor], "services", svcname, "type"
|
196
|
+
|
197
|
+
if chosen + 1 < user_services.size && ask("Bind another?", :default => false)
|
198
|
+
bind_services(user_services, chosen + 1)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def create_services(services)
|
178
203
|
svcs = services.collect(&:to_s).sort!
|
179
204
|
|
180
|
-
display "The following system services are available"
|
181
205
|
configure_service(
|
182
206
|
ask(
|
183
|
-
"
|
207
|
+
"What kind of service?",
|
184
208
|
:indexed => true,
|
185
209
|
:choices => svcs
|
186
|
-
)
|
210
|
+
)
|
187
211
|
)
|
188
212
|
|
189
|
-
if ask "
|
190
|
-
|
213
|
+
if ask "Create another?", :default => false
|
214
|
+
create_services(services)
|
191
215
|
end
|
192
216
|
end
|
193
217
|
|
data/lib/cli/runner.rb
CHANGED
@@ -238,10 +238,6 @@ class VMC::Cli::Runner
|
|
238
238
|
usage('vmc restart <appname>')
|
239
239
|
set_cmd(:apps, :restart, @args.size == 1 ? 1 : 0)
|
240
240
|
|
241
|
-
when 'rename'
|
242
|
-
usage('vmc rename <appname> <newname>')
|
243
|
-
set_cmd(:apps, :rename, 2)
|
244
|
-
|
245
241
|
when 'mem'
|
246
242
|
usage('vmc mem <appname> [memsize]')
|
247
243
|
if @args.size == 2
|
@@ -380,6 +376,10 @@ class VMC::Cli::Runner
|
|
380
376
|
set_cmd(:services, :tunnel, 1) if @args.size == 1
|
381
377
|
set_cmd(:services, :tunnel, 2) if @args.size == 2
|
382
378
|
|
379
|
+
when 'rails-console'
|
380
|
+
usage('vmc rails-console <appname>')
|
381
|
+
set_cmd(:apps, :console, 1)
|
382
|
+
|
383
383
|
when 'help'
|
384
384
|
display_help if @args.size == 0
|
385
385
|
@help_only = true
|
@@ -478,6 +478,7 @@ class VMC::Cli::Runner
|
|
478
478
|
@exit_status = false
|
479
479
|
rescue VMC::Client::TargetError, VMC::Client::NotFound, VMC::Client::BadTarget => e
|
480
480
|
puts e.message.red
|
481
|
+
puts e.backtrace
|
481
482
|
@exit_status = false
|
482
483
|
rescue VMC::Client::HTTPException => e
|
483
484
|
puts e.message.red
|
data/lib/cli/tunnel_helper.rb
CHANGED
@@ -39,7 +39,6 @@ module VMC::Cli
|
|
39
39
|
name, val = e.split("=", 2)
|
40
40
|
return val if name == "CALDECOTT_AUTH"
|
41
41
|
end
|
42
|
-
|
43
42
|
nil
|
44
43
|
end
|
45
44
|
|
@@ -184,9 +183,7 @@ module VMC::Cli
|
|
184
183
|
display ''
|
185
184
|
end
|
186
185
|
|
187
|
-
def start_tunnel(
|
188
|
-
display "Starting tunnel to #{service.bold} on port #{local_port.to_s.bold}."
|
189
|
-
|
186
|
+
def start_tunnel(local_port, conn_info, auth)
|
190
187
|
@local_tunnel_thread = Thread.new do
|
191
188
|
Caldecott::Client.start({
|
192
189
|
:local_port => local_port,
|
@@ -203,6 +200,8 @@ module VMC::Cli
|
|
203
200
|
at_exit { @local_tunnel_thread.kill }
|
204
201
|
end
|
205
202
|
|
203
|
+
|
204
|
+
|
206
205
|
def pick_tunnel_port(port)
|
207
206
|
original = port
|
208
207
|
|
@@ -230,8 +229,9 @@ module VMC::Cli
|
|
230
229
|
def wait_for_tunnel_start(port)
|
231
230
|
10.times do |n|
|
232
231
|
begin
|
233
|
-
TCPSocket.open('localhost', port)
|
232
|
+
client = TCPSocket.open('localhost', port)
|
234
233
|
display '' if n > 0
|
234
|
+
client.close
|
235
235
|
return true
|
236
236
|
rescue => e
|
237
237
|
display "Waiting for local tunnel to become available", false if n == 0
|
@@ -297,28 +297,36 @@ module VMC::Cli
|
|
297
297
|
tunnel_appname,
|
298
298
|
{ :name => tunnel_appname,
|
299
299
|
:staging => {:framework => "sinatra"},
|
300
|
-
:uris => ["#{tunnel_uniquename}.#{
|
300
|
+
:uris => ["#{tunnel_uniquename}.#{target_base}"],
|
301
301
|
:instances => 1,
|
302
302
|
:resources => {:memory => 64},
|
303
303
|
:env => ["CALDECOTT_AUTH=#{token}"]
|
304
304
|
}
|
305
305
|
)
|
306
306
|
|
307
|
-
|
307
|
+
apps_cmd.send(:upload_app_bits, tunnel_appname, HELPER_APP)
|
308
308
|
|
309
309
|
invalidate_tunnel_app_info
|
310
310
|
end
|
311
311
|
|
312
312
|
def stop_caldecott
|
313
|
-
|
313
|
+
apps_cmd.stop(tunnel_appname)
|
314
314
|
|
315
315
|
invalidate_tunnel_app_info
|
316
316
|
end
|
317
317
|
|
318
318
|
def start_caldecott
|
319
|
-
|
319
|
+
apps_cmd.start(tunnel_appname)
|
320
320
|
|
321
321
|
invalidate_tunnel_app_info
|
322
322
|
end
|
323
|
+
|
324
|
+
private
|
325
|
+
|
326
|
+
def apps_cmd
|
327
|
+
a = Command::Apps.new(@options)
|
328
|
+
a.client client
|
329
|
+
a
|
330
|
+
end
|
323
331
|
end
|
324
332
|
end
|
data/lib/cli/usage.rb
CHANGED
@@ -47,7 +47,6 @@ Currently available vmc commands are:
|
|
47
47
|
stop <appname> Stop the application
|
48
48
|
restart <appname> [--debug [MODE]] Restart the application
|
49
49
|
delete <appname> Delete the application
|
50
|
-
rename <appname> <newname> Rename the application
|
51
50
|
|
52
51
|
Application Updates
|
53
52
|
update <appname> [--path,--debug [MODE]] Update the application bits
|
data/lib/cli/version.rb
CHANGED
data/lib/vmc/client.rb
CHANGED
@@ -39,7 +39,7 @@ class VMC::Client
|
|
39
39
|
def initialize(target_url=VMC::DEFAULT_TARGET, auth_token=nil)
|
40
40
|
target_url = "http://#{target_url}" unless /^https?/ =~ target_url
|
41
41
|
target_url = target_url.gsub(/\/+$/, '')
|
42
|
-
@target =
|
42
|
+
@target = target_url
|
43
43
|
@auth_token = auth_token
|
44
44
|
end
|
45
45
|
|
@@ -149,7 +149,7 @@ class VMC::Client
|
|
149
149
|
|
150
150
|
# List the directory or download the actual file indicated by
|
151
151
|
# the path.
|
152
|
-
def app_files(name, path, instance=0)
|
152
|
+
def app_files(name, path, instance='0')
|
153
153
|
check_login_status
|
154
154
|
path = path.gsub('//', '/')
|
155
155
|
url = path(VMC::APPS_PATH, name, "instances", instance, "files", path)
|
@@ -318,7 +318,7 @@ class VMC::Client
|
|
318
318
|
|
319
319
|
def self.path(*path)
|
320
320
|
path.flatten.collect { |x|
|
321
|
-
URI.encode x, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
|
321
|
+
URI.encode x.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
|
322
322
|
}.join("/")
|
323
323
|
end
|
324
324
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: vmc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 7
|
5
|
-
version: 0.3.16.beta.
|
5
|
+
version: 0.3.16.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: 2012-
|
13
|
+
date: 2012-02-07 00:00:00 -08:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -71,7 +71,7 @@ dependencies:
|
|
71
71
|
requirements:
|
72
72
|
- - ~>
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.
|
74
|
+
version: 0.4.0
|
75
75
|
type: :runtime
|
76
76
|
version_requirements: *id005
|
77
77
|
- !ruby/object:Gem::Dependency
|
@@ -151,6 +151,7 @@ files:
|
|
151
151
|
- lib/cli/commands/services.rb
|
152
152
|
- lib/cli/commands/user.rb
|
153
153
|
- lib/cli/config.rb
|
154
|
+
- lib/cli/console_helper.rb
|
154
155
|
- lib/cli/core_ext.rb
|
155
156
|
- lib/cli/errors.rb
|
156
157
|
- lib/cli/frameworks.rb
|