appfog-vmc-plugin 0.1.8 → 0.1.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.
- checksums.yaml +8 -8
- data/lib/appfog-vmc-plugin/cfoundry/upload_helpers.rb +1 -1
- data/lib/appfog-vmc-plugin/commands/pull.rb +2 -0
- data/lib/appfog-vmc-plugin/plugin.rb +2 -0
- data/lib/appfog-vmc-plugin/version.rb +1 -1
- data/lib/appfog-vmc-plugin/vmc/app/instances.rb +1 -1
- 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 +141 -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/manifests.rb +315 -0
- data/lib/manifests-vmc-plugin/plugin.rb +149 -0
- data/lib/manifests-vmc-plugin/version.rb +3 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MzFlNWE1ZGY2M2RhYzE5YzhhMDQ0YzlmZTU1NTdhNDE3MjY5MTEzZg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MGVhMzA0NTE3MzcxMjhiYjZiY2E0YTczYWEzNzZiZGU1ODY5ZjU2Ng==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MmU1YmM0MWE0MGQ5YWEwMDIwZTczOTMyNWRmMTUxYWQ4YzVjYzdlM2IwZmE0
|
10
|
+
MTZjNjYwYmUyNTk2ODYxMGE4OTg4MjkzZDBmYTkxOWRjN2U0ZTc3OWY2YTI2
|
11
|
+
NjIyZmI1OTMxNzgzOGZmMThiYjIwODQ1MDk5ZDhjMDhlMmU4ZWI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Mzg3NDllNWE0ZjNhZTdmMzc1Y2QzOTBhMmY2NGEyMGEyYTU0NDE0ZDczNDE2
|
14
|
+
NWM2OGE2ZjgzYjQ0ODgxMjY0NWNkMTI5MTViNTc0ZTFkNzNiMTAwMTViMDZl
|
15
|
+
YTI3MTEzMGQ1MjBhODM2ZDUwNjYzOWNmMTAwMjM1MWMyNDhlOWE=
|
@@ -4,6 +4,8 @@ require "appfog-vmc-plugin/cfoundry"
|
|
4
4
|
require "appfog-vmc-plugin/vmc"
|
5
5
|
require "appfog-vmc-plugin/help"
|
6
6
|
require "appfog-vmc-plugin/net_http"
|
7
|
+
require "manifests-vmc-plugin/plugin"
|
8
|
+
|
7
9
|
|
8
10
|
command_files = "../deprecated/**/*.rb"
|
9
11
|
Dir[File.expand_path(command_files, __FILE__)].each do |file|
|
@@ -17,7 +17,7 @@ module VMC::App
|
|
17
17
|
inst = input[:inst, app.total_instances]
|
18
18
|
end
|
19
19
|
|
20
|
-
app.total_instances = inst if input.has?(:inst)
|
20
|
+
app.total_instances = inst.to_i if input.has?(:inst)
|
21
21
|
fail "No changes!" unless app.changed?
|
22
22
|
|
23
23
|
with_progress("Scaling #{c(app.name, :name)}") do
|
@@ -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,141 @@
|
|
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
|
+
end
|
109
|
+
|
110
|
+
def toplevel_attributes(manifest)
|
111
|
+
top =
|
112
|
+
manifest.reject { |k, _|
|
113
|
+
MANIFEST_META.include? k
|
114
|
+
}
|
115
|
+
|
116
|
+
# implicit toplevel path of .
|
117
|
+
top["path"] ||= "."
|
118
|
+
|
119
|
+
top
|
120
|
+
end
|
121
|
+
|
122
|
+
def normalize_key_val(val)
|
123
|
+
case val
|
124
|
+
when Hash
|
125
|
+
stringified = {}
|
126
|
+
|
127
|
+
val.each do |k, v|
|
128
|
+
stringified[k.to_sym] = normalize_key_val(v)
|
129
|
+
end
|
130
|
+
|
131
|
+
stringified
|
132
|
+
when Array
|
133
|
+
val.collect { |x| normalize_key_val(x) }
|
134
|
+
when nil
|
135
|
+
nil
|
136
|
+
else
|
137
|
+
val.to_s
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
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,315 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "set"
|
3
|
+
|
4
|
+
require "manifests-vmc-plugin/loader"
|
5
|
+
|
6
|
+
|
7
|
+
module VMCManifests
|
8
|
+
MANIFEST_FILE = "manifest.yml"
|
9
|
+
|
10
|
+
@@showed_manifest_usage = false
|
11
|
+
|
12
|
+
def manifest
|
13
|
+
return @manifest if @manifest
|
14
|
+
|
15
|
+
if manifest_file && File.exists?(manifest_file)
|
16
|
+
@manifest = load_manifest(manifest_file)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def save_manifest(save_to = manifest_file)
|
21
|
+
fail "No manifest to save!" unless @manifest
|
22
|
+
|
23
|
+
File.open(save_to, "w") do |io|
|
24
|
+
YAML.dump(@manifest, io)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# find the manifest file to work with
|
29
|
+
def manifest_file
|
30
|
+
return @manifest_file if @manifest_file
|
31
|
+
|
32
|
+
unless path = input[:manifest]
|
33
|
+
where = Dir.pwd
|
34
|
+
while true
|
35
|
+
if File.exists?(File.join(where, MANIFEST_FILE))
|
36
|
+
path = File.join(where, MANIFEST_FILE)
|
37
|
+
break
|
38
|
+
elsif File.basename(where) == "/"
|
39
|
+
path = nil
|
40
|
+
break
|
41
|
+
else
|
42
|
+
where = File.expand_path("../", where)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
return unless path
|
48
|
+
|
49
|
+
@manifest_file = File.expand_path(path)
|
50
|
+
end
|
51
|
+
|
52
|
+
# load and resolve a given manifest file
|
53
|
+
def load_manifest(file)
|
54
|
+
Loader.new(file, self).manifest
|
55
|
+
end
|
56
|
+
|
57
|
+
# dynamic symbol resolution
|
58
|
+
def resolve_symbol(sym)
|
59
|
+
case sym
|
60
|
+
when "target-url"
|
61
|
+
client_target
|
62
|
+
|
63
|
+
when "target-base"
|
64
|
+
target_base
|
65
|
+
|
66
|
+
when "random-word"
|
67
|
+
sprintf("%04x", rand(0x0100000))
|
68
|
+
|
69
|
+
when /^ask (.+)/
|
70
|
+
ask($1)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# find apps by an identifier, which may be either a tag, a name, or a path
|
75
|
+
def find_apps(identifier)
|
76
|
+
return [] unless manifest
|
77
|
+
|
78
|
+
apps = apps_by(:name, identifier)
|
79
|
+
|
80
|
+
if apps.empty?
|
81
|
+
apps = apps_by(:path, from_manifest(identifier))
|
82
|
+
end
|
83
|
+
|
84
|
+
apps
|
85
|
+
end
|
86
|
+
|
87
|
+
# return all the apps described by the manifest
|
88
|
+
def all_apps
|
89
|
+
manifest[:applications]
|
90
|
+
end
|
91
|
+
|
92
|
+
def current_apps
|
93
|
+
manifest[:applications].select do |app|
|
94
|
+
next unless app[:path]
|
95
|
+
from_manifest(app[:path]) == Dir.pwd
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# splits the user's input, resolving paths with the manifest,
|
100
|
+
# into internal/external apps
|
101
|
+
#
|
102
|
+
# internal apps are returned as their data in the manifest
|
103
|
+
#
|
104
|
+
# external apps are the strings that the user gave, to be
|
105
|
+
# passed along wholesale to the wrapped command
|
106
|
+
def apps_in_manifest(input = nil, use_name = true, &blk)
|
107
|
+
names_or_paths =
|
108
|
+
if input.has?(:apps)
|
109
|
+
# names may be given but be [], which will still cause
|
110
|
+
# interaction, so use #direct instead of #[] here
|
111
|
+
input.direct(:apps)
|
112
|
+
elsif input.has?(:app)
|
113
|
+
[input.direct(:app)]
|
114
|
+
elsif input.has?(:name)
|
115
|
+
[input.direct(:name)]
|
116
|
+
else
|
117
|
+
[]
|
118
|
+
end
|
119
|
+
|
120
|
+
internal = []
|
121
|
+
external = []
|
122
|
+
|
123
|
+
names_or_paths.each do |x|
|
124
|
+
if x.is_a?(String)
|
125
|
+
if x =~ %r([/\\])
|
126
|
+
apps = find_apps(File.expand_path(x))
|
127
|
+
|
128
|
+
if apps.empty?
|
129
|
+
fail("Path #{b(x)} is not present in manifest #{b(relative_manifest_file)}.")
|
130
|
+
end
|
131
|
+
else
|
132
|
+
apps = find_apps(x)
|
133
|
+
end
|
134
|
+
|
135
|
+
if !apps.empty?
|
136
|
+
internal += apps
|
137
|
+
else
|
138
|
+
external << x
|
139
|
+
end
|
140
|
+
else
|
141
|
+
external << x
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
[internal, external]
|
146
|
+
end
|
147
|
+
|
148
|
+
def create_manifest_for(app, path)
|
149
|
+
meta = {
|
150
|
+
"name" => app.name,
|
151
|
+
"infra" => app.infra.name,
|
152
|
+
"framework" => app.framework.name,
|
153
|
+
"runtime" => app.runtime.name,
|
154
|
+
"memory" => human_size(app.memory * 1024 * 1024, 0),
|
155
|
+
"instances" => app.total_instances,
|
156
|
+
"url" => app.url ? app.url.sub(target_base, '${target-base}') : "none",
|
157
|
+
"path" => path
|
158
|
+
}
|
159
|
+
|
160
|
+
services = app.services
|
161
|
+
|
162
|
+
unless services.empty?
|
163
|
+
meta["services"] = {}
|
164
|
+
|
165
|
+
services.each do |i|
|
166
|
+
if v2?
|
167
|
+
p = i.service_plan
|
168
|
+
s = p.service
|
169
|
+
|
170
|
+
meta["services"][i.name] = {
|
171
|
+
"label" => s.label,
|
172
|
+
"provider" => s.provider,
|
173
|
+
"version" => s.version,
|
174
|
+
"plan" => p.name
|
175
|
+
}
|
176
|
+
else
|
177
|
+
meta["services"][i.name] = {
|
178
|
+
"infra" => i.infra.name,
|
179
|
+
"vendor" => i.vendor,
|
180
|
+
"version" => i.version,
|
181
|
+
"tier" => i.tier
|
182
|
+
}
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
if cmd = app.command
|
188
|
+
meta["command"] = cmd
|
189
|
+
end
|
190
|
+
|
191
|
+
meta
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
def relative_manifest_file
|
197
|
+
Pathname.new(manifest_file).relative_path_from(Pathname.pwd)
|
198
|
+
end
|
199
|
+
|
200
|
+
def show_manifest_usage
|
201
|
+
return if @@showed_manifest_usage
|
202
|
+
|
203
|
+
path = relative_manifest_file
|
204
|
+
line "Using manifest file #{c(path, :name)}"
|
205
|
+
line
|
206
|
+
|
207
|
+
@@showed_manifest_usage = true
|
208
|
+
end
|
209
|
+
|
210
|
+
def no_apps
|
211
|
+
fail "No applications or manifest to operate on."
|
212
|
+
end
|
213
|
+
|
214
|
+
def warn_reset_changes
|
215
|
+
line c("Not applying manifest changes without --reset", :warning)
|
216
|
+
line "See `vmc diff` for more details."
|
217
|
+
line
|
218
|
+
end
|
219
|
+
|
220
|
+
def apps_by(attr, val)
|
221
|
+
manifest[:applications].select do |info|
|
222
|
+
info[attr] == val
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# expand a path relative to the manifest file's directory
|
227
|
+
def from_manifest(path)
|
228
|
+
File.expand_path(path, File.dirname(manifest_file))
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
def ask_to_save(input, app)
|
233
|
+
return if manifest_file
|
234
|
+
return unless ask("Save configuration?", :default => false)
|
235
|
+
|
236
|
+
manifest = create_manifest_for(app, input[:path])
|
237
|
+
|
238
|
+
with_progress("Saving to #{c("manifest.yml", :name)}") do
|
239
|
+
File.open("manifest.yml", "w") do |io|
|
240
|
+
YAML.dump(
|
241
|
+
{ "applications" => [manifest] },
|
242
|
+
io)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def env_hash(val)
|
248
|
+
if val.is_a?(Hash)
|
249
|
+
val
|
250
|
+
else
|
251
|
+
hash = {}
|
252
|
+
|
253
|
+
val.each do |pair|
|
254
|
+
name, val = pair.split("=", 2)
|
255
|
+
hash[name] = val
|
256
|
+
end
|
257
|
+
|
258
|
+
hash
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def setup_env(app, info)
|
263
|
+
return unless info[:env]
|
264
|
+
app.env = env_hash(info[:env])
|
265
|
+
end
|
266
|
+
|
267
|
+
def setup_services(app, info)
|
268
|
+
return if !info[:services] || info[:services].empty?
|
269
|
+
|
270
|
+
offerings = client.services
|
271
|
+
|
272
|
+
to_bind = []
|
273
|
+
|
274
|
+
info[:services].each do |name, svc|
|
275
|
+
name = name.to_s
|
276
|
+
|
277
|
+
if instance = client.service_instance_by_name(name)
|
278
|
+
to_bind << instance
|
279
|
+
else
|
280
|
+
offering = offerings.find { |o|
|
281
|
+
o.label == (svc[:label] || svc[:type] || svc[:vendor]) &&
|
282
|
+
(!svc[:version] || o.version == svc[:version]) &&
|
283
|
+
(o.provider == (svc[:provider] || "core"))
|
284
|
+
}
|
285
|
+
|
286
|
+
fail "Unknown service offering: #{svc.inspect}." unless offering
|
287
|
+
|
288
|
+
if v2?
|
289
|
+
plan = offering.service_plans.find { |p|
|
290
|
+
p.name == (svc[:plan] || "D100")
|
291
|
+
}
|
292
|
+
|
293
|
+
fail "Unknown service plan: #{svc[:plan]}." unless plan
|
294
|
+
end
|
295
|
+
|
296
|
+
invoke :create_service,
|
297
|
+
:name => name,
|
298
|
+
:offering => offering,
|
299
|
+
:plan => plan,
|
300
|
+
:app => app
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
to_bind.each do |s|
|
305
|
+
next if app.binds?(s)
|
306
|
+
|
307
|
+
# TODO: splat
|
308
|
+
invoke :bind_service, :app => app, :service => s
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def target_base
|
313
|
+
client_target.sub(/^[^\.]+\./, "")
|
314
|
+
end
|
315
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
require "vmc/plugin"
|
4
|
+
require "manifests-vmc-plugin/manifests"
|
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
|
+
# around(:pull) do |push, input|
|
33
|
+
# wrap_push(push, input)
|
34
|
+
# end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def wrap_with_optional_name(name_made_optional, cmd, input)
|
39
|
+
return cmd.call if input[:all]
|
40
|
+
|
41
|
+
unless manifest
|
42
|
+
# if the command knows how to handle this
|
43
|
+
if input.has?(:app) || !name_made_optional
|
44
|
+
return cmd.call
|
45
|
+
else
|
46
|
+
return no_apps
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
internal, external = apps_in_manifest(input)
|
51
|
+
|
52
|
+
return cmd.call if internal.empty? && !external.empty?
|
53
|
+
|
54
|
+
show_manifest_usage
|
55
|
+
|
56
|
+
if internal.empty? && external.empty?
|
57
|
+
internal = current_apps if internal.empty?
|
58
|
+
internal = all_apps if internal.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
internal = internal.collect { |app| app[:name] }
|
62
|
+
|
63
|
+
apps = internal + external
|
64
|
+
return no_apps if apps.empty?
|
65
|
+
|
66
|
+
apps.each.with_index do |app, num|
|
67
|
+
line unless quiet? || num == 0
|
68
|
+
cmd.call(input.without(:apps).merge_given(:app => app))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def apply_changes(app, input)
|
73
|
+
app.memory = megabytes(input[:memory]) if input.has?(:memory)
|
74
|
+
app.total_instances = input[:instances] if input.has?(:instances)
|
75
|
+
app.command = input[:command] if input.has?(:command)
|
76
|
+
app.production = input[:plan].upcase.start_with?("P") if input.has?(:plan)
|
77
|
+
app.infra = input[:infra] if input.has?(:infra)
|
78
|
+
app.framework = input[:framework] if input.has?(:framework)
|
79
|
+
app.runtime = input[:runtime] if input.has?(:runtime)
|
80
|
+
app.buildpack = input[:buildpack] if input.has?(:buildpack)
|
81
|
+
end
|
82
|
+
|
83
|
+
def wrap_push(push, input)
|
84
|
+
unless manifest
|
85
|
+
create_and_save_manifest(push, input)
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
particular, external = apps_in_manifest(input)
|
90
|
+
|
91
|
+
unless external.empty?
|
92
|
+
fail "Could not find #{b(external.join(", "))}' in the manifest."
|
93
|
+
end
|
94
|
+
|
95
|
+
apps = particular.empty? ? all_apps : particular
|
96
|
+
|
97
|
+
show_manifest_usage
|
98
|
+
|
99
|
+
spaced(apps) do |app_manifest|
|
100
|
+
push_with_manifest(app_manifest, push, input)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def push_with_manifest(app_manifest, push, input)
|
105
|
+
with_filters(
|
106
|
+
:push => {
|
107
|
+
:create_app => proc { |a|
|
108
|
+
setup_env(a, app_manifest)
|
109
|
+
a
|
110
|
+
},
|
111
|
+
:push_app => proc { |a|
|
112
|
+
setup_services(a, app_manifest)
|
113
|
+
a
|
114
|
+
}
|
115
|
+
}) do
|
116
|
+
app_input = push_input_for(app_manifest, input)
|
117
|
+
|
118
|
+
push.call(app_input)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def push_input_for(app_manifest, input)
|
123
|
+
existing_app = client.app_by_name(app_manifest[:name])
|
124
|
+
|
125
|
+
if !existing_app || input[:reset]
|
126
|
+
input = input.rebase_given(app_manifest)
|
127
|
+
else
|
128
|
+
warn_reset_changes if manifest_differs?(existing_app, input)
|
129
|
+
end
|
130
|
+
|
131
|
+
input.merge(
|
132
|
+
:path => from_manifest(app_manifest[:path]),
|
133
|
+
:name => app_manifest[:name],
|
134
|
+
:bind_services => false,
|
135
|
+
:create_services => false)
|
136
|
+
end
|
137
|
+
|
138
|
+
def manifest_differs?(app, input)
|
139
|
+
apply_changes(app, input)
|
140
|
+
app.changed?
|
141
|
+
end
|
142
|
+
|
143
|
+
def create_and_save_manifest(push, input)
|
144
|
+
with_filters(
|
145
|
+
:push => { :push_app => proc { |a| ask_to_save(input, a); a } }) do
|
146
|
+
push.call
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appfog-vmc-plugin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Santeford
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cfoundry
|
@@ -65,6 +65,14 @@ files:
|
|
65
65
|
- lib/appfog-vmc-plugin/vmc/start/login.rb
|
66
66
|
- lib/appfog-vmc-plugin/vmc/user/base.rb
|
67
67
|
- lib/appfog-vmc-plugin/vmc.rb
|
68
|
+
- lib/manifests-vmc-plugin/errors.rb
|
69
|
+
- lib/manifests-vmc-plugin/loader/builder.rb
|
70
|
+
- lib/manifests-vmc-plugin/loader/normalizer.rb
|
71
|
+
- lib/manifests-vmc-plugin/loader/resolver.rb
|
72
|
+
- lib/manifests-vmc-plugin/loader.rb
|
73
|
+
- lib/manifests-vmc-plugin/manifests.rb
|
74
|
+
- lib/manifests-vmc-plugin/plugin.rb
|
75
|
+
- lib/manifests-vmc-plugin/version.rb
|
68
76
|
homepage: http://www.appfog.com/
|
69
77
|
licenses: []
|
70
78
|
metadata: {}
|