diff --git a/bundler.d/puppet.rb b/bundler.d/puppet.rb index d806b63c5..2fe29bbab 100644 --- a/bundler.d/puppet.rb +++ b/bundler.d/puppet.rb @@ -1,4 +1,4 @@ -group :puppet, :puppetca do +group :puppet_proxy_legacy do gem 'puppet', '< 5.0.0' gem 'ruby-augeas', :require => 'augeas' end diff --git a/config/settings.d/puppet.yml.example b/config/settings.d/puppet.yml.example index 785621b7b..0f68b68e8 100644 --- a/config/settings.d/puppet.yml.example +++ b/config/settings.d/puppet.yml.example @@ -3,54 +3,12 @@ :enabled: false # valid providers: -# puppetrun (for puppetrun/kick, deprecated in Puppet 3) -# mcollective (uses mco puppet) -# puppetssh (run puppet over ssh) -# salt (uses salt puppet.run) -# customrun (calls a custom command with args) -#:puppet_provider: puppetrun - -# Custom salt puppet.run command -# Set :salt_puppetrun_cmd to 'puppet.run agent no-noop' to run in no-noop mode. -# Default command is puppet.run. -#:salt_puppetrun_cmd: puppet.run - -# Customrun command details -# Set :customrun_cmd to the full path of the script you want to run, instead of /bin/false -:customrun_cmd: /bin/false -# Set :customrun_args to any args you want to pass to your custom script. The hostname of the -# system to run against will be appended after the custom commands. -:customrun_args: -ay -f -s - -:puppet_conf: /etc/puppet/puppet.conf -# whether to use sudo before the ssh command -:puppetssh_sudo: false -# the command which will be sent to the host -:puppetssh_command: /usr/bin/puppet agent --onetime --no-usecacheonfailure -# wait for the command to finish (and capture exit code), or detach process and return 0 -# Note: enabling this option causes the Foreman web UI to be blocked when executing puppetrun, -# with timeout from the Browser and/or Foreman's REST client after 60 seconds. -:puppetssh_wait: false -# With which user should the proxy connect -#:puppetssh_user: root -#:puppetssh_keyfile: /etc/foreman-proxy/id_rsa - -# Which user to invoke sudo as to run puppet commands -#:puppet_user: root - -# If you want to override the puppet_user above just for mco commands -#:mcollective_user: peadmin - -# URL of the puppet master itself for API requests -#:puppet_url: https://puppet.example.com:8140 -# SSL certificates used to access the puppet master API -#:puppet_ssl_ca: /var/lib/puppet/ssl/certs/ca.pem -#:puppet_ssl_cert: /var/lib/puppet/ssl/certs/puppet.example.com.pem -#:puppet_ssl_key: /var/lib/puppet/ssl/private_keys/puppet.example.com.pem - -# Override use of Puppet's API to list environments, by default it will use only if -# environmentpath is given in puppet.conf, else will look for environments in puppet.conf -#:puppet_use_environment_api: true - -# Cache options -#:use_cache: true +# puppet_proxy_puppetrun (for puppetrun/kick, deprecated in Puppet 3) +# puppet_proxy_mcollective (uses mco puppet) +# puppet_proxy_puppetssh (run puppet over ssh) +# puppet_proxy_salt (uses salt puppet.run) +# puppet_proxy_customrun (calls a custom command with args) +#:use_provider: puppet_proxy_puppetrun + +# Puppet version used +#:puppet_version: 4.1 diff --git a/config/settings.d/puppet_proxy_customrun.yml.example b/config/settings.d/puppet_proxy_customrun.yml.example new file mode 100644 index 000000000..720f37377 --- /dev/null +++ b/config/settings.d/puppet_proxy_customrun.yml.example @@ -0,0 +1,7 @@ +--- +# Set :command to the full path of the script you want to run, instead of /bin/false +#:command: /bin/false +# +# Set :command_arguments to any args you want to pass to your custom script. The hostname of the +# system to run against will be appended after the custom commands. +#:command_arguments: -ay -f -s diff --git a/config/settings.d/puppet_proxy_legacy.yml.example b/config/settings.d/puppet_proxy_legacy.yml.example new file mode 100644 index 000000000..3c743793f --- /dev/null +++ b/config/settings.d/puppet_proxy_legacy.yml.example @@ -0,0 +1,24 @@ +# +# puppet_proxy_legacy module is used for puppet versions prior to 4.0 +# +# puppet_proxy_legacy is configured automatcially based on +# :puppet_version setting in smart-proxy's puppet.yml configuration file. +# +--- +#:puppet_conf: /etc/puppet/puppet.conf +# +# Override use of Puppet's API to list environments, by default it will use only if +# environmentpath is given in puppet.conf, else will look for environments in puppet.conf +# (Puppet versions prior to 4.0 only) +#:use_environment_api: true +# +# URL of the puppet master itself for API requests. Required if puppet_use_environment_api is set to true. +#:puppet_url: https://puppet.example.com:8140 +# +# SSL certificates used to access the environment API. Required if puppet_use_environment_api is set to true. +#:puppet_ssl_ca: /var/lib/puppet/ssl/certs/ca.pem +#:puppet_ssl_cert: /var/lib/puppet/ssl/certs/puppet.example.com.pem +#:puppet_ssl_key: /var/lib/puppet/ssl/private_keys/puppet.example.com.pem +# +# Enable/disable puppet class cache +#:use_cache: true diff --git a/config/settings.d/puppet_proxy_mcollective.yml.example b/config/settings.d/puppet_proxy_mcollective.yml.example new file mode 100644 index 000000000..694129be5 --- /dev/null +++ b/config/settings.d/puppet_proxy_mcollective.yml.example @@ -0,0 +1,12 @@ +--- +# +# User for execution of mco commands +# +# sudo permission needs to be added to ensure +# smart-proxy can execute 'sudo' command +# +# For Puppet Enterprise this means +# Defaults:foreman-proxy !requiretty +# foreman-proxy ALL=(peadmin) NOPASSWD: /opt/puppet/bin/mco *', +# +#:user: peadmin diff --git a/config/settings.d/puppet_proxy_puppet_api.yml.example b/config/settings.d/puppet_proxy_puppet_api.yml.example new file mode 100644 index 000000000..9c3c5d083 --- /dev/null +++ b/config/settings.d/puppet_proxy_puppet_api.yml.example @@ -0,0 +1,14 @@ +# +# puppet_proxy_pupppet_api module is used for puppet versions 4.0 and higher +# +# puppet_proxy_pupppet_api is configured automatcially based on +# :puppet_version setting in smart-proxy's puppet.yml configuration file. +# +--- +# URL of the puppet master itself for API requests. +#:puppet_url: https://puppet.example.com:8140 +# +# SSL certificates used to access the puppet API +#:puppet_ssl_ca: /var/lib/puppet/ssl/certs/ca.pem +#:puppet_ssl_cert: /var/lib/puppet/ssl/certs/puppet.example.com.pem +#:puppet_ssl_key: /var/lib/puppet/ssl/private_keys/puppet.example.com.pem diff --git a/config/settings.d/puppet_proxy_puppetrun.yml.example b/config/settings.d/puppet_proxy_puppetrun.yml.example new file mode 100644 index 000000000..7030cb276 --- /dev/null +++ b/config/settings.d/puppet_proxy_puppetrun.yml.example @@ -0,0 +1,16 @@ +--- +# +# User for execution of puppetrun commands +# +# sudo permission needs to be added to ensure +# smart-proxy can execute 'sudo' command +# +# Defaults:foreman-proxy !requiretty +# foreman-proxy ALL=(peadmin) NOPASSWD: /opt/puppet/bin/puppet *', +# +# or +# +# Defaults:foreman-proxy !requiretty +# foreman-proxy ALL=(peadmin) NOPASSWD: /opt/puppet/bin/puppetrun *', +# +#:user: peadmin diff --git a/config/settings.d/puppet_proxy_salt.yml.example b/config/settings.d/puppet_proxy_salt.yml.example new file mode 100644 index 000000000..d70844ff3 --- /dev/null +++ b/config/settings.d/puppet_proxy_salt.yml.example @@ -0,0 +1,3 @@ +--- +# Set :command to 'puppet.run agent no-noop' to run in no-noop mode. Default command is puppet.run. +#:command: puppet.run diff --git a/config/settings.d/puppet_proxy_ssh.yml.example b/config/settings.d/puppet_proxy_ssh.yml.example new file mode 100644 index 000000000..9ff2bff6d --- /dev/null +++ b/config/settings.d/puppet_proxy_ssh.yml.example @@ -0,0 +1,15 @@ +--- +# the command which will be sent to the host +#:command: puppet agent --onetime --no-usecacheonfailure +# +# whether to use sudo before the ssh command +#:use_sudo: false +# +# wait for the command to finish (and capture exit code), or detach process and return 0 +# Note: enabling this option causes the Foreman web UI to be blocked when executing puppetrun, +# with timeout from the Browser and/or Foreman's REST client after 60 seconds. +#:wait: false +# +# With which user should the proxy connect +#:user: root +#:keyfile: /etc/foreman-proxy/id_rsa diff --git a/extra/migrate_settings.rb b/extra/migrate_settings.rb index fd57ba87f..8e8de4342 100644 --- a/extra/migrate_settings.rb +++ b/extra/migrate_settings.rb @@ -96,6 +96,10 @@ def underscore(src) src = src.tr("-", "_") src.downcase end + + def strip_ruby_symbol_encoding(astring) + astring.gsub("!ruby/symbol ", ":").gsub("!ruby/sym ", ":") + end end class Migrator diff --git a/extra/migrations/20150826000000_migrate_dhcp_settings.rb b/extra/migrations/20150826000000_migrate_dhcp_settings.rb index 7acbba599..0b32baf05 100644 --- a/extra/migrations/20150826000000_migrate_dhcp_settings.rb +++ b/extra/migrations/20150826000000_migrate_dhcp_settings.rb @@ -62,8 +62,4 @@ def write_to_files(output) end end end - - def strip_ruby_symbol_encoding(astring) - astring.gsub("!ruby/symbol ", ":").gsub("!ruby/sym ", ":") - end end diff --git a/extra/migrations/20160413000000_migrate_puppet_settings.rb b/extra/migrations/20160413000000_migrate_puppet_settings.rb new file mode 100644 index 000000000..ad98a5e7b --- /dev/null +++ b/extra/migrations/20160413000000_migrate_puppet_settings.rb @@ -0,0 +1,100 @@ +require 'yaml' + +class MigratePuppetSettings < ::Proxy::Migration + KNOWN_PARAMETERS = { + :enabled => [:puppet, :enabled], + :puppet_provider => [:puppet, :use_provider], + :puppet_user => [:puppet_proxy_puppetrun, :puppet_proxy_mcollective, :puppet_user], + :salt_puppetrun_cmd => [:puppet_proxy_salt, :command], + :customrun_cmd => [:puppet_proxy_customrun, :command], + :customrun_args => [:puppet_proxy_customrun, :command_arguments], + :use_cache => [:puppet_proxy_legacy, :use_cache], + :puppet_conf => [:puppet_proxy_legacy, :puppet_conf], + :puppet_use_environment_api => [:puppet_proxy_legacy, :use_environment_api], + :puppet_url => [:puppet_proxy_legacy, :puppet_proxy_puppet_api, :puppet_url], + :puppet_ssl_ca => [:puppet_proxy_legacy, :puppet_proxy_puppet_api, :puppet_ssl_ca], + :puppet_ssl_cert => [:puppet_proxy_legacy, :puppet_proxy_puppet_api, :puppet_ssl_cert], + :puppet_ssl_key => [:puppet_proxy_legacy, :puppet_proxy_puppet_api, :puppet_ssl_key], + :puppetssh_sudo => [:puppet_proxy_ssh, :use_sudo], + :puppetssh_command => [:puppet_proxy_ssh, :command], + :puppetssh_wait => [:puppet_proxy_ssh, :wait], + :puppetssh_user => [:puppet_proxy_ssh, :user], + :puppetssh_keyfile => [:puppet_proxy_ssh, :keyfile], + :mcollective_user => [:puppet_proxy_mcollective, :user] + } + + def migrate + puppet_config = path(src_dir, "settings.d", "puppet.yml") + if !File.exist?(puppet_config) + duplicate_original_configuration + return + end + + to_migrate = YAML.load_file(puppet_config) + + output = migrate_puppet_configuration(to_migrate) + copy_original_configuration_except(path("settings.d", "puppet.yml")) + write_to_files(output) + end + + def remap_parameter(aparameter, avalue) + module_names_to_parameter = KNOWN_PARAMETERS.has_key?(aparameter) ? KNOWN_PARAMETERS[aparameter] : [:unknown, aparameter] + parameter_name = module_names_to_parameter.last + module_names = module_names_to_parameter[0..-2] + + avalue = old_provider_name_to_new(avalue) if parameter_name == :use_provider + module_names.map {|module_name| [module_name, parameter_name, avalue]} + end + + def old_provider_name_to_new(aname) + if ['puppetrun', 'mcollective', 'puppetssh', 'salt', 'customrun'].include?(aname) + aname == 'puppetssh' ? 'puppet_proxy_ssh' : 'puppet_proxy_' + aname + else + aname + end + end + + def puppet_version + require 'puppet' + Puppet::PUPPETVERSION + rescue Exception + "4.3.1" + end + + def migrate_puppet_configuration(to_migrate) + migrated = Hash.new { |h,k| h[k] = Hash.new } + to_migrate.each do |option, value| + remap_parameter(option, value).each {|module_name, parameter_name, parameter_value| migrated[module_name][parameter_name] = parameter_value} + end + + # deal with puppet_user setting, which used to be global, but has been moved (and renamed) to puppetrun and mcollective modules + if migrated.has_key?(:puppet_proxy_puppetrun) + puppetrun_user = migrated[:puppet_proxy_puppetrun].delete(:puppet_user) + migrated[:puppet_proxy_puppetrun][:user] = puppetrun_user unless puppetrun_user.nil? + end + + if migrated.has_key?(:puppet_proxy_mcollective) + puppet_user = migrated[:puppet_proxy_mcollective].delete(:puppet_user) + if !(migrated[:puppet_proxy_mcollective].has_key?(:user) || puppet_user.nil?) + migrated[:puppet_proxy_mcollective][:user] = puppet_user + end + end + + migrated[:puppet][:puppet_version] = puppet_version + + migrated + end + + def write_to_files(output) + output.keys.each do |m| + next if output[m].empty? || m == :unknown + File.open(path(dst_dir, "settings.d", "#{m}.yml"),'w') do |f| + f.write(strip_ruby_symbol_encoding(output[m].to_yaml)) + if (m == :puppet) && !output[:unknown].empty? + f.write "\n# Unparsed options, please review\n" + f.write(strip_ruby_symbol_encoding(output[:unknown].to_yaml).gsub(/^---/,'')) + end + end + end + end +end diff --git a/lib/proxy/error.rb b/lib/proxy/error.rb index c64d28b42..88ac5a228 100644 --- a/lib/proxy/error.rb +++ b/lib/proxy/error.rb @@ -1,3 +1,16 @@ module Proxy::Error + class HttpError < StandardError + attr_reader :status_code, :response_body + def initialize(status_code, response_body, msg = nil) + @status_code = status_code + @response_body = response_body + @msg = msg + end + + def to_s + @msg.nil? ? "#{status_code} #{response_body}" : "#{@msg}: #{status_code} #{response_body}" + end + end + class ConfigurationError < StandardError; end end diff --git a/lib/proxy/plugin_initializer.rb b/lib/proxy/plugin_initializer.rb index 3bbd954e8..bd7d6dae1 100644 --- a/lib/proxy/plugin_initializer.rb +++ b/lib/proxy/plugin_initializer.rb @@ -24,9 +24,13 @@ def resolve_providers(all_plugins_and_providers) providers = all_plugins_and_providers.select {|p| used_providers.include?(p[:name].to_sym)} not_available = used_providers - providers.map {|p| p[:name].to_sym} - return @providers = providers.map {|p| p[:class]} if not_available.empty? - fail_group_with_message("Disabling all modules in the group '#{member_names.join(', ')}': following providers are not available #{not_available}") + if not_available.empty? + logger.debug "Providers #{printable_module_names(used_providers)} are going to be configured for '#{@plugin.plugin_name}'" + return @providers = providers.map {|p| p[:class]} + end + + fail_group_with_message("Disabling all modules in the group #{printable_module_names(member_names)}: following providers are not available #{printable_module_names(not_available)}") end def members @@ -37,6 +41,11 @@ def member_names members.map {|m| m.plugin_name } end + def printable_module_names(names) + printable = names.map {|name| "'#{name}'"}.join(", ") + "[#{printable}]" + end + def load_plugin_settings plugin.module_loader_class.new(plugin, di_container).load_settings rescue Exception => e @@ -46,12 +55,10 @@ def load_plugin_settings def load_provider_settings return if failed? providers.each do |p| - begin p.module_loader_class.new(p, di_container).load_settings(plugin.settings.marshal_dump) - rescue Exception => e - fail_group(e) - end end + rescue Exception => e + fail_group(e) end def configure @@ -64,7 +71,7 @@ def configure end def fail_group(an_exception) - fail_group_with_message("Disabling all modules in the group '#{member_names.join(', ')}' due to a failure in one of them: #{an_exception}", an_exception.backtrace) + fail_group_with_message("Disabling all modules in the group #{printable_module_names(member_names)} due to a failure in one of them: #{an_exception}", an_exception.backtrace) end def fail_group_with_message(a_message, a_backtrace = nil) @@ -215,7 +222,7 @@ def merge_settings(provider_settings, main_plugin_settings) main_plugin_settings.delete(:enabled) # all modules have 'enabled' setting, we ignore it when looking for duplicate setting names if !(overlap = main_plugin_settings.keys - (main_plugin_settings.keys - provider_settings.keys)).empty? - raise "Provider '#{plugin.plugin_name}' settings conflict with the main plugin's settings: #{overlap}" + raise Exception, "Provider '#{plugin.plugin_name}' settings conflict with the main plugin's settings: #{overlap}" end provider_settings.merge(main_plugin_settings) end @@ -254,8 +261,8 @@ def execute_validators(validations, config) validations.inject([]) do |all, validator| validator_class = available_validators[validator[:name]] - raise "Found an unknown validator '#{validator[:name]}' when validating '#{plugin.plugin_name}' module." if validator_class.nil? - validator_class.new(plugin, validator[:setting], validator[:args], validator[:predicate]).validate!(config) + raise Exception, "Encountered an unknown validator '#{validator[:name]}' when validating '#{plugin.plugin_name}' module." if validator_class.nil? + validator_class.new(plugin, validator[:setting], validator[:args], validator[:predicate]).evaluate_predicate_and_validate!(config) all << {:class => validator_class, :setting => validator[:setting], :args => validator[:args], :predicate => validator[:predicate]} end end diff --git a/lib/proxy/plugin_validators.rb b/lib/proxy/plugin_validators.rb index bbdebceca..d0dc14915 100644 --- a/lib/proxy/plugin_validators.rb +++ b/lib/proxy/plugin_validators.rb @@ -15,12 +15,15 @@ def evaluate_predicate(settings) return true if @predicate.nil? return @predicate.call(settings) end + + def evaluate_predicate_and_validate!(settings) + return true unless evaluate_predicate(settings) + validate!(settings) + end end class FileReadable < Base def validate!(settings) - return true unless evaluate_predicate(settings) - setting_value = settings[@setting_name] return true if !required_setting? && setting_value.nil? # validate optional settings only if they aren't nil raise ::Proxy::Error::ConfigurationError, "File at '#{setting_value}' defined in '#{@setting_name}' parameter doesn't exist or is unreadable" unless File.readable?(setting_value) @@ -30,8 +33,6 @@ def validate!(settings) class Presence < Base def validate!(settings) - return true unless evaluate_predicate(settings) - setting_value = settings[@setting_name] raise ::Proxy::Error::ConfigurationError, "Parameter '#{@setting_name}' is expected to have a non-empty value" if setting_value.to_s.empty? true diff --git a/lib/smart_proxy_main.rb b/lib/smart_proxy_main.rb index cf28f5a99..452677059 100644 --- a/lib/smart_proxy_main.rb +++ b/lib/smart_proxy_main.rb @@ -66,6 +66,13 @@ module Proxy require 'dhcp_libvirt/dhcp_libvirt' require 'puppetca/puppetca' require 'puppet_proxy/puppet' + require 'puppet_proxy_customrun/puppet_proxy_customrun' + require 'puppet_proxy_legacy/puppet_proxy_legacy' + require 'puppet_proxy_mcollective/puppet_proxy_mcollective' + require 'puppet_proxy_puppet_api/puppet_proxy_puppet_api' + require 'puppet_proxy_puppetrun/puppet_proxy_puppetrun' + require 'puppet_proxy_salt/puppet_proxy_salt' + require 'puppet_proxy_ssh/puppet_proxy_ssh' require 'bmc/bmc' require 'realm/realm' require 'logs/logs' diff --git a/modules/puppet_proxy/api_request.rb b/modules/puppet_proxy/api_request.rb deleted file mode 100644 index 76c6e3182..000000000 --- a/modules/puppet_proxy/api_request.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'puppet_proxy/puppet' -require 'puppet_proxy/initializer' -require 'net/http' -require 'net/https' -require 'uri' - -module Proxy::Puppet - class ApiRequest - attr_reader :url, :ssl_ca, :ssl_cert, :ssl_key - - def initialize - certname = Puppet[:certname] - - @url = Proxy::Puppet::Plugin.settings.puppet_url.to_s.empty? ? "https://#{Facter.value(:fqdn)}:8140" : Proxy::Puppet::Plugin.settings.puppet_url - begin - URI.parse(url) - rescue URI::InvalidURIError => e - raise ::Puppet::Error::ConfigurationError.new("Invalid puppet_url setting: #{e}") - end - - @ssl_ca = Proxy::Puppet::Plugin.settings.puppet_ssl_ca - @ssl_cert = Proxy::Puppet::Plugin.settings.puppet_ssl_cert.to_s.empty? ? "/var/lib/puppet/ssl/certs/#{certname}.pem" : Proxy::Puppet::Plugin.settings.puppet_ssl_cert - @ssl_key = Proxy::Puppet::Plugin.settings.puppet_ssl_key.to_s.empty? ? "/var/lib/puppet/ssl/private_keys/#{certname}.pem" : Proxy::Puppet::Plugin.settings.puppet_ssl_key - end - - def send_request(path) - uri = URI.parse(url) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = uri.scheme == 'https' - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - - if http.use_ssl? - if ssl_ca && !ssl_ca.to_s.empty? - http.ca_file = ssl_ca - http.verify_mode = OpenSSL::SSL::VERIFY_PEER - end - - if ssl_cert && !ssl_cert.to_s.empty? && ssl_key && !ssl_key.to_s.empty? - http.cert = OpenSSL::X509::Certificate.new(File.read(ssl_cert)) - http.key = OpenSSL::PKey::RSA.new(File.read(ssl_key), nil) - end - end - - path = [uri.path, path].join('/') unless uri.path.empty? - req = Net::HTTP::Get.new(URI.join(uri.to_s, path).path) - req.add_field('Accept', 'application/json') - http.request(req) - end - end - - class EnvironmentsApi < ApiRequest - def find_environments - response = send_request('/v2.0/environments') - if response.is_a? Net::HTTPOK - JSON.load(response.body) - else - raise ApiError.new("Failed to query Puppet find environments API (#{response.code}): #{response.body}") - end - end - end - - class EnvironmentsApiv3 < ApiRequest - def find_environments - response = send_request('puppet/v3/environments') - if response.is_a? Net::HTTPOK - JSON.load(response.body) - else - raise ApiError.new("Failed to query Puppet find environments API (#{response.code}): #{response.body}") - end - end - end -end diff --git a/modules/puppet_proxy/class_scanner_eparser.rb b/modules/puppet_proxy/class_scanner_eparser.rb deleted file mode 100644 index 5b0616f26..000000000 --- a/modules/puppet_proxy/class_scanner_eparser.rb +++ /dev/null @@ -1,144 +0,0 @@ -require 'puppet' -require 'puppet_proxy/puppet_class' -require 'puppet_proxy/class_scanner_base' - -if Puppet::PUPPETVERSION.to_f >= 3.2 - require 'puppet/pops' - - module Proxy::Puppet - class ClassScannerEParser < ClassScannerBase - def scan_manifest manifest, filename = '' - # FIX ME: - # We must use this on puppet 2.6, as it appears to change its global state when used. - # We should probably initialize puppet just once (during startup) on other platforms - # as global state changes can lead to concurrency issues - # If it's important to detect changes in environments without proxy restarts, - # we should consider switching to environments api when they it's available. - ::Proxy::Puppet::Initializer.new.reset_puppet - klasses = [] - - already_seen = Set.new - already_seen << '' # Prevent the toplevel "main" class from matching - ast = Puppet::Pops::Parser::Parser.new.parse_string manifest - class_finder = ClassFinder.new - - class_finder.do_find ast.current - klasses = class_finder.klasses - - klasses - rescue => e - puts "Error while parsing #{filename}: #{e}" - klasses - end - end - - class ClassFinder - attr_reader :klasses - - def initialize - @klasses = [] - @finder_visitor = Puppet::Pops::Visitor.new(self, 'find', 0, 0) - end - - def do_find ast - @finder_visitor.visit(ast) - end - - def find_HostClassDefinition o - params = {} - o.parameters.each do |param| - params[param.name] = ast_to_value_new(param.value) rescue nil - end - @klasses << PuppetClass.new(o.name, params) - - if o.body - do_find(o.body) - end - end - - def find_BlockExpression o - o.statements.collect {|x| do_find(x) } - end - - def find_CallNamedFunctionExpression o - if o.lambda - do_find(o.lambda) - end - end - - def find_Program o - if o.body - do_find(o.body) - end - end - - def find_Object o - #puts "Unhandled object:#{o}" - end - - def ast_to_value_new value - unless value.class.name.start_with? "Puppet::Pops::Model::" - # Native Ruby types - case value - # Supported with exact JSON equivalent - when NilClass, String, Numeric, Array, Hash, FalseClass, TrueClass - value - when Struct - value.hash - when Enumerable - value.to_a - # Stringified - when Regexp # /(?:stringified)/ - "/#{value}/" - when Symbol # stringified - value.to_s - else - raise TypeError - end - else - # Parser types - case value - # Supported with exact JSON equivalent - when Puppet::Pops::Model::BooleanExpression, Puppet::Pops::Model::LiteralString, Puppet::Pops::Model::LiteralNumber, Puppet::Pops::Model::QualifiedName - (Puppet::Parser::Scope.number?(value.value) || value.value) - when Puppet::Pops::Model::UnaryMinusExpression - - ast_to_value_new(value.expr) - when Puppet::Pops::Model::ArithmeticExpression - ast_to_value_new(value.left_expr).send(value.operator, ast_to_value_new(value.right_expr)) - # Supported with stringification - when Puppet::Pops::Model::ConcatenatedString - # This is the case when two params are concatenated together ,e.g. "param_${key}_something" - # Note1: only simple content are supported, plus variables whose raw name is taken - # Note2: The variable substitution WON'T be done by Puppet from the ENC YAML output - value.segments.map {|v| ast_to_value_new v}.join rescue nil - when Puppet::Pops::Model::TextExpression - ast_to_value_new value.expr - when Puppet::Pops::Model::VariableExpression - "${#{ast_to_value_new value.expr}}" - when (Puppet::Pops::Model::TypeReference rescue nil) - value.value - when Puppet::Pops::Model::LiteralUndef - "" - # Depends on content - when Puppet::Pops::Model::LiteralList - value.values.inject([]) { |arr, v| (arr << ast_to_value_new(v)) rescue arr } - when Puppet::Pops::Model::LiteralHash - # Note that all keys are string in Puppet - Hash[value.entries.inject([]) { |arr, entry| (arr << [ast_to_value_new(entry.key).to_s, ast_to_value_new(entry.value)]) rescue arr }] - when Puppet::Pops::Model::NamedFunctionDefinition - value.to_s - # Let's see if a raw evaluation works with no scope for any other type - else - if value.respond_to? :value - value.value - elsif value.respond_to? :expr - ast_to_value_new value.expr - else - raise TypeError - end - end - end - end - end - end -end diff --git a/modules/puppet_proxy/configuration_loader.rb b/modules/puppet_proxy/configuration_loader.rb new file mode 100644 index 000000000..52baff010 --- /dev/null +++ b/modules/puppet_proxy/configuration_loader.rb @@ -0,0 +1,20 @@ +module ::Proxy::Puppet + class ConfigurationLoader + def load_programmable_settings(settings) + raise ::Proxy::Error::ConfigurationError, "Parameter ':puppet_version' is expected to have a non-empty value" if settings[:puppet_version].to_s.empty? + + use_provider = settings[:use_provider] + use_provider = [use_provider].compact unless use_provider.is_a?(Array) + use_provider << (settings[:puppet_version].to_s >= "4.0" ? :puppet_proxy_puppet_api : :puppet_proxy_legacy) + settings[:use_provider] = use_provider + + settings + end + + def load_classes + require 'puppet_proxy_common/errors' + require 'puppet_proxy/dependency_injection' + require 'puppet_proxy/puppet_api' + end + end +end diff --git a/modules/puppet_proxy/customrun.rb b/modules/puppet_proxy/customrun.rb deleted file mode 100644 index f3b9397f6..000000000 --- a/modules/puppet_proxy/customrun.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'puppet_proxy/runner' - -class Proxy::Puppet::CustomRun < Proxy::Puppet::Runner - def run - cmd = Proxy::Puppet::Plugin.settings.customrun_cmd - unless File.exist?( cmd ) - logger.warn "#{cmd} not found." - return false - end - - customrun_args = (a = Proxy::Puppet::Plugin.settings.customrun_args).is_a?(Array) ? a : (a || '').split(' ') - shell_command(([escape_for_shell(cmd), customrun_args] + shell_escaped_nodes).flatten) - end -end diff --git a/modules/puppet_proxy/dependency_injection.rb b/modules/puppet_proxy/dependency_injection.rb new file mode 100644 index 000000000..e06082b73 --- /dev/null +++ b/modules/puppet_proxy/dependency_injection.rb @@ -0,0 +1,8 @@ +module Proxy::Puppet + module DependencyInjection + include Proxy::DependencyInjection::Accessors + def container_instance + @container_instance ||= ::Proxy::Plugins.instance.find {|p| p[:name] == :puppet }[:di_container] + end + end +end diff --git a/modules/puppet_proxy/dependency_injection/container.rb b/modules/puppet_proxy/dependency_injection/container.rb deleted file mode 100644 index e08dc1ef0..000000000 --- a/modules/puppet_proxy/dependency_injection/container.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Proxy::Puppet - module DependencyInjection - class Container < Proxy::DependencyInjection::Container; end - - module Wiring - include Proxy::DependencyInjection::Wiring - - def container_instance - Container.instance - end - end - - module Injectors - include Proxy::DependencyInjection::Accessors - - def container_instance - Container.instance - end - end - end -end diff --git a/modules/puppet_proxy/dependency_injection/dependencies.rb b/modules/puppet_proxy/dependency_injection/dependencies.rb deleted file mode 100644 index c100fc786..000000000 --- a/modules/puppet_proxy/dependency_injection/dependencies.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'puppet_proxy/runtime_configuration' - -module Proxy::Puppet - module DependencyInjection - class Dependencies - extend Proxy::Puppet::RuntimeConfiguration - extend Proxy::Puppet::DependencyInjection::Wiring - - def self.puppet_parser_class(a_parser) - case a_parser - when :future_parser - require 'puppet_proxy/class_scanner_eparser' - ::Proxy::Puppet::ClassScannerEParser - else - require 'puppet_proxy/class_scanner' - ::Proxy::Puppet::ClassScanner - end - end - - def self.environments_retriever_class(a_retriever) - case a_retriever - when :api_v3 - require 'puppet_proxy/puppet_api_v3_environments_retriever' - ::Proxy::Puppet::PuppetApiV3EnvironmentsRetriever - when :api_v2 - require 'puppet_proxy/puppet_api_v2_environments_retriever' - ::Proxy::Puppet::PuppetApiV2EnvironmentsRetriever - else - require 'puppet_proxy/puppet_config_environments_retriever' - ::Proxy::Puppet::PuppetConfigEnvironmentsRetriever - end - end - - dependency :puppet_class_scanner_impl, puppet_parser_class(puppet_parser) - dependency :environments_retriever_impl, environments_retriever_class(environments_retriever) - dependency :puppet_configuration_impl, Proxy::Puppet::PuppetConfig - - if Proxy::Puppet::Plugin.settings.use_cache - require 'puppet_proxy/puppet_cache' - singleton_dependency :puppet_cache_impl, Proxy::Puppet::PuppetCache - else - dependency :puppet_cache_impl, puppet_parser_class(puppet_parser) - end - end - end -end diff --git a/modules/puppet_proxy/environment.rb b/modules/puppet_proxy/environment.rb deleted file mode 100644 index 2f049f282..000000000 --- a/modules/puppet_proxy/environment.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'puppet_proxy/dependency_injection/container' - -class Proxy::Puppet::Environment - extend Proxy::Puppet::DependencyInjection::Injectors - inject_attr :puppet_cache_impl, :puppet_class_scanner - inject_attr :environments_retriever_impl, :environments_retriever - - class << self - def all - new(:name => "", :paths => "").all - end - - def find name - all.find { |e| e.name == name } - end - end - - attr_reader :name, :paths - - def initialize args - @name = args[:name].to_s || raise("Must provide a name") - @paths= args[:paths] || raise("Must provide a path") - end - - def to_s - name - end - - def classes - paths.map {|path| puppet_class_scanner.scan_directory(path, name) }.flatten - end - - def all - environments_retriever.all - end -end diff --git a/modules/puppet_proxy/mcollective.rb b/modules/puppet_proxy/mcollective.rb deleted file mode 100644 index cbc0355f3..000000000 --- a/modules/puppet_proxy/mcollective.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'puppet_proxy/runner' - -class Proxy::Puppet::MCollective < Proxy::Puppet::Runner - def run - cmd = [] - cmd.push(which("sudo")) - - # whatever user this is getting the sudo permissions will need to be added to ensure the smart-proxy - # can execute the sudo command - # For Puppet Enterprise this means - # Defaults:foreman-proxy !requiretty - # foreman-proxy ALL=(peadmin) NOPASSWD: /opt/puppet/bin/mco *', - user = Proxy::Puppet::Plugin.settings.mcollective_user || Proxy::Puppet::Plugin.settings.puppet_user - if user - cmd.push("-u", user) - end - - cmd.push(which("mco", ["/opt/puppet/bin", "/opt/puppetlabs/bin"])) - - if cmd.include?(false) - logger.warn "sudo or the mco binary is missing." - logger.warn "You must have the correct sudo permissions like: foreman-proxy ALL=(${user}) NOPASSWD: /opt/puppet/bin/mco *'" if user - return false - end - - shell_command(cmd + ["puppet", "runonce", "-I"] + shell_escaped_nodes) - end -end diff --git a/modules/puppet_proxy/puppet.rb b/modules/puppet_proxy/puppet.rb index 01882e52b..789db7a15 100644 --- a/modules/puppet_proxy/puppet.rb +++ b/modules/puppet_proxy/puppet.rb @@ -1,5 +1,2 @@ +require 'puppet_proxy/configuration_loader' require 'puppet_proxy/puppet_plugin' -module Proxy::Puppet - class ApiError < ::StandardError; end - class DataError < ::StandardError; end -end diff --git a/modules/puppet_proxy/puppet_api.rb b/modules/puppet_proxy/puppet_api.rb index 4e4c3e50b..3a9da0943 100644 --- a/modules/puppet_proxy/puppet_api.rb +++ b/modules/puppet_proxy/puppet_api.rb @@ -1,40 +1,18 @@ -require 'puppet_proxy/environment' - class Proxy::Puppet::Api < ::Sinatra::Base + extend Proxy::Puppet::DependencyInjection helpers ::Proxy::Helpers + authorize_with_trusted_hosts authorize_with_ssl_client - def puppet_setup(opts = {}) - raise "Smart Proxy is not configured to support Puppet runs" unless Proxy::Puppet::Plugin.settings.enabled - case Proxy::Puppet::Plugin.settings.puppet_provider - when "puppetrun" - require 'puppet_proxy/puppetrun' - @server = Proxy::Puppet::PuppetRun.new(opts) - when "mcollective" - require 'puppet_proxy/mcollective' - @server = Proxy::Puppet::MCollective.new(opts) - when "puppetssh" - require 'puppet_proxy/puppet_ssh' - @server = Proxy::Puppet::PuppetSSH.new(opts) - when "salt" - require 'puppet_proxy/salt' - @server = Proxy::Puppet::Salt.new(opts) - when "customrun" - require 'puppet_proxy/customrun' - @server = Proxy::Puppet::CustomRun.new(opts) - else - log_halt 400, "Unrecognized or missing puppet_provider: #{Proxy::Puppet::Plugin.settings.puppet_provider || "MISSING"}" - end - rescue => e - log_halt 400, e - end + inject_attr :class_retriever_impl, :class_retriever + inject_attr :environment_retriever_impl, :environment_retriever + inject_attr :puppet_runner_impl, :puppet_runner post "/run" do - nodes = params[:nodes] begin - log_halt 400, "Failed puppet run: No nodes defined" unless nodes - log_halt 500, "Failed puppet run: Check Log files" unless puppet_setup(:nodes => [nodes].flatten).run + log_halt 400, "Failed puppet run: No nodes defined" unless params[:nodes] + log_halt 500, "Failed puppet run: Check Log files" unless puppet_runner.run([params[:nodes]].flatten) rescue => e log_halt 500, "Failed puppet run: #{e}" end @@ -43,30 +21,31 @@ def puppet_setup(opts = {}) get "/environments" do content_type :json begin - Proxy::Puppet::Environment.all.map(&:name).to_json + environment_retriever.all.map(&:name).to_json rescue => e - log_halt 406, "Failed to list puppet environments: #{e}" + log_halt 406, "Failed to list puppet environments: #{e}" # FIXME: replace 406 with status codes from http response end end get "/environments/:environment" do content_type :json begin - env = Proxy::Puppet::Environment.find(params[:environment]) - log_halt 404, "Not found" unless env + env = environment_retriever.get(params[:environment]) {:name => env.name, :paths => env.paths}.to_json + rescue Proxy::Puppet::EnvironmentNotFound + log_halt 404, "Could not find environment '#{params[:environment]}'" rescue => e - log_halt 406, "Failed to show puppet environment: #{e}" + log_halt 406, "Failed to show puppet environment: #{e}" # FIXME: replace 406 with appropriate status codes end end get "/environments/:environment/classes" do content_type :json begin - env = Proxy::Puppet::Environment.find(params[:environment]) - log_halt 404, "Not found" unless env - env.classes.map{|k| {k.to_s => { :name => k.name, :module => k.module, :params => k.params} } }.to_json - rescue => e + class_retriever.classes_in_environment(params[:environment]).map{|k| {k.to_s => { :name => k.name, :module => k.module, :params => k.params} } }.to_json + rescue Proxy::Puppet::EnvironmentNotFound + log_halt 404, "Could not find environment '#{params[:environment]}'" + rescue Exception => e log_halt 406, "Failed to show puppet classes: #{e}" end end diff --git a/modules/puppet_proxy/puppet_api_v2_environments_retriever.rb b/modules/puppet_proxy/puppet_api_v2_environments_retriever.rb deleted file mode 100644 index 5842b022e..000000000 --- a/modules/puppet_proxy/puppet_api_v2_environments_retriever.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'puppet_proxy/api_request' - -class Proxy::Puppet::PuppetApiV2EnvironmentsRetriever - def all - response = Proxy::Puppet::EnvironmentsApi.new.find_environments - raise Proxy::Puppet::DataError.new("No environments list in Puppet API response") unless response['environments'] - environments = response['environments'].inject({}) do |envs, item| - envs[item.first] = item.last['settings']['modulepath'] if item.last && item.last['settings'] && item.last['settings']['modulepath'] - envs - end - environments.map { |env, path| Proxy::Puppet::Environment.new(:name => env, :paths => path) } - end -end diff --git a/modules/puppet_proxy/puppet_api_v3_environments_retriever.rb b/modules/puppet_proxy/puppet_api_v3_environments_retriever.rb deleted file mode 100644 index bc654c6f3..000000000 --- a/modules/puppet_proxy/puppet_api_v3_environments_retriever.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'puppet_proxy/api_request' - -class Proxy::Puppet::PuppetApiV3EnvironmentsRetriever - def all - response = Proxy::Puppet::EnvironmentsApiv3.new.find_environments - raise Proxy::Puppet::DataError.new("No environments list in Puppet API response") unless response['environments'] - environments = response['environments'].inject({}) do |envs, item| - envs[item.first] = item.last['settings']['modulepath'] if item.last && item.last['settings'] && item.last['settings']['modulepath'] - envs - end - environments.map { |env, path| Proxy::Puppet::Environment.new(:name => env, :paths => path) } - end -end diff --git a/modules/puppet_proxy/puppet_class.rb b/modules/puppet_proxy/puppet_class.rb deleted file mode 100644 index 75f49c336..000000000 --- a/modules/puppet_proxy/puppet_class.rb +++ /dev/null @@ -1,43 +0,0 @@ -class Proxy::Puppet::PuppetClass - def initialize name, params = {} - @klass = name || raise("Must provide puppet class name") - @params = params - end - - def to_s - self.module.nil? ? name : "#{self.module}::#{name}" - end - - # returns module name (excluding of the class name) - def module - klass[0..(klass.index("::")-1)] if has_module?(klass) - end - - # returns class name (excluding of the module name) - def name - has_module?(klass) ? klass[(klass.index("::")+2)..-1] : klass - end - - attr_reader :params - attr_reader :klass - - def has_module?(klass) - !!klass.index("::") - end - - def to_json(*a) - { - 'json_class' => self.class.name, - 'klass' => klass, - 'params' => params - }.to_json(*a) - end - - def self.from_hash(o) - new(o['klass'], o['params']) - end - - def ==(other) - klass == other.klass && params == other.params - end -end \ No newline at end of file diff --git a/modules/puppet_proxy/puppet_plugin.rb b/modules/puppet_proxy/puppet_plugin.rb index 80c3e2ad3..3f43b66bb 100644 --- a/modules/puppet_proxy/puppet_plugin.rb +++ b/modules/puppet_proxy/puppet_plugin.rb @@ -3,22 +3,10 @@ class Plugin < Proxy::Plugin http_rackup_path File.expand_path("http_config.ru", File.expand_path("../", __FILE__)) https_rackup_path File.expand_path("http_config.ru", File.expand_path("../", __FILE__)) - default_settings :puppet_provider => 'puppetrun', :puppet_conf => '/etc/puppet/puppet.conf', :use_cache => true, - :salt_puppetrun_cmd => 'puppet.run', :puppet_ssl_ca => '/var/lib/puppet/ssl/certs/ca.pem' - plugin :puppet, ::Proxy::VERSION - validate_readable :puppet_conf - - after_activation do - require 'puppet_proxy/initializer' - require 'puppet_proxy/ssl_configuration_validator' - - ::Proxy::Puppet::Initializer.new.reset_puppet - ::Proxy::Puppet::SslConfigurationValidator.new.validate_ssl_paths! - - require 'puppet_proxy/dependency_injection/container' - require 'puppet_proxy/dependency_injection/dependencies' - end + uses_provider + load_programmable_settings ::Proxy::Puppet::ConfigurationLoader + load_classes ::Proxy::Puppet::ConfigurationLoader end end diff --git a/modules/puppet_proxy/puppet_ssh.rb b/modules/puppet_proxy/puppet_ssh.rb deleted file mode 100644 index 25dd047bf..000000000 --- a/modules/puppet_proxy/puppet_ssh.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'puppet_proxy/runner' - -class Proxy::Puppet::PuppetSSH < Proxy::Puppet::Runner - def run - cmd = [] - cmd.push(which('sudo')) if Proxy::Puppet::Plugin.settings.puppetssh_sudo - cmd.push(which('ssh')) - cmd.push("-l", Proxy::Puppet::Plugin.settings.puppetssh_user.to_s) if Proxy::Puppet::Plugin.settings.puppetssh_user - if (file = Proxy::Puppet::Plugin.settings.puppetssh_keyfile) - if File.exist?(file) - cmd.push("-i", file.to_s) - else - logger.warn("Unable to access SSH private key:#{file}, ignoring...") - end - end - - if cmd.include?(false) - logger.warn 'sudo or the ssh binary is missing.' - return false - end - - ssh_command = Proxy::Puppet::Plugin.settings.puppetssh_command || 'puppet agent --onetime --no-usecacheonfailure' - ssh_command = escape_for_shell(ssh_command) if RUBY_VERSION <= '1.8.7' - nodes.each do |node| - shell_command(cmd + [escape_for_shell(node), ssh_command], Proxy::Puppet::Plugin.settings.puppetssh_wait || false) - end - end -end diff --git a/modules/puppet_proxy/puppetrun.rb b/modules/puppet_proxy/puppetrun.rb deleted file mode 100644 index 745153bdd..000000000 --- a/modules/puppet_proxy/puppetrun.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'puppet_proxy/runner' - -class Proxy::Puppet::PuppetRun < ::Proxy::Puppet::Runner - def run - # Search in /opt/ for puppet enterprise users - default_path = "/opt/puppet/bin" - # search for puppet for users using puppet 2.6+ - cmd = [] - cmd.push(which("sudo")) - - if Proxy::Puppet::Plugin.settings.puppet_user - cmd.push("-u", Proxy::Puppet::Plugin.settings.puppet_user) - end - - cmd.push(which("puppetrun", default_path) || which("puppet", default_path)) - - if cmd.include?(false) - logger.warn "sudo or puppetrun binary was not found - aborting" - return false - end - - # Append kick to the puppet command if we are not using the old puppetca command - cmd.push("kick") if cmd.any? { |part| part.end_with?('puppet') } - shell_command(cmd + (shell_escaped_nodes.map {|n| ["--host", n] }).flatten) - end -end diff --git a/modules/puppet_proxy/runtime_configuration.rb b/modules/puppet_proxy/runtime_configuration.rb deleted file mode 100644 index c2b1f85a1..000000000 --- a/modules/puppet_proxy/runtime_configuration.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'proxy/util' -require 'puppet_proxy/puppet_config' - -module Proxy::Puppet::RuntimeConfiguration - include Proxy::Util - - def puppet_parser - use_future_parser = puppet_version.to_i >= 4 || - (puppet_configuration[:main] && puppet_configuration[:main][:parser] == 'future') || - (puppet_configuration[:master] && puppet_configuration[:master][:parser] == 'future') - use_future_parser ? :future_parser : :legacy_parser - end - - def environments_retriever - force = to_bool(Proxy::Puppet::Plugin.settings.puppet_use_environment_api, nil) - - if puppet_version.to_i >= 4 - :api_v3 - elsif puppet_version.to_f < 3.2 - :config_file - elsif !force.nil? && force - :api_v2 - elsif !force.nil? && !force - :config_file - else - use_environment_api = !!([:main, :master].find { |s| (puppet_configuration[s] && puppet_configuration[s][:environmentpath] && !puppet_configuration[s][:environmentpath].empty?) }) - use_environment_api ? :api_v2 : :config_file - end - end - - def puppet_configuration - Proxy::Puppet::PuppetConfig.new.get - end - - def puppet_version - Puppet::PUPPETVERSION - end -end diff --git a/modules/puppet_proxy/salt.rb b/modules/puppet_proxy/salt.rb deleted file mode 100644 index da1ad9e0f..000000000 --- a/modules/puppet_proxy/salt.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'puppet_proxy/runner' - -class Proxy::Puppet::Salt < Proxy::Puppet::Runner - def run - cmd = [] - cmd.push(which('sudo')) - cmd.push(which('salt')) - - if cmd.include?(false) - logger.warn 'sudo or the salt binary is missing.' - return false - end - - cmd.push('-L') - cmd.push(shell_escaped_nodes.join(',')) - salt_puppetrun_cmd = Proxy::Puppet::Plugin.settings.salt_puppetrun_cmd - cmd.push(salt_puppetrun_cmd) - - shell_command(cmd) - end -end diff --git a/modules/puppet_proxy/ssl_configuration_validator.rb b/modules/puppet_proxy/ssl_configuration_validator.rb deleted file mode 100644 index 6339a6d0b..000000000 --- a/modules/puppet_proxy/ssl_configuration_validator.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'puppet_proxy/runtime_configuration' - -module Proxy::Puppet - class SslConfigurationValidator - include Proxy::Puppet::RuntimeConfiguration - - def validate_ssl_paths! - return true if environments_retriever == :config_file - - ssl_ca = Proxy::Puppet::Plugin.settings.puppet_ssl_ca - - check_file(ssl_ca, "puppet CA certificate at '#{ssl_ca}' defined in ':puppet_ssl_ca' setting doesn't exist or is unreadable") - check_file(ssl_cert, "puppet client certificate at #{ssl_cert} defined in ':puppet_ssl_cert' setting doesn't exist or is unreadable") - check_file(ssl_key, "puppet client private key at #{ssl_key} defined in ':puppet_ssl_key' setting doesn't exist or is unreadable") - - true - end - - def ssl_cert - Proxy::Puppet::Plugin.settings.puppet_ssl_cert.to_s.empty? ? "/var/lib/puppet/ssl/certs/#{certname}.pem" : Proxy::Puppet::Plugin.settings.puppet_ssl_cert - end - - def ssl_key - Proxy::Puppet::Plugin.settings.puppet_ssl_key.to_s.empty? ? "/var/lib/puppet/ssl/private_keys/#{certname}.pem" : Proxy::Puppet::Plugin.settings.puppet_ssl_key - end - - def check_file(path, message) - raise ::Proxy::Error::ConfigurationError, message unless File.readable?(path) - end - - def certname - Puppet[:certname] - end - end -end diff --git a/modules/puppet_proxy_common/api_request.rb b/modules/puppet_proxy_common/api_request.rb new file mode 100644 index 000000000..d0d35c208 --- /dev/null +++ b/modules/puppet_proxy_common/api_request.rb @@ -0,0 +1,45 @@ +require 'net/http' +require 'net/https' +require 'uri' + +module Proxy::Puppet + class ApiRequest + attr_reader :url, :ssl_ca, :ssl_cert, :ssl_key + + def initialize(url, ssl_ca, ssl_cert, ssl_key) + @url = url + @ssl_ca = ssl_ca + @ssl_cert = ssl_cert + @ssl_key = ssl_key + end + + def send_request(path) + uri = URI.parse(url) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = uri.scheme == 'https' + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + + if http.use_ssl? + if ssl_ca && !ssl_ca.to_s.empty? + http.ca_file = ssl_ca + http.verify_mode = OpenSSL::SSL::VERIFY_PEER + end + + if ssl_cert && !ssl_cert.to_s.empty? && ssl_key && !ssl_key.to_s.empty? + http.cert = OpenSSL::X509::Certificate.new(File.read(ssl_cert)) + http.key = OpenSSL::PKey::RSA.new(File.read(ssl_key), nil) + end + end + + path = [uri.path.chomp("/"), path.start_with?("/") ? path.slice(1..-1) : path].join('/') + req = Net::HTTP::Get.new(path) + req.add_field('Accept', 'application/json') + http.request(req) + end + + def handle_response(a_response, a_msg = nil) + return JSON.load(a_response.body) if a_response.is_a? Net::HTTPOK + raise ::Proxy::Error::HttpError.new(a_response.code, a_response.body, a_msg) + end + end +end diff --git a/modules/puppet_proxy_common/custom_validators.rb b/modules/puppet_proxy_common/custom_validators.rb new file mode 100644 index 000000000..f168dc385 --- /dev/null +++ b/modules/puppet_proxy_common/custom_validators.rb @@ -0,0 +1,12 @@ +module ::Proxy::Puppet + class Validators + class UrlValidator < ::Proxy::PluginValidators::Base + def validate!(settings) + raise ::Proxy::Error::ConfigurationError, "Setting 'puppet_url' is expected to contain a url for puppet server" if settings[:puppet_url].to_s.empty? + URI.parse(settings[:puppet_url]) + rescue URI::InvalidURIError + raise ::Proxy::Error::ConfigurationError.new("Setting 'puppet_url' contains an invalid url for puppet server") + end + end + end +end diff --git a/modules/puppet_proxy_common/environment.rb b/modules/puppet_proxy_common/environment.rb new file mode 100644 index 000000000..2f657f02a --- /dev/null +++ b/modules/puppet_proxy_common/environment.rb @@ -0,0 +1,14 @@ +module Proxy::Puppet + class Environment + attr_reader :name, :paths + + def initialize(name, paths) + @name = name.to_s + @paths = paths + end + + def to_s + name + end + end +end diff --git a/modules/puppet_proxy_common/environments_retriever_base.rb b/modules/puppet_proxy_common/environments_retriever_base.rb new file mode 100644 index 000000000..a058ff3ad --- /dev/null +++ b/modules/puppet_proxy_common/environments_retriever_base.rb @@ -0,0 +1,26 @@ +class Proxy::Puppet::EnvironmentsRetrieverBase + attr_reader :puppet_url, :ssl_ca, :ssl_cert, :ssl_key + + def initialize(puppet_url, puppet_ssl_ca, puppet_ssl_cert, puppet_ssl_key) + @puppet_url = puppet_url + @ssl_ca = puppet_ssl_ca + @ssl_cert = puppet_ssl_cert + @ssl_key = puppet_ssl_key + end + + def get(an_environment) + found = all.find { |e| e.name == an_environment } + raise Proxy::Puppet::EnvironmentNotFound.new("Could not find environment '#{an_environment}'") unless found + found + end + + def all + response = @api.find_environments + raise Proxy::Puppet::DataError.new("No environments list in Puppet API response") unless response['environments'] + environments = response['environments'].inject({}) do |envs, item| + envs[item.first] = item.last['settings']['modulepath'] if item.last && item.last['settings'] && item.last['settings']['modulepath'] + envs + end + environments.map { |env, path| Proxy::Puppet::Environment.new(env, path) } + end +end diff --git a/modules/puppet_proxy_common/errors.rb b/modules/puppet_proxy_common/errors.rb new file mode 100644 index 000000000..f4795980c --- /dev/null +++ b/modules/puppet_proxy_common/errors.rb @@ -0,0 +1,4 @@ +module Proxy::Puppet + class EnvironmentNotFound < StandardError; end + class DataError < StandardError; end +end diff --git a/modules/puppet_proxy_common/puppet_class.rb b/modules/puppet_proxy_common/puppet_class.rb new file mode 100644 index 000000000..05c1d31f8 --- /dev/null +++ b/modules/puppet_proxy_common/puppet_class.rb @@ -0,0 +1,45 @@ +module Proxy::Puppet + class PuppetClass + def initialize name, params = {} + @klass = name || raise("Must provide puppet class name") + @params = params + end + + def to_s + self.module.nil? ? name : "#{self.module}::#{name}" + end + + # returns module name (excluding of the class name) + def module + klass[0..(klass.index("::")-1)] if has_module?(klass) + end + + # returns class name (excluding of the module name) + def name + has_module?(klass) ? klass[(klass.index("::")+2)..-1] : klass + end + + attr_reader :params + attr_reader :klass + + def has_module?(klass) + !!klass.index("::") + end + + def to_json(*a) + { + 'json_class' => self.class.name, + 'klass' => klass, + 'params' => params + }.to_json(*a) + end + + def self.from_hash(o) + new(o['klass'], o['params']) + end + + def ==(other) + klass == other.klass && params == other.params + end + end +end diff --git a/modules/puppet_proxy/runner.rb b/modules/puppet_proxy_common/runner.rb similarity index 86% rename from modules/puppet_proxy/runner.rb rename to modules/puppet_proxy_common/runner.rb index 23c67ed27..350b91da8 100644 --- a/modules/puppet_proxy/runner.rb +++ b/modules/puppet_proxy_common/runner.rb @@ -3,14 +3,7 @@ class Runner include Proxy::Log include Proxy::Util - def initialize(opts) - @nodes = opts[:nodes] - end - - protected - attr_reader :nodes - - def shell_escaped_nodes + def shell_escaped_nodes(nodes) nodes.collect { |n| escape_for_shell(n) } end diff --git a/modules/puppet_proxy_customrun/customrun_main.rb b/modules/puppet_proxy_customrun/customrun_main.rb new file mode 100644 index 000000000..b937b05f1 --- /dev/null +++ b/modules/puppet_proxy_customrun/customrun_main.rb @@ -0,0 +1,18 @@ +class Proxy::PuppetCustomrun::Runner < Proxy::Puppet::Runner + attr_reader :command, :command_arguments + + def initialize(command, arguments) + @command = command + @command_arguments = arguments.is_a?(Array) ? arguments : arguments.split(' ') + super() + end + + def run(nodes) + unless File.exist?(command) + logger.warn "#{command} not found." + return false + end + + shell_command(([escape_for_shell(command), command_arguments] + shell_escaped_nodes(nodes)).flatten) + end +end diff --git a/modules/puppet_proxy_customrun/plugin_configuration.rb b/modules/puppet_proxy_customrun/plugin_configuration.rb new file mode 100644 index 000000000..10ca11454 --- /dev/null +++ b/modules/puppet_proxy_customrun/plugin_configuration.rb @@ -0,0 +1,14 @@ +module ::Proxy::PuppetCustomrun + class PluginConfiguration + def load_classes + require 'puppet_proxy_common/runner' + require 'puppet_proxy_customrun/customrun_main' + end + + def load_dependency_injection_wirings(container_instance, settings) + container_instance.dependency :puppet_runner_impl, (lambda do + ::Proxy::PuppetCustomrun::Runner.new(settings[:command], settings[:command_arguments]) + end) + end + end +end diff --git a/modules/puppet_proxy_customrun/puppet_proxy_customrun.rb b/modules/puppet_proxy_customrun/puppet_proxy_customrun.rb new file mode 100644 index 000000000..4fb7a03da --- /dev/null +++ b/modules/puppet_proxy_customrun/puppet_proxy_customrun.rb @@ -0,0 +1,2 @@ +require 'puppet_proxy_customrun/plugin_configuration' +require 'puppet_proxy_customrun/puppet_proxy_customrun_plugin' diff --git a/modules/puppet_proxy_customrun/puppet_proxy_customrun_plugin.rb b/modules/puppet_proxy_customrun/puppet_proxy_customrun_plugin.rb new file mode 100644 index 000000000..354c99a1e --- /dev/null +++ b/modules/puppet_proxy_customrun/puppet_proxy_customrun_plugin.rb @@ -0,0 +1,10 @@ +module Proxy::PuppetCustomrun + class Plugin < Proxy::Provider + plugin :puppet_proxy_customrun, ::Proxy::VERSION + + load_classes ::Proxy::PuppetCustomrun::PluginConfiguration + load_dependency_injection_wirings ::Proxy::PuppetCustomrun::PluginConfiguration + + validate_presence :command, :command_arguments + end +end diff --git a/modules/puppet_proxy/class_scanner.rb b/modules/puppet_proxy_legacy/class_scanner.rb similarity index 93% rename from modules/puppet_proxy/class_scanner.rb rename to modules/puppet_proxy_legacy/class_scanner.rb index 7c00c3e85..538563b8c 100644 --- a/modules/puppet_proxy/class_scanner.rb +++ b/modules/puppet_proxy_legacy/class_scanner.rb @@ -1,8 +1,12 @@ -require 'puppet_proxy/puppet_class' -require 'puppet_proxy/class_scanner_base' - -module Proxy::Puppet +module Proxy::PuppetLegacy class ClassScanner < ClassScannerBase + attr_reader :puppet_initializer + + def initialize(environments_retriever, puppet_initializer) + @puppet_initializer = puppet_initializer + super(environments_retriever) + end + def scan_manifest manifest, filename = '' # FIX ME: # We must use this on puppet 2.6, as it appears to change its global state when used. @@ -10,7 +14,7 @@ def scan_manifest manifest, filename = '' # as global state changes can lead to concurrency issues # If it's important to detect changes in environments without proxy restarts, # we should consider switching to environments api when they it's available. - ::Proxy::Puppet::Initializer.new.reset_puppet + puppet_initializer.reset_puppet parser = Puppet::Parser::Parser.new Puppet::Node::Environment.new klasses = [] @@ -27,7 +31,7 @@ def scan_manifest manifest, filename = '' klass.arguments.each do |name, value| params[name] = ast_to_value(value) rescue nil end - klasses << PuppetClass.new(klass.namespace, params) + klasses << ::Proxy::Puppet::PuppetClass.new(klass.namespace, params) end end klasses @@ -116,4 +120,4 @@ def ast_to_value value end end end -end \ No newline at end of file +end diff --git a/modules/puppet_proxy/class_scanner_base.rb b/modules/puppet_proxy_legacy/class_scanner_base.rb similarity index 57% rename from modules/puppet_proxy/class_scanner_base.rb rename to modules/puppet_proxy_legacy/class_scanner_base.rb index 03ad343c6..f1c86bf50 100644 --- a/modules/puppet_proxy/class_scanner_base.rb +++ b/modules/puppet_proxy_legacy/class_scanner_base.rb @@ -1,10 +1,14 @@ -require 'puppet_proxy/initializer' - -module Proxy::Puppet +module Proxy::PuppetLegacy class ClassScannerBase + attr_reader :environments_retriever + + def initialize(environments_retriever) + @environments_retriever = environments_retriever + end + # scans a given directory and its sub directory for puppet classes using the parser passed to it # returns an array of PuppetClass objects. - def scan_directory directory, environment + def scan_directory(directory) Dir.glob("#{directory}/*/manifests/**/*.pp").map do |filename| # the encoding is ignored under 1.8.7. # For the rest of rubies this will force external encoding to be UTF-8 @@ -13,5 +17,13 @@ def scan_directory directory, environment scan_manifest f.read, filename end.compact.flatten end + + def classes(paths) + paths.map {|path| scan_directory(path) }.flatten + end + + def classes_in_environment(an_environment) + classes(environments_retriever.get(an_environment).paths) + end end end diff --git a/modules/puppet_proxy_legacy/class_scanner_eparser.rb b/modules/puppet_proxy_legacy/class_scanner_eparser.rb new file mode 100644 index 000000000..25fddbfe7 --- /dev/null +++ b/modules/puppet_proxy_legacy/class_scanner_eparser.rb @@ -0,0 +1,147 @@ +if Puppet::PUPPETVERSION >= "3.2" + require 'puppet/pops' +end + +module Proxy::PuppetLegacy + class ClassScannerEParser < ClassScannerBase + attr_reader :puppet_initializer + + def initialize(environments_retriever, puppet_initializer) + @puppet_initializer = puppet_initializer + super(environments_retriever) + end + + def scan_manifest manifest, filename = '' + # FIX ME: + # We must use this on puppet 2.6, as it appears to change its global state when used. + # We should probably initialize puppet just once (during startup) on other platforms + # as global state changes can lead to concurrency issues + # If it's important to detect changes in environments without proxy restarts, + # we should consider switching to environments api when they it's available. + puppet_initializer.reset_puppet + klasses = [] + + already_seen = Set.new + already_seen << '' # Prevent the toplevel "main" class from matching + ast = Puppet::Pops::Parser::Parser.new.parse_string manifest + class_finder = ClassFinder.new + + class_finder.do_find ast.current + klasses = class_finder.klasses + + klasses + rescue => e + puts "Error while parsing #{filename}: #{e}" + klasses + end + end + + class ClassFinder + attr_reader :klasses + + def initialize + @klasses = [] + @finder_visitor = Puppet::Pops::Visitor.new(self, 'find', 0, 0) + end + + def do_find ast + @finder_visitor.visit(ast) + end + + def find_HostClassDefinition o + params = {} + o.parameters.each do |param| + params[param.name] = ast_to_value_new(param.value) rescue nil + end + @klasses << ::Proxy::Puppet::PuppetClass.new(o.name, params) + + if o.body + do_find(o.body) + end + end + + def find_BlockExpression o + o.statements.collect {|x| do_find(x) } + end + + def find_CallNamedFunctionExpression o + if o.lambda + do_find(o.lambda) + end + end + + def find_Program o + if o.body + do_find(o.body) + end + end + + def find_Object o + #puts "Unhandled object:#{o}" + end + + def ast_to_value_new value + unless value.class.name.start_with? "Puppet::Pops::Model::" + # Native Ruby types + case value + # Supported with exact JSON equivalent + when NilClass, String, Numeric, Array, Hash, FalseClass, TrueClass + value + when Struct + value.hash + when Enumerable + value.to_a + # Stringified + when Regexp # /(?:stringified)/ + "/#{value}/" + when Symbol # stringified + value.to_s + else + raise TypeError + end + else + # Parser types + case value + # Supported with exact JSON equivalent + when Puppet::Pops::Model::BooleanExpression, Puppet::Pops::Model::LiteralString, Puppet::Pops::Model::LiteralNumber, Puppet::Pops::Model::QualifiedName + (Puppet::Parser::Scope.number?(value.value) || value.value) + when Puppet::Pops::Model::UnaryMinusExpression + - ast_to_value_new(value.expr) + when Puppet::Pops::Model::ArithmeticExpression + ast_to_value_new(value.left_expr).send(value.operator, ast_to_value_new(value.right_expr)) + # Supported with stringification + when Puppet::Pops::Model::ConcatenatedString + # This is the case when two params are concatenated together ,e.g. "param_${key}_something" + # Note1: only simple content are supported, plus variables whose raw name is taken + # Note2: The variable substitution WON'T be done by Puppet from the ENC YAML output + value.segments.map {|v| ast_to_value_new v}.join rescue nil + when Puppet::Pops::Model::TextExpression + ast_to_value_new value.expr + when Puppet::Pops::Model::VariableExpression + "${#{ast_to_value_new value.expr}}" + when (Puppet::Pops::Model::TypeReference rescue nil) + value.value + when Puppet::Pops::Model::LiteralUndef + "" + # Depends on content + when Puppet::Pops::Model::LiteralList + value.values.inject([]) { |arr, v| (arr << ast_to_value_new(v)) rescue arr } + when Puppet::Pops::Model::LiteralHash + # Note that all keys are string in Puppet + Hash[value.entries.inject([]) { |arr, entry| (arr << [ast_to_value_new(entry.key).to_s, ast_to_value_new(entry.value)]) rescue arr }] + when Puppet::Pops::Model::NamedFunctionDefinition + value.to_s + # Let's see if a raw evaluation works with no scope for any other type + else + if value.respond_to? :value + value.value + elsif value.respond_to? :expr + ast_to_value_new value.expr + else + raise TypeError + end + end + end + end + end +end diff --git a/modules/puppet_proxy_legacy/environments_api_request.rb b/modules/puppet_proxy_legacy/environments_api_request.rb new file mode 100644 index 000000000..f8eef4d17 --- /dev/null +++ b/modules/puppet_proxy_legacy/environments_api_request.rb @@ -0,0 +1,7 @@ +module ::Proxy::PuppetLegacy + class EnvironmentsApi < ::Proxy::Puppet::ApiRequest + def find_environments + handle_response(send_request('v2.0/environments'), "Failed to query Puppet find environments v2 API") + end + end +end diff --git a/modules/puppet_proxy/initializer.rb b/modules/puppet_proxy_legacy/initializer.rb similarity index 55% rename from modules/puppet_proxy/initializer.rb rename to modules/puppet_proxy_legacy/initializer.rb index fbae16725..a89dbf168 100644 --- a/modules/puppet_proxy/initializer.rb +++ b/modules/puppet_proxy_legacy/initializer.rb @@ -1,29 +1,32 @@ -require 'puppet' - -module Proxy::Puppet +module Proxy::PuppetLegacy class Initializer include Proxy::Log + attr_reader :puppet_conf + + def initialize(puppet_conf) + @puppet_conf = puppet_conf + end def reset_puppet Puppet.clear - if Puppet::PUPPETVERSION.to_i >= 3 + if Puppet::PUPPETVERSION >= "3" # Used on Puppet 3.0, private method that clears the "initialized or # not" state too, so a full config reload takes place and we pick up # new environments Puppet.settings.send(:clear_everything_for_tests) end - Puppet[:config] = Proxy::Puppet::Plugin.settings.puppet_conf - logger.debug "Initializing from Puppet config file: #{Proxy::Puppet::Plugin.settings.puppet_conf}" + Puppet[:config] = puppet_conf + logger.debug "Initializing from Puppet config file: #{puppet_conf}" - if Puppet::PUPPETVERSION.to_i >= 3 + if Puppet::PUPPETVERSION >= "3" Puppet.initialize_settings else Puppet.parse_config end # Don't follow imports, the proxy scans for .pp files itself - Puppet[:ignoreimport] = true if Puppet::PUPPETVERSION.to_i < 4 && Puppet[:parser] != 'future' + Puppet[:ignoreimport] = true if Puppet::PUPPETVERSION < "4" && Puppet[:parser] != 'future' end end end diff --git a/modules/puppet_proxy_legacy/plugin_configuration.rb b/modules/puppet_proxy_legacy/plugin_configuration.rb new file mode 100644 index 000000000..73a54be20 --- /dev/null +++ b/modules/puppet_proxy_legacy/plugin_configuration.rb @@ -0,0 +1,121 @@ +require 'proxy/util' + +module ::Proxy::PuppetLegacy + class PluginConfiguration + include Proxy::Util + + def load_programmable_settings(settings) + puppet_conf_exists?(settings[:puppet_conf]) + puppet_configuration = load_puppet_configuration(settings[:puppet_conf]) + + use_future_parser = use_future_parser?(puppet_configuration) + use_cache = !!settings[:use_cache] + + settings[:classes_retriever] = if use_cache && use_future_parser + :cached_future_parser + elsif use_cache && !use_future_parser + :cached_legacy_parser + elsif !use_cache && use_future_parser + :future_parser + else + :legacy_parser + end + + force = to_bool(settings[:use_environment_api], nil) + settings[:environments_retriever] = if settings[:puppet_version].to_s < '3.2' + :config_file + elsif !force.nil? && force + :api_v2 + elsif !force.nil? && !force + :config_file + else + use_environment_api?(puppet_configuration) ? :api_v2 : :config_file + end + + settings + end + + def load_classes + require 'puppet_proxy_common/custom_validators' + require 'puppet_proxy_legacy/puppet_config' + require 'puppet_proxy_common/errors' + require 'puppet_proxy_common/environments_retriever_base' + require 'puppet_proxy_legacy/class_scanner_base' + require 'puppet_proxy_common/environment' + require 'puppet_proxy_common/puppet_class' + require 'puppet_proxy_common/api_request' + + require 'puppet' + require 'puppet_proxy_legacy/initializer' + require 'puppet_proxy_legacy/environments_api_request' + end + + def load_dependency_injection_wirings(container_instance, settings) + case settings[:environments_retriever] + when :api_v2 + require 'puppet_proxy_legacy/puppet_api_v2_environments_retriever' + container_instance.dependency :environment_retriever_impl, (lambda do + ::Proxy::PuppetLegacy::PuppetApiV2EnvironmentsRetriever.new(settings[:puppet_url], settings[:puppet_ssl_ca], settings[:puppet_ssl_cert], settings[:puppet_ssl_key]) + end) + else + require 'puppet_proxy_legacy/puppet_config_environments_retriever' + container_instance.dependency :puppet_configuration, lambda {Proxy::PuppetLegacy::ConfigReader.new(settings[:puppet_conf])} + container_instance.dependency :environment_retriever_impl, (lambda do + ::Proxy::PuppetLegacy::PuppetConfigEnvironmentsRetriever.new(container_instance.get_dependency(:puppet_configuration), settings[:puppet_conf]) + end) + end + + container_instance.dependency :puppet_initializer, lambda {Proxy::PuppetLegacy::Initializer.new(settings[:puppet_conf]) } + + case settings[:classes_retriever] + when :cached_future_parser + require 'puppet_proxy_legacy/class_scanner_eparser' + require 'puppet_proxy_legacy/puppet_cache' + container_instance.singleton_dependency :class_retriever_impl, (lambda do + ::Proxy::PuppetLegacy::PuppetCache.new( + container_instance.get_dependency(:environment_retriever_impl), + ::Proxy::PuppetLegacy::ClassScannerEParser.new(nil, container_instance.get_dependency(:puppet_initializer))) + end) + when :cached_legacy_parser + require 'puppet_proxy_legacy/class_scanner' + require 'puppet_proxy_legacy/puppet_cache' + container_instance.singleton_dependency :class_retriever_impl, (lambda do + ::Proxy::PuppetLegacy::PuppetCache.new( + container_instance.get_dependency(:environment_retriever_impl), + ::Proxy::PuppetLegacy::ClassScanner.new(nil, container_instance.get_dependency(:puppet_initializer))) + end) + when :future_parser + require 'puppet_proxy_legacy/class_scanner_eparser' + container_instance.dependency :class_retriever_impl, (lambda do + ::Proxy::PuppetLegacy::ClassScannerEParser.new( + container_instance.get_dependency(:environment_retriever_impl), + container_instance.get_dependency(:puppet_initializer)) + end) + else + require 'puppet_proxy_legacy/class_scanner' + container_instance.dependency :class_retriever_impl, (lambda do + ::Proxy::PuppetLegacy::ClassScanner.new( + container_instance.get_dependency(:environment_retriever_impl), + container_instance.get_dependency(:puppet_initializer)) + end) + end + end + + def puppet_conf_exists?(path) + raise ::Proxy::Error::ConfigurationError, "Puppet configuration file '#{path}' defined in ':puppet_conf' setting doesn't exist or is unreadable" unless File.readable?(path) + end + + def use_future_parser?(puppet_config) + (puppet_config[:main] && puppet_config[:main][:parser] == 'future') || + (puppet_config[:master] && puppet_config[:master][:parser] == 'future') + end + + def use_environment_api?(puppet_config) + !([:main, :master].any? { |s| (puppet_config[s] && puppet_config[s][:environmentpath] && !puppet_config[s][:environmentpath].empty?) }) + end + + def load_puppet_configuration(config) + @config ||= Proxy::PuppetLegacy::ConfigReader.new(config).get + end + end +end diff --git a/modules/puppet_proxy_legacy/puppet_api_v2_environments_retriever.rb b/modules/puppet_proxy_legacy/puppet_api_v2_environments_retriever.rb new file mode 100644 index 000000000..07bf23d52 --- /dev/null +++ b/modules/puppet_proxy_legacy/puppet_api_v2_environments_retriever.rb @@ -0,0 +1,8 @@ +module Proxy::PuppetLegacy + class PuppetApiV2EnvironmentsRetriever < Proxy::Puppet::EnvironmentsRetrieverBase + def initialize(puppet_url, puppet_ssl_ca, puppet_ssl_cert, puppet_ssl_key, api = nil) + super(puppet_url, puppet_ssl_ca, puppet_ssl_cert, puppet_ssl_key) + @api = api || Proxy::PuppetLegacy::EnvironmentsApi.new(puppet_url, ssl_ca, ssl_cert, ssl_key) + end + end +end diff --git a/modules/puppet_proxy/puppet_cache.rb b/modules/puppet_proxy_legacy/puppet_cache.rb similarity index 70% rename from modules/puppet_proxy/puppet_cache.rb rename to modules/puppet_proxy_legacy/puppet_cache.rb index 4be77d24d..dc26b4f37 100644 --- a/modules/puppet_proxy/puppet_cache.rb +++ b/modules/puppet_proxy_legacy/puppet_cache.rb @@ -1,23 +1,21 @@ require 'proxy/memory_store' require 'thread' -require 'puppet_proxy/dependency_injection/container' -module Proxy::Puppet - class PuppetCache +module Proxy::PuppetLegacy + class PuppetCache < ClassScannerBase include Proxy::Log - extend Proxy::Puppet::DependencyInjection::Injectors - inject_attr :puppet_class_scanner_impl, :puppet_class_scanner + attr_reader :class_parser - def initialize(classes_store = ::Proxy::MemoryStore.new, timestamps_store = ::Proxy::MemoryStore.new) + def initialize(environments_retriever, class_parser, classes_store = ::Proxy::MemoryStore.new, timestamps_store = ::Proxy::MemoryStore.new) @classes_cache = classes_store @timestamps = timestamps_store + @class_parser = class_parser @mutex = Mutex.new + super(environments_retriever) end - def scan_directory directory, environment - logger.debug("Running scan_directory on #{environment}: #{directory}") - + def scan_directory directory @mutex.synchronize do tmp_classes = ::Proxy::MemoryStore.new tmp_timestamps = ::Proxy::MemoryStore.new @@ -32,7 +30,7 @@ def scan_directory directory, environment else logger.debug("Scanning #{puppetmodule} classes in #{filename}") f = File.open(filename, "r:UTF-8") - tmp_classes[directory, filename] = puppet_class_scanner.scan_manifest f.read, filename + tmp_classes[directory, filename] = class_parser.scan_manifest f.read, filename tmp_timestamps[directory, filename] = File.mtime(filename).to_i end end diff --git a/modules/puppet_proxy/puppet_config.rb b/modules/puppet_proxy_legacy/puppet_config.rb similarity index 75% rename from modules/puppet_proxy/puppet_config.rb rename to modules/puppet_proxy_legacy/puppet_config.rb index 257a3f47a..6d538af11 100644 --- a/modules/puppet_proxy/puppet_config.rb +++ b/modules/puppet_proxy_legacy/puppet_config.rb @@ -1,17 +1,10 @@ require 'augeas' -module Proxy::Puppet - class PuppetConfig - def get - Proxy::Puppet::ConfigReader.new(Proxy::Puppet::Plugin.settings.puppet_conf).get - end - end - +module Proxy::PuppetLegacy class ConfigReader attr_reader :config def initialize(config) - raise "Puppet config at #{config} was not found" unless File.exist?(config) @config = config end diff --git a/modules/puppet_proxy/puppet_config_environments_retriever.rb b/modules/puppet_proxy_legacy/puppet_config_environments_retriever.rb similarity index 82% rename from modules/puppet_proxy/puppet_config_environments_retriever.rb rename to modules/puppet_proxy_legacy/puppet_config_environments_retriever.rb index c29d3c461..6e8ae897c 100644 --- a/modules/puppet_proxy/puppet_config_environments_retriever.rb +++ b/modules/puppet_proxy_legacy/puppet_config_environments_retriever.rb @@ -1,16 +1,24 @@ -require 'puppet_proxy/dependency_injection/container' - -class Proxy::Puppet::PuppetConfigEnvironmentsRetriever +class Proxy::PuppetLegacy::PuppetConfigEnvironmentsRetriever < Proxy::Puppet::EnvironmentsRetrieverBase include ::Proxy::Log - extend Proxy::Puppet::DependencyInjection::Injectors + attr_reader :puppet_configuration, :puppet_config_file_path - inject_attr :puppet_configuration_impl, :puppet_configuration + def initialize(puppet_configuration, puppet_config_file_path) + @puppet_configuration = puppet_configuration + @puppet_config_file_path = puppet_config_file_path + end def conf - puppet_configuration.get + @puppet_configuration.get end + # rubocop:disable Metrics/PerceivedComplexity + # rubocop:disable Metrics/AbcSize + # rubocop:disable Metrics/MethodLength def all + if !conf.has_key?(:main) || !conf.has_key?(:master) + raise Exception, "Puppet configuration at #{@puppet_config_file_path} is missing 'main' and/or 'master' sections." + end + env = { } # query for the environments variable if conf[:main][:environments].nil? @@ -94,6 +102,6 @@ def all end new_env.reject { |k, v| k.nil? || v.nil? } - new_env.map { |environment, path| Proxy::Puppet::Environment.new(:name => environment, :paths => path.split(":")) } + new_env.map { |environment, path| Proxy::Puppet::Environment.new(environment, path.split(":")) } end end diff --git a/modules/puppet_proxy_legacy/puppet_proxy_legacy.rb b/modules/puppet_proxy_legacy/puppet_proxy_legacy.rb new file mode 100644 index 000000000..2d1a60623 --- /dev/null +++ b/modules/puppet_proxy_legacy/puppet_proxy_legacy.rb @@ -0,0 +1,3 @@ +require 'puppet_proxy_common/custom_validators' +require 'puppet_proxy_legacy/plugin_configuration' +require 'puppet_proxy_legacy/puppet_proxy_legacy_plugin' diff --git a/modules/puppet_proxy_legacy/puppet_proxy_legacy_plugin.rb b/modules/puppet_proxy_legacy/puppet_proxy_legacy_plugin.rb new file mode 100644 index 000000000..206edef89 --- /dev/null +++ b/modules/puppet_proxy_legacy/puppet_proxy_legacy_plugin.rb @@ -0,0 +1,16 @@ +module Proxy::PuppetLegacy + class Plugin < Proxy::Provider + default_settings :puppet_ssl_ca => '/var/lib/puppet/ssl/certs/ca.pem', :puppet_conf => '/etc/puppet/puppet.conf', :use_cache => true + + plugin :puppet_proxy_legacy, ::Proxy::VERSION + + load_classes ::Proxy::PuppetLegacy::PluginConfiguration + load_programmable_settings "::Proxy::PuppetLegacy::PluginConfiguration" + load_validators :url => ::Proxy::Puppet::Validators::UrlValidator + load_dependency_injection_wirings "::Proxy::PuppetLegacy::PluginConfiguration" + + validate_readable :puppet_conf + validate :puppet_url, :url => true, :if => lambda {|settings| settings[:environments_retriever] != :config_file} + validate :puppet_ssl_ca, :puppet_ssl_cert, :puppet_ssl_key, :file_readable => true, :if => lambda {|settings| settings[:environments_retriever] != :config_file} + end +end diff --git a/modules/puppet_proxy_mcollective/mcollective_main.rb b/modules/puppet_proxy_mcollective/mcollective_main.rb new file mode 100644 index 000000000..6d074a824 --- /dev/null +++ b/modules/puppet_proxy_mcollective/mcollective_main.rb @@ -0,0 +1,36 @@ +class Proxy::PuppetMCollective::Runner < Proxy::Puppet::Runner + attr_reader :user + + def initialize(mco_user) + @user = mco_user + end + + def run(nodes) + cmd = [] + + sudo_path = which('sudo') + unless sudo_path + logger.error("sudo binary is missing, aborting.") + return false + end + cmd.push(sudo_path) + + # sudo permission needs to be added to ensure + # smart-proxy can execute 'sudo' command + # For Puppet Enterprise this means + # Defaults:foreman-proxy !requiretty + # foreman-proxy ALL=(peadmin) NOPASSWD: /opt/puppet/bin/mco *', + if user + cmd.push("-u", user) + end + + mco_path = which("mco", ["/opt/puppet/bin", "/opt/puppetlabs/bin"]) + unless mco_path + logger.error("mco binary is missing, aborting.") + return false + end + cmd.push(mco_path) + + shell_command(cmd + ["puppet", "runonce", "-I"] + shell_escaped_nodes(nodes)) + end +end diff --git a/modules/puppet_proxy_mcollective/plugin_configuration.rb b/modules/puppet_proxy_mcollective/plugin_configuration.rb new file mode 100644 index 000000000..65ba14797 --- /dev/null +++ b/modules/puppet_proxy_mcollective/plugin_configuration.rb @@ -0,0 +1,14 @@ +module ::Proxy::PuppetMCollective + class PluginConfiguration + def load_classes + require 'puppet_proxy_common/runner' + require 'puppet_proxy_mcollective/mcollective_main' + end + + def load_dependency_injection_wirings(container_instance, settings) + container_instance.dependency :puppet_runner_impl, (lambda do + ::Proxy::PuppetMCollective::Runner.new(settings[:user]) + end) + end + end +end diff --git a/modules/puppet_proxy_mcollective/puppet_proxy_mcollective.rb b/modules/puppet_proxy_mcollective/puppet_proxy_mcollective.rb new file mode 100644 index 000000000..7884eef3e --- /dev/null +++ b/modules/puppet_proxy_mcollective/puppet_proxy_mcollective.rb @@ -0,0 +1,2 @@ +require 'puppet_proxy_mcollective/plugin_configuration' +require 'puppet_proxy_mcollective/puppet_proxy_mcollective_plugin' diff --git a/modules/puppet_proxy_mcollective/puppet_proxy_mcollective_plugin.rb b/modules/puppet_proxy_mcollective/puppet_proxy_mcollective_plugin.rb new file mode 100644 index 000000000..d39d27a3a --- /dev/null +++ b/modules/puppet_proxy_mcollective/puppet_proxy_mcollective_plugin.rb @@ -0,0 +1,8 @@ +module Proxy::PuppetMCollective + class Plugin < Proxy::Provider + plugin :puppet_proxy_mcollective, ::Proxy::VERSION + + load_classes ::Proxy::PuppetMCollective::PluginConfiguration + load_dependency_injection_wirings ::Proxy::PuppetMCollective::PluginConfiguration + end +end diff --git a/modules/puppet_proxy_puppet_api/plugin_configuration.rb b/modules/puppet_proxy_puppet_api/plugin_configuration.rb new file mode 100644 index 000000000..883f8e910 --- /dev/null +++ b/modules/puppet_proxy_puppet_api/plugin_configuration.rb @@ -0,0 +1,30 @@ +module ::Proxy::PuppetApi + class PluginConfiguration + def load_programmable_settings(settings) + settings[:classes_retriever] = :apiv3 + settings[:environments_retriever] = :apiv3 + settings + end + + def load_classes + require 'puppet_proxy_common/custom_validators' + require 'puppet_proxy_common/errors' + require 'puppet_proxy_common/environments_retriever_base' + require 'puppet_proxy_common/environment' + require 'puppet_proxy_common/puppet_class' + require 'puppet_proxy_common/api_request' + require 'puppet_proxy_puppet_api/v3_api_request' + require 'puppet_proxy_puppet_api/v3_environments_retriever' + require 'puppet_proxy_puppet_api/v3_classes_retriever' + end + + def load_dependency_injection_wirings(container_instance, settings) + container_instance.dependency :environment_retriever_impl, + lambda {::Proxy::PuppetApi::V3EnvironmentsRetriever.new(settings[:puppet_url], settings[:puppet_ssl_ca], settings[:puppet_ssl_cert], settings[:puppet_ssl_key])} + + container_instance.dependency :class_retriever_impl, + lambda {::Proxy::PuppetApi::V3ClassesRetriever.new(settings[:puppet_url], settings[:puppet_ssl_ca], settings[:puppet_ssl_cert], settings[:puppet_ssl_key])} + + end + end +end diff --git a/modules/puppet_proxy_puppet_api/puppet_proxy_puppet_api.rb b/modules/puppet_proxy_puppet_api/puppet_proxy_puppet_api.rb new file mode 100644 index 000000000..92b7b743f --- /dev/null +++ b/modules/puppet_proxy_puppet_api/puppet_proxy_puppet_api.rb @@ -0,0 +1,3 @@ +require 'puppet_proxy_common/custom_validators' +require 'puppet_proxy_puppet_api/plugin_configuration' +require 'puppet_proxy_puppet_api/puppet_proxy_puppet_api_plugin' diff --git a/modules/puppet_proxy_puppet_api/puppet_proxy_puppet_api_plugin.rb b/modules/puppet_proxy_puppet_api/puppet_proxy_puppet_api_plugin.rb new file mode 100644 index 000000000..2a174ba38 --- /dev/null +++ b/modules/puppet_proxy_puppet_api/puppet_proxy_puppet_api_plugin.rb @@ -0,0 +1,15 @@ +module Proxy::PuppetApi + class Plugin < Proxy::Provider + default_settings :puppet_ssl_ca => '/var/lib/puppet/ssl/certs/ca.pem' + + plugin :puppet_proxy_puppet_api, ::Proxy::VERSION + + load_validators :url => ::Proxy::Puppet::Validators::UrlValidator + load_programmable_settings ::Proxy::PuppetApi::PluginConfiguration + load_classes ::Proxy::PuppetApi::PluginConfiguration + load_dependency_injection_wirings ::Proxy::PuppetApi::PluginConfiguration + + validate :puppet_url, :url => true + validate_readable :puppet_ssl_ca, :puppet_ssl_cert, :puppet_ssl_key + end +end diff --git a/modules/puppet_proxy_puppet_api/v3_api_request.rb b/modules/puppet_proxy_puppet_api/v3_api_request.rb new file mode 100644 index 000000000..0cb602044 --- /dev/null +++ b/modules/puppet_proxy_puppet_api/v3_api_request.rb @@ -0,0 +1,16 @@ +module Proxy::PuppetApi + class EnvironmentsApiv3 < ::Proxy::Puppet::ApiRequest + def find_environments + handle_response(send_request('puppet/v3/environments'), "Failed to query Puppet find environments v3 API") + end + end + + class ResourceTypeApiv3 < ::Proxy::Puppet::ApiRequest + # kind (optional) can be 'class', 'node', or 'defined_type' + def list_classes(environment, kind = nil) + kind_filter = kind.nil? || kind.empty? ? "" : "kind=#{kind}&" + response = send_request("puppet/v3/resource_types/*?#{kind_filter}&environment=#{environment}") + response.code == '404' ? [] : handle_response(response) # resource api responds with a 404 if filter returns no results + end + end +end diff --git a/modules/puppet_proxy_puppet_api/v3_classes_retriever.rb b/modules/puppet_proxy_puppet_api/v3_classes_retriever.rb new file mode 100644 index 000000000..a35dd09d2 --- /dev/null +++ b/modules/puppet_proxy_puppet_api/v3_classes_retriever.rb @@ -0,0 +1,28 @@ +class Proxy::PuppetApi::V3ClassesRetriever + attr_reader :puppet_url, :ssl_ca, :ssl_cert, :ssl_key + + def initialize(puppet_url, puppet_ssl_ca, puppet_ssl_cert, puppet_ssl_key, api = nil) + @puppet_url = puppet_url + @ssl_ca = puppet_ssl_ca + @ssl_cert = puppet_ssl_cert + @ssl_key = puppet_ssl_key + @api = api || Proxy::PuppetApi::ResourceTypeApiv3.new(puppet_url, ssl_ca, ssl_cert, ssl_key) + end + + def convert_to_proxy_var_parameter_representation(puppet_resource_type_response) + puppet_resource_type_response.inject([]) do |to_return, current_resource| + params = current_resource['parameters'].inject({}) do |all, current| + all[current[0]] = (current[1].is_a?(String) && current[1].start_with?('$')) ? "${#{current[1].slice(1..-1)}}" : current[1] + all + end + to_return << ::Proxy::Puppet::PuppetClass.new(current_resource['name'], params) + end + end + + def classes_in_environment(environment) + convert_to_proxy_var_parameter_representation(@api.list_classes(environment, "class")) + rescue ::Proxy::Error::HttpError => e + raise Proxy::Puppet::EnvironmentNotFound.new(e.response_body) if e.status_code.to_s == '400' && e.response_body.include?("Could not find environment") + raise e + end +end diff --git a/modules/puppet_proxy_puppet_api/v3_environments_retriever.rb b/modules/puppet_proxy_puppet_api/v3_environments_retriever.rb new file mode 100644 index 000000000..610a08d0d --- /dev/null +++ b/modules/puppet_proxy_puppet_api/v3_environments_retriever.rb @@ -0,0 +1,8 @@ +module Proxy::PuppetApi + class V3EnvironmentsRetriever < Proxy::Puppet::EnvironmentsRetrieverBase + def initialize(puppet_url, puppet_ssl_ca, puppet_ssl_cert, puppet_ssl_key, api = nil) + super(puppet_url, puppet_ssl_ca, puppet_ssl_cert, puppet_ssl_key) + @api = api || Proxy::PuppetApi::EnvironmentsApiv3.new(puppet_url, ssl_ca, ssl_cert, ssl_key) + end + end +end diff --git a/modules/puppet_proxy_puppetrun/plugin_configuration.rb b/modules/puppet_proxy_puppetrun/plugin_configuration.rb new file mode 100644 index 000000000..fd61a4d2f --- /dev/null +++ b/modules/puppet_proxy_puppetrun/plugin_configuration.rb @@ -0,0 +1,14 @@ +module ::Proxy::PuppetRun + class PluginConfiguration + def load_classes + require 'puppet_proxy_common/runner' + require 'puppet_proxy_puppetrun/puppetrun_main' + end + + def load_dependency_injection_wirings(container_instance, settings) + container_instance.dependency :puppet_runner_impl, (lambda do + ::Proxy::PuppetRun::Runner.new(settings[:user]) + end) + end + end +end diff --git a/modules/puppet_proxy_puppetrun/puppet_proxy_puppetrun.rb b/modules/puppet_proxy_puppetrun/puppet_proxy_puppetrun.rb new file mode 100644 index 000000000..69445d5e5 --- /dev/null +++ b/modules/puppet_proxy_puppetrun/puppet_proxy_puppetrun.rb @@ -0,0 +1,2 @@ +require 'puppet_proxy_puppetrun/plugin_configuration' +require 'puppet_proxy_puppetrun/puppet_proxy_puppetrun_plugin' diff --git a/modules/puppet_proxy_puppetrun/puppet_proxy_puppetrun_plugin.rb b/modules/puppet_proxy_puppetrun/puppet_proxy_puppetrun_plugin.rb new file mode 100644 index 000000000..fd2cceab4 --- /dev/null +++ b/modules/puppet_proxy_puppetrun/puppet_proxy_puppetrun_plugin.rb @@ -0,0 +1,7 @@ +module Proxy::PuppetRun + class Plugin < Proxy::Provider + plugin :puppet_proxy_puppetrun, ::Proxy::VERSION + load_classes ::Proxy::PuppetRun::PluginConfiguration + load_dependency_injection_wirings ::Proxy::PuppetRun::PluginConfiguration + end +end diff --git a/modules/puppet_proxy_puppetrun/puppetrun_main.rb b/modules/puppet_proxy_puppetrun/puppetrun_main.rb new file mode 100644 index 000000000..cd3733d46 --- /dev/null +++ b/modules/puppet_proxy_puppetrun/puppetrun_main.rb @@ -0,0 +1,38 @@ +module Proxy::PuppetRun + class Runner < ::Proxy::Puppet::Runner + attr_reader :user + + def initialize(puppetrun_user) + @user = puppetrun_user + end + + def run(nodes) + cmd = [] + + sudo_path = which("sudo") + unless sudo_path + logger.error("sudo binary is missing, aborting.") + return false + end + cmd.push(sudo_path) + + if user + cmd.push("-u", user) + end + + default_path = "/opt/puppet/bin" + # Search in /opt/ for puppet enterprise users + # search for puppet for users using puppet 2.6+ + puppetrun_path = which("puppetrun", default_path) || which("puppet", default_path) + unless puppetrun_path + logger.error("puppetrun binary was not found - aborting.") + return false + end + cmd.push(puppetrun_path) + + # Append kick to the puppet command if we are not using the old puppetca command + cmd.push("kick") if cmd.any? { |part| part.end_with?('puppet') } + shell_command(cmd + (shell_escaped_nodes(nodes).map {|n| ["--host", n] }).flatten) + end + end +end diff --git a/modules/puppet_proxy_salt/plugin_configuration.rb b/modules/puppet_proxy_salt/plugin_configuration.rb new file mode 100644 index 000000000..3d040b3f4 --- /dev/null +++ b/modules/puppet_proxy_salt/plugin_configuration.rb @@ -0,0 +1,14 @@ +module ::Proxy::PuppetSalt + class PluginConfiguration + def load_classes + require 'puppet_proxy_common/runner' + require 'puppet_proxy_salt/salt_main' + end + + def load_dependency_injection_wirings(container_instance, settings) + container_instance.dependency :puppet_runner_impl, (lambda do + ::Proxy::PuppetSalt::Runner.new(settings[:command]) + end) + end + end +end diff --git a/modules/puppet_proxy_salt/puppet_proxy_salt.rb b/modules/puppet_proxy_salt/puppet_proxy_salt.rb new file mode 100644 index 000000000..5485843ee --- /dev/null +++ b/modules/puppet_proxy_salt/puppet_proxy_salt.rb @@ -0,0 +1,2 @@ +require 'puppet_proxy_salt/plugin_configuration' +require 'puppet_proxy_salt/puppet_proxy_salt_plugin' diff --git a/modules/puppet_proxy_salt/puppet_proxy_salt_plugin.rb b/modules/puppet_proxy_salt/puppet_proxy_salt_plugin.rb new file mode 100644 index 000000000..4859cf01a --- /dev/null +++ b/modules/puppet_proxy_salt/puppet_proxy_salt_plugin.rb @@ -0,0 +1,10 @@ +module Proxy::PuppetSalt + class Plugin < Proxy::Provider + plugin :puppet_proxy_salt, ::Proxy::VERSION + + default_settings :command => "puppet.run" + + load_classes ::Proxy::PuppetSalt::PluginConfiguration + load_dependency_injection_wirings ::Proxy::PuppetSalt::PluginConfiguration + end +end diff --git a/modules/puppet_proxy_salt/salt_main.rb b/modules/puppet_proxy_salt/salt_main.rb new file mode 100644 index 000000000..bae098582 --- /dev/null +++ b/modules/puppet_proxy_salt/salt_main.rb @@ -0,0 +1,31 @@ +class Proxy::PuppetSalt::Runner < Proxy::Puppet::Runner + attr_reader :command + + def initialize(puppetrun_command) + @command = puppetrun_command + end + + def run(nodes) + cmd = [] + + sudo_path = which('sudo') + unless sudo_path + logger.error('sudo binary is missing, aborting.') + return false + end + cmd.push(sudo_path) + + salt_path = which('salt') + unless sudo_path + logger.error('salt binary is missing, aborting.') + return false + end + cmd.push(salt_path) + + cmd.push('-L') + cmd.push(shell_escaped_nodes(nodes).join(',')) + cmd.push(command) + + shell_command(cmd) + end +end diff --git a/modules/puppet_proxy_ssh/plugin_configuration.rb b/modules/puppet_proxy_ssh/plugin_configuration.rb new file mode 100644 index 000000000..865c96cfb --- /dev/null +++ b/modules/puppet_proxy_ssh/plugin_configuration.rb @@ -0,0 +1,14 @@ +module ::Proxy::PuppetSsh + class PluginConfiguration + def load_classes + require 'puppet_proxy_common/runner' + require 'puppet_proxy_ssh/puppet_proxy_ssh_main' + end + + def load_dependency_injection_wirings(container_instance, settings) + container_instance.dependency :puppet_runner_impl, (lambda do + ::Proxy::PuppetSsh::Runner.new(settings[:command], settings[:user], settings[:keyfile], settings[:use_sudo], settings[:wait]) + end) + end + end +end diff --git a/modules/puppet_proxy_ssh/puppet_proxy_ssh.rb b/modules/puppet_proxy_ssh/puppet_proxy_ssh.rb new file mode 100644 index 000000000..4a75ad1b0 --- /dev/null +++ b/modules/puppet_proxy_ssh/puppet_proxy_ssh.rb @@ -0,0 +1,2 @@ +require 'puppet_proxy_ssh/plugin_configuration' +require 'puppet_proxy_ssh/puppet_proxy_ssh_plugin' diff --git a/modules/puppet_proxy_ssh/puppet_proxy_ssh_main.rb b/modules/puppet_proxy_ssh/puppet_proxy_ssh_main.rb new file mode 100644 index 000000000..05d115c6e --- /dev/null +++ b/modules/puppet_proxy_ssh/puppet_proxy_ssh_main.rb @@ -0,0 +1,46 @@ +class Proxy::PuppetSsh::Runner < Proxy::Puppet::Runner + attr_reader :command, :user, :keyfile_path, :use_sudo, :wait_for_command_to_finish + + def initialize(puppetssh_command, puppetssh_user, ssh_keyfile, use_sudo, wait_for_command_to_finish) + @command = puppetssh_command + @user = puppetssh_user + @keyfile_path = ssh_keyfile.to_s + @use_sudo = use_sudo + @wait_for_command_to_finish = wait_for_command_to_finish + end + + def run(nodes) + cmd = [] + + if use_sudo + sudo_path = which('sudo') + unless sudo_path + logger.error('sudo binary is missing, aborting.') + return false + end + cmd.push(sudo_path) + end + + ssh_path = which('ssh') + unless ssh_path + logger.error('ssh binary is missing, aborting.') + return false + end + cmd.push(ssh_path) + + cmd.push("-l", user) if user + + if keyfile_path + if File.exist?(keyfile_path) + cmd.push("-i", keyfile_path) + else + logger.warn("Unable to access SSH private key:#{keyfile_path}, ignoring...") + end + end + + ssh_command = RUBY_VERSION <= '1.8.7' ? escape_for_shell(command) : command + nodes.each do |node| + shell_command(cmd + [escape_for_shell(node), ssh_command], wait_for_command_to_finish) + end + end +end diff --git a/modules/puppet_proxy_ssh/puppet_proxy_ssh_plugin.rb b/modules/puppet_proxy_ssh/puppet_proxy_ssh_plugin.rb new file mode 100644 index 000000000..e8169451e --- /dev/null +++ b/modules/puppet_proxy_ssh/puppet_proxy_ssh_plugin.rb @@ -0,0 +1,11 @@ +module Proxy::PuppetSsh + class Plugin < Proxy::Provider + plugin :puppet_proxy_ssh, ::Proxy::VERSION + + default_settings :command => "puppet agent --onetime --no-usecacheonfailure", :use_sudo => false, + :wait => false + + load_classes ::Proxy::PuppetSsh::PluginConfiguration + load_dependency_injection_wirings ::Proxy::PuppetSsh::PluginConfiguration + end +end diff --git a/modules/puppetca/puppetca_main.rb b/modules/puppetca/puppetca_main.rb index 32983acda..0a93dabb5 100644 --- a/modules/puppetca/puppetca_main.rb +++ b/modules/puppetca/puppetca_main.rb @@ -1,5 +1,4 @@ require 'openssl' -require 'puppet' require 'set' module Proxy::PuppetCa @@ -104,13 +103,7 @@ def find_puppetca end default_path = ["/opt/puppet/bin", "/opt/puppet/sbin", "/opt/puppetlabs/bin"] - - # puppetca is the old method of using puppet cert which is new in puppet 2.6 - if Puppet::PUPPETVERSION.to_i < 3 - @puppetca = which("puppetca", default_path) || which("puppet", default_path) - else - @puppetca = which("puppet", default_path) - end + @puppetca = which("puppetca", default_path) || which("puppet", default_path) unless File.exist?(@puppetca.to_s) logger.warn "unable to find puppetca binary" diff --git a/modules/puppetca/puppetca_plugin.rb b/modules/puppetca/puppetca_plugin.rb index 1b3d0d00b..d82da3de4 100644 --- a/modules/puppetca/puppetca_plugin.rb +++ b/modules/puppetca/puppetca_plugin.rb @@ -4,6 +4,7 @@ class Plugin < ::Proxy::Plugin https_rackup_path File.expand_path("http_config.ru", File.expand_path("../", __FILE__)) default_settings :ssldir => '/var/lib/puppet/ssl', :puppetdir => '/etc/puppet' + plugin :puppetca, ::Proxy::VERSION end -end \ No newline at end of file +end diff --git a/test/migrations/puppet_migration_test.rb b/test/migrations/puppet_migration_test.rb new file mode 100644 index 000000000..8d3948b38 --- /dev/null +++ b/test/migrations/puppet_migration_test.rb @@ -0,0 +1,97 @@ +require 'test_helper' + +require File.join(File.dirname(__FILE__),'../../extra/migrate_settings') +::Proxy::Migration.inject_migrations_instance(::Proxy::Migrations.new("dummy")) +require File.join(File.dirname(__FILE__),'../../extra/migrations/20160413000000_migrate_puppet_settings.rb') + +class ProxyPuppetMigrationTest < Test::Unit::TestCase + def setup + @migration = MigratePuppetSettings.new("/tmp") + end + + def test_old_to_new_provider_name_conversion + assert_equal 'puppet_proxy_puppetrun', @migration.old_provider_name_to_new('puppetrun') + assert_equal 'puppet_proxy_mcollective', @migration.old_provider_name_to_new('mcollective') + assert_equal 'puppet_proxy_salt', @migration.old_provider_name_to_new('salt') + assert_equal 'puppet_proxy_customrun', @migration.old_provider_name_to_new('customrun') + assert_equal 'puppet_proxy_ssh', @migration.old_provider_name_to_new('puppetssh') + assert_equal 'unknown', @migration.old_provider_name_to_new('unknown') + end + + def test_puppet_parameter_remapping + assert_equal [:puppet, :enabled, true], @migration.remap_parameter(:enabled, true).flatten + assert_equal [:puppet, :use_provider, 'puppet_proxy_salt'], @migration.remap_parameter(:puppet_provider, 'salt').flatten + end + + def test_puppet_legacy_parameter_mapping + assert_equal [:puppet_proxy_legacy, :puppet_conf, 'some/path'], @migration.remap_parameter(:puppet_conf, 'some/path').first + assert_equal [:puppet_proxy_legacy, :use_cache, true], @migration.remap_parameter(:use_cache, true).first + assert_equal [:puppet_proxy_legacy, :use_environment_api, true], @migration.remap_parameter(:puppet_use_environment_api, true).first + assert_equal [:puppet_proxy_legacy, :puppet_url, 'http://localhost'], @migration.remap_parameter(:puppet_url, "http://localhost").first + assert_equal [:puppet_proxy_legacy, :puppet_ssl_ca, 'some/path'], @migration.remap_parameter(:puppet_ssl_ca, "some/path").first + assert_equal [:puppet_proxy_legacy, :puppet_ssl_cert, 'some/path'], @migration.remap_parameter(:puppet_ssl_cert, "some/path").first + assert_equal [:puppet_proxy_legacy, :puppet_ssl_key, 'some/path'], @migration.remap_parameter(:puppet_ssl_key, "some/path").first + end + + def test_puppet_api_parameter_mapping + assert_equal [:puppet_proxy_puppet_api, :puppet_url, 'http://localhost'], @migration.remap_parameter(:puppet_url, "http://localhost").last + assert_equal [:puppet_proxy_puppet_api, :puppet_ssl_ca, 'some/path'], @migration.remap_parameter(:puppet_ssl_ca, "some/path").last + assert_equal [:puppet_proxy_puppet_api, :puppet_ssl_cert, 'some/path'], @migration.remap_parameter(:puppet_ssl_cert, "some/path").last + assert_equal [:puppet_proxy_puppet_api, :puppet_ssl_key, 'some/path'], @migration.remap_parameter(:puppet_ssl_key, "some/path").last + end + + def test_puppet_ssh_parameter_mapping + assert_equal [:puppet_proxy_ssh, :use_sudo, true], @migration.remap_parameter(:puppetssh_sudo, true).flatten + assert_equal [:puppet_proxy_ssh, :command, "command"], @migration.remap_parameter(:puppetssh_command, "command").flatten + assert_equal [:puppet_proxy_ssh, :wait, true], @migration.remap_parameter(:puppetssh_wait, true).flatten + assert_equal [:puppet_proxy_ssh, :user, "user"], @migration.remap_parameter(:puppetssh_user, "user").flatten + assert_equal [:puppet_proxy_ssh, :keyfile, "keyfile"], @migration.remap_parameter(:puppetssh_keyfile, "keyfile").flatten + end + + def test_puppet_mcollective_parameter_mapping + assert_equal [:puppet_proxy_mcollective, :puppet_user, "user"], @migration.remap_parameter(:puppet_user, "user").last + assert_equal [:puppet_proxy_mcollective, :user, "user"], @migration.remap_parameter(:mcollective_user, "user").first + end + + def test_puppetrun_parameter_mapping + assert_equal [:puppet_proxy_puppetrun, :puppet_user, "user"], @migration.remap_parameter(:puppet_user, "user").first + end + + def test_puppet_salt_parameter_mapping + assert_equal [:puppet_proxy_salt, :command, "command"], @migration.remap_parameter(:salt_puppetrun_cmd, "command").first + end + + def test_puppet_customrun_parameter_mapping + assert_equal [:puppet_proxy_customrun, :command, "command"], @migration.remap_parameter(:customrun_cmd, "command").first + assert_equal [:puppet_proxy_customrun, :command_arguments, "arg1 arg2"], @migration.remap_parameter(:customrun_args, "arg1 arg2").first + end + + def test_remapping_of_unknown_parameter + assert_equal [:unknown, :a_parameter, 'avalue'], @migration.remap_parameter(:a_parameter, 'avalue').first + end + + def test_migrate_puppet_user_for_puppetrun + assert_equal "a_user", @migration.migrate_puppet_configuration(:puppet_user => "a_user")[:puppet_proxy_puppetrun][:user] + assert_nil @migration.migrate_puppet_configuration(:puppet_user => "a_user")[:puppet_proxy_puppetrun][:puppet_user] + end + + def test_migrate_puppet_user_for_mcollective + assert_equal "a_user", @migration.migrate_puppet_configuration(:puppet_user => "a_user")[:puppet_proxy_mcollective][:user] + assert_nil @migration.migrate_puppet_configuration(:puppet_user => "a_user")[:puppet_proxy_mcollective][:puppet_user] + end + + def test_migrate_puppet_configuration + @migration.stubs(:puppet_version).returns("4.3.1") + assert_equal({:puppet => {:enabled => true, :puppet_version => "4.3.1"}, + :puppet_proxy_legacy => {:puppet_url => "http://localhost"}, + :puppet_proxy_puppet_api => {:puppet_url => "http://localhost"}}, + @migration.migrate_puppet_configuration(:enabled => true, :puppet_url => "http://localhost")) + end + + def test_migration_adds_puppet_version + @migration.stubs(:puppet_version).returns("4.3.1") + migrated = @migration.migrate_puppet_configuration({}) + assert_equal "4.3.1", migrated[:puppet][:puppet_version] + end +end + diff --git a/test/plugins/file_readable_validator_test.rb b/test/plugins/file_readable_validator_test.rb deleted file mode 100644 index 3a9915934..000000000 --- a/test/plugins/file_readable_validator_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'test_helper' -require 'ostruct' - -class FileReadableValidatorTest < Test::Unit::TestCase - class FileReadableValidatorTestPlugin < ::Proxy::Plugin - default_settings :a_setting => 'some_file' - end - - def test_file_readable_returns_true_for_optional_undefined_settings - FileReadableValidatorTestPlugin.load_test_settings({}) - assert ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'optional_setting', nil, nil).validate!({}) - end - - def test_file_readable_for_optional_defined_setting - File.expects(:readable?).with("other_file").returns(true) - assert ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'optional_setting', nil, nil).validate!(:optional_setting => 'other_file') - end - - def test_file_readable_for_required_setting - File.expects(:readable?).with("some_file").returns(true) - assert ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => 'some_file') - end - - def test_file_readable_raises_exception_if_file_is_unreadable - File.expects(:readable?).with("some_file").returns(false) - assert_raises ::Proxy::Error::ConfigurationError do - ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => 'some_file') - end - end -end diff --git a/test/plugins/module_loader_test.rb b/test/plugins/module_loader_test.rb index ac2714b62..deabc29a3 100644 --- a/test/plugins/module_loader_test.rb +++ b/test/plugins/module_loader_test.rb @@ -13,7 +13,7 @@ def test_merge_settings end def test_merge_settings_should_fail_when_duplicate_settings_detected - assert_raises(RuntimeError) { @loader.merge_settings({:duplicate => "first"}, :duplicate => "second")} + assert_raises(Exception) { @loader.merge_settings({:duplicate => "first"}, :duplicate => "second")} end def test_merge_settings_should_ignore_enabled @@ -73,26 +73,27 @@ def test_presence_validators_called_on_each_of_default_settings class TestValidator < ::Proxy::PluginValidators::Base def validate!(settings) - raise "Predicate evaluated to false!" unless evaluate_predicate(settings) true end end class TestPluginWithCustomValidators < ::Proxy::Plugin load_validators :testing => TestValidator - validate :setting, :testing => {:arg1 => "arg1", :arg2 => "arg2"} + validate :setting, :testing => {:arg1 => "arg1", :arg2 => "arg2"}, :if => lambda {|settings| settings[:evaluate]} end def test_validate_runtime_config_executes_custom_validators loader = ::Proxy::DefaultModuleLoader.new(TestPluginWithCustomValidators, nil) - results = loader.validate_settings(TestPluginWithCustomValidators, :setting => "value") - assert_equal([{:class => TestValidator, :setting => :setting, :args => {:arg1 => "arg1", :arg2 => "arg2"}, :predicate => nil}], results) - end + results = loader.validate_settings(TestPluginWithCustomValidators, :setting => "value", :evaluate => true) + predicate = TestPluginWithCustomValidators.validations.first[:predicate] + assert_equal([{:class => TestValidator, :setting => :setting, :args => {:arg1 => "arg1", :arg2 => "arg2"}, :predicate => predicate}], results) + end + class AnotherTestPluginWithCustomValidators < ::Proxy::Plugin validate :setting, :non_existent => true end def test_validate_runtime_config_raises_exception_on_unknown_validator loader = ::Proxy::DefaultModuleLoader.new(AnotherTestPluginWithCustomValidators, nil) - assert_raises(RuntimeError) { loader.validate_settings(AnotherTestPluginWithCustomValidators, :setting => "value")} + assert_raises(Exception) { loader.validate_settings(AnotherTestPluginWithCustomValidators, :setting => "value")} end class TestDIWirings diff --git a/test/plugins/presence_validator_test.rb b/test/plugins/presence_validator_test.rb deleted file mode 100644 index f6de08452..000000000 --- a/test/plugins/presence_validator_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'test_helper' - -class PresenceValidatorTest < Test::Unit::TestCase - class PresenceValidatorTestPlugin < ::Proxy::Plugin - default_settings :a_setting => 'some_file' - end - - def test_required_parameter_with_a_value_passes_validation - assert ::Proxy::PluginValidators::Presence.new(PresenceValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => 'some_file') - end - - def test_required_parameter_without_a_value_fails_validation - assert_raises ::Proxy::Error::ConfigurationError do - ::Proxy::PluginValidators::Presence.new(PresenceValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => nil) - end - end - - def test_optional_parameter_without_a_value_fails_validation - assert_raises ::Proxy::Error::ConfigurationError do - ::Proxy::PluginValidators::Presence.new(PresenceValidatorTestPlugin, 'optional_setting', nil, nil).validate!(:optional_setting => nil) - end - end -end diff --git a/test/plugins/validator_test.rb b/test/plugins/validator_test.rb new file mode 100644 index 000000000..9e2fb5c26 --- /dev/null +++ b/test/plugins/validator_test.rb @@ -0,0 +1,87 @@ +require 'test_helper' + +class BaseValidatorTest < Test::Unit::TestCase + class TestValidator < ::Proxy::PluginValidators::Base + attr_reader :validate_called + + def validate!(settings) + @validate_called = true + end + end + + class TestPlugin < ::Proxy::Plugin + default_settings :setting_a => 'a_value' + end + + def test_required_setting_is_true_for_settings_with_default_values + validator = TestValidator.new(TestPlugin, 'setting_a', nil, nil) + assert validator.required_setting? + end + + def test_required_setting_is_false_for_settings_without_default_values + validator = TestValidator.new(TestPlugin, 'setting_b', nil, nil) + assert !validator.required_setting? + end + + def test_validate_is_called_if_predicate_evaluates_to_true + validator = TestValidator.new(TestPlugin, 'setting_a', nil, lambda {|settings| settings[:should_validate] == true}) + validator.evaluate_predicate_and_validate!(:should_validate => true) + assert validator.validate_called + end + + def test_validate_is_not_called_if_predicate_evaluates_to_false + validator = TestValidator.new(TestPlugin, 'setting_a', nil, lambda {|settings| settings[:should_validate] == true}) + validator.evaluate_predicate_and_validate!(:should_validate => false) + assert !validator.validate_called + end +end + +class FileReadableValidatorTest < Test::Unit::TestCase + class FileReadableValidatorTestPlugin < ::Proxy::Plugin + default_settings :a_setting => 'some_file' + end + + def test_file_readable_returns_true_for_optional_undefined_settings + FileReadableValidatorTestPlugin.load_test_settings({}) + assert ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'optional_setting', nil, nil).validate!({}) + end + + def test_file_readable_for_optional_defined_setting + File.expects(:readable?).with("other_file").returns(true) + assert ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'optional_setting', nil, nil).validate!(:optional_setting => 'other_file') + end + + def test_file_readable_for_required_setting + File.expects(:readable?).with("some_file").returns(true) + assert ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => 'some_file') + end + + def test_file_readable_raises_exception_if_file_is_unreadable + File.expects(:readable?).with("some_file").returns(false) + assert_raises ::Proxy::Error::ConfigurationError do + ::Proxy::PluginValidators::FileReadable.new(FileReadableValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => 'some_file') + end + end +end + +class PresenceValidatorTest < Test::Unit::TestCase + class PresenceValidatorTestPlugin < ::Proxy::Plugin + default_settings :a_setting => 'some_file' + end + + def test_required_parameter_with_a_value_passes_validation + assert ::Proxy::PluginValidators::Presence.new(PresenceValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => 'some_file') + end + + def test_required_parameter_without_a_value_fails_validation + assert_raises ::Proxy::Error::ConfigurationError do + ::Proxy::PluginValidators::Presence.new(PresenceValidatorTestPlugin, 'a_setting', nil, nil).validate!(:a_setting => nil) + end + end + + def test_optional_parameter_without_a_value_fails_validation + assert_raises ::Proxy::Error::ConfigurationError do + ::Proxy::PluginValidators::Presence.new(PresenceValidatorTestPlugin, 'optional_setting', nil, nil).validate!(:optional_setting => nil) + end + end +end diff --git a/test/puppet/api_request_test.rb b/test/puppet/api_request_test.rb index f6f3e944e..074c5ed80 100644 --- a/test/puppet/api_request_test.rb +++ b/test/puppet/api_request_test.rb @@ -1,38 +1,63 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/api_request' +require 'puppet_proxy_common/api_request' +require 'puppet_proxy_legacy/environments_api_request' +require 'puppet_proxy_puppet_api/v3_api_request' require 'webmock/test_unit' class PuppetApiRequestTest < Test::Unit::TestCase - def setup - Puppet.expects(:[]).with(:certname).returns('puppet.example.com') - Facter.stubs(:value).with(:fqdn).returns('puppet.example.com') - end - def fixtures File.expand_path(File.join(File.dirname(__FILE__), '.', 'fixtures', 'authentication')) end - def test_get_environments - Proxy::Puppet::Plugin::settings.stubs(:puppet_url).returns('http://localhost:8140') - stub_request(:get, 'http://localhost:8140/v2.0/environments').to_return(:body => '{"environments":{}}') - result = Proxy::Puppet::EnvironmentsApi.new.find_environments - assert_equal({"environments" => {}}, result) - end - def test_ssl_config - Proxy::Puppet::Plugin::settings.expects(:puppet_ssl_ca).at_least_once.returns(File.join(fixtures, 'puppet_ca.pem')) - Proxy::Puppet::Plugin::settings.expects(:puppet_ssl_cert).at_least_once.returns(File.join(fixtures, 'foreman.example.com.cert')) - Proxy::Puppet::Plugin::settings.expects(:puppet_ssl_key).at_least_once.returns(File.join(fixtures, 'foreman.example.com.key')) stub_request(:get, 'https://puppet.example.com:8140/v2.0/environments').to_return(:body => '{}') - Proxy::Puppet::EnvironmentsApi.new.find_environments + Proxy::PuppetLegacy::EnvironmentsApi.new( + 'https://puppet.example.com:8140', + File.join(fixtures, 'puppet_ca.pem'), + File.join(fixtures, 'foreman.example.com.cert'), + File.join(fixtures, 'foreman.example.com.key')).find_environments end def test_api_error - Proxy::Puppet::Plugin::settings.stubs(:puppet_url).returns('http://puppet.example.com:8140') stub_request(:get, 'http://puppet.example.com:8140/v2.0/environments').to_return(:status => 403, :body => 'Not allowed') - assert_raise Proxy::Puppet::ApiError do - Proxy::Puppet::EnvironmentsApi.new.find_environments + assert_raise ::Proxy::Error::HttpError do + api = Proxy::PuppetLegacy::EnvironmentsApi.new('http://puppet.example.com:8140', nil, nil, nil) + api.handle_response(api.send_request('v2.0/environments'), "an error messsage") end end + + def test_parses_json_response + string_json = '[{"stdlib": {"module": null,"name": "stdlib","params": {}}}]' + stub_request(:get, 'http://localhost:8140/puppet/v3/resource_types/*?environment=testing').to_return(:body => string_json) + + api = Proxy::PuppetLegacy::EnvironmentsApi.new('http://localhost:8140', nil, nil, nil) + response = api.handle_response(api.send_request('puppet/v3/resource_types/*?environment=testing'), '') + + assert_equal(JSON.load(string_json), response) + end + + def test_get_environments_apiv2 + stub_request(:get, 'http://localhost:8140/v2.0/environments').to_return(:body => '{"environments":{}}') + result = Proxy::PuppetLegacy::EnvironmentsApi.new('http://localhost:8140', nil, nil, nil).find_environments + assert_equal({"environments" => {}}, result) + end + + def test_get_environments_apiv3 + stub_request(:get, 'http://localhost:8140/puppet/v3/environments').to_return(:body => '{"environments":{}}') + result = Proxy::PuppetApi::EnvironmentsApiv3.new('http://localhost:8140', nil, nil, nil).find_environments + assert_equal({"environments" => {}}, result) + end + + def test_list_classes_apiv3 + return_json = '[{"stdlib": {}}]' + stub_request(:get, 'http://localhost:8140/puppet/v3/resource_types/*?kind=class&environment=testing').to_return(:body => return_json) + result = Proxy::PuppetApi::ResourceTypeApiv3.new('http://localhost:8140', nil, nil, nil).list_classes('testing', 'class') + assert_equal([{'stdlib' => {}}], result) + end + + def test_list_classes_apiv3_returns_an_empty_list_if_no_classes_were_found + stub_request(:get, 'http://localhost:8140/puppet/v3/resource_types/*?kind=class&environment=testing').to_return(:status => 404, :body => "Could not find instances in resource_type with '*'") + result = Proxy::PuppetApi::ResourceTypeApiv3.new('http://localhost:8140', nil, nil, nil).list_classes('testing', 'class') + assert_equal([], result) + end end diff --git a/test/puppet/puppet_cache_test.rb b/test/puppet/caching_classes_retriever_test.rb similarity index 72% rename from test/puppet/puppet_cache_test.rb rename to test/puppet/caching_classes_retriever_test.rb index 3188dcf91..7bc171816 100644 --- a/test/puppet/puppet_cache_test.rb +++ b/test/puppet/caching_classes_retriever_test.rb @@ -1,18 +1,21 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/initializer' -require 'puppet_proxy/puppet_class' -require 'puppet_proxy/puppet_cache' +require 'puppet' +require 'puppet_proxy_legacy/initializer' +require 'puppet_proxy_common/puppet_class' +require 'puppet_proxy_common/environment' +require 'puppet_proxy_legacy/class_scanner_base' +require 'puppet_proxy_legacy/puppet_cache' +require 'puppet_proxy_legacy/class_scanner' +require 'puppet_proxy_legacy/class_scanner_eparser' require 'tmpdir' module PuppetCacheTestSuite def setup - Proxy::Puppet::Plugin.load_test_settings(:puppet_conf => module_path('puppet.conf')) - Proxy::Puppet::Initializer.new.reset_puppet + @initializer = Proxy::PuppetLegacy::Initializer.new(module_path('puppet.conf')) end def test_should_refresh_classes_cache_when_dir_is_not_in_cache - @scanner.scan_directory(module_path('modules_include'), 'example_env') + @scanner.scan_directory(module_path('modules_include')) assert_equal Proxy::Puppet::PuppetClass.new('testinclude'), @classes_cache[module_path('modules_include'), module_path('modules_include/testinclude/manifests/init.pp')].first @@ -22,7 +25,7 @@ def test_should_refresh_classes_cache_when_dir_is_not_in_cache end def test_should_refresh_timestamps_when_dir_is_not_in_cache - @scanner.scan_directory(module_path('modules_include'), 'example_env') + @scanner.scan_directory(module_path('modules_include')) assert @timestamps[module_path('modules_include'), module_path('modules_include/testinclude/manifests/sub/foo.pp')] assert @timestamps[module_path('modules_include'), module_path('modules_include/testinclude/manifests/init.pp')] @@ -30,9 +33,8 @@ def test_should_refresh_timestamps_when_dir_is_not_in_cache end def test_scan_directory_response - cache = @scanner.scan_directory(module_path('modules_include'), 'example_env') + cache = @scanner.scan_directory(module_path('modules_include')) - assert_kind_of Array, cache assert_equal 2, cache.size klass = cache.find { |k| k.name == "sub::foo" } @@ -52,7 +54,7 @@ def test_should_refresh_cache_when_dir_is_changed 1000 assert_equal 3, @classes_cache.values(module_path('modules_include')).size - @scanner.scan_directory(module_path('modules_include'), 'example_env') + @scanner.scan_directory(module_path('modules_include')) assert_equal 2, @classes_cache.values(module_path('modules_include')).size assert_equal 2, @timestamps.values(module_path('modules_include')).size @@ -66,7 +68,7 @@ def test_should_detect_module_removals Time.now.to_i + 10_000 assert @classes_cache[module_path('modules_include'), module_path('modules_include/removed_testinclude/manifests/init.pp')] - @scanner.scan_directory(module_path('modules_include'), 'example_env') + @scanner.scan_directory(module_path('modules_include')) assert_nil @classes_cache[module_path('modules_include'), module_path('modules_include/removed_testinclude/manifests/init.pp')] assert_nil @timestamps[module_path('modules_include'), module_path('modules_include/removed_testinclude/manifests/init.pp')] @@ -83,7 +85,7 @@ def test_should_not_refresh_cache_when_cache_is_more_recent (current_time = Time.now.to_i + 10_000) assert_equal 3, @classes_cache.values(module_path('modules_include')).size - @scanner.scan_directory(module_path('modules_include'), 'example_env') + @scanner.scan_directory(module_path('modules_include')) assert_equal 4, @classes_cache.values(module_path('modules_include')).size assert_equal 2, @timestamps.values(module_path('modules_include')).size assert @timestamps[module_path('modules_include'), module_path('modules_include/testinclude/manifests/init.pp')] == current_time @@ -91,45 +93,54 @@ def test_should_not_refresh_cache_when_cache_is_more_recent def test_should_return_no_puppet_classes_when_environment_has_no_modules Dir.expects(:glob).with('empty_environment/*').returns([]) - result = @scanner.scan_directory('empty_environment', 'example_env') + result = @scanner.scan_directory('empty_environment') assert result.empty? end def test_should_parse_puppet_classes_with_unicode_chars - @scanner.scan_directory(module_path('with_unicode_chars'), "testing") + @scanner.scan_directory(module_path('with_unicode_chars')) assert_equal 1, @classes_cache.values(module_path('with_unicode_chars')).size end + class EnvironmentRetrieverForTesting + def get(an_environment) + raise "Unexpected environment name '#{an_environment}'" unless an_environment == 'first' + ::Proxy::Puppet::Environment.new('first', [File.expand_path('modules_include', File.expand_path('../fixtures', __FILE__))]) + end + end + def test_responds_to_classes_in_environment + @scanner.classes_in_environment('first') + assert_equal 2, @timestamps.values(File.expand_path('modules_include', File.expand_path('../fixtures', __FILE__))).size + end + def module_path(relative_path) File.expand_path(relative_path, File.expand_path('../fixtures', __FILE__)) end end -if Puppet::PUPPETVERSION.to_i < 4 - class PuppetCacheWithLegacyParserTest < Test::Unit::TestCase +if Puppet::PUPPETVERSION < '4.0' + class CachingRetrieverWithLegacyParserTest < Test::Unit::TestCase include PuppetCacheTestSuite def setup super @classes_cache = ::Proxy::MemoryStore.new @timestamps = ::Proxy::MemoryStore.new - @scanner = ::Proxy::Puppet::PuppetCache.new(@classes_cache, @timestamps) - @scanner.puppet_class_scanner = ::Proxy::Puppet::ClassScanner.new + @scanner = ::Proxy::PuppetLegacy::PuppetCache.new(EnvironmentRetrieverForTesting.new, ::Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer), @classes_cache, @timestamps) end end end -if Puppet::PUPPETVERSION.to_f >= 3.2 - class PuppetCacheWithFutureParserTest < Test::Unit::TestCase +if Puppet::PUPPETVERSION > '3.2' + class CachingRetrieverWithFutureParserTest < Test::Unit::TestCase include PuppetCacheTestSuite def setup super @classes_cache = ::Proxy::MemoryStore.new @timestamps = ::Proxy::MemoryStore.new - @scanner = ::Proxy::Puppet::PuppetCache.new(@classes_cache, @timestamps) - @scanner.puppet_class_scanner = ::Proxy::Puppet::ClassScannerEParser.new + @scanner = ::Proxy::PuppetLegacy::PuppetCache.new(EnvironmentRetrieverForTesting.new, ::Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer), @classes_cache, @timestamps) end end end diff --git a/test/puppet/customrun_test.rb b/test/puppet/customrun_test.rb index e6c22aa58..712f532e1 100644 --- a/test/puppet/customrun_test.rb +++ b/test/puppet/customrun_test.rb @@ -1,35 +1,48 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/customrun' +require 'puppet_proxy_customrun/puppet_proxy_customrun' +require 'puppet_proxy_common/runner' +require 'puppet_proxy_customrun/customrun_main' -class CustomRunTest < Test::Unit::TestCase - def setup - @customrun = Proxy::Puppet::CustomRun.new(:nodes => ["host1", "host2"]) +class CustomrunTest < Test::Unit::TestCase + def test_arguments_can_be_array + customrun = Proxy::PuppetCustomrun::Runner.new('/bin/false', ["-ay", "-f", "-s"]) + assert_equal ["-ay", "-f", "-s"], customrun.command_arguments end - def test_customrun - ::Proxy::Puppet::Plugin.load_test_settings(:customrun_cmd => "/bin/false", :customrun_args => "-ay -f -s") - @customrun.expects(:shell_command).with(["/bin/false", "-ay", "-f", "-s", "host1", "host2"]).returns(true) - @customrun.run + def test_arguments_string_converted_to_array + customrun = Proxy::PuppetCustomrun::Runner.new('/bin/false', '-ay -f -s') + assert_equal ["-ay", "-f", "-s"], customrun.command_arguments end - def test_customrun_with_nil_customrun_args - ::Proxy::Puppet::Plugin.load_test_settings(:customrun_cmd => "/bin/false", :customrun_args => nil) - @customrun.expects(:shell_command).with(["/bin/false", "host1", "host2"]).returns(true) - @customrun.run + def test_empty_arguments_string_is_converted_to_empty_array + customrun = Proxy::PuppetCustomrun::Runner.new('/bin/false', '') + assert customrun.command_arguments.empty? end - def test_customrun_with_array_command_args - ::Proxy::Puppet::Plugin.load_test_settings(:customrun_cmd => "/bin/false", :customrun_args => ["-ay", "-f", "-s"]) - @customrun.expects(:shell_command).with(["/bin/false", "-ay", "-f", "-s", "host1", "host2"]).returns(true) - @customrun.run + def test_customrun + customrun = Proxy::PuppetCustomrun::Runner.new('/bin/false', ["-ay", "-f", "-s"]) + customrun.expects(:shell_command).with(["/bin/false", "-ay", "-f", "-s", "host1", "host2"]).returns(true) + customrun.run(["host1", "host2"]) end def test_customrun_uses_shell_escaped_command - ::Proxy::Puppet::Plugin.load_test_settings(:customrun_cmd => "puppet's_run", :customrun_args => "-ay -f -s") + customrun = Proxy::PuppetCustomrun::Runner.new("puppet's_run", ["-ay", "-f", "-s"]) File.stubs(:exist?).with("puppet's_run").returns(true) + customrun.expects(:shell_command).with(["puppet\\'s_run", "-ay", "-f", "-s", "host1", "host2"]).returns(true) + customrun.run(["host1", "host2"]) + end +end + +require 'puppet_proxy_customrun/plugin_configuration' + +class CustomrunConfigurationTest < Test::Unit::TestCase + def test_di_wiring_parameters + container = ::Proxy::DependencyInjection::Container.new + ::Proxy::PuppetCustomrun::PluginConfiguration.new.load_dependency_injection_wirings(container, + :command => "command", + :command_arguments => ['command', 'arguments']) - @customrun.expects(:shell_command).with(["puppet\\'s_run", "-ay", "-f", "-s", "host1", "host2"]).returns(true) - @customrun.run + assert_equal "command", container.get_dependency(:puppet_runner_impl).command + assert_equal ['command', 'arguments'], container.get_dependency(:puppet_runner_impl).command_arguments end end diff --git a/test/puppet/class_scanner_eparser_test.rb b/test/puppet/future_parser_classes_retriever_test.rb similarity index 61% rename from test/puppet/class_scanner_eparser_test.rb rename to test/puppet/future_parser_classes_retriever_test.rb index d5d65df49..2c266a19c 100644 --- a/test/puppet/class_scanner_eparser_test.rb +++ b/test/puppet/future_parser_classes_retriever_test.rb @@ -1,18 +1,15 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/initializer' -require 'puppet_proxy/class_scanner_eparser' - -# this is needed in order to load (not execute!) the suite without "uninitialized constant" errors -# in environments with puppet version prior to 3.2 -module Proxy::Puppet - class ClassScannerEParser < ClassScannerBase; end -end +require 'puppet' +require 'puppet_proxy_legacy/initializer' +require 'puppet_proxy_common/puppet_class' +require 'puppet_proxy_common/environment' +require 'puppet_proxy_legacy/class_scanner_base' +require 'puppet_proxy_legacy/puppet_cache' +require 'puppet_proxy_legacy/class_scanner_eparser' module ClassScannerEParserTestSuite def setup - Proxy::Puppet::Plugin.load_test_settings(:puppet_conf => File.expand_path('../fixtures/puppet.conf', __FILE__)) - Proxy::Puppet::Initializer.new.reset_puppet + @initializer = Proxy::PuppetLegacy::Initializer.new(File.expand_path('../fixtures/puppet.conf', __FILE__)) end def test_should_find_class_in_a_manifest @@ -22,7 +19,7 @@ class foreman::install { } EOF require 'puppet/pops' - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_manifest(manifest) assert_kind_of Array, klasses assert_equal 1, klasses.size @@ -36,7 +33,7 @@ def test_should_not_file_a_class manifest = <<-EOF include 'x::y' EOF - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_manifest(manifest) assert klasses.empty? end @@ -50,7 +47,7 @@ class foreman::params { } EOF - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_manifest(manifest) assert_kind_of Array, klasses assert_equal 2, klasses.size klasses.sort! { |k1,k2| k1.name <=> k2.name } @@ -68,7 +65,7 @@ class foreman::params { def test_should_scan_a_dir - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_directory('/tmp/no_such_dir', "example_env") + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_directory('/tmp/no_such_dir') assert_kind_of Array, klasses assert klasses.empty? end @@ -78,8 +75,7 @@ def test_should_extract_parameters__no_param_parenthesis class foreman::install { } EOF - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_manifest(manifest) assert_equal 1, klasses.size klass = klasses.first assert_equal({}, klass.params) @@ -90,8 +86,7 @@ def test_should_extract_parameters__empty_param_parenthesis class foreman::install () { } EOF - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_manifest(manifest) assert_equal 1, klasses.size klass = klasses.first assert_equal({}, klass.params) @@ -102,8 +97,7 @@ def test_should_extract_parameters__single_param_no_value class foreman::install ($mandatory) { } EOF - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_manifest(manifest) assert_equal 1, klasses.size klass = klasses.first assert_equal({'mandatory' => nil}, klass.params) @@ -127,7 +121,7 @@ class foreman::install ( ) { } EOF - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(@environment_retriever, @initializer).scan_manifest(manifest) assert_kind_of Array, klasses assert_equal 1, klasses.size klass = klasses.first @@ -148,7 +142,7 @@ class foreman::install ( end def test_should_handle_import_in_a_manifest_without_cache - klasses = Proxy::Puppet::ClassScannerEParser.new.scan_directory(File.expand_path('../fixtures/modules_include', __FILE__), "example_env") + klasses = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_directory(File.expand_path('../fixtures/modules_include', __FILE__)) assert_equal 2, klasses.size klass = klasses.find {|k| k.name == "sub::foo" } @@ -159,16 +153,32 @@ def test_should_handle_import_in_a_manifest_without_cache end def test_should_parse_puppet_classes_with_unicode_chars - classes = Proxy::Puppet::ClassScannerEParser.new.scan_directory(File.expand_path('../fixtures/with_unicode_chars', __FILE__), "testing") + classes = Proxy::PuppetLegacy::ClassScannerEParser.new(nil, @initializer).scan_directory(File.expand_path('../fixtures/with_unicode_chars', __FILE__)) assert_equal 1, classes.size assert_equal "unicodetest", classes.first.name end + class EnvironmentRetrieverForTesting + def get(an_environment) + raise "Unexpected environment name '#{an_environment}'" unless an_environment == 'first' + ::Proxy::Puppet::Environment.new('first', [File.expand_path('../fixtures/modules_include', __FILE__)]) + end + end + def test_returns_classes_in_environment + classes = Proxy::PuppetLegacy::ClassScannerEParser.new(EnvironmentRetrieverForTesting.new, @initializer).classes_in_environment('first') + + assert_equal 2, classes.size + assert classes.any? {|k| k.name == "testinclude" } + assert classes.any? {|k| k.name == "sub::foo" } + end + #TODO add scans to a real puppet directory with modules end -if Puppet::PUPPETVERSION.to_f >= 3.2 - class ClassScannerEParserTest < Test::Unit::TestCase +# Future parser isn't available on puppet versions prior to 3.2. +# As a result we cannot load and test ClassScannerEParser on puppet prior to 3.2. +if Puppet::PUPPETVERSION >= '3.2' + class FutureParserClassesRetrieverTest < Test::Unit::TestCase include ClassScannerEParserTestSuite end end diff --git a/test/puppet/class_scanner_test.rb b/test/puppet/legacy_parser_classes_retriever_test.rb similarity index 70% rename from test/puppet/class_scanner_test.rb rename to test/puppet/legacy_parser_classes_retriever_test.rb index e19210789..eb201cbba 100644 --- a/test/puppet/class_scanner_test.rb +++ b/test/puppet/legacy_parser_classes_retriever_test.rb @@ -1,12 +1,15 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/initializer' -require 'puppet_proxy/class_scanner' +require 'puppet' +require 'puppet_proxy_legacy/initializer' +require 'puppet_proxy_common/puppet_class' +require 'puppet_proxy_common/environment' +require 'puppet_proxy_legacy/class_scanner_base' +require 'puppet_proxy_legacy/puppet_cache' +require 'puppet_proxy_legacy/class_scanner' module ClassScannerTestSuite def setup - Proxy::Puppet::Plugin.load_test_settings(:puppet_conf => './test/fixtures/puppet.conf') - Proxy::Puppet::Initializer.new.reset_puppet + @initializer = Proxy::PuppetLegacy::Initializer.new(File.expand_path('../fixtures/puppet.conf', __FILE__)) end def test_should_find_class_in_a_manifest @@ -15,7 +18,7 @@ class foreman::install { include 'x::y' } EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert_kind_of Array, klasses assert_equal 1, klasses.size @@ -29,7 +32,7 @@ def test_should_not_file_a_class manifest = <<-EOF include 'x::y' EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert klasses.empty? end def test_should_find_multiple_class_in_a_manifest @@ -42,8 +45,7 @@ class foreman::params { } EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert_equal 2, klasses.size klasses.sort! { |k1,k2| k1.name <=> k2.name } @@ -59,8 +61,7 @@ class foreman::params { end def test_should_scan_and_return_empty_array_when_directory_does_not_exist - klasses = Proxy::Puppet::ClassScanner.new.scan_directory('/tmp/no_such_dir', "example_env") - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_directory('/tmp/no_such_dir') assert klasses.empty? end @@ -69,8 +70,7 @@ def test_should_extract_parameters__no_param_parenthesis class foreman::install { } EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert_equal 1, klasses.size klass = klasses.first assert_equal({}, klass.params) @@ -81,8 +81,7 @@ def test_should_extract_parameters__empty_param_parenthesis class foreman::install () { } EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert_equal 1, klasses.size klass = klasses.first assert_equal({}, klass.params) @@ -93,8 +92,7 @@ def test_should_extract_parameters__single_param_no_value class foreman::install ($mandatory) { } EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) - assert_kind_of Array, klasses + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert_equal 1, klasses.size klass = klasses.first assert_equal({'mandatory' => nil}, klass.params) @@ -117,7 +115,7 @@ class foreman::install ( ) { } EOF - klasses = Proxy::Puppet::ClassScanner.new.scan_manifest(manifest) + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_manifest(manifest) assert_kind_of Array, klasses assert_equal 1, klasses.size klass = klasses.first @@ -137,7 +135,7 @@ class foreman::install ( end def test_should_handle_import_in_a_manifest - klasses = Proxy::Puppet::ClassScanner.new.scan_directory(File.expand_path('../fixtures/modules_include', __FILE__), "example_env") + klasses = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_directory(File.expand_path('../fixtures/modules_include', __FILE__)) assert_kind_of Array, klasses assert_equal 2, klasses.size @@ -149,7 +147,7 @@ def test_should_handle_import_in_a_manifest end def test_should_parse_puppet_classes_with_unicode_chars - classes = Proxy::Puppet::ClassScanner.new.scan_directory(File.expand_path('../fixtures/with_unicode_chars', __FILE__), "testing") + classes = Proxy::PuppetLegacy::ClassScanner.new(nil, @initializer).scan_directory(File.expand_path('../fixtures/with_unicode_chars', __FILE__)) assert_equal 1, classes.size assert_equal "unicodetest", classes.first.name end @@ -157,8 +155,8 @@ def test_should_parse_puppet_classes_with_unicode_chars #TODO add scans to a real puppet directory with modules end -if Puppet::PUPPETVERSION.to_i < 4 - class ClassScannerTest < Test::Unit::TestCase +if Puppet::PUPPETVERSION < '4.0' + class LegacyParserClassesRetrieverTest < Test::Unit::TestCase include ClassScannerTestSuite end end diff --git a/test/puppet/mcollective_test.rb b/test/puppet/mcollective_test.rb index 42ce06466..ab72a215b 100644 --- a/test/puppet/mcollective_test.rb +++ b/test/puppet/mcollective_test.rb @@ -1,58 +1,49 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/mcollective' +require 'puppet_proxy_mcollective/puppet_proxy_mcollective' +require 'puppet_proxy_common/runner' +require 'puppet_proxy_mcollective/mcollective_main' class MCollectiveTest < Test::Unit::TestCase def setup - @mcollective = Proxy::Puppet::MCollective.new(:nodes => ["host1", "host2"]) + @mcollective = Proxy::PuppetMCollective::Runner.new(nil) end - + def test_run_command @mcollective.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @mcollective.stubs(:which).with("mco", anything).returns("/usr/bin/mco") @mcollective.expects(:shell_command).with(["/usr/bin/sudo", "/usr/bin/mco", "puppet", "runonce", "-I", "host1", "host2"]).returns(true) - assert @mcollective.run - end - - def test_run_command_with_puppet_user_defined - @mcollective.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @mcollective.stubs(:which).with("mco", anything).returns("/usr/bin/mco") - Proxy::Puppet::Plugin.settings.stubs(:puppet_user).returns("example") - - @mcollective.expects(:shell_command).with(["/usr/bin/sudo", "-u", "example", "/usr/bin/mco", "puppet", "runonce", "-I", "host1", "host2"]).returns(true) - - assert @mcollective.run + assert @mcollective.run(["host1", "host2"]) end def test_run_command_with_mcollective_user_defined + @mcollective = Proxy::PuppetMCollective::Runner.new("peadmin") @mcollective.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @mcollective.stubs(:which).with("mco", anything).returns("/usr/bin/mco") - Proxy::Puppet::Plugin.settings.stubs(:mcollective_user).returns("peadmin") - @mcollective.expects(:shell_command).with(["/usr/bin/sudo", "-u", "peadmin", "/usr/bin/mco", "puppet", "runonce", "-I", "host1", "host2"]).returns(true) - assert @mcollective.run - end - - def test_run_command_with_mcollective_user_should_take_precedence - @mcollective.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @mcollective.stubs(:which).with("mco", anything).returns("/usr/bin/mco") - Proxy::Puppet::Plugin.settings.stubs(:puppet_user).returns("example") - Proxy::Puppet::Plugin.settings.stubs(:mcollective_user).returns("peadmin") @mcollective.expects(:shell_command).with(["/usr/bin/sudo", "-u", "peadmin", "/usr/bin/mco", "puppet", "runonce", "-I", "host1", "host2"]).returns(true) - assert @mcollective.run + assert @mcollective.run(["host1", "host2"]) end def test_run_command_with_missing_sudo @mcollective.stubs(:which).with("sudo", anything).returns(false) @mcollective.stubs(:which).with("mco", anything).returns("/usr/bin/mco") - assert !@mcollective.run + assert !@mcollective.run(["host1", "host2"]) end def test_run_command_with_missing_mco @mcollective.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @mcollective.stubs(:which).with("mco", anything).returns(false) - assert !@mcollective.run + assert !@mcollective.run(["host1", "host2"]) + end +end + +class MCollectiveConfigurationTest < Test::Unit::TestCase + def test_di_wiring_parameters + container = ::Proxy::DependencyInjection::Container.new + ::Proxy::PuppetMCollective::PluginConfiguration.new.load_dependency_injection_wirings(container, :user => "a_user") + + assert_equal "a_user", container.get_dependency(:puppet_runner_impl).user end end diff --git a/test/puppet/puppet_api_configuration_test.rb b/test/puppet/puppet_api_configuration_test.rb new file mode 100644 index 000000000..b7f45aa40 --- /dev/null +++ b/test/puppet/puppet_api_configuration_test.rb @@ -0,0 +1,62 @@ +require 'test_helper' +require 'puppet_proxy_puppet_api/puppet_proxy_puppet_api' + +class PuppetApiConfigurationTest < Test::Unit::TestCase + def setup + @configuration = ::Proxy::PuppetApi::PluginConfiguration.new + end + + def test_load_programmable_settings_sets_classes_retriever + assert_equal :apiv3, @configuration.load_programmable_settings({})[:classes_retriever] + end + + def test_load_programmable_settings_sets_environments_retriever + assert_equal :apiv3, @configuration.load_programmable_settings({})[:environments_retriever] + end +end + +class PuppetApiDefaultSettingsTest < Test::Unit::TestCase + def test_default_settings + Proxy::PuppetApi::Plugin.load_test_settings({}) + assert_equal '/var/lib/puppet/ssl/certs/ca.pem', Proxy::PuppetApi::Plugin.settings.puppet_ssl_ca + end +end + +require 'puppet_proxy_common/environments_retriever_base' +require 'puppet_proxy_puppet_api/v3_environments_retriever' +require 'puppet_proxy_puppet_api/v3_classes_retriever' + +class PuppetApiDIWiringsTest < Test::Unit::TestCase + def setup + @configuration = ::Proxy::PuppetApi::PluginConfiguration.new + @container = ::Proxy::DependencyInjection::Container.new + end + + def test_apiv3_environments_retriever_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, + :puppet_url => "http://puppet.url", + :puppet_ssl_ca => "path_to_ca_cert", + :puppet_ssl_cert => "path_to_ssl_cert", + :puppet_ssl_key => "path_to_ssl_key") + + assert @container.get_dependency(:environment_retriever_impl).instance_of?(::Proxy::PuppetApi::V3EnvironmentsRetriever) + assert_equal "http://puppet.url", @container.get_dependency(:environment_retriever_impl).puppet_url + assert_equal "path_to_ca_cert", @container.get_dependency(:environment_retriever_impl).ssl_ca + assert_equal "path_to_ssl_cert", @container.get_dependency(:environment_retriever_impl).ssl_cert + assert_equal "path_to_ssl_key", @container.get_dependency(:environment_retriever_impl).ssl_key + end + + def test_apiv3_classes_retriever_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, + :puppet_url => "http://puppet.url", + :puppet_ssl_ca => "path_to_ca_cert", + :puppet_ssl_cert => "path_to_ssl_cert", + :puppet_ssl_key => "path_to_ssl_key") + + assert @container.get_dependency(:class_retriever_impl).instance_of?(::Proxy::PuppetApi::V3ClassesRetriever) + assert_equal "http://puppet.url", @container.get_dependency(:class_retriever_impl).puppet_url + assert_equal "path_to_ca_cert", @container.get_dependency(:class_retriever_impl).ssl_ca + assert_equal "path_to_ssl_cert", @container.get_dependency(:class_retriever_impl).ssl_cert + assert_equal "path_to_ssl_key", @container.get_dependency(:class_retriever_impl).ssl_key + end +end diff --git a/test/puppet/puppet_api_environments_retriever_test.rb b/test/puppet/puppet_api_environments_retriever_test.rb index ce63c4af7..2aa5e27ae 100644 --- a/test/puppet/puppet_api_environments_retriever_test.rb +++ b/test/puppet/puppet_api_environments_retriever_test.rb @@ -1,18 +1,20 @@ require 'test_helper' -require 'puppet_proxy/environment' -require 'puppet_proxy/puppet_api_v2_environments_retriever' -require 'puppet_proxy/puppet_api_v3_environments_retriever' +require 'puppet_proxy_common/environment' +require 'puppet_proxy_common/environments_retriever_base' +require 'puppet_proxy_common/errors' +require 'puppet_proxy_legacy/puppet_api_v2_environments_retriever' +require 'puppet_proxy_puppet_api/v3_environments_retriever' module PuppetApiEnvironmentsRetrieverTestSuite - def test_uses_environments_api - @api_class.any_instance.expects(:find_environments).returns('environments' => []) - @retriever.all + class EnvironmentApiForTesting + attr_accessor :find_environments_response + def find_environments + find_environments_response + end end def test_api_response_parsing - @api_class.any_instance. - stubs(:find_environments). - returns(JSON.load(File.read(File.expand_path('../fixtures/environments_api.json', __FILE__)))) + @api.find_environments_response = JSON.load(File.read(File.expand_path('../fixtures/environments_api.json', __FILE__))) envs = @retriever.all assert_equal Set.new(['production', 'example_env', 'development', 'common']), Set.new(envs.map { |e| e.name }) @@ -24,7 +26,7 @@ def test_api_response_parsing end def test_error_raised_if_response_has_no_environments - @api_class.any_instance.stubs(:find_environments).returns({}) + @api.find_environments_response = {} assert_raises Proxy::Puppet::DataError do @retriever.all end @@ -35,8 +37,8 @@ class PuppetApiV2EnvironmentsRetrieverTest < Test::Unit::TestCase include PuppetApiEnvironmentsRetrieverTestSuite def setup - @retriever = Proxy::Puppet::PuppetApiV2EnvironmentsRetriever.new - @api_class = Proxy::Puppet::EnvironmentsApi + @api = PuppetApiEnvironmentsRetrieverTestSuite::EnvironmentApiForTesting.new + @retriever = Proxy::PuppetLegacy::PuppetApiV2EnvironmentsRetriever.new(nil, nil, nil, nil, @api) end end @@ -44,7 +46,7 @@ class PuppetApiV3EnvironmentsRetrieverTest < Test::Unit::TestCase include PuppetApiEnvironmentsRetrieverTestSuite def setup - @retriever = Proxy::Puppet::PuppetApiV3EnvironmentsRetriever.new - @api_class = Proxy::Puppet::EnvironmentsApiv3 + @api = PuppetApiEnvironmentsRetrieverTestSuite::EnvironmentApiForTesting.new + @retriever = Proxy::PuppetApi::V3EnvironmentsRetriever.new(nil, nil, nil, nil, @api) end end diff --git a/test/puppet/puppet_api_test.rb b/test/puppet/puppet_api_test.rb index df34d0140..6778dc106 100644 --- a/test/puppet/puppet_api_test.rb +++ b/test/puppet/puppet_api_test.rb @@ -1,77 +1,142 @@ require 'test_helper' require 'json' -require 'ostruct' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/puppet_api' +require 'puppet_proxy_common/puppet_class' +require 'puppet_proxy_common/environment' +require 'puppet_proxy_common/environments_retriever_base' +require 'puppet_proxy_common/errors' -ENV['RACK_ENV'] = 'test' +class ApiTestEnvironmentsRetriever < ::Proxy::Puppet::EnvironmentsRetrieverBase + attr_reader :first, :second + + def initialize + @first = ::Proxy::Puppet::Environment.new("first", ["path1", "path2"]) + @second = ::Proxy::Puppet::Environment.new("second", ["path3", "path4"]) + end + def all + [@first, @second] + end + + def get(an_environment) + super(an_environment) + end +end + +class ApiTestClassesRetriever + attr_reader :class_one, :class_two + + def initialize + @class_one = ::Proxy::Puppet::PuppetClass.new("dns::install") + @class_two = ::Proxy::Puppet::PuppetClass.new("dns", "dns_server_package" => "${::dns::params::dns_server_package}") + end -class Proxy::Puppet::Api - attr_reader :server + def classes_in_environment(an_environment) + case an_environment + when 'first' + [@class_one, @class_two] + when 'second' + raise Proxy::Puppet::EnvironmentNotFound.new + else + raise "Unexpected environment name '#{an_environment}' was passed in into #classes_in_environment method." + end + end +end + +class ApiTestPuppetRunner + attr_reader :nodes + + def run(nodes) + @nodes = nodes + end +end + +module Proxy::Puppet + module DependencyInjection + include Proxy::DependencyInjection::Accessors + def container_instance + Proxy::DependencyInjection::Container.new do |c| + c.dependency :class_retriever_impl, ApiTestClassesRetriever + c.dependency :environment_retriever_impl, ApiTestEnvironmentsRetriever + end + end + end end +require 'puppet_proxy/puppet_api' + +ENV['RACK_ENV'] = 'test' + class PuppetApiTest < Test::Unit::TestCase + include Rack::Test::Methods - def app - Proxy::Puppet::Api.new + def setup + @class_retriever = ApiTestClassesRetriever.new + @environment_retriever = ApiTestEnvironmentsRetriever.new + + @class_one = @class_retriever.class_one + @class_two = @class_retriever.class_two end - def setup - apache = OpenStruct.new(:name => "apache::class", :module => "apache", :params => {:ensure => nil, :enable => true}) - apache.stubs(:to_s).returns(apache.name) - @foo = OpenStruct.new(:name => "foo", :paths => ["/etc/puppet/modules/foo"], :classes => [apache]) - @bar = OpenStruct.new(:name => "bar", :paths => ["/etc/puppet/modules/common", "/etc/puppet/modules/bar"], :classes => []) - @foo.stubs(:to_s).returns(@foo.name) - @bar.stubs(:to_s).returns(@bar.name) + def app + app = Proxy::Puppet::Api.new + @test_runner = ApiTestPuppetRunner.new + app.helpers.puppet_runner = @test_runner + app end - def test_api_gets_puppet_environments - Proxy::Puppet::Environment.expects(:all).returns([@foo, @bar]) + def test_gets_puppet_environments get "/environments" assert last_response.ok?, "Last response was not ok: #{last_response.body}" - data = JSON.parse(last_response.body) - assert_equal ["foo", "bar"], data + assert_equal [@environment_retriever.first.name, @environment_retriever.second.name], JSON.parse(last_response.body) end - def test_api_gets_single_puppet_environment - Proxy::Puppet::Environment.expects(:find).with("foo").returns(@foo) - get "/environments/foo" + def test_gets_single_puppet_environment + get "/environments/#{@environment_retriever.first.name}" assert last_response.ok?, "Last response was not ok: #{last_response.body}" data = JSON.parse(last_response.body) - assert_equal "foo", data["name"] - assert_equal ["/etc/puppet/modules/foo"], data["paths"] + assert_equal @environment_retriever.first.name, data["name"] + assert_equal @environment_retriever.first.paths, data["paths"] end - def test_api_missing_single_puppet_environment - Proxy::Puppet::Environment.expects(:find).with("unknown").returns(nil) + def test_missing_single_puppet_environment get "/environments/unknown" assert_equal 404, last_response.status end - def test_api_gets_puppet_environment_classes - Proxy::Puppet::Environment.expects(:find).with("foo").returns(@foo) - get "/environments/foo/classes" + def test_gets_puppet_environment_classes + get "/environments/first/classes" assert last_response.ok?, "Last response was not ok: #{last_response.body}" data = JSON.parse(last_response.body) - assert_equal Array, data.class - assert_equal "apache::class", data[0]["apache::class"]["name"] - assert_equal "apache", data[0]["apache::class"]["module"] - assert data[0]["apache::class"]["params"].include? "ensure" - assert data[0]["apache::class"]["params"]["enable"] + + assert_equal({'name' => @class_one.name, 'module' => @class_one.module, 'params' => @class_one.params}, data[0]["dns::install"]) + assert_equal({'name' => @class_two.name, 'module' => @class_two.module, 'params' => @class_two.params}, data[1]["dns"]) + end + + def test_get_puppet_class_from_non_existing_environment + get "/environments/second/classes" + assert_equal 404, last_response.status + end + + def test_puppet_run + post "/run", :nodes => ['node1', 'node2'] + assert last_response.ok?, "Last response was not ok: #{last_response.body}" + assert_equal ['node1', 'node2'], @test_runner.nodes end - def test_puppet_setup - setups = { "puppetrun" => "Proxy::Puppet::PuppetRun", "mcollective" => "Proxy::Puppet::MCollective", - "puppetssh" => "Proxy::Puppet::PuppetSSH", "salt" => "Proxy::Puppet::Salt", - "customrun" => "Proxy::Puppet::CustomRun" } + def test_puppet_run_without_nodes + post "/run" + assert_equal 400, last_response.status + end - Proxy::Puppet::Plugin.settings.stubs(:enabled).returns(true) + def test_puppet_run_when_puppet_runner_fails + ApiTestPuppetRunner.any_instance.expects(:run).returns(nil) + post "/run", :nodes => ['node1', 'node2'] + assert_equal 500, last_response.status + end - setups.each do |k, v| - Proxy::Puppet::Plugin.settings.stubs(:puppet_provider).returns(k) - (api = Proxy::Puppet::Api.new!).puppet_setup - assert_equal v, api.server.class.to_s - end + def test_puppet_run_when_puppet_runner_raises_exception + ApiTestPuppetRunner.any_instance.expects(:run).raises(Exception) + post "/run", :nodes => ['node1', 'node2'] + assert_equal 500, last_response.status end end diff --git a/test/puppet/puppet_api_v3_classes_retriever_test.rb b/test/puppet/puppet_api_v3_classes_retriever_test.rb new file mode 100644 index 000000000..c36d3d39a --- /dev/null +++ b/test/puppet/puppet_api_v3_classes_retriever_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' +require 'puppet_proxy_common/api_request' +require 'puppet_proxy_puppet_api/v3_api_request' +require 'puppet_proxy_common/errors' +require 'puppet_proxy_common/puppet_class' +require 'puppet_proxy_puppet_api/v3_classes_retriever' + +class PuppetApiv3ClassesRetrieverTest < Test::Unit::TestCase + class ClassesRetrieverForTesting; end + + def setup + @api = ClassesRetrieverForTesting.new + @retriever = Proxy::PuppetApi::V3ClassesRetriever.new(nil, nil, nil, nil, @api) + end + + def test_uses_puppet_resource_api + Proxy::PuppetApi::ResourceTypeApiv3.any_instance.expects(:list_classes).with('test_environment', 'class').returns([]) + Proxy::PuppetApi::V3ClassesRetriever.new(nil, nil, nil, nil).classes_in_environment('test_environment') + end + + def test_should_raise_environment_not_found_when_puppet_cannot_find_it + @api.expects(:list_classes).raises(Proxy::Error::HttpError.new(400, "Could not find environment")) + assert_raises(Proxy::Puppet::EnvironmentNotFound) { @retriever.classes_in_environment('test_environment') } + end + + def test_should_re_raise_exception_on_other_errors + @api.expects(:list_classes).raises(Proxy::Error::HttpError.new(500, "Could not find environment")) + assert_raises(Proxy::Error::HttpError) { @retriever.classes_in_environment('test_environment') } + end + + def test_should_surround_variable_expression_parameters_in_curvy_braces + classes = @retriever.convert_to_proxy_var_parameter_representation([{'name' => 'dns', 'parameters' => {"localzonepath" => "$::dns::params::localzonepath"}}]) + assert_equal({"localzonepath" => "${::dns::params::localzonepath}"}, classes[0].params) + end + + def test_should_keep_non_variable_expression_parameters_as_is + classes = @retriever.convert_to_proxy_var_parameter_representation([{'name' => 'dns', 'parameters' => {"localzonepath" => "a_path", "a_param" => 42}}]) + assert_equal({"localzonepath" => "a_path", "a_param" => 42}, classes[0].params) + end + + def test_should_assign_correct_class_name + classes = @retriever.convert_to_proxy_var_parameter_representation([{'name' => 'dns', 'parameters' => {}}]) + assert_equal('dns', classes[0].name) + end +end diff --git a/test/puppet/puppet_class_test.rb b/test/puppet/puppet_class_test.rb index fb7763a08..08e08ed73 100644 --- a/test/puppet/puppet_class_test.rb +++ b/test/puppet/puppet_class_test.rb @@ -1,18 +1,14 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/puppet_class' -require 'puppet_proxy/initializer' +require 'puppet_proxy_common/puppet_class' class PuppetClassTest < Test::Unit::TestCase - def setup - Proxy::Puppet::Plugin.load_test_settings(:use_cache => false) - end - def test_should_parse_modulename_correctly klass = Proxy::Puppet::PuppetClass.new "foreman_proxy::install" assert_equal "foreman_proxy", klass.module + klass = Proxy::Puppet::PuppetClass.new "dummy" assert_nil klass.module + klass = Proxy::Puppet::PuppetClass.new "dummy::klass::nested" assert_equal "dummy", klass.module end @@ -20,8 +16,10 @@ def test_should_parse_modulename_correctly def test_should_parse_puppet_class_correctly klass = Proxy::Puppet::PuppetClass.new "foreman_proxy::install" assert_equal "install", klass.name + klass = Proxy::Puppet::PuppetClass.new "dummy" assert_equal "dummy", klass.name + klass = Proxy::Puppet::PuppetClass.new "dummy::klass::nested" assert_equal "klass::nested", klass.name end diff --git a/test/puppet/puppet_config_environments_retriever_test.rb b/test/puppet/puppet_config_environments_retriever_test.rb index 8cc0601b9..02a16527d 100644 --- a/test/puppet/puppet_config_environments_retriever_test.rb +++ b/test/puppet/puppet_config_environments_retriever_test.rb @@ -1,7 +1,8 @@ require 'test_helper' -require 'puppet_proxy/dependency_injection/container' -require 'puppet_proxy/environment' -require 'puppet_proxy/puppet_config_environments_retriever' +require 'puppet_proxy_common/environment' +require 'puppet_proxy_common/environments_retriever_base' +require 'puppet_proxy_common/errors' +require 'puppet_proxy_legacy/puppet_config_environments_retriever' class PuppetConfigurationForTesting attr_accessor :data @@ -11,13 +12,12 @@ def get; data; end class PuppetConfigEnvironmentsRetrieverTest < Test::Unit::TestCase def setup @puppet_configuration = PuppetConfigurationForTesting.new - @retriever = Proxy::Puppet::PuppetConfigEnvironmentsRetriever.new - @retriever.puppet_configuration = @puppet_configuration + @retriever = Proxy::PuppetLegacy::PuppetConfigEnvironmentsRetriever.new(@puppet_configuration, "/etc/puppet/puppet.conf") end def test_single_static_env @puppet_configuration.data = { - :main => {}, + :main => {}, :master => {}, :production => { :modulepath => module_path('environments/prod') } } @@ -37,7 +37,7 @@ def test_master_is_remapped_to_production_when_solo def test_multiple_static_env @puppet_configuration.data = { - :main => {}, + :main => {}, :master => {}, :production => { :modulepath => module_path('environments/prod') }, :development => { :modulepath => module_path('environments/dev') } } @@ -47,7 +47,7 @@ def test_multiple_static_env def test_multiple_modulepath_in_single_env_loads_all_classes @puppet_configuration.data = { - :main => {}, + :main => {}, :master => {}, :production => { :modulepath => module_path('environments/dev', 'environments/prod') }, } env = @retriever.all @@ -99,6 +99,37 @@ def test_multiple_modulepath_in_single_env_with_broken_entry assert_equal env.map { |e| e.name }, ['master'] end + def test_missing_main_section_in_puppet_configuration_raises_exception + @puppet_configuration.data = { + :master => {} + } + assert_raise(Exception) { @retriever.all } + end + + def test_missing_master_section_in_puppet_configuration_raises_exception + @puppet_configuration.data = { + :main => {} + } + assert_raise(Exception) { @retriever.all } + end + + def test_get_environment + @puppet_configuration.data = { + :main => {}, :master => {}, + :production => { :modulepath => module_path('environments/prod') } + } + + env = @retriever.get('production') + assert_equal 'production', env.name + end + + def test_get_environment_raises_exception_if_environment_not_found + @puppet_configuration.data = { + :master => {}, :main => {} + } + assert_raise(Proxy::Puppet::EnvironmentNotFound) { @retriever.get('non_existent') } + end + def module_path(*relative_path) paths = relative_path.map { |path| File.expand_path(path, File.expand_path('../fixtures', __FILE__)) } paths.size < 2 ? paths.first : paths.join(':') diff --git a/test/puppet/puppet_config_reader_test.rb b/test/puppet/puppet_config_reader_test.rb index cf0e21fef..eadc13dc7 100644 --- a/test/puppet/puppet_config_reader_test.rb +++ b/test/puppet/puppet_config_reader_test.rb @@ -1,5 +1,5 @@ require 'test_helper' -require 'puppet_proxy/puppet_config' +require 'puppet_proxy_legacy/puppet_config' class PuppetConfigReaderTest < Test::Unit::TestCase def setup @@ -7,7 +7,7 @@ def setup end def build - Proxy::Puppet::ConfigReader.new(@puppet_conf) + Proxy::PuppetLegacy::ConfigReader.new(@puppet_conf) end def test_get_should_return_section_hash diff --git a/test/puppet/puppet_config_test.rb b/test/puppet/puppet_config_test.rb deleted file mode 100644 index 3a0a737e3..000000000 --- a/test/puppet/puppet_config_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'test_helper' -require 'puppet_proxy/puppet_plugin' - -class PuppetConfigTest < Test::Unit::TestCase - def test_omitted_settings_have_default_values - Proxy::Puppet::Plugin.load_test_settings({}) - - assert_equal 'puppetrun', Proxy::Puppet::Plugin.settings.puppet_provider - assert_equal '/etc/puppet/puppet.conf', Proxy::Puppet::Plugin.settings.puppet_conf - assert_equal 'puppet.run', Proxy::Puppet::Plugin.settings.salt_puppetrun_cmd - assert_equal '/var/lib/puppet/ssl/certs/ca.pem', Proxy::Puppet::Plugin.settings.puppet_ssl_ca - assert Proxy::Puppet::Plugin.settings.use_cache - end -end diff --git a/test/puppet/puppet_environment_test.rb b/test/puppet/puppet_environment_test.rb deleted file mode 100644 index 63286f541..000000000 --- a/test/puppet/puppet_environment_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'test_helper' -require 'puppet_proxy/environment' - -class PuppetEnvironmentTest < Test::Unit::TestCase - - def setup - @environment = Proxy::Puppet::Environment.new(:name => 'test', :paths => ['path_1']) - end - - def test_should_use_environments_retriever_to_get_environments - environments_retriever = mock() - environments_retriever.expects(:all).returns([]) - - @environment.environments_retriever = environments_retriever - @environment.all - end - - def test_should_use_puppet_cache_when_enumerating_classes - puppet_cache = mock() - puppet_cache.expects(:scan_directory).with('path_1', 'test').returns([]) - - @environment.puppet_class_scanner = puppet_cache - @environment.classes - end -end diff --git a/test/puppet/puppet_legacy_configuration_test.rb b/test/puppet/puppet_legacy_configuration_test.rb new file mode 100644 index 000000000..c34dd8925 --- /dev/null +++ b/test/puppet/puppet_legacy_configuration_test.rb @@ -0,0 +1,189 @@ +require 'test_helper' +require 'puppet_proxy_legacy/puppet_proxy_legacy' + +class PuppetLegacyProgrammableSettingsTest < Test::Unit::TestCase + def setup + @configuration = ::Proxy::PuppetLegacy::PluginConfiguration.new + end + + def test_use_future_parser_when_main_parser_is_set + assert @configuration.use_future_parser?(:main => {:parser => "future"}) + end + + def test_use_future_parser_when_master_parser_is_set + assert @configuration.use_future_parser?(:master => {:parser => "future"}) + end + + def test_use_future_parser_when_main_and_master_are_missing + assert !@configuration.use_future_parser?({}) + end + + def test_use_environment_api_when_main_environmentpath_is_set + assert !@configuration.use_environment_api?(:main => {:environmentpath => ["a/path"]}) + end + + def test_use_environment_api_when_master_environmentpath_is_set + assert !@configuration.use_environment_api?(:master => {:environmentpath => ["a/path"]}) + end + + def test_use_environment_api_when_main_and_master_are_missing + assert @configuration.use_environment_api?({}) + end + + def test_use_environment_api_when_no_environment_paths_are_present + configuration = LegacyProviderConfigurationForTesting.new({}) + assert configuration.use_environment_api?(:main => {}, :master => {}) + end + + def test_puppet_conf_exists_is_used_in_load_programmable_settings_call + @configuration.expects(:puppet_conf_exists?).with("a/path") + @configuration.stubs(:load_puppet_configuration).returns({}) + @configuration.load_programmable_settings(:puppet_conf => "a/path") + end + + class LegacyProviderConfigurationForTesting < ::Proxy::PuppetLegacy::PluginConfiguration + def initialize(puppet_config) + @config = puppet_config + end + + def puppet_conf_exists?(a_path); end + end + + def test_load_puppet_configuration_is_used_in_load_programmable_settings_call + configuration = LegacyProviderConfigurationForTesting.new({}) + configuration.stubs(:load_puppet_configuration).with("a/path").returns({}) + configuration.load_programmable_settings(:puppet_conf => "a/path") + end + + def test_load_programmable_settings_sets_cached_future_parser + configuration = LegacyProviderConfigurationForTesting.new(:main => {:parser => "future"}) + assert_equal :cached_future_parser, configuration.load_programmable_settings(:use_cache => true)[:classes_retriever] + end + + def test_load_programmable_settings_sets_future_parser + configuration = LegacyProviderConfigurationForTesting.new(:main => {:parser => "future"}) + assert_equal :future_parser, configuration.load_programmable_settings(:use_cache => false)[:classes_retriever] + end + + def test_load_programmable_settings_sets_cached_legacy_parser + configuration = LegacyProviderConfigurationForTesting.new({}) + assert_equal :cached_legacy_parser, configuration.load_programmable_settings(:use_cache => true)[:classes_retriever] + end + + def test_load_programmable_settings_sets_legacy_parser + configuration = LegacyProviderConfigurationForTesting.new({}) + assert_equal :legacy_parser, configuration.load_programmable_settings(:use_cache => false)[:classes_retriever] + end + + def test_load_programmable_settings_sets_config_file_for_environments_retriever_for_puppet_before_3_2 + configuration = LegacyProviderConfigurationForTesting.new({}) + assert_equal :config_file, configuration.load_programmable_settings(:puppet_version => "3.1")[:environments_retriever] + end + + def test_load_programmable_settings_sets_config_file_for_environments_retriever_when_puppet_use_environment_api_is_false + configuration = LegacyProviderConfigurationForTesting.new({}) + assert_equal :config_file, configuration.load_programmable_settings(:puppet_version => "3.2", :use_environment_api => false)[:environments_retriever] + end + + def test_load_programmable_settings_sets_api_v2_for_environments_retriever_when_puppet_use_environment_api_is_true + configuration = LegacyProviderConfigurationForTesting.new({}) + assert_equal :api_v2, configuration.load_programmable_settings(:puppet_version => "3.2", :use_environment_api => true)[:environments_retriever] + end + + def test_load_programmable_settings_sets_api_v2_for_environments_retriever_whithout_puppet_use_environment_api_and_environmentpath_missing + configuration = LegacyProviderConfigurationForTesting.new(:master => {}, :main => {}) + assert_equal :api_v2, configuration.load_programmable_settings(:puppet_version => "3.2")[:environments_retriever] + end + + def test_load_programmable_settings_sets_api_v2_for_environments_retriever_whithout_puppet_use_environment_api_and_environmentpath_present + configuration = LegacyProviderConfigurationForTesting.new(:master => {}, :main => {:environmentpath => ["a/path"]}) + assert_equal :config_file, configuration.load_programmable_settings(:puppet_version => "3.2")[:environments_retriever] + end +end + +class PuppetLegacyDefaultSettingsTest < Test::Unit::TestCase + def test_default_settings + Proxy::PuppetLegacy::Plugin.load_test_settings({}) + assert_equal '/var/lib/puppet/ssl/certs/ca.pem', Proxy::PuppetLegacy::Plugin.settings.puppet_ssl_ca + assert_equal '/etc/puppet/puppet.conf', Proxy::PuppetLegacy::Plugin.settings.puppet_conf + assert Proxy::PuppetLegacy::Plugin.settings.use_cache + end +end + +require 'puppet_proxy_common/environments_retriever_base' +require 'puppet_proxy_legacy/class_scanner_base' +require 'puppet_proxy_legacy/initializer' + +class PuppetLegacyDIWiringsTest < Test::Unit::TestCase + def setup + @configuration = ::Proxy::PuppetLegacy::PluginConfiguration.new + @container = ::Proxy::DependencyInjection::Container.new + end + + def test_apiv2_environments_retriever_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, :environments_retriever => :api_v2, + :puppet_url => "http://puppet.url", + :puppet_ssl_ca => "path_to_ca_cert", + :puppet_ssl_cert => "path_to_ssl_cert", + :puppet_ssl_key => "path_to_ssl_key") + + assert @container.get_dependency(:environment_retriever_impl).instance_of?(::Proxy::PuppetLegacy::PuppetApiV2EnvironmentsRetriever) + assert_equal "http://puppet.url", @container.get_dependency(:environment_retriever_impl).puppet_url + assert_equal "path_to_ca_cert", @container.get_dependency(:environment_retriever_impl).ssl_ca + assert_equal "path_to_ssl_cert", @container.get_dependency(:environment_retriever_impl).ssl_cert + assert_equal "path_to_ssl_key", @container.get_dependency(:environment_retriever_impl).ssl_key + end + + def test_puppet_configuration_wiring + @configuration.load_dependency_injection_wirings(@container, :environments_retriever => :config_file, + :puppet_conf => "path_to_puppet_conf") + + assert @container.get_dependency(:puppet_configuration).instance_of?(Proxy::PuppetLegacy::ConfigReader) + end + + def test_config_environments_retriever_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, :environments_retriever => :config_file, + :puppet_conf => "path_to_puppet_conf") + + assert @container.get_dependency(:environment_retriever_impl).instance_of?(::Proxy::PuppetLegacy::PuppetConfigEnvironmentsRetriever) + assert_not_nil @container.get_dependency(:environment_retriever_impl).puppet_configuration + assert_equal "path_to_puppet_conf", @container.get_dependency(:environment_retriever_impl).puppet_config_file_path + end + + def test_puppet_initializer_wiring + @configuration.load_dependency_injection_wirings(@container, :puppet_conf => "path_to_puppet_conf") + assert @container.get_dependency(:puppet_initializer).instance_of?(Proxy::PuppetLegacy::Initializer) + end + + def test_cached_future_parser_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, :classes_retriever => :cached_future_parser) + + assert @container.get_dependency(:class_retriever_impl).instance_of?(::Proxy::PuppetLegacy::PuppetCache) + assert_not_nil @container.get_dependency(:class_retriever_impl).environments_retriever + assert @container.get_dependency(:class_retriever_impl).class_parser.instance_of?(::Proxy::PuppetLegacy::ClassScannerEParser) + end + + def test_cached_legacy_parser_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, :classes_retriever => :cached_legacy_parser) + + assert @container.get_dependency(:class_retriever_impl).instance_of?(::Proxy::PuppetLegacy::PuppetCache) + assert_not_nil @container.get_dependency(:class_retriever_impl).environments_retriever + assert @container.get_dependency(:class_retriever_impl).class_parser.instance_of?(::Proxy::PuppetLegacy::ClassScanner) + end + + def test_future_parser_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, :classes_retriever => :future_parser) + + assert @container.get_dependency(:class_retriever_impl).instance_of?(::Proxy::PuppetLegacy::ClassScannerEParser) + assert_not_nil @container.get_dependency(:class_retriever_impl).environments_retriever + assert_not_nil @container.get_dependency(:class_retriever_impl).puppet_initializer + end + + def test_legacy_parser_wiring_parameters + @configuration.load_dependency_injection_wirings(@container, :classes_retriever => :legacy_parser) + + assert @container.get_dependency(:class_retriever_impl).instance_of?(::Proxy::PuppetLegacy::ClassScanner) + assert_not_nil @container.get_dependency(:class_retriever_impl).environments_retriever + assert_not_nil @container.get_dependency(:class_retriever_impl).puppet_initializer + end +end diff --git a/test/puppet/puppet_runtime_configuration_test.rb b/test/puppet/puppet_runtime_configuration_test.rb deleted file mode 100644 index f0cdfa582..000000000 --- a/test/puppet/puppet_runtime_configuration_test.rb +++ /dev/null @@ -1,82 +0,0 @@ -require 'test_helper' -require 'puppet/puppet_test_helper' -require 'puppet_proxy/runtime_configuration' - -class PuppetRuntimeConfigurationForTesting - include Proxy::Puppet::RuntimeConfiguration - attr_accessor :puppet_configuration - attr_accessor :puppet_version -end - -class PuppetRuntimeConfigurationTest < Test::Unit::TestCase - def setup - @configuration = PuppetRuntimeConfigurationForTesting.new - end - - def test_should_use_environment_api_with_environmentpath_set_main - @configuration.puppet_version = "3.5" - @configuration.puppet_configuration = { :main => {:environmentpath => '/etc' }} - assert_equal :api_v2, @configuration.environments_retriever - end - - def test_should_use_environment_api_with_environmentpath_set_master - @configuration.puppet_version = "3.5" - @configuration.puppet_configuration = { :master => {:environmentpath => '/etc'}} - assert_equal :api_v2, @configuration.environments_retriever - end - - def test_should_not_use_environment_api_with_no_environmentpath - @configuration.puppet_version = "3.5" - @configuration.puppet_configuration = {} - assert_equal :config_file, @configuration.environments_retriever - end - - def test_should_not_use_environment_api_when_override_is_set_to_false - Proxy::Puppet::Plugin.load_test_settings(:puppet_use_environment_api => false) - @configuration.puppet_version = "3.5" - @configuration.puppet_configuration = { :main => {:environmentpath => '/etc' }} - - assert_equal :config_file, @configuration.environments_retriever - end - - def test_should_use_environment_api_when_override_is_set_to_true - Proxy::Puppet::Plugin.load_test_settings(:puppet_use_environment_api => true) - @configuration.puppet_version = "3.5" - @configuration.puppet_configuration = {} - - assert_equal :api_v2, @configuration.environments_retriever - end - - def test_should_use_config_file_environments_for_puppet_older_than_3_2 - @configuration.puppet_version = "3.0" - @configuration.puppet_configuration = {} - assert_equal :config_file, @configuration.environments_retriever - end - - def test_should_use_api_v3_for_puppet_4 - @configuration.puppet_version = "4.0" - @configuration.puppet_configuration = {} - assert_equal :api_v3, @configuration.environments_retriever - end - - def test_should_use_future_parser_for_puppet_4 - @configuration.puppet_version = "4.0" - assert_equal :future_parser, @configuration.puppet_parser - end - - def test_should_use_future_parser_if_enabled_in_main_config - @configuration.puppet_configuration = { :main => {:parser => 'future' }} - assert_equal :future_parser, @configuration.puppet_parser - end - - def test_should_use_future_parser_if_enabled_in_master_config - @configuration.puppet_configuration = { :master => {:parser => 'future' }} - assert_equal :future_parser, @configuration.puppet_parser - end - - def test_should_use_legacy_parser_otherwise - @configuration.puppet_version = "3.5" - @configuration.puppet_configuration = {} - assert_equal :legacy_parser, @configuration.puppet_parser - end -end diff --git a/test/puppet/puppet_test_helper.rb b/test/puppet/puppet_test_helper.rb deleted file mode 100644 index e38c81740..000000000 --- a/test/puppet/puppet_test_helper.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'puppet_proxy/puppet' -require 'puppet_proxy/initializer' - -Proxy::Puppet::Plugin.load_test_settings(:puppet_conf => './test/fixtures/puppet.conf') -Proxy::Puppet::Initializer.new.reset_puppet diff --git a/test/puppet/puppetrun_test.rb b/test/puppet/puppetrun_test.rb index c1143de73..bb26a0897 100644 --- a/test/puppet/puppetrun_test.rb +++ b/test/puppet/puppetrun_test.rb @@ -1,38 +1,39 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/puppetrun' +require 'puppet_proxy_common/runner' +require 'puppet_proxy_puppetrun/puppet_proxy_puppetrun' +require 'puppet_proxy_puppetrun/puppetrun_main' class PuppetRunTest < Test::Unit::TestCase def setup - @puppetrun = Proxy::Puppet::PuppetRun.new(:nodes => ["host1", "host2"]) + @puppetrun = Proxy::PuppetRun::Runner.new(nil) end - + def test_command_line_with_puppet @puppetrun.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @puppetrun.stubs(:which).with("puppet", anything).returns("/usr/sbin/puppet") @puppetrun.stubs(:which).with("puppetrun", anything).returns(false) - + @puppetrun.expects(:shell_command).with(["/usr/bin/sudo", "/usr/sbin/puppet", "kick", "--host", "host1", "--host", "host2"]).returns(true) - assert @puppetrun.run + assert @puppetrun.run(["host1", "host2"]) end - + def test_command_line_with_puppet_and_puppet_user + @puppetrun = Proxy::PuppetRun::Runner.new("example") @puppetrun.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @puppetrun.stubs(:which).with("puppet", anything).returns("/usr/sbin/puppet") @puppetrun.stubs(:which).with("puppetrun", anything).returns(false) - Proxy::Puppet::Plugin.settings.stubs(:puppet_user).returns("example") - + @puppetrun.expects(:shell_command).with(["/usr/bin/sudo", "-u", "example", "/usr/sbin/puppet", "kick", "--host", "host1", "--host", "host2"]).returns(true) - assert @puppetrun.run + assert @puppetrun.run(["host1", "host2"]) end - + def test_command_line_with_puppetrun @puppetrun.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @puppetrun.stubs(:which).with("puppetrun", anything).returns("/usr/sbin/puppetrun") @puppetrun.stubs(:which).with("puppet", anything).returns(false) @puppetrun.expects(:shell_command).with(["/usr/bin/sudo", "/usr/sbin/puppetrun", "--host", "host1", "--host", "host2"]).returns(true) - assert @puppetrun.run + assert @puppetrun.run(["host1", "host2"]) end def test_missing_sudo @@ -40,14 +41,23 @@ def test_missing_sudo @puppetrun.stubs(:which).with("puppetrun", anything).returns("/usr/sbin/puppetrun") @puppetrun.stubs(:which).with("puppet", anything).returns(false) - assert !@puppetrun.run + assert !@puppetrun.run(["host1", "host2"]) end - + def test_missing_puppet @puppetrun.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") @puppetrun.stubs(:which).with("puppetrun", anything).returns(false) @puppetrun.stubs(:which).with("puppet", anything).returns(false) - assert !@puppetrun.run + assert !@puppetrun.run(["host1", "host2"]) + end +end + +class PuppetRunConfigurationTest < Test::Unit::TestCase + def test_di_wiring_parameters + container = ::Proxy::DependencyInjection::Container.new + ::Proxy::PuppetRun::PluginConfiguration.new.load_dependency_injection_wirings(container, :user => "a_user") + + assert_equal "a_user", container.get_dependency(:puppet_runner_impl).user end end diff --git a/test/puppet/puppetsalt_test.rb b/test/puppet/puppetsalt_test.rb index 5949adfb6..2b218c221 100644 --- a/test/puppet/puppetsalt_test.rb +++ b/test/puppet/puppetsalt_test.rb @@ -1,9 +1,11 @@ require 'test_helper' -require 'puppet_proxy/salt' +require 'puppet_proxy_salt/puppet_proxy_salt' +require 'puppet_proxy_common/runner' +require 'puppet_proxy_salt/salt_main' class PuppetSaltTest < Test::Unit::TestCase def setup - @salt = Proxy::Puppet::Salt.new(:nodes => ['host1', 'host2']) + @salt = Proxy::PuppetSalt::Runner.new("puppet.run") end def test_command_line_with_default_command @@ -11,18 +13,31 @@ def test_command_line_with_default_command @salt.stubs(:which).with('salt', anything).returns('/usr/bin/salt') @salt.expects(:shell_command).with(['/usr/bin/sudo', '/usr/bin/salt', '-L', 'host1,host2', 'puppet.run']).returns(true) - assert @salt.run + assert @salt.run(['host1', 'host2']) end def test_missing_sudo @salt.stubs(:which).with('sudo', anything).returns(false) @salt.stubs(:which).with('salt', anything).returns('/usr/bin/salt') - assert !@salt.run + assert !@salt.run(['host1', 'host2']) end def test_missing_salt @salt.stubs(:which).with('sudo', anything).returns('/usr/bin/sudo') @salt.stubs(:which).with('salt', anything).returns(false) - assert !@salt.run + assert !@salt.run(['host1', 'host2']) + end +end + +class PuppetSaltConfigurationTest < Test::Unit::TestCase + def test_di_wiring_parameters + container = ::Proxy::DependencyInjection::Container.new + ::Proxy::PuppetSalt::PluginConfiguration.new.load_dependency_injection_wirings(container, :command => "a_command") + + assert_equal "a_command", container.get_dependency(:puppet_runner_impl).command + end + + def test_plugin_default_parameters + assert_equal({:command => "puppet.run"}, ::Proxy::PuppetSalt::Plugin.default_settings) end end diff --git a/test/puppet/puppetssh_test.rb b/test/puppet/puppetssh_test.rb index 27650c3c9..7c91fe33d 100644 --- a/test/puppet/puppetssh_test.rb +++ b/test/puppet/puppetssh_test.rb @@ -1,119 +1,139 @@ require 'test_helper' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/puppet_ssh' +require 'puppet_proxy_ssh/puppet_proxy_ssh' +require 'puppet_proxy_common/runner' +require 'puppet_proxy_ssh/puppet_proxy_ssh_main' class PuppetSshTest < Test::Unit::TestCase - def setup - @puppetssh = Proxy::Puppet::PuppetSSH.new(:nodes => ["host1", "host2"]) - end - def test_command_line_with_default_command - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + puppetssh = Proxy::PuppetSsh::Runner.new("puppet agent --onetime --no-usecacheonfailure", nil, nil, false, false) + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") command = if RUBY_VERSION <= '1.8.7' "puppet\\ agent\\ --onetime\\ --no-usecacheonfailure" else "puppet agent --onetime --no-usecacheonfailure" end - @puppetssh. + + puppetssh. expects(:shell_command). with(["/usr/bin/ssh", "host1", command], false). returns(true) - @puppetssh. + puppetssh. expects(:shell_command). with(["/usr/bin/ssh", "host2", command], false). returns(true) - assert @puppetssh.run + assert puppetssh.run(["host1", "host2"]) end def test_command_line_with_sudo - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_sudo).returns(true) - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_command).returns('/bin/true') - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - - @puppetssh.expects(:shell_command).with(["/usr/bin/sudo", "/usr/bin/ssh", "host1", "/bin/true"], false).returns(true) - @puppetssh.expects(:shell_command).with(["/usr/bin/sudo", "/usr/bin/ssh", "host2", "/bin/true"], false).returns(true) - assert @puppetssh.run + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, nil, true, false) + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + + puppetssh.expects(:shell_command).with(["/usr/bin/sudo", "/usr/bin/ssh", "host1", "/bin/true"], false).returns(true) + puppetssh.expects(:shell_command).with(["/usr/bin/sudo", "/usr/bin/ssh", "host2", "/bin/true"], false).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_command_line_with_ssh_keyfile - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_keyfile).returns('/root/.ssh/id_rsa') - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_command).returns('/bin/true') + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, '/root/.ssh/id_rsa', false, false) File.stubs(:exist?).returns(true) - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-i", "/root/.ssh/id_rsa", "host1", "/bin/true"], false).returns(true) - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-i", "/root/.ssh/id_rsa", "host2", "/bin/true"], false).returns(true) - assert @puppetssh.run + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-i", "/root/.ssh/id_rsa", "host1", "/bin/true"], false).returns(true) + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-i", "/root/.ssh/id_rsa", "host2", "/bin/true"], false).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_command_line_with_ssh_keyfile_that_doesnt_exists - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_keyfile).returns('/root/.ssh/id_rsa') - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_command).returns('/bin/true') + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, '/root/.ssh/id_rsa', false, false) File.stubs(:exists?).returns(false) - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host1", "/bin/true"], false).returns(true) - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host2", "/bin/true"], false).returns(true) - assert @puppetssh.run + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host1", "/bin/true"], false).returns(true) + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host2", "/bin/true"], false).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_command_line_with_ssh_username - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_user).returns('root') - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_command).returns('/bin/true') - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-l", "root", "host1", "/bin/true"], false).returns(true) - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-l", "root", "host2", "/bin/true"], false).returns(true) - assert @puppetssh.run + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", 'root', nil, false, false) + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-l", "root", "host1", "/bin/true"], false).returns(true) + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "-l", "root", "host2", "/bin/true"], false).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_command_line_without_sudo - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_command).returns('/bin/true') - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, nil, false, false) + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host1", "/bin/true"], false).returns(true) - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host2", "/bin/true"], false).returns(true) - assert @puppetssh.run + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host1", "/bin/true"], false).returns(true) + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host2", "/bin/true"], false).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_command_line_with_puppetssh_wait - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_command).returns('/bin/true') - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_wait).returns(true) - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host1", "/bin/true"], true).returns(true) - @puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host2", "/bin/true"], true).returns(true) - assert @puppetssh.run + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, nil, false, true) + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host1", "/bin/true"], true).returns(true) + puppetssh.expects(:shell_command).with(["/usr/bin/ssh", "host2", "/bin/true"], true).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_missing_sudo - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_sudo).returns(true) - @puppetssh.stubs(:which).with("sudo", anything).returns(false) - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - @puppetssh.stubs(:shell_command).returns(true) - assert !@puppetssh.run + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, nil, true, false) + puppetssh.stubs(:which).with("sudo", anything).returns(false) + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + puppetssh.stubs(:shell_command).returns(true) + assert !puppetssh.run(["host1", "host2"]) end def test_missing_sudo_and_not_needed - Proxy::Puppet::Plugin.settings.stubs(:puppetssh_sudo).returns(false) - @puppetssh.stubs(:which).with("sudo", anything).returns(false) - @puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") - @puppetssh.stubs(:shell_command).returns(true) - assert @puppetssh.run + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, nil, false, false) + puppetssh.stubs(:which).with("sudo", anything).returns(false) + puppetssh.stubs(:which).with("ssh", anything).returns("/usr/bin/ssh") + puppetssh.stubs(:shell_command).returns(true) + assert puppetssh.run(["host1", "host2"]) end def test_missing_ssh - @puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") - @puppetssh.stubs(:which).with("ssh", anything).returns(false) + puppetssh = Proxy::PuppetSsh::Runner.new("/bin/true", nil, nil, false, false) + puppetssh.stubs(:which).with("sudo", anything).returns("/usr/bin/sudo") + puppetssh.stubs(:which).with("ssh", anything).returns(false) + + assert !puppetssh.run(["host1", "host2"]) + end +end + +class PuppetSshConfigurationTest < Test::Unit::TestCase + def test_di_wiring_parameters + container = ::Proxy::DependencyInjection::Container.new + ::Proxy::PuppetSsh::PluginConfiguration.new.load_dependency_injection_wirings(container, + :command => 'a_command', + :use_sudo => true, + :wait => true, + :keyfile => 'a_keyfile', + :user => "a_user") + + assert_equal "a_command", container.get_dependency(:puppet_runner_impl).command + assert_equal "a_user", container.get_dependency(:puppet_runner_impl).user + assert_equal "a_keyfile", container.get_dependency(:puppet_runner_impl).keyfile_path + assert_equal true, container.get_dependency(:puppet_runner_impl).use_sudo + assert_equal true, container.get_dependency(:puppet_runner_impl).wait_for_command_to_finish + end - assert !@puppetssh.run + def test_default_settings + Proxy::PuppetSsh::Plugin.load_test_settings({}) + assert_equal 'puppet agent --onetime --no-usecacheonfailure', Proxy::PuppetSsh::Plugin.settings.command + assert !Proxy::PuppetSsh::Plugin.settings.use_sudo + assert !Proxy::PuppetSsh::Plugin.settings.wait end end diff --git a/test/puppet/runner_test.rb b/test/puppet/runner_test.rb index 5e70503b4..9a3bb9487 100644 --- a/test/puppet/runner_test.rb +++ b/test/puppet/runner_test.rb @@ -1,22 +1,20 @@ require 'test_helper' -require 'puppet_proxy/runner' +require 'puppet_proxy_common/runner' class RunnerTest < Test::Unit::TestCase def setup - @runner = Proxy::Puppet::Runner.new(:nodes => ['foo', 'bar', 'foo bar']) + @runner = Proxy::Puppet::Runner.new end def test_shell_escaped_nodes - assert_equal ['foo', 'bar', 'foo\ bar'], @runner.send(:shell_escaped_nodes) + assert_equal ['foo', 'bar', 'foo\ bar'], @runner.shell_escaped_nodes(['foo', 'bar', 'foo bar']) end def test_shell_command_true - success = @runner.send(:shell_command, ['true']) - assert_equal true, success + assert @runner.shell_command(['true']) end def test_shell_command_false - success = @runner.send(:shell_command, ['false']) - assert_equal false, success + assert !@runner.shell_command(['false']) end end diff --git a/test/puppet/ssl_configuration_validator_test.rb b/test/puppet/ssl_configuration_validator_test.rb deleted file mode 100644 index f3e425b6f..000000000 --- a/test/puppet/ssl_configuration_validator_test.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'test_helper' -require 'puppet_proxy/puppet' -require 'puppet_proxy/puppet_plugin' -require 'puppet_proxy/ssl_configuration_validator' - -class SslConfigurationValidatorForTesting < ::Proxy::Puppet::SslConfigurationValidator - attr_accessor :environments_retriever, :certname -end - -class SslConfigurationValidatorTest < Test::Unit::TestCase - def setup - @ssl_config_validator = SslConfigurationValidatorForTesting.new - @ssl_config_validator.environments_retriever = :api_v2 - end - - def test_should_fail_when_ssl_key_is_not_readable - Proxy::Puppet::Plugin.load_test_settings( - :puppet_ssl_ca => certs_path('puppet_ca.pem'), - :puppet_ssl_cert => certs_path('foreman.example.com.cert'), - :puppet_ssl_key => 'non_existent_key') - - assert_raises ::Proxy::Error::ConfigurationError do - @ssl_config_validator.validate_ssl_paths! - end - end - - def test_should_fail_when_ssl_cert_is_not_readable - Proxy::Puppet::Plugin.load_test_settings( - :puppet_ssl_ca => certs_path('puppet_ca.pem'), - :puppet_ssl_cert => 'non_existent_cert', - :puppet_ssl_key => certs_path('foreman.example.com.key')) - - assert_raises ::Proxy::Error::ConfigurationError do - @ssl_config_validator.validate_ssl_paths! - end - - end - - def test_should_fail_when_ca_cert_is_not_readable - Proxy::Puppet::Plugin.load_test_settings( - :puppet_ssl_ca => 'non_existent_ca_cert', - :puppet_ssl_cert => certs_path('foreman.example.com.cert'), - :puppet_ssl_key => certs_path('foreman.example.com.key')) - - assert_raises ::Proxy::Error::ConfigurationError do - @ssl_config_validator.validate_ssl_paths! - end - end - - def test_should_pass_if_config_file_environments_are_used - @ssl_config_validator.environments_retriever = :config_file - assert @ssl_config_validator.validate_ssl_paths! - end - - def test_should_pass_if_ssl_files_are_readable - Proxy::Puppet::Plugin.load_test_settings( - :puppet_ssl_ca => certs_path('puppet_ca.pem'), - :puppet_ssl_cert => certs_path('foreman.example.com.cert'), - :puppet_ssl_key => certs_path('foreman.example.com.key')) - - assert @ssl_config_validator.validate_ssl_paths! - end - - def test_default_ssl_cert_path - @ssl_config_validator.certname = 'test' - assert_equal '/var/lib/puppet/ssl/certs/test.pem', @ssl_config_validator.ssl_cert - end - - def test_default_ssl_key_path - @ssl_config_validator.certname = 'test' - assert_equal '/var/lib/puppet/ssl/private_keys/test.pem', @ssl_config_validator.ssl_key - end - - def certs_path(relative_path) - File.expand_path(relative_path, File.expand_path('../fixtures/authentication', __FILE__)) - end -end