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.
@@ -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/command"
1
+ require "vmc/cli"
2
2
 
3
3
  module VMC
4
- class Service < Command
5
- desc "create", "Create a service"
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
- flag(:vendor) { |choices|
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
- flag(:version) { |choices|
11
- ask "Which version?", :choices => choices
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
- def create
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(:vendor, services.keys)
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(:version, meta[:versions])
62
+ version = input[:version, meta[:versions]]
27
63
  end
28
64
 
29
- service = client.service(input(:name, meta[:vendor]))
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
- desc "bind", "Bind a service to an application"
80
+
81
+ desc "Bind a service to an application"
41
82
  group :services, :manage
42
- flag(:name) { |choices|
83
+ input(:name, :argument => true,
84
+ :desc => "Service to bind") { |choices|
43
85
  ask "Which service?", :choices => choices
44
86
  }
45
- flag(:app) { |choices|
87
+ input(:app, :argument => true,
88
+ :desc => "Application to bind to") { |choices|
46
89
  ask "Which application?", :choices => choices
47
90
  }
48
- def bind(name = nil, appname = nil)
49
- name ||= input(:name, client.services.collect(&:name))
50
- appname ||= input(:app, client.apps.collect(&:name))
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
- desc "unbind", "Unbind a service from an application"
100
+
101
+ desc "Unbind a service from an application"
58
102
  group :services, :manage
59
- flag(:name) { |choices|
103
+ input(:name, :argument => true,
104
+ :desc => "Service to unbind") { |choices|
60
105
  ask "Which service?", :choices => choices
61
106
  }
62
- flag(:app) { |choices|
107
+ input(:app, :argument => true,
108
+ :desc => "Application to unbind from") { |choices|
63
109
  ask "Which application?", :choices => choices
64
110
  }
65
- def unbind(name = nil, appname = nil)
66
- appname ||= input(:app, client.apps.collect(&:name))
111
+ def unbind_service(input)
112
+ appname = input[:app, client.apps.collect(&:name)]
67
113
 
68
114
  app = client.app(appname)
69
- name ||= input(:name, app.services)
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
- desc "delete", "Delete a service"
122
+
123
+ desc "Delete a service"
77
124
  group :services, :manage
78
- flag(:really) { |name, color|
79
- force? || ask("Really delete #{c(name, color)}?", :default => false)
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
- flag(:all, :default => false)
85
- def delete(name = nil)
86
- if input(:all)
87
- return unless input(:really, "ALL SERVICES", :bad)
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
- unless name
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(:name, services.collect(&:name))
150
+ name = input[:name, services.collect(&:name)]
101
151
  end
102
152
 
103
- return unless input(:really, name, :name)
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
- ensure
109
- forget(:really)
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