Permalink
Browse files

Fixes #7008: dns providers are now plugins

  • Loading branch information...
dmitri-d authored and Dominic Cleal committed Feb 6, 2015
1 parent e9a0235 commit d905c67c1067696000b0ff4fefde711c99f9e731
Showing with 753 additions and 295 deletions.
  1. +1 −0 .gitignore
  2. +23 −0 Rakefile
  3. +6 −12 config/settings.d/dns.yml.example
  4. +7 −0 config/settings.d/dns_dnscmd.yml.example
  5. +8 −0 config/settings.d/dns_nsupdate.yml.example
  6. +11 −0 config/settings.d/dns_nsupdate_gss.yml.example
  7. +8 −0 config/settings.d/dns_virsh.yml.example
  8. +21 −6 extra/migrate_settings.rb
  9. +1 −1 extra/migrations/20150327000000_migrate_monolithic_config.rb
  10. +73 −0 extra/migrations/20150611000000_migrate_dns_settings.rb
  11. +112 −0 lib/proxy/pluggable.rb
  12. +59 −95 lib/proxy/plugin.rb
  13. +30 −0 lib/proxy/provider.rb
  14. +8 −0 lib/proxy/provider_factory.rb
  15. +1 −1 lib/proxy/settings.rb
  16. +7 −0 lib/smart_proxy.rb
  17. +3 −0 lib/smart_proxy_for_testing.rb
  18. +1 −30 modules/dns/dns_api.rb
  19. +4 −3 modules/dns/dns_plugin.rb
  20. +1 −0 modules/dns_dnscmd/dns_dnscmd.rb
  21. +33 −28 modules/{dns/providers/dnscmd.rb → dns_dnscmd/dns_dnscmd_main.rb}
  22. +14 −0 modules/dns_dnscmd/dns_dnscmd_plugin.rb
  23. +1 −0 modules/dns_nsupdate/dns_nsupdate.rb
  24. +1 −0 modules/dns_nsupdate/dns_nsupdate_gss.rb
  25. +3 −3 modules/{dns/providers/nsupdate_gss.rb → dns_nsupdate/dns_nsupdate_gss_main.rb}
  26. +17 −0 modules/dns_nsupdate/dns_nsupdate_gss_plugin.rb
  27. +15 −10 modules/{dns/providers/nsupdate.rb → dns_nsupdate/dns_nsupdate_main.rb}
  28. +14 −0 modules/dns_nsupdate/dns_nsupdate_plugin.rb
  29. +1 −0 modules/dns_virsh/dns_virsh.rb
  30. +7 −2 modules/{dns/providers/virsh.rb → dns_virsh/dns_virsh_main.rb}
  31. +12 −0 modules/dns_virsh/dns_virsh_plugin.rb
  32. +1 −27 test/dns/dns_config_test.rb
  33. +0 −62 test/dns/dns_update_test.rb
  34. +32 −0 test/dns_nsupdate/dns_nsupdate_config_test.rb
  35. +26 −0 test/dns_nsupdate/dns_nsupdate_test.rb
  36. +40 −0 test/dns_virsh/dns_virsh_test.rb
  37. +46 −0 test/migrations/dns_migration_test.rb
  38. +13 −0 test/migrations/migration_dns_settings.yml
  39. +37 −8 test/migrations/migration_test.rb
  40. +54 −0 test/plugin_test.rb
  41. +1 −7 test/root/root_api_test.rb
@@ -3,6 +3,7 @@ tags
config/settings.yml
config/settings.d/*.yml
config/migration_state
config_*/*
.idea
logs
*swp
@@ -1,6 +1,10 @@
require 'rake'
require 'rake/testtask'
require 'rdoc/task'
require 'fileutils'
require 'tmpdir'
require File.join(File.dirname(__FILE__),'extra/migrate_settings')

load 'tasks/proxy_tasks.rake'
load 'tasks/jenkins.rake'
load 'tasks/pkg.rake'
@@ -37,3 +41,22 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end

desc 'Migrate configuration settings.'
task :migrate_settings do
app_dir = File.dirname(__FILE__)
config_src_path = File.join(app_dir, "config", "settings.yml")
modules_config_src_path = File.join(app_dir, "config", "settings.d")
migrations_dir_path = File.join(app_dir, "extra", "migrations")
migrations_state_file_path = File.join(app_dir, "config", "migration_state")
FileUtils.touch(migrations_state_file_path)

Dir.mktmpdir do |working_dir|
::Proxy::Migrator.new(
working_dir, migrations_dir_path, config_src_path, modules_config_src_path,
::Proxy::Migrations.new(migrations_state_file_path).load_past_migrations!).migrate

FileUtils.mv(File.join(app_dir, "config"), File.join(app_dir, "config_#{Time.now.strftime("%Y%m%d%H%M%S")}"))
FileUtils.mv(File.join(working_dir, "result"), File.join(app_dir, "config"))
end
end
@@ -3,17 +3,11 @@
:enabled: false

