summaryrefslogtreecommitdiff
path: root/lib/leap_cli
diff options
context:
space:
mode:
Diffstat (limited to 'lib/leap_cli')
-rw-r--r--lib/leap_cli/commands/pre.rb4
-rw-r--r--lib/leap_cli/config/manager.rb42
-rw-r--r--lib/leap_cli/config/object.rb105
-rw-r--r--lib/leap_cli/config/object_list.rb15
-rw-r--r--lib/leap_cli/log.rb1
-rw-r--r--lib/leap_cli/path.rb17
-rw-r--r--lib/leap_cli/util.rb3
7 files changed, 148 insertions, 39 deletions
diff --git a/lib/leap_cli/commands/pre.rb b/lib/leap_cli/commands/pre.rb
index b1df5cd..dce01eb 100644
--- a/lib/leap_cli/commands/pre.rb
+++ b/lib/leap_cli/commands/pre.rb
@@ -38,7 +38,9 @@ module LeapCli
if Path.ok?
true
else
- bail!("Could not find the root directory. Change current working directory or try --root")
+ bail! do
+ log :error, "- Could not find the root directory. Change current working directory or try --root"
+ end
end
#
diff --git a/lib/leap_cli/config/manager.rb b/lib/leap_cli/config/manager.rb
index 7406f1c..e90b589 100644
--- a/lib/leap_cli/config/manager.rb
+++ b/lib/leap_cli/config/manager.rb
@@ -17,21 +17,37 @@ module LeapCli
#
# load .json configuration files
#
- def load(provider_dir=Path.provider)
- @provider_dir = provider_dir
- @services = load_all_json(Path.named_path([:service_config, '*'], provider_dir))
- @tags = load_all_json(Path.named_path([:tag_config, '*'], provider_dir))
- @nodes = load_all_json(Path.named_path([:node_config, '*'], provider_dir))
- @common = load_json(Path.named_path(:common_config, provider_dir))
- @provider = load_json(Path.named_path(:provider_config, provider_dir))
- @secrets = load_json(Path.named_path(:secrets_config, provider_dir))
-
- Util::assert!(@provider, "Failed to load provider.json")
- Util::assert!(@common, "Failed to load common.json")
+ def load
+ @provider_dir = Path.provider
+ # load base
+ base_services = load_all_json(Path.named_path([:service_config, '*'], Path.provider_base))
+ base_tags = load_all_json(Path.named_path([:tag_config, '*'], Path.provider_base))
+ base_common = load_json(Path.named_path(:common_config, Path.provider_base))
+ base_provider = load_json(Path.named_path(:provider_config, Path.provider_base))
+
+ # load provider
+ provider_path = Path.named_path(:provider_config, @provider_dir)
+ common_path = Path.named_path(:common_config, @provider_dir)
+ Util::assert_files_exist!(provider_path, common_path)
+ @services = load_all_json(Path.named_path([:service_config, '*'], @provider_dir))
+ @tags = load_all_json(Path.named_path([:tag_config, '*'], @provider_dir))
+ @nodes = load_all_json(Path.named_path([:node_config, '*'], @provider_dir))
+ @common = load_json(common_path)
+ @provider = load_json(provider_path)
+ @secrets = load_json(Path.named_path(:secrets_config, @provider_dir))
+
+ # inherit
+ @services.inherit_from! base_services
+ @tags.inherit_from! base_tags
+ @common.inherit_from! base_common
+ @provider.inherit_from! base_provider
@nodes.each do |name, node|
@nodes[name] = apply_inheritance(node)
end
+
+ # validate
+ validate_provider(@provider)
end
#
@@ -244,7 +260,9 @@ module LeapCli
#
PRIVATE_IP_RANGES = /(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/
def validate_provider(provider)
- Util::assert! provider.vagrant.network =~ PRIVATE_IP_RANGES, 'provider.json error: vagrant.network is not a local private network'
+ Util::assert! provider.vagrant.network =~ PRIVATE_IP_RANGES do
+ log 0, :error, 'in provider.json: vagrant.network is not a local private network'
+ end
end
end
diff --git a/lib/leap_cli/config/object.rb b/lib/leap_cli/config/object.rb
index bf0452a..ef28179 100644
--- a/lib/leap_cli/config/object.rb
+++ b/lib/leap_cli/config/object.rb
@@ -114,36 +114,78 @@ module LeapCli
#
# a deep (recursive) merge with another Config::Object.
#
- def deep_merge!(object)
+ # if prefer_self is set to true, the value from self will be picked when there is a conflict
+ # that cannot be merged.
+ #
+ def deep_merge!(object, prefer_self=false)
object.each do |key,new_value|
old_value = self.fetch key, nil
+
+ # clean up boolean
+ new_value = true if new_value == "true"
+ new_value = false if new_value == "false"
+ old_value = true if old_value == "true"
+ old_value = false if old_value == "false"
+
+ # merge hashes
if old_value.is_a?(Hash) || new_value.is_a?(Hash)
- # merge hashes
value = Config::Object.new(@manager, @node)
old_value.is_a?(Hash) ? value.deep_merge!(old_value) : (value[key] = old_value if old_value.any?)
- new_value.is_a?(Hash) ? value.deep_merge!(new_value) : (value[key] = new_value if new_value.any?)
+ new_value.is_a?(Hash) ? value.deep_merge!(new_value, prefer_self) : (value[key] = new_value if new_value.any?)
+
+ # merge arrays
elsif old_value.is_a?(Array) || new_value.is_a?(Array)
- # merge arrays
value = []
old_value.is_a?(Array) ? value += old_value : value << old_value
new_value.is_a?(Array) ? value += new_value : value << new_value
- value.compact!
+ value = value.compact.uniq
+
+ # merge nil
elsif new_value.nil?
value = old_value
elsif old_value.nil?
value = new_value
+
+ # merge boolean
elsif old_value.is_a?(Boolean) && new_value.is_a?(Boolean)
- value = new_value
+ # FalseClass and TrueClass are different classes, so we must handle them separately
+ if prefer_self
+ value = old_value
+ else
+ value = new_value
+ end
+
+ # catch errors
elsif old_value.class != new_value.class
- raise 'Type mismatch. Cannot merge %s with %s. Key value is %s, name is %s.' % [old_value.class, new_value.class, key, name]
+ raise 'Type mismatch. Cannot merge %s (%s) with %s (%s). Key is "%s", name is "%s".' % [
+ old_value.inspect, old_value.class,
+ new_value.inspect, new_value.class,
+ key, self.class
+ ]
+
+ # merge strings and numbers
else
- value = new_value
+ if prefer_self
+ value = old_value
+ else
+ value = new_value
+ end
end
+
+ # save value
self[key] = value
end
self
end
+ #
+ # like a reverse deep merge
+ # (self takes precedence)
+ #
+ def inherit_from!(object)
+ self.deep_merge!(object, true)
+ end
+
##
## NODE SPECIFIC
## maybe these should be moved to a Node class.
@@ -170,12 +212,18 @@ module LeapCli
global.nodes
end
- class FileMissing < Exception; end
+ class FileMissing < Exception
+ attr_accessor :path, :options
+ def initialize(path, options={})
+ @path = path
+ @options = options
+ end
+ end
#
# inserts the contents of a file
#
- def file(filename)
+ def file(filename, options={})
if filename.is_a? Symbol
filename = [filename, @node.name]
end
@@ -187,12 +235,21 @@ module LeapCli
File.read(filepath)
end
else
- raise FileMissing.new(Path.named_path(filename))
+ raise FileMissing.new(Path.named_path(filename), options)
""
end
end
#
+ # like #file, but allow missing files
+ #
+ def try_file(filename)
+ return file(filename)
+ rescue FileMissing
+ return nil
+ end
+
+ #
# inserts a named secret, generating it if needed.
#
# manager.export_secrets should be called later to capture any newly generated secrets.
@@ -218,18 +275,26 @@ module LeapCli
value = @node.instance_eval($1) #, @node.send(:binding))
self[key] = value
rescue SystemStackError => exc
- log :error, "while evaluating node '#{@node.name}'"
- log "offending string: #{$1}", :indent => 1
- log "STACK OVERFLOW, BAILING OUT. There must be an eval loop of death (variables with circular dependencies)."
+ log 0, :error, "while evaluating node '#{@node.name}'"
+ log 0, "offending string: #{$1}", :indent => 1
+ log 0, "STACK OVERFLOW, BAILING OUT. There must be an eval loop of death (variables with circular dependencies).", :indent => 1
raise SystemExit.new()
rescue FileMissing => exc
- log :error, "while evaluating node '#{@node.name}'"
- log "offending string: #{$1}", :indent => 1
- log "error message: no file '#{exc}'", :indent => 1
+ Util::bail! do
+ if exc.options[:missing]
+ log :missing, exc.options[:missing].gsub('$node', @node.name)
+ else
+ log :error, "while evaluating node '#{@node.name}'"
+ log "offending string: #{$1}", :indent => 1
+ log "error message: no file '#{exc}'", :indent => 1
+ end
+ end
rescue StandardError => exc
- log :error, "while evaluating node '#{@node.name}'"
- log "offending string: #{$1}", :indent => 1
- log "error message: #{exc}", :indent => 1
+ Util::bail! do
+ log :error, "while evaluating node '#{@node.name}'"
+ log "offending string: #{$1}", :indent => 1
+ log "error message: #{exc}", :indent => 1
+ end
end
end
value
diff --git a/lib/leap_cli/config/object_list.rb b/lib/leap_cli/config/object_list.rb
index b0839ca..0fa60f1 100644
--- a/lib/leap_cli/config/object_list.rb
+++ b/lib/leap_cli/config/object_list.rb
@@ -30,7 +30,7 @@ module LeapCli
value = config[field]
if !value.nil?
if value.is_a? Array
- if value.includes?(match_value)
+ if value.include?(match_value)
results[name] = config
end
else
@@ -89,6 +89,19 @@ module LeapCli
result
end
+ #
+ # applies inherit_from! to all objects.
+ #
+ def inherit_from!(object_list)
+ object_list.each do |name, object|
+ if self[name]
+ self[name].inherit_from!(object)
+ else
+ self[name] = object.dup
+ end
+ end
+ end
+
end
end
end
diff --git a/lib/leap_cli/log.rb b/lib/leap_cli/log.rb
index aa9fd16..1cc1c6a 100644
--- a/lib/leap_cli/log.rb
+++ b/lib/leap_cli/log.rb
@@ -57,6 +57,7 @@ def log(*args)
when :run then Paint['run', :magenta]
when :failed then Paint['FAILED', :red, :bold]
when :ran then Paint['ran', :green, :bold]
+ when :bail then Paint['bailing out', :red, :bold]
else Paint[title.to_s, :cyan, :bold]
end
print "#{prefix} "
diff --git a/lib/leap_cli/path.rb b/lib/leap_cli/path.rb
index ed4e478..a783a91 100644
--- a/lib/leap_cli/path.rb
+++ b/lib/leap_cli/path.rb
@@ -18,6 +18,11 @@ module LeapCli; module Path
:service_config => 'services/#{arg}.json',
:tag_config => 'tags/#{arg}.json',
+ # input data files
+ :commercial_cert => 'files/cert/#{arg}.crt',
+ :commercial_key => 'files/cert/#{arg}.key',
+ :commercial_csr => 'files/cert/#{arg}.csr',
+
# output files
:user_ssh => 'users/#{arg}/#{arg}_ssh.pub',
:user_pgp => 'users/#{arg}/#{arg}_pgp.pub',
@@ -64,8 +69,12 @@ module LeapCli; module Path
@platform ||= File.expand_path("#{root}/leap_platform")
end
- def self.platform_provider
- "#{platform}/provider"
+ def self.provider_base
+ "#{platform}/provider_base"
+ end
+
+ def self.provider_templates
+ "#{platform}/provider_templates"
end
def self.provider
@@ -92,7 +101,7 @@ module LeapCli; module Path
def self.search_path
@search_path ||= begin
search_path = []
- [Path.platform_provider, Path.provider].each do |provider|
+ [Path.provider_base, Path.provider].each do |provider|
files_dir = named_path(:files_dir, provider)
search_path << provider
search_path << named_path(:files_dir, provider)
@@ -110,7 +119,7 @@ module LeapCli; module Path
def self.find_file(filename)
# named path?
if filename.is_a? Array
- path = named_path(filename, platform_provider)
+ path = named_path(filename, Path.provider_base)
return path if File.exists?(path)
path = named_path(filename, provider)
return path if File.exists?(path)
diff --git a/lib/leap_cli/util.rb b/lib/leap_cli/util.rb
index 20036b2..bad1f6c 100644
--- a/lib/leap_cli/util.rb
+++ b/lib/leap_cli/util.rb
@@ -23,11 +23,12 @@ module LeapCli
#
def bail!(message=nil)
if block_given?
+ LeapCli.log_level = 3
yield
elsif message
puts message
end
- puts("Bailing out.")
+ log :bail, ""
raise SystemExit.new
end