cfoundry 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -34,5 +34,13 @@ module CFoundry
34
34
  def to_hash
35
35
  @hash
36
36
  end
37
+
38
+ def to_s
39
+ @hash.to_s
40
+ end
41
+
42
+ def inspect
43
+ @hash.inspect
44
+ end
37
45
  end
38
46
  end
@@ -1,18 +1,25 @@
1
1
  require "cfoundry/baseclient"
2
2
 
3
+ require "cfoundry/v1/app"
4
+ require "cfoundry/v1/framework"
5
+ require "cfoundry/v1/runtime"
6
+ require "cfoundry/v1/service"
7
+ require "cfoundry/v1/service_instance"
8
+ require "cfoundry/v1/user"
9
+ require "cfoundry/v1/base"
3
10
  require "cfoundry/v1/client"
4
11
 
5
12
  require "cfoundry/v2/app"
6
13
  require "cfoundry/v2/framework"
7
- require "cfoundry/v2/organization"
8
14
  require "cfoundry/v2/runtime"
9
15
  require "cfoundry/v2/service"
10
16
  require "cfoundry/v2/service_binding"
11
17
  require "cfoundry/v2/service_instance"
12
18
  require "cfoundry/v2/service_plan"
13
19
  require "cfoundry/v2/service_auth_token"
14
- require "cfoundry/v2/space"
15
20
  require "cfoundry/v2/user"
21
+ require "cfoundry/v2/organization"
22
+ require "cfoundry/v2/space"
16
23
  require "cfoundry/v2/domain"
17
24
  require "cfoundry/v2/route"
18
25
  require "cfoundry/v2/base"
@@ -1,31 +1,54 @@
1
+ require "tmpdir"
1
2
  require "fileutils"
2
3
  require "pathname"
3
4
  require "digest/sha1"
4
5
 
6
+ require "cfoundry/zip"
7
+
5
8
  module CFoundry
6
9
  module UploadHelpers
7
10
  # Default paths to exclude from upload payload.
8
11
  UPLOAD_EXCLUDE = %w{.git _darcs .svn}
9
12
 
10
- def make_fingerprints(path)
11
- fingerprints = []
12
- total_size = 0
13
+ # Minimum size for an application payload to bother checking resources.
14
+ RESOURCE_CHECK_LIMIT = 64 * 1024
15
+
16
+ # Upload application's code to target. Do this after #create! and before
17
+ # #start!
18
+ #
19
+ # [path]
20
+ # A path pointing to either a directory, or a .jar, .war, or .zip
21
+ # file.
22
+ #
23
+ # If a .vmcignore file is detected under the given path, it will be used
24
+ # to exclude paths from the payload, similar to a .gitignore.
25
+ #
26
+ # [check_resources]
27
+ # If set to `false`, the entire payload will be uploaded
28
+ # without checking the resource cache.
29
+ #
30
+ # Only do this if you know what you're doing.
31
+ def upload(path, check_resources = true)
32
+ unless File.exist? path
33
+ raise CFoundry::Error, "Invalid application path '#{path}'"
34
+ end
13
35
 
14
- Dir.glob("#{path}/**/*", File::FNM_DOTMATCH) do |filename|
15
- next if File.directory?(filename)
36
+ zipfile = "#{Dir.tmpdir}/#{@guid}.zip"
37
+ tmpdir = "#{Dir.tmpdir}/.vmc_#{@guid}_files"
16
38
 
17
- size = File.size(filename)
39
+ FileUtils.rm_f(zipfile)
40
+ FileUtils.rm_rf(tmpdir)
18
41
 
19
- total_size += size
42
+ prepare_package(path, tmpdir)
20
43
 
21
- fingerprints << {
22
- :size => size,
23
- :sha1 => Digest::SHA1.file(filename).hexdigest,
24
- :fn => filename
25
- }
26
- end
44
+ resources = determine_resources(tmpdir) if check_resources
27
45
 
28
- [fingerprints, total_size]
46
+ packed = CFoundry::Zip.pack(tmpdir, zipfile)
47
+
48
+ @client.base.upload_app(@guid, packed && zipfile, resources || [])
49
+ ensure
50
+ FileUtils.rm_f(zipfile) if zipfile
51
+ FileUtils.rm_rf(tmpdir) if tmpdir
29
52
  end
30
53
 
31
54
  def prepare_package(path, to)
