Playing With Tokudb
I've decided to take a look at Tokudb and see, how easy it is to use and administer. Since it's much better to have your stuff being repeatable and easily shareable, we're gonna use Puppet and Vagrant for this.
The layout is based on my article
The Perfect Puppet Setup For Vagrant-article.
https://github.com/mindreframer/vagrant-tokudb-puppet/
Let's dive deeper into a slightly more complext module for Puppet:
class tokudb{
class{"tokudb::params": }
-> class{"tokudb::users":}
-> class{"tokudb::download":}
-> class{"tokudb::packages":}
-> class{"tokudb::configs":}
-> class{"tokudb::initialize":}
-> class{"tokudb::service":}
}
class tokudb::users{
user { 'mysql':
ensure => 'present',
uid => $tokudb::params::user_id,
}
-> group { "mysql":
ensure => "present",
gid => $tokudb::params::user_id,
}
}
class tokudb::download{
$filepath = $tokudb::params::download_file
$fullpath = $tokudb::params::fullpath
file{"/vagrant":
ensure => directory
}
-> exec{"download tokudb":
command => "curl $tokudb::params::download_url > /vagrant/$filepath",
unless => "test -e /vagrant/$filepath"
}
-> exec{"decompress tokudb":
command => "tar xvfz /vagrant/$filepath",
cwd => "/usr/local",
unless => "test -e $tokudb::params::base_dir"
}
-> file{$tokudb::params::base_dir:
ensure => link,
target => "/usr/local/$fullpath",
}
-> exec{"adjust filerights tokudb":
command => "chown -R mysql:mysql $tokudb::params::base_dir"
}
}
class tokudb::packages{
package{$tokudb::params::packagenames: ensure => installed}
}
class tokudb::configs{
file{"/etc/init.d/mysql":
content => template("tokudb/mysql.server.erb"),
mode => 0755,
}
file{"/etc/mysql":
ensure => directory
}
-> file{"/etc/mysql/my.cnf":
content => template("tokudb/my.cnf.erb"),
}
-> file{$tokudb::params::data_dir:
ensure => directory,
owner => 'mysql', group => 'mysql'
}
}
class tokudb::initialize{
$check_file = "$tokudb::params::base_dir/.installed"
exec{"init mysql":
command => "echo 1 && cd $tokudb::params::base_dir && ./scripts/mysql_install_db --user=mysql && touch $check_file",
unless => "test -e $check_file"
}
}
class tokudb::service{
service{"mysql":
ensure => running,
subscribe => Class["tokudb::configs"]
}
}
Let's discuss some attributes, that this script exposes:
It is composed of small classes with descriptive names
the wiring up for dependencies happens in the main class, e.g. on a highlevel. We don't use
require
for smaller folders, files, packages, etc.it has no external dependencies (except relying on
Curl
being installed)we use absolute variables, like
$tokudb::params::download_file
, that means the configuration happens inparams.pp
class. Thetokudb
- class does not care, where those params came from: hardcoded,Hiera
, CSV, with logic conditions, etcthe order of methods is optimized for reading, it tells us a story.
it is sequential, since people are much better at following simple 1-2-3-steps instructions, like:
Prepare params first, then create users, download stuff, install packages, now please create configuration files, now would be a good moment to initialize our database, ah, and since we're prepared everything, be so nice and start the process!
class tokudb{
class{"tokudb::params": }
-> class{"tokudb::users":}
-> class{"tokudb::download":}
-> class{"tokudb::packages":}
-> class{"tokudb::configs":}
-> class{"tokudb::initialize":}
-> class{"tokudb::service":}
}
- It's making liberal usage of
Exec
-resource for Puppet, that is officially not the best practice, but it's much-much faster and more flexible, than writing your own Puppet Ruby-Code for Resources - that includes:
- managing file rights for bigger folders ( puppet would try to store the file attributes for every file in the hierarchy and check it on every run, don't do it)
- testing the outcome of an Exec, I don't like the
creates => 'blah'
attribute, Unix with 'test -condition evaluation utility' is more flexible
- it's idempotent, means it won't download files twice, initialize database twice, so every
Exec
Resource should have anunless
-attribute - it makes heavy use of
->
(ordering arrow)-Operator (Relationshiops in Puppet), e.g.
class tokudb::download{
$filepath = $tokudb::params::download_file
$fullpath = $tokudb::params::fullpath
file{"/vagrant":
ensure => directory
}
-> exec{"download tokudb":
command => "curl $tokudb::params::download_url > /vagrant/$filepath",
unless => "test -e /vagrant/$filepath"
}
-> exec{"decompress tokudb":
command => "echo 1 && cd /usr/local && tar xvfz /vagrant/$filepath",
unless => "test -e $tokudb::params::base_dir"
}
-> file{$tokudb::params::base_dir:
ensure => link,
target => "/usr/local/$fullpath",
}
-> exec{"adjust filerights tokudb":
command => "chown -R mysql:mysql $tokudb::params::base_dir"
}
}
- for operations, that produce no easily checkable output (like the database initialization), I'm just
touch
-ing a file after success and skip the operation, if it is already present
class tokudb::initialize{
$check_file = "$tokudb::params::base_dir/.installed"
exec{"init mysql":
command => "echo 1 && cd $tokudb::params::base_dir && scripts/mysql_install_db --user=mysql && touch $check_file",
unless => "test -e $check_file"
}
}
- for operations, that require changing into a directory, we use the
cwd
-attribute of theExec
Resource. Sometimes, for no obvious reasoms, it won't work. Just prepending your command with "cd /some/directory && ..." will also fail, because puppet checks for binary presence, andcd
is not a binary... So, I employ theecho
-hack: "echo 1 && cd /some/dir && ...". Looks stupid, but works. If you have any better suggestions, pls tell me!
I'm quite happy with the outcome, it's comprehensible, shareable and future-proof, since we extacted the params, that might change from system-to-system or in future.
Go ahead and play with it, see, if you like it!