cloulu 0.0.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/{cloulu → cl} +0 -0
- data/lib/cc_api_stub/applications.rb +53 -0
- data/lib/cc_api_stub/domains.rb +16 -0
- data/lib/cc_api_stub/frameworks.rb +22 -0
- data/lib/cc_api_stub/helper.rb +131 -0
- data/lib/cc_api_stub/login.rb +21 -0
- data/lib/cc_api_stub/organization_users.rb +21 -0
- data/lib/cc_api_stub/organizations.rb +70 -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 +25 -0
- data/lib/cc_api_stub/spaces.rb +49 -0
- data/lib/cc_api_stub/users.rb +84 -0
- data/lib/cc_api_stub.rb +17 -0
- data/lib/cfoundry/auth_token.rb +63 -0
- data/lib/cfoundry/baseclient.rb +201 -0
- data/lib/cfoundry/chatty_hash.rb +46 -0
- data/lib/cfoundry/client.rb +46 -0
- data/lib/cfoundry/concerns/login_helpers.rb +13 -0
- data/lib/cfoundry/errors.rb +160 -0
- data/lib/cfoundry/rest_client.rb +299 -0
- data/lib/cfoundry/test_support.rb +3 -0
- data/lib/cfoundry/trace_helpers.rb +40 -0
- data/lib/cfoundry/uaaclient.rb +112 -0
- data/lib/cfoundry/upload_helpers.rb +187 -0
- data/lib/cfoundry/v1/app.rb +363 -0
- data/lib/cfoundry/v1/base.rb +72 -0
- data/lib/cfoundry/v1/client.rb +193 -0
- data/lib/cfoundry/v1/framework.rb +21 -0
- data/lib/cfoundry/v1/model.rb +178 -0
- data/lib/cfoundry/v1/model_magic.rb +129 -0
- data/lib/cfoundry/v1/runtime.rb +24 -0
- data/lib/cfoundry/v1/service.rb +39 -0
- data/lib/cfoundry/v1/service_instance.rb +32 -0
- data/lib/cfoundry/v1/service_plan.rb +19 -0
- data/lib/cfoundry/v1/user.rb +22 -0
- data/lib/cfoundry/v2/app.rb +392 -0
- data/lib/cfoundry/v2/base.rb +83 -0
- data/lib/cfoundry/v2/client.rb +138 -0
- data/lib/cfoundry/v2/domain.rb +11 -0
- data/lib/cfoundry/v2/framework.rb +14 -0
- data/lib/cfoundry/v2/model.rb +148 -0
- data/lib/cfoundry/v2/model_magic.rb +449 -0
- data/lib/cfoundry/v2/organization.rb +16 -0
- data/lib/cfoundry/v2/route.rb +15 -0
- data/lib/cfoundry/v2/runtime.rb +12 -0
- data/lib/cfoundry/v2/service.rb +19 -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_instance.rb +14 -0
- data/lib/cfoundry/v2/service_plan.rb +12 -0
- data/lib/cfoundry/v2/space.rb +18 -0
- data/lib/cfoundry/v2/user.rb +64 -0
- data/lib/cfoundry/validator.rb +39 -0
- data/lib/cfoundry/version.rb +4 -0
- data/lib/cfoundry/zip.rb +56 -0
- data/lib/cfoundry.rb +2 -0
- data/lib/manifests-vmc-plugin/errors.rb +21 -0
- data/lib/manifests-vmc-plugin/loader/builder.rb +34 -0
- data/lib/manifests-vmc-plugin/loader/normalizer.rb +149 -0
- data/lib/manifests-vmc-plugin/loader/resolver.rb +79 -0
- data/lib/manifests-vmc-plugin/loader.rb +31 -0
- data/lib/manifests-vmc-plugin/plugin.rb +145 -0
- data/lib/manifests-vmc-plugin/version.rb +3 -0
- data/lib/manifests-vmc-plugin.rb +313 -0
- data/lib/mothership/base.rb +99 -0
- data/lib/mothership/callbacks.rb +85 -0
- data/lib/mothership/command.rb +146 -0
- data/lib/mothership/errors.rb +38 -0
- data/lib/mothership/help/commands.rb +53 -0
- data/lib/mothership/help/printer.rb +170 -0
- data/lib/mothership/help.rb +64 -0
- data/lib/mothership/inputs.rb +189 -0
- data/lib/mothership/parser.rb +182 -0
- data/lib/mothership/version.rb +3 -0
- data/lib/mothership.rb +64 -0
- data/lib/tunnel-vmc-plugin/plugin.rb +178 -0
- data/lib/tunnel-vmc-plugin/tunnel.rb +308 -0
- data/lib/tunnel-vmc-plugin/version.rb +3 -0
- data/lib/uaa/http.rb +168 -0
- data/lib/uaa/misc.rb +121 -0
- data/lib/uaa/scim.rb +292 -0
- data/lib/uaa/token_coder.rb +196 -0
- data/lib/uaa/token_issuer.rb +255 -0
- data/lib/uaa/util.rb +235 -0
- data/lib/uaa/version.rb +19 -0
- data/lib/uaa.rb +18 -0
- data/lib/vmc/cli/app/app.rb +45 -0
- data/lib/vmc/cli/app/apps.rb +99 -0
- data/lib/vmc/cli/app/base.rb +90 -0
- data/lib/vmc/cli/app/crashes.rb +42 -0
- data/lib/vmc/cli/app/delete.rb +95 -0
- data/lib/vmc/cli/app/deprecated.rb +11 -0
- data/lib/vmc/cli/app/env.rb +78 -0
- data/lib/vmc/cli/app/files.rb +137 -0
- data/lib/vmc/cli/app/health.rb +26 -0
- data/lib/vmc/cli/app/instances.rb +53 -0
- data/lib/vmc/cli/app/logs.rb +76 -0
- data/lib/vmc/cli/app/push/create.rb +165 -0
- data/lib/vmc/cli/app/push/interactions.rb +94 -0
- data/lib/vmc/cli/app/push/sync.rb +64 -0
- data/lib/vmc/cli/app/push.rb +109 -0
- data/lib/vmc/cli/app/rename.rb +35 -0
- data/lib/vmc/cli/app/restart.rb +20 -0
- data/lib/vmc/cli/app/scale.rb +71 -0
- data/lib/vmc/cli/app/start.rb +143 -0
- data/lib/vmc/cli/app/stats.rb +67 -0
- data/lib/vmc/cli/app/stop.rb +27 -0
- data/lib/vmc/cli/help.rb +11 -0
- data/lib/vmc/cli/interactive.rb +105 -0
- data/lib/vmc/cli/route/base.rb +12 -0
- data/lib/vmc/cli/route/map.rb +82 -0
- data/lib/vmc/cli/route/routes.rb +25 -0
- data/lib/vmc/cli/route/unmap.rb +94 -0
- data/lib/vmc/cli/service/base.rb +8 -0
- data/lib/vmc/cli/service/bind.rb +44 -0
- data/lib/vmc/cli/service/create.rb +126 -0
- data/lib/vmc/cli/service/delete.rb +86 -0
- data/lib/vmc/cli/service/rename.rb +35 -0
- data/lib/vmc/cli/service/service.rb +42 -0
- data/lib/vmc/cli/service/services.rb +114 -0
- data/lib/vmc/cli/service/unbind.rb +38 -0
- data/lib/vmc/cli/start/base.rb +94 -0
- data/lib/vmc/cli/start/colors.rb +13 -0
- data/lib/vmc/cli/start/info.rb +126 -0
- data/lib/vmc/cli/start/login.rb +97 -0
- data/lib/vmc/cli/start/logout.rb +17 -0
- data/lib/vmc/cli/start/target.rb +60 -0
- data/lib/vmc/cli/start/target_interactions.rb +37 -0
- data/lib/vmc/cli/start/targets.rb +16 -0
- data/lib/vmc/cli/user/base.rb +29 -0
- data/lib/vmc/cli/user/create.rb +39 -0
- data/lib/vmc/cli/user/delete.rb +27 -0
- data/lib/vmc/cli/user/passwd.rb +50 -0
- data/lib/vmc/cli/user/register.rb +42 -0
- data/lib/vmc/cli/user/users.rb +32 -0
- data/lib/vmc/cli/v2_check_cli.rb +16 -0
- data/lib/vmc/cli.rb +474 -0
- data/lib/vmc/constants.rb +13 -0
- data/lib/vmc/detect.rb +129 -0
- data/lib/vmc/errors.rb +19 -0
- data/lib/vmc/plugin.rb +56 -0
- data/lib/vmc/spacing.rb +89 -0
- data/lib/vmc/spec_helper.rb +1 -0
- data/lib/vmc/test_support.rb +6 -0
- data/lib/vmc/version.rb +3 -0
- data/lib/vmc.rb +8 -0
- data/vendor/errors/v1.yml +189 -0
- data/vendor/errors/v2.yml +360 -0
- metadata +303 -190
@@ -0,0 +1,18 @@
|
|
1
|
+
require "cfoundry/v2/model"
|
2
|
+
|
3
|
+
module CFoundry::V2
|
4
|
+
class Space < Model
|
5
|
+
attribute :name, :string
|
6
|
+
to_one :organization
|
7
|
+
to_many :developers, :as => :user
|
8
|
+
to_many :managers, :as => :user
|
9
|
+
to_many :auditors, :as => :user
|
10
|
+
to_many :apps
|
11
|
+
to_many :domains
|
12
|
+
to_many :service_instances
|
13
|
+
|
14
|
+
scoped_to_organization
|
15
|
+
|
16
|
+
queryable_by :name, :organization_guid, :developer_guid, :app_guid
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "cfoundry/v2/model"
|
2
|
+
|
3
|
+
module CFoundry::V2
|
4
|
+
class User < Model
|
5
|
+
to_many :spaces
|
6
|
+
to_many :organizations
|
7
|
+
to_many :managed_organizations, :as => :organization
|
8
|
+
to_many :billing_managed_organizations, :as => :organization
|
9
|
+
to_many :audited_organizations, :as => :organization
|
10
|
+
to_many :managed_spaces, :as => :space
|
11
|
+
to_many :audited_spaces, :as => :space
|
12
|
+
attribute :admin, :boolean
|
13
|
+
to_one :default_space, :as => :space
|
14
|
+
|
15
|
+
attribute :guid, :string # guid is explicitly set for users
|
16
|
+
|
17
|
+
queryable_by :space_guid, :organization_guid, :managed_organization_guid,
|
18
|
+
:billing_managed_organization_guid, :audited_organization_guid,
|
19
|
+
:managed_space_guid, :audited_space_guid
|
20
|
+
|
21
|
+
def guid
|
22
|
+
@guid
|
23
|
+
end
|
24
|
+
|
25
|
+
alias set_guid_attribute guid=
|
26
|
+
|
27
|
+
def guid=(x)
|
28
|
+
@guid = x
|
29
|
+
set_guid_attribute(x)
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :admin? :admin
|
33
|
+
|
34
|
+
def change_password!(new, old)
|
35
|
+
@client.base.uaa.change_password(@guid, new, old)
|
36
|
+
end
|
37
|
+
|
38
|
+
# optional metadata from UAA
|
39
|
+
attr_accessor :emails, :name
|
40
|
+
|
41
|
+
def email
|
42
|
+
return unless @emails && @emails.first
|
43
|
+
@emails.first[:value]
|
44
|
+
end
|
45
|
+
|
46
|
+
def given_name
|
47
|
+
return unless @name && @name[:givenName] != email
|
48
|
+
@name[:givenName]
|
49
|
+
end
|
50
|
+
|
51
|
+
def family_name
|
52
|
+
return unless @name && @name[:familyName] != email
|
53
|
+
@name[:familyName]
|
54
|
+
end
|
55
|
+
|
56
|
+
def full_name
|
57
|
+
if @name && @name[:fullName]
|
58
|
+
@name[:fullName]
|
59
|
+
elsif given_name && family_name
|
60
|
+
"#{given_name} #{family_name}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module CFoundry
|
2
|
+
module Validator
|
3
|
+
class << self
|
4
|
+
def value_matches?(val, type)
|
5
|
+
case type
|
6
|
+
when Class
|
7
|
+
val.is_a?(type)
|
8
|
+
when Regexp
|
9
|
+
val.is_a?(String) && val =~ type
|
10
|
+
when :url
|
11
|
+
value_matches?(val, URI::regexp(%w(http https)))
|
12
|
+
when :https_url
|
13
|
+
value_matches?(val, URI::regexp("https"))
|
14
|
+
when :boolean
|
15
|
+
val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
16
|
+
when Array
|
17
|
+
val.all? do |x|
|
18
|
+
value_matches?(x, type.first)
|
19
|
+
end
|
20
|
+
when Hash
|
21
|
+
val.is_a?(Hash) &&
|
22
|
+
type.all? { |name, subtype|
|
23
|
+
val.key?(name) && value_matches?(val[name], subtype)
|
24
|
+
}
|
25
|
+
when nil
|
26
|
+
true
|
27
|
+
else
|
28
|
+
val.is_a?(Object.const_get(type.to_s.capitalize))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_type(val, type)
|
33
|
+
unless value_matches?(val, type)
|
34
|
+
raise CFoundry::Mismatch.new(type, val)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/cfoundry/zip.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "zip/zipfilesystem"
|
2
|
+
|
3
|
+
module CFoundry
|
4
|
+
# Generic Zpi API. Uses rubyzip underneath, but may be changed in the future
|
5
|
+
# to use system zip command if necessary.
|
6
|
+
module Zip
|
7
|
+
# Directory entries to exclude from packing.
|
8
|
+
PACK_EXCLUSION_GLOBS = %w(.. . *~ #*# *.log)
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
# Get the entries in the zip file. Returns an array of the entire
|
13
|
+
# contents, recursively (not just top-level).
|
14
|
+
def entry_lines(file)
|
15
|
+
entries = []
|
16
|
+
::Zip::ZipFile.foreach(file) do |zentry|
|
17
|
+
entries << zentry
|
18
|
+
end
|
19
|
+
entries
|
20
|
+
end
|
21
|
+
|
22
|
+
# Unpack a zip +file+ to directory +dest+.
|
23
|
+
def unpack(file, dest)
|
24
|
+
::Zip::ZipFile.foreach(file) do |zentry|
|
25
|
+
epath = "#{dest}/#{zentry}"
|
26
|
+
dirname = File.dirname(epath)
|
27
|
+
FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
|
28
|
+
zentry.extract(epath) unless File.exists?(epath)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Determine what files in +dir+ to pack.
|
33
|
+
def files_to_pack(dir)
|
34
|
+
Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).select do |f|
|
35
|
+
File.exists?(f) &&
|
36
|
+
PACK_EXCLUSION_GLOBS.none? do |e|
|
37
|
+
File.fnmatch(e, File.basename(f))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Package directory +dir+ as file +zipfile+.
|
43
|
+
def pack(dir, zipfile)
|
44
|
+
files = files_to_pack(dir)
|
45
|
+
return false if files.empty?
|
46
|
+
|
47
|
+
::Zip::ZipFile.open(zipfile, true) do |zf|
|
48
|
+
files.each do |f|
|
49
|
+
zf.add(f.sub("#{dir}/",''), f)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/cfoundry.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module VMCManifests
|
2
|
+
class CircularDependency < RuntimeError
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
"Circular dependency in application '#@app'"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class UnknownSymbol < RuntimeError
|
13
|
+
def initialize(sym)
|
14
|
+
@sym = sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"Undefined symbol in manifest: '#@sym'"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module VMCManifests
|
2
|
+
module Builder
|
3
|
+
# parse a manifest and merge with its inherited manifests
|
4
|
+
def build(file)
|
5
|
+
manifest = YAML.load_file file
|
6
|
+
|
7
|
+
Array(manifest["inherit"]).each do |path|
|
8
|
+
manifest = merge_parent(path, manifest)
|
9
|
+
end
|
10
|
+
|
11
|
+
manifest
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# merge the manifest at `parent_path' into the `child'
|
17
|
+
def merge_parent(parent_path, child)
|
18
|
+
merge_manifest(build(from_manifest(parent_path)), child)
|
19
|
+
end
|
20
|
+
|
21
|
+
# deep hash merge
|
22
|
+
def merge_manifest(parent, child)
|
23
|
+
merge = proc do |_, old, new|
|
24
|
+
if new.is_a?(Hash) && old.is_a?(Hash)
|
25
|
+
old.merge(new, &merge)
|
26
|
+
else
|
27
|
+
new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
parent.merge(child, &merge)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module VMCManifests
|
2
|
+
module Normalizer
|
3
|
+
MANIFEST_META = ["applications", "properties"]
|
4
|
+
|
5
|
+
def normalize!(manifest)
|
6
|
+
toplevel = toplevel_attributes(manifest)
|
7
|
+
|
8
|
+
apps = manifest["applications"]
|
9
|
+
apps ||= [{}]
|
10
|
+
|
11
|
+
default_paths_to_keys!(apps)
|
12
|
+
|
13
|
+
apps = convert_to_array(apps)
|
14
|
+
|
15
|
+
merge_toplevel!(toplevel, manifest, apps)
|
16
|
+
normalize_apps!(apps)
|
17
|
+
|
18
|
+
manifest["applications"] = apps
|
19
|
+
|
20
|
+
normalize_paths!(apps)
|
21
|
+
|
22
|
+
keyval = normalize_key_val(manifest)
|
23
|
+
manifest.clear.merge!(keyval)
|
24
|
+
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def normalize_paths!(apps)
|
31
|
+
apps.each do |app|
|
32
|
+
app["path"] = from_manifest(app["path"])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def convert_to_array(apps)
|
37
|
+
return apps if apps.is_a?(Array)
|
38
|
+
|
39
|
+
ordered_by_deps(apps)
|
40
|
+
end
|
41
|
+
|
42
|
+
# sort applications in dependency order
|
43
|
+
# e.g. if A depends on B, B will be listed before A
|
44
|
+
def ordered_by_deps(apps, processed = Set[])
|
45
|
+
ordered = []
|
46
|
+
apps.each do |tag, info|
|
47
|
+
next if processed.include?(tag)
|
48
|
+
|
49
|
+
if deps = Array(info["depends-on"])
|
50
|
+
dep_apps = {}
|
51
|
+
deps.each do |dep|
|
52
|
+
dep_apps[dep] = apps[dep]
|
53
|
+
end
|
54
|
+
|
55
|
+
processed.add(tag)
|
56
|
+
|
57
|
+
ordered += ordered_by_deps(dep_apps, processed)
|
58
|
+
ordered << info
|
59
|
+
else
|
60
|
+
ordered << info
|
61
|
+
processed.add(tag)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
ordered.each { |app| app.delete("depends-on") }
|
66
|
+
|
67
|
+
ordered
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_paths_to_keys!(apps)
|
71
|
+
return if apps.is_a?(Array)
|
72
|
+
|
73
|
+
apps.each do |tag, app|
|
74
|
+
app["path"] ||= tag
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def normalize_apps!(apps)
|
79
|
+
apps.each do |app|
|
80
|
+
normalize_app!(app)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def merge_toplevel!(toplevel, manifest, apps)
|
85
|
+
return if toplevel.empty?
|
86
|
+
|
87
|
+
apps.collect! do |a|
|
88
|
+
toplevel.merge(a)
|
89
|
+
end
|
90
|
+
|
91
|
+
toplevel.each do |k, _|
|
92
|
+
manifest.delete k
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def normalize_app!(app)
|
97
|
+
if app["framework"].is_a?(Hash)
|
98
|
+
app["framework"] = app["framework"]["name"]
|
99
|
+
end
|
100
|
+
|
101
|
+
if app.key?("mem")
|
102
|
+
app["memory"] = app.delete("mem")
|
103
|
+
end
|
104
|
+
|
105
|
+
if app.key?("url") && app["url"].nil?
|
106
|
+
app["url"] = "none"
|
107
|
+
end
|
108
|
+
|
109
|
+
if app.key?("subdomain")
|
110
|
+
if app.key?("host")
|
111
|
+
app.delete("subdomain")
|
112
|
+
else
|
113
|
+
app["host"] = app.delete("subdomain")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def toplevel_attributes(manifest)
|
119
|
+
top =
|
120
|
+
manifest.reject { |k, _|
|
121
|
+
MANIFEST_META.include? k
|
122
|
+
}
|
123
|
+
|
124
|
+
# implicit toplevel path of .
|
125
|
+
top["path"] ||= "."
|
126
|
+
|
127
|
+
top
|
128
|
+
end
|
129
|
+
|
130
|
+
def normalize_key_val(val)
|
131
|
+
case val
|
132
|
+
when Hash
|
133
|
+
stringified = {}
|
134
|
+
|
135
|
+
val.each do |k, v|
|
136
|
+
stringified[k.to_sym] = normalize_key_val(v)
|
137
|
+
end
|
138
|
+
|
139
|
+
stringified
|
140
|
+
when Array
|
141
|
+
val.collect { |x| normalize_key_val(x) }
|
142
|
+
when nil
|
143
|
+
nil
|
144
|
+
else
|
145
|
+
val.to_s
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module VMCManifests
|
2
|
+
module Resolver
|
3
|
+
def resolve(manifest, resolver)
|
4
|
+
new = {}
|
5
|
+
|
6
|
+
new[:applications] = manifest[:applications].collect do |app|
|
7
|
+
resolve_lexically(resolver, app, [manifest])
|
8
|
+
end
|
9
|
+
|
10
|
+
resolve_lexically(resolver, new, [new])
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# resolve symbols, with hashes introducing new lexical symbols
|
16
|
+
def resolve_lexically(resolver, val, ctx)
|
17
|
+
case val
|
18
|
+
when Hash
|
19
|
+
new = {}
|
20
|
+
|
21
|
+
val.each do |k, v|
|
22
|
+
new[k] = resolve_lexically(resolver, v, [val] + ctx)
|
23
|
+
end
|
24
|
+
|
25
|
+
new
|
26
|
+
when Array
|
27
|
+
val.collect do |v|
|
28
|
+
resolve_lexically(resolver, v, ctx)
|
29
|
+
end
|
30
|
+
when String
|
31
|
+
val.gsub(/\$\{([^\}]+)\}/) do
|
32
|
+
resolve_symbol(resolver, $1, ctx)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
val
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# resolve a symbol to its value, and then resolve that value
|
40
|
+
def resolve_symbol(resolver, sym, ctx)
|
41
|
+
if found = find_symbol(sym.to_sym, ctx)
|
42
|
+
resolve_lexically(resolver, found, ctx)
|
43
|
+
found
|
44
|
+
elsif dynamic = resolver.resolve_symbol(sym)
|
45
|
+
dynamic
|
46
|
+
else
|
47
|
+
fail("Unknown symbol in manifest: #{sym}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# search for a symbol introduced in the lexical context
|
52
|
+
def find_symbol(sym, ctx)
|
53
|
+
ctx.each do |h|
|
54
|
+
if val = resolve_in(h, sym)
|
55
|
+
return val
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# find a value, searching in explicit properties first
|
63
|
+
def resolve_in(hash, *where)
|
64
|
+
find_in_hash(hash, [:properties] + where) ||
|
65
|
+
find_in_hash(hash, where)
|
66
|
+
end
|
67
|
+
|
68
|
+
# helper for following a path of values in a hash
|
69
|
+
def find_in_hash(hash, where)
|
70
|
+
what = hash
|
71
|
+
where.each do |x|
|
72
|
+
return nil unless what.is_a?(Hash)
|
73
|
+
what = what[x]
|
74
|
+
end
|
75
|
+
|
76
|
+
what
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "manifests-vmc-plugin/loader/builder"
|
2
|
+
require "manifests-vmc-plugin/loader/normalizer"
|
3
|
+
require "manifests-vmc-plugin/loader/resolver"
|
4
|
+
|
5
|
+
module VMCManifests
|
6
|
+
class Loader
|
7
|
+
include Builder
|
8
|
+
include Normalizer
|
9
|
+
include Resolver
|
10
|
+
|
11
|
+
def initialize(file, resolver)
|
12
|
+
@file = file
|
13
|
+
@resolver = resolver
|
14
|
+
end
|
15
|
+
|
16
|
+
def manifest
|
17
|
+
info = build(@file)
|
18
|
+
normalize! info
|
19
|
+
resolve info, @resolver
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# expand a path relative to the manifest file's directory
|
25
|
+
def from_manifest(path)
|
26
|
+
return path unless @file
|
27
|
+
|
28
|
+
File.expand_path(path, File.dirname(@file))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
require "vmc/plugin"
|
4
|
+
require "manifests-vmc-plugin"
|
5
|
+
|
6
|
+
|
7
|
+
class ManifestsPlugin < VMC::App::Base
|
8
|
+
include VMCManifests
|
9
|
+
|
10
|
+
option :manifest, :aliases => "-m", :value => :file,
|
11
|
+
:desc => "Path to manifest file to use"
|
12
|
+
|
13
|
+
|
14
|
+
[ :start, :restart, :instances, :logs, :env, :health, :stats,
|
15
|
+
:scale, :app, :stop, :delete
|
16
|
+
].each do |wrap|
|
17
|
+
name_made_optional = change_argument(wrap, :app, :optional)
|
18
|
+
|
19
|
+
around(wrap) do |cmd, input|
|
20
|
+
wrap_with_optional_name(name_made_optional, cmd, input)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
add_input :push, :reset, :desc => "Reset to values in the manifest",
|
26
|
+
:default => false
|
27
|
+
|
28
|
+
around(:push) do |push, input|
|
29
|
+
wrap_push(push, input)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def wrap_with_optional_name(name_made_optional, cmd, input)
|
35
|
+
return cmd.call if input[:all]
|
36
|
+
|
37
|
+
unless manifest
|
38
|
+
# if the command knows how to handle this
|
39
|
+
if input.has?(:app) || !name_made_optional
|
40
|
+
return cmd.call
|
41
|
+
else
|
42
|
+
return no_apps
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
internal, external = apps_in_manifest(input)
|
47
|
+
|
48
|
+
return cmd.call if internal.empty? && !external.empty?
|
49
|
+
|
50
|
+
show_manifest_usage
|
51
|
+
|
52
|
+
if internal.empty? && external.empty?
|
53
|
+
internal = current_apps if internal.empty?
|
54
|
+
internal = all_apps if internal.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
internal = internal.collect { |app| app[:name] }
|
58
|
+
|
59
|
+
apps = internal + external
|
60
|
+
return no_apps if apps.empty?
|
61
|
+
|
62
|
+
apps.each.with_index do |app, num|
|
63
|
+
line unless quiet? || num == 0
|
64
|
+
cmd.call(input.without(:apps).merge_given(:app => app))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def apply_changes(app, input)
|
69
|
+
app.memory = megabytes(input[:memory]) if input.has?(:memory)
|
70
|
+
app.total_instances = input[:instances] if input.has?(:instances)
|
71
|
+
app.command = input[:command] if input.has?(:command)
|
72
|
+
app.production = input[:plan].upcase.start_with?("P") if input.has?(:plan)
|
73
|
+
app.framework = input[:framework] if input.has?(:framework)
|
74
|
+
app.runtime = input[:runtime] if input.has?(:runtime)
|
75
|
+
app.buildpack = input[:buildpack] if input.has?(:buildpack)
|
76
|
+
end
|
77
|
+
|
78
|
+
def wrap_push(push, input)
|
79
|
+
unless manifest
|
80
|
+
create_and_save_manifest(push, input)
|
81
|
+
return
|
82
|
+
end
|
83
|
+
|
84
|
+
particular, external = apps_in_manifest(input)
|
85
|
+
|
86
|
+
unless external.empty?
|
87
|
+
fail "Could not find #{b(external.join(", "))}' in the manifest."
|
88
|
+
end
|
89
|
+
|
90
|
+
apps = particular.empty? ? all_apps : particular
|
91
|
+
|
92
|
+
show_manifest_usage
|
93
|
+
|
94
|
+
spaced(apps) do |app_manifest|
|
95
|
+
push_with_manifest(app_manifest, push, input)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def push_with_manifest(app_manifest, push, input)
|
100
|
+
with_filters(
|
101
|
+
:push => {
|
102
|
+
:create_app => proc { |a|
|
103
|
+
setup_env(a, app_manifest)
|
104
|
+
a
|
105
|
+
},
|
106
|
+
:push_app => proc { |a|
|
107
|
+
setup_services(a, app_manifest)
|
108
|
+
a
|
109
|
+
}
|
110
|
+
}) do
|
111
|
+
app_input = push_input_for(app_manifest, input)
|
112
|
+
|
113
|
+
push.call(app_input)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def push_input_for(app_manifest, input)
|
118
|
+
existing_app = client.app_by_name(app_manifest[:name])
|
119
|
+
rebased_input = input.rebase_given(app_manifest)
|
120
|
+
|
121
|
+
if !existing_app || input[:reset]
|
122
|
+
input = rebased_input
|
123
|
+
else
|
124
|
+
warn_reset_changes if manifest_differs?(existing_app, rebased_input)
|
125
|
+
end
|
126
|
+
|
127
|
+
input.merge(
|
128
|
+
:path => from_manifest(app_manifest[:path]),
|
129
|
+
:name => app_manifest[:name],
|
130
|
+
:bind_services => false,
|
131
|
+
:create_services => false)
|
132
|
+
end
|
133
|
+
|
134
|
+
def manifest_differs?(app, input)
|
135
|
+
apply_changes(app, input)
|
136
|
+
app.changed?
|
137
|
+
end
|
138
|
+
|
139
|
+
def create_and_save_manifest(push, input)
|
140
|
+
with_filters(
|
141
|
+
:push => { :push_app => proc { |a| ask_to_save(input, a); a } }) do
|
142
|
+
push.call
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|