@@ -97,5 +120,41 @@ module CFoundry
97
120
  files = Dir.glob("#{path}/**/*", File::FNM_DOTMATCH)
98
121
  files && files.select { |f| File.socket? f }
99
122
  end
123
+
124
+ def determine_resources(path)
125
+ fingerprints, total_size = make_fingerprints(path)
126
+
127
+ return if total_size <= RESOURCE_CHECK_LIMIT
128
+
129
+ resources = @client.base.resource_match(fingerprints)
130
+
131
+ resources.each do |resource|
132
+ FileUtils.rm_f resource[:fn]
133
+ resource[:fn].sub!("#{path}/", "")
134
+ end
135
+
136
+ resources
137
+ end
138
+
139
+ def make_fingerprints(path)
140
+ fingerprints = []
141
+ total_size = 0
142
+
143
+ Dir.glob("#{path}/**/*", File::FNM_DOTMATCH) do |filename|
144
+ next if File.directory?(filename)
145
+
146
+ size = File.size(filename)
147
+
148
+ total_size += size
149
+
150
+ fingerprints << {
151
+ :size => size,
152
+ :sha1 => Digest::SHA1.file(filename).hexdigest,
153
+ :fn => filename
154
+ }
155
+ end
156
+
157
+ [fingerprints, total_size]
158
+ end
100
159
  end
101
160
  end
@@ -1,123 +1,99 @@
1
- require "tmpdir"
2
-
3
- require "cfoundry/zip"
4
1
  require "cfoundry/upload_helpers"
5
2
  require "cfoundry/chatty_hash"
6
3
 
7
- require "cfoundry/v1/framework"
8
- require "cfoundry/v1/runtime"
4
+ require "cfoundry/v1/model"
9
5
 
10
6
  module CFoundry::V1
11
- # Class for representing a user's application on a given target (via
12
- # Client).
13
- #
14
- # Does not guarantee that the app exists; used for both app creation and
15
- # retrieval, as the attributes are all lazily retrieved. Setting attributes
16
- # does not perform any requests; use #update! to commit your changes.
17
- class App
7
+ class App < Model
18
8
  include CFoundry::UploadHelpers
19
9
 
20
- # Application name.
21
- attr_accessor :name
10
+ attribute :name, :string, :guid => true
11
+ attribute :instances, :integer
12
+ attribute :state, :string
13
+ attribute :created, :integer, :at => [:meta, :created]
14
+ attribute :version, :integer, :at => [:meta, :version]
15
+ attribute :framework, :string, :at => [:staging, :model]
16
+ attribute :runtime, :string, :at => [:staging, :stack]
17
+ attribute :command, :string, :at => [:staging, :command]
18
+ attribute :memory, :integer, :at => [:resources, :memory]
19
+ attribute :disk, :integer, :at => [:resources, :disk]
20
+ attribute :fds, :integer, :at => [:resources, :fds]
21
+ attribute :env, [:string], :default => []
22
+ attribute :uris, [:string], :default => []
23
+ attribute :services, [:string], :default => []
22
24
 
23
- # Application instance count.
24
- attr_accessor :total_instances
25
+ attribute :console, :boolean, :default => false,
26
+ :read => [:meta, :console], :write => :console
25
27
 
26
- # Services bound to the application.
27
- attr_accessor :services
28
+ attribute :debug, :string, :default => nil, :read => [:meta, :debug],
29
+ :write => :debug
28
30
 
29
- # Application environment variables.
30
- attr_accessor :env
31
+ attribute :running_instances, :integer, :read => :runningInstances,
32
+ :read_only => true
31
33
 
32
- # Application memory limit.
33
- attr_accessor :memory
34
34
 
35
- # Application framework.
36
- attr_accessor :framework
35
+ define_client_methods
37
36
 
38
- # Application runtime.
39
- attr_accessor :runtime
40
37
 
41
- # Application startup command.
42
- #
43
- # Used for standalone apps.
44
- attr_accessor :command
38
+ alias_method :total_instances, :instances
39
+ alias_method :total_instances=, :instances=
40
+
41
+ alias_method :debug_mode, :debug
42
+ alias_method :debug_mode=, :debug=
43
+
44
+ alias_method :framework_name, :framework
45
+ alias_method :framework_name=, :framework=
46
+
47
+ alias_method :runtime_name, :runtime
48
+ alias_method :runtime_name=, :runtime=
45
49
 
