Major refactor of mysql module.

This is a major change to the module and would be released as a new
version.

* Add self.instances to database and database_user for puppet resource.
* Update database provider to use flush method.
* Update module to conform to puppet-lint recommendations.
* Cleanup some unecessary logic in mysql::db define type.
* Move mysql_restart to config class.
* Use class to class dependency instead of resource dependency.
* Change appropriate rspec-puppet tests.
* Add fixtures directory to simplify testing.
* Update raketask and spec_helper to reflect fixture changes.
* Update mysql_password function to support validation.
* Move client installation to a separate class.
* Update documentation and readme.
This commit is contained in:
Nan Liu 2012-02-09 11:26:00 -08:00
parent 1e926b4516
commit b1f90fd1d2
32 changed files with 541 additions and 426 deletions

View file

@ -1,5 +1,5 @@
name 'puppetlabs-mysql'
version '0.0.1'
version '0.1.0'
source 'git://github.com/puppetlabs/puppetlabs-mysql.git'
author 'Puppet Labs'
license 'Apache'

View file

@ -1,68 +1,83 @@
# Mysql module for Puppet
This module manages mysql on Linux (RedHat/Debian) distros. A native mysql provider implements database resource type to handle database, database user, and database permission.
## Description
This module has evolved and is originally based on work by David Schmitt.
If anyone else was involved in the development of this module
and wants credit, let Puppetlabs know.
This module is based on work by David Schmitt. The following contributor have contributed patches to this module (beyond Puppet Labs):
* Christian G. Warden
* Daniel Black
* Justin Ellison
* Lowe Schmidt
* Matthias Pigulla
* William Van Hevelingen
## Usage
### mysql
Installs the mysql-client package.
<pre>
class { 'mysql': }
</pre>
class { 'mysql': }
### mysql::python
Installs mysql bindings for python.
<pre>
class { 'mysql::python': }
</pre>
class { 'mysql::python': }
### mysql::ruby
Installs mysql bindings for ruby.
<pre>
class { 'mysql::ruby': }
</pre>
class { 'mysql::ruby': }
### mysql::server
Installs mysql-server, starts service, sets `root_pw`, and sets root.
<pre>
class { 'mysql::server':
config_hash => { 'root_password' => 'foo' }
}
</pre>
Installs mysql-server packages, configures my.cnf and starts mysqld service:
Login information in `/etc/.my.cnf` and `/root/.my.cnf`.
class { 'mysql::server':
config_hash => { 'root_password' => 'foo' }
}
Database login information stored in `/root/.my.cnf`.
### mysql::db
Creates a database with a user and assign some privileges.
<pre>
mysql::db { 'mydb':
user => 'myuser',
password => 'mypass',
host => 'localhost',
grant => ['all'],
}
</pre>
mysql::db { 'mydb':
user => 'myuser',
password => 'mypass',
host => 'localhost',
grant => ['all'],
}
### Providers for database types:
<pre>
database { 'mydb':
charset => 'latin1',
}
</pre>
MySQL provider supports puppet resources command:
<pre>
database_user { 'bob@localhost':
password_hash => mysql_password('foo')
}
</pre>
$ puppet resource database
database { 'information_schema':
ensure => 'present',
charset => 'utf8',
}
database { 'mysql':
ensure => 'present',
charset => 'latin1',
}
<pre>
database_grant { 'user@localhost/database':
privileges => ['all'] ,
}
</pre>
The custom resources can be used in any other manifests:
database { 'mydb':
charset => 'latin1',
}
database_user { 'bob@localhost':
password_hash => mysql_password('foo')
}
database_grant { 'user@localhost/database':
privileges => ['all'] ,
}
A resource default can be specified to handle dependency:
Database {
require => Class['mysql::server'],
}

View file

@ -1,14 +1,18 @@
require 'rubygems'
require 'rake'
require 'rspec/core/rake_task'
require 'fileutils'
begin
require 'rspec/core/rake_task'
HAVE_RSPEC = true
rescue LoadError
HAVE_RSPEC = false
task :default do
system("rake -T")
end
task :default => [:build]
desc "Run all rspec-puppet tests"
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = ['--color']
# ignores fixtures directory.
t.pattern = 'spec/{classes,defines,unit}/**/*_spec.rb'
end
def update_module_version
gitdesc = %x{git describe}.chomp
@ -39,9 +43,9 @@ task :clean do
FileUtils.rm_rf("pkg/")
end
if HAVE_RSPEC then
desc 'Run all module spec tests (Requires rspec-puppet gem)'
task :spec do
system 'rspec --format d spec/'
end
desc "Check puppet manifests with puppet-lint"
task :lint do
# This requires pull request: https://github.com/rodjek/puppet-lint/pull/81
system("puppet-lint manifests")
system("puppet-lint tests")
end

View file

