Add db::mysql and db::mysql::host_access to openstacklib

The db::mysql resource is a library resource that can be used by nova, cinder,
ceilometer, etc., rather than replicating equivalent functionality across all
of these modules.

See https://review.openstack.org/#/c/104289

Change-Id: I76bd93d1579179932d1f48cea4bb80a2576a7fba
This commit is contained in:
Colleen Murphy 2014-07-07 14:03:47 -07:00
parent e72605f500
commit 6a547ee0e2
6 changed files with 445 additions and 2 deletions

View File

@ -1,3 +1,6 @@
fixtures:
repositories:
mysql: git://github.com/puppetlabs/puppetlabs-mysql.git
stdlib: git://github.com/puppetlabs/puppetlabs-stdlib.git
symlinks:
'openstacklib': "#{source_dir}"

View File

@ -6,3 +6,6 @@ license 'Apache License 2.0'
summary 'Puppet Labs OpenStackLib Module'
description 'Puppet module library to expose common functionality between OpenStack modules'
project_page 'https://launchpad.net/puppet-openstacklib'
dependency 'puppetlabs/mysql', '>=2.2.0 <3.0.0'
dependency 'puppetlabs/stdlib', '>=3.2.0'

View File

@ -39,9 +39,85 @@ Setup
example% puppet module install puppetlabs/openstacklib
### Beginning with openstacklib
Usage
-----
Instructions for beginning with openstacklib will be added later.
### Classes and Defined Types
#### Defined type: openstacklib::db::mysql
The db::mysql resource is a library resource that can be used by nova, cinder,
ceilometer, etc., to create a mysql database with configurable privileges for
a user connecting from defined hosts.
Typically this resource will be declared with a notify parameter to configure
the sync command to execute when the database resource is change.
For example, in heat::db::mysql you might declare:
```
::openstacklib::db::mysql { 'heat':
user => $user,
password_hash => mysql_password($password),
dbname => $dbname,
host => $host,
charset => $charset,
collate => $collate,
allowed_hosts => $allowed_hosts,
notify => Exec['heat-dbsync'],
}
```
Some modules should ensure that the database is created before the service is
set up. For example, in keystone::db::mysql you would have:
```
::openstacklib::db::mysql { 'keystone':
user => $user,
password_hash => mysql_password($password),
dbname => $dbname,
host => $host,
charset => $charset,
collate => $collate,
allowed_hosts => $allowed_hosts,
notify => Exec['keystone-manage db_sync'],
before => Service['keystone'],
}
```
** Parameters for openstacklib::db::mysql: **
#####`dbname`
The name of the database
string; optional; default to the $title of the resource, i.e. 'nova'
#####`user`
The database user to create;
string; optional; default to the $title of the resource, i.e. 'nova'
#####`password_hash`
Password hash to use for the database user for this service;
string; required
#####`host`
The IP address or hostname of the user in mysql_grant;
string; optional; default to '127.0.0.1'
#####`charset`
The charset to use for the database;
string; optional; default to 'utf8'
#####`collate`
The collate to use for the database;
string; optional; default to 'utf8_unicode_ci'
#####`allowed_hosts`
Additional hosts that are allowed to access this database;
array or string; optional; default to undef
#####`privileges`
Privileges given to the database user;
string or array of strings; optional; default to 'ALL'
Implementation
--------------

91
manifests/db/mysql.pp Normal file
View File

