cfoundry 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +22 -2
- data/lib/cfoundry/baseclient.rb +206 -0
- data/lib/cfoundry/client.rb +14 -144
- data/lib/cfoundry/uaaclient.rb +103 -0
- data/lib/cfoundry/{app.rb → v1/app.rb} +75 -64
- data/lib/cfoundry/v1/base.rb +206 -0
- data/lib/cfoundry/v1/client.rb +205 -0
- data/lib/cfoundry/v1/framework.rb +16 -0
- data/lib/cfoundry/v1/runtime.rb +14 -0
- data/lib/cfoundry/v1/service.rb +19 -0
- data/lib/cfoundry/{service.rb → v1/service_instance.rb} +15 -15
- data/lib/cfoundry/{user.rb → v1/user.rb} +9 -9
- data/lib/cfoundry/v2/app.rb +119 -0
- data/lib/cfoundry/v2/base.rb +140 -0
- data/lib/cfoundry/v2/client.rb +184 -0
- data/lib/cfoundry/v2/domain.rb +8 -0
- data/lib/cfoundry/v2/framework.rb +18 -0
- data/lib/cfoundry/v2/model.rb +149 -0
- data/lib/cfoundry/v2/organization.rb +15 -0
- data/lib/cfoundry/v2/runtime.rb +9 -0
- data/lib/cfoundry/v2/service.rb +16 -0
- data/lib/cfoundry/v2/service_instance.rb +12 -0
- data/lib/cfoundry/v2/service_plan.rb +10 -0
- data/lib/cfoundry/v2/space.rb +13 -0
- data/lib/cfoundry/v2/user.rb +50 -0
- data/lib/cfoundry/version.rb +1 -1
- metadata +27 -9
- data/lib/cfoundry/restclient.rb +0 -260
@@ -5,16 +5,19 @@ require "tmpdir"
|
|
5
5
|
|
6
6
|
require "cfoundry/zip"
|
7
7
|
|
8
|
-
|
8
|
+
require "cfoundry/v1/framework"
|
9
|
+
require "cfoundry/v1/runtime"
|
10
|
+
|
11
|
+
module CFoundry::V1
|
9
12
|
# Class for representing a user's application on a given target (via
|
10
13
|
# Client).
|
11
14
|
#
|
12
|
-
#
|
15
|
+
# Does not guarantee that the app exists; used for both app creation and
|
13
16
|
# retrieval, as the attributes are all lazily retrieved. Setting attributes
|
14
17
|
# does not perform any requests; use #update! to commit your changes.
|
15
18
|
class App
|
16
19
|
# Application name.
|
17
|
-
|
20
|
+
attr_accessor :name
|
18
21
|
|
19
22
|
# Application instance count.
|
20
23
|
attr_accessor :total_instances
|
@@ -69,12 +72,12 @@ module CFoundry
|
|
69
72
|
#
|
70
73
|
# Keeps the metadata, but clears target-specific state from it.
|
71
74
|
def delete!
|
72
|
-
@client.
|
75
|
+
@client.base.delete_app(@name)
|
73
76
|
|
74
77
|
if @manifest
|
75
|
-
@manifest.delete
|
76
|
-
@manifest.delete
|
77
|
-
@manifest.delete
|
78
|
+
@manifest.delete :meta
|
79
|
+
@manifest.delete :version
|
80
|
+
@manifest.delete :state
|
78
81
|
end
|
79
82
|
end
|
80
83
|
|
@@ -82,13 +85,13 @@ module CFoundry
|
|
82
85
|
#
|
83
86
|
# Call this after setting the various attributes.
|
84
87
|
def create!
|
85
|
-
@client.
|
88
|
+
@client.base.create_app(@manifest.merge(:name => @name))
|
86
89
|
@manifest = nil
|
87
90
|
end
|
88
91
|
|
89
92
|
# Check if the application exists on the target.
|
90
93
|
def exists?
|
91
|
-
@client.
|
94
|
+
@client.base.app(@name)
|
92
95
|
true
|
93
96
|
rescue CFoundry::NotFound
|
94
97
|
false
|
@@ -96,34 +99,35 @@ module CFoundry
|
|
96
99
|
|
97
100
|
# Retrieve all of the instances of the app, as Instance objects.
|
98
101
|
def instances
|
99
|
-
@client.
|
100
|
-
Instance.new(@name, m[
|
102
|
+
@client.base.instances(@name).collect do |m|
|
103
|
+
Instance.new(@name, m[:index], @client, m)
|
101
104
|
end
|
102
105
|
end
|
103
106
|
|
104
107
|
# Retrieve application statistics, e.g. CPU load and memory usage.
|
105
108
|
def stats
|
106
|
-
@client.
|
109
|
+
@client.base.stats(@name)
|
107
110
|
end
|
108
111
|
|
109
112
|
# Update application attributes. Does not restart the application.
|
110
113
|
def update!(what = {})
|
111
|
-
#
|
112
|
-
# we write to manifest["debug"] but read from manifest["meta"]["debug"]
|
114
|
+
# bleh. have to set these here (normally in :meta) or they'll get lost.
|
113
115
|
what[:debug] = debug_mode
|
116
|
+
what[:staging] = (what[:staging] || {}).merge(manifest[:staging])
|
117
|
+
what[:staging][:command] = command if command
|
114
118
|
|
115
|
-
@client.
|
119
|
+
@client.base.update_app(@name, manifest.merge(what))
|
116
120
|
@manifest = nil
|
117
121
|
end
|
118
122
|
|
119
123
|
# Stop the application.
|
120
124
|
def stop!
|
121
|
-
update!
|
125
|
+
update! :state => "STOPPED"
|
122
126
|
end
|
123
127
|
|
124
128
|
# Start the application.
|
125
129
|
def start!
|
126
|
-
update!
|
130
|
+
update! :state => "STARTED"
|
127
131
|
end
|
128
132
|
|
129
133
|
# Restart the application.
|
@@ -141,8 +145,8 @@ module CFoundry
|
|
141
145
|
def health
|
142
146
|
s = state
|
143
147
|
if s == "STARTED"
|
144
|
-
healthy_count = manifest[
|
145
|
-
expected = manifest[
|
148
|
+
healthy_count = manifest[:runningInstances]
|
149
|
+
expected = manifest[:instances]
|
146
150
|
if healthy_count && expected > 0
|
147
151
|
ratio = healthy_count / expected.to_f
|
148
152
|
if ratio == 1.0
|
@@ -179,13 +183,13 @@ module CFoundry
|
|
179
183
|
state == "STARTED"
|
180
184
|
end
|
181
185
|
|
182
|
-
{ :total_instances =>
|
183
|
-
:state =>
|
184
|
-
:status =>
|
185
|
-
:services =>
|
186
|
-
:uris =>
|
187
|
-
:urls =>
|
188
|
-
:env =>
|
186
|
+
{ :total_instances => :instances,
|
187
|
+
:state => :state,
|
188
|
+
:status => :state,
|
189
|
+
:services => :services,
|
190
|
+
:uris => :uris,
|
191
|
+
:urls => :uris,
|
192
|
+
:env => :env
|
189
193
|
}.each do |meth, attr|
|
190
194
|
define_method(meth) do
|
191
195
|
manifest[attr]
|
@@ -212,35 +216,41 @@ module CFoundry
|
|
212
216
|
|
213
217
|
# Application framework.
|
214
218
|
def framework
|
215
|
-
|
216
|
-
manifest[
|
219
|
+
Framework.new(
|
220
|
+
manifest[:staging][:framework] ||
|
221
|
+
manifest[:staging][:model])
|
217
222
|
end
|
218
223
|
|
219
224
|
def framework=(v) # :nodoc:
|
225
|
+
v = v.name if v.is_a?(Framework)
|
226
|
+
|
220
227
|
@manifest ||= {}
|
221
|
-
@manifest[
|
228
|
+
@manifest[:staging] ||= {}
|
222
229
|
|
223
|
-
if @manifest[
|
224
|
-
@manifest[
|
230
|
+
if @manifest[:staging].key? :model
|
231
|
+
@manifest[:staging][:model] = v
|
225
232
|
else
|
226
|
-
@manifest[
|
233
|
+
@manifest[:staging][:framework] = v
|
227
234
|
end
|
228
235
|
end
|
229
236
|
|
230
237
|
# Application runtime.
|
231
238
|
def runtime
|
232
|
-
|
233
|
-
manifest[
|
239
|
+
Framework.new(
|
240
|
+
manifest[:staging][:runtime] ||
|
241
|
+
manifest[:staging][:stack])
|
234
242
|
end
|
235
243
|
|
236
244
|
def runtime=(v) # :nodoc:
|
245
|
+
v = v.name if v.is_a?(Runtime)
|
246
|
+
|
237
247
|
@manifest ||= {}
|
238
|
-
@manifest[
|
248
|
+
@manifest[:staging] ||= {}
|
239
249
|
|
240
|
-
if @manifest[
|
241
|
-
@manifest[
|
250
|
+
if @manifest[:staging].key? :stack
|
251
|
+
@manifest[:staging][:stack] = v
|
242
252
|
else
|
243
|
-
@manifest[
|
253
|
+
@manifest[:staging][:runtime] = v
|
244
254
|
end
|
245
255
|
end
|
246
256
|
|
@@ -249,49 +259,50 @@ module CFoundry
|
|
249
259
|
#
|
250
260
|
# Used for standalone apps.
|
251
261
|
def command
|
252
|
-
manifest[
|
262
|
+
manifest[:staging][:command] ||
|
263
|
+
manifest[:meta][:command]
|
253
264
|
end
|
254
265
|
|
255
266
|
def command=(v) # :nodoc:
|
256
267
|
@manifest ||= {}
|
257
|
-
@manifest[
|
258
|
-
@manifest[
|
268
|
+
@manifest[:staging] ||= {}
|
269
|
+
@manifest[:staging][:command] = v
|
259
270
|
end
|
260
271
|
|
261
272
|
|
262
273
|
# Application memory.
|
263
274
|
def memory
|
264
|
-
manifest[
|
275
|
+
manifest[:resources][:memory]
|
265
276
|
end
|
266
277
|
|
267
278
|
def memory=(v) # :nodoc:
|
268
279
|
@manifest ||= {}
|
269
|
-
@manifest[
|
270
|
-
@manifest[
|
280
|
+
@manifest[:resources] ||= {}
|
281
|
+
@manifest[:resources][:memory] = v
|
271
282
|
end
|
272
283
|
|
273
284
|
|
274
285
|
# Application debug mode.
|
275
286
|
def debug_mode
|
276
|
-
manifest.fetch(
|
277
|
-
manifest[
|
287
|
+
manifest.fetch(:debug) do
|
288
|
+
manifest[:meta] && manifest[:meta][:debug]
|
278
289
|
end
|
279
290
|
end
|
280
291
|
|
281
292
|
def debug_mode=(v) # :nodoc:
|
282
293
|
@manifest ||= {}
|
283
|
-
@manifest[
|
294
|
+
@manifest[:debug] = v
|
284
295
|
end
|
285
296
|
|
286
297
|
|
287
298
|
# Bind services to application.
|
288
299
|
def bind(*service_names)
|
289
|
-
update!(
|
300
|
+
update!(:services => services + service_names)
|
290
301
|
end
|
291
302
|
|
292
303
|
# Unbind services from application.
|
293
304
|
def unbind(*service_names)
|
294
|
-
update!(
|
305
|
+
update!(:services =>
|
295
306
|
services.reject { |s|
|
296
307
|
service_names.include?(s)
|
297
308
|
})
|
@@ -352,7 +363,7 @@ module CFoundry
|
|
352
363
|
|
353
364
|
packed = CFoundry::Zip.pack(tmpdir, zipfile)
|
354
365
|
|
355
|
-
@client.
|
366
|
+
@client.base.upload_app(@name, packed && zipfile, resources || [])
|
356
367
|
ensure
|
357
368
|
FileUtils.rm_f(zipfile) if zipfile
|
358
369
|
FileUtils.rm_rf(tmpdir) if tmpdir
|
@@ -361,7 +372,7 @@ module CFoundry
|
|
361
372
|
private
|
362
373
|
|
363
374
|
def manifest
|
364
|
-
@manifest ||= @client.
|
375
|
+
@manifest ||= @client.base.app(@name)
|
365
376
|
end
|
366
377
|
|
367
378
|
def prepare_package(path, to)
|
@@ -430,11 +441,11 @@ module CFoundry
|
|
430
441
|
|
431
442
|
return if total_size <= RESOURCE_CHECK_LIMIT
|
432
443
|
|
433
|
-
resources = @client.
|
444
|
+
resources = @client.base.check_resources(fingerprints)
|
434
445
|
|
435
446
|
resources.each do |resource|
|
436
|
-
FileUtils.rm_f resource[
|
437
|
-
resource[
|
447
|
+
FileUtils.rm_f resource[:fn]
|
448
|
+
resource[:fn].sub!("#{path}/", "")
|
438
449
|
end
|
439
450
|
|
440
451
|
resources
|
@@ -491,32 +502,32 @@ module CFoundry
|
|
491
502
|
|
492
503
|
# Instance state.
|
493
504
|
def state
|
494
|
-
@manifest[
|
505
|
+
@manifest[:state]
|
495
506
|
end
|
496
507
|
alias_method :status, :state
|
497
508
|
|
498
509
|
# Instance start time.
|
499
510
|
def since
|
500
|
-
Time.at(@manifest[
|
511
|
+
Time.at(@manifest[:since])
|
501
512
|
end
|
502
513
|
|
503
514
|
# Instance debugger data. If instance is in debug mode, returns a hash
|
504
515
|
# containing :ip and :port keys.
|
505
516
|
def debugger
|
506
|
-
return unless @manifest[
|
517
|
+
return unless @manifest[:debug_ip] and @manifest[:debug_port]
|
507
518
|
|
508
|
-
{ :ip => @manifest[
|
509
|
-
:port => @manifest[
|
519
|
+
{ :ip => @manifest[:debug_ip],
|
520
|
+
:port => @manifest[:debug_port]
|
510
521
|
}
|
511
522
|
end
|
512
523
|
|
513
524
|
# Instance console data. If instance has a console, returns a hash
|
514
525
|
# containing :ip and :port keys.
|
515
526
|
def console
|
516
|
-
return unless @manifest[
|
527
|
+
return unless @manifest[:console_ip] and @manifest[:console_port]
|
517
528
|
|
518
|
-
{ :ip => @manifest[
|
519
|
-
:port => @manifest[
|
529
|
+
{ :ip => @manifest[:console_ip],
|
530
|
+
:port => @manifest[:console_port]
|
520
531
|
}
|
521
532
|
end
|
522
533
|
|
@@ -538,7 +549,7 @@ module CFoundry
|
|
538
549
|
#
|
539
550
|
# For example, <code>files("foo", "bar")</code> for +foo/bar+.
|
540
551
|
def files(*path)
|
541
|
-
@client.
|
552
|
+
@client.base.files(@app, @index, *path).split("\n").collect do |entry|
|
542
553
|
path + [entry.split(/\s+/, 2)[0]]
|
543
554
|
end
|
544
555
|
end
|
@@ -550,7 +561,7 @@ module CFoundry
|
|
550
561
|
#
|
551
562
|
# For example, <code>files("foo", "bar")</code> for +foo/bar+.
|
552
563
|
def file(*path)
|
553
|
-
@client.
|
564
|
+
@client.base.files(@app, @index, *path)
|
554
565
|
end
|
555
566
|
end
|
556
567
|
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
require "cfoundry/baseclient"
|
4
|
+
require "cfoundry/uaaclient"
|
5
|
+
|
6
|
+
require "cfoundry/errors"
|
7
|
+
|
8
|
+
module CFoundry::V1
|
9
|
+
class Base < CFoundry::BaseClient
|
10
|
+
attr_accessor :target, :token, :proxy, :trace
|
11
|
+
|
12
|
+
def initialize(
|
13
|
+
target = "https://api.cloudfoundry.com",
|
14
|
+
token = nil)
|
15
|
+
@target = target
|
16
|
+
@token = token
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# invalidate token data when changing token
|
21
|
+
def token=(t)
|
22
|
+
@token = t
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# The UAA used for this client.
|
27
|
+
#
|
28
|
+
# `false` if no UAA (legacy)
|
29
|
+
def uaa
|
30
|
+
return @uaa unless @uaa.nil?
|
31
|
+
|
32
|
+
endpoint = info[:authorization_endpoint]
|
33
|
+
return @uaa = false unless endpoint
|
34
|
+
|
35
|
+
@uaa = CFoundry::UAAClient.new(endpoint)
|
36
|
+
@uaa.trace = @trace
|
37
|
+
@uaa.token = @token
|
38
|
+
@uaa
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# Cloud metadata
|
43
|
+
def info
|
44
|
+
get("info", nil => :json)
|
45
|
+
end
|
46
|
+
|
47
|
+
def system_services
|
48
|
+
get("info", "services", nil => :json)
|
49
|
+
end
|
50
|
+
|
51
|
+
def system_runtimes
|
52
|
+
get("info", "runtimes", nil => :json)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Users
|
56
|
+
def users
|
57
|
+
get("users", nil => :json)
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_user(payload)
|
61
|
+
post(payload, "users")
|
62
|
+
end
|
63
|
+
|
64
|
+
def user(email)
|
65
|
+
get("users", email, nil => :json)
|
66
|
+
end
|
67
|
+
|
68
|
+
def delete_user(email)
|
69
|
+
delete("users", email, nil => :json)
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_user(email, payload)
|
74
|
+
put(payload, "users", email, :json => nil)
|
75
|
+
end
|
76
|
+
|
77
|
+
def create_token(payload, email)
|
78
|
+
post(payload, "users", email, "tokens", :json => :json)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Applications
|
82
|
+
def apps
|
83
|
+
get("apps", nil => :json)
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_app(payload)
|
87
|
+
post(payload, "apps", :json => :json)
|
88
|
+
end
|
89
|
+
|
90
|
+
def app(name)
|
91
|
+
get("apps", name, nil => :json)
|
92
|
+
end
|
93
|
+
|
94
|
+
def instances(name)
|
95
|
+
get("apps", name, "instances", nil => :json)[:instances]
|
96
|
+
end
|
97
|
+
|
98
|
+
def files(name, instance, *path)
|
99
|
+
get("apps", name, "instances", instance, "files", *path)
|
100
|
+
end
|
101
|
+
alias :file :files
|
102
|
+
|
103
|
+
def update_app(name, payload)
|
104
|
+
put(payload, "apps", name, :json => nil)
|
105
|
+
end
|
106
|
+
|
107
|
+
def delete_app(name)
|
108
|
+
# TODO: no JSON response?
|
109
|
+
delete("apps", name)
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
def stats(name)
|
114
|
+
get("apps", name, "stats", nil => :json)
|
115
|
+
end
|
116
|
+
|
117
|
+
def check_resources(fingerprints)
|
118
|
+
post(fingerprints, "resources", :json => :json)
|
119
|
+
end
|
120
|
+
|
121
|
+
def upload_app(name, zipfile, resources = [])
|
122
|
+
payload = {
|
123
|
+
:_method => "put",
|
124
|
+
:resources => resources.to_json,
|
125
|
+
:multipart => true,
|
126
|
+
:application =>
|
127
|
+
if zipfile.is_a? File
|
128
|
+
zipfile
|
129
|
+
elsif zipfile.is_a? String
|
130
|
+
File.new(zipfile, "rb")
|
131
|
+
end
|
132
|
+
}
|
133
|
+
|
134
|
+
post(payload, "apps", name, "application")
|
135
|
+
rescue RestClient::ServerBrokeConnection
|
136
|
+
retry
|
137
|
+
end
|
138
|
+
|
139
|
+
# Services
|
140
|
+
def services
|
141
|
+
get("services", nil => :json)
|
142
|
+
end
|
143
|
+
|
144
|
+
def create_service(manifest)
|
145
|
+
post(manifest, "services", :json => :json)
|
146
|
+
end
|
147
|
+
|
148
|
+
def service(name)
|
149
|
+
get("services", name, nil => :json)
|
150
|
+
end
|
151
|
+
|
152
|
+
def delete_service(name)
|
153
|
+
delete("services", name, nil => :json)
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def handle_response(response, accept)
|
160
|
+
json = accept == :json
|
161
|
+
|
162
|
+
case response.code
|
163
|
+
when 200, 204, 302
|
164
|
+
if accept == :headers
|
165
|
+
return response.headers
|
166
|
+
end
|
167
|
+
|
168
|
+
if json
|
169
|
+
if response.code == 204
|
170
|
+
raise "Expected JSON response, got 204 No Content"
|
171
|
+
end
|
172
|
+
|
173
|
+
parse_json(response)
|
174
|
+
else
|
175
|
+
response
|
176
|
+
end
|
177
|
+
|
178
|
+
when 400, 403
|
179
|
+
info = parse_json(response)
|
180
|
+
raise CFoundry::Denied.new(403, info[:description])
|
181
|
+
|
182
|
+
when 404
|
183
|
+
raise CFoundry::NotFound
|
184
|
+
|
185
|
+
when 411, 500, 504
|
186
|
+
begin
|
187
|
+
raise_error(parse_json(response))
|
188
|
+
rescue JSON::ParserError
|
189
|
+
raise CFoundry::BadResponse.new(response.code, response)
|
190
|
+
end
|
191
|
+
|
192
|
+
else
|
193
|
+
raise CFoundry::BadResponse.new(response.code, response)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def raise_error(info)
|
198
|
+
case info[:code]
|
199
|
+
when 402
|
200
|
+
raise CFoundry::UploadFailed.new(info[:description])
|
201
|
+
else
|
202
|
+
raise CFoundry::APIError.new(info[:code], info[:description])
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|