aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/leap_cli/commands/compile.rb2
-rw-r--r--lib/leap_cli/commands/list.rb27
-rw-r--r--lib/leap_cli/commands/test.rb2
-rw-r--r--lib/leap_cli/config/macros.rb2
-rw-r--r--lib/leap_cli/config/manager.rb132
-rw-r--r--lib/leap_cli/util/remote_command.rb27
-rw-r--r--lib/leap_cli/version.rb4
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']