@ -0,0 +1,91 @@
# == Definition: openstacklib::db::mysql
#
# This resource configures a mysql database for an OpenStack service
#
# == Parameters:
#
# [*dbname*]
# The name of the database
# string; optional; default to the $title of the resource, i.e. 'nova'
#
# [*user*]
# The database user to create;
# string; optional; default to the $title of the resource, i.e. 'nova'
#
# [*password_hash*]
# Password hash to use for the database user for this service;
# string; required
#
# [*host*]
# The IP address or hostname of the user in mysql_grant;
# string; optional; default to '127.0.0.1'
#
# [*charset*]
# The charset to use for the database;
# string; optional; default to 'utf8'
#
# [*collate*]
# The collate to use for the database;
# string; optional; default to 'utf8_unicode_ci'
#
# [*allowed_hosts*]
# Additional hosts that are allowed to access this database;
# array or string; optional; default to undef
#
# [*privileges*]
# Privileges given to the database user;
# string or array of strings; optional; default to 'ALL'
define openstacklib::db::mysql (
$password_hash,
$user = $title,
$dbname = $title,
$host = '127.0.0.1',
$charset = 'utf8',
$collate = 'utf8_unicode_ci',
$allowed_hosts = undef,
$privileges = 'ALL',
) {
include ::mysql::server
include ::mysql::client
mysql_database { $dbname:
ensure => present,
charset => $charset,
collate => $collate,
require => [ Class['mysql::server'], Class['mysql::client'] ],
}
mysql_user { "${user}@${host}":
ensure => present,
password_hash => $password_hash,
require => Class['mysql::server'],
}
mysql_grant { "${user}@${host}/${dbname}.*":
privileges => $privileges,
user => "${user}@${host}",
table => "${dbname}.*",
require => [Mysql_database[$dbname], Mysql_user["${user}@${host}"], Class['mysql::server'] ],
}
# Check allowed_hosts to avoid duplicate resource declarations
if is_array($allowed_hosts) and delete($allowed_hosts,$host) != [] {
$real_allowed_hosts = delete($allowed_hosts,$host)
$unique_real_allowed_hosts = prefix($real_allowed_hosts, "${dbname}_")
} elsif is_string($allowed_hosts) and ($allowed_hosts != $host) {
$real_allowed_hosts = $allowed_hosts
$unique_real_allowed_hosts = "${dbname}_${real_allowed_hosts}"
}
if $real_allowed_hosts {
openstacklib::db::mysql::host_access { $unique_real_allowed_hosts:
user => $user,
password_hash => $password_hash,
database => $dbname,
privileges => $privileges,
}
}
}

View File

@ -0,0 +1,41 @@
# Allow a user to access the database for the service
#
# == Namevar
# String with the form dbname_host. The host part of the string is the host
# to allow
#
# == Parameters
# [*user*]
# username to allow
#
# [*password_hash*]
# user password hash
#
# [*database*]
# the database name
#
# [*privileges*]
# the privileges to grant to this user
#
define openstacklib::db::mysql::host_access (
$user,
$password_hash,
$database,
$privileges,
) {
validate_re($title, '_', 'Title must be $dbname_$host')
$host = inline_template('<%= @title.split("_").last %>')
mysql_user { "${user}@${host}":
password_hash => $password_hash,
require => Mysql_database[$database],
}
mysql_grant { "${user}@${host}/${database}.*":
privileges => $privileges,
table => "${database}.*",
require => Mysql_user["${user}@${host}"],
user => "${user}@${host}",
}
}

View File

