cfoundry 0.4.8 → 0.4.9

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.
@@ -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