vmc 0.4.0.beta.12 → 0.4.0.beta.13
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.
- data/vmc-ng/bin/vmc +0 -3
- data/vmc-ng/lib/vmc.rb +5 -0
- data/vmc-ng/lib/vmc/cli.rb +190 -342
- data/vmc-ng/lib/vmc/cli/app.rb +363 -235
- data/vmc-ng/lib/vmc/cli/help.rb +12 -0
- data/vmc-ng/lib/vmc/cli/interactive.rb +101 -0
- data/vmc-ng/lib/vmc/cli/service.rb +116 -38
- data/vmc-ng/lib/vmc/cli/start.rb +252 -0
- data/vmc-ng/lib/vmc/cli/user.rb +53 -24
- data/vmc-ng/lib/vmc/plugin.rb +0 -5
- data/vmc-ng/lib/vmc/version.rb +1 -1
- metadata +16 -16
- data/vmc-ng/lib/vmc/cli/better_help.rb +0 -193
- data/vmc-ng/lib/vmc/cli/command.rb +0 -567
- data/vmc-ng/lib/vmc/cli/dots.rb +0 -190
@@ -0,0 +1,12 @@
|
|
1
|
+
require "mothership/help"
|
2
|
+
|
3
|
+
Mothership::Help.groups(
|
4
|
+
[:start, "Getting Started"],
|
5
|
+
[:apps, "Applications",
|
6
|
+
[:manage, "Management"],
|
7
|
+
[:info, "Information"]],
|
8
|
+
[:services, "Services",
|
9
|
+
[:manage, "Management"]],
|
10
|
+
[:admin, "Administration",
|
11
|
+
[:user, "User Management"]])
|
12
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "interact"
|
2
|
+
|
3
|
+
module VMC
|
4
|
+
module Interactive
|
5
|
+
include ::Interactive::Rewindable
|
6
|
+
|
7
|
+
def ask(question, options = {})
|
8
|
+
if force? and options.key?(:default)
|
9
|
+
options[:default]
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def list_choices(choices, options)
|
16
|
+
choices.each_with_index do |o, i|
|
17
|
+
puts "#{c(i + 1, :number)}: #{o}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def input_state(options)
|
22
|
+
CFState.new(options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def prompt(question, options)
|
26
|
+
value =
|
27
|
+
case options[:default]
|
28
|
+
when true
|
29
|
+
"y"
|
30
|
+
when false
|
31
|
+
"n"
|
32
|
+
when nil
|
33
|
+
""
|
34
|
+
else
|
35
|
+
options[:default].to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
print "#{question}"
|
39
|
+
print c("> ", :prompt)
|
40
|
+
|
41
|
+
unless value.empty?
|
42
|
+
print "#{c(value, :default) + "\b" * value.size}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def handler(which, state)
|
47
|
+
ans = state.answer
|
48
|
+
pos = state.position
|
49
|
+
|
50
|
+
if state.default?
|
51
|
+
if which.is_a?(Array) and which[0] == :key
|
52
|
+
# initial non-movement keypress clears default answer
|
53
|
+
clear_input(state)
|
54
|
+
else
|
55
|
+
# wipe away any coloring
|
56
|
+
redraw_input(state)
|
57
|
+
end
|
58
|
+
|
59
|
+
state.clear_default!
|
60
|
+
end
|
61
|
+
|
62
|
+
super
|
63
|
+
|
64
|
+
print "\n" if which == :enter
|
65
|
+
end
|
66
|
+
|
67
|
+
class CFState < ::Interactive::InputState
|
68
|
+
def initialize(options = {}, answer = nil, position = 0)
|
69
|
+
@options = options
|
70
|
+
|
71
|
+
if answer
|
72
|
+
@answer = answer
|
73
|
+
elsif options[:default]
|
74
|
+
case options[:default]
|
75
|
+
when true
|
76
|
+
@answer = "y"
|
77
|
+
when false
|
78
|
+
@answer = "n"
|
79
|
+
else
|
80
|
+
@answer = options[:default].to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
@default = true
|
84
|
+
else
|
85
|
+
@answer = ""
|
86
|
+
end
|
87
|
+
|
88
|
+
@position = position
|
89
|
+
@done = false
|
90
|
+
end
|
91
|
+
|
92
|
+
def clear_default!
|
93
|
+
@default = false
|
94
|
+
end
|
95
|
+
|
96
|
+
def default?
|
97
|
+
@default
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -1,32 +1,68 @@
|
|
1
|
-
require "vmc/cli
|
1
|
+
require "vmc/cli"
|
2
2
|
|
3
3
|
module VMC
|
4
|
-
class Service <
|
5
|
-
desc "
|
4
|
+
class Service < CLI
|
5
|
+
desc "List your services"
|
6
|
+
group :services
|
7
|
+
input :name, :desc => "Filter by name regexp"
|
8
|
+
input :app, :desc => "Filter by bound application regexp"
|
9
|
+
input :type, :desc => "Filter by service type regexp"
|
10
|
+
input :vendor, :desc => "Filter by service vendor regexp"
|
11
|
+
input :tier, :desc => "Filter by service tier regexp"
|
12
|
+
def services(input)
|
13
|
+
services =
|
14
|
+
with_progress("Getting services") do
|
15
|
+
client.services
|
16
|
+
end
|
17
|
+
|
18
|
+
puts "" unless quiet?
|
19
|
+
|
20
|
+
if services.empty? and !quiet?
|
21
|
+
puts "No services."
|
22
|
+
end
|
23
|
+
|
24
|
+
if app = input[:app]
|
25
|
+
apps = client.apps
|
26
|
+
services.reject! do |s|
|
27
|
+
apps.none? { |a| a.services.include? s.name }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
services.each do |s|
|
32
|
+
display_service(s) if service_matches(s, input)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
desc "Create a service"
|
6
38
|
group :services, :manage
|
7
|
-
|
39
|
+
input(:vendor, :argument => true,
|
40
|
+
:desc => "What kind of service (e.g. redis, mysql)") { |choices|
|
8
41
|
ask "What kind?", :choices => choices
|
9
42
|
}
|
10
|
-
|
11
|
-
|
12
|
-
}
|
13
|
-
flag(:name) { |vendor|
|
43
|
+
input(:name, :argument => true,
|
44
|
+
:desc => "Local name for the service") { |vendor|
|
14
45
|
random = sprintf("%x", rand(1000000))
|
15
46
|
ask "Name?", :default => "#{vendor}-#{random}"
|
16
47
|
}
|
17
|
-
|
48
|
+
input(:version, :desc => "Version of the service") { |choices|
|
49
|
+
ask "Which version?", :choices => choices
|
50
|
+
}
|
51
|
+
input :bind, :alias => "--app",
|
52
|
+
:desc => "Application to immediately bind to"
|
53
|
+
def create_service(input)
|
18
54
|
services = client.system_services
|
19
55
|
|
20
|
-
vendor = input
|
56
|
+
vendor = input[:vendor, services.keys.sort]
|
21
57
|
meta = services[vendor]
|
22
58
|
|
23
59
|
if meta[:versions].size == 1
|
24
60
|
version = meta[:versions].first
|
25
61
|
else
|
26
|
-
version = input
|
62
|
+
version = input[:version, meta[:versions]]
|
27
63
|
end
|
28
64
|
|
29
|
-
service = client.service(input
|
65
|
+
service = client.service(input[:name, meta[:vendor]])
|
30
66
|
service.type = meta[:type]
|
31
67
|
service.vendor = meta[:vendor]
|
32
68
|
service.version = version
|
@@ -35,56 +71,68 @@ module VMC
|
|
35
71
|
with_progress("Creating service #{c(service.name, :name)}") do
|
36
72
|
service.create!
|
37
73
|
end
|
74
|
+
|
75
|
+
if app = input[:bind]
|
76
|
+
invoke :bind_service, :name => service.name, :app => app
|
77
|
+
end
|
38
78
|
end
|
39
79
|
|
40
|
-
|
80
|
+
|
81
|
+
desc "Bind a service to an application"
|
41
82
|
group :services, :manage
|
42
|
-
|
83
|
+
input(:name, :argument => true,
|
84
|
+
:desc => "Service to bind") { |choices|
|
43
85
|
ask "Which service?", :choices => choices
|
44
86
|
}
|
45
|
-
|
87
|
+
input(:app, :argument => true,
|
88
|
+
:desc => "Application to bind to") { |choices|
|
46
89
|
ask "Which application?", :choices => choices
|
47
90
|
}
|
48
|
-
def
|
49
|
-
name
|
50
|
-
appname
|
91
|
+
def bind_service(input)
|
92
|
+
name = input[:name, client.services.collect(&:name)]
|
93
|
+
appname = input[:app, client.apps.collect(&:name)]
|
51
94
|
|
52
95
|
with_progress("Binding #{c(name, :name)} to #{c(appname, :name)}") do
|
53
96
|
client.app(appname).bind(name)
|
54
97
|
end
|
55
98
|
end
|
56
99
|
|
57
|
-
|
100
|
+
|
101
|
+
desc "Unbind a service from an application"
|
58
102
|
group :services, :manage
|
59
|
-
|
103
|
+
input(:name, :argument => true,
|
104
|
+
:desc => "Service to unbind") { |choices|
|
60
105
|
ask "Which service?", :choices => choices
|
61
106
|
}
|
62
|
-
|
107
|
+
input(:app, :argument => true,
|
108
|
+
:desc => "Application to unbind from") { |choices|
|
63
109
|
ask "Which application?", :choices => choices
|
64
110
|
}
|
65
|
-
def
|
66
|
-
appname
|
111
|
+
def unbind_service(input)
|
112
|
+
appname = input[:app, client.apps.collect(&:name)]
|
67
113
|
|
68
114
|
app = client.app(appname)
|
69
|
-
name
|
115
|
+
name = input[:name, app.services]
|
70
116
|
|
71
117
|
with_progress("Unbinding #{c(name, :name)} from #{c(appname, :name)}") do
|
72
118
|
app.unbind(name)
|
73
119
|
end
|
74
120
|
end
|
75
121
|
|
76
|
-
|
122
|
+
|
123
|
+
desc "Delete a service"
|
77
124
|
group :services, :manage
|
78
|
-
|
79
|
-
|
80
|
-
}
|
81
|
-
flag(:name) { |choices|
|
125
|
+
input(:name, :argument => true,
|
126
|
+
:desc => "Service to delete") { |choices|
|
82
127
|
ask "Delete which service?", :choices => choices
|
83
128
|
}
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
129
|
+
input(:really, :type => :boolean) { |name, color|
|
130
|
+
force? || ask("Really delete #{c(name, color)}?", :default => false)
|
131
|
+
}
|
132
|
+
input :all, :default => false, :desc => "Delete all services"
|
133
|
+
def delete_service(input)
|
134
|
+
if input[:all]
|
135
|
+
return unless input[:really, "ALL SERVICES", :bad]
|
88
136
|
|
89
137
|
with_progress("Deleting all services") do
|
90
138
|
client.services.collect(&:delete!)
|
@@ -93,20 +141,50 @@ module VMC
|
|
93
141
|
return
|
94
142
|
end
|
95
143
|
|
96
|
-
|
144
|
+
if input.given? :name
|
145
|
+
name = input[:name]
|
146
|
+
else
|
97
147
|
services = client.services
|
98
148
|
fail "No services." if services.empty?
|
99
149
|
|
100
|
-
name = input
|
150
|
+
name = input[:name, services.collect(&:name)]
|
101
151
|
end
|
102
152
|
|
103
|
-
return unless input
|
153
|
+
return unless input[:really, name, :name]
|
104
154
|
|
105
155
|
with_progress("Deleting #{c(name, :name)}") do
|
106
156
|
client.service(name).delete!
|
107
157
|
end
|
108
|
-
|
109
|
-
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def service_matches(s, options)
|
163
|
+
if name = options[:name]
|
164
|
+
return false if s.name !~ /#{name}/
|
165
|
+
end
|
166
|
+
|
167
|
+
if type = options[:type]
|
168
|
+
return false if s.type !~ /#{type}/
|
169
|
+
end
|
170
|
+
|
171
|
+
if vendor = options[:vendor]
|
172
|
+
return false if s.vendor !~ /#{vendor}/
|
173
|
+
end
|
174
|
+
|
175
|
+
if tier = options[:tier]
|
176
|
+
return false if s.tier !~ /#{tier}/
|
177
|
+
end
|
178
|
+
|
179
|
+
true
|
180
|
+
end
|
181
|
+
|
182
|
+
def display_service(s)
|
183
|
+
if quiet?
|
184
|
+
puts s.name
|
185
|
+
else
|
186
|
+
puts "#{c(s.name, :name)}: #{s.vendor} v#{s.version}"
|
187
|
+
end
|
110
188
|
end
|
111
189
|
end
|
112
190
|
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
require "vmc/cli"
|
2
|
+
|
3
|
+
module VMC
|
4
|
+
class Start < CLI
|
5
|
+
desc "Display information on the current target, user, etc."
|
6
|
+
group :start
|
7
|
+
input :runtimes, :type => :boolean,
|
8
|
+
:desc => "List supported runtimes"
|
9
|
+
input :services, :type => :boolean,
|
10
|
+
:desc => "List supported services"
|
11
|
+
input :frameworks, :type => :boolean,
|
12
|
+
:desc => "List supported frameworks"
|
13
|
+
def info(input)
|
14
|
+
info =
|
15
|
+
with_progress("Getting target information") do
|
16
|
+
client.info
|
17
|
+
end
|
18
|
+
|
19
|
+
authorized = !!info["frameworks"]
|
20
|
+
|
21
|
+
if input[:runtimes]
|
22
|
+
raise NotAuthorized unless authorized
|
23
|
+
|
24
|
+
runtimes = {}
|
25
|
+
info["frameworks"].each do |_, f|
|
26
|
+
f["runtimes"].each do |r|
|
27
|
+
runtimes[r["name"]] = r
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
runtimes = runtimes.values.sort_by { |x| x["name"] }
|
32
|
+
|
33
|
+
if quiet?
|
34
|
+
runtimes.each do |r|
|
35
|
+
puts r["name"]
|
36
|
+
end
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
runtimes.each do |r|
|
41
|
+
puts ""
|
42
|
+
puts "#{c(r["name"], :name)}:"
|
43
|
+
puts " version: #{b(r["version"])}"
|
44
|
+
puts " description: #{b(r["description"])}"
|
45
|
+
end
|
46
|
+
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
if input[:services]
|
51
|
+
raise NotAuthorized unless authorized
|
52
|
+
|
53
|
+
services = client.system_services
|
54
|
+
|
55
|
+
if quiet?
|
56
|
+
services.each do |name, _|
|
57
|
+
puts name
|
58
|
+
end
|
59
|
+
|
60
|
+
return
|
61
|
+
end
|
62
|
+
|
63
|
+
services.each do |name, meta|
|
64
|
+
puts ""
|
65
|
+
puts "#{c(name, :name)}:"
|
66
|
+
puts " versions: #{meta[:versions].join ", "}"
|
67
|
+
puts " description: #{meta[:description]}"
|
68
|
+
puts " type: #{meta[:type]}"
|
69
|
+
end
|
70
|
+
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
if input[:frameworks]
|
75
|
+
raise NotAuthorized unless authorized
|
76
|
+
|
77
|
+
puts "" unless quiet?
|
78
|
+
|
79
|
+
info["frameworks"].each do |name, _|
|
80
|
+
puts name
|
81
|
+
end
|
82
|
+
|
83
|
+
return
|
84
|
+
end
|
85
|
+
|
86
|
+
puts ""
|
87
|
+
|
88
|
+
puts info["description"]
|
89
|
+
puts ""
|
90
|
+
puts "target: #{b(client.target)}"
|
91
|
+
puts " version: #{info["version"]}"
|
92
|
+
puts " support: #{info["support"]}"
|
93
|
+
|
94
|
+
if info["user"]
|
95
|
+
puts ""
|
96
|
+
puts "user: #{b(info["user"])}"
|
97
|
+
puts " usage:"
|
98
|
+
|
99
|
+
limits = info["limits"]
|
100
|
+
info["usage"].each do |k, v|
|
101
|
+
m = limits[k]
|
102
|
+
if k == "memory"
|
103
|
+
puts " #{k}: #{usage(v * 1024 * 1024, m * 1024 * 1024)}"
|
104
|
+
else
|
105
|
+
puts " #{k}: #{b(v)} of #{b(m)} limit"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
desc "Set or display the current target cloud"
|
113
|
+
group :start
|
114
|
+
input :url, :argument => :optional,
|
115
|
+
:desc => "Target URL to switch to"
|
116
|
+
def target(input)
|
117
|
+
if !input.given?(:url)
|
118
|
+
display_target
|
119
|
+
return
|
120
|
+
end
|
121
|
+
|
122
|
+
target = sane_target_url(input[:url])
|
123
|
+
display = c(target.sub(/https?:\/\//, ""), :name)
|
124
|
+
with_progress("Setting target to #{display}") do
|
125
|
+
unless force?
|
126
|
+
# check that the target is valid
|
127
|
+
CFoundry::Client.new(target).info
|
128
|
+
end
|
129
|
+
|
130
|
+
set_target(target)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
desc "List known targets."
|
136
|
+
group :start, :hidden => true
|
137
|
+
def targets(input)
|
138
|
+
tokens.each do |target, auth|
|
139
|
+
puts target
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
desc "Authenticate with the target"
|
145
|
+
group :start
|
146
|
+
input(:email, :argument => true, :desc => "Account email") {
|
147
|
+
ask("Email")
|
148
|
+
}
|
149
|
+
input :password, :desc => "Account password"
|
150
|
+
# TODO: implement new authentication scheme
|
151
|
+
def login(input)
|
152
|
+
unless quiet?
|
153
|
+
display_target
|
154
|
+
puts ""
|
155
|
+
end
|
156
|
+
|
157
|
+
email = input[:email]
|
158
|
+
password = input[:password]
|
159
|
+
|
160
|
+
authenticated = false
|
161
|
+
failed = false
|
162
|
+
until authenticated
|
163
|
+
unless force?
|
164
|
+
if failed || !password
|
165
|
+
password = ask("Password", :echo => "*", :forget => true)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
with_progress("Authenticating") do |s|
|
170
|
+
begin
|
171
|
+
save_token(client.login(email, password))
|
172
|
+
authenticated = true
|
173
|
+
rescue CFoundry::Denied
|
174
|
+
return if force?
|
175
|
+
|
176
|
+
s.fail do
|
177
|
+
failed = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
ensure
|
183
|
+
exit_status 1 if not authenticated
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
desc "Log out from the target"
|
188
|
+
group :start
|
189
|
+
def logout(input)
|
190
|
+
with_progress("Logging out") do
|
191
|
+
remove_token
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
desc "Create a user and log in"
|
197
|
+
group :start, :hidden => true
|
198
|
+
input(:email, :argument => true, :desc => "Desired email") {
|
199
|
+
ask("Email")
|
200
|
+
}
|
201
|
+
input(:password, :desc => "Desired password") {
|
202
|
+
ask("Password", :echo => "*", :forget => true)
|
203
|
+
}
|
204
|
+
input(:verify, :desc => "Repeat password") {
|
205
|
+
ask("Confirm Password", :echo => "*", :forget => true)
|
206
|
+
}
|
207
|
+
input :login, :type => :boolean, :default => true,
|
208
|
+
:desc => "Automatically log in?"
|
209
|
+
def register(input)
|
210
|
+
unless quiet?
|
211
|
+
puts "Target: #{c(client_target, :name)}"
|
212
|
+
puts ""
|
213
|
+
end
|
214
|
+
|
215
|
+
email = input[:email]
|
216
|
+
password = input[:password]
|
217
|
+
|
218
|
+
if !force? && password != input[:verify]
|
219
|
+
fail "Passwords do not match."
|
220
|
+
end
|
221
|
+
|
222
|
+
with_progress("Creating user") do
|
223
|
+
client.register(email, password)
|
224
|
+
end
|
225
|
+
|
226
|
+
if input[:login]
|
227
|
+
with_progress("Logging in") do
|
228
|
+
save_token(client.login(email, password))
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
desc "Show color configuration"
|
235
|
+
group :start, :hidden => true
|
236
|
+
def colors(input)
|
237
|
+
user_colors.each do |n, c|
|
238
|
+
puts "#{n}: #{c(c.to_s, n)}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
def display_target
|
245
|
+
if quiet?
|
246
|
+
puts client.target
|
247
|
+
else
|
248
|
+
puts "Target: #{c(client.target, :name)}"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|