cfoundry 0.2.0 → 0.2.1
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/lib/cfoundry/app.rb +166 -23
- data/lib/cfoundry/client.rb +45 -10
- data/lib/cfoundry/errors.rb +23 -7
- data/lib/cfoundry/restclient.rb +1 -1
- data/lib/cfoundry/service.rb +42 -5
- data/lib/cfoundry/user.rb +27 -5
- data/lib/cfoundry/version.rb +3 -2
- data/lib/cfoundry/zip.rb +9 -1
- metadata +4 -4
data/lib/cfoundry/app.rb
CHANGED
@@ -6,23 +6,67 @@ require "tmpdir"
|
|
6
6
|
require "cfoundry/zip"
|
7
7
|
|
8
8
|
module CFoundry
|
9
|
+
# Class for representing a user's application on a given target (via
|
10
|
+
# Client).
|
11
|
+
#
|
12
|
+
# Goes not guarantee that the app exists; used for both app creation and
|
13
|
+
# retrieval, as the attributes are all lazily retrieved. Setting attributes
|
14
|
+
# does not perform any requests; use #update! to commit your changes.
|
9
15
|
class App
|
16
|
+
# Application name.
|
10
17
|
attr_reader :name
|
11
18
|
|
19
|
+
# Application instance count.
|
20
|
+
attr_accessor :total_instances
|
21
|
+
|
22
|
+
# Services bound to the application.
|
23
|
+
attr_accessor :services
|
24
|
+
|
25
|
+
# Application environment variables.
|
26
|
+
attr_accessor :env
|
27
|
+
|
28
|
+
# Application memory limit.
|
29
|
+
attr_accessor :memory
|
30
|
+
|
31
|
+
# Application framework.
|
32
|
+
attr_accessor :framework
|
33
|
+
|
34
|
+
# Application runtime.
|
35
|
+
attr_accessor :runtime
|
36
|
+
|
37
|
+
# Application startup command.
|
38
|
+
#
|
39
|
+
# Used for standalone apps.
|
40
|
+
attr_accessor :command
|
41
|
+
|
42
|
+
# Application debug mode.
|
43
|
+
attr_accessor :debug_mode
|
44
|
+
|
45
|
+
# Application state.
|
46
|
+
attr_accessor :state
|
47
|
+
alias_method :status, :state
|
48
|
+
|
49
|
+
# URIs mapped to the application.
|
50
|
+
attr_accessor :uris
|
51
|
+
alias_method :urls, :uris
|
52
|
+
|
53
|
+
|
54
|
+
# Create an App object.
|
55
|
+
#
|
56
|
+
# You'll usually call Client#app instead
|
12
57
|
def initialize(name, client, manifest = nil)
|
13
58
|
@name = name
|
14
59
|
@client = client
|
15
60
|
@manifest = manifest
|
16
61
|
end
|
17
62
|
|
18
|
-
def inspect
|
63
|
+
def inspect # :nodoc:
|
19
64
|
"#<App '#@name'>"
|
20
65
|
end
|
21
66
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
67
|
+
# Delete the application from the target.
|
68
|
+
#
|
69
|
+
# Keeps the metadata, but clears target-specific state from it.
|
26
70
|
def delete!
|
27
71
|
@client.rest.delete_app(@name)
|
28
72
|
|
@@ -33,11 +77,15 @@ module CFoundry
|
|
33
77
|
end
|
34
78
|
end
|
35
79
|
|
80
|
+
# Create the application on the target.
|
81
|
+
#
|
82
|
+
# Call this after setting the various attributes.
|
36
83
|
def create!
|
37
84
|
@client.rest.create_app(@manifest.merge("name" => @name))
|
38
85
|
@manifest = nil
|
39
86
|
end
|
40
87
|
|
88
|
+
# Check if the application exists on the target.
|
41
89
|
def exists?
|
42
90
|
@client.rest.app(@name)
|
43
91
|
true
|
@@ -45,16 +93,19 @@ module CFoundry
|
|
45
93
|
false
|
46
94
|
end
|
47
95
|
|
96
|
+
# Retrieve all of the instances of the app, as Instance objects.
|
48
97
|
def instances
|
49
98
|
@client.rest.instances(@name).collect do |m|
|
50
99
|
Instance.new(@name, m["index"], @client, m)
|
51
100
|
end
|
52
101
|
end
|
53
102
|
|
103
|
+
# Retrieve application statistics, e.g. CPU load and memory usage.
|
54
104
|
def stats
|
55
105
|
@client.rest.stats(@name)
|
56
106
|
end
|
57
107
|
|
108
|
+
# Update application attributes. Does not restart the application.
|
58
109
|
def update!(what = {})
|
59
110
|
# TODO: hacky; can we not just set in meta field?
|
60
111
|
# we write to manifest["debug"] but read from manifest["meta"]["debug"]
|
@@ -64,19 +115,28 @@ module CFoundry
|
|
64
115
|
@manifest = nil
|
65
116
|
end
|
66
117
|
|
118
|
+
# Stop the application.
|
67
119
|
def stop!
|
68
120
|
update! "state" => "STOPPED"
|
69
121
|
end
|
70
122
|
|
123
|
+
# Start the application.
|
71
124
|
def start!
|
72
125
|
update! "state" => "STARTED"
|
73
126
|
end
|
74
127
|
|
128
|
+
# Restart the application.
|
75
129
|
def restart!
|
76
130
|
stop!
|
77
131
|
start!
|
78
132
|
end
|
79
133
|
|
134
|
+
# Determine application health.
|
135
|
+
#
|
136
|
+
# If all instances are running, returns "RUNNING". If only some are
|
137
|
+
# started, returns the precentage of them that are healthy.
|
138
|
+
#
|
139
|
+
# Otherwise, returns application's status.
|
80
140
|
def health
|
81
141
|
s = state
|
82
142
|
if s == "STARTED"
|
@@ -97,20 +157,26 @@ module CFoundry
|
|
97
157
|
end
|
98
158
|
end
|
99
159
|
|
160
|
+
# Check that all application instances are running.
|
100
161
|
def healthy?
|
101
162
|
# invalidate cache so the check is fresh
|
102
163
|
@manifest = nil
|
103
164
|
health == "RUNNING"
|
104
165
|
end
|
166
|
+
alias_method :running?, :healthy?
|
105
167
|
|
168
|
+
# Is the application stopped?
|
106
169
|
def stopped?
|
107
170
|
state == "STOPPED"
|
108
171
|
end
|
109
172
|
|
173
|
+
# Is the application started?
|
174
|
+
#
|
175
|
+
# Note that this does not imply that all instances are running. See
|
176
|
+
# #healthy?
|
110
177
|
def started?
|
111
178
|
state == "STARTED"
|
112
179
|
end
|
113
|
-
alias_method :running?, :started?
|
114
180
|
|
115
181
|
{ :total_instances => "instances",
|
116
182
|
:state => "state",
|
@@ -130,10 +196,12 @@ module CFoundry
|
|
130
196
|
end
|
131
197
|
end
|
132
198
|
|
199
|
+
# Shortcut for uris[0]
|
133
200
|
def uri
|
134
201
|
uris[0]
|
135
202
|
end
|
136
203
|
|
204
|
+
# Shortcut for uris = [x]
|
137
205
|
def uri=(x)
|
138
206
|
self.uris = [x]
|
139
207
|
end
|
@@ -141,12 +209,12 @@ module CFoundry
|
|
141
209
|
alias :url :uri
|
142
210
|
alias :url= :uri=
|
143
211
|
|
144
|
-
def framework
|
212
|
+
def framework # :nodoc:
|
145
213
|
manifest["staging"]["framework"] ||
|
146
214
|
manifest["staging"]["model"]
|
147
215
|
end
|
148
216
|
|
149
|
-
def framework=(v)
|
217
|
+
def framework=(v) # :nodoc:
|
150
218
|
@manifest ||= {}
|
151
219
|
@manifest["staging"] ||= {}
|
152
220
|
|
@@ -157,12 +225,12 @@ module CFoundry
|
|
157
225
|
end
|
158
226
|
end
|
159
227
|
|
160
|
-
def runtime
|
228
|
+
def runtime # :nodoc:
|
161
229
|
manifest["staging"]["runtime"] ||
|
162
230
|
manifest["staging"]["stack"]
|
163
231
|
end
|
164
232
|
|
165
|
-
def runtime=(v)
|
233
|
+
def runtime=(v) # :nodoc:
|
166
234
|
@manifest ||= {}
|
167
235
|
@manifest["staging"] ||= {}
|
168
236
|
|
@@ -173,39 +241,47 @@ module CFoundry
|
|
173
241
|
end
|
174
242
|
end
|
175
243
|
|
176
|
-
|
244
|
+
|
245
|
+
def command # :nodoc:
|
177
246
|
manifest["staging"]["command"]
|
178
247
|
end
|
179
248
|
|
180
|
-
def command=(v)
|
249
|
+
def command=(v) # :nodoc:
|
181
250
|
@manifest ||= {}
|
182
251
|
@manifest["staging"] ||= {}
|
183
252
|
@manifest["staging"]["command"] = v
|
184
253
|
end
|
185
254
|
|
186
|
-
|
255
|
+
|
256
|
+
def memory # :nodoc:
|
187
257
|
manifest["resources"]["memory"]
|
188
258
|
end
|
189
259
|
|
190
|
-
def memory=(v)
|
260
|
+
def memory=(v) # :nodoc:
|
191
261
|
@manifest ||= {}
|
192
262
|
@manifest["resources"] ||= {}
|
193
263
|
@manifest["resources"]["memory"] = v
|
194
264
|
end
|
195
265
|
|
196
|
-
|
197
|
-
|
266
|
+
|
267
|
+
def debug_mode # :nodoc:
|
268
|
+
manifest.fetch("debug") do
|
269
|
+
manifest["meta"] && manifest["meta"]["debug"]
|
270
|
+
end
|
198
271
|
end
|
199
272
|
|
200
|
-
def debug_mode=(v)
|
273
|
+
def debug_mode=(v) # :nodoc:
|
201
274
|
@manifest ||= {}
|
202
275
|
@manifest["debug"] = v
|
203
276
|
end
|
204
277
|
|
278
|
+
|
279
|
+
# Bind services to application.
|
205
280
|
def bind(*service_names)
|
206
281
|
update!("services" => services + service_names)
|
207
282
|
end
|
208
283
|
|
284
|
+
# Unbind services from application.
|
209
285
|
def unbind(*service_names)
|
210
286
|
update!("services" =>
|
211
287
|
services.reject { |s|
|
@@ -213,16 +289,46 @@ module CFoundry
|
|
213
289
|
})
|
214
290
|
end
|
215
291
|
|
292
|
+
# Retrieve file listing under path for the first instance of the application.
|
293
|
+
#
|
294
|
+
# [path]
|
295
|
+
# A sequence of strings representing path segments.
|
296
|
+
#
|
297
|
+
# For example, <code>files("foo", "bar")</code> for +foo/bar+.
|
216
298
|
def files(*path)
|
217
299
|
Instance.new(@name, 0, @client).files(*path)
|
218
300
|
end
|
219
301
|
|
302
|
+
# Retrieve file contents for the first instance of the application.
|
303
|
+
#
|
304
|
+
# [path]
|
305
|
+
# A sequence of strings representing path segments.
|
306
|
+
#
|
307
|
+
# For example, <code>files("foo", "bar")</code> for +foo/bar+.
|
220
308
|
def file(*path)
|
221
309
|
Instance.new(@name, 0, @client).file(*path)
|
222
310
|
end
|
223
311
|
|
312
|
+
# Default paths to exclude from upload payload.
|
313
|
+
#
|
314
|
+
# Value: .git, _darcs, .svn
|
224
315
|
UPLOAD_EXCLUDE = %w{.git _darcs .svn}
|
225
316
|
|
317
|
+
# Upload application's code to target. Do this after #create! and before
|
318
|
+
# #start!
|
319
|
+
#
|
320
|
+
# [path]
|
321
|
+
# A path pointing to either a directory, or a .jar, .war, or .zip
|
322
|
+
# file.
|
323
|
+
#
|
324
|
+
# If a .vmcignore file is detected under the given path, it will be used
|
325
|
+
# to exclude paths from the payload, similar to a .gitignore.
|
326
|
+
#
|
327
|
+
# [check_resources]
|
328
|
+
# If set to `false`, the entire payload will be uploaded
|
329
|
+
# without checking the resource cache.
|
330
|
+
#
|
331
|
+
# Only do this if you know what you're doing.
|
226
332
|
def upload(path, check_resources = true)
|
227
333
|
unless File.exist? path
|
228
334
|
raise "invalid application path '#{path}'"
|
@@ -248,6 +354,10 @@ module CFoundry
|
|
248
354
|
|
249
355
|
private
|
250
356
|
|
357
|
+
def manifest
|
358
|
+
@manifest ||= @client.rest.app(@name)
|
359
|
+
end
|
360
|
+
|
251
361
|
def prepare_package(path, to)
|
252
362
|
if path =~ /\.(jar|war|zip)$/
|
253
363
|
CFoundry::Zip.unpack(path, to)
|
@@ -291,6 +401,9 @@ module CFoundry
|
|
291
401
|
end
|
292
402
|
end
|
293
403
|
|
404
|
+
# Minimum size for an application payload to bother checking resources.
|
405
|
+
#
|
406
|
+
# Value: 64kb
|
294
407
|
RESOURCE_CHECK_LIMIT = 64 * 1024
|
295
408
|
|
296
409
|
def determine_resources(path)
|
@@ -349,9 +462,17 @@ module CFoundry
|
|
349
462
|
files && files.select { |f| File.socket? f }
|
350
463
|
end
|
351
464
|
|
465
|
+
# Class represnting a running instance of an application.
|
352
466
|
class Instance
|
353
|
-
|
467
|
+
# The application this instance belongs to.
|
468
|
+
attr_reader :app
|
354
469
|
|
470
|
+
# Application instance number.
|
471
|
+
attr_reader :index
|
472
|
+
|
473
|
+
# Create an Instance object.
|
474
|
+
#
|
475
|
+
# You'll usually call App#instances instead
|
355
476
|
def initialize(appname, index, client, manifest = {})
|
356
477
|
@app = appname
|
357
478
|
@index = index
|
@@ -359,33 +480,43 @@ module CFoundry
|
|
359
480
|
@manifest = manifest
|
360
481
|
end
|
361
482
|
|
362
|
-
def inspect
|
483
|
+
def inspect # :nodoc:
|
363
484
|
"#<App::Instance '#@app' \##@index>"
|
364
485
|
end
|
365
486
|
|
487
|
+
# Instance state.
|
366
488
|
def state
|
367
489
|
@manifest["state"]
|
368
490
|
end
|
369
491
|
alias_method :status, :state
|
370
492
|
|
493
|
+
# Instance start time.
|
371
494
|
def since
|
372
495
|
Time.at(@manifest["since"])
|
373
496
|
end
|
374
497
|
|
498
|
+
# Instance debugger data. If instance is in debug mode, returns a hash
|
499
|
+
# containing :ip and :port keys.
|
375
500
|
def debugger
|
376
501
|
return unless @manifest["debug_ip"] and @manifest["debug_port"]
|
377
|
-
|
378
|
-
|
502
|
+
|
503
|
+
{ :ip => @manifest["debug_ip"],
|
504
|
+
:port => @manifest["debug_port"]
|
379
505
|
}
|
380
506
|
end
|
381
507
|
|
508
|
+
# Instance console data. If instance has a console, returns a hash
|
509
|
+
# containing :ip and :port keys.
|
382
510
|
def console
|
383
511
|
return unless @manifest["console_ip"] and @manifest["console_port"]
|
384
|
-
|
385
|
-
|
512
|
+
|
513
|
+
{ :ip => @manifest["console_ip"],
|
514
|
+
:port => @manifest["console_port"]
|
386
515
|
}
|
387
516
|
end
|
388
517
|
|
518
|
+
# True if instance is starting or running, false if it's down or
|
519
|
+
# flapping.
|
389
520
|
def healthy?
|
390
521
|
case state
|
391
522
|
when "STARTING", "RUNNING"
|
@@ -395,12 +526,24 @@ module CFoundry
|
|
395
526
|
end
|
396
527
|
end
|
397
528
|
|
529
|
+
# Retrieve file listing under path for this instance.
|
530
|
+
#
|
531
|
+
# [path]
|
532
|
+
# A sequence of strings representing path segments.
|
533
|
+
#
|
534
|
+
# For example, <code>files("foo", "bar")</code> for +foo/bar+.
|
398
535
|
def files(*path)
|
399
536
|
@client.rest.files(@app, @index, *path).split("\n").collect do |entry|
|
400
537
|
path + [entry.split(/\s+/, 2)[0]]
|
401
538
|
end
|
402
539
|
end
|
403
540
|
|
541
|
+
# Retrieve file contents for this instance.
|
542
|
+
#
|
543
|
+
# [path]
|
544
|
+
# A sequence of strings representing path segments.
|
545
|
+
#
|
546
|
+
# For example, <code>files("foo", "bar")</code> for +foo/bar+.
|
404
547
|
def file(*path)
|
405
548
|
@client.rest.files(@app, @index, *path)
|
406
549
|
end
|
data/lib/cfoundry/client.rb
CHANGED
@@ -5,39 +5,53 @@ require "cfoundry/user"
|
|
5
5
|
|
6
6
|
|
7
7
|
module CFoundry
|
8
|
+
# The primary API entrypoint. Wraps RESTClient to provide nicer return
|
9
|
+
# values. Initialize with the target and, optionally, an auth token. These
|
10
|
+
# are the only two internal states.
|
8
11
|
class Client
|
9
|
-
attr_reader :rest
|
12
|
+
attr_reader :rest #:nodoc:
|
10
13
|
|
11
|
-
|
14
|
+
# Create a new Client for interfacing with the given target.
|
15
|
+
#
|
16
|
+
# A token may also be provided to skip the login step.
|
17
|
+
def initialize(target = "http://api.cloudfoundry.com", token = nil)
|
12
18
|
@rest = RESTClient.new(*args)
|
13
19
|
end
|
14
20
|
|
21
|
+
# The current target URL of the client.
|
15
22
|
def target
|
16
23
|
@rest.target
|
17
24
|
end
|
18
25
|
|
26
|
+
# Current proxy user. Usually nil.
|
19
27
|
def proxy
|
20
28
|
@rest.proxy
|
21
29
|
end
|
22
30
|
|
23
|
-
|
24
|
-
|
31
|
+
# Set the proxy user for the client. Must be authorized as an
|
32
|
+
# administrator for this to have any effect.
|
33
|
+
def proxy=(email)
|
34
|
+
@rest.proxy = email
|
25
35
|
end
|
26
36
|
|
37
|
+
# Is the client tracing API requests?
|
27
38
|
def trace
|
28
39
|
@rest.trace
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
|
-
|
42
|
+
# Set the tracing flag; if true, API requests and responses will be
|
43
|
+
# printed out.
|
44
|
+
def trace=(bool)
|
45
|
+
@rest.trace = bool
|
33
46
|
end
|
34
47
|
|
35
48
|
|
36
|
-
#
|
49
|
+
# Retrieve target metadata.
|
37
50
|
def info
|
38
51
|
@rest.info
|
39
52
|
end
|
40
53
|
|
54
|
+
# Retrieve available services. Returned as a Hash from vendor => metadata.
|
41
55
|
def system_services
|
42
56
|
services = {}
|
43
57
|
|
@@ -55,12 +69,13 @@ module CFoundry
|
|
55
69
|
services
|
56
70
|
end
|
57
71
|
|
72
|
+
# Retrieve available runtimes.
|
58
73
|
def system_runtimes
|
59
74
|
@rest.system_runtimes
|
60
75
|
end
|
61
76
|
|
62
77
|
|
63
|
-
#
|
78
|
+
# Retrieve user list. Admin-only.
|
64
79
|
def users
|
65
80
|
@rest.users.collect do |json|
|
66
81
|
CFoundry::User.new(
|
@@ -71,47 +86,67 @@ module CFoundry
|
|
71
86
|
end
|
72
87
|
end
|
73
88
|
|
89
|
+
# Construct a User object. The return value is lazy, and no requests are
|
90
|
+
# made from this alone.
|
91
|
+
#
|
92
|
+
# This should be used for both user creation (after calling User#create!)
|
93
|
+
# and retrieval.
|
74
94
|
def user(email)
|
75
95
|
CFoundry::User.new(email, self)
|
76
96
|
end
|
77
97
|
|
98
|
+
# Create a user on the target and return a User object representing them.
|
78
99
|
def register(email, password)
|
79
100
|
@rest.create_user(:email => email, :password => password)
|
80
101
|
user(email)
|
81
102
|
end
|
82
103
|
|
104
|
+
# Authenticate with the target. Sets the client token.
|
83
105
|
def login(email, password)
|
84
106
|
@rest.token =
|
85
107
|
@rest.create_token({ :password => password }, email)["token"]
|
86
108
|
end
|
87
109
|
|
110
|
+
# Clear client token. No requests are made for this.
|
88
111
|
def logout
|
89
112
|
@rest.token = nil
|
90
113
|
end
|
91
114
|
|
115
|
+
# Is an authentication token set on the client?
|
92
116
|
def logged_in?
|
93
117
|
!!@rest.token
|
94
118
|
end
|
95
119
|
|
96
120
|
|
97
|
-
#
|
121
|
+
# Retreive all of the current user's applications.
|
98
122
|
def apps
|
99
123
|
@rest.apps.collect do |json|
|
100
124
|
CFoundry::App.new(json["name"], self, json)
|
101
125
|
end
|
102
126
|
end
|
103
127
|
|
128
|
+
# Construct an App object. The return value is lazy, and no requests are
|
129
|
+
# made from this method alone.
|
130
|
+
#
|
131
|
+
# This should be used for both app creation (after calling App#create!)
|
132
|
+
# and retrieval.
|
104
133
|
def app(name)
|
105
134
|
CFoundry::App.new(name, self)
|
106
135
|
end
|
107
136
|
|
108
|
-
|
137
|
+
|
138
|
+
# Retrieve all of the current user's services.
|
109
139
|
def services
|
110
140
|
@rest.services.collect do |json|
|
111
141
|
CFoundry::Service.new(json["name"], self, json)
|
112
142
|
end
|
113
143
|
end
|
114
144
|
|
145
|
+
# Construct a Service object. The return value is lazy, and no requests are
|
146
|
+
# made from this method alone.
|
147
|
+
#
|
148
|
+
# This should be used for both service creation (after calling
|
149
|
+
# Service#create!) and retrieval.
|
115
150
|
def service(name)
|
116
151
|
CFoundry::Service.new(name, self)
|
117
152
|
end
|
data/lib/cfoundry/errors.rb
CHANGED
@@ -1,28 +1,32 @@
|
|
1
1
|
module CFoundry
|
2
|
+
# Exception representing errors returned by the API.
|
2
3
|
class APIError < RuntimeError
|
3
|
-
class << self
|
4
|
-
attr_reader :error_code, :description
|
4
|
+
class << self # :nodoc:
|
5
|
+
attr_reader :error_code, :description # :nodoc:
|
5
6
|
|
6
|
-
def setup(code, description = nil)
|
7
|
+
def setup(code, description = nil) # :nodoc:
|
7
8
|
@error_code = code
|
8
9
|
@description = description
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
13
|
+
# Create an APIError with a given error code and description.
|
12
14
|
def initialize(error_code = nil, description = nil)
|
13
15
|
@error_code = error_code
|
14
16
|
@description = description
|
15
17
|
end
|
16
18
|
|
19
|
+
# A number representing the error.
|
17
20
|
def error_code
|
18
21
|
@error_code || self.class.error_code
|
19
22
|
end
|
20
23
|
|
24
|
+
# A description of the error.
|
21
25
|
def description
|
22
26
|
@description || self.class.description
|
23
27
|
end
|
24
28
|
|
25
|
-
def to_s
|
29
|
+
def to_s # :nodoc:
|
26
30
|
if error_code
|
27
31
|
"#{error_code}: #{description}"
|
28
32
|
else
|
@@ -31,31 +35,40 @@ module CFoundry
|
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
38
|
+
# Generic exception thrown when accessing something that doesn't exist (e.g.
|
39
|
+
# getting info of unknown application).
|
34
40
|
class NotFound < APIError
|
35
41
|
setup(404, "entity not found or inaccessible")
|
36
42
|
end
|
37
43
|
|
44
|
+
# Lower-level exception for when we cannot connect to the target.
|
38
45
|
class TargetRefused < APIError
|
39
46
|
@description = "target refused connection"
|
40
47
|
|
48
|
+
# Error message.
|
41
49
|
attr_reader :message
|
42
50
|
|
51
|
+
# Message varies as this represents various network errors.
|
43
52
|
def initialize(message)
|
44
53
|
@message = message
|
45
54
|
end
|
46
55
|
|
47
|
-
def to_s
|
56
|
+
def to_s # :nodoc:
|
48
57
|
"#{description} (#{@message})"
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
61
|
+
# Exception raised when an application payload fails to upload.
|
52
62
|
class UploadFailed < APIError
|
53
63
|
setup(402)
|
54
64
|
end
|
55
65
|
|
66
|
+
# Exception raised when access is denied to something, either because the
|
67
|
+
# user is not logged in or is not an administrator.
|
56
68
|
class Denied < APIError
|
57
|
-
attr_reader :error_code, :description
|
69
|
+
attr_reader :error_code, :description # :nodoc:
|
58
70
|
|
71
|
+
# Initialize, with a default error code and message.
|
59
72
|
def initialize(
|
60
73
|
error_code = 200,
|
61
74
|
description = "Operation not permitted")
|
@@ -64,13 +77,16 @@ module CFoundry
|
|
64
77
|
end
|
65
78
|
end
|
66
79
|
|
80
|
+
# Exception raised when the response is unexpected; usually from a server
|
81
|
+
# error.
|
67
82
|
class BadResponse < StandardError
|
83
|
+
# Initialize, with the HTTP response code and body.
|
68
84
|
def initialize(code, body = nil)
|
69
85
|
@code = code
|
70
86
|
@body = body
|
71
87
|
end
|
72
88
|
|
73
|
-
def to_s
|
89
|
+
def to_s # :nodoc:
|
74
90
|
"target failed to handle our request due to an internal error (#{@code})"
|
75
91
|
end
|
76
92
|
end
|
data/lib/cfoundry/restclient.rb
CHANGED
data/lib/cfoundry/service.rb
CHANGED
@@ -1,29 +1,58 @@
|
|
1
1
|
module CFoundry
|
2
|
+
# Class for representing a user's service on a given target (via Client).
|
3
|
+
#
|
4
|
+
# Goes not guarantee that the service exists; used for both service creation
|
5
|
+
# and retrieval, as the attributes are all lazily retrieved. Setting
|
6
|
+
# attributes does not perform any requests; use #update! to commit your
|
7
|
+
# changes.
|
2
8
|
class Service
|
9
|
+
# Service name.
|
3
10
|
attr_reader :name
|
4
11
|
|
12
|
+
# Service type (e.g. key-value).
|
13
|
+
attr_accessor :type
|
14
|
+
|
15
|
+
# Service vendor (redis, mysql, etc.).
|
16
|
+
attr_accessor :vendor
|
17
|
+
|
18
|
+
# Service version.
|
19
|
+
attr_accessor :version
|
20
|
+
|
21
|
+
# Service properties.
|
22
|
+
attr_accessor :properties
|
23
|
+
|
24
|
+
# Service tier. Usually "free" for now.
|
25
|
+
attr_accessor :tier
|
26
|
+
|
27
|
+
# Service metadata.
|
28
|
+
attr_accessor :meta
|
29
|
+
|
30
|
+
# Create a Service object.
|
31
|
+
#
|
32
|
+
# You'll usually call Client#service instead.
|
5
33
|
def initialize(name, client, manifest = nil)
|
6
34
|
@name = name
|
7
35
|
@client = client
|
8
36
|
@manifest = manifest
|
9
37
|
end
|
10
38
|
|
11
|
-
def inspect
|
39
|
+
def inspect # :nodoc:
|
12
40
|
"#<Service '#@name'>"
|
13
41
|
end
|
14
42
|
|
15
|
-
|
16
|
-
@manifest ||= @client.rest.service(@name)
|
17
|
-
end
|
18
|
-
|
43
|
+
# Delete the service from the target.
|
19
44
|
def delete!
|
20
45
|
@client.rest.delete_service(@name)
|
21
46
|
end
|
22
47
|
|
48
|
+
# Create the service on the target.
|
49
|
+
#
|
50
|
+
# Call this after setting the various attributes.
|
23
51
|
def create!
|
24
52
|
@client.rest.create_service(@manifest.merge("name" => @name))
|
25
53
|
end
|
26
54
|
|
55
|
+
# Check if the service exists on the target.
|
27
56
|
def exists?
|
28
57
|
@client.rest.service(@name)
|
29
58
|
true
|
@@ -31,10 +60,12 @@ module CFoundry
|
|
31
60
|
false
|
32
61
|
end
|
33
62
|
|
63
|
+
# Timestamp of when the service was created.
|
34
64
|
def created
|
35
65
|
Time.at(meta["created"])
|
36
66
|
end
|
37
67
|
|
68
|
+
# Timestamp of when the service was last updated.
|
38
69
|
def updated
|
39
70
|
Time.at(meta["updated"])
|
40
71
|
end
|
@@ -55,5 +86,11 @@ module CFoundry
|
|
55
86
|
@manifest[attr] = v
|
56
87
|
end
|
57
88
|
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def manifest
|
93
|
+
@manifest ||= @client.rest.service(@name)
|
94
|
+
end
|
58
95
|
end
|
59
96
|
end
|
data/lib/cfoundry/user.rb
CHANGED
@@ -1,34 +1,46 @@
|
|
1
1
|
module CFoundry
|
2
|
+
# Class for representing a user on a given target (via Client).
|
3
|
+
#
|
4
|
+
# Goes not guarantee that the user exists; used for both user creation and
|
5
|
+
# retrieval, as the attributes are all lazily retrieved. Setting attributes
|
6
|
+
# does not perform any requests; use #update! to commit your changes.
|
2
7
|
class User
|
8
|
+
# User email.
|
3
9
|
attr_reader :email
|
4
10
|
|
11
|
+
|
12
|
+
# Create a User object.
|
13
|
+
#
|
14
|
+
# You'll usually call Client#user instead
|
5
15
|
def initialize(email, client, manifest = nil)
|
6
16
|
@email = email
|
7
17
|
@client = client
|
8
18
|
@manifest = manifest
|
9
19
|
end
|
10
20
|
|
11
|
-
def inspect
|
21
|
+
def inspect # :nodoc:
|
12
22
|
"#<User '#@email'>"
|
13
23
|
end
|
14
24
|
|
15
|
-
|
16
|
-
@manifest ||= @client.rest.user(@email)
|
17
|
-
end
|
18
|
-
|
25
|
+
# Delete the user from the target.
|
19
26
|
def delete!
|
20
27
|
@client.rest.delete_user(@email)
|
21
28
|
end
|
22
29
|
|
30
|
+
# Create the user on the target.
|
31
|
+
#
|
32
|
+
# Call this after setting the various attributes.
|
23
33
|
def create!
|
24
34
|
@client.rest.create_user(@manifest.merge("email" => @email))
|
25
35
|
end
|
26
36
|
|
37
|
+
# Update user attributes.
|
27
38
|
def update!(what = {})
|
28
39
|
@client.rest.update_user(@email, manifest.merge(what))
|
29
40
|
@manifest = nil
|
30
41
|
end
|
31
42
|
|
43
|
+
# Check if the user exists on the target.
|
32
44
|
def exists?
|
33
45
|
@client.rest.user(@email)
|
34
46
|
true
|
@@ -36,12 +48,22 @@ module CFoundry
|
|
36
48
|
false
|
37
49
|
end
|
38
50
|
|
51
|
+
# Check if the user is an administrator.
|
39
52
|
def admin?
|
40
53
|
manifest["admin"]
|
41
54
|
end
|
42
55
|
|
56
|
+
# Set the user's password.
|
57
|
+
#
|
58
|
+
# Call #update! after using this.
|
43
59
|
def password=(str)
|
44
60
|
manifest["password"] = str
|
45
61
|
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def manifest
|
66
|
+
@manifest ||= @client.rest.user(@email)
|
67
|
+
end
|
46
68
|
end
|
47
69
|
end
|
data/lib/cfoundry/version.rb
CHANGED
data/lib/cfoundry/zip.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require "zip/zipfilesystem"
|
2
2
|
|
3
3
|
module CFoundry
|
4
|
+
# Generic Zpi API. Uses rubyzip underneath, but may be changed in the future
|
5
|
+
# to use system zip command if necessary.
|
4
6
|
module Zip
|
7
|
+
# Directory entries to exclude from packing.
|
5
8
|
PACK_EXCLUSION_GLOBS = ['..', '.', '*~', '#*#', '*.log']
|
6
9
|
|
7
10
|
module_function
|
8
11
|
|
12
|
+
# Get the entries in the zip file. Returns an array of the entire
|
13
|
+
# contents, recursively (not just top-level).
|
9
14
|
def entry_lines(file)
|
10
15
|
entries = []
|
11
16
|
::Zip::ZipFile.foreach(file) do |zentry|
|
@@ -14,6 +19,7 @@ module CFoundry
|
|
14
19
|
entries
|
15
20
|
end
|
16
21
|
|
22
|
+
# Unpack a zip +file+ to directory +dest+.
|
17
23
|
def unpack(file, dest)
|
18
24
|
::Zip::ZipFile.foreach(file) do |zentry|
|
19
25
|
epath = "#{dest}/#{zentry}"
|
@@ -23,6 +29,7 @@ module CFoundry
|
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
32
|
+
# Determine what files in +dir+ to pack.
|
26
33
|
def files_to_pack(dir)
|
27
34
|
Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).select do |f|
|
28
35
|
File.exists?(f) &&
|
@@ -32,6 +39,7 @@ module CFoundry
|
|
32
39
|
end
|
33
40
|
end
|
34
41
|
|
42
|
+
# Package directory +dir+ as file +zipfile+.
|
35
43
|
def pack(dir, zipfile)
|
36
44
|
files = files_to_pack(dir)
|
37
45
|
return false if files.empty?
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfoundry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alex Suraci
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-06-02 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rest-client
|