Disables Ceph's Apache on Ubuntu 13.10 and 14.04 141/head
authorWalter Huf <walter.huf@corvisa.com>
Wed, 30 Jul 2014 18:01:52 +0000 (13:01 -0500)
committerWalter Huf <walter.huf@corvisa.com>
Wed, 30 Jul 2014 18:01:52 +0000 (13:01 -0500)
64 files changed:
.gitignore [new file with mode: 0644]
.kitchen.yml [new file with mode: 0644]
.rubocop.yml [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
Berksfile [new file with mode: 0644]
CHANGELOG.md [new file with mode: 0644]
Gemfile [new file with mode: 0644]
README.md [new file with mode: 0644]
Rakefile [new file with mode: 0644]
attributes/cephfs.rb [new file with mode: 0644]
attributes/conf.rb [new file with mode: 0644]
attributes/default.rb [new file with mode: 0644]
attributes/mds.rb [new file with mode: 0644]
attributes/mon.rb [new file with mode: 0644]
attributes/osd.rb [new file with mode: 0644]
attributes/radosgw.rb [new file with mode: 0644]
attributes/radosgw_apache2.rb [new file with mode: 0644]
attributes/repo.rb [new file with mode: 0644]
infrastructure.yml [new file with mode: 0644]
libraries/default.rb [new file with mode: 0644]
libraries/utils.rb [new file with mode: 0644]
metadata.rb [new file with mode: 0644]
providers/cephfs.rb [new file with mode: 0644]
providers/client.rb [new file with mode: 0644]
recipes/_common.rb [new file with mode: 0644]
recipes/_common_install.rb [new file with mode: 0644]
recipes/all_in_one.rb [new file with mode: 0644]
recipes/apt.rb [new file with mode: 0644]
recipes/cephfs.rb [new file with mode: 0644]
recipes/cephfs_install.rb [new file with mode: 0644]
recipes/conf.rb [new file with mode: 0644]
recipes/install.rb [new file with mode: 0644]
recipes/mds.rb [new file with mode: 0644]
recipes/mds_install.rb [new file with mode: 0644]
recipes/mon.rb [new file with mode: 0644]
recipes/mon_install.rb [new file with mode: 0644]
recipes/osd.rb [new file with mode: 0644]
recipes/osd_install.rb [new file with mode: 0644]
recipes/radosgw.rb [new file with mode: 0644]
recipes/radosgw_apache2.rb [new file with mode: 0644]
recipes/radosgw_apache2_repo.rb [new file with mode: 0644]
recipes/radosgw_install.rb [new file with mode: 0644]
recipes/repo.rb [new file with mode: 0644]
recipes/rpm.rb [new file with mode: 0644]
recipes/tgt.rb [new file with mode: 0644]
resources/cephfs.rb [new file with mode: 0644]
resources/client.rb [new file with mode: 0644]
roles/ceph-mds.json [new file with mode: 0644]
roles/ceph-mon.json [new file with mode: 0644]
roles/ceph-osd.json [new file with mode: 0644]
roles/ceph-radosgw.json [new file with mode: 0644]
roles/ceph-tgt.json [new file with mode: 0644]
templates/default/ceph.conf.erb [new file with mode: 0644]
templates/default/mods/fastcgi.conf.erb [new file with mode: 0644]
templates/default/rgw.conf.erb [new file with mode: 0644]
templates/default/s3gw.fcgi.erb [new file with mode: 0644]
test/cookbooks/ceph_test/CHANGELOG.md [new file with mode: 0644]
test/cookbooks/ceph_test/README.md [new file with mode: 0644]
test/cookbooks/ceph_test/attributes/cephfs_mount.rb [new file with mode: 0644]
test/cookbooks/ceph_test/metadata.rb [new file with mode: 0644]
test/cookbooks/ceph_test/recipes/cephfs.rb [new file with mode: 0644]
test/integration/Vagrantfile.erb [new file with mode: 0644]
test/integration/aio/bats/ceph-running.bats [new file with mode: 0644]
test/integration/aio/bats/cephfs.bats [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..351201e
--- /dev/null
@@ -0,0 +1,17 @@
+.vagrant
+Berksfile.lock
+*~
+*#
+.#*
+\#*#
+.*.sw[a-z]
+*.un~
+/cookbooks
+
+# Bundler
+Gemfile.lock
+bin/*
+.bundle/*
+
+.kitchen/
+.kitchen.local.yml
diff --git a/.kitchen.yml b/.kitchen.yml
new file mode 100644 (file)
index 0000000..ee21cc1
--- /dev/null
@@ -0,0 +1,64 @@
+---
+driver_plugin: vagrant
+driver_config:
+  vagrantfile_erb: test/integration/Vagrantfile.erb
+  require_chef_omnibus: true
+
+platforms:
+- name: ubuntu-12.04
+  run_list:
+    - recipe[apt]
+- name: ubuntu-14.04
+  run_list:
+    - recipe[apt]
+- name: debian-7.4
+  run_list:
+    - recipe[apt]
+- name: centos-6.5
+- name: centos-5.10
+- name: fedora-18
+
+provisioner:
+    name: chef_zero
+
+suites:
+- name: default
+  run_list:
+    - "recipe[ceph::repo]"
+    - "recipe[ceph]"
+  attributes: &defaults
+    ceph:
+      config:
+        fsid: ae3f1d03-bacd-4a90-b869-1a4fabb107f2
+        mon_initial_members:
+          - "127.0.0.1"
+- name: osd
+  run_list:
+    - "role[ceph-osd]"
+  attributes: *defaults
+- name: mon
+  run_list:
+    - "role[ceph-mon]"
+  attributes: *defaults
+- name: mds
+  run_list:
+    - "role[ceph-mds]"
+  attributes: *defaults
+- name: radosgw
+  run_list:
+    - "role[ceph-radosgw]"
+  attributes: *defaults
+- name: aio
+  attributes:
+    ceph:
+      config-sections:
+        global:
+          "osd journal size" : 128
+          "osd pool default size": 1
+      osd_devices:
+        - { device: "/dev/sdb" }
+        - { device: "/dev/sdc" }
+        - { device: "/dev/sdd" }
+  run_list:
+    - recipe[ceph::all_in_one]
+    - recipe[ceph_test::cephfs]
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644 (file)
index 0000000..0fde6a5
--- /dev/null
@@ -0,0 +1,28 @@
+AllCops:
+  Include:
+    - Berksfile
+    - Gemfile
+    - Rakefile
+    - Thorfile
+    - Guardfile
+  Exclude:
+    - vendor/**
+
+ClassLength:
+  Enabled: false
+Documentation:
+  Enabled: false
+Encoding:
+  Enabled: false
+HashSyntax:
+  Enabled: false
+LineLength:
+  Enabled: false
+MethodLength:
+  Enabled: false
+SignalException:
+  Enabled: false
+TrailingComma:
+  Enabled: false
+WordArray:
+  Enabled: false
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..7d2bad2
--- /dev/null
@@ -0,0 +1,7 @@
+language: ruby
+rvm:
+  - 1.9.3
+  - 2.0.0
+bundler_args: --without integration
+script:
+  - bundle exec rake travis
diff --git a/Berksfile b/Berksfile
new file mode 100644 (file)
index 0000000..8b96da8
--- /dev/null
+++ b/Berksfile
@@ -0,0 +1,8 @@
+site :opscode
+
+metadata
+
+group :integration do
+  cookbook 'apt'
+  cookbook 'ceph_test', path: 'test/cookbooks/ceph_test'
+end
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..bd9bf1c
--- /dev/null
@@ -0,0 +1,17 @@
+ceph
+====
+
+v0.2.0 (2014-03-03)
+-------------------
+
+- Add tests and fixes related.
+- Add ceph-extra
+- Fix searching feature
+- Refactor RPM part
+- Add iscsi tgt
+
+
+v0.1.0 (2013-07-18)
+-------------------
+
+- Initial changelog
diff --git a/Gemfile b/Gemfile
new file mode 100644 (file)
index 0000000..39c60fb
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,14 @@
+source 'https://rubygems.org'
+
+gem 'chef', '~> 11'
+gem 'berkshelf', '~> 2.0.10'
+
+group :test do
+  gem 'foodcritic', '~> 3.0'
+  gem 'rubocop', '~> 0.23.0'
+end
+
+group :integration do
+  gem 'test-kitchen', '~> 1.1.1'
+  gem 'kitchen-vagrant', '~> 0.14'
+end
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..892708c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,140 @@
+# Chef cookbook [![Build Status](https://travis-ci.org/ceph/ceph-cookbook.svg?branch=master)](https://travis-ci.org/ceph/ceph-cookbook) [![Gitter chat](https://badges.gitter.im/ceph/ceph-cookbook.png)](https://gitter.im/ceph/ceph-cookbook)
+
+## DESCRIPTION
+
+Installs and configures Ceph, a distributed network storage and filesystem designed to provide excellent performance, reliability, and scalability.
+
+The current version is focused towards deploying Monitors and OSD on Ubuntu.
+
+For documentation on how to use this cookbook, refer to the [USAGE](#USAGE) section.
+
+For help, use [Gitter chat](https://gitter.im/ceph/ceph-cookbook), [mailing-list](mailto:ceph-users-join@lists.ceph.com) or [issues](https://github.com/ceph/ceph-cookbook/issues)
+
+## REQUIREMENTS
+
+### Chef
+
+>= 11.6.0
+
+### Platform
+
+Tested as working:
+
+* Ubuntu Precise (12.04)
+
+### Cookbooks
+
+The ceph cookbook requires the following cookbooks from Opscode:
+
+https://github.com/opscode/cookbooks
+
+* apt
+* apache2
+
+
+## ATTRIBUTES
+
+### Ceph Rados Gateway
+
+* node[:ceph][:radosgw][:api_fqdn]
+* node[:ceph][:radosgw][:admin_email]
+* node[:ceph][:radosgw][:rgw_addr]
+
+## TEMPLATES
+
+## USAGE
+
+Ceph cluster design is beyond the scope of this README, please turn to the
+public wiki, mailing lists, visit our IRC channel, or contact Inktank:
+
+http://ceph.com/docs/master
+http://ceph.com/resources/mailing-list-irc/
+http://www.inktank.com/
+
+
+### Ceph Monitor
+
+Ceph monitor nodes should use the ceph-mon role.
+
+Includes:
+
+* ceph::default
+* ceph::conf
+
+### Ceph Metadata Server
+
+Ceph metadata server nodes should use the ceph-mds role.
+
+Includes:
+
+* ceph::default
+
+### Ceph OSD
+
+Ceph OSD nodes should use the ceph-osd role
+
+Includes:
+
+* ceph::default
+* ceph::conf
+
+### Ceph Rados Gateway
+
+Ceph Rados Gateway nodes should use the ceph-radosgw role
+
+## Resources/Providers
+
+### ceph\_client
+
+The ceph\_client LWRP provides an easy way to construct a Ceph client key. These keys are needed by anything that needs to talk to the Ceph cluster, including RadosGW, CephFS, and RBD access.
+
+#### Actions
+
+- :add - creates a client key with the given parameters
+
+#### Parameters
+
+- :name - name attribute. The name of the client key to create. This is used to provide a default for the other parameters
+- :caps - A hash of capabilities that should be granted to the client key. Defaults to `{ 'mon' => 'allow r', 'osd' => 'allow r' }`
+- :as\_keyring - Whether the key should be saved in a keyring format or a simple secret key. Defaults to true, meaning it is saved as a keyring
+- :keyname - The key name to register in Ceph. Defaults to `client.#{name}.#{hostname}`
+- :filename - Where to save the key. Defaults to `/etc/ceph/ceph.client.#{name}.#{hostname}.keyring` if `as_keyring` and `/etc/ceph/ceph.client.#{name}.#{hostname}.secret` if not `as_keyring`
+- :owner - Which owner should own the saved key file. Defaults to root
+- :group - Which group should own the saved key file. Defaults to root
+- :mode - What file mode should be applied. Defaults to '00640'
+
+### ceph\_cephfs
+
+The ceph\_cephfs LWRP provides an easy way to mount CephFS. It will automatically create a Ceph client key for the machine and mount CephFS to the specified location. If the kernel client is used, instead of the fuse client, a pre-existing subdirectory of CephFS can be mounted instead of the root.
+
+#### Actions
+
+- :mount - mounts CephFS
+- :umount - unmounts CephFS
+- :remount - remounts CephFS
+- :enable - adds an fstab entry to mount CephFS
+- :disable - removes an fstab entry to mount CephFS
+
+#### Parameters
+
+- :directory - name attribute. Where to mount CephFS in the local filesystem
+- :use\_fuse - whether to use ceph-fuse or the kernel client to mount the filesystem. ceph-fuse is updated more often, but the kernel client allows for subdirectory mounting. Defaults to true
+- :cephfs\_subdir - which CephFS subdirectory to mount. Defaults to '/'. An exception will be thrown if this option is set to anything other than '/' if use\_fuse is also true
+
+## LICENSE AND AUTHORS
+
+* Author: Kyle Bader <kyle.bader@dreamhost.com>
+
+* Copyright 2013, DreamHost Web Hosting and Inktank Storage Inc.
+
+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.
diff --git a/Rakefile b/Rakefile
new file mode 100644 (file)
index 0000000..4a798ce
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,48 @@
+#!/usr/bin/env rake
+
+# Style tests. Rubocop and Foodcritic
+namespace :style do
+  begin
+    require 'rubocop/rake_task'
+    desc 'Run Ruby style checks'
+    RuboCop::RakeTask.new(:ruby)
+  rescue LoadError
+    puts '>>>>> Rubocop gem not loaded, omitting tasks' unless ENV['CI']
+  end
+
+  begin
+    require 'foodcritic'
+
+    desc 'Run Chef style checks'
+    FoodCritic::Rake::LintTask.new(:chef) do |t|
+      t.options = {
+        fail_tags: ['any'],
+        tags: ['~FC003'],
+        chef_version: '11.6.0'
+      }
+    end
+  rescue LoadError
+    puts '>>>>> foodcritic gem not loaded, omitting tasks' unless ENV['CI']
+  end
+end
+
+desc 'Run all style checks'
+task style: ['style:chef', 'style:ruby']
+
+# Integration tests. Kitchen.ci
+namespace :integration do
+  begin
+    require 'kitchen/rake_tasks'
+
+    desc 'Run kitchen integration tests'
+    Kitchen::RakeTasks.new
+  rescue LoadError
+    puts '>>>>> Kitchen gem not loaded, omitting tasks' unless ENV['CI']
+  end
+end
+
+desc 'Run all tests on Travis'
+task travis: ['style']
+
+# Default
+task default: ['style', 'integration:kitchen:all']
diff --git a/attributes/cephfs.rb b/attributes/cephfs.rb
new file mode 100644 (file)
index 0000000..a832d9d
--- /dev/null
@@ -0,0 +1,10 @@
+default['ceph']['cephfs_mount'] = '/ceph'
+
+case node['platform_family']
+when 'debian'
+  packages = ['ceph-fs-common', 'ceph-fuse']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['cephfs']['packages'] = packages
+else
+  default['ceph']['cephfs']['packages'] = []
+end
diff --git a/attributes/conf.rb b/attributes/conf.rb
new file mode 100644 (file)
index 0000000..8836945
--- /dev/null
@@ -0,0 +1,3 @@
+default['ceph']['config'] = {}
+default['ceph']['config-sections'] = {}
+default['ceph']['search_environment'] = true
diff --git a/attributes/default.rb b/attributes/default.rb
new file mode 100644 (file)
index 0000000..e05bec6
--- /dev/null
@@ -0,0 +1,24 @@
+default['ceph']['install_debug'] = false
+default['ceph']['encrypted_data_bags'] = false
+
+default['ceph']['install_repo'] = true
+
+case node['platform']
+when 'ubuntu'
+  default['ceph']['init_style'] = 'upstart'
+else
+  default['ceph']['init_style'] = 'sysvinit'
+end
+
+case node['platform_family']
+when 'debian'
+  packages = ['ceph-common']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['packages'] = packages
+when 'rhel', 'fedora'
+  packages = ['ceph']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['packages'] = packages
+else
+  default['ceph']['packages'] = []
+end
diff --git a/attributes/mds.rb b/attributes/mds.rb
new file mode 100644 (file)
index 0000000..54c21cd
--- /dev/null
@@ -0,0 +1,12 @@
+include_attribute 'ceph'
+
+default['ceph']['mds']['init_style'] = node['init_style']
+
+case node['platform_family']
+when 'debian'
+  packages = ['ceph-mds']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['mds']['packages'] = packages
+else
+  default['ceph']['mds']['packages'] = []
+end
diff --git a/attributes/mon.rb b/attributes/mon.rb
new file mode 100644 (file)
index 0000000..5d146e6
--- /dev/null
@@ -0,0 +1,14 @@
+include_attribute 'ceph'
+
+default['ceph']['mon']['init_style'] = node['ceph']['init_style']
+
+default['ceph']['mon']['secret_file'] = '/etc/chef/secrets/ceph_mon'
+
+case node['platform_family']
+when 'debian', 'rhel', 'fedora'
+  packages = ['ceph']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['mon']['packages'] = packages
+else
+  default['ceph']['mon']['packages'] = []
+end
diff --git a/attributes/osd.rb b/attributes/osd.rb
new file mode 100644 (file)
index 0000000..addbcce
--- /dev/null
@@ -0,0 +1,14 @@
+include_attribute 'ceph'
+
+default['ceph']['osd']['init_style'] = node['ceph']['init_style']
+
+default['ceph']['osd']['secret_file'] = '/etc/chef/secrets/ceph_osd'
+
+case node['platform_family']
+when 'debian', 'rhel', 'fedora'
+  packages = ['ceph']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['osd']['packages'] = packages
+else
+  default['ceph']['osd']['packages'] = []
+end
diff --git a/attributes/radosgw.rb b/attributes/radosgw.rb
new file mode 100644 (file)
index 0000000..833f3c6
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Cookbook Name:: ceph
+# Attributes:: radosgw
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+#
+
+include_attribute 'ceph'
+
+default['ceph']['radosgw']['api_fqdn'] = 'localhost'
+default['ceph']['radosgw']['admin_email'] = 'admin@example.com'
+default['ceph']['radosgw']['rgw_addr'] = '*:80'
+default['ceph']['radosgw']['rgw_port'] = false
+default['ceph']['radosgw']['webserver_companion'] = 'apache2' # can be false
+default['ceph']['radosgw']['use_apache_fork'] = true
+default['ceph']['radosgw']['init_style'] = node['ceph']['init_style']
+
+case node['platform_family']
+when 'debian'
+  packages = ['radosgw']
+  packages += debug_packages(packages) if node['ceph']['install_debug']
+  default['ceph']['radosgw']['packages'] = packages
+when 'rhel', 'fedora', 'suse'
+  default['ceph']['radosgw']['packages'] = ['ceph-radosgw']
+else
+  default['ceph']['radosgw']['packages'] = []
+end
diff --git a/attributes/radosgw_apache2.rb b/attributes/radosgw_apache2.rb
new file mode 100644 (file)
index 0000000..047c2a8
--- /dev/null
@@ -0,0 +1,6 @@
+case node['platform_family']
+when 'debian', 'suse'
+  default['ceph']['radosgw']['apache2']['packages'] = ['libapache2-mod-fastcgi']
+when 'rhel', 'fedora'
+  default['ceph']['radosgw']['apache2']['packages'] = ['mod_fastcgi']
+end
diff --git a/attributes/repo.rb b/attributes/repo.rb
new file mode 100644 (file)
index 0000000..2da7d42
--- /dev/null
@@ -0,0 +1,52 @@
+default['ceph']['branch'] = 'stable' # Can be stable, testing or dev.
+# Major release version to install or gitbuilder branch
+default['ceph']['version'] = 'dumpling'
+default['ceph']['el_add_epel'] = true
+default['ceph']['repo_url'] = 'http://ceph.com'
+default['ceph']['extras_repo_url'] = 'http://ceph.com/packages/ceph-extras'
+default['ceph']['extras_repo'] = false
+
+case node['platform_family']
+when 'debian'
+  # Debian/Ubuntu default repositories
+  default['ceph']['debian']['stable']['repository'] = "#{node['ceph']['repo_url']}/debian-#{node['ceph']['version']}/"
+  default['ceph']['debian']['stable']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+  default['ceph']['debian']['testing']['repository'] = "#{node['ceph']['repo_url']}/debian-testing/"
+  default['ceph']['debian']['testing']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+  default['ceph']['debian']['dev']['repository'] = "http://gitbuilder.ceph.com/ceph-deb-#{node['lsb']['codename']}-x86_64-basic/ref/#{node['ceph']['version']}"
+  default['ceph']['debian']['dev']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
+  default['ceph']['debian']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/debian/"
+  default['ceph']['debian']['extras']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+when 'rhel'
+  # Redhat/CentOS default repositories
+  default['ceph']['rhel']['stable']['repository'] = "#{node['ceph']['repo_url']}/rpm-#{node['ceph']['version']}/el6/x86_64/"
+  default['ceph']['rhel']['stable']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+  default['ceph']['rhel']['testing']['repository'] = "#{node['ceph']['repo_url']}/rpm-testing/el6/x86_64/"
+  default['ceph']['rhel']['testing']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+  default['ceph']['rhel']['dev']['repository'] = "http://gitbuilder.ceph.com/ceph-rpm-centos6-x86_64-basic/ref/#{node['ceph']['version']}/x86_64/"
+  default['ceph']['rhel']['dev']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
+  default['ceph']['rhel']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/rpm/rhel6/x86_64/"
+  default['ceph']['rhel']['extras']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+when 'fedora'
+  # Fedora default repositories
+  default['ceph']['fedora']['stable']['repository'] = "#{node['ceph']['repo_url']}/rpm-#{node['ceph']['version']}/fc#{node['platform_version']}/x86_64/"
+  default['ceph']['fedora']['stable']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+  default['ceph']['fedora']['testing']['repository'] = "#{node['ceph']['repo_url']}/rpm-testing/fc#{node['platform_version']}/x86_64/"
+  default['ceph']['fedora']['testing']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+  default['ceph']['fedora']['dev']['repository'] = "http://gitbuilder.ceph.com/ceph-rpm-fc#{node['platform_version']}-x86_64-basic/ref/#{node['ceph']['version']}/RPMS/x86_64/"
+  default['ceph']['fedora']['dev']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
+  default['ceph']['fedora']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/rpm/fedora#{node['platform_version']}/x86_64/"
+  default['ceph']['fedora']['extras']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
+when 'suse'
+  # (Open)SuSE default repositories
+  # Chef doesn't make a difference between suse and opensuse
+  suse = Mixlib::ShellOut.new("head -n1 /etc/SuSE-release| awk '{print $1}'").run_command.stdout.chomp.downcase
+  suse = 'sles' if suse == 'suse'
+  suse_version = suse << Mixlib::ShellOut.new("grep VERSION /etc/SuSE-release | awk -F'= ' '{print $2}'").run_command.stdout.chomp
+
+  default['ceph']['suse']['stable']['repository'] = "#{node['ceph']['repo_url']}/rpm-#{node['ceph']['version']}/#{suse_version}/x86_64/ceph-release-1-0.#{suse_version}.noarch.rpm"
+  default['ceph']['suse']['testing']['repository'] = "#{node['ceph']['repo_url']}/rpm-testing/#{suse_version}/x86_64/ceph-release-1-0.#{suse_version}.noarch.rpm"
+  default['ceph']['suse']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/rpm/#{suse_version}/x86_64/"
+else
+  fail "#{node['platform_family']} is not supported"
+end
diff --git a/infrastructure.yml b/infrastructure.yml
new file mode 100644 (file)
index 0000000..de8655b
--- /dev/null
@@ -0,0 +1,6 @@
+roles:
+- ceph-mds:
+- ceph-mon:
+- ceph-osd:
+- ceph-radosgw:
+- ceph-tgt:
diff --git a/libraries/default.rb b/libraries/default.rb
new file mode 100644 (file)
index 0000000..acb78c7
--- /dev/null
@@ -0,0 +1,182 @@
+require 'json'
+
+def crowbar?
+  !defined?(Chef::Recipe::Barclamp).nil?
+end
+
+def mon_env_search_string
+  if crowbar?
+    mon_roles = search(:role, 'name:crowbar-* AND run_list:role\[ceph-mon\]')
+    unless mon_roles.empty?
+      search_string = mon_roles.map { |role_object| 'roles:' + role_object.name }.join(' OR ')
+      search_string = "(#{search_string}) AND ceph_config_environment:#{node['ceph']['config']['environment']}"
+    end
+  else
+    search_string = 'ceph_is_mon:true'
+    if node['ceph']['search_environment'].is_a?(String)
+      # search for nodes with this particular env
+      search_string += " AND chef_environment:#{node['ceph']['search_environment']}"
+    elsif node['ceph']['search_environment']
+      # search for any nodes with this environment
+      search_string += " AND chef_environment:#{node.chef_environment}"
+    else
+      # search for any mon nodes
+    end
+  end
+  search_string
+end
+
+def mon_nodes
+  search_string = mon_env_search_string
+
+  if use_cephx? && !node['ceph']['encrypted_data_bags']
+    search_string = "(#{search_string}) AND (ceph_bootstrap_osd_key:*)"
+  end
+  search(:node, search_string)
+end
+
+def osd_secret
+  if node['ceph']['encrypted_data_bags']
+    secret = Chef::EncryptedDataBagItem.load_secret(node['ceph']['osd']['secret_file'])
+    return Chef::EncryptedDataBagItem.load('ceph', 'osd', secret)['secret']
+  else
+    return mon_nodes[0]['ceph']['bootstrap_osd_key']
+  end
+end
+
+# If public_network is specified with one or more networks, we need to
+# search for a matching monitor IP in the node environment.
+# 1. For each public network specified:
+#    a. We look if the network is IPv6 or IPv4
+#    b. We look for a route matching the network
+#    c. If we found match, we return the IP with the port
+def find_node_ip_in_network(network, nodeish = nil)
+  require 'netaddr'
+  nodeish = node unless nodeish
+  network.split(/\s*,\s*/).each do |n|
+    net = NetAddr::CIDR.create(n)
+    nodeish['network']['interfaces'].each do |_iface, addrs|
+      addresses = addrs['addresses'] || []
+      addresses.each do |ip, params|
+        return ip_address_to_ceph_address(ip, params) if ip_address_in_network?(ip, params, net)
+      end
+    end
+  end
+  nil
+end
+
+def ip_address_in_network?(ip, params, net)
+  # Find the IP on this interface that matches the public_network
+  # Uses a few heuristics to find the primary IP that ceph would bind to
+  # Most secondary IPs never have a broadcast value set
+  # Other secondary IPs have a prefix of /32
+  # Match the prefix that we want from the public_network prefix
+  if params['family'] == 'inet' && net.version == 4
+    ip4_address_in_network?(ip, params, net)
+  elsif params['family'] == 'inet6' && net.version == 6
+    ip6_address_in_network?(ip, params, net)
+  else
+    false
+  end
+end
+
+def ip4_address_in_network?(ip, params, net)
+  net.contains?(ip) && params.key?('broadcast') && params['prefixlen'].to_i == net.bits
+end
+
+def ip6_address_in_network?(ip, params, net)
+  net.contains?(ip) && params['prefixlen'].to_i == net.bits
+end
+
+def ip_address_to_ceph_address(ip, params)
+  if params['family'].eql?('inet')
+    return "#{ip}:6789"
+  elsif params['family'].eql?('inet6')
+    return "[#{ip}]:6789"
+  end
+end
+
+def mon_addresses
+  mon_ips = []
+
+  if File.exist?("/var/run/ceph/ceph-mon.#{node['hostname']}.asok")
+    mon_ips = quorum_members_ips
+  else
+    mons = []
+    # make sure if this node runs ceph-mon, it's always included even if
+    # search is laggy; put it first in the hopes that clients will talk
+    # primarily to local node
+    mons << node if node['ceph']['is_mon']
+
+    mons += mon_nodes
+    if crowbar?
+      mon_ips = mons.map { |node| Chef::Recipe::Barclamp::Inventory.get_network_by_type(node, 'admin').address }
+    else
+      if node['ceph']['config']['global'] && node['ceph']['config']['global']['public network']
+        mon_ips = mons.map { |nodeish| find_node_ip_in_network(node['ceph']['config']['global']['public network'], nodeish) }
+      else
+        mon_ips = mons.map { |node| node['ipaddress'] + ':6789' }
+      end
+    end
+  end
+  mon_ips.reject { |m| m.nil? }.uniq
+end
+
+def mon_secret
+  if node['ceph']['encrypted_data_bags']
+    secret = Chef::EncryptedDataBagItem.load_secret(node['ceph']['mon']['secret_file'])
+    Chef::EncryptedDataBagItem.load('ceph', 'mon', secret)['secret']
+  elsif !mon_nodes.empty?
+    mon_nodes[0]['ceph']['monitor-secret']
+  elsif node['ceph']['monitor-secret']
+    node['ceph']['monitor-secret']
+  else
+    Chef::Log.info('No monitor secret found')
+    nil
+  end
+end
+
+def quorum_members_ips
+  mon_ips = []
+  cmd = Mixlib::ShellOut.new("ceph --admin-daemon /var/run/ceph/ceph-mon.#{node['hostname']}.asok mon_status")
+  cmd.run_command
+  cmd.error!
+
+  mons = JSON.parse(cmd.stdout)['monmap']['mons']
+  mons.each do |k|
+    mon_ips.push(k['addr'][0..-3])
+  end
+  mon_ips
+end
+
+QUORUM_STATES = %w(leader, peon)
+def quorum?
+  # "ceph auth get-or-create-key" would hang if the monitor wasn't
+  # in quorum yet, which is highly likely on the first run. This
+  # helper lets us delay the key generation into the next
+  # chef-client run, instead of hanging.
+  #
+  # Also, as the UNIX domain socket connection has no timeout logic
+  # in the ceph tool, this exits immediately if the ceph-mon is not
+  # running for any reason; trying to connect via TCP/IP would wait
+  # for a relatively long timeout.
+
+  cmd = Mixlib::ShellOut.new("ceph --admin-daemon /var/run/ceph/ceph-mon.#{node['hostname']}.asok mon_status")
+  cmd.run_command
+  cmd.error!
+
+  state = JSON.parse(cmd.stdout)['state']
+  QUORUM_STATES.include?(state)
+end
+
+# Cephx is on by default, but users can disable it.
+# type can be one of 3 values: cluster, service, or client.  If the value is none of the above, set it to cluster
+def use_cephx?(type = nil)
+  # Verify type is valid
+  type = 'cluster' if %w(cluster service client).index(type).nil?
+
+  # CephX is enabled if it's not configured at all, or explicity enabled
+  node['ceph']['config'].nil? ||
+    node['ceph']['config']['global'].nil? ||
+    node['ceph']['config']['global']["auth #{type} required"] == 'cephx'
+end
diff --git a/libraries/utils.rb b/libraries/utils.rb
new file mode 100644 (file)
index 0000000..257472f
--- /dev/null
@@ -0,0 +1,14 @@
+def debug_packages(packages)
+  packages.map { |x| x + debug_ext }
+end
+
+def debug_ext
+  case node['platform_family']
+  when 'debian'
+    '-dbg'
+  when 'rhel', 'fedora'
+    '-debug'
+  else
+    ''
+  end
+end
diff --git a/metadata.rb b/metadata.rb
new file mode 100644 (file)
index 0000000..01e49dc
--- /dev/null
@@ -0,0 +1,12 @@
+name 'ceph'
+maintainer 'Kyle Bader'
+maintainer_email 'kyle.bader@dreamhost.com'
+license 'Apache 2.0'
+description 'Installs/Configures the Ceph distributed filesystem'
+long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
+version '0.2.1'
+
+depends        'apache2', '>= 1.1.12'
+depends 'apt'
+depends 'yum', '>= 3.0'
+depends 'yum-epel'
diff --git a/providers/cephfs.rb b/providers/cephfs.rb
new file mode 100644 (file)
index 0000000..7396183
--- /dev/null
@@ -0,0 +1,85 @@
+def create_client
+  # Client settings
+  client_name = "cephfs.#{node['hostname']}"
+  filename = "/etc/ceph/ceph.client.#{client_name}.secret"
+
+  name = 'cephfs'
+  ceph_client name do
+    filename filename
+    caps('mon' => 'allow r', 'osd' => 'allow rw', 'mds' => 'allow')
+    as_keyring false
+  end
+end
+
+def manage_mount(directory, subdir, use_fuse, action)
+  # Client settings
+  client_name = "cephfs.#{node['hostname']}"
+  filename = "/etc/ceph/ceph.client.#{client_name}.secret"
+
+  if use_fuse
+    if subdir != '/'
+      Chef::Application.fatal!("Can't use a subdir with fuse mounts yet")
+    end
+    mount "#{action} #{directory}" do
+      mount_point directory
+      fstype 'fuse.ceph'
+      # needs two slashes to indicate a network mount to chef
+      device "conf=//etc/ceph/ceph.conf,id=#{client_name},keyfile=#{filename}"
+      options 'defaults'
+      dump 0
+      pass 0
+      action action
+    end
+  else
+    mons = mon_addresses.join(',') + ':' + subdir
+    mount "#{action} #{directory}" do
+      mount_point directory
+      fstype 'ceph'
+      device mons
+      options "_netdev,name=#{client_name},secretfile=#{filename}"
+      dump 0
+      pass 0
+      action action
+    end
+  end
+end
+
+def whyrun_supported?
+  true
+end
+
+def create_mount(action)
+  create_client
+  directory @new_resource.directory
+  manage_mount(@new_resource.directory, @new_resource.cephfs_subdir, @new_resource.use_fuse, action)
+end
+
+action :mount do
+  converge_by("Creating cephfs mount at #{@new_resource.directory}") do
+    create_mount(:mount)
+  end
+end
+
+action :remount do
+  converge_by("Remounting cephfs mount at #{@new_resource.directory}") do
+    create_mount(:remount)
+  end
+end
+
+action :umount do
+  converge_by("Unmounting cephfs mount at #{@new_resource.directory}") do
+    manage_mount(@new_resource.directory, @new_resource.cephfs_subdir, @new_resource.use_fuse, :umount)
+  end
+end
+
+action :enable do
+  converge_by("Enabling cephfs mount at #{@new_resource.directory}") do
+    create_mount(:enable)
+  end
+end
+
+action :disable do
+  converge_by("Disabling cephfs mount at #{@new_resource.directory}") do
+    manage_mount(@new_resource.directory, @new_resource.cephfs_subdir, @new_resource.use_fuse, :disable)
+  end
+end
diff --git a/providers/client.rb b/providers/client.rb
new file mode 100644 (file)
index 0000000..d2154d3
--- /dev/null
@@ -0,0 +1,76 @@
+use_inline_resources
+
+def whyrun_supported?
+  true
+end
+
+action :add do
+  current_resource = @current_resource
+  filename = @current_resource.filename
+  keyname = @current_resource.keyname
+  caps = @new_resource.caps.map { |k, v| "#{k} '#{v}'" }.join(' ')
+  owner = @new_resource.owner
+  group = @new_resource.group
+  mode = @new_resource.mode
+  unless @current_resource.caps_match
+    converge_by("Set caps for #{@new_resource}") do
+      auth_set_key(keyname, caps)
+      current_resource.key = get_key(keyname)
+
+    end
+  end
+  # update the key in the file
+  file filename do
+    content file_content
+    owner owner
+    group group
+    mode mode
+  end
+
+end
+
+def load_current_resource
+  @current_resource = Chef::Resource::CephClient.new(@new_resource.name)
+  @current_resource.name(@new_resource.name)
+  @current_resource.as_keyring(@new_resource.as_keyring)
+  @current_resource.keyname(@new_resource.keyname || "client.#{current_resource.name}.#{node['hostname']}")
+  @current_resource.caps(get_caps(@current_resource.keyname))
+  default_filename = "/etc/ceph/ceph.client.#{@new_resource.name}.#{node['hostname']}.#{@new_resource.as_keyring ? 'keyring' : 'secret'}"
+  @current_resource.filename(@new_resource.filename || default_filename)
+  @current_resource.key = get_key(@current_resource.keyname)
+  @current_resource.caps_match = true if @current_resource.caps == @new_resource.caps
+end
+
+def file_content
+  @current_resource.as_keyring ? "[#{@current_resource.keyname}]\n\tkey = #{@current_resource.key}\n" : @current_resource.key
+end
+
+def get_key(keyname)
+  cmd = "ceph auth print_key #{keyname} --name mon. --key='#{mon_secret}'"
+  Mixlib::ShellOut.new(cmd).run_command.stdout
+end
+
+def get_caps(keyname)
+  caps = {}
+  cmd = "ceph auth get #{keyname} --name mon. --key='#{mon_secret}'"
+  output = Mixlib::ShellOut.new(cmd).run_command.stdout
+  output.scan(/caps\s*(\S+)\s*=\s*"([^"]*)"/) { |k, v| caps[k] = v }
+  caps
+end
+
+def auth_set_key(keyname, caps)
+  secret = mon_secret
+  # try to add the key
+  cmd = "ceph auth get-or-create #{keyname} #{caps} --name mon. --key='#{secret}'"
+  get_or_create = Mixlib::ShellOut.new(cmd)
+  get_or_create.run_command
+  if get_or_create.stderr.scan(/EINVAL.*but cap.*does not match/)
+    Chef::Log.info('Deleting old key with incorrect caps')
+    # delete an old key if it exists and is wrong
+    Mixlib::ShellOut.new("ceph auth del #{keyname} --name mon. --key='#{secret}'").run_command
+    # try to create again
+    get_or_create = Mixlib::ShellOut.new(cmd)
+    get_or_create.run_command
+  end
+  get_or_create.error!
+end
diff --git a/recipes/_common.rb b/recipes/_common.rb
new file mode 100644 (file)
index 0000000..f738e65
--- /dev/null
@@ -0,0 +1,8 @@
+include_recipe 'ceph::_common_install'
+
+# Tools needed by cookbook
+node['ceph']['packages'].each do |pck|
+  package pck
+end
+
+chef_gem 'netaddr'
diff --git a/recipes/_common_install.rb b/recipes/_common_install.rb
new file mode 100644 (file)
index 0000000..171a227
--- /dev/null
@@ -0,0 +1 @@
+include_recipe 'ceph::repo' if node['ceph']['install_repo']
diff --git a/recipes/all_in_one.rb b/recipes/all_in_one.rb
new file mode 100644 (file)
index 0000000..794f377
--- /dev/null
@@ -0,0 +1,6 @@
+
+include_recipe 'ceph::mon'
+include_recipe 'ceph::osd'
+include_recipe 'ceph::mds'
+include_recipe 'ceph::cephfs'
+include_recipe 'ceph::radosgw'
diff --git a/recipes/apt.rb b/recipes/apt.rb
new file mode 100644 (file)
index 0000000..d101b00
--- /dev/null
@@ -0,0 +1,27 @@
+
+include_recipe 'apt'
+
+branch = node['ceph']['branch']
+
+distribution_codename =
+case node['lsb']['codename']
+when 'jessie' then 'sid'
+else node['lsb']['codename']
+end
+
+apt_repository 'ceph' do
+  repo_name 'ceph'
+  uri node['ceph']['debian'][branch]['repository']
+  distribution distribution_codename
+  components ['main']
+  key node['ceph']['debian'][branch]['repository_key']
+end
+
+apt_repository 'ceph-extras' do
+  repo_name 'ceph-extras'
+  uri node['ceph']['debian']['extras']['repository']
+  distribution distribution_codename
+  components ['main']
+  key node['ceph']['debian']['extras']['repository_key']
+  only_if { node['ceph']['extras_repo'] }
+end
diff --git a/recipes/cephfs.rb b/recipes/cephfs.rb
new file mode 100644 (file)
index 0000000..28ac60c
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: cephfs
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+requires_fuse =
+  case node['platform']
+  when 'debian'
+    node['platform_version'].to_f < 7.0
+  when 'ubuntu'
+    node['platform_version'].to_f < 12.04
+  when 'redhat'
+    node['platform_version'].to_f < 7.0
+  when 'fedora'
+    node['platform_version'].to_f < 17.0
+  else
+    true
+end
+
+ceph_cephfs node['ceph']['cephfs_mount'] do
+  use_fuse requires_fuse
+  action [:mount, :enable]
+end
diff --git a/recipes/cephfs_install.rb b/recipes/cephfs_install.rb
new file mode 100644 (file)
index 0000000..826997d
--- /dev/null
@@ -0,0 +1,5 @@
+include_recipe 'ceph::_common_install'
+
+node['ceph']['cephfs']['packages'].each do |pck|
+  package pck
+end
diff --git a/recipes/conf.rb b/recipes/conf.rb
new file mode 100644 (file)
index 0000000..43d6a54
--- /dev/null
@@ -0,0 +1,26 @@
+# fail 'mon_initial_members must be set in config' if node['ceph']['config']['mon_initial_members'].nil?
+
+unless node['ceph']['config']['fsid']
+  Chef::Log.warn('We are genereting a new uuid for fsid')
+  require 'securerandom'
+  node.set['ceph']['config']['fsid'] = SecureRandom.uuid
+  node.save
+end
+
+directory '/etc/ceph' do
+  owner 'root'
+  group 'root'
+  mode '0755'
+  action :create
+end
+
+template '/etc/ceph/ceph.conf' do
+  source 'ceph.conf.erb'
+  variables lazy {
+    {
+      :mon_addresses => mon_addresses,
+      :is_rgw => node['ceph']['is_radosgw']
+    }
+  }
+  mode '0644'
+end
diff --git a/recipes/install.rb b/recipes/install.rb
new file mode 100644 (file)
index 0000000..7d1eb57
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: default
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+packages = []
+
+case node['platform_family']
+when 'debian'
+  packages = %w(
+    ceph
+    ceph-common
+  )
+
+  if node['ceph']['install_debug']
+    packages_dbg = %w(
+      ceph-dbg
+      ceph-common-dbg
+    )
+    packages += packages_dbg
+  end
+when 'rhel', 'fedora'
+  packages = %w(
+    ceph
+  )
+
+  if node['ceph']['install_debug']
+    packages_dbg = %w(
+      ceph-debug
+    )
+    packages += packages_dbg
+  end
+end
+
+packages.each do |pkg|
+  package pkg do
+    action :install
+  end
+end
diff --git a/recipes/mds.rb b/recipes/mds.rb
new file mode 100644 (file)
index 0000000..69ca3a5
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: mds
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+include_recipe 'ceph::_common'
+include_recipe 'ceph::mds_install'
+include_recipe 'ceph::conf'
+
+cluster = 'ceph'
+
+directory "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}" do
+  owner 'root'
+  group 'root'
+  mode 00755
+  recursive true
+  action :create
+end
+
+ceph_client 'mds' do
+  caps('osd' => 'allow *', 'mon' => 'allow rwx')
+  keyname "mds.#{node['hostname']}"
+  filename "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}/keyring"
+end
+
+file "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}/done" do
+  owner 'root'
+  group 'root'
+  mode 00644
+end
+
+service_type = node['ceph']['osd']['init_style']
+
+case service_type
+when 'upstart'
+  filename = 'upstart'
+else
+  filename = 'sysvinit'
+end
+file "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}/#{filename}" do
+  owner 'root'
+  group 'root'
+  mode 00644
+end
+
+service 'ceph_mds' do
+  case service_type
+  when 'upstart'
+    service_name 'ceph-mds-all-starter'
+    provider Chef::Provider::Service::Upstart
+  else
+    service_name 'ceph'
+  end
+  action [:enable, :start]
+  supports :restart => true
+end
diff --git a/recipes/mds_install.rb b/recipes/mds_install.rb
new file mode 100644 (file)
index 0000000..3ce533a
--- /dev/null
@@ -0,0 +1,5 @@
+include_recipe 'ceph::_common_install'
+
+node['ceph']['mds']['packages'].each do |pck|
+  package pck
+end
diff --git a/recipes/mon.rb b/recipes/mon.rb
new file mode 100644 (file)
index 0000000..76a5d91
--- /dev/null
@@ -0,0 +1,130 @@
+# This recipe creates a monitor cluster
+#
+# You should never change the mon default path or
+# the keyring path.
+# Don't change the cluster name either
+# Default path for mon data: /var/lib/ceph/mon/$cluster-$id/
+#   which will be /var/lib/ceph/mon/ceph-`hostname`/
+#   This path is used by upstart. If changed, upstart won't
+#   start the monitor
+# The keyring files are created using the following pattern:
+#  /etc/ceph/$cluster.client.$name.keyring
+#  e.g. /etc/ceph/ceph.client.admin.keyring
+#  The bootstrap-osd and bootstrap-mds keyring are a bit
+#  different and are created in
+#  /var/lib/ceph/bootstrap-{osd,mds}/ceph.keyring
+
+node.default['ceph']['is_mon'] = true
+
+include_recipe 'ceph::_common'
+include_recipe 'ceph::mon_install'
+include_recipe 'ceph::conf'
+
+service_type = node['ceph']['mon']['init_style']
+
+directory '/var/run/ceph' do
+  owner 'root'
+  group 'root'
+  mode 00755
+  recursive true
+  action :create
+end
+
+directory "/var/lib/ceph/mon/ceph-#{node['hostname']}" do
+  owner 'root'
+  group 'root'
+  mode 00755
+  recursive true
+  action :create
+end
+
+# TODO: cluster name
+cluster = 'ceph'
+
+unless File.exist?("/var/lib/ceph/mon/ceph-#{node['hostname']}/done")
+  keyring = "#{Chef::Config[:file_cache_path]}/#{cluster}-#{node['hostname']}.mon.keyring"
+
+  execute 'format mon-secret as keyring' do
+    command lazy { "ceph-authtool '#{keyring}' --create-keyring --name=mon. --add-key='#{mon_secret}' --cap mon 'allow *'" }
+    creates "#{Chef::Config[:file_cache_path]}/#{cluster}-#{node['hostname']}.mon.keyring"
+    only_if { mon_secret }
+  end
+
+  execute 'generate mon-secret as keyring' do
+    command "ceph-authtool '#{keyring}' --create-keyring --name=mon. --gen-key --cap mon 'allow *'"
+    creates "#{Chef::Config[:file_cache_path]}/#{cluster}-#{node['hostname']}.mon.keyring"
+    not_if { mon_secret }
+    notifies :create, 'ruby_block[save mon_secret]', :immediately
+  end
+
+  ruby_block 'save mon_secret' do
+    block do
+      fetch = Mixlib::ShellOut.new("ceph-authtool '#{keyring}' --print-key --name=mon.")
+      fetch.run_command
+      key = fetch.stdout
+      node.set['ceph']['monitor-secret'] = key
+      node.save
+    end
+    action :nothing
+  end
+
+  execute 'ceph-mon mkfs' do
+    command "ceph-mon --mkfs -i #{node['hostname']} --keyring '#{keyring}'"
+  end
+
+  ruby_block 'finalise' do
+    block do
+      ['done', service_type].each do |ack|
+        ::File.open("/var/lib/ceph/mon/ceph-#{node['hostname']}/#{ack}", 'w').close
+      end
+    end
+  end
+end
+
+if service_type == 'upstart'
+  service 'ceph-mon' do
+    provider Chef::Provider::Service::Upstart
+    action :enable
+  end
+  service 'ceph-mon-all' do
+    provider Chef::Provider::Service::Upstart
+    supports :status => true
+    action [:enable, :start]
+  end
+end
+
+service 'ceph_mon' do
+  case service_type
+  when 'upstart'
+    service_name 'ceph-mon-all-starter'
+    provider Chef::Provider::Service::Upstart
+  else
+    service_name 'ceph'
+  end
+  supports :restart => true, :status => true
+  action [:enable, :start]
+end
+
+mon_addresses.each do |addr|
+  execute "peer #{addr}" do
+    command "ceph --admin-daemon '/var/run/ceph/ceph-mon.#{node['hostname']}.asok' add_bootstrap_peer_hint #{addr}"
+    ignore_failure true
+  end
+end
+
+# The key is going to be automatically created, We store it when it is created
+# If we're storing keys in encrypted data bags, then they've already been generated above
+if use_cephx? && !node['ceph']['encrypted_data_bags']
+  ruby_block 'get osd-bootstrap keyring' do
+    block do
+      run_out = ''
+      while run_out.empty?
+        run_out = Mixlib::ShellOut.new('ceph auth get-key client.bootstrap-osd').run_command.stdout.strip
+        sleep 2
+      end
+      node.override['ceph']['bootstrap_osd_key'] = run_out
+      node.save
+    end
+    not_if { node['ceph']['bootstrap_osd_key'] }
+  end
+end
diff --git a/recipes/mon_install.rb b/recipes/mon_install.rb
new file mode 100644 (file)
index 0000000..557ad4c
--- /dev/null
@@ -0,0 +1,5 @@
+include_recipe 'ceph::_common_install'
+
+node['ceph']['mon']['packages'].each do |pck|
+  package pck
+end
diff --git a/recipes/osd.rb b/recipes/osd.rb
new file mode 100644 (file)
index 0000000..fc2f9c6
--- /dev/null
@@ -0,0 +1,150 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: osd
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+# this recipe allows bootstrapping new osds, with help from mon
+# Sample environment:
+# #knife node edit ceph1
+# "osd_devices": [
+#   {
+#       "device": "/dev/sdc"
+#   },
+#   {
+#       "device": "/dev/sdd",
+#       "dmcrypt": true,
+#       "journal": "/dev/sdd"
+#   }
+# ]
+
+include_recipe 'ceph::_common'
+include_recipe 'ceph::osd_install'
+include_recipe 'ceph::conf'
+
+package 'gdisk' do
+  action :upgrade
+end
+
+package 'cryptsetup' do
+  action :upgrade
+  only_if { node['dmcrypt'] }
+end
+
+service_type = node['ceph']['osd']['init_style']
+
+directory '/var/lib/ceph/bootstrap-osd' do
+  owner 'root'
+  group 'root'
+  mode '0755'
+end
+
+# TODO: cluster name
+cluster = 'ceph'
+
+execute 'format bootstrap-osd as keyring' do
+  command lazy { "ceph-authtool '/var/lib/ceph/bootstrap-osd/#{cluster}.keyring' --create-keyring --name=client.bootstrap-osd --add-key='#{osd_secret}'" }
+  creates "/var/lib/ceph/bootstrap-osd/#{cluster}.keyring"
+  only_if { osd_secret }
+end
+
+if crowbar?
+  node['crowbar']['disks'].each do |disk, _data|
+    execute "ceph-disk-prepare #{disk}" do
+      command "ceph-disk-prepare /dev/#{disk}"
+      only_if { node['crowbar']['disks'][disk]['usage'] == 'Storage' }
+      notifies :run, 'execute[udev trigger]', :immediately
+    end
+
+    ruby_block "set disk usage for #{disk}" do
+      block do
+        node.set['crowbar']['disks'][disk]['usage'] = 'ceph-osd'
+        node.save
+      end
+    end
+  end
+
+  execute 'udev trigger' do
+    command 'udevadm trigger --subsystem-match=block --action=add'
+    action :nothing
+  end
+else
+  # Calling ceph-disk-prepare is sufficient for deploying an OSD
+  # After ceph-disk-prepare finishes, the new device will be caught
+  # by udev which will run ceph-disk-activate on it (udev will map
+  # the devices if dm-crypt is used).
+  # IMPORTANT:
+  #  - Always use the default path for OSD (i.e. /var/lib/ceph/
+  # osd/$cluster-$id)
+  #  - $cluster should always be ceph
+  #  - The --dmcrypt option will be available starting w/ Cuttlefish
+  if node['ceph']['osd_devices']
+    devices = node['ceph']['osd_devices']
+
+    devices = Hash[(0...devices.size).zip devices] unless devices.kind_of? Hash
+
+    devices.each do |index, osd_device|
+      unless osd_device['status'].nil?
+        Log.info("osd: osd_device #{osd_device} has already been setup.")
+        next
+      end
+
+      directory osd_device['device'] do # ~FC022
+        owner 'root'
+        group 'root'
+        recursive true
+        only_if { osd_device['type'] == 'directory' }
+      end
+
+      dmcrypt = osd_device['encrypted'] == true ? '--dmcrypt' : ''
+
+      execute "ceph-disk-prepare on #{osd_device['device']}" do
+        command "ceph-disk-prepare #{dmcrypt} #{osd_device['device']} #{osd_device['journal']}"
+        action :run
+        notifies :create, "ruby_block[save osd_device status #{index}]", :immediately
+      end
+
+      execute "ceph-disk-activate #{osd_device['device']}" do
+        only_if { osd_device['type'] == 'directory' }
+      end
+
+      # we add this status to the node env
+      # so that we can implement recreate
+      # and/or delete functionalities in the
+      # future.
+      ruby_block "save osd_device status #{index}" do
+        block do
+          node.normal['ceph']['osd_devices'][index]['status'] = 'deployed'
+          node.save
+        end
+        action :nothing
+      end
+    end
+    service 'ceph_osd' do
+      case service_type
+      when 'upstart'
+        service_name 'ceph-osd-all-starter'
+        provider Chef::Provider::Service::Upstart
+      else
+        service_name 'ceph'
+      end
+      action [:enable, :start]
+      supports :restart => true
+    end
+  else
+    Log.info('node["ceph"]["osd_devices"] empty')
+  end
+end
diff --git a/recipes/osd_install.rb b/recipes/osd_install.rb
new file mode 100644 (file)
index 0000000..21991ad
--- /dev/null
@@ -0,0 +1,5 @@
+include_recipe 'ceph::_common_install'
+
+node['ceph']['osd']['packages'].each do |pck|
+  package pck
+end
diff --git a/recipes/radosgw.rb b/recipes/radosgw.rb
new file mode 100644 (file)
index 0000000..f533d18
--- /dev/null
@@ -0,0 +1,60 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: radosgw
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+node.default['ceph']['is_radosgw'] = true
+
+include_recipe 'ceph::_common'
+include_recipe 'ceph::radosgw_install'
+include_recipe 'ceph::conf'
+
+if !::File.exist?("/var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}/done")
+  if node['ceph']['radosgw']['webserver_companion']
+    include_recipe "ceph::radosgw_#{node['ceph']['radosgw']['webserver_companion']}"
+  end
+
+  ceph_client 'radosgw' do
+    caps('mon' => 'allow rw', 'osd' => 'allow rwx')
+  end
+
+  directory "/var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}" do
+    recursive true
+  end
+
+  file "/var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}/done" do
+    action :create
+  end
+
+  service 'radosgw' do
+    case node['ceph']['radosgw']['init_style']
+    when 'upstart'
+      service_name 'radosgw-all-starter'
+      provider Chef::Provider::Service::Upstart
+    else
+      if node['platform'] == 'debian'
+        service_name 'radosgw'
+      else
+        service_name 'ceph-radosgw'
+      end
+    end
+    supports :restart => true
+    action [:enable, :start]
+  end
+else
+  Log.info('Rados Gateway already deployed')
+end
diff --git a/recipes/radosgw_apache2.rb b/recipes/radosgw_apache2.rb
new file mode 100644 (file)
index 0000000..9f23e51
--- /dev/null
@@ -0,0 +1,81 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: radosgw_apache2
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+# For EL, delete the current fastcgi configuration
+# and set the correct owners for dirs and logs
+# d_owner = d_group = 'root'
+# if node['platform_family'] == 'rhel'
+#   file "#{node['apache']['dir']}/conf.d/fastcgi.conf" do
+#     action :delete
+#     backup false
+#   end
+#   d_owner = d_group = 'apache'
+# end
+
+# %W(/var/run/ceph
+#    /var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}
+#    /var/lib/apache2/
+# ).each do |dir|
+#   directory dir do
+#     owner d_owner
+#     group d_group
+#     mode '0755'
+#     recursive true
+#     action :create
+#   end
+# end
+
+include_recipe 'ceph::_common'
+include_recipe 'ceph::_common_install'
+include_recipe 'ceph::radosgw_apache2_repo'
+
+node['ceph']['radosgw']['apache2']['packages'].each do |pck|
+  package pck
+end
+
+include_recipe 'apache2'
+
+apache_module 'fastcgi' do
+  conf true
+end
+
+apache_module 'rewrite' do
+  conf false
+end
+
+web_app 'rgw' do
+  template 'rgw.conf.erb'
+  server_name node['ceph']['radosgw']['api_fqdn']
+  admin_email node['ceph']['radosgw']['admin_email']
+  ceph_rgw_addr node['ceph']['radosgw']['rgw_addr']
+end
+
+service 'apache2' do
+  action :restart
+end
+
+template '/var/www/s3gw.fcgi' do
+  source 's3gw.fcgi.erb'
+  owner 'root'
+  group 'root'
+  mode '0755'
+  variables(
+    :ceph_rgw_client => "client.radosgw.#{node['hostname']}"
+  )
+end
diff --git a/recipes/radosgw_apache2_repo.rb b/recipes/radosgw_apache2_repo.rb
new file mode 100644 (file)
index 0000000..eda49ca
--- /dev/null
@@ -0,0 +1,33 @@
+if node['ceph']['radosgw']['use_apache_fork'] == true
+  if node.platform_family?('debian') &&
+    %w(precise quantal raring squeeze wheezy).include?(node['lsb']['codename'])
+    apt_repository 'ceph-apache2' do
+      repo_name 'ceph-apache2'
+      uri "http://gitbuilder.ceph.com/apache2-deb-#{node['lsb']['codename']}-x86_64-basic/ref/master"
+      distribution node['lsb']['codename']
+      components ['main']
+      key 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
+    end
+    apt_repository 'ceph-modfastcgi' do
+      repo_name 'ceph-modfastcgi'
+      uri "http://gitbuilder.ceph.com/libapache-mod-fastcgi-deb-#{node['lsb']['codename']}-x86_64-basic/ref/master"
+      distribution node['lsb']['codename']
+      components ['main']
+      key 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
+    end
+  elsif (node.platform_family?('fedora') && [18, 19].include?(node['platform_version'].to_i)) ||
+    (node.platform_family?('rhel') && [6].include?(node['platform_version'].to_i))
+    platform_family = node['platform_family']
+    platform_version = node['platform_version'].to_i
+    yum_repository 'ceph-apache2' do
+      baseurl "http://gitbuilder.ceph.com/apache2-rpm-#{node['platform']}#{platform_version}-x86_64-basic/ref/master"
+      gpgkey node['ceph'][platform_family]['dev']['repository_key']
+    end
+    yum_repository 'ceph-modfastcgi' do
+      baseurl "http://gitbuilder.ceph.com/mod_fastcgi-rpm-#{node['platform']}#{platform_version}-x86_64-basic/ref/master"
+      gpgkey node['ceph'][platform_family]['dev']['repository_key']
+    end
+  else
+    Log.info("Ceph's Apache and Apache FastCGI forks not available for this distribution")
+  end
+end
diff --git a/recipes/radosgw_install.rb b/recipes/radosgw_install.rb
new file mode 100644 (file)
index 0000000..7944d49
--- /dev/null
@@ -0,0 +1,5 @@
+include_recipe 'ceph::_common_install'
+
+node['ceph']['radosgw']['packages'].each do |pck|
+  package pck
+end
diff --git a/recipes/repo.rb b/recipes/repo.rb
new file mode 100644 (file)
index 0000000..6ef37de
--- /dev/null
@@ -0,0 +1,8 @@
+case node['platform_family']
+when 'debian'
+  include_recipe 'ceph::apt'
+when 'rhel', 'suse', 'fedora'
+  include_recipe 'ceph::rpm'
+else
+  fail 'not supported'
+end
diff --git a/recipes/rpm.rb b/recipes/rpm.rb
new file mode 100644 (file)
index 0000000..a2708ef
--- /dev/null
@@ -0,0 +1,32 @@
+platform_family = node['platform_family']
+
+case platform_family
+when 'rhel'
+  include_recipe 'yum-epel' if node['ceph']['el_add_epel']
+end
+
+branch = node['ceph']['branch']
+if branch == 'dev' && platform_family != 'centos' && platform_family != 'fedora'
+  fail "Dev branch for #{platform_family} is not yet supported"
+end
+
+yum_repository 'ceph' do
+  baseurl node['ceph'][platform_family][branch]['repository']
+  gpgkey node['ceph'][platform_family][branch]['repository_key']
+end
+
+yum_repository 'ceph-extra' do
+  baseurl node['ceph'][platform_family]['extras']['repository']
+  gpgkey node['ceph'][platform_family]['extras']['repository_key']
+  only_if { node['ceph']['extras_repo'] }
+end
+
+package 'parted'    # needed by ceph-disk-prepare to run partprobe
+package 'hdparm'    # used by ceph-disk activate
+package 'xfsprogs'  # needed by ceph-disk-prepare to format as xfs
+if node['platform_family'] == 'rhel' && node['platform_version'].to_f > 6
+  package 'btrfs-progs' # needed to format as btrfs, in the future
+end
+if node['platform_family'] == 'rhel' && node['platform_version'].to_f < 7
+  package 'python-argparse'
+end
diff --git a/recipes/tgt.rb b/recipes/tgt.rb
new file mode 100644 (file)
index 0000000..eb353e9
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph
+# Recipe:: radosgw
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+node.default['ceph']['extras_repo'] = true
+
+case node['platform_family']
+when 'debian'
+  packages = %w(
+    tgt
+  )
+when 'rhel', 'fedora'
+  packages = %w(
+    scsi-target-utils
+  )
+end
+
+packages.each do |pkg|
+  package pkg do
+    action :upgrade
+  end
+end
+
+include_recipe 'ceph::conf'
+# probably needs the key
+service 'tgt' do
+  if node['platform'] == 'ubuntu'
+    # The ceph version of tgt does not provide an Upstart script
+    provider Chef::Provider::Service::Init::Debian
+    service_name 'tgt'
+  else
+    service_name 'tgt'
+  end
+  supports :restart => true
+  action [:enable, :start]
+end
diff --git a/resources/cephfs.rb b/resources/cephfs.rb
new file mode 100644 (file)
index 0000000..191d942
--- /dev/null
@@ -0,0 +1,14 @@
+actions :mount, :umount, :remount, :enable, :disable
+default_action :mount
+
+attribute :directory, :kind_of => String, :name_attribute => true, :required => true
+attribute :use_fuse, :kind_of => [TrueClass, FalseClass], :required => true, :default => true
+attribute :cephfs_subdir, :kind_of => String, :default => '/'
+
+def initialize(*args)
+  super
+  @action = :mount
+  @run_context.include_recipe 'ceph::_common'
+  @run_context.include_recipe 'ceph::cephfs_install'
+  @run_context.include_recipe 'ceph::conf'
+end
diff --git a/resources/client.rb b/resources/client.rb
new file mode 100644 (file)
index 0000000..2428b34
--- /dev/null
@@ -0,0 +1,24 @@
+actions :add
+default_action :add
+
+attribute :name, :kind_of => String, :name_attribute => true
+attribute :caps, :kind_of => Hash, :default => { 'mon' => 'allow r', 'osd' => 'allow r' }
+
+# Whether to store the secret in a keyring file or a plain secret file
+attribute :as_keyring, :kind_of => [TrueClass, FalseClass], :default => true
+
+# what the key should be called in the ceph cluster
+# defaults to client.#{name}.#{hostname}
+attribute :keyname, :kind_of => String
+
+# where the key should be saved
+# defaults to /etc/ceph/ceph.client.#{name}.#{hostname}.keyring if as_keyring
+# defaults to /etc/ceph/ceph.client.#{name}.#{hostname}.secret if not as_keyring
+attribute :filename, :kind_of => String
+
+# key file access creds
+attribute :owner, :kind_of => String, :default => 'root'
+attribute :group, :kind_of => String, :default => 'root'
+attribute :mode, :kind_of => [Integer, String], :default => '00640'
+
+attr_accessor :key, :caps_match
diff --git a/roles/ceph-mds.json b/roles/ceph-mds.json
new file mode 100644 (file)
index 0000000..5383145
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "name": "ceph-mds",
+  "description": "Ceph Metadata Server",
+  "run_list": [
+    "recipe[ceph::repo]",
+    "recipe[ceph::mds]"
+  ]
+}
diff --git a/roles/ceph-mon.json b/roles/ceph-mon.json
new file mode 100644 (file)
index 0000000..10162ff
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "name": "ceph-mon",
+  "description": "Ceph Monitor",
+  "run_list": [
+    "recipe[ceph::repo]",
+    "recipe[ceph::mon]"
+  ]
+}
diff --git a/roles/ceph-osd.json b/roles/ceph-osd.json
new file mode 100644 (file)
index 0000000..e749490
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "name": "ceph-osd",
+  "description": "Ceph Object Storage Device",
+  "run_list": [
+    "recipe[ceph::repo]",
+    "recipe[ceph::osd]"
+  ]
+}
diff --git a/roles/ceph-radosgw.json b/roles/ceph-radosgw.json
new file mode 100644 (file)
index 0000000..925d017
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "name": "ceph-radosgw",
+  "description": "Ceph RADOS Gateway",
+  "run_list": [
+    "recipe[ceph::repo]",
+    "recipe[ceph::radosgw]"
+  ]
+}
diff --git a/roles/ceph-tgt.json b/roles/ceph-tgt.json
new file mode 100644 (file)
index 0000000..f5dce87
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "name": "ceph-tgt",
+  "description": "Ceph iSCSI Target",
+  "run_list": [
+    "recipe[ceph::repo]",
+    "recipe[ceph::tgt]"
+  ]
+}
diff --git a/templates/default/ceph.conf.erb b/templates/default/ceph.conf.erb
new file mode 100644 (file)
index 0000000..1a1015c
--- /dev/null
@@ -0,0 +1,54 @@
+[global]
+<% unless node['ceph']['config']['fsid'].nil? -%>
+  fsid = <%= node['ceph']['config']['fsid'] %>
+<% end -%>
+<% if node['ceph']['is_mon'] -%>
+  mon initial members = <%= node['ceph']['config']['mon_initial_members'] %>
+<% end -%>
+  mon host = <%= @mon_addresses.sort.join(', ') %>
+<% if (! node['ceph']['config']['global'].nil?) -%>
+  <% node['ceph']['config']['global'].sort.each do |k, v| %>
+  <%= k %> = <%= v %>
+  <% end %>
+<% end -%>
+
+<% if (! node['ceph']['config']['osd'].nil?) -%>
+[osd]
+  <% node['ceph']['config']['osd'].sort.each do |k, v| %>
+  <%= k %> = <%= v %>
+  <% end %>
+<% end -%>
+
+<% if (! node['ceph']['config']['mon'].nil?) -%>
+[mon]
+  <% node['ceph']['config']['mon'].sort.each do |k, v| %>
+  <%= k %> = <%= v %>
+  <% end %>
+<% end -%>
+
+<% if (! node['ceph']['config']['mds'].nil?) -%>
+[mds]
+  <% node['ceph']['config']['mds'].sort.each do |key, value| -%>
+  <%= key %> = <%= value %>
+  <%   end -%>
+<% end -%>
+
+<% if (@is_rgw) -%>
+[client.radosgw.<%= node['hostname'] %>]
+  host = <%= node['hostname'] %>
+  rgw socket path = /var/run/ceph/radosgw.<%= node['hostname'] %>
+  keyring = /etc/ceph/ceph.client.radosgw.<%= node['hostname'] %>.keyring
+  log file = /var/log/ceph/radosgw.log
+<% if (! node['ceph']['config']['rgw'].nil?) -%>
+  <% node['ceph']['config']['rgw'].sort.each do |k, v| %>
+  <%= k %> = <%= v %>
+  <% end %>
+<% end -%>
+<% end -%>
+
+<% node['ceph']['config-sections'].sort.each do |name, sect| %>
+[<%= name %>]
+  <% sect.sort.each do |k, v| %>
+  <%= k %> = <%= v %>
+  <% end %>
+<% end %>
diff --git a/templates/default/mods/fastcgi.conf.erb b/templates/default/mods/fastcgi.conf.erb
new file mode 100644 (file)
index 0000000..a252609
--- /dev/null
@@ -0,0 +1,5 @@
+<IfModule mod_fastcgi.c>
+  AddHandler fastcgi-script .fcgi
+  #FastCgiWrapper /usr/lib/apache2/suexec
+  FastCgiIpcDir /var/lib/apache2/fastcgi
+</IfModule>
diff --git a/templates/default/rgw.conf.erb b/templates/default/rgw.conf.erb
new file mode 100644 (file)
index 0000000..322fb01
--- /dev/null
@@ -0,0 +1,39 @@
+<% if node['ceph']['radosgw']['rgw_port'] -%>
+FastCgiExternalServer /var/www/s3gw.fcgi -host 127.0.0.1:<%= node['ceph']['radosgw']['rgw_port'] %>
+<% else -%>
+FastCgiExternalServer /var/www/s3gw.fcgi -socket /var/run/ceph/radosgw.<%= node['hostname'] %>
+<% end -%>
+
+LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\"" proxy_combined
+LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\"" proxy_debug
+
+<VirtualHost <%= node['ceph']['radosgw']['rgw_addr'] %>>
+  ServerName <%= @params[:server_name] %>
+<% if node['ceph']['radosgw']['api_aliases'] -%>
+<%   node['ceph']['radosgw']['api_aliases'].each do |api_alias| -%>
+  ServerAlias <%= api_alias %>
+<%   end -%>
+<% end -%>
+  ServerAdmin <%= node["ceph"]["radosgw"]["admin_email"] %>
+  DocumentRoot /var/www/
+
+  RewriteEngine On
+  RewriteRule ^/([a-zA-Z0-9-_.]*)([/]?.*) /s3gw.fcgi?page=$1&params=$2&%{QUERY_STRING} [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
+
+  <IfModule mod_fastcgi.c>
+    <Directory /var/www/>
+      Options +ExecCGI
+      AllowOverride All
+      SetHandler fastcgi-script
+      Order allow,deny
+      Allow from all
+      AuthBasicAuthoritative Off
+    </Directory>
+  </IfModule>
+
+  AllowEncodedSlashes On
+
+  ErrorLog /var/log/<%= node['apache']['package'] %>/error.log
+  CustomLog /var/log/<%= node['apache']['package'] %>/rgw-access.log proxy_combined
+  ServerSignature Off
+</VirtualHost>
diff --git a/templates/default/s3gw.fcgi.erb b/templates/default/s3gw.fcgi.erb
new file mode 100644 (file)
index 0000000..c6b684f
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec /usr/bin/radosgw -c /etc/ceph/ceph.conf -n <%= @ceph_rgw_client %>
diff --git a/test/cookbooks/ceph_test/CHANGELOG.md b/test/cookbooks/ceph_test/CHANGELOG.md
new file mode 100644 (file)
index 0000000..d6e3f13
--- /dev/null
@@ -0,0 +1,13 @@
+ceph_test CHANGELOG
+===================
+
+This file is used to list changes made in each version of the ceph_test cookbook.
+
+0.1.0
+-----
+- [your_name] - Initial release of ceph_test
+
+- - -
+Check the [Markdown Syntax Guide](http://daringfireball.net/projects/markdown/syntax) for help with Markdown.
+
+The [Github Flavored Markdown page](http://github.github.com/github-flavored-markdown/) describes the differences between markdown on github and standard markdown.
diff --git a/test/cookbooks/ceph_test/README.md b/test/cookbooks/ceph_test/README.md
new file mode 100644 (file)
index 0000000..7b9b0ba
--- /dev/null
@@ -0,0 +1,68 @@
+ceph_test Cookbook
+==================
+TODO: Enter the cookbook description here.
+
+e.g.
+This cookbook makes your favorite breakfast sandwich.
+
+Requirements
+------------
+TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
+
+e.g.
+#### packages
+- `toaster` - ceph_test needs toaster to brown your bagel.
+
+Attributes
+----------
+TODO: List your cookbook attributes here.
+
+e.g.
+#### ceph_test::default
+<table>
+  <tr>
+    <th>Key</th>
+    <th>Type</th>
+    <th>Description</th>
+    <th>Default</th>
+  </tr>
+  <tr>
+    <td><tt>['ceph_test']['bacon']</tt></td>
+    <td>Boolean</td>
+    <td>whether to include bacon</td>
+    <td><tt>true</tt></td>
+  </tr>
+</table>
+
+Usage
+-----
+#### ceph_test::default
+TODO: Write usage instructions for each cookbook.
+
+e.g.
+Just include `ceph_test` in your node's `run_list`:
+
+```json
+{
+  "name":"my_node",
+  "run_list": [
+    "recipe[ceph_test]"
+  ]
+}
+```
+
+Contributing
+------------
+TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.
+
+e.g.
+1. Fork the repository on Github
+2. Create a named feature branch (like `add_component_x`)
+3. Write your change
+4. Write tests for your change (if applicable)
+5. Run the tests, ensuring they all pass
+6. Submit a Pull Request using Github
+
+License and Authors
+-------------------
+Authors: TODO: List authors
diff --git a/test/cookbooks/ceph_test/attributes/cephfs_mount.rb b/test/cookbooks/ceph_test/attributes/cephfs_mount.rb
new file mode 100644 (file)
index 0000000..fc2c912
--- /dev/null
@@ -0,0 +1 @@
+default['ceph']['cephfs_mount'] = '/recipe_ceph'
diff --git a/test/cookbooks/ceph_test/metadata.rb b/test/cookbooks/ceph_test/metadata.rb
new file mode 100644 (file)
index 0000000..17f6f69
--- /dev/null
@@ -0,0 +1,8 @@
+name 'ceph_test'
+maintainer 'Kyle Bader'
+maintainer_email 'kyle.bader@dreamhost.com'
+license 'Apache 2.0'
+description 'Installs/Configures ceph_test'
+long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
+version '0.1.0'
+depends 'ceph'
diff --git a/test/cookbooks/ceph_test/recipes/cephfs.rb b/test/cookbooks/ceph_test/recipes/cephfs.rb
new file mode 100644 (file)
index 0000000..3ad328b
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Author:: Kyle Bader <kyle.bader@dreamhost.com>
+# Cookbook Name:: ceph_test
+# Recipe:: cephfs
+#
+# Copyright 2011, DreamHost Web Hosting
+#
+# 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.
+
+requires_fuse =
+  case node['platform']
+  when 'debian'
+    node['platform_version'].to_f < 7.0
+  when 'ubuntu'
+    node['platform_version'].to_f < 12.04
+  when 'redhat'
+    node['platform_version'].to_f < 7.0
+  when 'fedora'
+    node['platform_version'].to_f < 17.0
+  else
+    true
+end
+
+ceph_cephfs '/ceph' do
+  use_fuse requires_fuse
+  action [:mount, :enable]
+end
+ceph_cephfs '/ceph.fuse' do
+  use_fuse true
+  action [:mount]
+end
+directory '/ceph/subdir'
+file '/ceph/subdir/file' do
+  content "It works\n"
+end
+
+unless requires_fuse
+  ceph_cephfs '/subceph' do
+    use_fuse false
+    cephfs_subdir '/subdir'
+    action [:mount]
+  end
+end
diff --git a/test/integration/Vagrantfile.erb b/test/integration/Vagrantfile.erb
new file mode 100644 (file)
index 0000000..8266d08
--- /dev/null
@@ -0,0 +1,10 @@
+Vagrant.configure("2") do |config|
+  config.vm.box = "<%= config[:box] %>"
+  config.vm.box_url = "<%= config[:box_url ]%>"
+  (0..2).each do |d|
+    config.vm.provider :virtualbox do |vb|
+      vb.customize [ "createhd", "--filename", "disk-#{d}", "--size", "1000" ]
+      vb.customize [ "storageattach", :id, "--storagectl", "IDE Controller", "--device", (1+d)/2, "--port", (1+d)%2, "--type", "hdd", "--medium", "disk-#{d}.vdi" ]
+    end
+  end
+end
diff --git a/test/integration/aio/bats/ceph-running.bats b/test/integration/aio/bats/ceph-running.bats
new file mode 100644 (file)
index 0000000..578d7e4
--- /dev/null
@@ -0,0 +1,19 @@
+@test "ceph is running" {
+  ceph -s | grep HEALTH
+}
+
+@test "ceph is healthy" {
+  ceph -s | grep HEALTH_OK
+}
+
+@test "cephfs is mounted" {
+  mount | grep 'type ceph'
+}
+
+@test "radosgw is running" {
+  ps auxwww | grep radosg[w]
+}
+
+@test "apache is running and listening" {
+  netstat -ln | grep -E '^\S+\s+\S+\s+\S+\s+\S+:80\s+'
+}
diff --git a/test/integration/aio/bats/cephfs.bats b/test/integration/aio/bats/cephfs.bats
new file mode 100644 (file)
index 0000000..8dd3cbe
--- /dev/null
@@ -0,0 +1,41 @@
+@test "/recipe_ceph is mounted" {
+  grep -q -E '^\S+\s+/recipe_ceph\s+' /proc/mounts
+}
+
+@test "/ceph is mounted" {
+  grep -q -E '^\S+\s+/ceph\s+' /proc/mounts
+}
+@test "/ceph.fuse is mounted" {
+  grep -q -E '^\S+\s+/ceph\.fuse\s+fuse' /proc/mounts
+}
+
+@test "/ceph is in fstab" {
+  grep -q -E '^\S+\s+/ceph\s+' /etc/fstab
+}
+@test "/ceph.fuse is NOT in fstab" {
+  grep -v -q -E '^\S+\s+/ceph.fuse\s+' /etc/fstab
+}
+
+@test "test file exists in /ceph" {
+  test -e /ceph/subdir/file
+  grep -q 'It works' /ceph/subdir/file
+}
+@test "test file exists in /ceph.fuse" {
+  test -e /ceph.fuse/subdir/file
+  grep -q 'It works' /ceph.fuse/subdir/file
+}
+
+# if we are using kernel cephfs
+if grep -q -E '^\S+\s+/ceph\s+ceph' /proc/mounts; then
+  @test "/subceph is mounted" {
+    grep -q -E '^\S+\s+/subceph\s+ceph' /proc/mounts
+  }
+  @test "/subceph is NOT in fstab" {
+    grep -v -q -E '^\S+\s+/subceph\s+' /etc/fstab
+  }
+  @test "test file exists in /subceph" {
+    test -e /subceph/file
+    grep -q 'It works' /subceph/file
+  }
+fi
+