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.
@@ -5,16 +5,19 @@ require "tmpdir"
5
5
 
6
6
  require "cfoundry/zip"
7
7
 
8
- module CFoundry
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
- # Goes not guarantee that the app exists; used for both app creation and
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
- attr_reader :name
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.rest.delete_app(@name)
75
+ @client.base.delete_app(@name)
73
76
 
74
77
  if @manifest
75
- @manifest.delete "meta"
76
- @manifest.delete "version"
77
- @manifest.delete "state"
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.rest.create_app(@manifest.merge("name" => @name))
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.rest.app(@name)
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.rest.instances(@name).collect do |m|
100
- Instance.new(@name, m["index"], @client, 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.rest.stats(@name)
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
- # TODO: hacky; can we not just set in meta field?
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.rest.update_app(@name, manifest.merge(what))
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! "state" => "STOPPED"
125
+ update! :state => "STOPPED"
122
126
  end
123
127
 
124
128
  # Start the application.
125
129
  def start!
126
- update! "state" => "STARTED"
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["runningInstances"]
145
- expected = manifest["instances"]
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 => "instances",
183
- :state => "state",
184
- :status => "state",
185
- :services => "services",
186
- :uris => "uris",
187
- :urls => "uris",
188
- :env => "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
- manifest["staging"]["framework"] ||
216
- manifest["staging"]["model"]
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["staging"] ||= {}
228
+ @manifest[:staging] ||= {}
222
229
 
223
- if @manifest["staging"].key? "model"
224
- @manifest["staging"]["model"] = v
230
+ if @manifest[:staging].key? :model
231
+ @manifest[:staging][:model] = v
225
232
  else
226
- @manifest["staging"]["framework"] = v
233
+ @manifest[:staging][:framework] = v
227
234
  end
228
235
  end
229
236
 
230
237
  # Application runtime.
231
238
  def runtime
232
- manifest["staging"]["runtime"] ||
233
- manifest["staging"]["stack"]
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["staging"] ||= {}
248
+ @manifest[:staging] ||= {}
239
249
 
240
- if @manifest["staging"].key? "stack"
241
- @manifest["staging"]["stack"] = v
250
+ if @manifest[:staging].key? :stack
251
+ @manifest[:staging][:stack] = v
242
252
  else
243
- @manifest["staging"]["runtime"] = v
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["staging"]["command"]
262
+ manifest[:staging][:command] ||
263
+ manifest[:meta][:command]
253
264
  end
254
265
 
255
266
  def command=(v) # :nodoc:
256
267
  @manifest ||= {}
257
- @manifest["staging"] ||= {}
258
- @manifest["staging"]["command"] = v
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["resources"]["memory"]
275
+ manifest[:resources][:memory]
265
276
  end
266
277
 
267
278
  def memory=(v) # :nodoc:
268
279
  @manifest ||= {}
269
- @manifest["resources"] ||= {}
270
- @manifest["resources"]["memory"] = v
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("debug") do
277
- manifest["meta"] && manifest["meta"]["debug"]
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["debug"] = v
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!("services" => services + service_names)
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!("services" =>
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.rest.upload_app(@name, packed && zipfile, resources || [])
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.rest.app(@name)
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.rest.check_resources(fingerprints)
444
+ resources = @client.base.check_resources(fingerprints)
434
445
 
435
446
  resources.each do |resource|
436
- FileUtils.rm_f resource["fn"]
437
- resource["fn"].sub!("#{path}/", '')
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["state"]
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["since"])
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["debug_ip"] and @manifest["debug_port"]
517
+ return unless @manifest[:debug_ip] and @manifest[:debug_port]
507
518
 
508
- { :ip => @manifest["debug_ip"],
509
- :port => @manifest["debug_port"]
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["console_ip"] and @manifest["console_port"]
527
+ return unless @manifest[:console_ip] and @manifest[:console_port]
517
528
 
518
- { :ip => @manifest["console_ip"],
519
- :port => @manifest["console_port"]
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.rest.files(@app, @index, *path).split("\n").collect do |entry|
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.rest.files(@app, @index, *path)
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