46
- # Application debug mode.
47
- attr_accessor :debug_mode
50
+ alias_method :service_names, :services
51
+ alias_method :service_names=, :services=
48
52
 
49
- # Application state.
50
- attr_accessor :state
51
53
  alias_method :status, :state
54
+ alias_method :status=, :state=
52
55
 
53
- # URIs mapped to the application.
54
- attr_accessor :uris
55
56
  alias_method :urls, :uris
57
+ alias_method :urls=, :uris=
56
58
 
59
+ alias_method :env_array, :env
60
+ alias_method :env_array=, :env=
57
61
 
58
- # Create an App object.
59
- #
60
- # You'll usually call Client#app instead
61
- def initialize(name, client, manifest = nil)
62
- @name = name
63
- @client = client
64
- @manifest = manifest
65
- @diff = {}
62
+ def framework
63
+ @client.framework(framework_name)
66
64
  end
67
65
 
68
- # Show string representing the application.
69
- def inspect
70
- "#<App '#@name'>"
66
+ def framework=(obj)
67
+ set_named(:framework, obj)
71
68
  end
72
69
 
73
- # Basic equality test by name.
74
- def eql?(other)
75
- other.is_a?(self.class) && other.name == @name
70
+ def runtime
71
+ @client.runtime(runtime_name)
76
72
  end
77
- alias :== :eql?
78
-
79
- # Delete the application from the target.
80
- #
81
- # Keeps the metadata, but clears target-specific state from it.
82
- def delete!
83
- @client.base.delete_app(@name)
84
73
 
85
- if @manifest
86
- @diff = read_manifest
87
- @manifest = nil
88
- end
74
+ def runtime=(obj)
75
+ set_named(:runtime, obj)
89
76
  end
90
77
 
91
- # Create the application on the target.
92
- #
93
- # Call this after setting the various attributes.
94
- def create!
95
- @client.base.create_app(create_manifest)
96
- @diff = {}
78
+ def services
79
+ service_names.collect { |name| @client.service_instance(name) }
97
80
  end
98
81
 
99
- def invalidate!
100
- @manifest = nil
82
+ def services=(objs)
83
+ set_many_named(:service, objs)
101
84
  end
102
85
 
103
- # Check if the application exists on the target.
104
- def exists?
105
- @client.base.app(@name)
106
- true
107
- rescue CFoundry::AppNotFound
108
- false
109
- end
110
86
 
111
87
  # Retrieve all of the instances of the app, as Instance objects.
112
88
  def instances
113
- @client.base.instances(@name).collect do |m|
89
+ @client.base.instances(@guid).collect do |m|
114
90
  Instance.new(self, m[:index].to_s, @client, m)
115
91
  end
116
92
  end
117
93
 
118
94
  # Retrieve crashed instances
119
95
  def crashes
120
- @client.base.crashes(@name).collect do |i|
96
+ @client.base.crashes(@guid).collect do |i|
121
97
  Instance.new(self, i[:instance].to_s, @client, i)
122
98
  end
123
99
  end
@@ -126,35 +102,23 @@ module CFoundry::V1
126
102
  def stats
127
103
  stats = {}
128
104
 
129
- @client.base.stats(@name).each do |idx, info|
105
+ @client.base.stats(@guid).each do |idx, info|
130
106
  stats[idx.to_s] = info
131
107
  end
132
108
 
133
109
  stats
134
110
  end
135
111
 
136
- # Update application attributes. Does not restart the application.
137
- def update!(what = {})
138
- what.each do |k, v|
139
- send(:"#{k}=", v)
140
- end
141
-
142
- @client.base.update_app(@name, update_manifest)
143
-
144
- @manifest = nil
145
- @diff = {}
146
-
147
- self
148
- end
149
-
150
112
  # Stop the application.
151
113
  def stop!
152
- update! :state => "STOPPED"
114
+ self.state = "STOPPED"
115
+ update!
153
116
  end
154
117
 
155
118
  # Start the application.
156
119
  def start!
157
- update! :state => "STARTED"
120
+ self.state = "STARTED"
121
+ update!
158
122
  end
159
123
 
160
124
  # Restart the application.
@@ -193,7 +157,7 @@ module CFoundry::V1
193
157
  # Check that all application instances are running.
194
158
  def healthy?
195
159
  # invalidate cache so the check is fresh
196
- @manifest = nil
160
+ invalidate!
197
161
  health == "RUNNING"
