Skip to content
Snippets Groups Projects
Commit 5080ab1d authored by Florian Philippon's avatar Florian Philippon
Browse files

Initial commit for glusterfs cookbook

parent c8b014e0
No related branches found
No related tags found
No related merge requests found
Showing
with 530 additions and 29 deletions
......@@ -4,4 +4,4 @@ Changelog
1.0.0
-----
- Initial version
- Initial version with Centos 7 support
......@@ -3,3 +3,5 @@ source 'https://rubygems.org'
gem 'berkshelf'
gem 'test-kitchen'
gem 'kitchen-docker_cli'
gem 'kitchen-inspec'
gem 'busser-inspec'
......@@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2016 Sam4Mobile
Copyright (c) 2015-2016 Sam4Mobile
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......
GlusterFS
=============
==================
Description
-----------
Installs/Configures a GlusterFS cluster using systemd
GlusterFS is a scalable network filesystem.
This cookbook focuses on deploying a GlusterFS cluster via Chef.
Requirements
------------
......@@ -16,16 +18,39 @@ Declared in [metadata.rb](metadata.rb) and in [Gemfile](Gemfile).
### Platforms
A *systemd* managed distribution:
- RHEL Family 7, tested on Centos
- RHEL Family 7, tested on Centos 7.2
Usage
-----
### Easy Setup
Create a role `glusterfs` having `recipe['glusterfs']` in its
runlist and setting `node['glusterfs']['role']` to itself. Add this
role in the runlists of the nodes you want to use for your cluster. By default,
you need exactly 3 nodes.
### Search
By default, the *config* recipe use a search to find the members of a cluster.
The search is parametrized by a role name, defined in attribute
`node['glusterfs']['role']` which default to *glusterfs*.
Node having this role in their expanded runlist will be considered in the same
glusterfs cluster. For safety reason, if search is used, you need to define
`node['glusterfs']['size']` (3 by default). The cookbook will return
(with success) until the search return *size* nodes. This ensures the
stability of the configuration during the initial startup of a cluster.
If you do not want to use search, it is possible to define
`node['glusterfs']['hosts']` with an array containing the hostnames of
the nodes of a glusterfs cluster. In this case, *size* attribute is ignored
and search deactivated.
### Test
This cookbook is fully tested through the installation of a working 3-nodes
cluster in docker hosts. This uses kitchen, docker and some monkey-patching.
cluster in docker hosts. This uses kitchen (>= 1.5.0), docker (>= 1.10) and
a small monkey-patch.
For more information, see *.kitchen.yml* and *test* directory.
......@@ -40,14 +65,40 @@ this cookbook behavior.
Recipes
-------
### default
* default
* repository (setup yum repositories)
* package (install glusterfs-server)
* service (make sure glusterd service is enabled and started)
* configure (probe an host into the cluster and create a volume)
* client (mount a glusterfs volume)
Do some things.
Resources/Providers
-------------------
None.
### Probe
Probe an host into the GlusterFS cluster.
#### Example
```ruby
glusterfs_probe 'my-custom-host.test'
```
### Volume
#### Example
```ruby
glusterfs_volume 'myvol' do
type 'replica'
type_number 2
transport_type 'tcp'
servers ['host1.example','host2.example']
mount_points ['/mnt/brick1','/mnt/brick2']
end
```
Changelog
---------
......@@ -63,10 +114,10 @@ request.
License and Author
------------------
- Author:: Florian Philippon (<florian.philippon@s4m.io>)
- Author:: Florian Philippon (<florian.philippon@s4m.io>)
```text
Copyright (c) 2016 Sam4Mobile
Copyright (c) 2015-2016 Sam4Mobile
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......
#
# Copyright (c) 2016 Sam4Mobile
# Copyright (c) 2015-2016 Sam4Mobile
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -13,3 +13,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# EPEL Repo
default['epel']['mirrorlist'] =
'http://mirrors.fedoraproject.org/mirrorlist?repo=epel-7&arch=$basearch'
default['epel']['gpgkey'] =
'http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7'
default['glusterfs']['baserepo'] =
'http://download.gluster.org/pub/gluster/glusterfs'
default['glusterfs']['endpointrepo'] =
'LATEST/EPEL.repo/epel-$releasever/$basearch'
# GlusterFS
default['glusterfs']['server']['pkg_version'] = '3.7.10-1.el7'
# Cluster configuration
# Role used by the search to find other nodes of the cluster
default['glusterfs']['role'] = 'glusterfs'
# Hosts of the cluster, deactivate search if not empty
default['glusterfs']['hosts'] = []
# Expected size of the cluster. Ignored if hosts is not empty
default['glusterfs']['size'] = 3
......@@ -9,3 +9,6 @@ issues_url 'https://gitlab.com/s4m-chef-repositories/glusterfs/issues'
version '1.0.0'
supports 'centos', '>= 7.1'
depends 'yum'
depends 'cluster-search'
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
use_inline_resources
action :create do
host = new_resource.host
bin = new_resource.bin
if been_probed?(host)
unless node['fqdn'] == host
converge_by("Probe #{host}") do
execute "#{bin} peer probe #{host}" do
action :run
end
execute 'check_peer_status' do
command <<-EOF
#{bin} peer status | grep -A 2 -B 1 #{host} | \
grep 'Peer in Cluster (Connected)'
EOF
retries new_resource.peer_wait_retries
retry_delay new_resource.peer_wait_retry_delay
end
end
end
end
end
def been_probed?(host)
shell_out(
"#{new_resource.bin} pool list | awk '{if(NR>1)print $2}' | grep #{host}"
).exitstatus == 1
end
def whyrun_supported?
true
end
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
use_inline_resources
action :create do
volume = new_resource.name
if been_created?(volume)
converge_by("Creating #{new_resource}") do
volume_create(bind)
end
end
end
action :start do
volume = new_resource.name
if been_started?(volume)
converge_by("Starting #{new_resource}") do
shell_out(
"#{new_resource.bin} volume start #{new_resource.name}"
).error!
end
end
end
action :expand do
volume = new_resource.name
converge_by("Expanding #{new_resource}") do
shell_out(
"#{new_resource.bin} volume add-brick #{volume} #{bind}"
).error!
end
end
def bind
new_resource.mount_points.map do |mount_point|
new_resource.servers.map do |server|
"#{server}:#{mount_point}"
end
end
end
def default_volume_command(bind)
"#{new_resource.bin} volume create #{new_resource.name} \
#{new_resource.type} #{new_resource.type_number} \
#{new_resource.redundancy} \
transport #{new_resource.transport_type} \
#{bind.join(' ')} force"
end
def volume_create(bind)
shell_out(default_volume_command(bind)).error!
end
def been_created?(volume)
shell_out(
"#{new_resource.bin} volume list| grep #{volume}"
).exitstatus == 1
end
def been_started?(volume)
volume = new_resource.name(new_resource.name)
shell_out(
"#{new_resource.bin} volume info #{volume} \
| grep Status \
| awk '{print $2}' \
| grep 'Started'"
).exitstatus == 1
end
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
# Install glusterfs client
%w(glusterfs glusterfs-fuse attr).each do |pkg|
package pkg
end
if node['glusterfs']['client']
node['glusterfs']['client'].each_pair do |_key, client|
directory client['mount_point'] do
recursive true
action :create
end
mount client['mount_point'] do
device "#{client['server']}:#{client['volume']}"
fstype 'glusterfs'
action [:enable, :mount]
end
end
end
return if node['glusterfs']['client'].nil?
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
# Use ClusterSearch
::Chef::Recipe.send(:include, ClusterSearch)
gluster_cluster = cluster_search(node['glusterfs'])
return if gluster_cluster.nil?
initiator_id = node['glusterfs']['initiator_id']
if initiator_id < 1 || initiator_id > gluster_cluster['hosts'].size
raise 'Invalid id'
end
raise 'Cannot find myself in the cluster' if gluster_cluster['my_id'] == -1
if gluster_cluster['my_id'] == initiator_id
# Probe hosts into the GlusterFS cluster
gluster_cluster['hosts'].each do |host|
glusterfs_probe host
end
# Configure and start GlusterFS volumes based on attributes
node['glusterfs']['volumes'].each_pair do |_key, vol|
glusterfs_volume vol['name'] do
type vol['type']
type_number vol['type_number']
transport_type vol['transport_type']
mount_points vol['mount_points']
type vol['type']
servers gluster_cluster['hosts']
action [:create, :start]
end
end
end
......@@ -13,3 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "#{cookbook_name}::repository"
include_recipe "#{cookbook_name}::package"
include_recipe "#{cookbook_name}::service"
include_recipe "#{cookbook_name}::configure"
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
package 'glusterfs-server' do
version node['glusterfs']['server']['pkg_version']
action :install
end
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
yum_repository 'epel' do
description 'Extra Packages for Enterprise Linux 7'
mirrorlist node['epel']['mirrorlist']
gpgkey node['epel']['gpgkey']
action :create
end
gluster_base_url = node['glusterfs']['baserepo']
gluster_url = node['glusterfs']['endpointrepo']
yum_repository 'glusterfs-epel' do
description 'GlusterFS repository'
baseurl "#{gluster_base_url}/#{gluster_url}"
gpgkey "#{gluster_base_url}/LATEST/rsa.pub"
action :create
end
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
service 'glusterd' do
action [:enable, :start]
subscribes :restart, 'package[glusterfs-server]', :immediately
end
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
actions :create
default_action :create
attribute :host, kind_of: String, name_attribute: true
attribute :bin, kind_of: String, default: '/usr/sbin/gluster'
attribute :peer_wait_retries, kind_of: Integer, default: 10
attribute :peer_wait_retry_delay, kind_of: Integer, default: 10
#
# Copyright (c) 2016 Sam4Mobile
#
# 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.
#
actions :create, :start, :expand
default_action :create
attribute :name, kind_of: String, name_attribute: true
attribute :type, kind_of: String, required: false
attribute :type_number, kind_of: Integer, required: false
attribute :redundancy, kind_of: String, required: false
attribute :transport_type, kind_of: String, required: false, default: 'tcp'
attribute :mount_points, kind_of: Array, required: true
attribute :servers, kind_of: Array, required: false
attribute :bin, kind_of: String, required: false, default: '/usr/sbin/gluster'
I, [2016-04-15T14:10:16.887555 #5538] INFO -- Kitchen: -----> Starting Kitchen (v1.7.3)
E, [2016-04-15T14:10:16.887877 #5538] ERROR -- Kitchen: ------Exception-------
E, [2016-04-15T14:10:16.887898 #5538] ERROR -- Kitchen: Class: Kitchen::UserError
E, [2016-04-15T14:10:16.887910 #5538] ERROR -- Kitchen: Message: Kitchen YAML file /home/florian/Work/cookbooks/glusterfs/test/integration/glusterfs-1/.kitchen.yml does not exist.
E, [2016-04-15T14:10:16.887932 #5538] ERROR -- Kitchen: ------Backtrace-------
E, [2016-04-15T14:10:16.887941 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/loader/yaml.rb:74:in `read'
E, [2016-04-15T14:10:16.887949 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/config.rb:149:in `data'
E, [2016-04-15T14:10:16.887957 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/config.rb:128:in `suites'
E, [2016-04-15T14:10:16.887966 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/config.rb:179:in `filter_instances'
E, [2016-04-15T14:10:16.887974 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/config.rb:138:in `build_instances'
E, [2016-04-15T14:10:16.887982 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/config.rb:114:in `instances'
E, [2016-04-15T14:10:16.887990 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/command.rb:115:in `filtered_instances'
E, [2016-04-15T14:10:16.887998 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/command.rb:145:in `parse_subcommand'
E, [2016-04-15T14:10:16.888006 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/command/action.rb:38:in `block in call'
E, [2016-04-15T14:10:16.888024 #5538] ERROR -- Kitchen: /usr/lib/ruby/2.3.0/benchmark.rb:293:in `measure'
E, [2016-04-15T14:10:16.888033 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/command/action.rb:37:in `call'
E, [2016-04-15T14:10:16.888041 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/cli.rb:56:in `perform'
E, [2016-04-15T14:10:16.888050 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/cli.rb:180:in `block (2 levels) in <class:CLI>'
E, [2016-04-15T14:10:16.888058 #5538] ERROR -- Kitchen: /home/florian/.gem/ruby/2.3.0/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
E, [2016-04-15T14:10:16.888066 #5538] ERROR -- Kitchen: /home/florian/.gem/ruby/2.3.0/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
E, [2016-04-15T14:10:16.888074 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/cli.rb:321:in `invoke_task'
E, [2016-04-15T14:10:16.888083 #5538] ERROR -- Kitchen: /home/florian/.gem/ruby/2.3.0/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
E, [2016-04-15T14:10:16.888091 #5538] ERROR -- Kitchen: /home/florian/.gem/ruby/2.3.0/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
E, [2016-04-15T14:10:16.888099 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/bin/kitchen:13:in `block in <top (required)>'
E, [2016-04-15T14:10:16.888107 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/lib/kitchen/errors.rb:154:in `with_friendly_errors'
E, [2016-04-15T14:10:16.888115 #5538] ERROR -- Kitchen: /usr/lib/ruby/gems/2.3.0/gems/test-kitchen-1.7.3/bin/kitchen:13:in `<top (required)>'
E, [2016-04-15T14:10:16.888123 #5538] ERROR -- Kitchen: /home/florian/.gem/ruby/2.3.0/bin/kitchen:23:in `load'
E, [2016-04-15T14:10:16.888131 #5538] ERROR -- Kitchen: /home/florian/.gem/ruby/2.3.0/bin/kitchen:23:in `<main>'
E, [2016-04-15T14:10:16.888139 #5538] ERROR -- Kitchen: ----------------------
#
# Copyright (c) 2015-2016 Sam4Mobile
#
# 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'
describe package('glusterfs-server') do
it { should be_installed }
end
describe service('glusterd') do
it { should be_running }
it { should be_enabled }
end
describe port(240_07) do
it { should be_listening }
end
describe command(
'gluster volume info | grep -A5 myvol | grep -B 3 Started'
) do
its(:exit_status) { should eq 0 }
end
describe command(
'gluster peer status | grep "Number of Peers:" | grep "2"'
) do
its(:exit_status) { should eq 0 }
end
#
# Copyright (c) 2015-2016 Sam4Mobile
#
# 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'
describe package('glusterfs') do
it { should be_installed }
end
describe file('/mnt/data') do
it { should be_mounted.with(type: 'fuse.glusterfs') }
end
#
# Copyright (c) 2016 Sam4Mobile
#
# 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 'serverspec'
set :backend, :exec
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment