aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2014-09-30 13:36:26 -0700
committerelijah <elijah@riseup.net>2014-09-30 13:36:26 -0700
commita5b77fa30ed5548978c0907b74ba986cdbf6c11a (patch)
treefad9db58d566fb3cc2b4a605bc941ea580dfb1a9
parent410b5d793e8b8ee0abd42b581f09d8c7d5721ed3 (diff)
downloadleap_cli-a5b77fa30ed5548978c0907b74ba986cdbf6c11a.tar.gz
leap_cli-a5b77fa30ed5548978c0907b74ba986cdbf6c11a.tar.bz2
environment pinning: new commands `leap env`, `leap env pin X` and `leap env unpin`. See `leap help env` for more information.
-rw-r--r--lib/leap_cli/commands/compile.rb7
-rw-r--r--lib/leap_cli/commands/deploy.rb14
-rw-r--r--lib/leap_cli/commands/env.rb53
-rw-r--r--lib/leap_cli/commands/list.rb9
-rw-r--r--lib/leap_cli/commands/pre.rb7
-rw-r--r--lib/leap_cli/config/manager.rb104
-rw-r--r--lib/leap_cli/config/tag.rb7
-rw-r--r--lib/leap_cli/leapfile.rb70
-rw-r--r--lib/leap_cli/version.rb2
9 files changed, 206 insertions, 67 deletions
diff --git a/lib/leap_cli/commands/compile.rb b/lib/leap_cli/commands/compile.rb
index eaedfbf..13fa9ac 100644
--- a/lib/leap_cli/commands/compile.rb
+++ b/lib/leap_cli/commands/compile.rb
@@ -9,10 +9,13 @@ module LeapCli
c.command :all do |all|
all.action do |global_options,options,args|
environment = args.first
+ if !LeapCli.leapfile.environment.nil? && environment != LeapCli.leapfile.environment
+ bail! "You cannot specify an ENVIRONMENT argument while the environment is pinned."
+ end
if environment && manager.environment_names.include?(environment)
- compile_hiera_files(manager.filter(args))
+ compile_hiera_files(manager.filter([environment]))
else
- compile_hiera_files
+ compile_hiera_files(manager.filter)
end
end
end
diff --git a/lib/leap_cli/commands/deploy.rb b/lib/leap_cli/commands/deploy.rb
index 553b2b1..bd1f479 100644
--- a/lib/leap_cli/commands/deploy.rb
+++ b/lib/leap_cli/commands/deploy.rb
@@ -36,7 +36,7 @@ module LeapCli
init_submodules
end
- nodes = filter_deploy_nodes(args)
+ nodes = manager.filter!(args)
if nodes.size > 1
say "Deploying to these nodes: #{nodes.keys.join(', ')}"
if !global[:yes] && !agree("Continue? ")
@@ -253,17 +253,5 @@ module LeapCli
tags.join(',')
end
- #
- # for safety, we allow production deploys to be turned off in the Leapfile.
- #
- def filter_deploy_nodes(filter)
- nodes = manager.filter!(filter)
- if !leapfile.allow_production_deploy
- nodes = nodes[:environment => "!production"]
- assert! nodes.any?, "Skipping deploy because @allow_production_deploy is disabled."
- end
- nodes
- end
-
end
end
diff --git a/lib/leap_cli/commands/env.rb b/lib/leap_cli/commands/env.rb
new file mode 100644
index 0000000..d81e82f
--- /dev/null
+++ b/lib/leap_cli/commands/env.rb
@@ -0,0 +1,53 @@
+module LeapCli
+ module Commands
+
+ desc "Manipulate and query environment information."
+ long_desc "The 'environment' node property can be used to isolate sets of nodes into entirely separate environments. "+
+ "A node in one environment will never interact with a node from another environment. "+
+ "Environment pinning works by modifying your ~/.leaprc file and is dependent on the "+
+ "absolute file path of your provider directory (pins don't apply if you move the directory)"
+ command :env do |c|
+ c.desc "List the available environments. The pinned environment, if any, will be marked with '*'."
+ c.command :ls do |ls|
+ ls.action do |global_options, options, args|
+ envs = ["default"] + manager.environment_names.compact.sort
+ envs.each do |env|
+ if env
+ if LeapCli.leapfile.environment == env
+ puts "* #{env}"
+ else
+ puts " #{env}"
+ end
+ end
+ end
+ end
+ end
+
+ c.desc 'Pin the environment to ENVIRONMENT. All subsequent commands will only apply to nodes in this environment.'
+ c.arg_name 'ENVIRONMENT'
+ c.command :pin do |pin|
+ pin.action do |global_options,options,args|
+ environment = args.first
+ if environment == 'default' ||
+ (environment && manager.environment_names.include?(environment))
+ LeapCli.leapfile.set('environment', environment)
+ log 0, :saved, "Leapfile with environment set to #{environment}."
+ end
+ end
+ end
+
+ c.desc "Unpin the environment. All subsequent commands will apply to all nodes."
+ c.command :unpin do |unpin|
+ unpin.action do |global_options, options, args|
+ LeapCli.leapfile.unset('environment')
+ log 0, :saved, "Leapfile, removing environment property."
+ end
+ end
+
+ c.default_command :ls
+ end
+
+ protected
+
+ end
+end \ No newline at end of file
diff --git a/lib/leap_cli/commands/list.rb b/lib/leap_cli/commands/list.rb
index be9163b..b8d7739 100644
--- a/lib/leap_cli/commands/list.rb
+++ b/lib/leap_cli/commands/list.rb
@@ -30,9 +30,10 @@ module LeapCli; module Commands
if args.any?
NodeTable.new(manager.filter(args), colors).run
else
- TagTable.new('SERVICES', manager.services, colors).run
- TagTable.new('TAGS', manager.tags, colors).run
- NodeTable.new(manager.nodes, colors).run
+ environment = LeapCli.leapfile.environment || '_all_'
+ TagTable.new('SERVICES', manager.env(environment).services, colors).run
+ TagTable.new('TAGS', manager.env(environment).tags, colors).run
+ NodeTable.new(manager.filter(), colors).run
end
end
end
@@ -41,7 +42,6 @@ module LeapCli; module Commands
private
def self.print_node_properties(nodes, properties)
- node_list = manager.nodes
properties = properties.split(',')
max_width = nodes.keys.inject(0) {|max,i| [i.size,max].max}
nodes.each_node do |node|
@@ -75,6 +75,7 @@ module LeapCli; module Commands
column "NODES", :width => HighLine::SystemExtensions.terminal_size.first - max_width - 2, :padding => 2
end
tags.each do |tag|
+ next if @tag_list[tag].node_list.empty?
row :color => @colors[1] do
column tag
column @tag_list[tag].node_list.keys.sort.join(', ')
diff --git a/lib/leap_cli/commands/pre.rb b/lib/leap_cli/commands/pre.rb
index 835eada..2e5c34e 100644
--- a/lib/leap_cli/commands/pre.rb
+++ b/lib/leap_cli/commands/pre.rb
@@ -48,13 +48,6 @@ module LeapCli; module Commands
bail! { log :missing, "platform directory '#{Path.platform}'" }
end
- if LeapCli.leapfile.platform_branch && LeapCli::Util.is_git_directory?(Path.platform)
- branch = LeapCli::Util.current_git_branch(Path.platform)
- if branch != LeapCli.leapfile.platform_branch
- bail! "Wrong branch for #{Path.platform}. Was '#{branch}', should be '#{LeapCli.leapfile.platform_branch}'. Edit Leapfile to disable this check."
- end
- end
-
#
# set log file
#
diff --git a/lib/leap_cli/config/manager.rb b/lib/leap_cli/config/manager.rb
index 21dafd1..e11d5c6 100644
--- a/lib/leap_cli/config/manager.rb
+++ b/lib/leap_cli/config/manager.rb
@@ -64,9 +64,24 @@ module LeapCli
e
end
- def services; env('default').services; end
- def tags; env('default').tags; end
- def provider; env('default').provider; end
+ #
+ # The default accessors for services, tags, and provider.
+ # For these defaults, use 'default' environment, or whatever
+ # environment is pinned.
+ #
+ def services
+ env(default_environment).services
+ end
+ def tags
+ env(default_environment).tags
+ end
+ def provider
+ env(default_environment).provider
+ end
+
+ def default_environment
+ LeapCli.leapfile.environment
+ end
##
## IMPORT EXPORT
@@ -90,8 +105,8 @@ module LeapCli
@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.........'
+ # For the default environment, load provider services, tags, and provider.json
+ 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)
@@ -102,17 +117,28 @@ module LeapCli
validate_provider(e.provider)
end
- # load provider services, tags, and provider.json, OTHER environments
+ # create a special '_all_' environment, used for tracking the union
+ # of all the environments
+ env('_all_') do |e|
+ e.services = Config::ObjectList.new
+ e.tags = Config::ObjectList.new
+ e.provider = Config::Provider.new
+ e.services.inherit_from! env('default').services
+ e.tags.inherit_from! env('default').tags
+ e.provider.inherit_from! env('default').provider
+ end
+
+ # For each defined environment, load provider services, tags, and provider.json.
environment_names.each do |ename|
next unless ename
- log 3, :loading, '%s environment.........' % 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
+ e.services.inherit_from! env('default').services
+ e.tags.inherit_from! env('default').tags
+ e.provider.inherit_from! env('default').provider
validate_provider(e.provider)
end
end
@@ -123,10 +149,8 @@ module LeapCli
@nodes[name] = apply_inheritance(node)
end
- # remove disabled nodes
- unless options[:include_disabled]
- remove_disabled_nodes
- end
+ # do some node-list post-processing
+ cleanup_node_lists(options)
# apply control files
@nodes.each do |name, node|
@@ -209,22 +233,31 @@ module LeapCli
#
# if conditions is prefixed with +, then it works like an AND. Otherwise, it works like an OR.
#
+ # The environment is pinned, then all filters get an automatic +environment_name
+ # applied (whatever the name happens to be).
+ #
# 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, options={})
- if filters.empty?
+ def filter(filters=nil, options={})
+ # handle empty filter
+ if filters.nil? || filters.empty?
+ node_list = self.nodes
+ if LeapCli.leapfile.environment
+ node_list = node_list[:environment => LeapCli.leapfile.environment_filter]
+ end
if options[:local] === false
- return nodes[:environment => '!local']
- else
- return nodes
+ node_list = node_list[:environment => '!local']
end
+ return node_list
end
+
+ # handle non-empty filters
if filters[0] =~ /^\+/
# don't let the first filter have a + prefix
filters[0] = filters[0][1..-1]
end
-
node_list = Config::ObjectList.new
filters.each do |filter|
if filter =~ /^\+/
@@ -240,6 +273,12 @@ module LeapCli
node_list.merge!(nodes_for_name(filter))
end
end
+
+ # optionally apply environment pin
+ if !options[:nopin] && LeapCli.leapfile.environment
+ node_list = node_list[:environment => environment_filter]
+ end
+
return node_list
end
@@ -414,7 +453,6 @@ module LeapCli
raise LeapCli::ConfigError.new(node, "error " + msg) if throw_exceptions
else
new_node.deep_merge!(service)
- self.services[node_service].node_list.add(name, new_node)
end
end
end
@@ -432,7 +470,6 @@ module LeapCli
raise LeapCli::ConfigError.new(node, "error " + msg) if throw_exceptions
else
new_node.deep_merge!(tag)
- self.tags[node_tag].node_list.add(name, new_node)
end
end
end
@@ -446,28 +483,35 @@ module LeapCli
apply_inheritance(node, true)
end
- def remove_disabled_nodes
+ #
+ # 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
@nodes.each do |name, node|
- unless node.enabled
- log 2, :skipping, "disabled node #{name}."
- @nodes.delete(name)
- @disabled_nodes[name] = node
+ if node.enabled || options[:include_disabled]
if node['services']
node['services'].to_a.each do |node_service|
- self.services[node_service].node_list.delete(node.name)
+ 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|
- self.tags[node_tag].node_list.delete(node.name)
+ 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}."
+ @nodes.delete(name)
+ @disabled_nodes[name] = node
end
end
end
-
#
# returns a set of nodes corresponding to a single name, where name could be a node name, service name, or tag name.
#
diff --git a/lib/leap_cli/config/tag.rb b/lib/leap_cli/config/tag.rb
index e5e719d..31f4f76 100644
--- a/lib/leap_cli/config/tag.rb
+++ b/lib/leap_cli/config/tag.rb
@@ -13,6 +13,13 @@ module LeapCli; module Config
super(manager)
@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 bdf2c37..8895f4d 100644
--- a/lib/leap_cli/leapfile.rb
+++ b/lib/leap_cli/leapfile.rb
@@ -16,13 +16,28 @@ module LeapCli
attr_accessor :leap_version
attr_accessor :log
attr_accessor :vagrant_network
- attr_accessor :platform_branch
- attr_accessor :allow_production_deploy
+ attr_accessor :environment
def initialize
@vagrant_network = '10.5.5.0/24'
end
+ #
+ # The way the Leapfile handles pinning of environment (self.environment) is a little tricky.
+ # If self.environment is nil, then there is no pin. If self.environment is 'default', then
+ # there is a pin to the default environment. The problem is that an environment of nil
+ # is used to indicate the default environment in node properties.
+ #
+ # This method returns the environment tag as needed when filtering nodes.
+ #
+ def environment_filter
+ if self.environment == 'default'
+ nil
+ else
+ self.environment
+ end
+ end
+
def load(search_directory=nil)
directory = File.expand_path(find_in_directory_tree('Leapfile', search_directory))
if directory == '/'
@@ -33,7 +48,7 @@ module LeapCli
#
@provider_directory_path = directory
read_settings(directory + '/Leapfile')
- read_settings(ENV['HOME'] + '/.leaprc')
+ read_settings(leaprc_path)
@platform_directory_path = File.expand_path(@platform_directory_path || '../leap_platform', @provider_directory_path)
#
@@ -51,20 +66,55 @@ module LeapCli
"You need platform version #{LeapCli::COMPATIBLE_PLATFORM_VERSION.first} to #{LeapCli::COMPATIBLE_PLATFORM_VERSION.last}."
end
- #
- # set defaults
- #
- if @allow_production_deploy.nil?
- # by default, only allow production deploys from 'master' or if not a git repo
- @allow_production_deploy = !LeapCli::Util.is_git_directory?(@provider_directory_path) ||
- LeapCli::Util.current_git_branch(@provider_directory_path) == 'master'
+ unless @allow_production_deploy.nil?
+ Util::log 0, :warning, "in Leapfile: @allow_production_deploy is no longer supported."
+ end
+ unless @platform_branch.nil?
+ Util::log 0, :warning, "in Leapfile: @platform_branch is no longer supported."
end
return true
end
end
+ def set(property, value)
+ edit_leaprc(property, value)
+ end
+
+ def unset(property)
+ edit_leaprc(property)
+ end
+
private
+ #
+ # adds or removes a line to .leaprc for this particular provider directory.
+ # if value is nil, the line is removed. if not nil, it is added or replaced.
+ #
+ def edit_leaprc(property, value=nil)
+ file_path = leaprc_path
+ lines = []
+ if File.exists?(file_path)
+ regexp = /self\.#{Regexp.escape(property)} = .*? if @provider_directory_path == '#{Regexp.escape(@provider_directory_path)}'/
+ File.readlines(file_path).each do |line|
+ unless line =~ regexp
+ lines << line
+ end
+ end
+ end
+ unless value.nil?
+ lines << "self.#{property} = #{value.inspect} if @provider_directory_path == '#{@provider_directory_path}'\n"
+ end
+ File.open(file_path, 'w') do |f|
+ f.write(lines.join)
+ end
+ rescue Errno::EACCES, IOError => exc
+ Util::bail! :error, "trying to save ~/.leaprc (#{exc})."
+ end
+
+ def leaprc_path
+ File.join(ENV['HOME'], '.leaprc')
+ end
+
def read_settings(file)
if File.exists? file
Util::log 2, :read, file
diff --git a/lib/leap_cli/version.rb b/lib/leap_cli/version.rb
index f8a725b..019e267 100644
--- a/lib/leap_cli/version.rb
+++ b/lib/leap_cli/version.rb
@@ -1,6 +1,6 @@
module LeapCli
unless defined?(LeapCli::VERSION)
- VERSION = '1.5.8'
+ VERSION = '1.5.9'
COMPATIBLE_PLATFORM_VERSION = '0.5.3'..'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.'