From 74132ec038a07dd8924cf9feea4b85b210736ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Mon, 19 Jan 2015 22:00:25 +0100 Subject: [PATCH] Add type & provider for managing plugins --- README.md | 12 ++++ lib/puppet/provider/mysql_plugin/mysql.rb | 53 ++++++++++++++ lib/puppet/type/mysql_plugin.rb | 17 +++++ spec/acceptance/types/mysql_plugin_spec.rb | 34 +++++++++ .../provider/mysql_plugin/mysql_spec.rb | 71 +++++++++++++++++++ spec/unit/puppet/type/mysql_plugin_spec.rb | 24 +++++++ tests/mysql_plugin.pp | 19 +++++ 7 files changed, 230 insertions(+) create mode 100644 lib/puppet/provider/mysql_plugin/mysql.rb create mode 100644 lib/puppet/type/mysql_plugin.rb create mode 100644 spec/acceptance/types/mysql_plugin_spec.rb create mode 100644 spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb create mode 100644 spec/unit/puppet/type/mysql_plugin_spec.rb create mode 100644 tests/mysql_plugin.pp diff --git a/README.md b/README.md index a29d6f111..d2bf3ce4d 100644 --- a/README.md +++ b/README.md @@ -566,6 +566,17 @@ mysql_grant { 'root@localhost/mysql.user': } ``` +####mysql_plugin + +`mysql_plugin` can be used to load plugins into the MySQL Server. + +```puppet +mysql_plugin { 'auth_socket': + ensure => 'present', + soname => 'auth_socket.so', +} +``` + ##Limitations This module has been tested on: @@ -603,4 +614,5 @@ This module is based on work by David Schmitt. The following contributors have c * William Van Hevelingen * Michael Arnold * Chris Weyl +* Daniƫl van Eeden diff --git a/lib/puppet/provider/mysql_plugin/mysql.rb b/lib/puppet/provider/mysql_plugin/mysql.rb new file mode 100644 index 000000000..2cb640bd8 --- /dev/null +++ b/lib/puppet/provider/mysql_plugin/mysql.rb @@ -0,0 +1,53 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_plugin).provide(:mysql, :parent => Puppet::Provider::Mysql) do + desc 'Manages MySQL plugins.' + + commands :mysql => 'mysql' + + def self.instances + mysql([defaults_file, '-NBe', 'show plugins'].compact).split("\n").collect do |line| + name, status, type, library, license = line.split(/\t/) + new(:name => name, + :ensure => :present, + :soname => library + ) + end + end + + # We iterate over each mysql_plugin entry in the catalog and compare it against + # the contents of the property_hash generated by self.instances + def self.prefetch(resources) + plugins = instances + resources.keys.each do |plugin| + if provider = plugins.find { |pl| pl.name == plugin } + resources[plugin].provider = provider + end + end + end + + def create + # Use plugin_name.so as soname if it's not specified. This won't work on windows as + # there it should be plugin_name.dll + @resource[:soname].nil? ? (soname=@resource[:name] + '.so') : (soname=@resource[:soname]) + mysql([defaults_file, '-NBe', "install plugin #{@resource[:name]} soname '#{soname}'"].compact) + + @property_hash[:ensure] = :present + @property_hash[:soname] = @resource[:soname] + + exists? ? (return true) : (return false) + end + + def destroy + mysql([defaults_file, '-NBe', "uninstall plugin #{@resource[:name]}"].compact) + + @property_hash.clear + exists? ? (return false) : (return true) + end + + def exists? + @property_hash[:ensure] == :present || false + end + + mk_resource_methods + +end diff --git a/lib/puppet/type/mysql_plugin.rb b/lib/puppet/type/mysql_plugin.rb new file mode 100644 index 000000000..e8279209f --- /dev/null +++ b/lib/puppet/type/mysql_plugin.rb @@ -0,0 +1,17 @@ +Puppet::Type.newtype(:mysql_plugin) do + @doc = 'Manage MySQL plugins.' + + ensurable + + autorequire(:file) { '/root/.my.cnf' } + + newparam(:name, :namevar => true) do + desc 'The name of the MySQL plugin to manage.' + end + + newproperty(:soname) do + desc 'The name of the library' + newvalue(/^\w+\.\w+$/) + end + +end diff --git a/spec/acceptance/types/mysql_plugin_spec.rb b/spec/acceptance/types/mysql_plugin_spec.rb new file mode 100644 index 000000000..338f060fc --- /dev/null +++ b/spec/acceptance/types/mysql_plugin_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper_acceptance' + +describe 'mysql_plugin' do + describe 'setup' do + it 'should work with no errors' do + pp = <<-EOS + class { 'mysql::server': } + EOS + + apply_manifest(pp, :catch_failures => true) + end + end + + describe 'load plugin' do + it 'should work without errors' do + pp = <<-EOS + mysql_plugin { 'auth_socket': + ensure => present, + soname => 'auth_socket.so', + } + EOS + + apply_manifest(pp, :catch_failures => true) + end + + it 'should find the plugin' do + shell("mysql -NBe \"select plugin_name from information_schema.plugins where plugin_name='auth_socket'\"") do |r| + expect(r.stdout).to match(/^auth_socket$/) + expect(r.stderr).to be_empty + end + end + end + +end diff --git a/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb b/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb new file mode 100644 index 000000000..340562ff8 --- /dev/null +++ b/spec/unit/puppet/provider/mysql_plugin/mysql_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe Puppet::Type.type(:mysql_plugin).provider(:mysql) do + + let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' } + + let(:resource) { Puppet::Type.type(:mysql_plugin).new( + { :ensure => :present, + :soname => 'auth_socket.so', + :name => 'auth_socket', + :provider => described_class.name + } + )} + let(:provider) { resource.provider } + + before :each do + Facter.stubs(:value).with(:root_home).returns('/root') + Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql') + File.stubs(:file?).with('/root/.my.cnf').returns(true) + provider.class.stubs(:mysql).with([defaults_file, '-NBe', 'show plugins']).returns('auth_socket ACTIVE AUTHENTICATION auth_socket.so GPL') + end + + let(:instance) { provider.class.instances.first } + + describe 'self.prefetch' do + it 'exists' do + provider.class.instances + provider.class.prefetch({}) + end + end + + describe 'create' do + it 'loads a plugin' do + provider.expects(:mysql).with([defaults_file, '-NBe', "install plugin #{resource[:name]} soname '#{resource[:soname]}'"]) + provider.expects(:exists?).returns(true) + expect(provider.create).to be_truthy + end + end + + describe 'destroy' do + it 'unloads a plugin if present' do + provider.expects(:mysql).with([defaults_file, '-NBe', "uninstall plugin #{resource[:name]}"]) + provider.expects(:exists?).returns(false) + expect(provider.destroy).to be_truthy + end + end + + describe 'exists?' do + it 'checks if plugin exists' do + expect(instance.exists?).to be_truthy + end + end + + describe 'self.defaults_file' do + it 'sets --defaults-extra-file' do + File.stubs(:file?).with('/root/.my.cnf').returns(true) + expect(provider.defaults_file).to eq '--defaults-extra-file=/root/.my.cnf' + end + it 'fails if file missing' do + File.stubs(:file?).with('/root/.my.cnf').returns(false) + expect(provider.defaults_file).to be_nil + end + end + + describe 'soname' do + it 'returns a soname' do + expect(instance.soname).to eq('auth_socket.so') + end + end + +end diff --git a/spec/unit/puppet/type/mysql_plugin_spec.rb b/spec/unit/puppet/type/mysql_plugin_spec.rb new file mode 100644 index 000000000..e94c518b7 --- /dev/null +++ b/spec/unit/puppet/type/mysql_plugin_spec.rb @@ -0,0 +1,24 @@ +require 'puppet' +require 'puppet/type/mysql_plugin' +describe Puppet::Type.type(:mysql_plugin) do + + before :each do + @plugin = Puppet::Type.type(:mysql_plugin).new(:name => 'test', :soname => 'test.so') + end + + it 'should accept a plugin name' do + expect(@plugin[:name]).to eq('test') + end + + it 'should accept a library name' do + @plugin[:soname] = 'test.so' + expect(@plugin[:soname]).to eq('test.so') + end + + it 'should require a name' do + expect { + Puppet::Type.type(:mysql_plugin).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + +end diff --git a/tests/mysql_plugin.pp b/tests/mysql_plugin.pp new file mode 100644 index 000000000..ab76fc266 --- /dev/null +++ b/tests/mysql_plugin.pp @@ -0,0 +1,19 @@ +class { 'mysql::server': + root_password => 'password' +} + +mysql::plugin{ 'validate_password': + ensure => present, + soname => $::osfamily ? { + windows => 'validate_password.dll', + default => 'validate_password.so' + } +} + +mysql::plugin{ 'auth_socket': + ensure => present, + soname => $::osfamily ? { + windows => 'auth_socket.dll', + default => 'auth_socket.so' + } +}