diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..b4e98be --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,31 @@ +## How to Contribute to This Project + +#### **Did You Find a Bug?** + + * **Ensure the bug was not already reported** by searching on GitHub under **Issues**. + * If you're unable to find an open issue addressing the problem, **open a new one**. Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. + +#### **Did You Write a Patch That Fixes a Bug?** + + * Open a new GitHub pull request with the patch. + 1. Fork this project + 1. Create your feature branch: `git checkout -b my-new-feature` + 1. Commit your changes: `git commit -am 'Add some feature'` + 1. Push to the branch: `git push origin my-new-feature` + 1. Submit a pull request via GitHub's web interface + * Ensure the PR description clearly describes the problem and its solution. Include the relevant issue number if applicable. + +#### **Do You Intend to Add a New Feature or Change an Existing One?** + + * Suggest your change as a **new issue** using the label `enhancement` **BEFORE** you start writing code. + +#### **Do You Want to Sponsor Open Source Development?** + +If you need express resolution of a bug or new features you can consider the opportunity of **sponsoring** the relevant development. + + * Open an issue on GitHub (of type `bug` or `enhancement`) with the details of what you want + * Contact [example42](http://www.example42.com/#contact) referring the issue you created + * Tell us how you want to sponsor the development (sending money, gifts or offering services) + * If we agree on the conditions we will place your [company] name in the module's Sponsors List + +Thanks for contributing! :heart: diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..1d8c11a --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,19 @@ +## Expected Behavior + + +## Actual Behavior + + +## Steps to Reproduce the Problem + + 1. + 1. + 1. + +## Specifications + +Please add this info: + + 1. Output of ```facter -p``` on the failing node (at least the OS related facts) + 1. Version of Puppet and of the module + 1. The relevant Puppet code and eventually Hiera data diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..8b0f809 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +## Before submitting your PR + + 1. Open an **issue** and refer to its number in your PR title + 1. If it's a bug and you have the solution, go on with the PR! + 1. If it's an enhancement, please wait for our feedback before starting to work on it + 1. Please run ```puppet-lint``` on your code and ensure it's compliant + +## After submitting your PR + + 1. Verify Travis checks and eventually fix the errors + 1. Feel free to ping us if we don't reply promptly + diff --git a/.gitignore b/.gitignore index 3d116dc..82ab9d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,20 @@ +/.idea /.gradle -/metadata.json /.rvmrc +/_site build pkg/ +coverage/ Session.vim spec/fixtures .*.sw[a-z] +Gemfile.lock *.un~ +/.vagrant +/vagrant/modules/public +.coveralls.yml +.bundle/ +.yardoc/ +doc/ +vendor/ +_site/ diff --git a/.travis.yml b/.travis.yml index 667053b..de40c51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,42 @@ language: ruby +bundler_args: --without development rvm: - 1.8.7 - 1.9.3 + - 2.0.0 + - 2.1.1 script: - - "rake spec SPEC_OPTS='--format documentation'" + - "bundle exec rake validate lint spec SPEC_OPTS='--format documentation'" env: - - PUPPET_VERSION="~> 2.6.0" - PUPPET_VERSION="~> 2.7.0" - - PUPPET_VERSION="~> 3.0.0" + - PUPPET_VERSION="~> 3.1.0" + - PUPPET_VERSION="~> 3.2.0" + - PUPPET_VERSION="~> 3.3.0" - PUPPET_VERSION="~> 3.4.0" + - PUPPET_VERSION="~> 3.5.0" + - PUPPET_VERSION="~> 3.6.0" + - PUPPET_VERSION="~> 3.7.0" matrix: exclude: + # fails on can't convert String into Integer at init.pp:284 + # fqdn_rand patch in - rvm: 1.9.3 - env: PUPPET_VERSION="~> 2.6.0" - gemfile: .gemfile.travis - - rvm: 1.9.3 env: PUPPET_VERSION="~> 2.7.0" - gemfile: .gemfile.travis - -gemfile: .gemfile + # fails on "Could not autoload package: constant Puppet::Type::Package" + - rvm: 2.0.0 + env: PUPPET_VERSION="~> 3.1.0" + # fails on iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions + - rvm: 2.0.0 + env: PUPPET_VERSION="~> 2.7.0" + - rvm: 2.1.1 + env: PUPPET_VERSION="~> 2.7.0" + # fails on "can't modify frozen Symbol" + - rvm: 2.1.1 + env: PUPPET_VERSION="~> 3.1.0" + - rvm: 2.1.1 + env: PUPPET_VERSION="~> 3.2.0" + - rvm: 2.1.1 + env: PUPPET_VERSION="~> 3.3.0" notifications: email: - al@lab42.it diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..0bb0e37 --- /dev/null +++ b/Gemfile @@ -0,0 +1,17 @@ +source 'https://rubygems.org' + +puppetversion = ENV['PUPPET_VERSION'] + +is_ruby18 = RUBY_VERSION.start_with? '1.8' + +if is_ruby18 + gem 'rspec', "~> 3.1.0", :require => false +end +gem 'puppet', puppetversion, :require => false +gem 'puppet-lint' +gem 'puppetlabs_spec_helper', '>= 0.1.0' +gem 'rspec-puppet' + +group :development do + gem 'puppet-blacksmith' +end \ No newline at end of file diff --git a/Modulefile b/Modulefile deleted file mode 100644 index df0e987..0000000 --- a/Modulefile +++ /dev/null @@ -1,13 +0,0 @@ -name 'example42-mysql' -version '2.1.3' - -author 'Alessandro Franceschi' -license 'Apache2' -project_page 'http://www.example42.com' -source 'https://github.com/example42/puppet-mysql' -summary 'Puppet module for mysql' -description 'This module installs and manages mysql. Check README.rdoc for details. Puppi is required for some common functions: you can install them without using the whole module. Monitor and firewall dependencies are needed only if the relevant features are enabled' -dependency 'puppetlabs/stdlib', '>=2.0.0' -dependency 'example42/puppi', '>=2.0.0' -# optional_dependency 'example42/firewall', '>=2.0.0' -# optional_dependency 'example42/monitor', '>=2.0.0' diff --git a/README.md b/README.md index 3efaf3a..d1263b7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +# Deprecation notice + +This module was designed for Puppet versions 2 and 3. It should work also on Puppet 4 but doesn't use any of its features. + +The current Puppet 3 compatible codebase is no longer actively maintained by example42. + +Still, Pull Requests that fix bugs or introduce backwards compatible features will be accepted. + + # Puppet module: mysql This is a Puppet mysql module from the second generation of Example42 Puppet Modules. @@ -35,7 +44,7 @@ For detailed info about the logic and usage patterns of Example42 modules read R The simplest way to create database is the following. mysql::grant { 'db1': - mysql_username => 'myusername', + mysql_user => 'myusername', mysql_password => 'mypassword', } @@ -45,7 +54,7 @@ This will create a MySQL database named 'db1' with a MySQL grant allowing full a If you want to customize the host the new user can connect from you have to use the 'mysql\_host'. mysql::grant { 'db1': - mysql_username => 'myusername', + mysql_user => 'myusername', mysql_password => 'mypassword', mysql_host => '10.42.42.0/255.255.255.0', } @@ -56,7 +65,7 @@ Here the whole 10.42.42.0/24 can connect. For privileges customization there is the 'mysql\_privileges' parameter. mysql::grant { 'db1': - mysql_username => 'myusername', + mysql_user => 'myusername', mysql_password => 'mypassword', mysql_privileges => 'SELECT', } @@ -68,7 +77,7 @@ Like for standard puppet resource you can use the 'ensure' parameter in order to mysql::grant { 'db1': ensure => 'absent', - mysql_username => 'myusername', + mysql_user => 'myusername', mysql_password => 'mypassword', } @@ -79,7 +88,7 @@ The mysql\_db\_init\_query\_file is an optional parameter allowing to specify a mysql::grant { 'db1': ensure => 'absent', - mysql_username => 'myusername', + mysql_user => 'myusername', mysql_password => 'mypassword', mysql_db_init_query_file => '/full/path/to/the/schema.sql', } @@ -161,6 +170,26 @@ __NOTE__: The SQL file should already be uploaded on mysql server host. my_class => 'mysql::example42', } +## USAGE - Hiera Support +* Manage MySQL configuration using Hiera + +```yaml +mysql::template: 'modules/mysql/my.cnf.erb' +mysql::root_password: 'example42' +mysql::options: + port: '3306' + bind-address: '127.0.0.1' +``` + +* Defining MySQL resources using Hiera + +```yaml +mysql::grant_hash: + 'db1': + mysql_user: 'myusername' + mysql_password: 'mypassword' + mysql_host: '10.42.42.0/255.255.255.0' +``` ## USAGE - Example42 extensions management * Activate puppi (recommended, but disabled by default) diff --git a/manifests/grant.pp b/manifests/grant.pp index 9ed4b05..f4616d1 100644 --- a/manifests/grant.pp +++ b/manifests/grant.pp @@ -49,7 +49,7 @@ ) { if $remote_host == '' { - require mysql + include mysql } $dbname = $mysql_db ? { @@ -90,6 +90,11 @@ default => any2bool($mysql_create_db) } + $manage_remote_host = $remote_host ? { + '' => 'localhost', + default => $remote_host, + } + if (!defined(File[$mysql_grant_filepath])) { file { $mysql_grant_filepath: ensure => directory, @@ -125,7 +130,6 @@ default => undef, } - exec { "mysqlgrant-${mysql_user}-${nice_mysql_host}-${dbname}": command => $exec_command, require => $exec_require, @@ -137,10 +141,10 @@ if $mysql_db_init_query_file != '' and $mysql_create_db == true { mysql::queryfile { "mysql_db_init_query_file-${nice_mysql_host}-${dbname}": mysql_file => $mysql_db_init_query_file, - mysql_user => $mysql_user, - mysql_password => $mysql_password, - mysql_db => $mysql_db, - mysql_host => $mysql_host, + mysql_user => $remote_user, + mysql_password => $remote_password, + mysql_db => $dbname, + mysql_host => $manage_remote_host, subscribe => Exec["mysqlgrant-${mysql_user}-${nice_mysql_host}-${dbname}"], } } diff --git a/manifests/init.pp b/manifests/init.pp index f569627..fda04fa 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -188,6 +188,10 @@ # [*pid_file*] # Path of pid file. Used by monitor # +# [*socket*] +# Path to the mysql socket file. If set, will appear in .my.cnf +# Remember to duplicate in the server configuration. +# # [*data_dir*] # Path of application data directory. Used by puppi # @@ -223,6 +227,7 @@ # class mysql ( $root_password = params_lookup( 'root_password' ), + $root_cnf_template = params_lookup( 'root_cnf_template' ), $password_salt = params_lookup( 'password_salt' ), $my_class = params_lookup( 'my_class' ), $source = params_lookup( 'source' ), @@ -260,11 +265,17 @@ $config_file_group = params_lookup( 'config_file_group' ), $config_file_init = params_lookup( 'config_file_init' ), $pid_file = params_lookup( 'pid_file' ), + $socket = params_lookup( 'socket' ), $data_dir = params_lookup( 'data_dir' ), $log_dir = params_lookup( 'log_dir' ), $log_file = params_lookup( 'log_file' ), $port = params_lookup( 'port' ), - $protocol = params_lookup( 'protocol' ) + $protocol = params_lookup( 'protocol' ), + $augeas_hash = params_lookup( 'augeas_hash'), + $grant_hash = params_lookup( 'grant_hash'), + $query_hash = params_lookup( 'query_hash'), + $queryfile_hash = params_lookup( 'queryfile_hash'), + $user_hash = params_lookup( 'user_hash'), ) inherits mysql::params { $bool_source_dir_purge=any2bool($source_dir_purge) @@ -279,6 +290,28 @@ $bool_debug=any2bool($debug) $bool_audit_only=any2bool($audit_only) + ## Integration with Hiera + if $augeas_hash != {} { + validate_hash($augeas_hash) + create_resources('mysql::augeas', $augeas_hash) + } + if $grant_hash != {} { + validate_hash($grant_hash) + create_resources('mysql::grant', $grant_hash) + } + if $query_hash != {} { + validate_hash($query_hash) + create_resources('mysql::query', $query_hash) + } + if $queryfile_hash != {} { + validate_hash($queryfile_hash) + create_resources('mysql::queryfile', $queryfile_hash) + } + if $user_hash != {} { + validate_hash($user_hash) + create_resources('mysql::user', $user_hash) + } + ### Root password setup $random_password = $mysql::password_salt ? { '' => fqdn_rand(100000000000), @@ -371,12 +404,12 @@ if $mysql::bool_absent == false { service { 'mysql': - ensure => $mysql::manage_service_ensure, - name => $mysql::service, - enable => $mysql::manage_service_enable, - hasstatus => $mysql::service_status, - pattern => $mysql::process, - require => [ Package['mysql'] , File['mysql.conf'] ] + ensure => $mysql::manage_service_ensure, + name => $mysql::service, + enable => $mysql::manage_service_enable, + hasstatus => $mysql::service_status, + pattern => $mysql::process, + require => [ Package['mysql'] , File['mysql.conf'] ] } } @@ -395,7 +428,7 @@ } # The whole mysql configuration directory can be recursively overriden - if $mysql::source_dir { + if $mysql::source_dir and $mysql::source_dir != '' { file { 'mysql.dir': ensure => directory, path => $mysql::config_dir, @@ -411,11 +444,10 @@ ### Include custom class if $my_class is set - if $mysql::my_class { + if $mysql::my_class and $mysql::my_class != '' { include $mysql::my_class } - ### Provide puppi data, if enabled ( puppi => true ) if $mysql::bool_puppi == true { $classvars=get_class_args() diff --git a/manifests/params.pp b/manifests/params.pp index 4092f1e..07e5401 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -16,6 +16,7 @@ ### Module specific parameters $root_password = '' + $root_cnf_template = 'mysql/root.my.cnf.erb' $password_salt = '' ### Application related parameters @@ -112,6 +113,7 @@ $absent = false $disable = false $disableboot = false + $socket = '' ### General module variables that can have a site or per module default $monitor = false @@ -125,5 +127,10 @@ $puppi_helper = 'standard' $debug = false $audit_only = false + $grant_hash = {} + $user_hash = {} + $augeas_hash = {} + $query_hash = {} + $queryfile_hash = {} } diff --git a/manifests/password.pp b/manifests/password.pp index 6f89efd..2995989 100644 --- a/manifests/password.pp +++ b/manifests/password.pp @@ -6,8 +6,8 @@ class mysql::password { # Load the variables used in this module. Check the params.pp file - require mysql - require mysql::params + include mysql + include mysql::params if ! defined(File['/root/.my.cnf']) { file { '/root/.my.cnf': @@ -16,7 +16,7 @@ mode => '0400', owner => $mysql::config_file_owner, group => $mysql::config_file_group, - content => template('mysql/root.my.cnf.erb'), + content => template($mysql::root_cnf_template), # replace => false, # require => Exec['mysql_root_password'], } @@ -35,11 +35,11 @@ } exec { 'mysql_backup_root_my_cnf': - require => Service['mysql'], - path => '/bin:/sbin:/usr/bin:/usr/sbin', - unless => 'diff /root/.my.cnf /root/.my.cnf.backup', - command => 'cp /root/.my.cnf /root/.my.cnf.backup ; true', - before => File['/root/.my.cnf'], + require => Service['mysql'], + path => '/bin:/sbin:/usr/bin:/usr/sbin', + unless => 'diff /root/.my.cnf /root/.my.cnf.backup', + command => 'cp /root/.my.cnf /root/.my.cnf.backup ; true', + before => File['/root/.my.cnf'], } diff --git a/manifests/queryfile.pp b/manifests/queryfile.pp index 01c585c..a34f57b 100644 --- a/manifests/queryfile.pp +++ b/manifests/queryfile.pp @@ -41,10 +41,7 @@ } exec { "mysqlqueryfile-${name}": - command => "mysql ${arg_mysql_defaults_file} \ - ${arg_mysql_user} ${arg_mysql_password} ${arg_mysql_host} \ - ${mysql_db} < ${mysql_file} && \ - touch ${mysql_query_filepath}/mysqlqueryfile-${name}.run", + command => "mysql ${arg_mysql_defaults_file} ${arg_mysql_user} ${arg_mysql_password} ${arg_mysql_host} ${mysql_db} < ${mysql_file} && touch ${mysql_query_filepath}/mysqlqueryfile-${name}.run", path => [ '/usr/bin' , '/usr/sbin' , '/bin' , '/sbin' ], creates => "${mysql_query_filepath}/mysqlqueryfile-${name}.run", unless => "ls ${mysql_query_filepath}/mysqlqueryfile-${name}.run", diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..c4d6542 --- /dev/null +++ b/metadata.json @@ -0,0 +1,21 @@ +{ + "name": "example42-mysql", + "version": "2.1.8", + "summary": "Puppet module for mysql", + "author": "Alessandro Franceschi", + "description": "This module installs and manages mysql. Check README.rdoc for details. Puppi is required for some common functions: you can install them without using the whole module. Monitor and firewall dependencies are needed only if the relevant features are enabled", + "dependencies": [ + { + "name": "example42/puppi", + "version_requirement": ">=2.0.0" + } + ], + "types": [ + + ], + "checksums": { + }, + "source": "https://github.com/example42/puppet-mysql", + "project_page": "http://www.example42.com", + "license": "Apache2" +} diff --git a/spec/defines/grant_spec.rb b/spec/defines/grant_spec.rb index a345bf6..975e2be 100644 --- a/spec/defines/grant_spec.rb +++ b/spec/defines/grant_spec.rb @@ -127,4 +127,50 @@ it { should contain_file('mysqlgrant-someuser-10.42.42.0_255.255.255.0-all.sql').with_content(/REVOKE ALL ON \*\.\* FROM 'someuser'@'10.42.42.0\/255.255.255.0';/) } it { should contain_file('mysqlgrant-someuser-10.42.42.0_255.255.255.0-all.sql').with_content(/FLUSH PRIVILEGES;/) } end + + describe 'Test grant with initial data' do + let(:params) { { + :name => 'sample1', + :mysql_db => 'example_db', + :mysql_user => 'someuser', + :mysql_password => 'somepassword', + :mysql_db_init_query_file => '/example/42.sql', + } } + + it { should contain_mysql__queryfile('mysql_db_init_query_file-localhost-example_db').with_mysql_file('/example/42.sql') } + it { should contain_mysql__queryfile('mysql_db_init_query_file-localhost-example_db').with_mysql_host('localhost') } + end + + describe 'Test grant with initial data' do + let(:params) { { + :name => 'sample1', + :mysql_db => 'example_db', + :mysql_host => '10.42.42.0/255.255.255.0', + :mysql_user => 'someuser', + :mysql_password => 'somepassword', + :mysql_db_init_query_file => '/example/42.sql', + } } + + it { should contain_mysql__queryfile('mysql_db_init_query_file-10.42.42.0_255.255.255.0-example_db').with_mysql_file('/example/42.sql') } + it { should contain_mysql__queryfile('mysql_db_init_query_file-10.42.42.0_255.255.255.0-example_db').with_mysql_host('localhost') } + end + + describe 'Test grant with initial data' do + let(:params) { { + :name => 'sample1', + :mysql_db => 'example_db', + :mysql_host => '10.42.42.0/255.255.255.0', + :mysql_user => 'someuser', + :mysql_password => 'somepassword', + :mysql_db_init_query_file => '/example/42.sql', + :remote_host => '10.42.42.42', + :remote_user => 'user42', + :remote_password => 'pass42', + } } + + it { should contain_mysql__queryfile('mysql_db_init_query_file-10.42.42.0_255.255.255.0-example_db').with_mysql_file('/example/42.sql') } + it { should contain_mysql__queryfile('mysql_db_init_query_file-10.42.42.0_255.255.255.0-example_db').with_mysql_host('10.42.42.42') } + it { should contain_mysql__queryfile('mysql_db_init_query_file-10.42.42.0_255.255.255.0-example_db').with_mysql_user('user42') } + it { should contain_mysql__queryfile('mysql_db_init_query_file-10.42.42.0_255.255.255.0-example_db').with_mysql_password('pass42') } + end end diff --git a/templates/root.my.cnf.backup.erb b/templates/root.my.cnf.backup.erb index 4e89135..e8f2521 100644 --- a/templates/root.my.cnf.backup.erb +++ b/templates/root.my.cnf.backup.erb @@ -2,3 +2,4 @@ [client] password= +<% if scope.lookupvar('mysql::socket') != '' %>socket=<%= scope.lookupvar('mysql::socket') %><% end %> diff --git a/templates/root.my.cnf.erb b/templates/root.my.cnf.erb index 1a712cf..9e70145 100644 --- a/templates/root.my.cnf.erb +++ b/templates/root.my.cnf.erb @@ -2,3 +2,4 @@ [client] password=<%= scope.lookupvar('mysql::real_root_password') %> +<% if scope.lookupvar('mysql::socket') != '' %>socket=<%= scope.lookupvar('mysql::socket') %><% end %>