cfoundry 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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