@ -2,8 +2,14 @@
require 'digest/sha1'
module Puppet::Parser::Functions
newfunction(:mysql_password, :type => :rvalue) do |args|
'*' + Digest::SHA1.hexdigest(Digest::SHA1.digest(args[0])).upcase
end
end
newfunction(:mysql_password, :type => :rvalue, :doc => <<-EOS
Returns the mysql password hash from the clear text password.
EOS
) do |args|
raise(Puppet::ParseError, "mysql_password(): Wrong number of arguments " +
"given (#{args.size} for 1)") if args.size != 1
'*' + Digest::SHA1.hexdigest(Digest::SHA1.digest(args[0])).upcase
end
end

View file

@ -1,7 +1,11 @@
Puppet::Type.type(:database).provide(:default) do
desc "This is a default provider that does nothing. This allows us to install mysql on the same puppet run where we want to use it."
def self.instances
[]
end
def create
return false
end
@ -14,7 +18,6 @@ Puppet::Type.type(:database).provide(:default) do
fail('This is just the default provider for database, all it does is fail')
end
def charset
return false
end
@ -22,6 +25,4 @@ Puppet::Type.type(:database).provide(:default) do
def charset=(value)
return false
end
# retrieve the current set of mysql databases
end

View file

@ -1,21 +1,34 @@
Puppet::Type.type(:database).provide(:mysql) do
desc "Create mysql database."
desc "Manages MySQL database."
defaultfor :kernel => 'Linux'
optional_commands :mysqladmin => 'mysqladmin'
optional_commands :mysql => 'mysql'
optional_commands :mysqlshow => 'mysqlshow'
optional_commands :mysqladmin => 'mysqladmin'
def self.instances
mysql('-NBe', "show databases").split("\n").collect do |name|
new(:name => name)
end
end
def create
mysql('-NBe', "CREATE DATABASE #{@resource[:name]} CHARACTER SET #{resource[:charset]}")
mysql('-NBe', "create database #{@resource[:name]} character set #{resource[:charset]}")
end
def destroy
mysqladmin('-f', 'drop', @resource[:name])
end
def charset
mysql('-NBe', "show create database #{resource[:name]}").match(/.*?(\S+)\s\*\//)[1]
end
def charset=(value)
mysql('-NBe', "alter database #{resource[:name]} CHARACTER SET #{value}")
end
def exists?
begin
mysql('-NBe', "show databases").match(/^#{@resource[:name]}$/)
@ -24,14 +37,6 @@ Puppet::Type.type(:database).provide(:mysql) do
return nil
end
end
def charset
mysql('-NBe', "show create database #{resource[:name]}").match(/.*?(\S+)\s\*\//)[1]
end
def charset=(value)
mysql('-NBe', "alter database #{resource[:name]} CHARACTER SET #{value}")
end
# retrieve the current set of mysql databases
end

View file

@ -1,21 +1,27 @@
# A grant is either global or per-db. This can be distinguished by the syntax
# of the name:
# user@host => global
# user@host/db => per-db
# user@host => global
# user@host/db => per-db
Puppet::Type.type(:database_grant).provide(:default) do
desc "Uses mysql as database."
def self.instances
[]
end
def destroy
return false
end
def create
return false
end
def exists?
def exists?
fail('Default provider for database_grant should never be used')
end
end

View file

@ -1,155 +1,154 @@
# A grant is either global or per-db. This can be distinguished by the syntax
# of the name:
# user@host => global
# user@host/db => per-db
# user@host => global
# user@host/db => per-db
MYSQL_USER_PRIVS = [ :select_priv, :insert_priv, :update_priv, :delete_priv,
:create_priv, :drop_priv, :reload_priv, :shutdown_priv, :process_priv,
:file_priv, :grant_priv, :references_priv, :index_priv, :alter_priv,
:show_db_priv, :super_priv, :create_tmp_table_priv, :lock_tables_priv,
:execute_priv, :repl_slave_priv, :repl_client_priv, :create_view_priv,
:show_view_priv, :create_routine_priv, :alter_routine_priv,
:create_user_priv, :event_priv, :trigger_priv
:create_priv, :drop_priv, :reload_priv, :shutdown_priv, :process_priv,
:file_priv, :grant_priv, :references_priv, :index_priv, :alter_priv,
:show_db_priv, :super_priv, :create_tmp_table_priv, :lock_tables_priv,
:execute_priv, :repl_slave_priv, :repl_client_priv, :create_view_priv,
:show_view_priv, :create_routine_priv, :alter_routine_priv,
:create_user_priv, :event_priv, :trigger_priv
]
MYSQL_DB_PRIVS = [ :select_priv, :insert_priv, :update_priv, :delete_priv,
:create_priv, :drop_priv, :grant_priv, :references_priv, :index_priv,
:alter_priv, :create_tmp_table_priv, :lock_tables_priv, :create_view_priv,
:show_view_priv, :create_routine_priv, :alter_routine_priv, :execute_priv
:create_priv, :drop_priv, :grant_priv, :references_priv, :index_priv,
:alter_priv, :create_tmp_table_priv, :lock_tables_priv, :create_view_priv,
:show_view_priv, :create_routine_priv, :alter_routine_priv, :execute_priv
]
Puppet::Type.type(:database_grant).provide(:mysql) do
desc "Uses mysql as database."
desc "Uses mysql as database."
defaultfor :kernel => 'Linux'
defaultfor :kernel => 'Linux'
optional_commands :mysql => 'mysql'
optional_commands :mysqladmin => 'mysqladmin'
optional_commands :mysql => 'mysql'
optional_commands :mysqladmin => 'mysqladmin'
def mysql_flush
mysqladmin "flush-privileges"
end
def mysql_flush
mysqladmin "flush-privileges"
end
# this parses the
def split_name(string)
matches = /^([^@]*)@([^\/]*)(\/(.*))?$/.match(string).captures.compact
case matches.length
when 2
{
:type => :user,
:user => matches[0],
:host => matches[1]
}
when 4
{
:type => :db,
:user => matches[0],
:host => matches[1],
:db => matches[3]
}
end
end
# this parses the
def split_name(string)
matches = /^([^@]*)@([^\/]*)(\/(.*))?$/.match(string).captures.compact
case matches.length
when 2
{
:type => :user,
:user => matches[0],
:host => matches[1]
}
when 4
{
:type => :db,
:user => matches[0],
:host => matches[1],
:db => matches[3]
}
end
end
def create_row
unless @resource.should(:privileges).empty?
name = split_name(@resource[:name])
case name[:type]
when :user
mysql "mysql", "-e", "INSERT INTO user (host, user) VALUES ('%s', '%s')" % [
name[:host], name[:user],
]
when :db
mysql "mysql", "-e", "INSERT INTO db (host, user, db) VALUES ('%s', '%s', '%s')" % [
name[:host], name[:user], name[:db],
]
end
mysql_flush
end
end
def create_row
unless @resource.should(:privileges).empty?
name = split_name(@resource[:name])
case name[:type]
when :user
mysql "mysql", "-e", "INSERT INTO user (host, user) VALUES ('%s', '%s')" % [
name[:host], name[:user],
]
when :db
mysql "mysql", "-e", "INSERT INTO db (host, user, db) VALUES ('%s', '%s', '%s')" % [
name[:host], name[:user], name[:db],
]
end
mysql_flush
end
end
def destroy
mysql "mysql", "-e", "REVOKE ALL ON '%s'.* FROM '%s@%s'" % [ @resource[:privileges], @resource[:database], @resource[:name], @resource[:host] ]
end
def row_exists?
name = split_name(@resource[:name])
fields = [:user, :host]
if name[:type] == :db
fields << :db
end
not mysql( "mysql", "-NBe", 'SELECT "1" FROM %s WHERE %s' % [ name[:type], fields.map do |f| "%s = '%s'" % [f, name[f]] end.join(' AND ')]).empty?
end
def destroy
mysql "mysql", "-e", "REVOKE ALL ON '%s'.* FROM '%s@%s'" % [ @resource[:privileges], @resource[:database], @resource[:name], @resource[:host] ]
end
def all_privs_set?
all_privs = case split_name(@resource[:name])[:type]
when :user
MYSQL_USER_PRIVS
when :db
MYSQL_DB_PRIVS
end
all_privs = all_privs.collect do |p| p.to_s end.sort.join("|")
privs = privileges.collect do |p| p.to_s end.sort.join("|")
def row_exists?
name = split_name(@resource[:name])
fields = [:user, :host]
if name[:type] == :db
fields << :db
end
not mysql( "mysql", "-NBe", 'SELECT "1" FROM %s WHERE %s' % [ name[:type], fields.map do |f| "%s = '%s'" % [f, name[f]] end.join(' AND ')]).empty?
end
all_privs == privs
end
def all_privs_set?
all_privs = case split_name(@resource[:name])[:type]
when :user
MYSQL_USER_PRIVS
when :db
MYSQL_DB_PRIVS
end
all_privs = all_privs.collect do |p| p.to_s end.sort.join("|")
privs = privileges.collect do |p| p.to_s end.sort.join("|")
def privileges
name = split_name(@resource[:name])
privs = ""
all_privs == privs
end
case name[:type]
when :user
privs = mysql "mysql", "-Be", 'select * from user where user="%s" and host="%s"' % [ name[:user], name[:host] ]
when :db
privs = mysql "mysql", "-Be", 'select * from db where user="%s" and host="%s" and db="%s"' % [ name[:user], name[:host], name[:db] ]
end
def privileges
name = split_name(@resource[:name])
privs = ""
if privs.match(/^$/)
privs = [] # no result, no privs
else
# returns a line with field names and a line with values, each tab-separated
privs = privs.split(/\n/).map! do |l| l.chomp.split(/\t/) end
# transpose the lines, so we have key/value pairs
privs = privs[0].zip(privs[1])
privs = privs.select do |p| p[0].match(/_priv$/) and p[1] == 'Y' end
end
case name[:type]
when :user
privs = mysql "mysql", "-Be", 'select * from user where user="%s" and host="%s"' % [ name[:user], name[:host] ]
when :db
privs = mysql "mysql", "-Be", 'select * from db where user="%s" and host="%s" and db="%s"' % [ name[:user], name[:host], name[:db] ]
end
privs.collect do |p| symbolize(p[0].downcase) end
end
if privs.match(/^$/)
privs = [] # no result, no privs
else
# returns a line with field names and a line with values, each tab-separated
privs = privs.split(/\n/).map! do |l| l.chomp.split(/\t/) end
# transpose the lines, so we have key/value pairs
privs = privs[0].zip(privs[1])
privs = privs.select do |p| p[0].match(/_priv$/) and p[1] == 'Y' end
end
def privileges=(privs)
unless row_exists?
create_row
end
privs.collect do |p| symbolize(p[0].downcase) end
end
# puts "Setting privs: ", privs.join(", ")
name = split_name(@resource[:name])
stmt = ''
where = ''
all_privs = []
case name[:type]
when :user
stmt = 'update user set '
where = ' where user="%s" and host="%s"' % [ name[:user], name[:host] ]
all_privs = MYSQL_USER_PRIVS
when :db
stmt = 'update db set '
where = ' where user="%s" and host="%s"' % [ name[:user], name[:host] ]
all_privs = MYSQL_DB_PRIVS
end
def privileges=(privs)
unless row_exists?
create_row
end
if privs[0] == :all
privs = all_privs
end
# puts "stmt:", stmt
set = all_privs.collect do |p| "%s = '%s'" % [p, privs.include?(p) ? 'Y' : 'N'] end.join(', ')
# puts "set:", set
stmt = stmt << set << where
# puts "Setting privs: ", privs.join(", ")
name = split_name(@resource[:name])
stmt = ''
where = ''
all_privs = []
case name[:type]
when :user
stmt = 'update user set '
where = ' where user="%s" and host="%s"' % [ name[:user], name[:host] ]
all_privs = MYSQL_USER_PRIVS
when :db
stmt = 'update db set '
where = ' where user="%s" and host="%s"' % [ name[:user], name[:host] ]
all_privs = MYSQL_DB_PRIVS
end
mysql "mysql", "-Be", stmt
mysql_flush
end
if privs[0] == :all
privs = all_privs
end
# puts "stmt:", stmt
set = all_privs.collect do |p| "%s = '%s'" % [p, privs.include?(p) ? 'Y' : 'N'] end.join(', ')
# puts "set:", set
stmt = stmt << set << where
mysql "mysql", "-Be", stmt
mysql_flush
end
end

View file

@ -2,22 +2,26 @@ Puppet::Type.type(:database_user).provide(:default) do
desc "manage users for a mysql database."
def self.instances
[]
end
def create
return false
end
def destroy
return false
end
def exists?
fail("this is just a default, it should not actually be used")
end
def password_hash
return false
end
def password_hash=(string)
return false
end

View file

@ -4,35 +4,39 @@ Puppet::Type.type(:database_user).provide(:mysql) do
defaultfor :kernel => 'Linux'
optional_commands :mysql => 'mysql'
optional_commands :mysql => 'mysql'
optional_commands :mysqladmin => 'mysqladmin'
def self.instances
users = mysql("mysql", '-BNe' "select concat(User, '@',Host) as User from mysql.user").split("\n")
users.select{ |user| user =~ /\.+@/ }.collect do |name|
new(:name => name)
end
end
def create
mysql "mysql", "-e", "create user '%s' identified by PASSWORD '%s'" % [ @resource[:name].sub("@", "'@'"), @resource.value(:password_hash) ]
mysql_flush
mysql("mysql", "-e", "create user '%s' identified by PASSWORD '%s'" % [ @resource[:name].sub("@", "'@'"), @resource.value(:password_hash) ])
end
def destroy
mysql "mysql", "-e", "drop user '%s'" % @resource.value(:name).sub("@", "'@'")
mysql_flush
mysql("mysql", "-e", "drop user '%s'" % @resource.value(:name).sub("@", "'@'") )
end
def exists?
not mysql("mysql", "-NBe", "select '1' from user where CONCAT(user, '@', host) = '%s'" % @resource.value(:name)).empty?
end
def password_hash
mysql("mysql", "-NBe", "select password from user where CONCAT(user, '@', host) = '%s'" % @resource.value(:name)).chomp
end
def password_hash=(string)
mysql "mysql", "-e", "SET PASSWORD FOR '%s' = '%s'" % [ @resource[:name].sub("@", "'@'"), string ]
mysql_flush
mysql("mysql", "-e", "SET PASSWORD FOR '%s' = '%s'" % [ @resource[:name].sub("@", "'@'"), string ] )
end
private
def exists?
not mysql("mysql", "-NBe", "select '1' from user where CONCAT(user, '@', host) = '%s'" % @resource.value(:name)).empty?
end
def mysql_flush
def flush
@property_hash.clear
mysqladmin "flush-privileges"
end
end

View file

@ -1,14 +1,13 @@
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database) do
@doc = "Manage creation/deletion of a database."
@doc = "Manage databases."
ensurable
newparam(:name) do
newparam(:name, :namevar=>true) do
desc "The name of the database."
isnamevar
end
newproperty(:charset) do
desc "The characterset to use for a database"
defaultto :utf8
@ -16,4 +15,3 @@ Puppet::Type.newtype(:database) do
end
end

View file

@ -25,7 +25,7 @@ Puppet::Type.newtype(:database_grant) do
reqs
end
newparam(:name) do
newparam(:name, :namevar=>true) do
desc "The primary key: either user@host for global privilges or user@host/database for database specific privileges"
end
@ -60,7 +60,7 @@ Puppet::Type.newtype(:database_grant) do
# use the sorted outputs for comparison
def insync?(is)
if defined? @should and @should
case self.should_to_s
case self.should_to_s
when "all"
self.provider.all_privs_set?
when self.is_to_s(is)
@ -72,7 +72,7 @@ Puppet::Type.newtype(:database_grant) do
true
end
end
end
end

View file

@ -4,16 +4,13 @@ Puppet::Type.newtype(:database_user) do
ensurable
newparam(:name) do
desc "The name of the user. This uses the 'username@hostname' or username@hosname."
newparam(:name, :namevar=>true) do
desc "The name of the user. This uses the 'username@hostname' or username@hostname."
validate do |value|
unless value =~ /\w+@[\w%]+/
raise ArgumentError, "Invalid database user #{value}"
end
list = value.split('@')
if list[0].size > 16
raise ArgumentError,
"MySQL usernames are limited to a maximum of 16 characters"
raise(ArgumentError, "Invalid database user #{value}") unless value =~ /\w+@[\w%]+/
username = value.split('@')[0]
if username.size > 16
raise ArgumentError, "MySQL usernames are limited to a maximum of 16 characters"
end
end
end
@ -22,4 +19,5 @@ Puppet::Type.newtype(:database_user) do
desc "The password hash of the user. Use mysql_password() for creating such a hash."
newvalue(/\w+/)
end
end

View file

@ -1,56 +1,98 @@
# Class: mysql::config
#
# Parameters:
#
# [*root_password*] - root user password.
# [*old_root_password*] - previous root user password,
# [*bind_address*] - address to bind service.
# [*port*] - port to bind service.
# [*etc_root_password*] - whether to save /etc/.my.cnf.
# [*service_name*] - mysql service name.
# [*config_file*] - my.cnf configuration file path.
# [*socket*] - mysql socket.
#
# Actions:
#
# Requires:
#
# class mysql::server
#
# Usage:
#
# class { 'mysql::config':
# root_password => 'changeme',
# bind_address => $::ipaddress,
# }
#
class mysql::config(
$root_password = 'UNSET',
$root_password = 'UNSET',
$old_root_password = '',
$bind_address = '127.0.0.1',
$port = 3306,
# rather or not to store the rootpw in /etc/my.cnf
$etc_root_password = false
) {
include mysql::params
$bind_address = $mysql::params::bind_address,
$port = $mysql::params::port,
$etc_root_password = $mysql::params::etc_root_password,
$service_name = $mysql::params::service_name,
$config_file = $mysql::params::config_file,
$socket = $mysql::params::socket,
) inherits mysql::params {
Class['mysql::server'] -> Class['mysql::config']
File {
owner => 'root',
group => 'root',
mode => '0400',
notify => Exec['mysqld-restart'],
}
# This kind of sucks, that I have to specify a difference resource for
# restart. the reason is that I need the service to be started before mods
# to the config file which can cause a refresh
exec { 'mysqld-restart':
command => "service ${service_name} restart",
refreshonly => true,
path => '/sbin/:/usr/sbin/',
subscribe => Exec['set_mysql_rootpw']
}
# manage root password if it is set
if !($root_password == 'UNSET') {
if $root_password != 'UNSET' {
case $old_root_password {
'': {$old_pw=''}
default: {$old_pw="-p${old_root_password}"}
'': { $old_pw='' }
default: { $old_pw="-p${old_root_password}" }
}
exec{ 'set_mysql_rootpw':
exec { 'set_mysql_rootpw':
command => "mysqladmin -u root ${old_pw} password ${root_password}",
#logoutput => on_failure,
logoutput => true,
unless => "mysqladmin -u root -p${root_password} status > /dev/null",
unless => "mysqladmin -u root -p${root_password} status > /dev/null",
path => '/usr/local/sbin:/usr/bin',
require => [Package['mysql-server'], Service['mysqld']],
before => File['/root/.my.cnf'],
notify => Exec['mysqld-restart'],
}
file{'/root/.my.cnf':
file { '/root/.my.cnf':
content => template('mysql/my.cnf.pass.erb'),
require => Exec['set_mysql_rootpw'],
}
if $etc_root_password {
file{'/etc/my.cnf':
content => template('mysql/my.cnf.pass.erb'),
require => Exec['set_mysql_rootpw'],
}
file{ '/etc/my.cnf':
content => template('mysql/my.cnf.pass.erb'),
require => Exec['set_mysql_rootpw'],
}
}
}
File {
owner => 'root',
group => 'root',
mode => '0400',
notify => Exec['mysqld-restart'],
require => Package['mysql-server']
}
file { '/etc/mysql':
ensure => directory,
mode => '755',
}
file { '/etc/mysql/conf.d':
ensure => directory,
mode => '755',
}
file { $mysql::params::config_file:
content => template('mysql/my.cnf.erb'),
file { '/etc/mysql':
ensure => directory,
mode => '0755',
}
file { '/etc/mysql/conf.d':
ensure => directory,
mode => '0755',
}
file { $config_file:
content => template('mysql/my.cnf.erb'),
mode => '0644',
}
}

View file

@ -1,23 +1,26 @@
# Define: mysql::db
#
# This module creates database instances, a user,
# and grants that user privileges to the DB.
# This module creates database instances, a user, and grants that user
# privileges to the database.
#
# Parameters:
# [*title*] - database name
# [*user*] - user to create
# [*password*] - user's password
# [*charset*] - charset for db
# [*host*] - host for assigning privileges to user
# [*grant*] - array of privileges to grant to user
# [*sql*] - sql to inject in db (always runs)
# [*title*] - mysql database name.
# [*user*] - username to create and grant access.
# [*password*] - user's password.
# [*charset*] - database charset.
# [*host*] - host for assigning privileges to user.
# [*grant*] - array of privileges to grant user.
# [*enforce_sql*] - whether to enforce or conditionally run sql on creation.
# [*sql*] - sql statement to run.
#
# Actions:
#
# Requires:
#
# class mysql::server
#
# Sample Usage:
#
#
# mysql::db { 'mydb':
# user => 'my_user',
# password => 'password',
@ -28,15 +31,15 @@
define mysql::db (
$user,
$password,
$charset = 'utf8',
$host = 'localhost',
$grant='all',
$enforce_sql = false,
$sql=''
$charset = 'utf8',
$host = 'localhost',
$grant = 'all',
$sql = '',
$enforce_sql = false
) {
if $grant == 'all' {
$safe_grant = [ 'alter_priv','alter_routine_priv','create_priv','create_routine_priv','create_tmp_table_priv','create_view_priv','delete_priv','drop_priv','event_priv','execute_priv','grant_priv','index_priv','insert_priv','lock_tables_priv','references_priv','select_priv','show_view_priv','trigger_priv','update_priv']
$safe_grant = [ 'alter_priv', 'alter_routine_priv', 'create_priv', 'create_routine_priv', 'create_tmp_table_priv', 'create_view_priv', 'delete_priv', 'drop_priv', 'event_priv', 'execute_priv', 'grant_priv', 'index_priv', 'insert_priv', 'lock_tables_priv', 'references_priv', 'select_priv', 'show_view_priv', 'trigger_priv', 'update_priv']
} else {
$safe_grant = $grant
}
@ -46,34 +49,29 @@ define mysql::db (
charset => $charset,
provider => 'mysql',
require => Class['mysql::server'],
notify => $sql ? {
'' => undef,
default => Exec["${name}-import-import"],
}
}
database_user{"${user}@${host}":
database_user { "${user}@${host}":
ensure => present,
password_hash => mysql_password($password),
provider => 'mysql',
require => Database[$name],
}
database_grant{"${user}@${host}/${name}":
# privileges => [ 'alter_priv', 'insert_priv', 'select_priv', 'update_priv' ],
database_grant { "${user}@${host}/${name}":
privileges => $safe_grant,
provider => 'mysql',
require => Database_user["${user}@${host}"],
}
if($sql) {
exec{"${name}-import-import":
if $sql {
exec{ "${name}-import":
command => "/usr/bin/mysql -u ${user} -p${password} -h ${host} ${name} < ${sql}",
logoutput => true,
refreshonly => $enforce_sql ? {
true => false,
false => true,
},
refreshonly => ! $enforce_sql,
require => Database_grant["${user}@${host}/${name}"],
subscribe => Database[$name],
}
}
}

View file

@ -1,20 +1,24 @@
# Class: mysql
#
# this module installs mysql client software.
# This class installs mysql client software.
#
# Parameters:
# [*client_package_name*] - The name of the mysql client package.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql(
$client_package_name = $mysql::params::client_package_name
class mysql (
$package_name = $mysql::params::client_package_name,
$package_ensure = 'present'
) inherits mysql::params {
package {"mysql-client":
name => $client_package_name,
ensure => installed,
package { 'mysql_client':
name => $package_name,
ensure => $package_ensure,
}
}

View file

@ -1,7 +1,6 @@
# Class: mysql::params
#
# This class holds parameters that need to be
# accessed by other classes.
# The mysql configuration settings.
#
# Parameters:
#
@ -11,17 +10,25 @@
#
# Sample Usage:
#
class mysql::params{
case $::operatingsystem {
'centos', 'redhat', 'fedora': {
$service_name = 'mysqld'
$client_package_name = 'mysql'
$socket = '/var/lib/mysql/mysql.sock'
$config_file = '/etc/my.cnf'
$ruby_package_name = 'ruby-mysql'
$python_package_name = 'MySQL-python'
class mysql::params {
$bind_address = '127.0.0.1'
$port = 3306
$server_package_name = 'mysql-server'
$etc_root_password = false
case $::osfamily {
'RedHat': {
$service_name = 'mysqld'
$client_package_name = 'mysql'
$socket = '/var/lib/mysql/mysql.sock'
$config_file = '/etc/my.cnf'
$ruby_package_name = 'ruby-mysql'
$ruby_package_provider = 'gem'
$python_package_name = 'MySQL-python'
}
'ubuntu', 'debian': {
'Debian': {
$service_name = 'mysql'
$client_package_name = 'mysql-client'
$socket = '/var/run/mysqld/mysqld.sock'
@ -29,8 +36,10 @@ class mysql::params{
$ruby_package_name = 'libmysql-ruby'
$python_package_name = 'python-mysqldb'
}
default: {
fail("Unsupported operating system: ${::operatingsystem}. ${module_name} supports debian, ubuntu, redhat, centos, and fedora.")
fail("Unsupported operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian")
}
}
}

View file

@ -14,12 +14,13 @@
# Sample Usage:
#
class mysql::python(
$ensure = installed,
$package_name = $mysql::params::python_package_name
$package_name = $mysql::params::python_package_name,
$package_ensure = 'present'
) inherits mysql::params {
package { 'python-mysqldb':
name => $package_name,
ensure => $ensure,
name => $package_name,
ensure => $package_ensure,
}
}

View file

@ -13,22 +13,16 @@
#
# Sample Usage:
#
class mysql::ruby(
$ensure = installed,
$package_name = $mysql::params::ruby_package_name,
$package_provider = 'gem'
class mysql::ruby (
$package_name = $mysql::params::ruby_package_name,
$package_provider = $mysql::params::ruby_package_provider,
$package_ensure = 'present'
) inherits mysql::params {
# I am not making the mysql package a dep for this
# the only dep is the package which yum will resolve for me.
#case $operatingsystem {
# 'debian', 'ubuntu' : {$ruby_mysql_name = 'libmysql-ruby'}
# default: {$ruby_mysql_name = 'ruby-mysql'}
#}
package{'ruby-mysql':
# name => $ruby_mysql_name,
name => $package_name,
package{ 'ruby_mysql':
name => $package_name,
ensure => $package_ensure,
provider => $package_provider,
ensure => $ensure,
}
}

View file

@ -1,12 +1,12 @@
# Class: mysql::server
#
# manages the installation of the mysql server.
# manages the package, service, my.cnf
# manages the installation of the mysql server. manages the package, service,
# my.cnf
#
# Parameters:
# [*config_hash*] - hash of config parameters that need to be set.
# [*service_name*] - name of service
# [*package_name*] - name of package
# [*package_name*] - name of package
# [*service_name*] - name of service
# [*config_hash*] - hash of config parameters that need to be set.
#
# Actions:
#
@ -14,40 +14,25 @@
#
# Sample Usage:
#
class mysql::server(
$service_name = $mysql::params::service_name,
$config_hash = {},
$package_name = 'mysql-server'
class mysql::server (
$package_name = $mysql::params::server_package_name,
$package_ensure = 'present',
$service_name = $mysql::params::service_name,
$config_hash = {}
) inherits mysql::params {
# automatically create a class to deal with
# configuration
$hash = {
"mysql::config" => $config_hash
}
create_resources("class", $hash)
create_resources( 'class', {'mysql::config' => $config_hash} )
package{'mysql-server':
package { 'mysql-server':
name => $package_name,
ensure => present,
notify => Service['mysqld'],
ensure => $package_ensure,
}
service { 'mysqld':
name => $service_name,
ensure => running,
enable => true,
}
# this kind of sucks, that I have to specify a difference resource for restart.
# the reason is that I need the service to be started before mods to the config
# file which can cause a refresh
exec{ 'mysqld-restart':
command => "service ${service_name} restart",
refreshonly => true,
path => '/sbin/:/usr/sbin/',
}
File{
owner => 'mysql',
group => 'mysql',
name => $service_name,
ensure => running,
enable => true,
require => Package['mysql-server'],
}
}

View file

@ -1,18 +1,19 @@
class mysql::server::monitor (
$mysql_monitor_username,
$mysql_monitor_password,
$mysql_monitor_hostname
) {
database_user{
"${mysql_monitor_username}@${mysql_monitor_hostname}":
password_hash => mysql_password($mysql_monitor_password),
ensure => present,
require => Service['mysqld'],
class ['mysql::server'] -> class['mysql::monitor']
database_user{ "${mysql_monitor_username}@${mysql_monitor_hostname}":
password_hash => mysql_password($mysql_monitor_password),
ensure => present,
}
database_grant { "${mysql_monitor_username}@${mysql_monitor_hostname}":
privileges => [ 'process_priv', 'super_priv' ],
require => [ Mysql_user["${mysql_monitor_username}@${mysql_monitor_hostname}"], Service['mysqld']],
privileges => [ 'process_priv', 'super_priv' ],
require => Mysql_user["${mysql_monitor_username}@${mysql_monitor_hostname}"],
}
}

View file

@ -1,15 +1,16 @@
# Copyright 2009 Larry Ludwig (larrylud@gmail.com)
#
# Licensed under the Apache License, Version 2.0 (the "License"); you
# may not use this file except in compliance with the License. You
# may obtain a copy of the License at
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS"
# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing
# permissions and limitations under the License.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
class mysql::server::mysqltuner {
# mysql performance tester

View file

@ -1,6 +1,9 @@
require 'spec_helper'
describe 'mysql' do
let :facts do
{ :osfamily => 'Debian'}
end
it { should contain_class 'mysql' }
end

View file

@ -13,18 +13,18 @@ describe 'mysql::db', :type => :define do
should contain_database('test_db').without_notify
end
it 'should notify exec to import sql if sql script is given' do
it 'should subscribe to database if sql script is given' do
params.merge!({'sql' => 'test_sql'})
should contain_database('test_db').with_notify('Exec[test_db-import-import]')
should contain_exec('test_db-import').with_subscribe('Database[test_db]')
end
it 'should only import sql script on creation if not enforcing' do
params.merge!({'sql' => 'test_sql', 'enforce_sql' => false})
should contain_exec('test_db-import-import').with_refreshonly(true)
should contain_exec('test_db-import').with_refreshonly(true)
end
it 'should import sql script on creation if enforcing' do
params.merge!({'sql' => 'test_sql', 'enforce_sql' => true})
should contain_exec('test_db-import-import').with_refreshonly(false)
should contain_exec('test_db-import').with_refreshonly(false)
end
end

0
spec/fixtures/manifests/site.pp vendored Normal file
View file

1
spec/fixtures/modules/mysql vendored Symbolic link
View file

@ -0,0 +1 @@
../../../

View file

@ -1,7 +1,16 @@
require 'puppet'
require 'rubygems'
require 'rspec'
require 'rspec-puppet'
RSpec.configure do |c|
c.module_path = File.join(File.dirname(__FILE__), '../../')
def param_value(subject, type, title, param)
subject.resource(type, title).send(:parameters)[param.to_sym]
end
RSpec.configure do |c|
c.module_path = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures/modules'))
# Using an empty site.pp file to avoid: https://github.com/rodjek/rspec-puppet/issues/15
c.manifest_dir = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures/manifests'))
# Use fixtures for config file mainly to support using our own hiera.yaml settings.
# Pending: https://github.com/rodjek/rspec-puppet/pull/21
# c.config = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures/puppet.conf'))
end

View file

@ -0,0 +1,30 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the mysql_password function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("mysql_password").should == "function_mysql_password"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_mysql_password([]) }.should( raise_error(Puppet::ParseError))
end
it "should raise a ParseError if there is more than 1 arguments" do
lambda { @scope.function_mysql_password(['foo', 'bar']) }.should( raise_error(Puppet::ParseError))
end
it "should convert password into a hash" do
result = @scope.function_mysql_password(["password"])
result.should(eq('*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19'))
end
end

View file

@ -1,12 +1,12 @@
[client]
port = <%= port %>
socket = <%= scope.lookupvar('mysql::params::socket') %>
socket = <%= socket %>
[mysqld_safe]
socket = <%= scope.lookupvar('mysql::params::socket') %>
socket = <%= socket %>
nice = 0
[mysqld]
user = mysql
socket = <%= scope.lookupvar('mysql::params::socket') %>
socket = <%= socket %>
port = <%= port %>
basedir = /usr
datadir = /var/lib/mysql

View file

@ -1,12 +1,12 @@
class { 'mysql::server':
config_hash => {'root_password' => 'password'}
}
database{['test1', 'test2', 'test3']:
ensure => present,
charset => 'utf8',
database{ ['test1', 'test2', 'test3']:
ensure => present,
charset => 'utf8',
require => Class['mysql::server'],
}
database{'test4':
ensure => present,
charset => 'latin1',
database{ 'test4':
ensure => present,
charset => 'latin1',
}

View file

@ -1,23 +1,23 @@
$mysql_root_pw='password'
$mysql_root_pw = 'password'
class { 'mysql::server':
config_hash => {
root_password => 'password',
}
}
#database_user{['test1@localhost', 'test2@localhost', 'test3@localhost']:
database_user{'redmine@localhost':
# ensure => absent,
ensure => present,
database_user{ 'redmine@localhost':
ensure => present,
password_hash => mysql_password('redmine'),
require => Class['mysql::server'],
require => Class['mysql::server'],
}
database_user{'dan@localhost':
ensure => present,
database_user{ 'dan@localhost':
ensure => present,
password_hash => mysql_password('blah')
}
database_user{'dan@%':
ensure => present,
database_user{ 'dan@%':
ensure => present,
password_hash => mysql_password('blah'),
}

View file

@ -1,6 +1,3 @@
class { 'mysql::server':
config_hash => {
'root_password' => 'password',
#'old_root_password' => 'puppet'
}
config_hash => { 'root_password' => 'password', },
}