diff options
Diffstat (limited to 'lib/leap_cli')
-rw-r--r-- | lib/leap_cli/commands/pre.rb | 4 | ||||
-rw-r--r-- | lib/leap_cli/config/manager.rb | 42 | ||||
-rw-r--r-- | lib/leap_cli/config/object.rb | 105 | ||||
-rw-r--r-- | lib/leap_cli/config/object_list.rb | 15 | ||||
-rw-r--r-- | lib/leap_cli/log.rb | 1 | ||||
-rw-r--r-- | lib/leap_cli/path.rb | 17 | ||||
-rw-r--r-- | lib/leap_cli/util.rb | 3 |
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 |