198
162
  end
199
163
  alias_method :running?, :healthy?
@@ -212,40 +176,6 @@ module CFoundry::V1
212
176
  end
213
177
 
214
178
 
215
- { :total_instances => :instances,
216
- :running_instances => :running_instances,
217
- :runtime_name => :runtime,
218
- :framework_name => :framework,
219
- :service_names => :services,
220
- :env_array => :env,
221
- :state => :state,
222
- :status => :state,
223
- :uris => :uris,
224
- :urls => :uris,
225
- :command => :command,
226
- :console => :console,
227
- :memory => :memory,
228
- :disk => :disk,
229
- :fds => :fds,
230
- :debug_mode => :debug,
231
- :version => :version,
232
- :meta_version => :meta_version,
233
- :created => :created
234
- }.each do |meth, attr|
235
- define_method(meth) do
236
- if @diff.key?(attr)
237
- @diff[attr]
238
- else
239
- read_manifest[attr]
240
- end
241
- end
242
-
243
- define_method(:"#{meth}=") do |v|
244
- @diff[attr] = v
245
- end
246
- end
247
-
248
-
249
179
  # Shortcut for uris[0]
250
180
  def uri
251
181
  uris[0]
@@ -256,28 +186,8 @@ module CFoundry::V1
256
186
  self.uris = [x]
257
187
  end
258
188
 
259
- alias :url :uri
260
- alias :url= :uri=
261
-
262
- # Application framework.
263
- def framework
264
- Framework.new(framework_name)
265
- end
266
-
267
- def framework=(v) # :nodoc:
268
- v = v.name if v.is_a?(Framework)
269
- self.framework_name = v
270
- end
271
-
272
- # Application runtime.
273
- def runtime
274
- Runtime.new(runtime_name)
275
- end
276
-
277
- def runtime=(v) # :nodoc:
278
- v = v.name if v.is_a?(Runtime)
279
- self.runtime_name = v
280
- end
189
+ alias_method :url, :uri
190
+ alias_method :url=, :uri=
281
191
 
282
192
  def env
283
193
  e = env_array || []
@@ -312,15 +222,14 @@ module CFoundry::V1
312
222
 
313
223
  # Bind services to application.
314
224
  def bind(*instances)
315
- update!(:services => services + instances)
225
+ self.services += instances
226
+ update!
316
227
  end
317
228
 
318
229
  # Unbind services from application.
319
230
  def unbind(*instances)
320
- update!(:services =>
321
- services.reject { |s|
322
- instances.any? { |i| i.name == s.name }
323
- })
231
+ self.services -= instances
232
+ update!
324
233
  end
325
234
 
326
235
  def binds?(instance)
@@ -347,139 +256,28 @@ module CFoundry::V1
347
256
  Instance.new(self, "0", @client).file(*path)
348
257
  end
349
258
 
350
- # Upload application's code to target. Do this after #create! and before
351
- # #start!
352
- #
353
- # [path]
354
- # A path pointing to either a directory, or a .jar, .war, or .zip
355
- # file.
356
- #
357
- # If a .vmcignore file is detected under the given path, it will be used
358
- # to exclude paths from the payload, similar to a .gitignore.
359
- #
360
- # [check_resources]
361
- # If set to `false`, the entire payload will be uploaded
362
- # without checking the resource cache.
363
- #
364
- # Only do this if you know what you're doing.
365
- def upload(path, check_resources = true)
366
- unless File.exist? path
367
- raise CFoundry::Error, "Invalid application path '#{path}'"
368
- end
369
-
370
- zipfile = "#{Dir.tmpdir}/#{@name}.zip"
371
- tmpdir = "#{Dir.tmpdir}/.vmc_#{@name}_files"
372
-
373
- FileUtils.rm_f(zipfile)
374
- FileUtils.rm_rf(tmpdir)
375
-
376
- prepare_package(path, tmpdir)
377
-
378
- resources = determine_resources(tmpdir) if check_resources
379
-
380
- packed = CFoundry::Zip.pack(tmpdir, zipfile)
381
-
382
- @client.base.upload_app(@name, packed && zipfile, resources || [])
383
- ensure
384
- FileUtils.rm_f(zipfile) if zipfile
385
- FileUtils.rm_rf(tmpdir) if tmpdir
386
- end
387
-
388
259
  private
389
260
 