@ -0,0 +1,229 @@
require 'spec_helper'
describe 'openstacklib::db::mysql' do
let :pre_condition do
'include mysql::server'
end
password_hash = 'AA1420F182E88B9E5F874F6FBE7459291E8F4601'
let :required_params do
{ :password_hash => password_hash }
end
title = 'nova'
let (:title) { title }
context 'on a Debian osfamily' do
let :facts do
{ :osfamily => "Debian" }
end
context 'with only required parameters' do
let :params do
required_params
end
it { should contain_mysql_database(title).with(
:charset => 'utf8',
:collate => 'utf8_unicode_ci'
)}
it { should contain_mysql_user("#{title}@127.0.0.1").with(
:password_hash => password_hash
)}
it { should contain_mysql_grant("#{title}@127.0.0.1/#{title}.*").with(
:user => "#{title}@127.0.0.1",
:privileges => 'ALL',
:table => "#{title}.*"
)}
end
context 'when overriding charset' do
let :params do
{ :charset => 'latin1' }.merge(required_params)
end
it { should contain_mysql_database(title).with_charset(params[:charset]) }
end
context 'when omiting the required parameter password_hash' do
let :params do
required_params.delete(:password_hash)
end
it { expect { should raise_error(Puppet::Error) } }
end
context 'when notifying other resources' do
let :pre_condition do
'exec {"nova-db-sync":}'
end
let :params do
{ :notify => 'Exec[nova-db-sync]'}.merge(required_params)
end
it { should contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Mysql[#{title}]") }
end
context 'when required for other openstack services' do
let :pre_condition do
'service {"keystone":}'
end
let :title do
'keystone'
end
let :params do
{ :before => 'Service[keystone]'}.merge(required_params)
end
it { should contain_service('keystone').that_requires("Openstacklib::Db::Mysql[keystone]") }
end
context "overriding allowed_hosts param to array" do
let :params do
{ :allowed_hosts => ['127.0.0.1','%'] }.merge(required_params)
end
it {should_not contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
it {should contain_openstacklib__db__mysql__host_access("#{title}_%").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
end
context "overriding allowed_hosts param to string" do
let :params do
{
:password_hash => password_hash,
:allowed_hosts => '192.168.1.1'
}
end
it {should contain_openstacklib__db__mysql__host_access("#{title}_192.168.1.1").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
end
context "overriding allowed_hosts param equals to host param " do
let :params do
{
:password_hash => password_hash,
:allowed_hosts => '127.0.0.1'
}
end
it {should_not contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
end
end
context 'on a RedHat osfamily' do
let :facts do
{ :osfamily => 'RedHat' }
end
context 'with only required parameters' do
let :params do
required_params
end
it { should contain_mysql_database(title).with(
:charset => 'utf8',
:collate => 'utf8_unicode_ci'
)}
it { should contain_mysql_user("#{title}@127.0.0.1").with(
:password_hash => password_hash
)}
it { should contain_mysql_grant("#{title}@127.0.0.1/#{title}.*").with(
:user => "#{title}@127.0.0.1",
:privileges => 'ALL',
:table => "#{title}.*"
)}
end
context 'when overriding charset' do
let :params do
{ :charset => 'latin1' }.merge(required_params)
end
it { should contain_mysql_database(title).with_charset(params[:charset]) }
end
context 'when omiting the required parameter password' do
let :params do
required_params.delete(:password)
end
it { expect { should raise_error(Puppet::Error) } }
end
context 'when notifying other resources' do
let(:pre_condition) { 'exec {"nova-db-sync":}' }
let(:params) { { :notify => 'Exec[nova-db-sync]'}.merge(required_params) }
it { should contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Mysql[#{title}]") }
end
context 'when required for other openstack services' do
let(:pre_condition) { 'service {"keystone":}' }
let(:title) { 'keystone' }
let(:params) { { :before => 'Service[keystone]'}.merge(required_params) }
it { should contain_service('keystone').that_requires("Openstacklib::Db::Mysql[keystone]") }
end
context "overriding allowed_hosts param to array" do
let :params do
{ :allowed_hosts => ['127.0.0.1','%'] }.merge(required_params)
end
it {should_not contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
it {should contain_openstacklib__db__mysql__host_access("#{title}_%").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
end
context "overriding allowed_hosts param to string" do
let :params do
{
:password_hash => password_hash,
:allowed_hosts => '192.168.1.1'
}
end
it {should contain_openstacklib__db__mysql__host_access("#{title}_192.168.1.1").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
end
context "overriding allowed_hosts param equals to host param " do
let :params do
{
:password_hash => password_hash,
:allowed_hosts => '127.0.0.1'
}
end
it {should_not contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
:user => title,
:password_hash => password_hash,
:database => title
)}
end
end
end