Hello. This is Komiya.
This is the last time.
Here are some places to test the recipes I introduced last time. Serverspec.
I wrote in the link below why Serverspec is good, but I think the following points are good.
・It is not a Chef test tool, but an external tool, so there are no dependencies (it can also be used in puppet).
・The design concept is simple and easy to use, so it was easy to use without much effort.
Reference:
Serverspec at hbstudy #45 Introduction Chef Solo Picking up fallen ears kayac/newbie-training "Introductory Puppet" resource_type manual advanced_tipsNCSTUDY#05 Hands-on Materials Parallel_tests
・Setup
Versions 0.3 and 0.6 felt that the way the tests were written was slightly different, so I recommend the new one that follows the manual.
[shell]# yum install rubygems
gem install serverspec rake
serverspec-init
Select a backend type:
1) SSH
2) Exec (local)
Select number: 1
Vagrant instance y/n: y
Input vagrant instance name: 10.0.0.241
+ spec/10.0.0.241/
+ spec/10.0.0.241/httpd_spec.rb[/shell]
<br>When the command is finished running, it will create some files as described above.<br>```
\[shell\]# serverspec-init ~omitted~ Input target host name: 10.0.0.240 + spec/10.0.0.240/ + spec/10.0.0.240/httpd\_spec.rb\[/shell\]
After specifying SSH and entering the target host, a directory for each host was created.
I'm going to write a test.
\[shell\]# vi spec/10.0.0.240/httpd\_spec.rb require 'spec\_helper'
describe 'httpd' do it { should be_installed } it { should be_enabled } it { should be_running } end
describe 'port 80' do it { should be_listening } end
describe '/etc/httpd/conf/httpd.conf' do
it { should be_file }
it { should contain "ServerName localhost:80" }
end[/shell]
Changed from DetectOS to RedHat (because it's CentOS)
```
[shell]# vi spec/spec_helper.rb include Serverspec::Helper::RedHat[/shell]
Modify the config of ssh to be able to pass the connection information
[shell]# vi .ssh/config Host 10.0.0.240 HostName 10.0.0.240 User root Port 22 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile "/root/.ssh/ komi-test.pem" IdentitiesOnly yes LogLevel FATAL Host 10.0.0.241 HostName 10.0.0.241 User root Port 22 UserKnownHostsFile /dev/null StrictHostKeyChecking no PasswordAuthentication no IdentityFile "/root/.ssh/komi-test.pem" IdentitiesOnly yes[/shell]
Modify the test file name on the DB side and modify the content to match the entity
[shell]# mv spec/10.0.0.241/httpd_spec.rb spec/10.0.0.241/mysqld_spec.rb
vi spec/10.0.0.241/mysqld_spec.rb
require 'spec_helper'
describe 'mysql-server' do
it { should be_installed }
end
describe 'mysqld' do
it { should be_enabled }
it { should be_running }
end
describe 'port 3306' do
it { should be_listening }
end
describe '/etc/my.cnf' do
it { should be_file }
it { should contain "server-id = 103" }
end[/shell]<br>For the time being, I will check if the test is as written<br>```
\[shell\]# rake spec (in /root) /root/.rbenv/versions/1.9.2-p290/bin/ruby -S rspec spec/10.0.0.240/httpd\_spec.rb spec/10.0.0.241/mysqld\_spec.rb ............
Finished in 0.74866 seconds
12 examples, 0 failures[/shell]
It seems that what I wrote went well.
In the case of an error, the following command that failed and its return are printed, so it is very easy to understand.
```
[shell]Failures:
1) mysql-server
Failure/Error: it { should be_enabled }
chkconfig --list mysql-server | grep 3:on
error reading information on service mysql-server: No such file or directory
2) mysql-server
Failure/Error: it { should be_running }
ps aux | grep -w -- mysql-server | grep -qv grep[/shell]<br>→ these are said to be mysql-server in chkconfig and ps commands, so I will fix them by separating the should be_installed, enabled, and running blocks.<br>
<br>
<br>Next, we will add all the necessary tests and test them<br>In order to reuse recipes and tests as a set, it is thought that it would be better to divide the test file into the same way as the recipe.<br>```
For the time being, I will divide the test files into cookbook units.
Maybe you can create a test file with a name corresponding to the recipe for each host directory.
Base\_setting recipe tests are duplicated, so I would like to manage them for each role, but this will be an issue in the future.
\[shell\]# vi spec/10.0.0.240/base\_spec.rb require 'spec\_helper'
Create a backup directory
describe file('/etc/.backup') do it { should be_directory } end
describe file('/etc/hosts') do it { should contain '10.0.0.240 xxx-web03' } end
Setting the default gateway
describe default_gateway do its(:ipaddress) { should eq '10.0.0.93' } its(:interface) { should eq 'eth0' } end
selinux is disable
describe selinux do it { should be_disabled } end
Exclude update kernel in yum.conf
describe file('/etc/yum.conf') do it { should contain 'exclude=kernel*' } end
Disable ipv6 in modprobe.conf
describe file('/etc/modprobe.conf') do it { should contain 'options ipv6 disable=1' } end
The required package must be included
%w{ sendmail ntp }.each do |pkg| describe package("#{pkg}") do it { should be_installed } end end
Unnecessary service outage
%w{ ip6tables iptables messagebus kudzu }.each do |services| describe service("services") do it { should_not be_enabled } it { should_not be_running } end end
log cut-off settings
describe file('/etc/logrotate.d/syslog') do it { should contain 'compress' } it { should contain 'rotate 53' } end
Unnecessary cron permission must be 0
%w{ makewhatis.cron mlocate.cron prelink }.each do |files| describe file("/etc/cron.daily/#{files}") do it { should be_mode 0 } end end
describe file('/etc/cron.weekly/makewhatis.cron') do it { should be_mode 0 } end
cron for ntpdate
describe cron do it { should have_entry '0 * * * * /usr/sbin/ntpdate -bs 10.0.0.93' } end
timezone
#describe file('/etc/localtime') do
it { should be_linked_to '/usr/share/zoneinfo/Japan' }
#end
kernelparams for webserver
describe 'Linux kernel parameters' do context linux_kernel_parameter('net.ipv4.tcp_syncookies') do its(:value) { should eq 1 } end
context linux_kernel_parameter('vm.swappiness') do its(:value) { should eq 30 } end
context linux_kernel_parameter('net.ipv4.tcp_tw_reuse') do its(:value) { should eq 0 } end
context linux_kernel_parameter('net.ipv4.tcp_tw_recycle') do its(:value) { should eq 0 } end
context linux_kernel_parameter('net.ipv4.tcp_fin_timeout') do its(:value) { should eq 60 } end
context linux_kernel_parameter('net.ipv4.tcp_max_syn_backlog') do its(:value) { should eq 4096 } end
context linux_kernel_parameter('net.core.somaxconn') do its(:value) { should eq 4096 } end end
Testing login users
%w{ xxx-op yyy-op dev }.each do |u| describe user("#{u}") do it { should exist } it { should belong_to_group 'wheel' } end end
# rake spec
Omitted
Finished in 3.13 seconds
40 examples, 0 failures[/shell]
For the time being, I have moved so far.
If you don't upgrade the serverspec itself to 0.6, some linux_kernel_paramater and cron won't work because there is no such method.
```
[shell]# cp -p spec/10.0.0.240/base_spec.rb spec/10.0.0.241/
vi spec/10.0.0.241/base_spec.rb
diff spec/10.0.0.240/base_spec.rb spec/10.0.0.241/base_spec.rb
9c9
< it { should contain '10.0.0.240 xxx-web03' }
---
> it { should contain '10.0.0.241 xxx-db03' }
75c75
< # kernelparams for webserver
---
> # kernelparams for dbserver
82c82
< its(:value) { should eq 30 }
---
> its(:value) { should eq 0 }
86c86
< its(:value) { should eq 0 }
---
> its(:value) { should eq 1 }
90c90
< its(:value) { should eq 0 }
---
> its(:value) { should eq 1 }
94c94
< its(:value) { should eq 60 }
---
> its(:value) { should eq 10 }
98c98
< its(:value) { should eq 4096 }
---
> its(:value) { should eq 8192 }
102c102
< its(:value) { should eq 4096 }
---
> its(:value) { should eq 8192 }[/shell]<br>```
・I wrote a little bit of the httpd cookbook test
\[shell\]require 'spec\_helper'
%w{ httpd php php-pecl-ssh2 php-mysql php-common php-devel php-pear php-pdo php-mbstring php-pecl-apc php-mcrypt php-cli mysql-libs }.each do |pkg| describe package("#{pkg}") do it { should be_installed } end end
describe service('httpd') do it { should be_enabled } it { should be_running } end
describe port(80) do it { should be_listening } end
describe file('/etc/httpd/conf/httpd.conf') do it { should be_file } it { should contain "ServerName localhost:80" } end
basic auth test
describe file('/etc/httpd/conf.d/basic_auth.conf') do it { should be_file } it { should contain "Require valid-user" } end
describe file('/etc/httpd/conf/.htpasswd') do it { should be_file } it { should contain "dev" } end
wp contents exists test
describe file('/var/www/html/wp-config.php') do it { should be_file } end
mount fuse test
#describe file('/var/www/html/assets') do
it { should be_mounted.with(:type => 'fuse') }
it { should be_mounted.with(:options => { :rw => true } ) }
#end[/shell]
```
- Added some tests for mysqld
[shell]require 'spec_helper'
describe package('mysql-server') do
it { should be_installed }
end
describe service('mysqld') do
it { should be_enabled }
it { should be_running }
end
describe port(3306) do
it { should be_listening }
end
describe file('/etc/my.cnf') do
it { should be_file }
it { should contain "server-id = 103" }
end
describe file('/etc/logrotate.d/mysqld') do
it { should be_file }
it { should contain "/usr/bin/mysqladmin flush-logs" }
end
describe file('/opt/bin/mysql-back.sh') do
it { should be_file }
it { should be_executable }
end[/shell]<br>・Write a test for munin<br>```
\[shell\]# vi spec/10.0.0.240/munin\_spec.rb require 'spec\_helper'
%w{ munin-node perl-DBI }.each do |pkg| describe package("#{pkg}") do it { should be_installed } end end
describe service('munin-node') do it { should be_enabled } it { should be_running } end
describe port(4949) do it { should be_listening } end
munin plugins
%w{ cpu memory df load tcp iostat if_eth0 if_err_eth0 }.each do |plg| describe file("/etc/munin/plugins/#{plg}") do it { should be_file } end end
munin plugins for httpd
%w{ apache_accesses apache_processes }.each do |plg| describe file("/etc/munin/plugins/#{plg}") do it { should be_file } end end
munin plugins for mysql
#%w{ mysql_slowqueries mysql_queries mysql_threads }.each do |plg|
describe file("/etc/munin/plugins/#{plg}") do
it { should be_file }
end
#end
# cp -p spec/10.0.0.240/munin\_spec.rb spec/10.0.0.241/munin\_spec.rb
# vi spec/10.0.0.241/munin\_spec.rb
# diff spec/10.0.0.240/munin\_spec.rb spec/10.0.0.241/munin\_spec.rb
26,33c26 < %w{ apache_accesses apache_processes }.each do |plg| < describe file("/etc/munin/plugins/#{plg}") do < it { should be_file } < end < end < < ## munin plugins for mysql < #%w{ mysql_slowqueries mysql_queries mysql_threads }.each do |plg|
> #%w{ apache_accesses apache_processes }.each do |plg|
38a32,38
> # munin plugins for mysql
> %w{ mysql_slowqueries mysql_queries mysql_threads }.each do |plg|
> describe file("/etc/munin/plugins/#{plg}") do
> it { should be_file }
> end
> end
>[/shell]
Write a zabbix test
```
[shell]# vi spec/10.0.0.240/zabbix_spec.rb require 'spec_helper'
%w{ zabbix-agent zabbix zabbix-jp-release }.each do |pkg|
describe package("#{pkg}") do
it { should be_installed }
end
end
describe service('zabbix-agent') do
it { should be_enabled }
it { should be_running }
end
describe port(10050) do
it { should be_listening }
end
describe file('/opt/bin/mem_monitor.sh') do
it { should be_executable }
end
cp -p spec/10.0.0.240/zabbix_spec.rb spec/10.0.0.241/zabbix_spec.rb
rake spec
~Omitted~
Finished in 5.09 seconds
152 examples, 0 failures[/shell]<br>I tested it without any problems.<br>It is questionable whether the test is enough.<br>```
I haven't tested the user or replication, but it seems that I can only check the standard output with the command resource type.
The command is this ↓,
mysql -u root -p`cat /path_to_file` -s -e "show grants for repl@'10.0.0.%';"
I can only think of writing a test that says the return value is this ↓
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON _._ TO 'repl'@'10.0.0.%' IDENTIFIED BY PASSWORD '\*43E209EED080057E35C2630AC06D3296\*\*\*\*\*'
I wonder if the complex ones feel like making a check command with a simple return value.
This information is also
・HTML output can be done with rake spec SPEC\_OPTS="--format html". If it is not an error, only OK will come back, so the visibility is good when you want a report.
・ gem install ci\_reporter and add 'ci/reporter/rake/rspec' to Rakefile.
Can be converted to JUnit format XML (available in Jenkins)
・If you use [parallel\_tests](https://github.com/grosser/parallel_tests), you can run it in parallel and it's fast. It looks good when there are a lot of cars.
・If you want to use a role or attribute, the following sites may be helpful.
[advanced\_tips](http://serverspec.org/advanced_tips.html)[How to Handle Host-Specific Attribute Values in Serverspec](http://mizzy.org/blog/2013/05/12/2/) [Reading chef json in Serverspec](http://blog.kenjiskywalker.org/blog/2013/07/31/serverspec-attribute/) Let's [write tests for a server environment with serverspec](http://www.slideshare.net/ikedai/serverspec)
This is the end of the feature-length Chef series.
Thank you for taking a long time.
Click here for the back number↓
[Introduction of Chef-Solo and Vagrant (VPC Environment)](https://blog.colorkrew.com/chef-solo_vagrant_install/)[Environment Before Writing Recipes in Chef-Solo (Vagrantfile, role, node, data\_bags)Writing](https://blog.colorkrew.com/vagrantfile_role_data_bags/) [Recipes for Existing Procedures in Chef 1 (Default Setup)](https://blog.colorkrew.com/chef-solo_base_setting-recipe/)[Write a recipe for an existing procedure in Chef 2 (user-created)](https://blog.colorkrew.com/chef-solo_user_manage/) [Write a recipe for an existing procedure in Chef 3 (WEB server)](https://blog.colorkrew.com/chef-solo_webservers_recipe/) [Write a recipe for an existing procedure in Chef 4 (DB server)](https://blog.colorkrew.com/chef-solo_dbservers_recipe/) [Write a recipe for an existing procedure in Chef 5 (munin, zabbix)](https://blog.colorkrew.com/chef-solo_munin_zabbix_recipe/) [Test a recipe written in Chef ( serverspec)](https://blog.colorkrew.com/chef_serverspec/)