diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/leap_cli/commands/compile.rb | 2 | ||||
-rw-r--r-- | lib/leap_cli/commands/list.rb | 27 | ||||
-rw-r--r-- | lib/leap_cli/commands/test.rb | 2 | ||||
-rw-r--r-- | lib/leap_cli/config/macros.rb | 2 | ||||
-rw-r--r-- | lib/leap_cli/config/manager.rb | 132 | ||||
-rw-r--r-- | lib/leap_cli/util/remote_command.rb | 27 | ||||
-rw-r--r-- | lib/leap_cli/version.rb | 4 |
7 files changed, 131 insertions, 65 deletions
diff --git a/lib/leap_cli/commands/compile.rb b/lib/leap_cli/commands/compile.rb index 11e6e35..e96cb6a 100644 --- a/lib/leap_cli/commands/compile.rb +++ b/lib/leap_cli/commands/compile.rb @@ -125,7 +125,7 @@ module LeapCli end # all other records - manager.environments.each do |env| + manager.environment_names.each do |env| next if env == 'local' nodes = manager.nodes[:environment => env] next unless nodes.any? diff --git a/lib/leap_cli/commands/list.rb b/lib/leap_cli/commands/list.rb index 15b91d5..5b84113 100644 --- a/lib/leap_cli/commands/list.rb +++ b/lib/leap_cli/commands/list.rb @@ -15,6 +15,11 @@ module LeapCli; module Commands c.flag 'print', :desc => 'What attributes to print (optional)' c.switch 'disabled', :desc => 'Include disabled nodes in the list.', :negatable => false c.action do |global_options,options,args| + if global_options[:color] + colors = ['cyan', 'white'] + else + colors = [nil, nil] + end puts if options['disabled'] manager.load(:include_disabled => true) # reload, with disabled nodes @@ -23,11 +28,11 @@ module LeapCli; module Commands print_node_properties(manager.filter(args), options['print']) else if args.any? - NodeTable.new(manager.filter(args)).run + NodeTable.new(manager.filter(args), colors).run else - TagTable.new('SERVICES', manager.services).run - TagTable.new('TAGS', manager.tags).run - NodeTable.new(manager.nodes).run + TagTable.new('SERVICES', manager.services, colors).run + TagTable.new('TAGS', manager.tags, colors).run + NodeTable.new(manager.nodes, colors).run end end end @@ -57,20 +62,21 @@ module LeapCli; module Commands class TagTable include CommandLineReporter - def initialize(heading, tag_list) + def initialize(heading, tag_list, colors) @heading = heading @tag_list = tag_list + @colors = colors end def run tags = @tag_list.keys.sort max_width = [20, (tags+[@heading]).inject(0) {|max,i| [i.size,max].max}].max table :border => false do - row :color => 'cyan' do + row :color => @colors[0] do column @heading, :align => 'right', :width => max_width column "NODES", :width => HighLine::SystemExtensions.terminal_size.first - max_width - 2, :padding => 2 end tags.each do |tag| - row :color => 'white' do + row :color => @colors[1] do column tag column @tag_list[tag].node_list.keys.sort.join(', ') end @@ -85,8 +91,9 @@ module LeapCli; module Commands # class NodeTable include CommandLineReporter - def initialize(node_list) + def initialize(node_list, colors) @node_list = node_list + @colors = colors end def run rows = @node_list.keys.sort.collect do |node_name| @@ -102,13 +109,13 @@ module LeapCli; module Commands max_service_width = (rows.map{|i|i[1]} + ["SERVICES"]).inject(0) {|max,i| [i.size+padding+padding,max].max} max_tag_width = (rows.map{|i|i[2]} + ["TAGS"] ).inject(0) {|max,i| [i.size,max].max} table :border => false do - row :color => 'cyan' do + row :color => @colors[0] do column "NODES", :align => 'right', :width => max_node_width column "SERVICES", :width => max_service_width, :padding => 2 column "TAGS", :width => max_tag_width end rows.each do |r| - row :color => 'white' do + row :color => @colors[1] do column r[0] column r[1] column r[2] diff --git a/lib/leap_cli/commands/test.rb b/lib/leap_cli/commands/test.rb index 024ca25..2584a69 100644 --- a/lib/leap_cli/commands/test.rb +++ b/lib/leap_cli/commands/test.rb @@ -46,7 +46,7 @@ module LeapCli; module Commands assert_config! 'provider.ca.client_certificates.unlimited_prefix' assert_config! 'provider.ca.client_certificates.limited_prefix' template = read_file! Path.find_file(:test_client_openvpn_template) - manager.environments.each do |env| + manager.environment_names.each do |env| vpn_nodes = manager.nodes[:environment => env][:services => 'openvpn']['openvpn.allow_limited' => true] if vpn_nodes.any? generate_test_client_cert(provider.ca.client_certificates.limited_prefix) do |key, cert| diff --git a/lib/leap_cli/config/macros.rb b/lib/leap_cli/config/macros.rb index b5dc3b8..2eabdd0 100644 --- a/lib/leap_cli/config/macros.rb +++ b/lib/leap_cli/config/macros.rb @@ -25,7 +25,7 @@ module LeapCli; module Config # grab an environment appropriate provider # def provider - global.providers[@node.environment] || global.provider + global.env(@node.environment).provider end # diff --git a/lib/leap_cli/config/manager.rb b/lib/leap_cli/config/manager.rb index 7969d40..1a66bff 100644 --- a/lib/leap_cli/config/manager.rb +++ b/lib/leap_cli/config/manager.rb @@ -9,16 +9,24 @@ end module LeapCli module Config + class Environment + attr_accessor :services, :tags, :provider + end + # # A class to manage all the objects in all the configuration files. # class Manager + def initialize + @environments = {} # hash of `Environment` objects, keyed by name. + end + ## ## ATTRIBUTES ## - attr_reader :services, :tags, :nodes, :provider, :providers, :common, :secrets + attr_reader :nodes, :common, :secrets attr_reader :base_services, :base_tags, :base_provider, :base_common # @@ -32,10 +40,24 @@ module LeapCli # returns an Array of all the environments defined for this provider. # the returned array includes nil (for the default environment) # - def environments - @environments ||= [nil] + self.tags.collect {|name, tag| tag['environment']}.compact + def environment_names + @environment_names ||= [nil] + env.tags.collect {|name, tag| tag['environment']}.compact end + # + # Returns the appropriate environment variable + # + def env(env=nil) + env ||= 'default' + e = @environments[env] ||= Environment.new + yield e if block_given? + e + end + + def services; env('default').services; end + def tags; env('default').tags; end + def provider; env('default').provider; end + ## ## IMPORT EXPORT ## @@ -48,34 +70,43 @@ module LeapCli # load base @base_services = load_all_json(Path.named_path([:service_config, '*'], Path.provider_base), Config::Tag) - @base_tags = load_all_json(Path.named_path([:tag_config, '*'], Path.provider_base), Config::Tag) - @base_common = load_json(Path.named_path(:common_config, Path.provider_base), Config::Object) - @base_provider = load_json(Path.named_path(:provider_config, Path.provider_base), Config::Provider) + @base_tags = load_all_json(Path.named_path([:tag_config, '*'], Path.provider_base), Config::Tag) + @base_common = load_json( Path.named_path(:common_config, Path.provider_base), Config::Object) + @base_provider = load_json( Path.named_path(:provider_config, Path.provider_base), Config::Provider) # 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), Config::Tag) - @tags = load_all_json(Path.named_path([:tag_config, '*'], @provider_dir), Config::Tag) - @nodes = load_all_json(Path.named_path([:node_config, '*'], @provider_dir), Config::Node) - @common = load_json(common_path, Config::Object) - @provider = load_json(provider_path, Config::Provider) - @secrets = load_json(Path.named_path(:secrets_config, @provider_dir), Config::Secrets) - - ### BEGIN HACK - ### remove this after it is likely that no one has any old-style secrets.json - if @secrets['webapp_secret_token'] - @secrets = Config::Secrets.new - Util::log :warning, "Creating all new secrets.json (new version is scoped by environment). Make sure to do a full deploy so that new secrets take effect." + @nodes = load_all_json(Path.named_path([:node_config, '*'], @provider_dir), Config::Node) + @common = load_json( Path.named_path(:common_config, @provider_dir), Config::Object) + @secrets = load_json( Path.named_path(:secrets_config, @provider_dir), Config::Secrets) + @common.inherit_from! @base_common + + # load provider services, tags, and provider.json, DEFAULT environment + log 3, :loading, 'default environment.........' + env('default') do |e| + e.services = load_all_json(Path.named_path([:service_config, '*'], @provider_dir), Config::Tag, :no_dots => true) + e.tags = load_all_json(Path.named_path([:tag_config, '*'], @provider_dir), Config::Tag, :no_dots => true) + e.provider = load_json( Path.named_path(:provider_config, @provider_dir), Config::Provider, :assert => true) + e.services.inherit_from! @base_services + e.tags.inherit_from! @base_tags + e.provider.inherit_from! @base_provider + validate_provider(e.provider) + end + + # load provider services, tags, and provider.json, OTHER environments + environment_names.each do |ename| + next unless ename + log 3, :loading, '%s environment.........' % ename + env(ename) do |e| + e.services = load_all_json(Path.named_path([:service_env_config, '*', ename], @provider_dir), Config::Tag) + e.tags = load_all_json(Path.named_path([:tag_env_config, '*', ename], @provider_dir), Config::Tag) + e.provider = load_json( Path.named_path([:provider_env_config, ename], @provider_dir), Config::Provider) + e.services.inherit_from! env.services + e.tags.inherit_from! env.tags + e.provider.inherit_from! env.provider + validate_provider(e.provider) + end end - ### END HACK - # 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| Util::assert! name =~ /^[0-9a-z-]+$/, "Illegal character(s) used in node name '#{name}'" @nodes[name] = apply_inheritance(node) @@ -84,19 +115,6 @@ module LeapCli unless options[:include_disabled] remove_disabled_nodes end - - # load optional environment specific providers - validate_provider(@provider) - @providers = {} - environments.each do |env| - if Path.defined?(:provider_env_config) - provider_path = Path.named_path([:provider_env_config, env], @provider_dir) - providers[env] = load_json(provider_path, Config::Provider) - providers[env].inherit_from! @provider - validate_provider(providers[env]) - end - end - end # @@ -232,12 +250,13 @@ module LeapCli private - def load_all_json(pattern, object_class) + 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$/,'') + name = File.basename(filename).force_encoding('utf-8').sub(/^([^\.]+).*\.json$/,'\1') obj['name'] ||= name results[name] = obj end @@ -245,7 +264,10 @@ module LeapCli results end - def load_json(filename, object_class) + def load_json(filename, object_class, options={}) + if options[:assert] + Util::assert_files_exist!(filename) + end if !File.exists?(filename) return object_class.new(self) end @@ -311,20 +333,32 @@ module LeapCli new_node = Config::Node.new(self) name = node.name + # 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). + node_env = self.env + if node['tags'] + node['tags'].to_a.each do |tag| + if self.environment_names.include?(tag) + node_env = self.env(tag) + end + end + end + # inherit from common new_node.deep_merge!(@common) # inherit from services if node['services'] node['services'].to_a.each do |node_service| - service = @services[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) - service.node_list.add(name, new_node) + self.services[node_service].node_list.add(name, new_node) end end end @@ -335,14 +369,14 @@ module LeapCli end if node['tags'] node['tags'].to_a.each do |node_tag| - tag = @tags[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) - tag.node_list.add(name, new_node) + self.tags[node_tag].node_list.add(name, new_node) end end end @@ -365,12 +399,12 @@ module LeapCli @disabled_nodes[name] = node if node['services'] node['services'].to_a.each do |node_service| - @services[node_service].node_list.delete(node.name) + self.services[node_service].node_list.delete(node.name) end end if node['tags'] node['tags'].to_a.each do |node_tag| - @tags[node_tag].node_list.delete(node.name) + self.tags[node_tag].node_list.delete(node.name) end end end diff --git a/lib/leap_cli/util/remote_command.rb b/lib/leap_cli/util/remote_command.rb index 6972bbb..b4b2b1f 100644 --- a/lib/leap_cli/util/remote_command.rb +++ b/lib/leap_cli/util/remote_command.rb @@ -48,9 +48,34 @@ module LeapCli; module Util; module RemoteCommand # # 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 { - :config => "~/.ssh/config", + :keys_only => false, # Don't you dare change this. :global_known_hosts_file => path(:known_hosts), :user_known_hosts_file => '/dev/null', :paranoid => true diff --git a/lib/leap_cli/version.rb b/lib/leap_cli/version.rb index 9f8e381..7c39e05 100644 --- a/lib/leap_cli/version.rb +++ b/lib/leap_cli/version.rb @@ -1,7 +1,7 @@ module LeapCli unless defined?(LeapCli::VERSION) - VERSION = '1.5.3' - COMPATIBLE_PLATFORM_VERSION = '0.3.0'..'1.99' + VERSION = '1.5.4' + COMPATIBLE_PLATFORM_VERSION = '0.5.2'..'1.99' SUMMARY = 'Command line interface to the LEAP platform' DESCRIPTION = 'The command "leap" can be used to manage a bevy of servers running the LEAP platform from the comfort of your own home.' LOAD_PATHS = ['lib', 'vendor/certificate_authority/lib', 'vendor/rsync_command/lib'] |