leap_cli 1.7.4 → 1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/leap +6 -13
- data/lib/leap/platform.rb +2 -0
- data/lib/leap_cli.rb +2 -1
- data/lib/leap_cli/bootstrap.rb +197 -0
- data/lib/leap_cli/commands/common.rb +61 -0
- data/lib/leap_cli/commands/new.rb +5 -1
- data/lib/leap_cli/commands/pre.rb +1 -66
- data/lib/leap_cli/config/environment.rb +180 -0
- data/lib/leap_cli/config/manager.rb +100 -197
- data/lib/leap_cli/config/node.rb +2 -2
- data/lib/leap_cli/config/object.rb +56 -43
- data/lib/leap_cli/config/object_list.rb +6 -3
- data/lib/leap_cli/config/provider.rb +11 -0
- data/lib/leap_cli/config/secrets.rb +14 -1
- data/lib/leap_cli/config/tag.rb +2 -2
- data/lib/leap_cli/leapfile.rb +1 -0
- data/lib/leap_cli/log.rb +1 -0
- data/lib/leap_cli/logger.rb +16 -12
- data/lib/leap_cli/markdown_document_listener.rb +3 -1
- data/lib/leap_cli/path.rb +12 -0
- data/lib/leap_cli/remote/leap_plugin.rb +9 -34
- data/lib/leap_cli/remote/puppet_plugin.rb +0 -40
- data/lib/leap_cli/remote/tasks.rb +9 -34
- data/lib/leap_cli/ssh_key.rb +5 -2
- data/lib/leap_cli/version.rb +2 -2
- metadata +5 -18
- data/lib/leap_cli/commands/ca.rb +0 -518
- data/lib/leap_cli/commands/clean.rb +0 -16
- data/lib/leap_cli/commands/compile.rb +0 -340
- data/lib/leap_cli/commands/db.rb +0 -65
- data/lib/leap_cli/commands/deploy.rb +0 -368
- data/lib/leap_cli/commands/env.rb +0 -76
- data/lib/leap_cli/commands/facts.rb +0 -100
- data/lib/leap_cli/commands/inspect.rb +0 -144
- data/lib/leap_cli/commands/list.rb +0 -132
- data/lib/leap_cli/commands/node.rb +0 -165
- data/lib/leap_cli/commands/node_init.rb +0 -169
- data/lib/leap_cli/commands/ssh.rb +0 -220
- data/lib/leap_cli/commands/test.rb +0 -74
- data/lib/leap_cli/commands/user.rb +0 -136
- data/lib/leap_cli/commands/util.rb +0 -50
- data/lib/leap_cli/commands/vagrant.rb +0 -197
@@ -0,0 +1,180 @@
|
|
1
|
+
#
|
2
|
+
# All configurations files can be isolated into separate environments.
|
3
|
+
#
|
4
|
+
# Each config json in each environment inherits from the default environment,
|
5
|
+
# which in term inherits from the "_base_" environment:
|
6
|
+
#
|
7
|
+
# _base_ -- base provider in leap_platform
|
8
|
+
# '- default -- environment in provider dir when no env is set
|
9
|
+
# '- production -- example environment
|
10
|
+
#
|
11
|
+
|
12
|
+
module LeapCli; module Config
|
13
|
+
|
14
|
+
class Environment
|
15
|
+
# the String name of the environment
|
16
|
+
attr_accessor :name
|
17
|
+
|
18
|
+
# the shared Manager object
|
19
|
+
attr_accessor :manager
|
20
|
+
|
21
|
+
# hashes of {name => Config::Object}
|
22
|
+
attr_accessor :services, :tags, :partials
|
23
|
+
|
24
|
+
# a Config::Provider
|
25
|
+
attr_accessor :provider
|
26
|
+
|
27
|
+
# a Config::Object
|
28
|
+
attr_accessor :common
|
29
|
+
|
30
|
+
# shared, non-inheritable
|
31
|
+
def nodes; @@nodes; end
|
32
|
+
def secrets; @@secrets; end
|
33
|
+
|
34
|
+
def initialize(manager, name, search_dir, parent, options={})
|
35
|
+
@@nodes ||= nil
|
36
|
+
@@secrets ||= nil
|
37
|
+
|
38
|
+
@manager = manager
|
39
|
+
@name = name
|
40
|
+
|
41
|
+
load_provider_files(search_dir, options)
|
42
|
+
|
43
|
+
if parent
|
44
|
+
@services.inherit_from! parent.services, self
|
45
|
+
@tags.inherit_from! parent.tags , self
|
46
|
+
@partials.inherit_from! parent.partials, self
|
47
|
+
@common.inherit_from! parent.common
|
48
|
+
@provider.inherit_from! parent.provider
|
49
|
+
end
|
50
|
+
|
51
|
+
if @provider
|
52
|
+
@provider.set_env(name)
|
53
|
+
@provider.validate!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_provider_files(search_dir, options)
|
58
|
+
#
|
59
|
+
# load empty environment if search_dir doesn't exist
|
60
|
+
#
|
61
|
+
if search_dir.nil? || !Dir.exist?(search_dir)
|
62
|
+
@services = Config::ObjectList.new
|
63
|
+
@tags = Config::ObjectList.new
|
64
|
+
@partials = Config::ObjectList.new
|
65
|
+
@provider = Config::Provider.new
|
66
|
+
@common = Config::Object.new
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# inheritable
|
72
|
+
#
|
73
|
+
if options[:scope]
|
74
|
+
scope = options[:scope]
|
75
|
+
@services = load_all_json(Path.named_path([:service_env_config, '*', scope], search_dir), Config::Tag, options)
|
76
|
+
@tags = load_all_json(Path.named_path([:tag_env_config, '*', scope], search_dir), Config::Tag, options)
|
77
|
+
@partials = load_all_json(Path.named_path([:service_env_config, '_*', scope], search_dir), Config::Tag, options)
|
78
|
+
@provider = load_json( Path.named_path([:provider_env_config, scope], search_dir), Config::Provider, options)
|
79
|
+
@common = load_json( Path.named_path([:common_env_config, scope], search_dir), Config::Object, options)
|
80
|
+
else
|
81
|
+
@services = load_all_json(Path.named_path([:service_config, '*'], search_dir), Config::Tag, options)
|
82
|
+
@tags = load_all_json(Path.named_path([:tag_config, '*'], search_dir), Config::Tag, options)
|
83
|
+
@partials = load_all_json(Path.named_path([:service_config, '_*'], search_dir), Config::Tag, options)
|
84
|
+
@provider = load_json( Path.named_path(:provider_config, search_dir), Config::Provider, options)
|
85
|
+
@common = load_json( Path.named_path(:common_config, search_dir), Config::Object, options)
|
86
|
+
end
|
87
|
+
|
88
|
+
# remove 'name' from partials, since partials get merged with nodes
|
89
|
+
@partials.values.each {|partial| partial.delete('name'); }
|
90
|
+
|
91
|
+
#
|
92
|
+
# shared: currently non-inheritable
|
93
|
+
# load the first ones we find, and only those.
|
94
|
+
#
|
95
|
+
if @@nodes.nil? || @@nodes.empty?
|
96
|
+
@@nodes = load_all_json(Path.named_path([:node_config, '*'], search_dir), Config::Node, options)
|
97
|
+
end
|
98
|
+
if @@secrets.nil? || @@secrets.empty?
|
99
|
+
@@secrets = load_json(Path.named_path(:secrets_config, search_dir), Config::Secrets, options)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Loads a json template file as a Hash (used only when creating a new node .json
|
105
|
+
# file for the first time).
|
106
|
+
#
|
107
|
+
def template(template)
|
108
|
+
path = Path.named_path([:template_config, template], Path.provider_base)
|
109
|
+
if File.exists?(path)
|
110
|
+
return load_json(path, Config::Object)
|
111
|
+
else
|
112
|
+
return nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def load_all_json(pattern, object_class, options={})
|
119
|
+
results = Config::ObjectList.new
|
120
|
+
Dir.glob(pattern).each do |filename|
|
121
|
+
next if options[:no_dots] && File.basename(filename) !~ /^[^\.]*\.json$/
|
122
|
+
obj = load_json(filename, object_class)
|
123
|
+
if obj
|
124
|
+
name = File.basename(filename).force_encoding('utf-8').sub(/^([^\.]+).*\.json$/,'\1')
|
125
|
+
obj['name'] ||= name
|
126
|
+
if options[:env]
|
127
|
+
obj.environment = options[:env]
|
128
|
+
end
|
129
|
+
results[name] = obj
|
130
|
+
end
|
131
|
+
end
|
132
|
+
results
|
133
|
+
end
|
134
|
+
|
135
|
+
def load_json(filename, object_class, options={})
|
136
|
+
if !File.exists?(filename)
|
137
|
+
return object_class.new(self)
|
138
|
+
end
|
139
|
+
|
140
|
+
Util::log :loading, filename, 3
|
141
|
+
|
142
|
+
#
|
143
|
+
# Read a JSON file, strip out comments.
|
144
|
+
#
|
145
|
+
# UTF8 is the default encoding for JSON, but others are allowed:
|
146
|
+
# https://www.ietf.org/rfc/rfc4627.txt
|
147
|
+
#
|
148
|
+
buffer = StringIO.new
|
149
|
+
File.open(filename, "rb", :encoding => 'UTF-8') do |f|
|
150
|
+
while (line = f.gets)
|
151
|
+
next if line =~ /^\s*\/\//
|
152
|
+
buffer << line
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# force UTF-8
|
158
|
+
#
|
159
|
+
if $ruby_version >= [1,9]
|
160
|
+
string = buffer.string.force_encoding('utf-8')
|
161
|
+
else
|
162
|
+
string = Iconv.conv("UTF-8//IGNORE", "UTF-8", buffer.string)
|
163
|
+
end
|
164
|
+
|
165
|
+
# parse json
|
166
|
+
begin
|
167
|
+
hash = JSON.parse(string, :object_class => Hash, :array_class => Array) || {}
|
168
|
+
rescue SyntaxError, JSON::ParserError => exc
|
169
|
+
Util::log 0, :error, 'in file "%s":' % filename
|
170
|
+
Util::log 0, exc.to_s, :indent => 1
|
171
|
+
return nil
|
172
|
+
end
|
173
|
+
object = object_class.new(self)
|
174
|
+
object.deep_merge!(hash)
|
175
|
+
return object
|
176
|
+
end
|
177
|
+
|
178
|
+
end # end Environment
|
179
|
+
|
180
|
+
end; end
|
@@ -9,10 +9,6 @@ end
|
|
9
9
|
module LeapCli
|
10
10
|
module Config
|
11
11
|
|
12
|
-
class Environment
|
13
|
-
attr_accessor :services, :tags, :provider
|
14
|
-
end
|
15
|
-
|
16
12
|
#
|
17
13
|
# A class to manage all the objects in all the configuration files.
|
18
14
|
#
|
@@ -20,15 +16,6 @@ module LeapCli
|
|
20
16
|
|
21
17
|
def initialize
|
22
18
|
@environments = {} # hash of `Environment` objects, keyed by name.
|
23
|
-
|
24
|
-
# load macros and other custom ruby in provider base
|
25
|
-
platform_ruby_files = Dir[Path.provider_base + '/lib/*.rb']
|
26
|
-
if platform_ruby_files.any?
|
27
|
-
$: << Path.provider_base + '/lib'
|
28
|
-
platform_ruby_files.each do |rb_file|
|
29
|
-
require rb_file
|
30
|
-
end
|
31
|
-
end
|
32
19
|
Config::Object.send(:include, LeapCli::Macro)
|
33
20
|
end
|
34
21
|
|
@@ -36,9 +23,6 @@ module LeapCli
|
|
36
23
|
## ATTRIBUTES
|
37
24
|
##
|
38
25
|
|
39
|
-
attr_reader :nodes, :common, :secrets
|
40
|
-
attr_reader :base_services, :base_tags, :base_provider, :base_common
|
41
|
-
|
42
26
|
#
|
43
27
|
# returns the Hash of the contents of facts.json
|
44
28
|
#
|
@@ -59,32 +43,36 @@ module LeapCli
|
|
59
43
|
# the returned array includes nil (for the default environment)
|
60
44
|
#
|
61
45
|
def environment_names
|
62
|
-
@environment_names ||=
|
46
|
+
@environment_names ||= begin
|
47
|
+
[nil] + (env.tags.field('environment') + env.nodes.field('environment')).compact.uniq
|
48
|
+
end
|
63
49
|
end
|
64
50
|
|
65
51
|
#
|
66
52
|
# Returns the appropriate environment variable
|
67
53
|
#
|
68
54
|
def env(env=nil)
|
69
|
-
env
|
70
|
-
e = @environments[env] ||= Environment.new
|
71
|
-
yield e if block_given?
|
72
|
-
e
|
55
|
+
@environments[env || 'default']
|
73
56
|
end
|
74
57
|
|
75
58
|
#
|
76
|
-
# The default accessors
|
59
|
+
# The default accessors
|
60
|
+
#
|
77
61
|
# For these defaults, use 'default' environment, or whatever
|
78
62
|
# environment is pinned.
|
79
63
|
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
def
|
84
|
-
|
85
|
-
end
|
86
|
-
def provider
|
87
|
-
|
64
|
+
# I think it might be an error that these are ever used
|
65
|
+
# and I would like to get rid of them.
|
66
|
+
#
|
67
|
+
def services; env(default_environment).services; end
|
68
|
+
def tags; env(default_environment).tags; end
|
69
|
+
def partials; env(default_environment).partials; end
|
70
|
+
def provider; env(default_environment).provider; end
|
71
|
+
def common; env(default_environment).common; end
|
72
|
+
def secrets; env(default_environment).secrets; end
|
73
|
+
def nodes; env(default_environment).nodes; end
|
74
|
+
def template(*args)
|
75
|
+
self.env.template(*args)
|
88
76
|
end
|
89
77
|
|
90
78
|
def default_environment
|
@@ -95,6 +83,21 @@ module LeapCli
|
|
95
83
|
## IMPORT EXPORT
|
96
84
|
##
|
97
85
|
|
86
|
+
def add_environment(args)
|
87
|
+
if args[:inherit]
|
88
|
+
parent = @environments[args.delete(:inherit)]
|
89
|
+
else
|
90
|
+
parent = nil
|
91
|
+
end
|
92
|
+
@environments[args[:name]] = Environment.new(
|
93
|
+
self,
|
94
|
+
args.delete(:name),
|
95
|
+
args.delete(:dir),
|
96
|
+
parent,
|
97
|
+
args
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
98
101
|
#
|
99
102
|
# load .json configuration files
|
100
103
|
#
|
@@ -102,66 +105,37 @@ module LeapCli
|
|
102
105
|
@provider_dir = Path.provider
|
103
106
|
|
104
107
|
# load base
|
105
|
-
|
106
|
-
@base_tags = load_all_json(Path.named_path([:tag_config, '*'], Path.provider_base), Config::Tag)
|
107
|
-
@base_common = load_json( Path.named_path(:common_config, Path.provider_base), Config::Object)
|
108
|
-
@base_provider = load_json( Path.named_path(:provider_config, Path.provider_base), Config::Provider)
|
108
|
+
add_environment(name: '_base_', dir: Path.provider_base)
|
109
109
|
|
110
110
|
# load provider
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
@common.inherit_from! @base_common
|
115
|
-
|
116
|
-
# For the default environment, load provider services, tags, and provider.json
|
117
|
-
log 3, :loading, 'default environment...'
|
118
|
-
env('default') do |e|
|
119
|
-
e.services = load_all_json(Path.named_path([:service_config, '*'], @provider_dir), Config::Tag, :no_dots => true)
|
120
|
-
e.tags = load_all_json(Path.named_path([:tag_config, '*'], @provider_dir), Config::Tag, :no_dots => true)
|
121
|
-
e.provider = load_json( Path.named_path(:provider_config, @provider_dir), Config::Provider, :assert => true)
|
122
|
-
e.services.inherit_from! @base_services
|
123
|
-
e.tags.inherit_from! @base_tags
|
124
|
-
e.provider.inherit_from! @base_provider
|
125
|
-
validate_provider(e.provider)
|
126
|
-
end
|
111
|
+
Util::assert_files_exist!(Path.named_path(:provider_config, @provider_dir))
|
112
|
+
add_environment(name: 'default', dir: @provider_dir,
|
113
|
+
inherit: '_base_', no_dots: true)
|
127
114
|
|
128
|
-
# create a special '_all_' environment, used for tracking
|
129
|
-
# of all the environments
|
130
|
-
|
131
|
-
e.services = Config::ObjectList.new
|
132
|
-
e.tags = Config::ObjectList.new
|
133
|
-
e.provider = Config::Provider.new
|
134
|
-
e.services.inherit_from! env('default').services
|
135
|
-
e.tags.inherit_from! env('default').tags
|
136
|
-
e.provider.inherit_from! env('default').provider
|
137
|
-
end
|
115
|
+
# create a special '_all_' environment, used for tracking
|
116
|
+
# the union of all the environments
|
117
|
+
add_environment(name: '_all_', inherit: 'default')
|
138
118
|
|
139
|
-
#
|
119
|
+
# load environments
|
140
120
|
environment_names.each do |ename|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
e.tags = load_all_json(Path.named_path([:tag_env_config, '*', ename], @provider_dir), Config::Tag, :env => ename)
|
146
|
-
e.provider = load_json( Path.named_path([:provider_env_config, ename], @provider_dir), Config::Provider, :env => ename)
|
147
|
-
e.services.inherit_from! env('default').services
|
148
|
-
e.tags.inherit_from! env('default').tags
|
149
|
-
e.provider.inherit_from! env('default').provider
|
150
|
-
validate_provider(e.provider)
|
121
|
+
if ename
|
122
|
+
log 3, :loading, '%s environment...' % ename
|
123
|
+
add_environment(name: ename, dir: @provider_dir,
|
124
|
+
inherit: 'default', scope: ename)
|
151
125
|
end
|
152
126
|
end
|
153
127
|
|
154
128
|
# apply inheritance
|
155
|
-
|
129
|
+
env.nodes.each do |name, node|
|
156
130
|
Util::assert! name =~ /^[0-9a-z-]+$/, "Illegal character(s) used in node name '#{name}'"
|
157
|
-
|
131
|
+
env.nodes[name] = apply_inheritance(node)
|
158
132
|
end
|
159
133
|
|
160
134
|
# do some node-list post-processing
|
161
135
|
cleanup_node_lists(options)
|
162
136
|
|
163
137
|
# apply control files
|
164
|
-
|
138
|
+
env.nodes.each do |name, node|
|
165
139
|
control_files(node).each do |file|
|
166
140
|
begin
|
167
141
|
node.eval_file file
|
@@ -189,7 +163,7 @@ module LeapCli
|
|
189
163
|
existing_files = nil
|
190
164
|
|
191
165
|
unless node_list
|
192
|
-
node_list =
|
166
|
+
node_list = env.nodes
|
193
167
|
existing_hiera = Dir.glob(Path.named_path([:hiera, '*'], @provider_dir))
|
194
168
|
existing_files = Dir.glob(Path.named_path([:node_files_dir, '*'], @provider_dir))
|
195
169
|
end
|
@@ -224,8 +198,8 @@ module LeapCli
|
|
224
198
|
end
|
225
199
|
|
226
200
|
def export_secrets(clean_unused_secrets = false)
|
227
|
-
if
|
228
|
-
Util.write_file!([:secrets_config, @provider_dir],
|
201
|
+
if env.secrets.any?
|
202
|
+
Util.write_file!([:secrets_config, @provider_dir], env.secrets.dump_json(clean_unused_secrets) + "\n")
|
229
203
|
end
|
230
204
|
end
|
231
205
|
|
@@ -270,7 +244,7 @@ module LeapCli
|
|
270
244
|
# so, take the part before the first period as the node name
|
271
245
|
name = name.split('.').first
|
272
246
|
end
|
273
|
-
|
247
|
+
env.nodes[name]
|
274
248
|
end
|
275
249
|
|
276
250
|
#
|
@@ -284,137 +258,48 @@ module LeapCli
|
|
284
258
|
# yields each node, in sorted order
|
285
259
|
#
|
286
260
|
def each_node(&block)
|
287
|
-
nodes.each_node &block
|
261
|
+
env.nodes.each_node &block
|
288
262
|
end
|
289
263
|
|
290
264
|
def reload_node!(node)
|
291
|
-
|
292
|
-
end
|
293
|
-
|
294
|
-
#
|
295
|
-
# returns all the partial data for the specified partial path.
|
296
|
-
# partial path is always relative to provider root, but there must be multiple files
|
297
|
-
# that match because provider root might be the base provider or the local provider.
|
298
|
-
#
|
299
|
-
def partials(partial_path)
|
300
|
-
@partials ||= {}
|
301
|
-
if @partials[partial_path].nil?
|
302
|
-
[Path.provider_base, Path.provider].each do |provider_dir|
|
303
|
-
path = File.join(provider_dir, partial_path)
|
304
|
-
if File.exists?(path)
|
305
|
-
@partials[partial_path] ||= []
|
306
|
-
@partials[partial_path] << load_json(path, Config::Object)
|
307
|
-
end
|
308
|
-
end
|
309
|
-
if @partials[partial_path].nil?
|
310
|
-
raise RuntimeError, 'no such partial path `%s`' % partial_path, caller
|
311
|
-
end
|
312
|
-
end
|
313
|
-
@partials[partial_path]
|
265
|
+
env.nodes[node.name] = apply_inheritance!(node)
|
314
266
|
end
|
315
267
|
|
316
|
-
|
268
|
+
##
|
269
|
+
## CONNECTIONS
|
270
|
+
##
|
317
271
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
obj['name'] ||= name
|
326
|
-
if options[:env]
|
327
|
-
obj.environment = options[:env]
|
328
|
-
end
|
329
|
-
results[name] = obj
|
330
|
-
end
|
272
|
+
class ConnectionList < Array
|
273
|
+
def add(data={})
|
274
|
+
self << {
|
275
|
+
"from" => data[:from],
|
276
|
+
"to" => data[:to],
|
277
|
+
"port" => data[:port]
|
278
|
+
}
|
331
279
|
end
|
332
|
-
results
|
333
280
|
end
|
334
281
|
|
335
|
-
def
|
336
|
-
|
337
|
-
Util::assert_files_exist!(filename)
|
338
|
-
end
|
339
|
-
if !File.exists?(filename)
|
340
|
-
return object_class.new(self)
|
341
|
-
end
|
342
|
-
|
343
|
-
log :loading, filename, 3
|
344
|
-
|
345
|
-
#
|
346
|
-
# Read a JSON file, strip out comments.
|
347
|
-
#
|
348
|
-
# UTF8 is the default encoding for JSON, but others are allowed:
|
349
|
-
# https://www.ietf.org/rfc/rfc4627.txt
|
350
|
-
#
|
351
|
-
buffer = StringIO.new
|
352
|
-
File.open(filename, "rb", :encoding => 'UTF-8') do |f|
|
353
|
-
while (line = f.gets)
|
354
|
-
next if line =~ /^\s*\/\//
|
355
|
-
buffer << line
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
#
|
360
|
-
# force UTF-8
|
361
|
-
#
|
362
|
-
if $ruby_version >= [1,9]
|
363
|
-
string = buffer.string.force_encoding('utf-8')
|
364
|
-
else
|
365
|
-
string = Iconv.conv("UTF-8//IGNORE", "UTF-8", buffer.string)
|
366
|
-
end
|
367
|
-
|
368
|
-
# parse json
|
369
|
-
begin
|
370
|
-
hash = JSON.parse(string, :object_class => Hash, :array_class => Array) || {}
|
371
|
-
rescue SyntaxError, JSON::ParserError => exc
|
372
|
-
log 0, :error, 'in file "%s":' % filename
|
373
|
-
log 0, exc.to_s, :indent => 1
|
374
|
-
return nil
|
375
|
-
end
|
376
|
-
object = object_class.new(self)
|
377
|
-
object.deep_merge!(hash)
|
378
|
-
return object
|
282
|
+
def connections
|
283
|
+
@connections ||= ConnectionList.new
|
379
284
|
end
|
380
285
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
# key = options[:prefix].nil? ? "#{key}" : "#{options[:prefix]}#{options[:delimiter]||"_"}#{key}"
|
387
|
-
# if value.is_a? Hash
|
388
|
-
# flatten_hash(value, output, :prefix => key, :delimiter => options[:delimiter])
|
389
|
-
# else
|
390
|
-
# output[key] = value
|
391
|
-
# end
|
392
|
-
# end
|
393
|
-
# output.replace(input)
|
394
|
-
# output
|
395
|
-
# end
|
286
|
+
##
|
287
|
+
## PRIVATE
|
288
|
+
##
|
289
|
+
|
290
|
+
private
|
396
291
|
|
397
292
|
#
|
398
293
|
# makes a node inherit options from appropriate the common, service, and tag json files.
|
399
294
|
#
|
400
295
|
def apply_inheritance(node, throw_exceptions=false)
|
401
|
-
new_node = Config::Node.new(
|
402
|
-
name
|
403
|
-
|
404
|
-
|
405
|
-
# (Technically, this is wrong: a tag that sets the environment might not be
|
406
|
-
# named the same as the environment. This code assumes that it is).
|
407
|
-
node_env = self.env
|
408
|
-
if node['tags']
|
409
|
-
node['tags'].to_a.each do |tag|
|
410
|
-
if self.environment_names.include?(tag)
|
411
|
-
node_env = self.env(tag)
|
412
|
-
end
|
413
|
-
end
|
414
|
-
end
|
296
|
+
new_node = Config::Node.new(nil)
|
297
|
+
name = node.name
|
298
|
+
node_env = guess_node_env(node)
|
299
|
+
new_node.set_environment(node_env, new_node)
|
415
300
|
|
416
301
|
# inherit from common
|
417
|
-
new_node.deep_merge!(
|
302
|
+
new_node.deep_merge!(node_env.common)
|
418
303
|
|
419
304
|
# inherit from services
|
420
305
|
if node['services']
|
@@ -456,6 +341,28 @@ module LeapCli
|
|
456
341
|
apply_inheritance(node, true)
|
457
342
|
end
|
458
343
|
|
344
|
+
#
|
345
|
+
# Guess the environment of the node from the tag names.
|
346
|
+
#
|
347
|
+
# Technically, this is wrong: a tag that sets the environment might not be
|
348
|
+
# named the same as the environment. This code assumes that it is.
|
349
|
+
#
|
350
|
+
# Unfortunately, it is a chicken and egg problem. We need to know the nodes
|
351
|
+
# likely environment in order to apply the inheritance that will actually
|
352
|
+
# determine the node's properties.
|
353
|
+
#
|
354
|
+
def guess_node_env(node)
|
355
|
+
environment = self.env(default_environment)
|
356
|
+
if node['tags']
|
357
|
+
node['tags'].to_a.each do |tag|
|
358
|
+
if self.environment_names.include?(tag)
|
359
|
+
environment = self.env(tag)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
return environment
|
364
|
+
end
|
365
|
+
|
459
366
|
#
|
460
367
|
# does some final clean at the end of loading nodes.
|
461
368
|
# this includes removing disabled nodes, and populating
|
@@ -463,7 +370,7 @@ module LeapCli
|
|
463
370
|
#
|
464
371
|
def cleanup_node_lists(options)
|
465
372
|
@disabled_nodes = Config::ObjectList.new
|
466
|
-
|
373
|
+
env.nodes.each do |name, node|
|
467
374
|
if node.enabled || options[:include_disabled]
|
468
375
|
if node['services']
|
469
376
|
node['services'].to_a.each do |node_service|
|
@@ -479,16 +386,12 @@ module LeapCli
|
|
479
386
|
end
|
480
387
|
elsif !options[:include_disabled]
|
481
388
|
log 2, :skipping, "disabled node #{name}."
|
482
|
-
|
389
|
+
env.nodes.delete(name)
|
483
390
|
@disabled_nodes[name] = node
|
484
391
|
end
|
485
392
|
end
|
486
393
|
end
|
487
394
|
|
488
|
-
def validate_provider(provider)
|
489
|
-
# nothing yet.
|
490
|
-
end
|
491
|
-
|
492
395
|
#
|
493
396
|
# returns a list of 'control' files for this node.
|
494
397
|
# a control file is like a service or a tag JSON file, but it contains
|