Commit 66d91a3d authored by Loic Dachary's avatar Loic Dachary

ceph::mon create or destroy monitors

* ceph::mon resource

  create a MON if ensure == present or destroy one if absent

  all combinations of keys / keyring as specified in the blueprint are
  supported

* integration tests cover all cases and unit tests are implemented to
  ensure syntax correctness

* minor corrections to other classes are included ( two nodes for
  integration tests, default values for the ceph class etc. )

* A ceph::mons class wrapper is created for compatibility with
  scenario_node_terminus

Closes-Bug: #1251443

Change-Id: Ic56a4124738006f7946ee9c166295f7048cb7854
Signed-off-by: default avatarLoic Dachary <loic@dachary.org>
parent b99ec35e
default_set: 'ubuntu-server-12042-x64'
default_set: 'two-ubuntu-server-12042-x64'
sets:
'ubuntu-server-12042-x64':
'two-ubuntu-server-12042-x64':
default_node: 'first.vm'
nodes:
'main.vm':
'first.vm':
prefab: 'ubuntu-server-12042-x64'
options:
ip: '10.11.12.1'
'second.vm':
prefab: 'ubuntu-server-12042-x64'
options:
ip: '10.11.12.2'
'one-ubuntu-server-12042-x64':
nodes:
'first.vm':
prefab: 'ubuntu-server-12042-x64'
......@@ -4,7 +4,8 @@ source 'https://rubygems.org'
group :development, :test do
gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', '~> 0.3.2'
gem 'rspec-system-puppet'
gem 'rspec-system', '= 2.8.0'
gem 'rspec-system-puppet', '= 2.2.1'
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
......
......@@ -74,9 +74,10 @@ and tests are in spec/system. It runs virtual machines and requires
* [Install Vagrant and Virtualbox](http://docs-v1.vagrantup.com/v1/docs/getting-started/)
* bundle install --path vendor/bundle
* bundle exec rake spec:system
* BUNDLE_PATH=/tmp/vendor bundle install
* BUNDLE_PATH=/tmp/vendor bundle exec rake lint
* BUNDLE_PATH=/tmp/vendor bundle exec rake spec
* BUNDLE_PATH=/tmp/vendor bundle exec rake spec:system
On success it should complete with
......
......@@ -83,7 +83,7 @@
class ceph (
$fsid,
$authentication_type = 'cephx',
$keyring = '/etc/ceph/keyring',
$keyring = undef,
$osd_pool_default_pg_num = undef,
$osd_pool_default_pgp_num = undef,
$osd_pool_default_size = undef,
......@@ -146,4 +146,4 @@ class ceph (
'global/auth_supported': value => 'none';
}
}
}
\ No newline at end of file
}
#
# Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
# Copyright (C) iWeb Technologies Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
......@@ -12,24 +14,162 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Loic Dachary <loic@dachary.org>
# Author: David Moreau Simard <dmsimard@iweb.com>
#
# Installs and configures MONs (ceph monitors)
### == Parameters
# [*mon_data*] The monitor’s data location.
# Optional. Default provided by Ceph is '/var/lib/ceph/mon/$cluster-$id'.
# [*title*] The MON id.
# Mandatory. An alphanumeric string uniquely identifying the MON.
#
# [*ensure*] Installs ( present ) or remove ( absent ) a MON
# Optional. Defaults to present.
# If set to absent, it will stop the MON service and remove
# the associated data directory.
#
# [*public_addr*] The bind IP address.
# Optional. The IPv(4|6) address on which MON binds itself.
#
# [*cluster*] The ceph cluster
# Optional. Same default as ceph.
#
# [*keyring*] The location of the keyring used by MONs
# Optional. Defaults to '/var/lib/ceph/mon/$cluster-$id/keyring'.
# [*authentication_type*] Activate or deactivate authentication
# Optional. Default to cephx.
# Authentication is activated if the value is 'cephx' and deactivated
# if the value is 'none'. If the value is 'cephx', at least one of
# key or keyring must be provided.
#
# [*key*] Authentication key for [mon.]
# Optional. $key and $keyring are mutually exclusives.
#
# [*keyring*] Path of the [mon.] keyring file
# Optional. $key and $keyring are mutually exclusives.
#
define ceph::mon (
$ensure = present,
$public_addr = undef,
$cluster = undef,
$authentication_type = 'cephx',
$key = undef,
$keyring = undef,
) {
# a puppet name translates into a ceph id, the meaning is different
$id = $name
if $cluster {
$cluster_option = "--cluster ${cluster}"
}
if $::operatingsystem == 'Ubuntu' {
$init = 'upstart'
Service {
name => 'ceph-mon',
# workaround for bug https://projects.puppetlabs.com/issues/23187
provider => 'init',
start => "start ceph-mon id=${id}",
stop => "stop ceph-mon id=${id}",
status => "status ceph-mon id=${id}",
}
} elsif $::operatingsystem == 'Debian' {
$init = 'sysvinit'
Service {
name => 'ceph',
start => "service ceph start mon.${id}",
stop => "service ceph stop mon.${id}",
status => "service ceph status mon.${id}",
}
} else {
#
# TODO: create [mon.$id] in ceph.conf for init scripts that require it
#
fail("operatingsystem = ${::operatingsystem} is not supported")
}
$mon_service = "ceph-mon-${id}"
if $ensure == present {
$ceph_mkfs = "ceph-mkfs-${id}"
if $authentication_type == 'cephx' {
if ! $key and ! $keyring {
fail("authentication_type ${authentication_type} requires either key or keyring to be set but both are undef")
}
if $key and $keyring {
fail("key (set to ${key}) and keyring (set to ${keyring}) are mutually exclusive")
}
if $key {
$keyring_path = "/tmp/ceph-mon-keyring-${id}"
file { $keyring_path:
mode => '0444',
content => "[mon.]\n\tkey = ${key}\n\tcaps mon = \"allow *\"\n",
}
File[$keyring_path] -> Exec[$ceph_mkfs]
} else {
$keyring_path = $keyring
}
} else {
$keyring_path = '/dev/null'
}
if $public_addr {
$public_addr_option = "--public_addr ${public_addr}"
}
exec { $ceph_mkfs:
command => "/bin/true # comment to satisfy puppet syntax requirements
set -ex
mon_data=\$(ceph-mon ${cluster_option} --id ${id} --show-config | sed -n -e 's/^mon_data = //p')
if [ ! -d \$mon_data ] ; then
mkdir -p \$mon_data
if ceph-mon ${cluster_option} \
${public_addr_option} \
--mkfs \
--id ${id} \
--keyring ${keyring_path} ; then
touch \$mon_data/done \$mon_data/${init} \$mon_data/keyring
else
rm -fr \$mon_data
fi
fi
",
logoutput => true,
}
->
service { $mon_service:
ensure => running,
}
if $authentication_type == 'cephx' {
if $key {
Exec[$ceph_mkfs] -> Exec["rm-keyring-${id}"]
class ceph::mon (
$mon_data = '/var/lib/ceph/mon/$cluster-$id',
$keyring = '/var/lib/ceph/mon/$cluster-$id/keyring',
) {
exec { "rm-keyring-${id}":
command => "/bin/rm ${keyring_path}",
}
}
}
# [mon]
ceph_config {
'mon/mon_data': value => $mon_data;
'mon/keyring': value => $keyring;
} else {
service { $mon_service:
ensure => stopped
}
->
exec { "remove-mon-${id}":
command => "/bin/true # comment to satisfy puppet syntax requirements
set -ex
mon_data=\$(ceph-mon ${cluster_option} --id ${id} --show-config | sed -n -e 's/mon_data = //p')
if [ -d \"\$mon_data\" -a ! -d \"\$mon_data:removed\" ] ; then
mv \$mon_data \$mon_data:removed
fi
",
logoutput => true,
}
}
}
}
\ No newline at end of file
#
# Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.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
#
# 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.
#
# Author: Loic Dachary <loic@dachary.org>
#
# Class wrapper for the benefit of scenario_node_terminus
#
class ceph::mons($args, $defaults = {}) {
create_resources(ceph::mon, $args, $defaults)
}
......@@ -20,7 +20,8 @@
# Optional. Defaults provided by ceph is '/var/lib/ceph/osd/$cluster-$id'.
#
# [*osd_journal*] The path to the OSD’s journal.
# Optional. Absolute path. Defaults to '/var/lib/ceph/osd/$cluster-$id/journal'
# Optional. Absolute path.
# Defaults to '/var/lib/ceph/osd/$cluster-$id/journal'
#
# [*osd_journal_size*] The size of the journal in megabytes.
# Optional. Default provided by Ceph.
......@@ -63,4 +64,4 @@ class ceph::osd (
'osd/osd_mkfs_options': value => $osd_mkfs_options;
'osd/osd_mount_options': value => $osd_mount_options;
}
}
\ No newline at end of file
}
......@@ -37,7 +37,7 @@ describe 'ceph' do
'ensure' => 'present') }
it { should contain_ceph_config('global/fsid').with_value('d5252e7d-75bc-4083-85ed-fe51fa83f62b') }
it { should contain_ceph_config('global/keyring').with_value('/etc/ceph/keyring') }
it { should_not contain_ceph_config('global/keyring').with_value('/etc/ceph/keyring') }
it { should_not contain_ceph_config('global/osd_pool_default_pg_num').with_value('128') }
it { should_not contain_ceph_config('global/osd_pool_default_pgp_num').with_value('128') }
it { should_not contain_ceph_config('global/osd_pool_default_size').with_value('3') }
......@@ -118,4 +118,4 @@ describe 'ceph' do
it { should contain_ceph_config('global/auth_supported').with_value('none') }
end
end
end
\ No newline at end of file
end
#
# Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.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
#
# 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.
#
# Author: Loic Dachary <loic@dachary.org>
#
require 'spec_helper'
describe 'ceph::mons' do
let :facts do
{
:operatingsystem => 'Ubuntu',
}
end
let :params do
{
:args => {
'A' => {
'public_addr' => '1.2.3.4',
'authentication_type' => 'none',
},
'B' => {
'public_addr' => '1.2.3.4',
'authentication_type' => 'none',
},
},
:defaults => {
'cluster' => 'CLUSTER',
},
}
end
it {
should contain_service('ceph-mon-A').with('ensure' => "running")
should contain_service('ceph-mon-B').with('ensure' => "running")
}
# it { p subject.resources }
end
# Local Variables:
# compile-command: "cd ../.. ;
# export BUNDLE_PATH=/tmp/vendor ;
# bundle install ;
# bundle exec rake spec
# "
# End:
# Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
# Copyright (C) iWeb Technologies Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
......@@ -12,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Loic Dachary <loic@dachary.org>
# Author: David Moreau Simard <dmsimard@iweb.com>
require 'spec_helper'
......@@ -19,30 +21,38 @@ require 'spec_helper'
describe 'ceph::mon' do
describe 'Debian Family' do
let :facts do
{
:osfamily => 'Debian',
}
end
describe "with default params" do
describe "with custom params" do
it { should contain_ceph_config('mon/mon_data').with_value('/var/lib/ceph/mon/$cluster-$id') }
it { should contain_ceph_config('mon/keyring').with_value('/var/lib/ceph/mon/$cluster-$id/keyring') }
let :facts do
{
:operatingsystem => 'Ubuntu',
}
end
end
let :title do
'A'
end
describe "with custom params" do
let :params do
{
:mon_data => '/usr/local/ceph/var/lib/mon/mon._id',
:keyring => '/usr/local/ceph/var/lib/mon/mon._id/keyring',
:public_addr => '127.0.0.1',
:authentication_type => 'none',
}
end
it { should_not contain_ceph_config('mon/mon_data').with_value('/var/lib/ceph/mon/_cluster-_id') }
it { should_not contain_ceph_config('mon/keyring').with_value('/var/lib/ceph/mon/_cluster-_id/keyring') }
it { should contain_service('ceph-mon-A').with('ensure' => "running") }
# it { p subject.resources }
end
end
end
\ No newline at end of file
end
# Local Variables:
# compile-command: "cd ../.. ;
# export BUNDLE_PATH=/tmp/vendor ;
# bundle install ;
# bundle exec rake spec
# "
# End:
......@@ -30,9 +30,17 @@ RSpec.configure do |c|
c.include RSpecSystemPuppet::Helpers
c.before :suite do
puppet_install
puppet_master_install
puppet_module_install(:source => proj_root, :module_name => 'ceph')
shell 'puppet module install --version 1.4.0 puppetlabs/apt'
[ 'first.vm', 'second.vm' ].each do |vm|
puppet_install(:node => vm)
puppet_module_install(:source => proj_root,
:module_name => 'ceph',
:node => vm)
shell(:command => 'puppet module install --version 4.1.0 puppetlabs/stdlib',
:node => vm)
shell(:command => 'puppet module install --version 1.0.0 puppetlabs/inifile',
:node => vm)
shell(:command => 'puppet module install --version 1.4.0 puppetlabs/apt',
:node => vm)
end
end
end
#
# Copyright 2013 Cloudwatt <libre-licensing@cloudwatt.com>
#
# Author: Loic Dachary <loic@dachary.org>
#
# 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.
#
require 'spec_helper_system'
describe 'ceph::mon' do
releases = [ 'cuttlefish', 'dumpling', 'emperor' ]
fsid = 'a4807c9a-e76f-4666-a297-6d6cbc922e3a'
# ['emperor'].each do |release|
releases.each do |release|
describe release do
it 'should install one monitor with cephx and key' do
pp = <<-EOS
class { 'ceph::repo':
release => '#{release}',
}
->
class { 'ceph':
fsid => '#{fsid}',
mon_host => $::ipaddress_eth0,
}
->
ceph::mon { 'a':
public_addr => $::ipaddress_eth0,
key => 'AQCztJdSyNb0NBAASA2yPZPuwXeIQnDJ9O8gVw==',
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
r.refresh
r.exit_code.should_not == 1
end
shell 'test -f /etc/ceph/ceph.client.admin.keyring' do |r|
r.exit_code.should be_zero
end
end
it 'should uninstall one monitor' do
pp = <<-EOS
ceph::mon { 'a':
ensure => absent,
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
end
shell 'status ceph-mon id=a' do |r|
r.stdout.should be_empty
r.stderr.should =~ /Unknown instance: ceph.a/
r.exit_code.should_not be_zero
end
end
end
end
# [].each do |release|
releases.each do |release|
describe release do
it 'should install one monitor with cephx and keyring' do
key = 'AQCztJdSyNb0NBAASA2yPZPuwXeIQnDJ9O8gVw=='
keyring = "[mon.]\\n\\tkey = ${key}\\n\\tcaps mon = \"allow *\""
keyring_path = "/tmp/keyring"
shell "echo -e '${keyring}' > ${keyring_path}"
pp = <<-EOS
class { 'ceph::repo':
release => '#{release}',
}
->
class { 'ceph':
fsid => '#{fsid}',
mon_host => $::ipaddress_eth0,
}
->
ceph::mon { 'a':
public_addr => $::ipaddress_eth0,
keyring => '${keyring_path}',
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
r.refresh
r.exit_code.should_not == 1
end
shell 'test -f /etc/ceph/ceph.client.admin.keyring' do |r|
r.exit_code.should be_zero
end
end
it 'should uninstall one monitor' do
pp = <<-EOS
ceph::mon { 'a':
ensure => absent,
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
end
shell 'status ceph-mon id=a' do |r|
r.stdout.should be_empty
r.stderr.should =~ /Unknown instance: ceph.a/
r.exit_code.should_not be_zero
end
end
end
end
# [].each do |release|
releases.each do |release|
describe release do
it 'should install one monitor no cephx' do
pp = <<-EOS
class { 'ceph::repo':
release => '#{release}',
}
->
class { 'ceph':
fsid => '#{fsid}',
mon_host => $::ipaddress_eth0,
authentication_type => 'none',
}
->
ceph::mon { 'a':
public_addr => $::ipaddress_eth0,
authentication_type => 'none',
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
r.refresh
r.exit_code.should_not == 1
end
shell 'ceph -s' do |r|
r.stdout.should =~ /1 mons at/
r.stderr.should be_empty
r.exit_code.should be_zero
end
end
it 'should uninstall one monitor' do
pp = <<-EOS
ceph::mon { 'a':
ensure => absent,
}
EOS
puppet_apply(pp) do |r|
r.exit_code.should_not == 1
end
shell 'status ceph-mon id=a' do |r|
r.stdout.should be_empty
r.stderr.should =~ /Unknown instance: ceph.a/
r.exit_code.should_not be_zero
end
end
end
end
# [].each do |release|
releases.each do |release|
describe release do
it 'should install two monitors, two hosts, no cephx' do
[ 'first', 'second' ].each do |mon|
pp = <<-EOS
class { 'ceph::repo':
release => '#{release}',
}
->
class { 'ceph':
fsid => '#{fsid}',
mon_host => '10.11.12.1,10.11.12.2',
public_network => '10.11.12.0/24',
authentication_type => 'none',
}
->
ceph::mon { '#{mon}':
authentication_type => 'none',
}
EOS
puppet_apply(:node => "#{mon}.vm", :code => pp) do |r|
r.exit_code.should_not == 1
r.refresh
r.exit_code.should_not == 1
end
end
shell 'ceph -s' do |r|
r.stdout.should =~ /2 mons .* quorum 0,1 first,second/
r.stderr.should be_empty
r.exit_code.should be_zero
end
end
it 'should uninstall two monitors' do
[ 'first', 'second' ].each do |mon|
pp = <<-EOS
ceph::mon { '#{mon}':
ensure => absent,
}
EOS
puppet_apply(:node => "#{mon}.vm", :code => pp) do |r|
r.exit_code.should_not == 1
end
shell "status ceph-mon id=#{mon}" do |r|
r.stdout.should be_empty
r.stderr.should =~ /Unknown instance: ceph.#{mon}/
r.exit_code.should_not be_zero
end
end
end
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment