cfoundry 0.2.2 → 0.3.0
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/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
|