From 7f89d03d68f96e692da2653db30f8aae2ac1729b Mon Sep 17 00:00:00 2001 From: elijah Date: Tue, 20 May 2014 23:37:44 -0700 Subject: added support for environmentally scoped services and tags (e.g. services/webapp.production.json). requires latest platform. --- lib/leap_cli/commands/compile.rb | 2 +- lib/leap_cli/commands/test.rb | 2 +- lib/leap_cli/config/macros.rb | 2 +- lib/leap_cli/config/manager.rb | 132 ++++++++++++++++++++++++--------------- lib/leap_cli/version.rb | 4 +- test/leap_platform/platform.rb | 18 +++++- 6 files changed, 103 insertions(+), 57 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/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 c6938fe..63dce97 100644 --- a/lib/leap_cli/config/macros.rb +++ b/lib/leap_cli/config/macros.rb @@ -23,7 +23,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/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'] diff --git a/test/leap_platform/platform.rb b/test/leap_platform/platform.rb index 9f63b4c..52bb8df 100644 --- a/test/leap_platform/platform.rb +++ b/test/leap_platform/platform.rb @@ -1,15 +1,16 @@ +# encoding: utf-8 # # These are variables defined by this leap_platform and used by leap_cli. # Leap::Platform.define do - self.version = "1.1.2" - self.compatible_cli = "1.1.2".."1.99" + self.version = "0.5.2" + self.compatible_cli = "1.5.4".."1.99" # # the facter facts that should be gathered # - self.facts = ["ec2_local_ipv4"] + self.facts = ["ec2_local_ipv4", "ec2_public_ipv4"] # # the named paths for this platform @@ -31,6 +32,11 @@ Leap::Platform.define do :service_config => 'services/#{arg}.json', :tag_config => 'tags/#{arg}.json', + # input config files, environmentally scoped + :provider_env_config => 'provider.#{arg}.json', + :service_env_config => 'services/#{arg}.#{arg}.json', + :tag_env_config => 'tags/#{arg}.#{arg}.json', + # input templates :provider_json_template => 'files/service-definitions/provider.json.erb', :eip_service_json_template => 'files/service-definitions/#{arg}/eip-service.json.erb', @@ -43,6 +49,8 @@ Leap::Platform.define do :user_pgp => 'users/#{arg}/#{arg}_pgp.pub', :known_hosts => 'files/ssh/known_hosts', :authorized_keys => 'files/ssh/authorized_keys', + :monitor_pub_key => 'files/ssh/monitor_ssh.pub', + :monitor_priv_key => 'files/ssh/monitor_ssh', :ca_key => 'files/ca/ca.key', :ca_cert => 'files/ca/ca.crt', :client_ca_key => 'files/ca/client_ca.key', @@ -73,5 +81,9 @@ Leap::Platform.define do self.node_files = [ :node_config, :hiera, :node_x509_cert, :node_x509_key, :node_ssh_pub_key ] + + self.monitor_username = 'monitor' + + self.reserved_usernames = ['monitor'] end -- cgit v1.2.3