# Valid providers:
# nsupdate
# nsupdate_gss (for GSS-TSIG support)
# virsh
# dnscmd
#:dns_provider: nsupdate
#:dns_key: /etc/rndc.key
# use this setting if you are managing a dns server which is not localhost though this proxy
#:dns_server: dns.domain.com
# dns_nsupdate
# dns_nsupdate_gss (for GSS-TSIG support)
# dns_virsh
# dns_dnscmd
#:use_provider: dns_nsupdate
# use this setting if you want to override default TTL setting (86400)
#:dns_ttl: 86400
# use dns_tsig_* for GSS-TSIG updates using Kerberos. Required for Windows MS DNS with
# Secure Dynamic Updates, or BIND as used in FreeIPA. Set dns_provider to nsupdate_gss.
#:dns_tsig_keytab: /usr/share/foreman-proxy/dns.keytab
#:dns_tsig_principal: DNS/host.example.com@EXAMPLE.COM

@@ -0,0 +1,7 @@
---
#
# Configuration file for Windows-specific 'dnscmd' dns provider
#

# use this setting if you are managing a dns server which is not localhost though this proxy
#:dns_server: dns.domain.com
@@ -0,0 +1,8 @@
---
#
# Configuration file for 'nsupdate' dns provider
#

#:dns_key: /etc/rndc.key
# use this setting if you are managing a dns server which is not localhost though this proxy
#:dns_server: dns.domain.com
@@ -0,0 +1,11 @@
---
#
# Configuration file for 'nsupdate_gss' dns provider with GSS-TSIG support
#

# use this setting if you are managing a dns server which is not localhost though this proxy
#:dns_server: dns.domain.com
# use dns_tsig_* for GSS-TSIG updates using Kerberos. Required for Windows MS DNS with
# Secure Dynamic Updates, or BIND as used in FreeIPA. Set dns_provider to nsupdate_gss.
#:dns_tsig_keytab: /usr/share/foreman-proxy/dns.keytab
#:dns_tsig_principal: DNS/host.example.com@EXAMPLE.COM
@@ -0,0 +1,8 @@
---
#
# Configuration file for libvirtd-specific 'virsh' dns provider
#
# There's currently no configuration options for this provider.
# Virsh network name is a global parameter that can be set
# in the main settings.yml file in 'virsh_network' parameter.
#
@@ -69,6 +69,26 @@ def dst_dir
File.join(migration_dir, "dst")
end

def path(*segments)
File.join(segments)
end

def duplicate_original_configuration
FileUtils.cp_r(path(src_dir, '.'), dst_dir)
end

def copy_original_configuration_except(*exceptions)
FileUtils.cp_r(Dir.glob(path(src_dir, "*.yml")) - exceptions.map { |e| path(src_dir, e) }, dst_dir)
FileUtils.cp_r(
Dir.glob(path(src_dir, "settings.d", "*.*")) - exceptions.map { |e| path(src_dir, e) },
path(dst_dir, "settings.d"))
end

def create_migration_dirs
FileUtils.mkdir_p(src_dir)
FileUtils.mkdir_p(File.join(dst_dir, "settings.d"))
end

def underscore(src)
src = src.gsub(/::/, '/')
src = src.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
@@ -117,7 +137,7 @@ def execute_migrations(migrations)
m = migration.new(working_dir_path)
puts "#{m.migration_name}"

create_migration_dirs(m.src_dir, m.dst_dir)
m.create_migration_dirs
if migration == migrations.first
copy_original_configuration(m.src_dir)
else
@@ -159,11 +179,6 @@ def persist_migrations_state(migrations, path)
p "Couldn't save migration state: #{e}"
end

def create_migration_dirs(src_dir, dst_dir)
FileUtils.mkdir_p(src_dir)
FileUtils.mkdir_p(File.join(dst_dir, "settings.d"))
end

def copy_original_configuration(dst_dir)
FileUtils.cp(config_src_path, dst_dir)
if File.exist?(modules_config_src_path)
@@ -99,7 +99,7 @@ def migrate_monolithic_config(data)
def write_to_files(output,unknown)
modules.each do |m|
next if output[m] == {}
filepath = m == :settings ? File.join(dst_dir, "settings.yml") : File.join(File.join(dst_dir, "settings.d"), "#{m}.yml")
filepath = m == :settings ? File.join(dst_dir, "settings.yml") : path(dst_dir, "settings.d", "#{m}.yml")
File.open(filepath,'w') do |f|
f.write(output[m].to_yaml)
if m == :settings && unknown != {}
@@ -0,0 +1,73 @@
require 'yaml'

class MigrateDnsSettings < ::Proxy::Migration
def migrate
dns_config = path(src_dir, "settings.d", "dns.yml")
if !File.exist?(dns_config)
duplicate_original_configuration
return
end

