ncfoundry 4.9.2
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +11 -0
- data/Checkfile +2 -0
- data/Gemfile +3 -0
- data/LICENSE +987 -0
- data/NOTICE +10 -0
- data/README.md +9 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/cfoundry.gemspec +41 -0
- data/config/locales/en.yml +168 -0
- data/lib/cc_api_stub/app_usage_events.rb +11 -0
- data/lib/cc_api_stub/applications.rb +57 -0
- data/lib/cc_api_stub/domains.rb +32 -0
- data/lib/cc_api_stub/events.rb +11 -0
- data/lib/cc_api_stub/frameworks.rb +22 -0
- data/lib/cc_api_stub/helper.rb +148 -0
- data/lib/cc_api_stub/login.rb +21 -0
- data/lib/cc_api_stub/organization_users.rb +27 -0
- data/lib/cc_api_stub/organizations.rb +82 -0
- data/lib/cc_api_stub/routes.rb +26 -0
- data/lib/cc_api_stub/runtimes.rb +22 -0
- data/lib/cc_api_stub/service_bindings.rb +22 -0
- data/lib/cc_api_stub/service_instances.rb +22 -0
- data/lib/cc_api_stub/services.rb +21 -0
- data/lib/cc_api_stub/space_users.rb +27 -0
- data/lib/cc_api_stub/spaces.rb +58 -0
- data/lib/cc_api_stub/users.rb +85 -0
- data/lib/cc_api_stub.rb +20 -0
- data/lib/cfoundry/auth_token.rb +62 -0
- data/lib/cfoundry/baseclient.rb +220 -0
- data/lib/cfoundry/chatty_hash.rb +46 -0
- data/lib/cfoundry/client.rb +42 -0
- data/lib/cfoundry/concerns/login_helpers.rb +14 -0
- data/lib/cfoundry/concerns/proxy_options.rb +14 -0
- data/lib/cfoundry/errors.rb +163 -0
- data/lib/cfoundry/rest_client.rb +316 -0
- data/lib/cfoundry/test_support.rb +3 -0
- data/lib/cfoundry/trace_helpers.rb +64 -0
- data/lib/cfoundry/uaaclient.rb +151 -0
- data/lib/cfoundry/upload_helpers.rb +222 -0
- data/lib/cfoundry/v2/app.rb +313 -0
- data/lib/cfoundry/v2/app_event.rb +13 -0
- data/lib/cfoundry/v2/app_instance.rb +74 -0
- data/lib/cfoundry/v2/app_usage_event.rb +14 -0
- data/lib/cfoundry/v2/base.rb +112 -0
- data/lib/cfoundry/v2/client.rb +104 -0
- data/lib/cfoundry/v2/domain.rb +20 -0
- data/lib/cfoundry/v2/event.rb +17 -0
- data/lib/cfoundry/v2/helper.rb +11 -0
- data/lib/cfoundry/v2/managed_service_instance.rb +13 -0
- data/lib/cfoundry/v2/model.rb +213 -0
- data/lib/cfoundry/v2/model_magic/attribute.rb +49 -0
- data/lib/cfoundry/v2/model_magic/client_extensions.rb +170 -0
- data/lib/cfoundry/v2/model_magic/has_summary.rb +49 -0
- data/lib/cfoundry/v2/model_magic/query_multi_value_helper.rb +21 -0
- data/lib/cfoundry/v2/model_magic/query_value_helper.rb +33 -0
- data/lib/cfoundry/v2/model_magic/queryable_by.rb +39 -0
- data/lib/cfoundry/v2/model_magic/to_many.rb +145 -0
- data/lib/cfoundry/v2/model_magic/to_one.rb +81 -0
- data/lib/cfoundry/v2/model_magic.rb +134 -0
- data/lib/cfoundry/v2/organization.rb +44 -0
- data/lib/cfoundry/v2/quota_definition.rb +12 -0
- data/lib/cfoundry/v2/route.rb +25 -0
- data/lib/cfoundry/v2/service.rb +22 -0
- data/lib/cfoundry/v2/service_auth_token.rb +9 -0
- data/lib/cfoundry/v2/service_binding.rb +10 -0
- data/lib/cfoundry/v2/service_broker.rb +12 -0
- data/lib/cfoundry/v2/service_instance.rb +14 -0
- data/lib/cfoundry/v2/service_plan.rb +16 -0
- data/lib/cfoundry/v2/space.rb +31 -0
- data/lib/cfoundry/v2/stack.rb +10 -0
- data/lib/cfoundry/v2/user.rb +97 -0
- data/lib/cfoundry/v2/user_provided_service_instance.rb +16 -0
- data/lib/cfoundry/validator.rb +41 -0
- data/lib/cfoundry/version.rb +4 -0
- data/lib/cfoundry/zip.rb +56 -0
- data/lib/cfoundry.rb +6 -0
- data/release_notes/release_1_5_3.md +177 -0
- data/release_notes/release_2.3.1.md +14 -0
- data/release_notes/release_2.3.3.md +38 -0
- data/release_notes/release_2.3.4.md +16 -0
- data/release_notes/release_2.3.5.md +14 -0
- data/release_notes/release_2.3.6.md +14 -0
- data/release_notes/release_2.3.6.rc1.md +29 -0
- data/release_notes/release_2.3.6.rc2.md +19 -0
- data/release_notes/release_2.3.7.rc1.md +14 -0
- data/release_notes/release_2.4.0.md +41 -0
- data/release_notes/release_2.4.1.rc1.md +58 -0
- data/release_notes/release_3.0.0.md +21 -0
- data/release_notes/release_3.0.1.md +16 -0
- data/release_notes/release_3.0.2.rc1.md +19 -0
- data/release_notes/release_4.0.0.md +19 -0
- data/release_notes/release_4.0.1.md +14 -0
- data/release_notes/release_4.0.2.rc1.md +14 -0
- data/release_notes/release_4.0.2.rc2.md +11 -0
- data/release_notes/release_4.0.2.rc3.md +11 -0
- data/release_notes/release_4.0.2.rc4.md +19 -0
- data/release_notes/release_4.0.2.rc5.md +14 -0
- data/release_notes/release_4.0.3.md +19 -0
- data/release_notes/release_4.0.4.rc1.md +14 -0
- data/release_notes/release_4.0.4.rc2.md +14 -0
- data/release_notes/release_4.1.0.md +19 -0
- data/release_notes/release_4.2.0.rc.md +24 -0
- data/release_notes/release_4.3.0.md +22 -0
- data/release_notes/release_4.3.1.md +14 -0
- data/release_notes/release_4.3.10.md +14 -0
- data/release_notes/release_4.3.11.md +14 -0
- data/release_notes/release_4.3.12.md +14 -0
- data/release_notes/release_4.3.2.rc1.md +21 -0
- data/release_notes/release_4.3.3.md +24 -0
- data/release_notes/release_4.3.4.md +11 -0
- data/release_notes/release_4.3.4.rc1.md +24 -0
- data/release_notes/release_4.3.5.md +36 -0
- data/release_notes/release_4.3.5.rc1.md +21 -0
- data/release_notes/release_4.3.6.md +14 -0
- data/release_notes/release_4.3.7.md +50 -0
- data/release_notes/release_4.3.8.md +19 -0
- data/release_notes/release_4.3.9.md +14 -0
- data/release_notes/release_4.4.0.md +16 -0
- data/release_notes/release_4.5.1.md +11 -0
- data/release_notes/release_4.5.2.md +14 -0
- data/release_notes/release_4.5.3.md +29 -0
- data/release_notes/release_4.6.0.md +24 -0
- data/release_notes/release_4.6.1.md +14 -0
- data/release_notes/release_4.6.2.md +16 -0
- data/release_notes/release_4.6.3.rc1.md +14 -0
- data/release_notes/release_4.6.3.rc2.md +14 -0
- data/release_notes/release_4.6.3.rc3.md +17 -0
- data/release_notes/release_4.7.0.md +11 -0
- data/release_notes/release_4.7.1.md +14 -0
- data/release_notes/release_4.7.1.rc.1.md +14 -0
- data/release_notes/release_4.7.1.rc1.md +19 -0
- data/script/gpp +3 -0
- data/spec/cc_api_stub/app_usage_events_spec.rb +12 -0
- data/spec/cc_api_stub/applications_spec.rb +69 -0
- data/spec/cc_api_stub/domains_spec.rb +40 -0
- data/spec/cc_api_stub/events_spec.rb +12 -0
- data/spec/cc_api_stub/frameworks_spec.rb +19 -0
- data/spec/cc_api_stub/login_spec.rb +20 -0
- data/spec/cc_api_stub/organization_users_spec.rb +35 -0
- data/spec/cc_api_stub/organizations_spec.rb +118 -0
- data/spec/cc_api_stub/routes_spec.rb +19 -0
- data/spec/cc_api_stub/runtimes_spec.rb +19 -0
- data/spec/cc_api_stub/service_bindings_spec.rb +13 -0
- data/spec/cc_api_stub/service_instances_spec.rb +19 -0
- data/spec/cc_api_stub/services_spec.rb +11 -0
- data/spec/cc_api_stub/space_users_spec.rb +35 -0
- data/spec/cc_api_stub/spaces_spec.rb +38 -0
- data/spec/cc_api_stub/users_spec.rb +107 -0
- data/spec/cfoundry/auth_token_spec.rb +153 -0
- data/spec/cfoundry/baseclient_spec.rb +284 -0
- data/spec/cfoundry/client_spec.rb +13 -0
- data/spec/cfoundry/errors_spec.rb +117 -0
- data/spec/cfoundry/rest_client_spec.rb +367 -0
- data/spec/cfoundry/trace_helpers_spec.rb +91 -0
- data/spec/cfoundry/uaaclient_spec.rb +421 -0
- data/spec/cfoundry/upload_helpers_spec.rb +182 -0
- data/spec/cfoundry/v2/app_event_spec.rb +97 -0
- data/spec/cfoundry/v2/app_instance_spec.rb +31 -0
- data/spec/cfoundry/v2/app_spec.rb +354 -0
- data/spec/cfoundry/v2/app_usage_event_spec.rb +15 -0
- data/spec/cfoundry/v2/base_spec.rb +375 -0
- data/spec/cfoundry/v2/client_spec.rb +121 -0
- data/spec/cfoundry/v2/domain_spec.rb +63 -0
- data/spec/cfoundry/v2/event_spec.rb +15 -0
- data/spec/cfoundry/v2/managed_service_instance_spec.rb +149 -0
- data/spec/cfoundry/v2/model_magic/attribute_spec.rb +123 -0
- data/spec/cfoundry/v2/model_magic/has_summary_spec.rb +17 -0
- data/spec/cfoundry/v2/model_magic/to_many_spec.rb +53 -0
- data/spec/cfoundry/v2/model_magic/to_one_spec.rb +106 -0
- data/spec/cfoundry/v2/model_magic_spec.rb +43 -0
- data/spec/cfoundry/v2/model_spec.rb +472 -0
- data/spec/cfoundry/v2/organization_spec.rb +282 -0
- data/spec/cfoundry/v2/quota_definition_spec.rb +50 -0
- data/spec/cfoundry/v2/route_spec.rb +42 -0
- data/spec/cfoundry/v2/service_plan_spec.rb +53 -0
- data/spec/cfoundry/v2/service_spec.rb +58 -0
- data/spec/cfoundry/v2/space_spec.rb +160 -0
- data/spec/cfoundry/v2/user_provided_service_instance_spec.rb +57 -0
- data/spec/cfoundry/v2/user_spec.rb +206 -0
- data/spec/cfoundry/validator_spec.rb +94 -0
- data/spec/factories/app_events_factory.rb +7 -0
- data/spec/factories/app_usage_events_factory.rb +32 -0
- data/spec/factories/apps_factory.rb +11 -0
- data/spec/factories/clients_factory.rb +7 -0
- data/spec/factories/domains_factory.rb +10 -0
- data/spec/factories/events_factory.rb +50 -0
- data/spec/factories/organizations_factory.rb +12 -0
- data/spec/factories/quota_definitions_factory.rb +8 -0
- data/spec/factories/routes_factory.rb +10 -0
- data/spec/factories/service_instances_factory.rb +10 -0
- data/spec/factories/service_plans_factory.rb +10 -0
- data/spec/factories/services_factory.rb +10 -0
- data/spec/factories/spaces_factory.rb +10 -0
- data/spec/factories/user_provided_service_instances_factory.rb +10 -0
- data/spec/factories/users_factory.rb +10 -0
- data/spec/fixtures/apps/with_cfignore/.cfignore +4 -0
- data/spec/fixtures/apps/with_cfignore/.hidden_file +1 -0
- data/spec/fixtures/apps/with_cfignore/ambiguous_ignored +0 -0
- data/spec/fixtures/apps/with_cfignore/ignored_dir/file_in_ignored_dir.txt +1 -0
- data/spec/fixtures/apps/with_cfignore/ignored_file.txt +1 -0
- data/spec/fixtures/apps/with_cfignore/non_ignored_dir/file_in_non_ignored_dir.txt +1 -0
- data/spec/fixtures/apps/with_cfignore/non_ignored_dir/ignored_file.txt +1 -0
- data/spec/fixtures/apps/with_cfignore/non_ignored_dir/toplevel_ignored.txt +0 -0
- data/spec/fixtures/apps/with_cfignore/non_ignored_file.txt +1 -0
- data/spec/fixtures/apps/with_cfignore/toplevel_ignored.txt +0 -0
- data/spec/fixtures/apps/with_dotfiles/.dotfile +1 -0
- data/spec/fixtures/apps/with_dotfiles/xyz +1 -0
- data/spec/fixtures/apps/with_external_symlink/foo +1 -0
- data/spec/fixtures/apps/with_ignored_external_symlink/.cfignore +1 -0
- data/spec/fixtures/apps/with_ignored_external_symlink/foo +1 -0
- data/spec/fixtures/apps/with_nested_directories/foo/bar/baz/fizz +0 -0
- data/spec/fixtures/apps/with_nested_directories/xyz +0 -0
- data/spec/fixtures/empty_file +0 -0
- data/spec/fixtures/fake_cc_app_usage_events.json +152 -0
- data/spec/fixtures/fake_cc_application.json +20 -0
- data/spec/fixtures/fake_cc_application_summary.json +56 -0
- data/spec/fixtures/fake_cc_created_application.json +11 -0
- data/spec/fixtures/fake_cc_created_domain.json +15 -0
- data/spec/fixtures/fake_cc_created_organization.json +11 -0
- data/spec/fixtures/fake_cc_created_route.json +13 -0
- data/spec/fixtures/fake_cc_created_service_instance.json +11 -0
- data/spec/fixtures/fake_cc_created_space.json +11 -0
- data/spec/fixtures/fake_cc_created_user.json +11 -0
- data/spec/fixtures/fake_cc_domain.json +55 -0
- data/spec/fixtures/fake_cc_domain_spaces.json +27 -0
- data/spec/fixtures/fake_cc_empty_search.json +7 -0
- data/spec/fixtures/fake_cc_events.json +419 -0
- data/spec/fixtures/fake_cc_frameworks.json +20 -0
- data/spec/fixtures/fake_cc_managed_service_instance.json +83 -0
- data/spec/fixtures/fake_cc_organization.json +161 -0
- data/spec/fixtures/fake_cc_organization_domains.json +59 -0
- data/spec/fixtures/fake_cc_organization_search.json +37 -0
- data/spec/fixtures/fake_cc_organization_spaces.json +99 -0
- data/spec/fixtures/fake_cc_organization_summary.json +20 -0
- data/spec/fixtures/fake_cc_organization_users.json +81 -0
- data/spec/fixtures/fake_cc_route.json +16 -0
- data/spec/fixtures/fake_cc_runtimes.json +20 -0
- data/spec/fixtures/fake_cc_service_binding.json +22 -0
- data/spec/fixtures/fake_cc_service_bindings.json +24 -0
- data/spec/fixtures/fake_cc_service_instance.json +83 -0
- data/spec/fixtures/fake_cc_service_instances.json +72 -0
- data/spec/fixtures/fake_cc_services.json +160 -0
- data/spec/fixtures/fake_cc_space.json +45 -0
- data/spec/fixtures/fake_cc_space_apps.json +49 -0
- data/spec/fixtures/fake_cc_space_summary.json +84 -0
- data/spec/fixtures/fake_cc_spaces.json +92 -0
- data/spec/fixtures/fake_cc_stats.json +29 -0
- data/spec/fixtures/fake_cc_user.json +139 -0
- data/spec/fixtures/fake_cc_user_organizations.json +92 -0
- data/spec/fixtures/fake_cc_user_provided_service_instance.json +51 -0
- data/spec/fixtures/fake_cc_user_with_managers.json +85 -0
- data/spec/integration/client_spec.rb +38 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/factory_girl.rb +6 -0
- data/spec/support/shared_examples/cc_api_stub_request_examples.rb +79 -0
- data/spec/support/shared_examples/client_login_examples.rb +46 -0
- data/spec/support/shared_examples/model_summary_examples.rb +34 -0
- data/spec/support/test_model_builder.rb +10 -0
- data/vendor/errors/v1.yml +189 -0
- data/vendor/errors/v2.yml +845 -0
- metadata +712 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
require "tmpdir"
|
|
2
|
+
require "fileutils"
|
|
3
|
+
require "pathname"
|
|
4
|
+
require "digest/sha1"
|
|
5
|
+
|
|
6
|
+
require "cfoundry/zip"
|
|
7
|
+
|
|
8
|
+
module CFoundry
|
|
9
|
+
module UploadHelpers
|
|
10
|
+
# Default paths to exclude from upload payload.
|
|
11
|
+
UPLOAD_EXCLUDE = %w{.git _darcs .svn}
|
|
12
|
+
|
|
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 .cfignore 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
|
|
35
|
+
|
|
36
|
+
zipfile = "#{Dir.tmpdir}/#{@guid}.zip"
|
|
37
|
+
tmpdir = "#{Dir.tmpdir}/.cf_#{@guid}_files"
|
|
38
|
+
|
|
39
|
+
FileUtils.rm_f(zipfile)
|
|
40
|
+
FileUtils.rm_rf(tmpdir)
|
|
41
|
+
|
|
42
|
+
prepare_package(path, tmpdir)
|
|
43
|
+
|
|
44
|
+
resources = determine_resources(tmpdir) if check_resources
|
|
45
|
+
|
|
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
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def prepare_package(path, to)
|
|
57
|
+
if path =~ /\.(jar|war|zip)$/
|
|
58
|
+
CFoundry::Zip.unpack(path, to)
|
|
59
|
+
elsif (war_file = Dir.glob("#{path}/*.war").first)
|
|
60
|
+
CFoundry::Zip.unpack(war_file, to)
|
|
61
|
+
else
|
|
62
|
+
FileUtils.mkdir(to)
|
|
63
|
+
|
|
64
|
+
exclude = UPLOAD_EXCLUDE
|
|
65
|
+
if File.exists?("#{path}/.cfignore")
|
|
66
|
+
exclude += File.read("#{path}/.cfignore").split(/\n+/)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
files = files_to_consider(path, exclude)
|
|
70
|
+
|
|
71
|
+
check_unreachable_links(files, path)
|
|
72
|
+
|
|
73
|
+
copy_tree(files, path, to)
|
|
74
|
+
|
|
75
|
+
find_sockets(to).each do |s|
|
|
76
|
+
File.delete s
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def check_unreachable_links(files, path)
|
|
82
|
+
# only used for friendlier error message
|
|
83
|
+
pwd = Pathname.pwd
|
|
84
|
+
|
|
85
|
+
abspath = File.expand_path(path)
|
|
86
|
+
unreachable = []
|
|
87
|
+
files.each do |f|
|
|
88
|
+
file = Pathname.new(f)
|
|
89
|
+
if file.symlink? && !file.realpath.to_s.start_with?(abspath)
|
|
90
|
+
unreachable << file.relative_path_from(pwd)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
unless unreachable.empty?
|
|
95
|
+
root = Pathname.new(path).relative_path_from(pwd)
|
|
96
|
+
raise CFoundry::Error,
|
|
97
|
+
"Path contains links '#{unreachable}' that point outside '#{root}'"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def files_to_consider(path, exclusions)
|
|
102
|
+
entries = all_files(path)
|
|
103
|
+
|
|
104
|
+
exclusions.each do |exclusion|
|
|
105
|
+
ignore_pattern = exclusion.start_with?("/") ? File.join(path, exclusion) : File.join(path, "**", exclusion)
|
|
106
|
+
dir_glob = Dir.glob(ignore_pattern, File::FNM_DOTMATCH)
|
|
107
|
+
entries -= dir_glob
|
|
108
|
+
|
|
109
|
+
ignore_pattern = File.join(path, "**", exclusion, "**", "*")
|
|
110
|
+
dir_glob = Dir.glob(ignore_pattern, File::FNM_DOTMATCH)
|
|
111
|
+
entries -= dir_glob
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
entries
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def glob_matches?(file, path, pattern)
|
|
118
|
+
name = file.sub("#{path}/", "/")
|
|
119
|
+
flags = File::FNM_DOTMATCH
|
|
120
|
+
|
|
121
|
+
# when pattern ends with /, match only directories
|
|
122
|
+
if pattern.end_with?("/") && File.directory?(file)
|
|
123
|
+
name = "#{name}/"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
case pattern
|
|
127
|
+
# when pattern contains /, do a pathname match
|
|
128
|
+
when /\/./
|
|
129
|
+
flags |= File::FNM_PATHNAME
|
|
130
|
+
|
|
131
|
+
# otherwise, match any file path
|
|
132
|
+
else
|
|
133
|
+
pattern = "**/#{pattern}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
File.fnmatch(pattern, name, flags)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def find_sockets(path)
|
|
140
|
+
all_files(path).select { |f| File.socket? f }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def determine_resources(path)
|
|
144
|
+
fingerprints, total_size = make_fingerprints(path)
|
|
145
|
+
|
|
146
|
+
return if total_size <= RESOURCE_CHECK_LIMIT
|
|
147
|
+
|
|
148
|
+
resources = @client.base.resource_match(fingerprints)
|
|
149
|
+
|
|
150
|
+
resources.each do |resource|
|
|
151
|
+
FileUtils.rm_f resource[:fn]
|
|
152
|
+
resource[:fn].sub!("#{path}/", "")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
prune_empty_directories(path)
|
|
156
|
+
|
|
157
|
+
resources
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# OK, HERES THE PLAN...
|
|
161
|
+
#
|
|
162
|
+
# 1. Get all the directories in the entire file tree.
|
|
163
|
+
# 2. Sort them by the length of their absolute path.
|
|
164
|
+
# 3. Go through the list, longest paths first, and remove
|
|
165
|
+
# the directories that are empty.
|
|
166
|
+
#
|
|
167
|
+
# This ensures that directories containing empty directories
|
|
168
|
+
# are also pruned.
|
|
169
|
+
def prune_empty_directories(path)
|
|
170
|
+
all_files = all_files(path)
|
|
171
|
+
|
|
172
|
+
directories = all_files.select { |x| File.directory?(x) }
|
|
173
|
+
directories.sort! { |a, b| b.size <=> a.size }
|
|
174
|
+
|
|
175
|
+
directories.each do |directory|
|
|
176
|
+
entries = all_files(directory)
|
|
177
|
+
FileUtils.rmdir(directory) if entries.empty?
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def make_fingerprints(path)
|
|
182
|
+
fingerprints = []
|
|
183
|
+
total_size = 0
|
|
184
|
+
|
|
185
|
+
all_files(path).each do |filename|
|
|
186
|
+
next if File.directory?(filename)
|
|
187
|
+
|
|
188
|
+
size = File.size(filename)
|
|
189
|
+
|
|
190
|
+
total_size += size
|
|
191
|
+
|
|
192
|
+
fingerprints << {
|
|
193
|
+
:size => size,
|
|
194
|
+
:sha1 => Digest::SHA1.file(filename).hexdigest,
|
|
195
|
+
:fn => filename
|
|
196
|
+
}
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
[fingerprints, total_size]
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def all_files(path)
|
|
203
|
+
Dir.glob("#{path}/**/*", File::FNM_DOTMATCH).reject do |fn|
|
|
204
|
+
fn =~ /\.$/
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def copy_tree(files, path, to)
|
|
209
|
+
files.each do |file|
|
|
210
|
+
dest = file.sub("#{path}/", "#{to}/")
|
|
211
|
+
|
|
212
|
+
if File.directory?(file)
|
|
213
|
+
FileUtils.mkdir_p(dest)
|
|
214
|
+
else
|
|
215
|
+
destdir = File.dirname(dest)
|
|
216
|
+
FileUtils.mkdir_p(destdir)
|
|
217
|
+
FileUtils.cp(file, dest)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
require "tmpdir"
|
|
2
|
+
require "multi_json"
|
|
3
|
+
|
|
4
|
+
require "cfoundry/zip"
|
|
5
|
+
require "cfoundry/upload_helpers"
|
|
6
|
+
require "cfoundry/chatty_hash"
|
|
7
|
+
|
|
8
|
+
require "cfoundry/v2/model"
|
|
9
|
+
|
|
10
|
+
module CFoundry::V2
|
|
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 < Model
|
|
18
|
+
include CFoundry::UploadHelpers
|
|
19
|
+
|
|
20
|
+
attribute :name, :string
|
|
21
|
+
to_one :space
|
|
22
|
+
attribute :environment_json, :hash, :default => {}
|
|
23
|
+
attribute :memory, :integer, :default => 256
|
|
24
|
+
attribute :total_instances, :integer, :default => 1, :at => :instances
|
|
25
|
+
attribute :disk_quota, :integer, :default => 256
|
|
26
|
+
attribute :state, :string, :default => "STOPPED"
|
|
27
|
+
attribute :command, :string, :default => nil
|
|
28
|
+
attribute :console, :boolean, :default => false
|
|
29
|
+
attribute :buildpack, :string, :default => nil
|
|
30
|
+
to_one :stack, :default => nil
|
|
31
|
+
attribute :debug, :string, :default => nil
|
|
32
|
+
to_many :service_bindings
|
|
33
|
+
to_many :routes
|
|
34
|
+
to_many :events, :as => :app_event
|
|
35
|
+
|
|
36
|
+
scoped_to_space
|
|
37
|
+
|
|
38
|
+
queryable_by :name, :space_guid, :organization_guid
|
|
39
|
+
|
|
40
|
+
has_summary :urls => proc { |x| self.cache[:uris] = x },
|
|
41
|
+
:running_instances => proc { |x|
|
|
42
|
+
self.cache[:running_instances] = x
|
|
43
|
+
},
|
|
44
|
+
:instances => proc { |x|
|
|
45
|
+
self.total_instances = x
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private :environment_json
|
|
49
|
+
|
|
50
|
+
def delete!(opts = {})
|
|
51
|
+
super(opts.merge(:recursive => true))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def instances
|
|
55
|
+
AppInstance.for_app(name, @guid, @client)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def crashes
|
|
59
|
+
@client.base.crashes(@guid).collect do |m|
|
|
60
|
+
AppInstance.new(self.name, self.guid, m[:instance], @client, m)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def stats
|
|
65
|
+
stats = {}
|
|
66
|
+
|
|
67
|
+
@client.base.stats(@guid).each do |idx, info|
|
|
68
|
+
stats[idx.to_s] = info
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
stats
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def system_env
|
|
75
|
+
system_env = {}
|
|
76
|
+
|
|
77
|
+
@client.base.env(@guid).each do |idx, info|
|
|
78
|
+
system_env[idx.to_s] = info
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
system_env
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def services
|
|
85
|
+
service_bindings.collect(&:service_instance)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def env
|
|
89
|
+
CFoundry::ChattyHash.new(
|
|
90
|
+
method(:env=),
|
|
91
|
+
stringify(environment_json))
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def env=(x)
|
|
95
|
+
self.environment_json = stringify(x.to_hash)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
alias :debug_mode :debug
|
|
99
|
+
|
|
100
|
+
def uris
|
|
101
|
+
return @cache[:uris] if @cache[:uris]
|
|
102
|
+
|
|
103
|
+
routes.collect do |r|
|
|
104
|
+
"#{r.host}.#{r.domain.name}"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
alias :urls :uris
|
|
108
|
+
|
|
109
|
+
def uris=(uris)
|
|
110
|
+
raise CFoundry::Deprecated,
|
|
111
|
+
"App#uris= is invalid against V2 APIs; use add/remove_route"
|
|
112
|
+
end
|
|
113
|
+
alias :urls= :uris=
|
|
114
|
+
|
|
115
|
+
def uri
|
|
116
|
+
if uris = @cache[:uris]
|
|
117
|
+
return uris.first
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
if route = routes.first
|
|
121
|
+
"#{route.host}.#{route.domain.name}"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
alias :url :uri
|
|
125
|
+
|
|
126
|
+
def host
|
|
127
|
+
return nil if routes.empty?
|
|
128
|
+
routes.first.host
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def domain
|
|
132
|
+
return nil if routes.empty?
|
|
133
|
+
routes.first.domain.name
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def uri=(x)
|
|
137
|
+
self.uris = [x]
|
|
138
|
+
end
|
|
139
|
+
alias :url= :uri=
|
|
140
|
+
|
|
141
|
+
# Stop the application.
|
|
142
|
+
def stop!
|
|
143
|
+
self.state = "STOPPED"
|
|
144
|
+
update!
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Start the application.
|
|
148
|
+
def start!(&blk)
|
|
149
|
+
self.state = "STARTED"
|
|
150
|
+
update!(&blk)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Restart the application.
|
|
154
|
+
def restart!(&blk)
|
|
155
|
+
stop!
|
|
156
|
+
start!(&blk)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def update!
|
|
160
|
+
response = @client.base.update_app(@guid, @diff)
|
|
161
|
+
|
|
162
|
+
yield response[:headers]["x-app-staging-log"] if block_given?
|
|
163
|
+
|
|
164
|
+
@manifest = @client.base.send(:parse_json, response[:body])
|
|
165
|
+
|
|
166
|
+
@diff.clear
|
|
167
|
+
|
|
168
|
+
true
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def stream_update_log(log_url)
|
|
172
|
+
offset = 0
|
|
173
|
+
|
|
174
|
+
while true
|
|
175
|
+
begin
|
|
176
|
+
@client.stream_url(log_url + "&tail&tail_offset=#{offset}") do |out|
|
|
177
|
+
offset += out.size
|
|
178
|
+
yield out
|
|
179
|
+
end
|
|
180
|
+
rescue Timeout::Error
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
rescue CFoundry::APIError
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Determine application health.
|
|
187
|
+
#
|
|
188
|
+
# If all instances are running, returns "RUNNING". If only some are
|
|
189
|
+
# started, returns the percentage of them that are healthy.
|
|
190
|
+
#
|
|
191
|
+
# Otherwise, returns application's status.
|
|
192
|
+
def health
|
|
193
|
+
if state == "STARTED"
|
|
194
|
+
healthy_count = running_instances
|
|
195
|
+
expected = total_instances
|
|
196
|
+
|
|
197
|
+
if expected > 0
|
|
198
|
+
ratio = healthy_count / expected.to_f
|
|
199
|
+
if ratio == 1.0
|
|
200
|
+
"RUNNING"
|
|
201
|
+
else
|
|
202
|
+
"#{(ratio * 100).to_i}%"
|
|
203
|
+
end
|
|
204
|
+
else
|
|
205
|
+
"N/A"
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
state
|
|
209
|
+
end
|
|
210
|
+
rescue CFoundry::StagingError, CFoundry::NotStaged
|
|
211
|
+
"STAGING FAILED"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def percent_running
|
|
215
|
+
if state == "STARTED"
|
|
216
|
+
healthy_count = running_instances
|
|
217
|
+
expected = total_instances
|
|
218
|
+
|
|
219
|
+
expected > 0 ? (healthy_count / expected.to_f) * 100 : 0
|
|
220
|
+
else
|
|
221
|
+
0
|
|
222
|
+
end
|
|
223
|
+
rescue CFoundry::StagingError, CFoundry::NotStaged
|
|
224
|
+
0
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def running_instances
|
|
228
|
+
return @cache[:running_instances] if @cache[:running_instances]
|
|
229
|
+
|
|
230
|
+
running = 0
|
|
231
|
+
|
|
232
|
+
instances.each do |i|
|
|
233
|
+
running += 1 if i.state == "RUNNING"
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
running
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Check that all application instances are running.
|
|
240
|
+
def healthy?
|
|
241
|
+
# invalidate cache so the check is fresh
|
|
242
|
+
invalidate!
|
|
243
|
+
health == "RUNNING"
|
|
244
|
+
end
|
|
245
|
+
alias_method :running?, :healthy?
|
|
246
|
+
|
|
247
|
+
# Is the application stopped?
|
|
248
|
+
def stopped?
|
|
249
|
+
state == "STOPPED"
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Is the application started?
|
|
253
|
+
#
|
|
254
|
+
# Note that this does not imply that all instances are running. See
|
|
255
|
+
# #healthy?
|
|
256
|
+
def started?
|
|
257
|
+
state == "STARTED"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Bind services to application.
|
|
261
|
+
def bind(*instances)
|
|
262
|
+
instances.each do |i|
|
|
263
|
+
binding = @client.service_binding
|
|
264
|
+
binding.app = self
|
|
265
|
+
binding.service_instance = i
|
|
266
|
+
binding.create!
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
self
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Unbind services from application.
|
|
273
|
+
def unbind(*instances)
|
|
274
|
+
service_bindings.each do |b|
|
|
275
|
+
if instances.include? b.service_instance
|
|
276
|
+
b.delete!
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
self
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def binds?(instance)
|
|
284
|
+
service_bindings.any? { |b|
|
|
285
|
+
b.service_instance == instance
|
|
286
|
+
}
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def files(*path)
|
|
290
|
+
AppInstance.new(self.name, self.guid, "0", @client).files(*path)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def file(*path)
|
|
294
|
+
AppInstance.new(self.name, self.guid, "0", @client).file(*path)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def stream_file(*path, &blk)
|
|
298
|
+
AppInstance.new(self.name, self.guid, "0", @client).stream_file(*path, &blk)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
private
|
|
302
|
+
|
|
303
|
+
def stringify(hash)
|
|
304
|
+
new = {}
|
|
305
|
+
|
|
306
|
+
hash.each do |k, v|
|
|
307
|
+
new[k.to_s] = v.to_s
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
new
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "cfoundry/v2/model"
|
|
2
|
+
|
|
3
|
+
module CFoundry::V2
|
|
4
|
+
class AppEvent < Model
|
|
5
|
+
to_one :app
|
|
6
|
+
|
|
7
|
+
attribute :instance_guid, :string
|
|
8
|
+
attribute :instance_index, :integer
|
|
9
|
+
attribute :exit_status, :integer
|
|
10
|
+
attribute :exit_description, :string, :default => ""
|
|
11
|
+
attribute :timestamp, :string
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module CFoundry::V2
|
|
2
|
+
class AppInstance
|
|
3
|
+
attr_reader :id
|
|
4
|
+
|
|
5
|
+
def self.for_app(name, guid, client)
|
|
6
|
+
client.base.instances(guid).collect do |i, m|
|
|
7
|
+
AppInstance.new(name, guid, i.to_s, client, m)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(app_name, app_guid, id, client, manifest = {})
|
|
12
|
+
@app_name = app_name
|
|
13
|
+
@app_guid = app_guid
|
|
14
|
+
@id = id
|
|
15
|
+
@client = client
|
|
16
|
+
@manifest = manifest
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def inspect
|
|
20
|
+
"#<App::Instance '#{@app_name}' \##@id>"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def state
|
|
24
|
+
@manifest[:state]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
alias_method :status, :state
|
|
28
|
+
|
|
29
|
+
def since
|
|
30
|
+
if since = @manifest[:since]
|
|
31
|
+
Time.at(@manifest[:since])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def debugger
|
|
36
|
+
return unless @manifest[:debug_ip] and @manifest[:debug_port]
|
|
37
|
+
|
|
38
|
+
{:ip => @manifest[:debug_ip],
|
|
39
|
+
:port => @manifest[:debug_port]
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def console
|
|
44
|
+
return unless @manifest[:console_ip] and @manifest[:console_port]
|
|
45
|
+
|
|
46
|
+
{:ip => @manifest[:console_ip],
|
|
47
|
+
:port => @manifest[:console_port]
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def healthy?
|
|
52
|
+
case state
|
|
53
|
+
when "STARTING", "RUNNING"
|
|
54
|
+
true
|
|
55
|
+
when "DOWN", "FLAPPING"
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def files(*path)
|
|
61
|
+
@client.base.files(@app_guid, @id, *path).split("\n").collect do |entry|
|
|
62
|
+
path + [entry.split(/\s+/, 2)[0]]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def file(*path)
|
|
67
|
+
@client.base.files(@app_guid, @id, *path)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def stream_file(*path, &blk)
|
|
71
|
+
@client.base.stream_file(@app_guid, @id, *path, &blk)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require "cfoundry/v2/model"
|
|
2
|
+
|
|
3
|
+
module CFoundry::V2
|
|
4
|
+
class AppUsageEvent < Model
|
|
5
|
+
attribute :state, :string
|
|
6
|
+
attribute :memory_in_mb_per_instance, :integer
|
|
7
|
+
attribute :instance_count, :integer
|
|
8
|
+
attribute :app_guid, :string
|
|
9
|
+
attribute :app_name, :string
|
|
10
|
+
attribute :space_guid, :string
|
|
11
|
+
attribute :space_name, :string
|
|
12
|
+
attribute :org_guid, :string
|
|
13
|
+
end
|
|
14
|
+
end
|