diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/leap/platform.rb | 90 | ||||
| -rw-r--r-- | lib/leap_cli.rb | 20 | ||||
| -rw-r--r-- | lib/leap_cli/bootstrap.rb | 17 | ||||
| -rw-r--r-- | lib/leap_cli/config/environment.rb | 180 | ||||
| -rw-r--r-- | lib/leap_cli/config/filter.rb | 178 | ||||
| -rw-r--r-- | lib/leap_cli/config/manager.rb | 422 | ||||
| -rw-r--r-- | lib/leap_cli/config/node.rb | 78 | ||||
| -rw-r--r-- | lib/leap_cli/config/object.rb | 428 | ||||
| -rw-r--r-- | lib/leap_cli/config/object_list.rb | 209 | ||||
| -rw-r--r-- | lib/leap_cli/config/provider.rb | 22 | ||||
| -rw-r--r-- | lib/leap_cli/config/secrets.rb | 87 | ||||
| -rw-r--r-- | lib/leap_cli/config/sources.rb | 11 | ||||
| -rw-r--r-- | lib/leap_cli/config/tag.rb | 25 | ||||
| -rw-r--r-- | lib/leap_cli/leapfile.rb | 64 | ||||
| -rw-r--r-- | lib/leap_cli/log.rb | 209 | ||||
| -rw-r--r-- | lib/leap_cli/util.rb | 8 | ||||
| -rw-r--r-- | lib/leap_cli/util/remote_command.rb | 158 | ||||
| -rw-r--r-- | lib/leap_cli/util/secret.rb | 55 | ||||
| -rw-r--r-- | lib/leap_cli/util/x509.rb | 33 | 
19 files changed, 86 insertions, 2208 deletions
| diff --git a/lib/leap/platform.rb b/lib/leap/platform.rb deleted file mode 100644 index 9112ef3..0000000 --- a/lib/leap/platform.rb +++ /dev/null @@ -1,90 +0,0 @@ -module Leap - -  class Platform -    class << self -      # -      # configuration -      # - -      attr_reader :version -      attr_reader :compatible_cli -      attr_accessor :facts -      attr_accessor :paths -      attr_accessor :node_files -      attr_accessor :monitor_username -      attr_accessor :reserved_usernames - -      attr_accessor :hiera_dir -      attr_accessor :hiera_path -      attr_accessor :files_dir -      attr_accessor :leap_dir -      attr_accessor :init_path - -      attr_accessor :default_puppet_tags - -      def define(&block) -        # some defaults: -        @reserved_usernames = [] -        @hiera_dir  = '/etc/leap' -        @hiera_path = '/etc/leap/hiera.yaml' -        @leap_dir   = '/srv/leap' -        @files_dir  = '/srv/leap/files' -        @init_path  = '/srv/leap/initialized' -        @default_puppet_tags = [] - -        self.instance_eval(&block) - -        @version ||= Gem::Version.new("0.0") -      end - -      def version=(version) -        @version = Gem::Version.new(version) -      end - -      def compatible_cli=(range) -        @compatible_cli = range -        @minimum_cli_version = Gem::Version.new(range.first) -        @maximum_cli_version = Gem::Version.new(range.last) -      end - -      # -      # return true if the cli_version is compatible with this platform. -      # -      def compatible_with_cli?(cli_version) -        cli_version = Gem::Version.new(cli_version) -        cli_version >= @minimum_cli_version && cli_version <= @maximum_cli_version -      end - -      # -      # return true if the platform version is within the specified range. -      # -      def version_in_range?(range) -        if range.is_a? String -          range = range.split('..') -        end -        minimum_platform_version = Gem::Version.new(range.first) -        maximum_platform_version = Gem::Version.new(range.last) -        @version >= minimum_platform_version && @version <= maximum_platform_version -      end - -      def major_version -        if @version.segments.first == 0 -          @version.segments[0..1].join('.') -        else -          @version.segments.first -        end -      end - -      def method_missing(method, *args) -        puts -        puts "WARNING:" -        puts "  leap_cli is out of date and does not understand `#{method}`." -        puts "  called from: #{caller.first}" -        puts "  please upgrade to a newer leap_cli" -      end - -    end - -  end - -end
\ No newline at end of file diff --git a/lib/leap_cli.rb b/lib/leap_cli.rb index 36718e3..c0e139e 100644 --- a/lib/leap_cli.rb +++ b/lib/leap_cli.rb @@ -1,6 +1,6 @@  module LeapCli -  module Commands; end  # for commands in leap_cli/commands -  module Macro; end     # for macros in leap_platform/provider_base/lib/macros +  module Commands; end  # for commands in leap_platform/lib/leap_cli/commands +  module Macro; end     # for macros in leap_platform/lib/leap_cli/macros  end  $ruby_version = RUBY_VERSION.split('.').collect{ |i| i.to_i }.extend(Comparable) @@ -13,8 +13,6 @@ $:.unshift(File.expand_path('../leap_cli/override',__FILE__))  require 'rubygems'  gem 'gli', '~> 2.12', '>= 2.12.0' -require 'leap/platform' -  require 'leap_cli/version'  require 'leap_cli/exceptions' @@ -31,27 +29,13 @@ require 'leap_cli/core_ext/yaml'  require 'leap_cli/log'  require 'leap_cli/path'  require 'leap_cli/util' -require 'leap_cli/util/secret' -require 'leap_cli/util/x509'  require 'leap_cli/bootstrap' -require 'leap_cli/config/object' -require 'leap_cli/config/node' -require 'leap_cli/config/tag' -require 'leap_cli/config/provider' -require 'leap_cli/config/secrets' -require 'leap_cli/config/object_list' -require 'leap_cli/config/filter' -require 'leap_cli/config/environment' -require 'leap_cli/config/manager' -  require 'leap_cli/markdown_document_listener'  #  # allow everyone easy access to log() command.  #  module LeapCli -  Util.send(:extend, LeapCli::LogCommand) -  Config::Manager.send(:include, LeapCli::LogCommand)    extend LeapCli::LogCommand  end diff --git a/lib/leap_cli/bootstrap.rb b/lib/leap_cli/bootstrap.rb index bc43115..f33aa42 100644 --- a/lib/leap_cli/bootstrap.rb +++ b/lib/leap_cli/bootstrap.rb @@ -40,6 +40,7 @@ module LeapCli          log_version        end        add_platform_lib_to_path +      load_platform_libraries        load_commands(app)        load_macros      end @@ -104,11 +105,10 @@ module LeapCli        elsif !leapfile_optional?(argv)          puts          puts " =" -        log :note, "There is no `Leapfile` in this directory, or any parent directory.\n"+ -                   " =       "+ +        log :NOTE, "There is no `Leapfile` in this directory, or any parent directory.\n"+ +                   " =      "+                     "Without this file, most commands will not be available."          puts " =" -        puts        end      end @@ -204,5 +204,16 @@ module LeapCli          $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)        end      end + +    # +    # loads libraries that live in the platform and should +    # always be available. +    # +    def load_platform_libraries +      if Path.platform +        require 'leap_cli/load_libraries' +      end +    end +    end  end diff --git a/lib/leap_cli/config/environment.rb b/lib/leap_cli/config/environment.rb deleted file mode 100644 index 398fd02..0000000 --- a/lib/leap_cli/config/environment.rb +++ /dev/null @@ -1,180 +0,0 @@ -# -# All configurations files can be isolated into separate environments. -# -# Each config json in each environment inherits from the default environment, -# which in term inherits from the "_base_" environment: -# -# _base_             -- base provider in leap_platform -# '- default         -- environment in provider dir when no env is set -#    '- production   -- example environment -# - -module LeapCli; module Config - -  class Environment -    # the String name of the environment -    attr_accessor :name - -    # the shared Manager object -    attr_accessor :manager - -    # hashes of {name => Config::Object} -    attr_accessor :services, :tags, :partials - -    # a Config::Provider -    attr_accessor :provider - -    # a Config::Object -    attr_accessor :common - -    # shared, non-inheritable -    def nodes; @@nodes; end -    def secrets; @@secrets; end - -    def initialize(manager, name, search_dir, parent, options={}) -      @@nodes ||= nil -      @@secrets ||= nil - -      @manager = manager -      @name    = name - -      load_provider_files(search_dir, options) - -      if parent -        @services.inherit_from! parent.services, self -            @tags.inherit_from! parent.tags    , self -        @partials.inherit_from! parent.partials, self -          @common.inherit_from! parent.common -        @provider.inherit_from! parent.provider -      end - -      if @provider -        @provider.set_env(name) -        @provider.validate! -      end -    end - -    def load_provider_files(search_dir, options) -      # -      # load empty environment if search_dir doesn't exist -      # -      if search_dir.nil? || !Dir.exist?(search_dir) -        @services = Config::ObjectList.new -        @tags     = Config::ObjectList.new -        @partials = Config::ObjectList.new -        @provider = Config::Provider.new -        @common   = Config::Object.new -        return -      end - -      # -      # inheritable -      # -      if options[:scope] -        scope = options[:scope] -        @services = load_all_json(Path.named_path([:service_env_config, '*', scope],  search_dir), Config::Tag, options) -        @tags     = load_all_json(Path.named_path([:tag_env_config, '*', scope],      search_dir), Config::Tag, options) -        @partials = load_all_json(Path.named_path([:service_env_config, '_*', scope], search_dir), Config::Tag, options) -        @provider = load_json(    Path.named_path([:provider_env_config, scope],      search_dir), Config::Provider, options) -        @common   = load_json(    Path.named_path([:common_env_config, scope],        search_dir), Config::Object, options) -      else -        @services = load_all_json(Path.named_path([:service_config, '*'],  search_dir), Config::Tag, options) -        @tags     = load_all_json(Path.named_path([:tag_config, '*'],      search_dir), Config::Tag, options) -        @partials = load_all_json(Path.named_path([:service_config, '_*'], search_dir), Config::Tag, options) -        @provider = load_json(    Path.named_path(:provider_config,        search_dir), Config::Provider, options) -        @common   = load_json(    Path.named_path(:common_config,          search_dir), Config::Object, options) -      end - -      # remove 'name' from partials, since partials get merged with nodes -      @partials.values.each {|partial| partial.delete('name'); } - -      # -      # shared: currently non-inheritable -      # load the first ones we find, and only those. -      # -      if @@nodes.nil? || @@nodes.empty? -        @@nodes = load_all_json(Path.named_path([:node_config, '*'], search_dir), Config::Node, options) -      end -      if @@secrets.nil? || @@secrets.empty? -        @@secrets = load_json(Path.named_path(:secrets_config, search_dir), Config::Secrets, options) -      end -    end - -    # -    # Loads a json template file as a Hash (used only when creating a new node .json -    # file for the first time). -    # -    def template(template) -      path = Path.named_path([:template_config, template], Path.provider_base) -      if File.exist?(path) -        return load_json(path, Config::Object) -      else -        return nil -      end -    end - -    private - -    def load_all_json(pattern, object_class, options={}) -      results = Config::ObjectList.new -      Dir.glob(pattern).each do |filename| -        next if options[:no_dots] && File.basename(filename) !~ /^[^\.]*\.json$/ -        obj = load_json(filename, object_class) -        if obj -          name = File.basename(filename).force_encoding('utf-8').sub(/^([^\.]+).*\.json$/,'\1') -          obj['name'] ||= name -          if options[:env] -            obj.environment = options[:env] -          end -          results[name] = obj -        end -      end -      results -    end - -    def load_json(filename, object_class, options={}) -      if !File.exist?(filename) -        return object_class.new(self) -      end - -      Util::log :loading, filename, 3 - -      # -      # Read a JSON file, strip out comments. -      # -      # UTF8 is the default encoding for JSON, but others are allowed: -      # https://www.ietf.org/rfc/rfc4627.txt -      # -      buffer = StringIO.new -      File.open(filename, "rb", :encoding => 'UTF-8') do |f| -        while (line = f.gets) -          next if line =~ /^\s*\/\// -          buffer << line -        end -      end - -      # -      # force UTF-8 -      # -      if $ruby_version >= [1,9] -        string = buffer.string.force_encoding('utf-8') -      else -        string = Iconv.conv("UTF-8//IGNORE", "UTF-8", buffer.string) -      end - -      # parse json -      begin -        hash = JSON.parse(string, :object_class => Hash, :array_class => Array) || {} -      rescue SyntaxError, JSON::ParserError => exc -        Util::log 0, :error, 'in file "%s":' % filename -        Util::log 0, exc.to_s, :indent => 1 -        return nil -      end -      object = object_class.new(self) -      object.deep_merge!(hash) -      return object -    end - -  end # end Environment - -end; end
\ No newline at end of file diff --git a/lib/leap_cli/config/filter.rb b/lib/leap_cli/config/filter.rb deleted file mode 100644 index 2c80be8..0000000 --- a/lib/leap_cli/config/filter.rb +++ /dev/null @@ -1,178 +0,0 @@ -# -# Many leap_cli commands accept a list of filters to select a subset of nodes for the command to -# be applied to. This class is a helper for manager to run these filters. -# -# Classes other than Manager should not use this class. -# -# Filter rules: -# -# * A filter consists of a list of tokens -# * A token may be a service name, tag name, environment name, or node name. -# * Each token may be optionally prefixed with a plus sign. -# * Multiple tokens with a plus are treated as an OR condition, -#   but treated as an AND condition with the plus sign. -# -# For example -# -# * openvpn +development => all nodes with service 'openvpn' AND environment 'development' -# * openvpn seattle => all nodes with service 'openvpn' OR tag 'seattle'. -# -# There can only be one environment specified. Typically, there are also tags -# for each environment name. These name are treated as environments, not tags. -# -module LeapCli -  module Config -    class Filter - -      # -      # filter -- array of strings, each one a filter -      # options -- hash, possible keys include -      #   :nopin -- disregard environment pinning -      #   :local -- if false, disallow local nodes -      # -      # A nil value in the filters array indicates -      # the default environment. This is in order to support -      # calls like `manager.filter(environments)` -      # -      def initialize(filters, options, manager) -        @filters = filters.nil? ? [] : filters.dup -        @environments = [] -        @options = options -        @manager = manager - -        # split filters by pulling out items that happen -        # to be environment names. -        if LeapCli.leapfile.environment.nil? || @options[:nopin] -          @environments = [] -        else -          @environments = [LeapCli.leapfile.environment] -        end -        @filters.select! do |filter| -          if filter.nil? -            @environments << nil unless @environments.include?(nil) -            false -          else -            filter_text = filter.sub(/^\+/,'') -            if is_environment?(filter_text) -              if filter_text == LeapCli.leapfile.environment -                # silently ignore already pinned environments -              elsif (filter =~ /^\+/ || @filters.first == filter) && !@environments.empty? -                LeapCli::Util.bail! do -                  LeapCli::Util.log "Environments are exclusive: no node is in two environments." do -                    LeapCli::Util.log "Tried to filter on '#{@environments.join('\' AND \'')}' AND '#{filter_text}'" -                  end -                end -              else -                @environments << filter_text -              end -              false -            else -              true -            end -          end -        end - -        # don't let the first filter have a + prefix -        if @filters[0] =~ /^\+/ -          @filters[0] = @filters[0][1..-1] -        end -      end - -      # actually run the filter, returns a filtered list of nodes -      def nodes() -        if @filters.empty? -          return nodes_for_empty_filter -        else -          return nodes_for_filter -        end -      end - -      private - -      def nodes_for_empty_filter -        node_list = @manager.nodes -        if @environments.any? -          node_list = node_list[ @environments.collect{|e|[:environment, env_to_filter(e)]} ] -        end -        if @options[:local] === false -          node_list = node_list[:environment => '!local'] -        end -        if @options[:disabled] === false -          node_list = node_list[:environment => '!disabled'] -        end -        node_list -      end - -      def nodes_for_filter -        node_list = Config::ObjectList.new -        @filters.each do |filter| -          if filter =~ /^\+/ -            keep_list = nodes_for_name(filter[1..-1]) -            node_list.delete_if do |name, node| -              if keep_list[name] -                false -              else -                true -              end -            end -          else -            node_list.merge!(nodes_for_name(filter)) -          end -        end -        node_list -      end - -      private - -      # -      # returns a set of nodes corresponding to a single name, -      # where name could be a node name, service name, or tag name. -      # -      # For services and tags, we only include nodes for the -      # environments that are active -      # -      def nodes_for_name(name) -        if node = @manager.nodes[name] -          return Config::ObjectList.new(node) -        elsif @environments.empty? -          if @manager.services[name] -            return @manager.env('_all_').services[name].node_list -          elsif @manager.tags[name] -            return @manager.env('_all_').tags[name].node_list -          else -            LeapCli::Util.log :warning, "filter '#{name}' does not match any node names, tags, services, or environments." -            return Config::ObjectList.new -          end -        else -          node_list = Config::ObjectList.new -          if @manager.services[name] -            @environments.each do |env| -              node_list.merge!(@manager.env(env).services[name].node_list) -            end -          elsif @manager.tags[name] -            @environments.each do |env| -              node_list.merge!(@manager.env(env).tags[name].node_list) -            end -          else -            LeapCli::Util.log :warning, "filter '#{name}' does not match any node names, tags, services, or environments." -          end -          return node_list -        end -      end - -      # -      # when pinning, we use the name 'default' to specify nodes -      # without an environment set, but when filtering, we need to filter -      # on :environment => nil. -      # -      def env_to_filter(environment) -        environment == 'default' ? nil : environment -      end - -      def is_environment?(text) -        text == 'default' || @manager.environment_names.include?(text) -      end - -    end -  end -end diff --git a/lib/leap_cli/config/manager.rb b/lib/leap_cli/config/manager.rb deleted file mode 100644 index 80ccbad..0000000 --- a/lib/leap_cli/config/manager.rb +++ /dev/null @@ -1,422 +0,0 @@ -# encoding: utf-8 - -require 'json/pure' - -if $ruby_version < [1,9] -  require 'iconv' -end - -module LeapCli -  module Config - -    # -    # A class to manage all the objects in all the configuration files. -    # -    class Manager - -      def initialize -        @environments = {} # hash of `Environment` objects, keyed by name. -        Config::Object.send(:include, LeapCli::Macro) -      end - -      ## -      ## ATTRIBUTES -      ## - -      # -      # returns the Hash of the contents of facts.json -      # -      def facts -        @facts ||= begin -          content = Util.read_file(:facts) -          if !content || content.empty? -            content = "{}" -          end -          JSON.parse(content) -        rescue SyntaxError, JSON::ParserError => exc -          Util::bail! "Could not parse facts.json -- #{exc}" -        end -      end - -      # -      # returns an Array of all the environments defined for this provider. -      # the returned array includes nil (for the default environment) -      # -      def environment_names -        @environment_names ||= begin -          [nil] + (env.tags.field('environment') + env.nodes.field('environment')).compact.uniq -        end -      end - -      # -      # Returns the appropriate environment variable -      # -      def env(env=nil) -        @environments[env || 'default'] -      end - -      # -      # The default accessors -      # -      # For these defaults, use 'default' environment, or whatever -      # environment is pinned. -      # -      # I think it might be an error that these are ever used -      # and I would like to get rid of them. -      # -      def services; env(default_environment).services; end -      def tags;     env(default_environment).tags;     end -      def partials; env(default_environment).partials; end -      def provider; env(default_environment).provider; end -      def common;   env(default_environment).common;   end -      def secrets;  env(default_environment).secrets;  end -      def nodes;    env(default_environment).nodes;    end -      def template(*args) -        self.env.template(*args) -      end - -      def default_environment -        LeapCli.leapfile.environment -      end - -      ## -      ## IMPORT EXPORT -      ## - -      def add_environment(args) -        if args[:inherit] -          parent = @environments[args.delete(:inherit)] -        else -          parent = nil -        end -        @environments[args[:name]] = Environment.new( -          self, -          args.delete(:name), -          args.delete(:dir), -          parent, -          args -        ) -      end - -      # -      # load .json configuration files -      # -      def load(options = {}) -        @provider_dir = Path.provider - -        # load base -        add_environment(name: '_base_', dir: Path.provider_base) - -        # load provider -        Util::assert_files_exist!(Path.named_path(:provider_config, @provider_dir)) -        add_environment(name: 'default', dir: @provider_dir, -          inherit: '_base_', no_dots: true) - -        # create a special '_all_' environment, used for tracking -        # the union of all the environments -        add_environment(name: '_all_', inherit: 'default') - -        # load environments -        environment_names.each do |ename| -          if ename -            log 3, :loading, '%s environment...' % ename -            add_environment(name: ename, dir: @provider_dir, -              inherit: 'default', scope: ename) -          end -        end - -        # apply inheritance -        env.nodes.each do |name, node| -          Util::assert! name =~ /^[0-9a-z-]+$/, "Illegal character(s) used in node name '#{name}'" -          env.nodes[name] = apply_inheritance(node) -        end - -        # do some node-list post-processing -        cleanup_node_lists(options) - -        # apply control files -        env.nodes.each do |name, node| -          control_files(node).each do |file| -            begin -              node.eval_file file -            rescue ConfigError => exc -              if options[:continue_on_error] -                exc.log -              else -                raise exc -              end -            end -          end -        end -      end - -      # -      # save compiled hiera .yaml files -      # -      # if a node_list is specified, only update those .yaml files. -      # otherwise, update all files, destroying files that are no longer used. -      # -      def export_nodes(node_list=nil) -        updated_hiera = [] -        updated_files = [] -        existing_hiera = nil -        existing_files = nil - -        unless node_list -          node_list = env.nodes -          existing_hiera = Dir.glob(Path.named_path([:hiera, '*'], @provider_dir)) -          existing_files = Dir.glob(Path.named_path([:node_files_dir, '*'], @provider_dir)) -        end - -        node_list.each_node do |node| -          filepath = Path.named_path([:node_files_dir, node.name], @provider_dir) -          hierapath = Path.named_path([:hiera, node.name], @provider_dir) -          Util::write_file!(hierapath, node.dump_yaml) -          updated_files << filepath -          updated_hiera << hierapath -        end - -        if @disabled_nodes -          # make disabled nodes appear as if they are still active -          @disabled_nodes.each_node do |node| -            updated_files << Path.named_path([:node_files_dir, node.name], @provider_dir) -            updated_hiera << Path.named_path([:hiera, node.name], @provider_dir) -          end -        end - -        # remove files that are no longer needed -        if existing_hiera -          (existing_hiera - updated_hiera).each do |filepath| -            Util::remove_file!(filepath) -          end -        end -        if existing_files -          (existing_files - updated_files).each do |filepath| -            Util::remove_directory!(filepath) -          end -        end -      end - -      def export_secrets(clean_unused_secrets = false) -        if env.secrets.any? -          Util.write_file!([:secrets_config, @provider_dir], env.secrets.dump_json(clean_unused_secrets) + "\n") -        end -      end - -      ## -      ## FILTERING -      ## - -      # -      # returns a node list consisting only of nodes that satisfy the filter criteria. -      # -      # filter: condition [condition] [condition] [+condition] -      # condition: [node_name | service_name | tag_name | environment_name] -      # -      # if conditions is prefixed with +, then it works like an AND. Otherwise, it works like an OR. -      # -      # args: -      # filter -- array of filter terms, one per item -      # -      # options: -      # :local -- if :local is false and the filter is empty, then local nodes are excluded. -      # :nopin -- if true, ignore environment pinning -      # -      def filter(filters=nil, options={}) -        Filter.new(filters, options, self).nodes() -      end - -      # -      # same as filter(), but exits if there is no matching nodes -      # -      def filter!(filters, options={}) -        node_list = filter(filters, options) -        Util::assert! node_list.any?, "Could not match any nodes from '#{filters.join ' '}'" -        return node_list -      end - -      # -      # returns a single Config::Object that corresponds to a Node. -      # -      def node(name) -        if name =~ /\./ -          # probably got a fqdn, since periods are not allowed in node names. -          # so, take the part before the first period as the node name -          name = name.split('.').first -        end -        env.nodes[name] -      end - -      # -      # returns a single node that is disabled -      # -      def disabled_node(name) -        @disabled_nodes[name] -      end - -      # -      # yields each node, in sorted order -      # -      def each_node(&block) -        env.nodes.each_node(&block) -      end - -      def reload_node!(node) -        env.nodes[node.name] = apply_inheritance!(node) -      end - -      ## -      ## CONNECTIONS -      ## - -      class ConnectionList < Array -        def add(data={}) -          self << { -            "from" => data[:from], -            "to" => data[:to], -            "port" => data[:port] -          } -        end -      end - -      def connections -        @connections ||= ConnectionList.new -      end - -      ## -      ## PRIVATE -      ## - -      private - -      # -      # makes a node inherit options from appropriate the common, service, and tag json files. -      # -      def apply_inheritance(node, throw_exceptions=false) -        new_node = Config::Node.new(nil) -        node_env = guess_node_env(node) -        new_node.set_environment(node_env, new_node) - -        # inherit from common -        new_node.deep_merge!(node_env.common) - -        # inherit from services -        if node['services'] -          node['services'].to_a.each do |node_service| -            service = node_env.services[node_service] -            if service.nil? -              msg = 'in node "%s": the service "%s" does not exist.' % [node['name'], node_service] -              log 0, :error, msg -              raise LeapCli::ConfigError.new(node, "error " + msg) if throw_exceptions -            else -              new_node.deep_merge!(service) -            end -          end -        end - -        # inherit from tags -        if node.vagrant? -          node['tags'] = (node['tags'] || []).to_a + ['local'] -        end -        if node['tags'] -          node['tags'].to_a.each do |node_tag| -            tag = node_env.tags[node_tag] -            if tag.nil? -              msg = 'in node "%s": the tag "%s" does not exist.' % [node['name'], node_tag] -              log 0, :error, msg -              raise LeapCli::ConfigError.new(node, "error " + msg) if throw_exceptions -            else -              new_node.deep_merge!(tag) -            end -          end -        end - -        # inherit from node -        new_node.deep_merge!(node) -        return new_node -      end - -      def apply_inheritance!(node) -        apply_inheritance(node, true) -      end - -      # -      # Guess the environment of the node from the tag names. -      # -      # Technically, this is wrong: a tag that sets the environment might not be -      # named the same as the environment. This code assumes that it is. -      # -      # Unfortunately, it is a chicken and egg problem. We need to know the nodes -      # likely environment in order to apply the inheritance that will actually -      # determine the node's properties. -      # -      def guess_node_env(node) -        if node.vagrant? -          return self.env("local") -        else -          environment = self.env(default_environment) -          if node['tags'] -            node['tags'].to_a.each do |tag| -              if self.environment_names.include?(tag) -                environment = self.env(tag) -              end -            end -          end -          return environment -        end -      end - -      # -      # does some final clean at the end of loading nodes. -      # this includes removing disabled nodes, and populating -      # the services[x].node_list and tags[x].node_list -      # -      def cleanup_node_lists(options) -        @disabled_nodes = Config::ObjectList.new -        env.nodes.each do |name, node| -          if node.enabled || options[:include_disabled] -            if node['services'] -              node['services'].to_a.each do |node_service| -                env(node.environment).services[node_service].node_list.add(node.name, node) -                env('_all_').services[node_service].node_list.add(node.name, node) -              end -            end -            if node['tags'] -              node['tags'].to_a.each do |node_tag| -                env(node.environment).tags[node_tag].node_list.add(node.name, node) -                env('_all_').tags[node_tag].node_list.add(node.name, node) -              end -            end -          elsif !options[:include_disabled] -            log 2, :skipping, "disabled node #{name}." -            env.nodes.delete(name) -            @disabled_nodes[name] = node -          end -        end -      end - -      # -      # returns a list of 'control' files for this node. -      # a control file is like a service or a tag JSON file, but it contains -      # raw ruby code that gets evaluated in the context of the node. -      # Yes, this entirely breaks our functional programming model -      # for JSON generation. -      # -      def control_files(node) -        files = [] -        [Path.provider_base, @provider_dir].each do |provider_dir| -          [['services', :service_config], ['tags', :tag_config]].each do |attribute, path_sym| -            node[attribute].each do |attr_value| -              path = Path.named_path([path_sym, "#{attr_value}.rb"], provider_dir).sub(/\.json$/,'') -              if File.exist?(path) -                files << path -              end -            end -          end -        end -        return files -      end - -    end -  end -end diff --git a/lib/leap_cli/config/node.rb b/lib/leap_cli/config/node.rb deleted file mode 100644 index f8ec052..0000000 --- a/lib/leap_cli/config/node.rb +++ /dev/null @@ -1,78 +0,0 @@ -# -# Configuration for a 'node' (a server in the provider's infrastructure) -# - -require 'ipaddr' - -module LeapCli; module Config - -  class Node < Object -    attr_accessor :file_paths - -    def initialize(environment=nil) -      super(environment) -      @node = self -      @file_paths = [] -    end - -    # -    # returns true if this node has an ip address in the range of the vagrant network -    # -    def vagrant? -      begin -        vagrant_range = IPAddr.new LeapCli.leapfile.vagrant_network -      rescue ArgumentError => exc -        Util::bail! { Util::log :invalid, "ip address '#{@node.ip_address}' vagrant.network" } -      end - -      begin -        ip_address = IPAddr.new @node.get('ip_address') -      rescue ArgumentError => exc -        Util::log :warning, "invalid ip address '#{@node.get('ip_address')}' for node '#{@node.name}'" -      end -      return vagrant_range.include?(ip_address) -    end - -    # -    # Return a hash table representation of ourselves, with the key equal to the @node.name, -    # and the value equal to the fields specified in *keys. -    # -    # Also, the result is flattened to a single hash, so a key of 'a.b' becomes 'a_b' -    # -    # compare to Object#pick(*keys). This method is the sames as Config::ObjectList#pick_fields, -    # but works on a single node. -    # -    # Example: -    # -    #  node.pick('domain.internal') => -    # -    #    { -    #      'node1': { -    #        'domain_internal': 'node1.example.i' -    #      } -    #    } -    # -    def pick_fields(*keys) -      {@node.name => self.pick(*keys)} -    end - -    # -    # can be overridden by the platform. -    # returns a list of node names that should be tested before this node -    # -    def test_dependencies -      [] -    end - -    # returns a string list of supported ssh host key algorithms for this node. -    # or an empty string if it could not be determined -    def supported_ssh_host_key_algorithms -      require 'leap_cli/ssh' -      @host_key_algo ||= LeapCli::SSH::Key.supported_host_key_algorithms( -        Util.read_file([:node_ssh_pub_key, @node.name]) -      ) -    end - -  end - -end; end diff --git a/lib/leap_cli/config/object.rb b/lib/leap_cli/config/object.rb deleted file mode 100644 index b117c2f..0000000 --- a/lib/leap_cli/config/object.rb +++ /dev/null @@ -1,428 +0,0 @@ -# encoding: utf-8 - -require 'erb' -require 'json/pure'  # pure ruby implementation is required for our sorted trick to work. - -if $ruby_version < [1,9] -  $KCODE = 'UTF8' -end -require 'ya2yaml' # pure ruby yaml - -module LeapCli -  module Config - -    # -    # This class represents the configuration for a single node, service, or tag. -    # Also, all the nested hashes are also of this type. -    # -    # It is called 'object' because it corresponds to an Object in JSON. -    # -    class Object < Hash - -      attr_reader :env -      attr_reader :node - -      def initialize(environment=nil, node=nil) -        raise ArgumentError unless environment.nil? || environment.is_a?(Config::Environment) -        @env = environment -        # an object that is a node as @node equal to self, otherwise all the -        # child objects point back to the top level node. -        @node = node || self -      end - -      def manager -        @env.manager -      end - -      # -      # TODO: deprecate node.global() -      # -      def global -        @env -      end - -      def environment=(e) -        self.store('environment', e) -      end - -      def environment -        self['environment'] -      end - -      def duplicate(env) -        new_object = self.deep_dup -        new_object.set_environment(env, new_object) -      end - -      # -      # export YAML -      # -      # We use pure ruby yaml exporter ya2yaml instead of SYCK or PSYCH because it -      # allows us greater compatibility regardless of installed ruby version and -      # greater control over how the yaml is exported (sorted keys, in particular). -      # -      def dump_yaml -        evaluate(@node) -        sorted_ya2yaml(:syck_compatible => true) -      end - -      # -      # export JSON -      # -      def dump_json(options={}) -        evaluate(@node) -        if options[:format] == :compact -          return self.to_json -        else -          excluded = {} -          if options[:exclude] -            options[:exclude].each do |key| -              excluded[key] = self[key] -              self.delete(key) -            end -          end -          json_str = JSON.sorted_generate(self) -          if excluded.any? -            self.merge!(excluded) -          end -          return json_str -        end -      end - -      def evaluate(context=@node) -        evaluate_everything(context) -        late_evaluate_everything(context) -      end - -      ## -      ## FETCHING VALUES -      ## - -      def [](key) -        get(key) -      end - -      # Overrride some default methods in Hash that are likely to -      # be used as attributes. -      alias_method :hkey, :key -      def key; get('key'); end - -      # -      # make hash addressable like an object (e.g. obj['name'] available as obj.name) -      # -      def method_missing(method, *args, &block) -        get!(method) -      end - -      def get(key) -        begin -          get!(key) -        rescue NoMethodError -          nil -        end -      end - -      # override behavior of #default() from Hash -      def default -        get!('default') -      end - -      # -      # Like a normal Hash#[], except: -      # -      # (1) lazily eval dynamic values when we encounter them. (i.e. strings that start with "= ") -      # -      # (2) support for nested references in a single string (e.g. ['a.b'] is the same as ['a']['b']) -      #     the dot path is always absolute, starting at the top-most object. -      # -      def get!(key) -        key = key.to_s -        if self.has_key?(key) -          fetch_value(key) -        elsif key =~ /\./ -          # for keys with with '.' in them, we start from the root object (@node). -          keys = key.split('.') -          value = self.get!(keys.first) -          if value.is_a? Config::Object -            value.get!(keys[1..-1].join('.')) -          else -            value -          end -        else -          raise NoMethodError.new(key, "No method '#{key}' for #{self.class}") -        end -      end - -      ## -      ## COPYING -      ## - -      # -      # A deep (recursive) merge with another Config::Object. -      # -      # If prefer_self is set to true, the value from self will be picked when there is a conflict -      # that cannot be merged. -      # -      # Merging rules: -      # -      # - If a value is a hash, we recursively merge it. -      # - If the value is simple, like a string, the new one overwrites the value. -      # - If the value is an array: -      #   - If both old and new values are arrays, the new one replaces the old. -      #   - If one of the values is simple but the other is an array, the simple is added to the array. -      # -      def deep_merge!(object, prefer_self=false) -        object.each do |key,new_value| -          if self.has_key?('+'+key) -            mode = :add -            old_value = self.fetch '+'+key, nil -            self.delete('+'+key) -          elsif self.has_key?('-'+key) -            mode = :subtract -            old_value = self.fetch '-'+key, nil -            self.delete('-'+key) -          elsif self.has_key?('!'+key) -            mode = :replace -            old_value = self.fetch '!'+key, nil -            self.delete('!'+key) -          else -            mode = :normal -            old_value = self.fetch key, nil -          end - -          # 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" - -          # force replace? -          if mode == :replace && prefer_self -            value = old_value - -          # merge hashes -          elsif old_value.is_a?(Hash) || new_value.is_a?(Hash) -            value = Config::Object.new(@env, @node) -            old_value.is_a?(Hash) ? value.deep_merge!(old_value) : (value[key] = old_value if !old_value.nil?) -            new_value.is_a?(Hash) ? value.deep_merge!(new_value, prefer_self) : (value[key] = new_value if !new_value.nil?) - -          # merge nil -          elsif new_value.nil? -            value = old_value -          elsif old_value.nil? -            value = new_value - -          # merge arrays when one value is not an array -          elsif old_value.is_a?(Array) && !new_value.is_a?(Array) -            (value = (old_value.dup << new_value).compact.uniq).delete('REQUIRED') -          elsif new_value.is_a?(Array) && !old_value.is_a?(Array) -            (value = (new_value.dup << old_value).compact.uniq).delete('REQUIRED') - -          # merge two arrays -          elsif old_value.is_a?(Array) && new_value.is_a?(Array) -            if mode == :add -              value = (old_value + new_value).sort.uniq -            elsif mode == :subtract -              value = new_value - old_value -            elsif prefer_self -              value = old_value -            else -              value = new_value -            end - -          # catch errors -          elsif type_mismatch?(old_value, new_value) -            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 simple strings & numbers -          else -            if prefer_self -              value = old_value -            else -              value = new_value -            end -          end - -          # save value -          self[key] = value -        end -        self -      end - -      def set_environment(env, node) -        @env = env -        @node = node -        self.each do |key, value| -          if value.is_a?(Config::Object) -            value.set_environment(env, node) -          end -        end -      end - -      # -      # like a reverse deep merge -      # (self takes precedence) -      # -      def inherit_from!(object) -        self.deep_merge!(object, true) -      end - -      # -      # Make a copy of ourselves, except only including the specified keys. -      # -      # Also, the result is flattened to a single hash, so a key of 'a.b' becomes 'a_b' -      # -      def pick(*keys) -        keys.map(&:to_s).inject(self.class.new(@manager)) do |hsh, key| -          value = self.get(key) -          if !value.nil? -            hsh[key.gsub('.','_')] = value -          end -          hsh -        end -      end - -      def eval_file(filename) -        evaluate_ruby(filename, File.read(filename)) -      end - -      protected - -      # -      # walks the object tree, eval'ing all the attributes that are dynamic ruby (e.g. value starts with '= ') -      # -      def evaluate_everything(context) -        keys.each do |key| -          obj = fetch_value(key, context) -          if is_required_value_not_set?(obj) -            Util::log 0, :warning, "required property \"#{key}\" is not set in node \"#{node.name}\"." -          elsif obj.is_a? Config::Object -            obj.evaluate_everything(context) -          end -        end -      end - -      # -      # some keys need to be evaluated 'late', after all the other keys have been evaluated. -      # -      def late_evaluate_everything(context) -        if @late_eval_list -          @late_eval_list.each do |key, value| -            self[key] = context.evaluate_ruby(key, value) -            if is_required_value_not_set?(self[key]) -              Util::log 0, :warning, "required property \"#{key}\" is not set in node \"#{node.name}\"." -            end -          end -        end -        values.each do |obj| -          if obj.is_a? Config::Object -            obj.late_evaluate_everything(context) -          end -        end -      end - -      # -      # evaluates the string `value` as ruby in the context of self. -      # (`key` is just passed for debugging purposes) -      # -      def evaluate_ruby(key, value) -        self.instance_eval(value, key, 1) -      rescue ConfigError => exc -        raise exc # pass through -      rescue SystemStackError => exc -        Util::log 0, :error, "while evaluating node '#{self.name}'" -        Util::log 0, "offending key: #{key}", :indent => 1 -        Util::log 0, "offending string: #{value}", :indent => 1 -        Util::log 0, "STACK OVERFLOW, BAILING OUT. There must be an eval loop of death (variables with circular dependencies).", :indent => 1 -        raise SystemExit.new(1) -      rescue FileMissing => exc -        Util::bail! do -          if exc.options[:missing] -            Util::log :missing, exc.options[:missing].gsub('$node', self.name).gsub('$file', exc.path) -          else -            Util::log :error, "while evaluating node '#{self.name}'" -            Util::log "offending key: #{key}", :indent => 1 -            Util::log "offending string: #{value}", :indent => 1 -            Util::log "error message: no file '#{exc}'", :indent => 1 -          end -          raise exc if DEBUG -        end -      rescue AssertionFailed => exc -        Util.bail! do -          Util::log :failed, "assertion while evaluating node '#{self.name}'" -          Util::log 'assertion: %s' % exc.assertion, :indent => 1 -          Util::log "offending key: #{key}", :indent => 1 -          raise exc if DEBUG -        end -      rescue SyntaxError, StandardError => exc -        Util::bail! do -          Util::log :error, "while evaluating node '#{self.name}'" -          Util::log "offending key: #{key}", :indent => 1 -          Util::log "offending string: #{value}", :indent => 1 -          Util::log "error message: #{exc.inspect}", :indent => 1 -          raise exc if DEBUG -        end -      end - -      private - -      # -      # fetches the value for the key, evaluating the value as ruby if it begins with '=' -      # -      def fetch_value(key, context=@node) -        value = fetch(key, nil) -        if value.is_a?(String) && value =~ /^=/ -          if value =~ /^=> (.*)$/ -            value = evaluate_later(key, $1) -          elsif value =~ /^= (.*)$/ -            value = context.evaluate_ruby(key, $1) -          end -          self[key] = value -        end -        return value -      end - -      def evaluate_later(key, value) -        @late_eval_list ||= [] -        @late_eval_list << [key, value] -        '<evaluate later>' -      end - -      # -      # when merging, we raise an error if this method returns true for the two values. -      # -      def type_mismatch?(old_value, new_value) -        if old_value.is_a?(Boolean) && new_value.is_a?(Boolean) -          # note: FalseClass and TrueClass are different classes -          # so we can't do old_value.class == new_value.class -          return false -        elsif old_value.is_a?(String) && old_value =~ /^=/ -          # pass through macros, since we don't know what the type will eventually be. -          return false -        elsif new_value.is_a?(String) && new_value =~ /^=/ -          return false -        elsif old_value.class == new_value.class -          return false -        else -          return true -        end -      end - -      # -      # returns true if the value has not been changed and the default is "REQUIRED" -      # -      def is_required_value_not_set?(value) -        if value.is_a? Array -          value == ["REQUIRED"] -        else -          value == "REQUIRED" -        end -      end - -    end # class -  end # module -end # module
\ No newline at end of file diff --git a/lib/leap_cli/config/object_list.rb b/lib/leap_cli/config/object_list.rb deleted file mode 100644 index f9299a6..0000000 --- a/lib/leap_cli/config/object_list.rb +++ /dev/null @@ -1,209 +0,0 @@ -require 'tsort' - -module LeapCli -  module Config -    # -    # A list of Config::Object instances (internally stored as a hash) -    # -    class ObjectList < Hash -      include TSort - -      def initialize(config=nil) -        if config -          self.add(config['name'], config) -        end -      end - -      # -      # If the key is a string, the Config::Object it references is returned. -      # -      # If the key is a hash, we treat it as a condition and filter all the Config::Objects using the condition. -      # A new ObjectList is returned. -      # -      # Examples: -      # -      # nodes['vpn1'] -      #   node named 'vpn1' -      # -      # nodes[:public_dns => true] -      #   all nodes with public dns -      # -      # nodes[:services => 'openvpn', 'location.country_code' => 'US'] -      #   all nodes with services containing 'openvpn' OR country code of US -      # -      # Sometimes, you want to do an OR condition with multiple conditions -      # for the same field. Since hash keys must be unique, you can use -      # an array representation instead: -      # -      # nodes[[:services, 'openvpn'], [:services, 'tor']] -      #   nodes with openvpn OR tor service -      # -      # nodes[:services => 'openvpn'][:tags => 'production'] -      #   nodes with openvpn AND are production -      # -      def [](key) -        if key.is_a?(Hash) || key.is_a?(Array) -          filter(key) -        else -          super key.to_s -        end -      end - -      def exclude(node) -        list = self.dup -        list.delete(node.name) -        return list -      end - -      def each_node(&block) -        self.keys.sort.each do |node_name| -          yield self[node_name] -        end -      end - -      # -      # filters this object list, producing a new list. -      # filter is an array or a hash. see [] -      # -      def filter(filter) -        results = Config::ObjectList.new -        filter.each do |field, match_value| -          field = field.is_a?(Symbol) ? field.to_s : field -          match_value = match_value.is_a?(Symbol) ? match_value.to_s : match_value -          if match_value.is_a?(String) && match_value =~ /^!/ -            operator = :not_equal -            match_value = match_value.sub(/^!/, '') -          else -            operator = :equal -          end -          each do |name, config| -            value = config[field] -            if value.is_a? Array -              if operator == :equal && value.include?(match_value) -                results[name] = config -              elsif operator == :not_equal && !value.include?(match_value) -                results[name] = config -              end -            else -              if operator == :equal && value == match_value -                results[name] = config -              elsif operator == :not_equal && value != match_value -                results[name] = config -              end -            end -          end -        end -        results -      end - -      def add(name, object) -        self[name] = object -      end - -      # -      # converts the hash of configs into an array of hashes, with ONLY the specified fields -      # -      def fields(*fields) -        result = [] -        keys.sort.each do |name| -          result << self[name].pick(*fields) -        end -        result -      end - -      # -      # like fields(), but returns an array of values instead of an array of hashes. -      # -      def field(field) -        field = field.to_s -        result = [] -        keys.sort.each do |name| -          result << self[name].get(field) -        end -        result -      end - -      # -      # pick_fields(field1, field2, ...) -      # -      # generates a Hash from the object list, but with only the fields that are picked. -      # -      # If there are more than one field, then the result is a Hash of Hashes. -      # If there is just one field, it is a simple map to the value. -      # -      # For example: -      # -      #   "neighbors" = "= nodes_like_me[:services => :couchdb].pick_fields('domain.full', 'ip_address')" -      # -      # generates this: -      # -      #   neighbors: -      #     couch1: -      #       domain_full: couch1.bitmask.net -      #       ip_address: "10.5.5.44" -      #     couch2: -      #       domain_full: couch2.bitmask.net -      #       ip_address: "10.5.5.52" -      # -      # But this: -      # -      #   "neighbors": "= nodes_like_me[:services => :couchdb].pick_fields('domain.full')" -      # -      # will generate this: -      # -      #   neighbors: -      #     couch1: couch1.bitmask.net -      #     couch2: couch2.bitmask.net -      # -      def pick_fields(*fields) -        self.values.inject({}) do |hsh, node| -          value = self[node.name].pick(*fields) -          if fields.size == 1 -            value = value.values.first -          end -          hsh[node.name] = value -          hsh -        end -      end - -      # -      # Applies inherit_from! to all objects. -      # -      # 'env' specifies what environment should be for -      # each object in the list. -      # -      def inherit_from!(object_list, env) -        object_list.each do |name, object| -          if self[name] -            self[name].inherit_from!(object) -          else -            self[name] = object.duplicate(env) -          end -        end -      end - -      # -      # topographical sort based on test dependency -      # -      def tsort_each_node(&block) -        self.each_key(&block) -      end - -      def tsort_each_child(node_name, &block) -        if self[node_name] -          self[node_name].test_dependencies.each do |test_me_first| -            if self[test_me_first] # TODO: in the future, allow for ability to optionally pull in all dependencies. -                                   # not just the ones that pass the node filter. -              yield(test_me_first) -            end -          end -        end -      end - -      def names_in_test_dependency_order -        self.tsort -      end - -    end -  end -end diff --git a/lib/leap_cli/config/provider.rb b/lib/leap_cli/config/provider.rb deleted file mode 100644 index 0d8bc1f..0000000 --- a/lib/leap_cli/config/provider.rb +++ /dev/null @@ -1,22 +0,0 @@ -# -# Configuration class for provider.json -# - -module LeapCli; module Config -  class Provider < Object -    attr_reader :environment -    def set_env(e) -      if e == 'default' -        @environment = nil -      else -        @environment = e -      end -    end -    def provider -      self -    end -    def validate! -      # nothing here yet :( -    end -  end -end; end diff --git a/lib/leap_cli/config/secrets.rb b/lib/leap_cli/config/secrets.rb deleted file mode 100644 index ca851c7..0000000 --- a/lib/leap_cli/config/secrets.rb +++ /dev/null @@ -1,87 +0,0 @@ -# encoding: utf-8 -# -# A class for the secrets.json file -# - -module LeapCli; module Config - -  class Secrets < Object -    attr_reader :node_list - -    def initialize(manager=nil) -      super(manager) -      @discovered_keys = {} -    end - -    # we can't use fetch() or get(), since those already have special meanings -    def retrieve(key, environment) -      environment ||= 'default' -      self.fetch(environment, {})[key.to_s] -    end - -    def set(*args, &block) -      if block_given? -        set_with_block(*args, &block) -      else -        set_without_block(*args) -      end -    end - -    # searches over all keys matching the regexp, checking to see if the value -    # has been already used by any of them. -    def taken?(regexp, value, environment) -      self.keys.grep(regexp).each do |key| -        return true if self.retrieve(key, environment) == value -      end -      return false -    end - -    def set_without_block(key, value, environment) -      set_with_block(key, environment) {value} -    end - -    def set_with_block(key, environment, &block) -      environment ||= 'default' -      key = key.to_s -      @discovered_keys[environment] ||= {} -      @discovered_keys[environment][key] = true -      self[environment] ||= {} -      self[environment][key] ||= yield -    end - -    # -    # if clean is true, then only secrets that have been discovered -    # during this run will be exported. -    # -    # if environment is also pinned, then we will clean those secrets -    # just for that environment. -    # -    # the clean argument should only be used when all nodes have -    # been processed, otherwise secrets that are actually in use will -    # get mistakenly removed. -    # -    def dump_json(clean=false) -      pinned_env = LeapCli.leapfile.environment -      if clean -        self.each_key do |environment| -          if pinned_env.nil? || pinned_env == environment -            env = self[environment] -            if env.nil? -              raise StandardError.new("secrets.json file seems corrupted. No such environment '#{environment}'") -            end -            env.each_key do |key| -              unless @discovered_keys[environment] && @discovered_keys[environment][key] -                self[environment].delete(key) -              end -            end -            if self[environment].empty? -              self.delete(environment) -            end -          end -        end -      end -      super() -    end -  end - -end; end diff --git a/lib/leap_cli/config/sources.rb b/lib/leap_cli/config/sources.rb deleted file mode 100644 index aee860d..0000000 --- a/lib/leap_cli/config/sources.rb +++ /dev/null @@ -1,11 +0,0 @@ -# encoding: utf-8 -# -# A class for the sources.json file -# - -module LeapCli -  module Config -    class Sources < Object -    end -  end -end diff --git a/lib/leap_cli/config/tag.rb b/lib/leap_cli/config/tag.rb deleted file mode 100644 index 6bd8d1e..0000000 --- a/lib/leap_cli/config/tag.rb +++ /dev/null @@ -1,25 +0,0 @@ -# -# -# A class for node services or node tags. -# -# - -module LeapCli; module Config - -  class Tag < Object -    attr_reader :node_list - -    def initialize(environment=nil) -      super(environment) -      @node_list = Config::ObjectList.new -    end - -    # don't copy the node list pointer when this object is dup'ed. -    def initialize_copy(orig) -      super -      @node_list = Config::ObjectList.new -    end - -  end - -end; end diff --git a/lib/leap_cli/leapfile.rb b/lib/leap_cli/leapfile.rb index ac40237..10af224 100644 --- a/lib/leap_cli/leapfile.rb +++ b/lib/leap_cli/leapfile.rb @@ -3,6 +3,8 @@  #  # It is akin to a Gemfile, Rakefile, or Capfile (e.g. it is a ruby file that gets eval'ed)  # +# Additional configuration options are defined in platform's leapfile_extensions.rb +#  module LeapCli    def self.leapfile @@ -10,17 +12,11 @@ module LeapCli    end    class Leapfile -    attr_accessor :platform_directory_path -    attr_accessor :provider_directory_path -    attr_accessor :custom_vagrant_vm_line -    attr_accessor :leap_version -    attr_accessor :log -    attr_accessor :vagrant_network -    attr_accessor :vagrant_basebox -    attr_accessor :environment +    attr_reader :platform_directory_path +    attr_reader :provider_directory_path +    attr_reader :environment      def initialize -      @vagrant_network = '10.5.5.0/24'      end      # @@ -61,19 +57,33 @@ module LeapCli          #          # load the platform          # -        platform_file = "#{@platform_directory_path}/platform.rb" -        unless File.exist?(platform_file) +        platform_class = "#{@platform_directory_path}/lib/leap/platform" +        platform_definition = "#{@platform_directory_path}/platform.rb" +        unless File.exist?(platform_definition)            Util.bail! "ERROR: The file `#{platform_file}` does not exist. Please check the value of `@platform_directory_path` in `Leapfile` or `~/.leaprc`."          end -        require "#{@platform_directory_path}/platform.rb" -        if !Leap::Platform.compatible_with_cli?(LeapCli::VERSION) || -           !Leap::Platform.version_in_range?(LeapCli::COMPATIBLE_PLATFORM_VERSION) -          Util.bail! "This leap command (v#{LeapCli::VERSION}) " + -                     "is not compatible with the platform #{@platform_directory_path} (v#{Leap::Platform.version}).\n   " + -                     "You need either leap command #{Leap::Platform.compatible_cli.first} to #{Leap::Platform.compatible_cli.last} or " + -                     "platform version #{LeapCli::COMPATIBLE_PLATFORM_VERSION.first} to #{LeapCli::COMPATIBLE_PLATFORM_VERSION.last}" +        require platform_class +        require platform_definition +        begin +          Leap::Platform.validate!(LeapCli::VERSION, LeapCli::COMPATIBLE_PLATFORM_VERSION, self) +        rescue StandardError => exc +          Util.bail! exc.to_s +        end +        leapfile_extensions = "#{@platform_directory_path}/lib/leap_cli/leapfile_extensions.rb" +        if File.exist?(leapfile_extensions) +          require leapfile_extensions +        end + +        # +        # validate +        # +        instance_variables.each do |var| +          var = var.to_s.sub('@', '') +          if !self.respond_to?(var) +            LeapCli.log :warning, "the variable `#{var}` is set in .leaprc or Leapfile, but it is not supported." +          end          end -        @valid = true +        @valid = validate          return @valid        end      end @@ -123,9 +133,8 @@ module LeapCli      def read_settings(file)        if File.exist? file -        Util::log 2, :read, file +        LeapCli.log 2, :read, file          instance_eval(File.read(file), file) -        validate(file)        end      end @@ -140,11 +149,16 @@ module LeapCli        return search_dir      end -    PRIVATE_IP_RANGES = /(^127\.0\.0\.1)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.)/ +    # to be overridden +    def validate +      return true +    end -    def validate(file) -      Util::assert! vagrant_network =~ PRIVATE_IP_RANGES do -        Util::log 0, :error, "in #{file}: vagrant_network is not a local private network" +    def method_missing(method, *args) +      if method =~ /=$/ +        self.instance_variable_set('@' + method.to_s.sub('=',''), args.first) +      else +        self.instance_variable_get('@' + method.to_s)        end      end diff --git a/lib/leap_cli/log.rb b/lib/leap_cli/log.rb index 03789c3..5203c97 100644 --- a/lib/leap_cli/log.rb +++ b/lib/leap_cli/log.rb @@ -86,6 +86,9 @@ module LeapCli        message = args.grep(String).first        options = args.grep(Hash).first || {}        host    = options[:host] +      if title +        title = title.to_s +      end        unless message && @log_level >= level          return        end @@ -99,21 +102,22 @@ module LeapCli        #        # apply filters +      # LogFilter will not be defined if no platform was loaded.        # -      if title -        title, filter_flags = LogFilter.apply_title_filters(title.to_s) -      else -        message, filter_flags = LogFilter.apply_message_filters(message) -        return if message.nil? +      if defined?(LeapCli::LogFilter) +        if title +          title, filter_flags = LogFilter.apply_title_filters(title) +        else +          message, filter_flags = LogFilter.apply_message_filters(message) +          return if message.nil? +        end +        options = options.merge(filter_flags)        end -      options = options.merge(filter_flags)        #        # set line prefix        # -      prefix = "" -      prefix += "[" + options[:host] + "] " if options[:host] -      prefix += title + " " if title +      prefix = prefix_str(host, title)        #        # write to the log file, always @@ -129,17 +133,17 @@ module LeapCli          end          if options[:color]            if host -            host = "[" + colorize(host, options[:color], options[:style]) + "] " +            host = colorize(host, options[:color], options[:style])            elsif title -            title = colorize(title, options[:color], options[:style]) + " " +            title = colorize(title, options[:color], options[:style])            else              message = colorize(message, options[:color], options[:style])            end          elsif title -          title = colorize(title, :cyan, :bold) + " " +          title = colorize(title, :cyan, :bold)          end          # new colorized prefix: -        prefix = [host, title].compact.join(' ') +        prefix = prefix_str(host, title)        end        log_raw(:stdout, options[:indent], prefix) { message } @@ -212,6 +216,14 @@ module LeapCli      private +    def prefix_str(host, title) +      prefix = "" +      prefix += "[" + host + "] " if host +      prefix += title + " " if title +      prefix += " " if !prefix.empty? && prefix !~ / $/ +      return prefix +    end +      EFFECTS = {        :reset         => 0,  :nothing         => 0,        :bright        => 1,  :bold            => 1, @@ -245,174 +257,3 @@ module LeapCli    end  end -# -# A module to hide, modify, and colorize log entries. -# - -module LeapCli -  module LogFilter -    # -    # options for formatters: -    # -    # :match       => regexp for matching a log line -    # :color       => what color the line should be -    # :style       => what style the line should be -    # :priority    => what order the formatters are applied in. higher numbers first. -    # :match_level => only apply filter at the specified log level -    # :level       => make this line visible at this log level or higher -    # :replace     => replace the matched text -    # :prepend     => insert text at start of message -    # :append      => append text to end of message -    # :exit        => force the exit code to be this (does not interrupt program, just -    #                 ensures a specific exit code when the program eventually exits) -    # -    FORMATTERS = [ -      # TRACE -      { :match => /command finished/,          :color => :white,   :style => :dim, :match_level => 3, :priority => -10 }, -      { :match => /executing locally/,         :color => :yellow,  :match_level => 3, :priority => -20 }, - -      # DEBUG -      #{ :match => /executing .*/,             :color => :green,   :match_level => 2, :priority => -10, :timestamp => true }, -      #{ :match => /.*/,                       :color => :yellow,  :match_level => 2, :priority => -30 }, -      { :match => /^transaction:/,             :level => 3 }, - -      # INFO -      { :match => /.*out\] (fatal:|ERROR:).*/, :color => :red,     :match_level => 1, :priority => -10 }, -      { :match => /Permission denied/,         :color => :red,     :match_level => 1, :priority => -20 }, -      { :match => /sh: .+: command not found/, :color => :magenta, :match_level => 1, :priority => -30 }, - -      # IMPORTANT -      { :match => /^(E|e)rr ::/,               :color => :red,     :match_level => 0, :priority => -10, :exit => 1}, -      { :match => /^ERROR:/,                   :color => :red,                        :priority => -10, :exit => 1}, -      #{ :match => /.*/,                        :color => :blue,    :match_level => 0, :priority => -20 }, - -      # CLEANUP -      #{ :match => /\s+$/,                      :replace => '', :priority => 0}, - -      # DEBIAN PACKAGES -      { :match => /^(Hit|Ign) /,                :color => :green,   :priority => -20}, -      { :match => /^Err /,                      :color => :red,     :priority => -20}, -      { :match => /^W(ARNING)?: /,              :color => :yellow,  :priority => -20}, -      { :match => /^E: /,                       :color => :red,     :priority => -20}, -      { :match => /already the newest version/, :color => :green,   :priority => -20}, -      { :match => /WARNING: The following packages cannot be authenticated!/, :color => :red, :level => 0, :priority => -10}, - -      # PUPPET -      { :match => /^(W|w)arning: Not collecting exported resources without storeconfigs/, :level => 2, :color => :yellow, :priority => -10}, -      { :match => /^(W|w)arning: Found multiple default providers for vcsrepo:/,          :level => 2, :color => :yellow, :priority => -10}, -      { :match => /^(W|w)arning: .*is deprecated.*$/, :level => 2, :color => :yellow, :priority => -10}, -      { :match => /^(W|w)arning: Scope.*$/,           :level => 2, :color => :yellow, :priority => -10}, -      #{ :match => /^(N|n)otice:/,                     :level => 1, :color => :cyan,   :priority => -20}, -      #{ :match => /^(N|n)otice:.*executed successfully$/, :level => 2, :color => :cyan, :priority => -15}, -      { :match => /^(W|w)arning:/,                    :level => 0, :color => :yellow, :priority => -20}, -      { :match => /^Duplicate declaration:/,          :level => 0, :color => :red,    :priority => -20}, -      #{ :match => /Finished catalog run/,             :level => 0, :color => :green,  :priority => -10}, -      { :match => /^APPLY COMPLETE \(changes made\)/, :level => 0, :color => :green, :style => :bold, :priority => -10}, -      { :match => /^APPLY COMPLETE \(no changes\)/,   :level => 0, :color => :green, :style => :bold, :priority => -10}, - -      # PUPPET FATAL ERRORS -      { :match => /^(E|e)rr(or|):/,                :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Wrapped exception:/,           :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Failed to parse template/,     :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Execution of.*returned/,       :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Parameter matches failed:/,    :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Syntax error/,                 :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Cannot reassign variable/,     :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^Could not find template/,      :level => 0, :color => :red, :priority => -1, :exit => 1}, -      { :match => /^APPLY COMPLETE.*fail/,         :level => 0, :color => :red, :style => :bold, :priority => -1, :exit => 1}, - -      # TESTS -      { :match => /^PASS: /,                :color => :green,   :priority => -20}, -      { :match => /^(FAIL|ERROR): /,        :color => :red,     :priority => -20}, -      { :match => /^(SKIP|WARN): /,         :color => :yellow,  :priority => -20}, -      { :match => /\d+ tests: \d+ passes, \d+ skips, 0 warnings, 0 failures, 0 errors/, -        :color => :green, :style => :bold, :priority => -20 }, -      { :match => /\d+ tests: \d+ passes, \d+ skips, [1-9][0-9]* warnings, 0 failures, 0 errors/, -        :color => :yellow, :style => :bold,  :priority => -20 }, -      { :match => /\d+ tests: \d+ passes, \d+ skips, \d+ warnings, \d+ failures, [1-9][0-9]* errors/, -        :color => :red, :style => :bold, :priority => -20 }, -      { :match => /\d+ tests: \d+ passes, \d+ skips, \d+ warnings, [1-9][0-9]* failures, \d+ errors/, -        :color => :red, :style => :bold, :priority => -20 }, - -      # LOG SUPPRESSION -      { :match => /^(W|w)arning: You cannot collect without storeconfigs being set/, :level => 2, :priority => 10}, -      { :match => /^(W|w)arning: You cannot collect exported resources without storeconfigs being set/, :level => 2, :priority => 10} -    ] - -    SORTED_FORMATTERS = FORMATTERS.sort_by { |i| -(i[:priority] || i[:prio] || 0) } - -    # -    # same as normal formatters, but only applies to the title, not the message. -    # -    TITLE_FORMATTERS = [ -      # red -      { :match => /error/, :color => :red, :style => :bold }, -      { :match => /fatal_error/, :replace => 'fatal error:', :color => :red, :style => :bold }, -      { :match => /removed/, :color => :red, :style => :bold }, -      { :match => /failed/, :replace => 'FAILED', :color => :red, :style => :bold }, -      { :match => /bail/, :replace => 'bailing out', :color => :red, :style => :bold }, -      { :match => /invalid/, :color => :red, :style => :bold }, - -      # yellow -      { :match => /warning/, :replace => 'warning:', :color => :yellow, :style => :bold }, -      { :match => /missing/, :color => :yellow, :style => :bold }, -      { :match => /skipping/, :color => :yellow, :style => :bold }, - -      # green -      { :match => /created/, :color => :green, :style => :bold }, -      { :match => /completed/, :color => :green, :style => :bold }, -      { :match => /ran/, :color => :green, :style => :bold }, - -      # cyan -      { :match => /note/, :replace => 'NOTE:', :color => :cyan, :style => :bold }, - -      # magenta -      { :match => /nochange/, :replace => 'no change', :color => :magenta }, -      { :match => /loading/, :color => :magenta }, -    ] - -    def self.apply_message_filters(message) -      return self.apply_filters(SORTED_FORMATTERS, message) -    end - -    def self.apply_title_filters(title) -      return self.apply_filters(TITLE_FORMATTERS, title) -    end - -    private - -    def self.apply_filters(formatters, message) -      level = LeapCli.logger.log_level -      result = {} -      formatters.each do |formatter| -        if (formatter[:match_level] == level || formatter[:match_level].nil?) -          if message =~ formatter[:match] -            # puts "applying formatter #{formatter.inspect}" -            result[:level] = formatter[:level] if formatter[:level] -            result[:color] = formatter[:color] if formatter[:color] -            result[:style] = formatter[:style] || formatter[:attribute] # (support original cap colors) - -            message.gsub!(formatter[:match], formatter[:replace]) if formatter[:replace] -            message.replace(formatter[:prepend] + message) unless formatter[:prepend].nil? -            message.replace(message + formatter[:append])  unless formatter[:append].nil? -            message.replace(Time.now.strftime('%Y-%m-%d %T') + ' ' + message) if formatter[:timestamp] - -            if formatter[:exit] -              LeapCli::Util.exit_status(formatter[:exit]) -            end - -            # stop formatting, unless formatter was just for string replacement -            break unless formatter[:replace] -          end -        end -      end - -      if result[:color] == :hide -        return [nil, {}] -      else -        return [message, result] -      end -    end - -  end -end diff --git a/lib/leap_cli/util.rb b/lib/leap_cli/util.rb index 248a59c..64b5c63 100644 --- a/lib/leap_cli/util.rb +++ b/lib/leap_cli/util.rb @@ -10,6 +10,10 @@ module LeapCli      @@exit_status = nil +    def log(*args, &block) +      LeapCli.log(*args, &block) +    end +      ##      ## QUITTING      ## @@ -44,7 +48,7 @@ module LeapCli          log 0, *message        end        log 0, :bail, "" -      raise SystemExit.new(@exit_status || 1) +      raise SystemExit.new(exit_status || 1)      end      # @@ -52,7 +56,7 @@ module LeapCli      #      def quit!(message='')        puts(message) -      raise SystemExit.new(@exit_status || 0) +      raise SystemExit.new(exit_status || 0)      end      # diff --git a/lib/leap_cli/util/remote_command.rb b/lib/leap_cli/util/remote_command.rb deleted file mode 100644 index c2f1ace..0000000 --- a/lib/leap_cli/util/remote_command.rb +++ /dev/null @@ -1,158 +0,0 @@ -module LeapCli; module Util; module RemoteCommand -  extend self - -  # -  # FYI -  #  Capistrano::Logger::IMPORTANT = 0 -  #  Capistrano::Logger::INFO      = 1 -  #  Capistrano::Logger::DEBUG     = 2 -  #  Capistrano::Logger::TRACE     = 3 -  # -  def ssh_connect(nodes, options={}, &block) -    options ||= {} -    node_list = parse_node_list(nodes) - -    cap = new_capistrano -    cap.logger = LeapCli::Logger.new(:level => [LeapCli.logger.log_level,3].min) -    user = options[:user] || 'root' -    cap.set :user, user -    cap.set :ssh_options, ssh_options # ssh options common to all nodes -    cap.set :use_sudo, false          # we may want to change this in the future - -    # Allow password authentication when we are bootstraping a single node -    # (and key authentication fails). -    if options[:bootstrap] && node_list.size == 1 -      hostname = node_list.values.first.name -      if options[:echo] -        cap.set(:password) { ask "Root SSH password for #{user}@#{hostname}> " } -      else -        cap.set(:password) { Capistrano::CLI.password_prompt " * Typed password will be hidden (use --echo to make it visible)\nRoot SSH password for #{user}@#{hostname}> " } -      end -    end - -    node_list.each do |name, node| -      cap.server node.domain.full, :dummy_arg, node_options(node, options[:ssh_options]) -    end - -    yield cap -  rescue Capistrano::ConnectionError => exc -    # not sure if this will work if english is not the locale?? -    if exc.message =~ /Too many authentication failures/ -      at_exit {ssh_config_help_message} -    end -    raise exc -  end - -  private - -  # -  # For available options, see http://net-ssh.github.com/net-ssh/classes/Net/SSH.html#method-c-start -  # -  # Capistrano has some very evil behavior in it's ssh.rb: -  # -  #   ssh_options = Net::SSH.configuration_for( -  #     server.host, ssh_options.fetch(:config, true) -  #   ).merge(ssh_options) -  #   # Once we've loaded the config, we don't need Net::SSH to do it again. -  #   ssh_options[:config] = false -  # -  # Net:SSH is supposed to call Net::SSH.configuration_for, but Capistrano is doing it -  # in advance and then disabling loading of configs. -  # -  # The result of this is the following: if you have IdentityFile in your ~/.ssh/config -  # file, then the above code will transform the ssh_options by reading ~/.ssh/config -  # and adding the keys specified via IdentityFile to ssh_options... -  # AND IT WILL SET :keys_only TO TRUE. -  # -  # The problem is that :keys_only will disable Net:SSH's ability to use ssh-agent. -  # With :keys_only set to true, it will not consult the ssh-agent at all. -  # -  # So nice of capistrano to parse ~/.ssh/config for us, but then add flags to the -  # ssh_options that prevent's these options from being useful. -  # -  # The current hackaround is to force :keys_only to be false. This allows the config -  # to be read and also allows ssh-agent to still be used. -  # -  def ssh_options -    { -      :keys_only => false, # Don't you dare change this. -      :global_known_hosts_file => path(:known_hosts), -      :user_known_hosts_file => '/dev/null', -      :paranoid => true, -      :verbose => net_ssh_log_level -    } -  end - -  def net_ssh_log_level -    if DEBUG -      case LeapCli.logger.log_level -        when 1 then 3 -        when 2 then 2 -        when 3 then 1 -        else 0 -      end -    else -      nil -    end -  end - -  # -  # For notes on advanced ways to set server-specific options, see -  # http://railsware.com/blog/2011/11/02/advanced-server-definitions-in-capistrano/ -  # -  # if, in the future, we want to do per-node password options, it would be done like so: -  # -  #  password_proc = Proc.new {Capistrano::CLI.password_prompt "Root SSH password for #{node.name}"} -  #  return {:password => password_proc} -  # -  def node_options(node, ssh_options_override=nil) -    { -      :ssh_options => { -        # :host_key_alias => node.name, << incompatible with ports in known_hosts -        :host_name => node.ip_address, -        :port => node.ssh.port -      }.merge(contingent_ssh_options_for_node(node)).merge(ssh_options_override||{}) -    } -  end - -  def new_capistrano -    # load once the library files -    @capistrano_enabled ||= begin -      require 'capistrano' -      require 'capistrano/cli' -      require 'leap_cli/lib_ext/capistrano_connections' -      require 'leap_cli/remote/leap_plugin' -      require 'leap_cli/remote/puppet_plugin' -      require 'leap_cli/remote/rsync_plugin' -      Capistrano.plugin :leap, LeapCli::Remote::LeapPlugin -      Capistrano.plugin :puppet, LeapCli::Remote::PuppetPlugin -      Capistrano.plugin :rsync, LeapCli::Remote::RsyncPlugin -      true -    end - -    # create capistrano instance -    cap = Capistrano::Configuration.new - -    # add tasks to capistrano instance -    cap.load File.dirname(__FILE__) + '/../remote/tasks.rb' - -    return cap -  end - -  def contingent_ssh_options_for_node(node) -    opts = {} -    if node.vagrant? -      opts[:keys] = [vagrant_ssh_key_file] -      opts[:keys_only] = true # only use the keys specified above, and ignore whatever keys the ssh-agent is aware of. -      opts[:paranoid] = false # we skip host checking for vagrant nodes, because fingerprint is different for everyone. -      if LeapCli.logger.log_level <= 1 -        opts[:verbose] = :error # suppress all the warnings about adding host keys to known_hosts, since it is not actually doing that. -      end -    end -    if !node.supported_ssh_host_key_algorithms.empty? -      opts[:host_key] = node.supported_ssh_host_key_algorithms -    end -    return opts -  end - -end; end; end
\ No newline at end of file diff --git a/lib/leap_cli/util/secret.rb b/lib/leap_cli/util/secret.rb deleted file mode 100644 index 749b959..0000000 --- a/lib/leap_cli/util/secret.rb +++ /dev/null @@ -1,55 +0,0 @@ -# encoding: utf-8 -# -# A simple secret generator -# -# Uses OpenSSL random number generator instead of Ruby's rand function -# -autoload :OpenSSL, 'openssl' - -module LeapCli; module Util -  class Secret -    CHARS = (('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a) - "i1loO06G".split(//u) -    HEX = (0..9).to_a + ('a'..'f').to_a - -    # -    # generate a secret with with no ambiguous characters. -    # -    # +length+ is in chars -    # -    # Only alphanumerics are allowed, in order to make these passwords work -    # for REST url calls and to allow you to easily copy and paste them. -    # -    def self.generate(length = 16) -      seed -      OpenSSL::Random.random_bytes(length).bytes.to_a.collect { |byte| -        CHARS[ byte % CHARS.length ] -      }.join -    end - -    # -    # generates a hex secret, instead of an alphanumeric on. -    # -    # length is in bits -    # -    def self.generate_hex(length = 128) -      seed -      OpenSSL::Random.random_bytes(length/4).bytes.to_a.collect { |byte| -        HEX[ byte % HEX.length ] -      }.join -    end - -    private - -    def self.seed -      @pid ||= 0 -      pid = $$ -      if @pid != pid -        now = Time.now -        ary = [now.to_i, now.nsec, @pid, pid] -        OpenSSL::Random.seed(ary.to_s) -        @pid = pid -      end -    end - -  end -end; end diff --git a/lib/leap_cli/util/x509.rb b/lib/leap_cli/util/x509.rb deleted file mode 100644 index 787fdfa..0000000 --- a/lib/leap_cli/util/x509.rb +++ /dev/null @@ -1,33 +0,0 @@ -autoload :OpenSSL, 'openssl' -autoload :CertificateAuthority, 'certificate_authority' - -require 'digest' -require 'digest/md5' -require 'digest/sha1' - -module LeapCli; module X509 -  extend self - -  # -  # returns a fingerprint of a x509 certificate -  # -  def fingerprint(digest, cert_file) -    if cert_file.is_a? String -      cert = OpenSSL::X509::Certificate.new(Util.read_file!(cert_file)) -    elsif cert_file.is_a? OpenSSL::X509::Certificate -      cert = cert_file -    elsif cert_file.is_a? CertificateAuthority::Certificate -      cert = cert_file.openssl_body -    end -    digester = case digest -      when "MD5" then Digest::MD5.new -      when "SHA1" then Digest::SHA1.new -      when "SHA256" then Digest::SHA256.new -      when "SHA384" then Digest::SHA384.new -      when "SHA512" then Digest::SHA512.new -    end -    digester.hexdigest(cert.to_der) -  end - - -end; end | 