to_migrate = YAML.load_file(dns_config)
output, unknown = migrate_dns_configuration(to_migrate)
copy_original_configuration_except(path("settings.d", "dns.yml"))
write_to_files(output, unknown)
end

def known_dns_options
{
:enabled => [:dns],
:dns_provider => [:dns],
:dns_key => [:dns_nsupdate],
:dns_server => [:dns_nsupdate, :dns_nsupdate_gss, :dns_dnscmd],
:dns_ttl => [:dns],
:dns_tsig_keytab => [:dns_nsupdate_gss],
:dns_tsig_principal => [:dns_nsupdate_gss]
}
end

def migrate_dns_configuration(data)
output = Hash.new { |h,k| h[k] = Hash.new }

data.each do |option, value|
if known_dns_options.include? option
module_names = known_dns_options[option]
module_names.each do |m|
if option == :dns_provider
output[m][:use_provider] = recognized_dns_provider_name?(value) ? migrate_dns_provider_name(value) : value
else
output[m][option] = value
end
end
data.delete(option)
end
end

return output, data
end

def migrate_dns_provider_name(aname)
if recognized_dns_provider_name?(aname)
'dns_' + aname
else
aname
end
end

def recognized_dns_provider_name?(aname)
['nsupdate', 'nsupdate_gss', 'virsh', 'dnscmd'].include?(aname)
end

def write_to_files(output, unknown)
output.keys.each do |m|
next if output[m] == {}
File.open(path(dst_dir, "settings.d", "#{m}.yml"),'w') do |f|
f.write(output[m].to_yaml)
if m == :dns && unknown != {}
f.write "\n# Unparsed options, please review\n"
f.write(unknown.to_yaml.gsub(/^---/,''))
end
end
end
end
end
@@ -0,0 +1,112 @@
module Proxy::Pluggable
def self.included(base)
base.send(:include, InstanceMethods)
base.send(:extend, ClassMethods)
end

module InstanceMethods
def plugin_name
self.class.plugin_name
end

def version
self.class.version
end

def bundler_group
self.class.bundler_group_name || self.plugin_name
end

def settings
self.class.settings
end

def log_used_default_settings
settings.defaults.select {|k,v| settings.used_defaults.include?(k)}.
inject({}) {|acc, c| acc[c[0].to_s] = c[1]; acc}.
sort.
collect {|c| ":#{c[0]}: #{c[1]}"}.
join(", ")
end

def after_activation
instance_eval(&self.class.after_activation_blk) if self.class.after_activation_blk
end

def validate!
validate_dependencies!(self.class.dependencies)
validate_prerequisites_enabled!(self.class.initialize_after)
end

def validate_prerequisites_enabled!(prerequisites)
prerequisites.each do |p|
if !(::Proxy::Plugins.find_plugin(p))
raise ::Proxy::PluginMisconfigured, "Unable to find dependency '#{p}' of '#{plugin_name}'."
end
if !(::Proxy::Plugins.plugin_enabled?(p))
raise ::Proxy::PluginMisconfigured, "Dependency '#{p}' of '#{plugin_name}' has not been enabled."
end
end
end

def validate_dependencies!(dependencies)
dependencies.each do |dep|
plugin = ::Proxy::Plugins.find_plugin(dep.name)
raise ::Proxy::PluginNotFound, "Plugin '#{dep.name}' required by plugin '#{plugin_name}' could not be found." unless plugin
unless ::Gem::Dependency.new('', dep.version).match?('', plugin.version)
raise ::Proxy::PluginVersionMismatch, "Available version '#{plugin.version}' of plugin '#{dep.name}' doesn't match version '#{dep.version}' required by plugin '#{plugin_name}'"
end
end
end
end

module ClassMethods
attr_reader :plugin_name, :version, :after_activation_blk, :plugin_default_settings, :bundler_group_name

def after_activation(&blk)
@after_activation_blk = blk
end

def dependencies
@dependencies ||= []
end

def requires(plugin_name, version_spec)
self.dependencies << ::Proxy::Dependency.new(plugin_name, version_spec.chomp('-develop'))
end

def bundler_group(name)
@bundler_group_name = name
end

# relative to ::Proxy::SETTINGS.settings_directory
def settings_file(apath = nil)
if apath.nil?
@settings_file || "#{plugin_name}.yml"
else
@settings = nil
@settings_file = apath
end
end

def default_settings(a_hash = {})
@settings = nil
@plugin_default_settings ||= {}
@plugin_default_settings.merge!(a_hash)
end

def settings
@settings ||= Proxy::Settings.load_plugin_settings(plugin_default_settings, settings_file)
end

def initialize_after(*module_names)
@initialize_after ||= []
if module_names.empty?
to_return = @uses_provider ? @initialize_after + [settings.use_provider] : @initialize_after
to_return.map(&:to_sym)
else
@initialize_after += module_names.map(&:to_sym)
end
end
end
end
Oops, something went wrong.

0 comments on commit d905c67

Please sign in to comment.