390
- ATTR_MAP = {
391
- :instances => :instances,
392
- :state => :state,
393
- :env => :env,
394
- :uris => :uris,
395
- :services => :services,
396
- :debug => :debug,
397
- :console => :console,
398
-
399
- :framework => [:staging, :model],
400
- :runtime => [:staging, :stack],
401
- :command => [:staging, :command],
402
-
403
- :meta_version => [:meta, :version],
404
- :created => [:meta, :created],
405
-
406
- :memory => [:resources, :memory],
407
- :disk => [:resources, :disk],
408
- :fds => [:resources, :fds]
409
- }
410
-
411
- def manifest
412
- @manifest ||= @client.base.app(@name)
413
- end
414
-
415
- def write_manifest(body = read_manifest, onto = {})
416
- onto[:name] = @name
261
+ def set_named(attr, val)
262
+ res = send(:"#{attr}_name=", val.name)
417
263
 
418
- ATTR_MAP.each do |what, where|
419
- if body.key?(what)
420
- put(body[what], onto, Array(where))
421
- end
422
- end
423
-
424
- onto
425
- end
426
-
427
- def put(what, where, path)
428
- if path.size == 1
429
- where[path.last] = what
430
- elsif name = path.first
431
- where[name] ||= {}
432
- put(what, where[name], path[1..-1])
264
+ if @changes.key?(attr)
265
+ old, new = @changes[attr]
266
+ @changes[attr] = [@client.send(attr, old), val]
433
267
  end
434
268
 
435
- nil
436
- end
437
-
438
- def update_manifest
439
- write_manifest(@diff, write_manifest)
440
- end
441
-
442
- def create_manifest
443
- write_manifest(@diff)
269
+ res
444
270
  end
445
271
 
446
- def read_manifest
447
- { :name => @name,
448
- :instances => manifest[:instances],
449
- :running_instances => manifest[:runningInstances],
450
- :state => manifest[:state],
451
- :env => manifest[:env],
452
- :uris => manifest[:uris],
453
- :version => manifest[:version],
454
- :services => manifest[:services],
455
- :framework => manifest[:staging][:model],
456
- :runtime => manifest[:staging][:stack],
457
- :console => manifest[:meta][:console],
458
- :meta_version => manifest[:meta][:version],
459
- :debug => manifest[:meta][:debug],
460
- :created => manifest[:meta][:created],
461
- :memory => manifest[:resources][:memory],
462
- :disk => manifest[:resources][:disk],
463
- :fds => manifest[:resources][:fds]
464
- }
465
- end
466
-
467
- # Minimum size for an application payload to bother checking resources.
468
- RESOURCE_CHECK_LIMIT = 64 * 1024
469
-
470
- def determine_resources(path)
471
- fingerprints, total_size = make_fingerprints(path)
472
-
473
- return if total_size <= RESOURCE_CHECK_LIMIT
474
-
475
- resources = @client.base.check_resources(fingerprints)
272
+ def set_many_named(attr, vals)
273
+ res = send(:"#{attr}_names=", val.collect(&:name))
476
274
 
477
- resources.each do |resource|
478
- FileUtils.rm_f resource[:fn]
479
- resource[:fn].sub!("#{path}/", "")
275
+ if @changes.key?(attr)
276
+ old, new = @changes[attr]
277
+ @changes[attr] = [old.collect { |o| @client.send(attr, o) }, vals]
480
278
  end
481
279
 
482
- resources
280
+ vals
483
281
  end
484
282
 
485
283
  # Class represnting a running instance of an application.
@@ -547,24 +345,12 @@ module CFoundry::V1
547
345
  end
548
346
  end
549
347
 
550
- # Retrieve file listing under path for this instance.
551
- #
552
- # [path]
553
- # A sequence of strings representing path segments.
554
- #
555
- # For example, <code>files("foo", "bar")</code> for +foo/bar+.
556
348
  def files(*path)
557
349
  @client.base.files(@app.name, @id, *path).split("\n").collect do |entry|
558
350
  path + [entry.split(/\s+/, 2)[0]]
559
351
  end
560
352
  end
561
353
 
562
- # Retrieve file contents for this instance.
563
- #
564
- # [path]
565
- # A sequence of strings representing path segments.
566
- #
567
- # For example, <code>files("foo", "bar")</code> for +foo/bar+.
568
354
  def file(*path)
569
355
  @client.base.files(@app.name, @id, *path)
570
356
  end