├── recipes
├── radosgw_civetweb.rb
├── mds_install.rb
├── mon_install.rb
├── osd_install.rb
├── radosgw_install.rb
├── all_in_one.rb
├── repo.rb
├── default.rb
├── cephfs_install.rb
├── pools.rb
├── conf.rb
├── apt.rb
├── cephfs.rb
├── rpm.rb
├── install.rb
├── tgt.rb
├── radosgw_apache2_repo.rb
├── mds.rb
├── radosgw.rb
├── radosgw_apache2.rb
├── mon.rb
└── osd.rb
├── test
├── cookbooks
│ └── ceph_test
│ │ ├── attributes
│ │ └── cephfs_mount.rb
│ │ ├── metadata.rb
│ │ ├── CHANGELOG.md
│ │ ├── recipes
│ │ └── cephfs.rb
│ │ └── README.md
└── integration
│ ├── aio
│ └── bats
│ │ ├── version.bats
│ │ ├── ceph-running.bats
│ │ └── cephfs.bats
│ └── Vagrantfile.erb
├── infrastructure.yml
├── templates
└── default
│ ├── s3gw.fcgi.erb
│ ├── mods
│ └── fastcgi.conf.erb
│ ├── rgw.conf.erb
│ └── ceph.conf.erb
├── attributes
├── conf.rb
├── radosgw_apache2.rb
├── mds.rb
├── mon.rb
├── osd.rb
├── cephfs.rb
├── default.rb
├── radosgw.rb
└── repo.rb
├── Berksfile
├── .travis.yml
├── roles
├── ceph-mds.json
├── ceph-tgt.json
├── ceph-osd.json
├── ceph-radosgw.json
└── ceph-mon.json
├── CHANGELOG.md
├── Gemfile
├── resources
├── cephfs.rb
├── pool.rb
└── client.rb
├── metadata.rb
├── .gitignore
├── .rubocop.yml
├── libraries
├── utils.rb
└── default.rb
├── Rakefile
├── chefignore
├── .kitchen.yml
├── providers
├── pool.rb
├── cephfs.rb
└── client.rb
├── LICENSE
└── README.md
/recipes/radosgw_civetweb.rb:
--------------------------------------------------------------------------------
1 | # Civetweb has no dependencies. It is included since the Firefly release.
2 |
--------------------------------------------------------------------------------
/test/cookbooks/ceph_test/attributes/cephfs_mount.rb:
--------------------------------------------------------------------------------
1 | default['ceph']['cephfs_mount'] = '/recipe_ceph'
2 |
--------------------------------------------------------------------------------
/infrastructure.yml:
--------------------------------------------------------------------------------
1 | roles:
2 | - ceph-mds:
3 | - ceph-mon:
4 | - ceph-osd:
5 | - ceph-radosgw:
6 | - ceph-tgt:
7 |
--------------------------------------------------------------------------------
/templates/default/s3gw.fcgi.erb:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | exec /usr/bin/radosgw -c /etc/ceph/ceph.conf -n <%= @ceph_rgw_client %>
3 |
--------------------------------------------------------------------------------
/recipes/mds_install.rb:
--------------------------------------------------------------------------------
1 | include_recipe 'ceph'
2 |
3 | node['ceph']['mds']['packages'].each do |pck|
4 | package pck
5 | end
6 |
--------------------------------------------------------------------------------
/recipes/mon_install.rb:
--------------------------------------------------------------------------------
1 | include_recipe 'ceph'
2 |
3 | node['ceph']['mon']['packages'].each do |pck|
4 | package pck
5 | end
6 |
--------------------------------------------------------------------------------
/recipes/osd_install.rb:
--------------------------------------------------------------------------------
1 | include_recipe 'ceph'
2 |
3 | node['ceph']['osd']['packages'].each do |pck|
4 | package pck
5 | end
6 |
--------------------------------------------------------------------------------
/recipes/radosgw_install.rb:
--------------------------------------------------------------------------------
1 | include_recipe 'ceph'
2 |
3 | node['ceph']['radosgw']['packages'].each do |pck|
4 | package pck
5 | end
6 |
--------------------------------------------------------------------------------
/attributes/conf.rb:
--------------------------------------------------------------------------------
1 | default['ceph']['config'] = {}
2 | default['ceph']['config-sections'] = {}
3 | default['ceph']['search_environment'] = true
4 |
--------------------------------------------------------------------------------
/recipes/all_in_one.rb:
--------------------------------------------------------------------------------
1 |
2 | include_recipe 'ceph::mon'
3 | include_recipe 'ceph::osd'
4 | include_recipe 'ceph::mds'
5 | include_recipe 'ceph::cephfs'
6 | include_recipe 'ceph::radosgw'
7 |
--------------------------------------------------------------------------------
/Berksfile:
--------------------------------------------------------------------------------
1 | source 'https://supermarket.chef.io'
2 |
3 | metadata
4 |
5 | group :integration do
6 | cookbook 'apt'
7 | cookbook 'ceph_test', path: 'test/cookbooks/ceph_test'
8 | end
9 |
--------------------------------------------------------------------------------
/recipes/repo.rb:
--------------------------------------------------------------------------------
1 | case node['platform_family']
2 | when 'debian'
3 | include_recipe 'ceph::apt'
4 | when 'rhel', 'suse', 'fedora'
5 | include_recipe 'ceph::rpm'
6 | else
7 | fail 'not supported'
8 | end
9 |
--------------------------------------------------------------------------------
/templates/default/mods/fastcgi.conf.erb:
--------------------------------------------------------------------------------
1 |
2 | AddHandler fastcgi-script .fcgi
3 | #FastCgiWrapper /usr/lib/apache2/suexec
4 | FastCgiIpcDir /var/lib/apache2/fastcgi
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | sudo: false
3 | cache: bundler
4 | bundler_args: --without kitchen_common kitchen_vagrant
5 | rvm:
6 | - 2.0
7 | - 2.1
8 | - 2.2
9 | script:
10 | - bundle exec rake travis
11 |
--------------------------------------------------------------------------------
/roles/ceph-mds.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ceph-mds",
3 | "json_class": "Chef::Role",
4 | "description": "Ceph Metadata Server",
5 | "run_list": [
6 | "recipe[ceph::repo]",
7 | "recipe[ceph::mds]"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/roles/ceph-tgt.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ceph-tgt",
3 | "json_class": "Chef::Role",
4 | "description": "Ceph iSCSI Target",
5 | "run_list": [
6 | "recipe[ceph::repo]",
7 | "recipe[ceph::tgt]"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/roles/ceph-osd.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ceph-osd",
3 | "json_class": "Chef::Role",
4 | "description": "Ceph Object Storage Device",
5 | "run_list": [
6 | "recipe[ceph::repo]",
7 | "recipe[ceph::osd]"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/roles/ceph-radosgw.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ceph-radosgw",
3 | "json_class": "Chef::Role",
4 | "description": "Ceph RADOS Gateway",
5 | "run_list": [
6 | "recipe[ceph::repo]",
7 | "recipe[ceph::radosgw]"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/recipes/default.rb:
--------------------------------------------------------------------------------
1 | include_recipe 'ceph::repo' if node['ceph']['install_repo']
2 | include_recipe 'ceph::conf'
3 |
4 | # Tools needed by cookbook
5 | node['ceph']['packages'].each do |pck|
6 | package pck
7 | end
8 |
9 | chef_gem 'netaddr'
10 |
--------------------------------------------------------------------------------
/roles/ceph-mon.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ceph-mon",
3 | "json_class": "Chef::Role",
4 | "description": "Ceph Monitor",
5 | "run_list": [
6 | "recipe[ceph::repo]",
7 | "recipe[ceph::mon]",
8 | "recipe[ceph::pools]"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ceph
2 | ====
3 |
4 | v0.2.0 (2014-03-03)
5 | -------------------
6 |
7 | - Add tests and fixes related.
8 | - Add ceph-extra
9 | - Fix searching feature
10 | - Refactor RPM part
11 | - Add iscsi tgt
12 |
13 |
14 | v0.1.0 (2013-07-18)
15 | -------------------
16 |
17 | - Initial changelog
18 |
--------------------------------------------------------------------------------
/test/cookbooks/ceph_test/metadata.rb:
--------------------------------------------------------------------------------
1 | name 'ceph_test'
2 | maintainer 'Kyle Bader'
3 | maintainer_email 'kyle.bader@dreamhost.com'
4 | license 'Apache 2.0'
5 | description 'Installs/Configures ceph_test'
6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7 | version '0.1.0'
8 | depends 'ceph'
9 |
--------------------------------------------------------------------------------
/test/integration/aio/bats/version.bats:
--------------------------------------------------------------------------------
1 | @test "ceph is installed from the official repo" {
2 | cephversion=`apt-cache policy ceph | grep -B 1 ceph.com | head -n 1 | sed 's/^[^0-9]\+\([^ ]\+\).*/\1/'`
3 | installedversion=`apt-cache policy ceph | grep 'Installed:' | awk '{print $2}'`
4 | test "$cephversion" = "$installedversion"
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/attributes/radosgw_apache2.rb:
--------------------------------------------------------------------------------
1 | case node['platform_family']
2 | when 'debian'
3 | default['ceph']['radosgw']['apache2']['packages'] = ['libapache2-mod-fastcgi']
4 | when 'suse'
5 | default['ceph']['radosgw']['apache2']['packages'] = ['apache2-mod_fastcgi', 'apache2-worker']
6 | when 'rhel', 'fedora'
7 | default['ceph']['radosgw']['apache2']['packages'] = ['mod_fastcgi']
8 | end
9 |
--------------------------------------------------------------------------------
/attributes/mds.rb:
--------------------------------------------------------------------------------
1 | include_attribute 'ceph'
2 |
3 | default['ceph']['mds']['init_style'] = node['init_style']
4 |
5 | case node['platform_family']
6 | when 'debian'
7 | packages = ['ceph-mds']
8 | packages += debug_packages(packages) if node['ceph']['install_debug']
9 | default['ceph']['mds']['packages'] = packages
10 | else
11 | default['ceph']['mds']['packages'] = []
12 | end
13 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | group :lint do
4 | gem 'foodcritic', '~> 4.0'
5 | gem 'rubocop', '~> 0.33'
6 | end
7 |
8 | group :unit do
9 | gem 'berkshelf', '~> 3.2'
10 | gem 'chefspec', '~> 4.3'
11 | end
12 |
13 | group :kitchen_common do
14 | gem 'test-kitchen', '~> 1.4'
15 | end
16 |
17 | group :kitchen_vagrant do
18 | gem 'kitchen-vagrant', '~> 0.18'
19 | end
20 |
--------------------------------------------------------------------------------
/recipes/cephfs_install.rb:
--------------------------------------------------------------------------------
1 | include_recipe 'ceph'
2 |
3 | node['ceph']['cephfs']['packages'].each do |pck|
4 | package pck
5 | end
6 |
7 | # Update the fuse.ceph helper for pre-firefly
8 | remote_file '/sbin/mount.fuse.ceph' do
9 | source 'https://raw.githubusercontent.com/ceph/ceph/master/src/mount.fuse.ceph'
10 | only_if { ::File.exist?('/sbin/mount.fuse.ceph') }
11 | not_if { ::File.readlines('/sbin/mount.fuse.ceph').grep(/_netdev/).any? }
12 | end
13 |
--------------------------------------------------------------------------------
/test/integration/aio/bats/ceph-running.bats:
--------------------------------------------------------------------------------
1 | @test "ceph is running" {
2 | ceph -s | grep HEALTH
3 | }
4 |
5 | @test "ceph is healthy" {
6 | ceph -s | grep HEALTH_OK
7 | }
8 |
9 | @test "cephfs is mounted" {
10 | mount | grep -E 'type (fuse\.)?ceph'
11 | }
12 |
13 | @test "radosgw is running" {
14 | ps auxwww | grep radosg[w]
15 | }
16 |
17 | @test "apache is running and listening" {
18 | netstat -ln | grep -E '^\S+\s+\S+\s+\S+\s+\S+:80\s+'
19 | }
20 |
--------------------------------------------------------------------------------
/attributes/mon.rb:
--------------------------------------------------------------------------------
1 | include_attribute 'ceph'
2 |
3 | default['ceph']['mon']['init_style'] = node['ceph']['init_style']
4 |
5 | default['ceph']['mon']['secret_file'] = '/etc/chef/secrets/ceph_mon'
6 |
7 | case node['platform_family']
8 | when 'debian', 'rhel', 'fedora'
9 | packages = ['ceph']
10 | packages += debug_packages(packages) if node['ceph']['install_debug']
11 | default['ceph']['mon']['packages'] = packages
12 | else
13 | default['ceph']['mon']['packages'] = []
14 | end
15 |
--------------------------------------------------------------------------------
/attributes/osd.rb:
--------------------------------------------------------------------------------
1 | include_attribute 'ceph'
2 |
3 | default['ceph']['osd']['init_style'] = node['ceph']['init_style']
4 |
5 | default['ceph']['osd']['secret_file'] = '/etc/chef/secrets/ceph_osd'
6 |
7 | case node['platform_family']
8 | when 'debian', 'rhel', 'fedora'
9 | packages = ['ceph']
10 | packages += debug_packages(packages) if node['ceph']['install_debug']
11 | default['ceph']['osd']['packages'] = packages
12 | else
13 | default['ceph']['osd']['packages'] = []
14 | end
15 |
--------------------------------------------------------------------------------
/test/integration/Vagrantfile.erb:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.vm.box = "<%= config[:box] %>"
3 | config.vm.box_url = "<%= config[:box_url ]%>"
4 | (0..2).each do |d|
5 | config.vm.provider :virtualbox do |vb|
6 | vb.customize [ "createhd", "--filename", "disk-#{d}", "--size", "1000" ]
7 | vb.customize [ "storageattach", :id, "--storagectl", "IDE Controller", "--device", (1+d)/2, "--port", (1+d)%2, "--type", "hdd", "--medium", "disk-#{d}.vdi" ]
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/resources/cephfs.rb:
--------------------------------------------------------------------------------
1 | actions :mount, :umount, :remount, :enable, :disable
2 | default_action :mount
3 |
4 | attribute :directory, :kind_of => String, :name_attribute => true, :required => true
5 | attribute :use_fuse, :kind_of => [TrueClass, FalseClass], :required => true, :default => true
6 | attribute :cephfs_subdir, :kind_of => String, :default => '/'
7 |
8 | def initialize(*args)
9 | super
10 | @action = :mount
11 | @run_context.include_recipe 'ceph'
12 | @run_context.include_recipe 'ceph::cephfs_install'
13 | end
14 |
--------------------------------------------------------------------------------
/test/cookbooks/ceph_test/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ceph_test CHANGELOG
2 | ===================
3 |
4 | This file is used to list changes made in each version of the ceph_test cookbook.
5 |
6 | 0.1.0
7 | -----
8 | - [your_name] - Initial release of ceph_test
9 |
10 | - - -
11 | Check the [Markdown Syntax Guide](http://daringfireball.net/projects/markdown/syntax) for help with Markdown.
12 |
13 | The [Github Flavored Markdown page](http://github.github.com/github-flavored-markdown/) describes the differences between markdown on github and standard markdown.
14 |
--------------------------------------------------------------------------------
/metadata.rb:
--------------------------------------------------------------------------------
1 | name 'ceph'
2 | maintainer 'Guilhem Lettron'
3 | maintainer_email 'guilhem@lettron.fr'
4 | license 'Apache 2.0'
5 | description 'Installs/Configures the Ceph distributed filesystem'
6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7 | version '0.9.3'
8 |
9 | depends 'apache2', '>= 1.1.12'
10 | depends 'apt'
11 | depends 'yum', '>= 3.0'
12 | depends 'yum-epel'
13 |
14 | source_url 'https://github.com/ceph/ceph-cookbook' if respond_to?(:source_url)
15 | issues_url 'https://github.com/ceph/ceph-cookbook/issues' if respond_to?(:issues_url)
16 |
--------------------------------------------------------------------------------
/attributes/cephfs.rb:
--------------------------------------------------------------------------------
1 | default['ceph']['cephfs_mount'] = '/ceph'
2 | default['ceph']['cephfs_use_fuse'] = nil # whether the recipe's fuse mount uses cephfs-fuse instead of kernel client, defaults to heuristics
3 |
4 | case node['platform_family']
5 | when 'debian'
6 | packages = ['ceph-fs-common', 'ceph-fuse']
7 | packages += debug_packages(packages) if node['ceph']['install_debug']
8 | default['ceph']['cephfs']['packages'] = packages
9 | when 'rhel', 'fedora', 'suse'
10 | default['ceph']['cephfs']['packages'] = ['ceph-fuse']
11 | else
12 | default['ceph']['cephfs']['packages'] = []
13 | end
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | .zero-knife.rb
3 | *.rbc
4 | .bundle
5 | .config
6 | coverage
7 | InstalledFiles
8 | lib/bundler/man
9 | pkg
10 | rdoc
11 | spec/reports
12 | test/tmp
13 | test/version_tmp
14 | tmp
15 | Gemfile.lock
16 | _Store
17 | *~
18 | *#
19 | .#*
20 | \#*#
21 | .*.sw[a-z]
22 | *.un~
23 | *.tmp
24 | *.bk
25 | *.bkup
26 | .ruby-version
27 | .ruby-gemset
28 | .rvmrc
29 |
30 | # YARD artifacts
31 | .yardoc
32 | _yardoc
33 | doc/
34 | .idea
35 |
36 | #chef stuff
37 | Berksfile.lock
38 | .kitchen
39 | .kitchen.local.yml
40 | vendor/
41 | .coverage/
42 |
43 | #vagrant stuff
44 | .vagrant/
45 | .vagrant.d/
46 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | AllCops:
2 | Include:
3 | - Berksfile
4 | - Gemfile
5 | - Rakefile
6 | - Thorfile
7 | - Guardfile
8 | Exclude:
9 | - vendor/**/*
10 |
11 | ClassLength:
12 | Enabled: false
13 | Documentation:
14 | Enabled: false
15 | Encoding:
16 | Enabled: false
17 | HashSyntax:
18 | Enabled: false
19 | LineLength:
20 | Enabled: false
21 | MethodLength:
22 | Enabled: false
23 | SignalException:
24 | Enabled: false
25 | TrailingComma:
26 | Enabled: false
27 | WordArray:
28 | Enabled: false
29 | Metrics/AbcSize:
30 | Enabled: false
31 | Metrics/PerceivedComplexity:
32 | Enabled: false
33 |
--------------------------------------------------------------------------------
/recipes/pools.rb:
--------------------------------------------------------------------------------
1 | # Author:: mick-m
2 | # Cookbook Name:: ceph
3 | # Recipe:: pools
4 | #
5 | # Copyright 2015, Workday
6 | #
7 | # This recipe creates user-defined Ceph pools defined in the Chef environment.
8 | # Having this code in a separate recipe allows better control of when the pools
9 | # are created.
10 |
11 | if node['ceph']['user_pools']
12 | node['ceph']['user_pools'].each do |pool|
13 | # Create user-defined pools
14 | ceph_pool pool['name'] do
15 | pg_num pool['pg_num']
16 | create_options pool['create_options'] if pool['create_options']
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/resources/pool.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Cookbook Name:: ceph
3 | # Resource:: pool
4 | #
5 | # Author:: Sergio de Carvalho
6 | #
7 |
8 | actions :create, :delete
9 | default_action :create
10 |
11 | attribute :name, :kind_of => String, :name_attribute => true
12 |
13 | # The total number of placement groups for the pool.
14 | attribute :pg_num, :kind_of => Integer, :required => true
15 |
16 | # Optional arguments for pool creation
17 | attribute :create_options, :kind_of => String
18 |
19 | # Forces a non-empty pool to be deleted.
20 | attribute :force, :kind_of => [TrueClass, FalseClass], :default => false
21 |
22 | attr_accessor :exists
23 |
--------------------------------------------------------------------------------
/recipes/conf.rb:
--------------------------------------------------------------------------------
1 | # fail 'mon_initial_members must be set in config' if node['ceph']['config']['mon_initial_members'].nil?
2 |
3 | unless node['ceph']['config']['fsid']
4 | Chef::Log.warn('We are genereting a new uuid for fsid')
5 | require 'securerandom'
6 | node.set['ceph']['config']['fsid'] = SecureRandom.uuid
7 | node.save
8 | end
9 |
10 | directory '/etc/ceph' do
11 | owner 'root'
12 | group 'root'
13 | mode '0755'
14 | action :create
15 | end
16 |
17 | template '/etc/ceph/ceph.conf' do
18 | source 'ceph.conf.erb'
19 | variables lazy {
20 | {
21 | :mon_addresses => mon_addresses,
22 | :is_rgw => node['ceph']['is_radosgw']
23 | }
24 | }
25 | mode '0644'
26 | end
27 |
--------------------------------------------------------------------------------
/attributes/default.rb:
--------------------------------------------------------------------------------
1 | default['ceph']['install_debug'] = false
2 | default['ceph']['encrypted_data_bags'] = false
3 |
4 | default['ceph']['install_repo'] = true
5 |
6 | default['ceph']['user_pools'] = []
7 |
8 | case node['platform']
9 | when 'ubuntu'
10 | default['ceph']['init_style'] = 'upstart'
11 | else
12 | default['ceph']['init_style'] = 'sysvinit'
13 | end
14 |
15 | case node['platform_family']
16 | when 'debian'
17 | packages = ['ceph-common']
18 | packages += debug_packages(packages) if node['ceph']['install_debug']
19 | default['ceph']['packages'] = packages
20 | when 'rhel', 'fedora'
21 | packages = ['ceph']
22 | packages += debug_packages(packages) if node['ceph']['install_debug']
23 | default['ceph']['packages'] = packages
24 | else
25 | default['ceph']['packages'] = []
26 | end
27 |
--------------------------------------------------------------------------------
/recipes/apt.rb:
--------------------------------------------------------------------------------
1 |
2 | include_recipe 'apt'
3 |
4 | branch = node['ceph']['branch']
5 |
6 | distribution_codename =
7 | case node['lsb']['codename']
8 | when 'jessie' then 'sid'
9 | else node['lsb']['codename']
10 | end
11 |
12 | apt_preference 'ceph_repo' do
13 | glob '*'
14 | pin 'origin "ceph.com"'
15 | pin_priority '1001'
16 | end
17 |
18 | apt_repository 'ceph' do
19 | repo_name 'ceph'
20 | uri node['ceph']['debian'][branch]['repository']
21 | distribution distribution_codename
22 | components ['main']
23 | key node['ceph']['debian'][branch]['repository_key']
24 | end
25 |
26 | apt_repository 'ceph-extras' do
27 | repo_name 'ceph-extras'
28 | uri node['ceph']['debian']['extras']['repository']
29 | distribution distribution_codename
30 | components ['main']
31 | key node['ceph']['debian']['extras']['repository_key']
32 | only_if { node['ceph']['extras_repo'] }
33 | end
34 |
--------------------------------------------------------------------------------
/libraries/utils.rb:
--------------------------------------------------------------------------------
1 | def debug_packages(packages)
2 | packages.map { |x| x + debug_ext }
3 | end
4 |
5 | def debug_ext
6 | case node['platform_family']
7 | when 'debian'
8 | '-dbg'
9 | when 'rhel', 'fedora'
10 | '-debug'
11 | else
12 | ''
13 | end
14 | end
15 |
16 | def cephfs_requires_fuse
17 | # What kernel version supports the given Ceph version tunables
18 | # http://ceph.com/docs/master/rados/operations/crush-map/
19 | min_versions = {
20 | 'argonaut' => 3.6,
21 | 'bobtail' => 3.9,
22 | 'cuttlefish' => 3.9,
23 | 'dumpling' => 3.9,
24 | 'emperor' => 3.9,
25 | 'firefly' => 3.15
26 | }
27 | min_versions.default = 3.15
28 |
29 | # If we are on linux and have a new-enough kernel, allow kernel mount
30 | if node['os'] == 'linux' && Gem::Version.new(node['kernel']['release'].to_f) >= Gem::Version.new(min_versions[node['ceph']['version']])
31 | false
32 | else
33 | true
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/recipes/cephfs.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: cephfs
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | ceph_cephfs node['ceph']['cephfs_mount'] do
21 | use_fuse node['ceph']['cephfs_use_fuse'].nil? ? cephfs_requires_fuse : node['ceph']['cephfs_use_fuse']
22 | action [:mount, :enable]
23 | end
24 |
--------------------------------------------------------------------------------
/resources/client.rb:
--------------------------------------------------------------------------------
1 | actions :add
2 | default_action :add
3 |
4 | attribute :name, :kind_of => String, :name_attribute => true
5 | attribute :caps, :kind_of => Hash, :default => { 'mon' => 'allow r', 'osd' => 'allow r' }
6 |
7 | # Whether to store the secret in a keyring file or a plain secret file
8 | attribute :as_keyring, :kind_of => [TrueClass, FalseClass], :default => true
9 |
10 | # what the key should be called in the ceph cluster
11 | # defaults to client.#{name}.#{hostname}
12 | attribute :keyname, :kind_of => String
13 |
14 | # The actual key (a random key will be generated if not provided)
15 | attribute :key, :kind_of => String, :default => nil
16 |
17 | # where the key should be saved
18 | # defaults to /etc/ceph/ceph.client.#{name}.#{hostname}.keyring if as_keyring
19 | # defaults to /etc/ceph/ceph.client.#{name}.#{hostname}.secret if not as_keyring
20 | attribute :filename, :kind_of => String
21 |
22 | # key file access creds
23 | attribute :owner, :kind_of => String, :default => 'root'
24 | attribute :group, :kind_of => String, :default => 'root'
25 | attribute :mode, :kind_of => [Integer, String], :default => '00640'
26 |
27 | attr_accessor :exists, :caps_match, :keys_match
28 |
--------------------------------------------------------------------------------
/recipes/rpm.rb:
--------------------------------------------------------------------------------
1 | platform_family = node['platform_family']
2 |
3 | case platform_family
4 | when 'rhel'
5 | include_recipe 'yum-epel' if node['ceph']['el_add_epel']
6 | end
7 |
8 | branch = node['ceph']['branch']
9 | if branch == 'dev' && platform_family != 'centos' && platform_family != 'fedora'
10 | fail "Dev branch for #{platform_family} is not yet supported"
11 | end
12 |
13 | yum_repository 'ceph' do
14 | baseurl node['ceph'][platform_family][branch]['repository']
15 | gpgkey node['ceph'][platform_family][branch]['repository_key']
16 | end
17 |
18 | yum_repository 'ceph-extra' do
19 | baseurl node['ceph'][platform_family]['extras']['repository']
20 | gpgkey node['ceph'][platform_family]['extras']['repository_key']
21 | only_if { node['ceph']['extras_repo'] }
22 | end
23 |
24 | package 'parted' # needed by ceph-disk-prepare to run partprobe
25 | package 'hdparm' # used by ceph-disk activate
26 | package 'xfsprogs' # needed by ceph-disk-prepare to format as xfs
27 | if node['platform_family'] == 'rhel' && node['platform_version'].to_f > 6
28 | package 'btrfs-progs' # needed to format as btrfs, in the future
29 | end
30 | if node['platform_family'] == 'rhel' && node['platform_version'].to_f < 7
31 | package 'python-argparse'
32 | end
33 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 |
3 | # Style tests. Rubocop and Foodcritic
4 | namespace :style do
5 | begin
6 | require 'rubocop/rake_task'
7 | desc 'Run Ruby style checks'
8 | RuboCop::RakeTask.new(:ruby)
9 | rescue LoadError
10 | puts '>>>>> Rubocop gem not loaded, omitting tasks' unless ENV['CI']
11 | end
12 |
13 | begin
14 | require 'foodcritic'
15 |
16 | desc 'Run Chef style checks'
17 | FoodCritic::Rake::LintTask.new(:chef) do |t|
18 | t.options = {
19 | fail_tags: ['any'],
20 | tags: ['~FC003'],
21 | chef_version: '11.6.0'
22 | }
23 | end
24 | rescue LoadError
25 | puts '>>>>> foodcritic gem not loaded, omitting tasks' unless ENV['CI']
26 | end
27 | end
28 |
29 | desc 'Run all style checks'
30 | task style: ['style:chef', 'style:ruby']
31 |
32 | # Integration tests. Kitchen.ci
33 | namespace :integration do
34 | begin
35 | require 'kitchen/rake_tasks'
36 |
37 | desc 'Run kitchen integration tests'
38 | Kitchen::RakeTasks.new
39 | rescue LoadError
40 | puts '>>>>> Kitchen gem not loaded, omitting tasks' unless ENV['CI']
41 | end
42 | end
43 |
44 | desc 'Run all tests on Travis'
45 | task travis: ['style']
46 |
47 | # Default
48 | task default: ['style', 'integration:kitchen:all']
49 |
--------------------------------------------------------------------------------
/test/cookbooks/ceph_test/recipes/cephfs.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph_test
4 | # Recipe:: cephfs
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | ceph_cephfs '/ceph' do
21 | use_fuse cephfs_requires_fuse
22 | action [:mount, :enable]
23 | end
24 | ceph_cephfs '/ceph.fuse' do
25 | use_fuse true
26 | action [:mount]
27 | end
28 | ceph_cephfs '/ceph.fstab' do
29 | use_fuse true
30 | action [:mount, :enable]
31 | end
32 | directory '/ceph/subdir'
33 | file '/ceph/subdir/file' do
34 | content "It works\n"
35 | end
36 |
37 | unless cephfs_requires_fuse
38 | ceph_cephfs '/subceph' do
39 | use_fuse false
40 | cephfs_subdir '/subdir'
41 | action [:mount]
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/recipes/install.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: default
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | packages = []
21 |
22 | case node['platform_family']
23 | when 'debian'
24 | packages = %w(
25 | ceph
26 | ceph-common
27 | )
28 |
29 | if node['ceph']['install_debug']
30 | packages_dbg = %w(
31 | ceph-dbg
32 | ceph-common-dbg
33 | )
34 | packages += packages_dbg
35 | end
36 | when 'rhel', 'fedora'
37 | packages = %w(
38 | ceph
39 | )
40 |
41 | if node['ceph']['install_debug']
42 | packages_dbg = %w(
43 | ceph-debug
44 | )
45 | packages += packages_dbg
46 | end
47 | end
48 |
49 | packages.each do |pkg|
50 | package pkg do
51 | action :install
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/test/integration/aio/bats/cephfs.bats:
--------------------------------------------------------------------------------
1 | @test "/recipe_ceph is mounted" {
2 | grep -q -E '^\S+\s+/recipe_ceph\s+' /proc/mounts
3 | }
4 |
5 | @test "/ceph is mounted" {
6 | grep -q -E '^\S+\s+/ceph\s+' /proc/mounts
7 | }
8 | @test "/ceph.fuse is mounted" {
9 | grep -q -E '^\S+\s+/ceph\.fuse\s+fuse' /proc/mounts
10 | }
11 | @test "/ceph.fstab is mounted" {
12 | grep -q -E '^\S+\s+/ceph\.fstab\s+fuse' /proc/mounts
13 | }
14 |
15 | @test "/ceph is in fstab" {
16 | grep -q -E '^\S+\s+/ceph\s+\S+\s+\S*_netdev\S*\s' /etc/fstab
17 | }
18 | @test "/ceph.fuse is NOT in fstab" {
19 | grep -v -q -E '^\S+\s+/ceph.fuse\s+' /etc/fstab
20 | }
21 | @test "/ceph.fstab is in fstab" {
22 | grep -q -E '^\S+\s+/ceph.fstab\s+\S+\s+\S*_netdev\S*\s' /etc/fstab
23 | }
24 |
25 | @test "test file exists in /ceph" {
26 | test -e /ceph/subdir/file
27 | grep -q 'It works' /ceph/subdir/file
28 | }
29 | @test "test file exists in /ceph.fuse" {
30 | test -e /ceph.fuse/subdir/file
31 | grep -q 'It works' /ceph.fuse/subdir/file
32 | }
33 |
34 | # if we are using kernel cephfs
35 | if grep -q -E '^\S+\s+/ceph\s+ceph' /proc/mounts; then
36 | @test "/subceph is mounted" {
37 | grep -q -E '^\S+\s+/subceph\s+ceph' /proc/mounts
38 | }
39 | @test "/subceph is NOT in fstab" {
40 | grep -v -q -E '^\S+\s+/subceph\s+' /etc/fstab
41 | }
42 | @test "test file exists in /subceph" {
43 | test -e /subceph/file
44 | grep -q 'It works' /subceph/file
45 | }
46 | fi
47 |
48 |
--------------------------------------------------------------------------------
/recipes/tgt.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: radosgw
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | node.default['ceph']['extras_repo'] = true
21 |
22 | case node['platform_family']
23 | when 'debian'
24 | packages = %w(
25 | tgt
26 | )
27 | when 'rhel', 'fedora'
28 | packages = %w(
29 | scsi-target-utils
30 | )
31 | end
32 |
33 | packages.each do |pkg|
34 | package pkg do
35 | action :upgrade
36 | end
37 | end
38 |
39 | include_recipe 'ceph::conf'
40 | # probably needs the key
41 | service 'tgt' do
42 | if node['platform'] == 'ubuntu'
43 | # The ceph version of tgt does not provide an Upstart script
44 | provider Chef::Provider::Service::Init::Debian
45 | service_name 'tgt'
46 | else
47 | service_name 'tgt'
48 | end
49 | supports :restart => true
50 | action [:enable, :start]
51 | end
52 |
--------------------------------------------------------------------------------
/chefignore:
--------------------------------------------------------------------------------
1 | # Put files/directories that should be ignored in this file when uploading
2 | # or sharing to the community site.
3 | # Lines that start with '# ' are comments.
4 |
5 | # OS generated files #
6 | ######################
7 | .DS_Store
8 | Icon?
9 | nohup.out
10 | ehthumbs.db
11 | Thumbs.db
12 |
13 | # SASS #
14 | ########
15 | .sass-cache
16 |
17 | # EDITORS #
18 | ###########
19 | \#*
20 | .#*
21 | *~
22 | *.sw[a-z]
23 | *.bak
24 | REVISION
25 | TAGS*
26 | tmtags
27 | *_flymake.*
28 | *_flymake
29 | *.tmproj
30 | .project
31 | .settings
32 | mkmf.log
33 |
34 | ## COMPILED ##
35 | ##############
36 | a.out
37 | *.o
38 | *.pyc
39 | *.so
40 | *.com
41 | *.class
42 | *.dll
43 | *.exe
44 | */rdoc/
45 |
46 | # Testing #
47 | ###########
48 | .watchr
49 | .rspec
50 | spec/*
51 | spec/fixtures/*
52 | test/*
53 | features/*
54 | examples/*
55 | Guardfile
56 | Procfile
57 |
58 | # SCM #
59 | #######
60 | .git
61 | */.git
62 | .gitignore
63 | .gitmodules
64 | .gitconfig
65 | .gitattributes
66 | .svn
67 | */.bzr/*
68 | */.hg/*
69 | */.svn/*
70 |
71 | # Berkshelf #
72 | #############
73 | Berksfile
74 | Berksfile.lock
75 | cookbooks/*
76 | tmp
77 |
78 | # Cookbooks #
79 | #############
80 | CONTRIBUTING
81 | CHANGELOG*
82 |
83 | # Strainer #
84 | ############
85 | Colanderfile
86 | Strainerfile
87 | .colander
88 | .strainer
89 |
90 | # Vagrant #
91 | ###########
92 | .vagrant
93 | Vagrantfile
94 |
95 | # Travis #
96 | ##########
97 | .travis.yml
98 | test/
99 | spec/
100 | examples/
101 |
--------------------------------------------------------------------------------
/.kitchen.yml:
--------------------------------------------------------------------------------
1 | ---
2 | driver_plugin: vagrant
3 | driver_config:
4 | vagrantfile_erb: test/integration/Vagrantfile.erb
5 | require_chef_omnibus: true
6 |
7 | platforms:
8 | - name: ubuntu-12.04
9 | run_list:
10 | - recipe[apt]
11 | - name: ubuntu-14.04
12 | run_list:
13 | - recipe[apt]
14 | attributes:
15 | apache:
16 | mpm: event # ugly workaround for onehealth-cookbooks/apache2 #236
17 | - name: debian-7.4
18 | run_list:
19 | - recipe[apt]
20 | - name: centos-6.5
21 | - name: centos-5.10
22 | - name: fedora-18
23 |
24 | provisioner:
25 | name: chef_zero
26 |
27 | suites:
28 | - name: default
29 | run_list:
30 | - "recipe[ceph::repo]"
31 | - "recipe[ceph]"
32 | attributes: &defaults
33 | ceph:
34 | config:
35 | fsid: ae3f1d03-bacd-4a90-b869-1a4fabb107f2
36 | mon_initial_members:
37 | - "127.0.0.1"
38 | - name: osd
39 | run_list:
40 | - "role[ceph-osd]"
41 | attributes: *defaults
42 | - name: mon
43 | run_list:
44 | - "role[ceph-mon]"
45 | attributes: *defaults
46 | - name: mds
47 | run_list:
48 | - "role[ceph-mds]"
49 | attributes: *defaults
50 | - name: radosgw
51 | run_list:
52 | - "role[ceph-radosgw]"
53 | attributes: *defaults
54 | - name: aio
55 | attributes:
56 | ceph:
57 | config-sections:
58 | global:
59 | "osd journal size" : 128
60 | "osd pool default size": 1
61 | osd_devices:
62 | - { device: "/dev/sdb" }
63 | - { device: "/dev/sdc" }
64 | - { device: "/dev/sdd" }
65 | run_list:
66 | - recipe[ceph::all_in_one]
67 | - recipe[ceph_test::cephfs]
68 |
--------------------------------------------------------------------------------
/attributes/radosgw.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Cookbook Name:: ceph
3 | # Attributes:: radosgw
4 | #
5 | # Copyright 2011, DreamHost Web Hosting
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | include_attribute 'ceph'
21 |
22 | default['ceph']['radosgw']['api_fqdn'] = 'localhost'
23 | default['ceph']['radosgw']['admin_email'] = 'admin@example.com'
24 | default['ceph']['radosgw']['rgw_addr'] = '*:80'
25 | default['ceph']['radosgw']['rgw_port'] = false
26 | default['ceph']['radosgw']['webserver_companion'] = 'apache2' # can be civetweb or false
27 | default['ceph']['radosgw']['use_apache_fork'] = true
28 | default['ceph']['radosgw']['init_style'] = node['ceph']['init_style']
29 |
30 | default['ceph']['radosgw']['path'] = '/var/www'
31 |
32 | if node['platform_family'] == 'suse'
33 | default['ceph']['radosgw']['path'] = '/srv/www/ceph-radosgw'
34 | end
35 |
36 | case node['platform_family']
37 | when 'debian'
38 | packages = ['radosgw']
39 | packages += debug_packages(packages) if node['ceph']['install_debug']
40 | default['ceph']['radosgw']['packages'] = packages
41 | when 'rhel', 'fedora', 'suse'
42 | default['ceph']['radosgw']['packages'] = ['ceph-radosgw']
43 | else
44 | default['ceph']['radosgw']['packages'] = []
45 | end
46 |
--------------------------------------------------------------------------------
/test/cookbooks/ceph_test/README.md:
--------------------------------------------------------------------------------
1 | ceph_test Cookbook
2 | ==================
3 | TODO: Enter the cookbook description here.
4 |
5 | e.g.
6 | This cookbook makes your favorite breakfast sandwich.
7 |
8 | Requirements
9 | ------------
10 | TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
11 |
12 | e.g.
13 | #### packages
14 | - `toaster` - ceph_test needs toaster to brown your bagel.
15 |
16 | Attributes
17 | ----------
18 | TODO: List your cookbook attributes here.
19 |
20 | e.g.
21 | #### ceph_test::default
22 |
23 |
24 | | Key |
25 | Type |
26 | Description |
27 | Default |
28 |
29 |
30 | | ['ceph_test']['bacon'] |
31 | Boolean |
32 | whether to include bacon |
33 | true |
34 |
35 |
36 |
37 | Usage
38 | -----
39 | #### ceph_test::default
40 | TODO: Write usage instructions for each cookbook.
41 |
42 | e.g.
43 | Just include `ceph_test` in your node's `run_list`:
44 |
45 | ```json
46 | {
47 | "name":"my_node",
48 | "run_list": [
49 | "recipe[ceph_test]"
50 | ]
51 | }
52 | ```
53 |
54 | Contributing
55 | ------------
56 | TODO: (optional) If this is a public cookbook, detail the process for contributing. If this is a private cookbook, remove this section.
57 |
58 | e.g.
59 | 1. Fork the repository on Github
60 | 2. Create a named feature branch (like `add_component_x`)
61 | 3. Write your change
62 | 4. Write tests for your change (if applicable)
63 | 5. Run the tests, ensuring they all pass
64 | 6. Submit a Pull Request using Github
65 |
66 | License and Authors
67 | -------------------
68 | Authors: TODO: List authors
69 |
--------------------------------------------------------------------------------
/recipes/radosgw_apache2_repo.rb:
--------------------------------------------------------------------------------
1 | if node['ceph']['radosgw']['use_apache_fork'] == true
2 | if node.platform_family?('debian') &&
3 | %w(precise quantal raring saucy squeeze trusty wheezy).include?(node['lsb']['codename'])
4 | apt_repository 'ceph-apache2' do
5 | repo_name 'ceph-apache2'
6 | uri "http://gitbuilder.ceph.com/apache2-deb-#{node['lsb']['codename']}-x86_64-basic/ref/master"
7 | distribution node['lsb']['codename']
8 | components ['main']
9 | key 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
10 | end
11 | apt_repository 'ceph-modfastcgi' do
12 | repo_name 'ceph-modfastcgi'
13 | uri "http://gitbuilder.ceph.com/libapache-mod-fastcgi-deb-#{node['lsb']['codename']}-x86_64-basic/ref/master"
14 | distribution node['lsb']['codename']
15 | components ['main']
16 | key 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
17 | end
18 | elsif (node.platform_family?('fedora') && [18, 19].include?(node['platform_version'].to_i)) ||
19 | (node.platform_family?('rhel') && [6].include?(node['platform_version'].to_i))
20 | platform_family = node['platform_family']
21 | platform_version = node['platform_version'].to_i
22 | yum_repository 'ceph-apache2' do
23 | baseurl "http://gitbuilder.ceph.com/apache2-rpm-#{node['platform']}#{platform_version}-x86_64-basic/ref/master"
24 | gpgkey node['ceph'][platform_family]['dev']['repository_key']
25 | end
26 | yum_repository 'ceph-modfastcgi' do
27 | baseurl "http://gitbuilder.ceph.com/mod_fastcgi-rpm-#{node['platform']}#{platform_version}-x86_64-basic/ref/master"
28 | gpgkey node['ceph'][platform_family]['dev']['repository_key']
29 | end
30 | else
31 | Log.info("Ceph's Apache and Apache FastCGI forks not available for this distribution")
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/templates/default/rgw.conf.erb:
--------------------------------------------------------------------------------
1 | <% if node['ceph']['radosgw']['rgw_port'] -%>
2 | FastCgiExternalServer <%= node['ceph']['radosgw']['path'] %>/s3gw.fcgi -host 127.0.0.1:<%= node['ceph']['radosgw']['rgw_port'] %>
3 | <% else -%>
4 | FastCgiExternalServer <%= node['ceph']['radosgw']['path'] %>/s3gw.fcgi -socket /var/run/ceph-radosgw/radosgw.<%= node['hostname'] %>
5 | <% end -%>
6 |
7 | LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\"" proxy_combined
8 | LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" \"%{Host}i\"" proxy_debug
9 |
10 | >
11 | ServerName <%= @params[:server_name] %>
12 | <% if node['ceph']['radosgw']['api_aliases'] -%>
13 | <% node['ceph']['radosgw']['api_aliases'].each do |api_alias| -%>
14 | ServerAlias <%= api_alias %>
15 | <% end -%>
16 | <% end -%>
17 | ServerAdmin <%= node["ceph"]["radosgw"]["admin_email"] %>
18 | DocumentRoot <%= node['ceph']['radosgw']['path'] %>
19 |
20 | RewriteEngine On
21 | RewriteRule ^/([a-zA-Z0-9-_.]*)([/]?.*) /s3gw.fcgi?page=$1¶ms=$2&%{QUERY_STRING} [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
22 |
23 |
24 | >
25 | Options +ExecCGI
26 | AllowOverride All
27 | SetHandler fastcgi-script
28 | AuthBasicAuthoritative Off
29 | <%- if node['apache']['version'].to_f < 2.4 %>
30 | Order allow,deny
31 | Allow from all
32 | <%- else %>
33 | Require all granted
34 | <%- end %>
35 |
36 |
37 |
38 | AllowEncodedSlashes On
39 |
40 | ErrorLog /var/log/<%= node['apache']['package'] %>/error.log
41 | CustomLog /var/log/<%= node['apache']['package'] %>/rgw-access.log proxy_combined
42 | ServerSignature Off
43 |
44 |
--------------------------------------------------------------------------------
/providers/pool.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Cookbook Name:: ceph
3 | # Provider:: pool
4 | #
5 | # Author:: Sergio de Carvalho
6 | #
7 |
8 | def whyrun_supported?
9 | true
10 | end
11 |
12 | use_inline_resources
13 |
14 | action :create do
15 | if @current_resource.exists
16 | Chef::Log.info "#{@new_resource} already exists - nothing to do."
17 | else
18 | converge_by("Creating #{@new_resource}") do
19 | create_pool
20 | end
21 | end
22 | end
23 |
24 | action :delete do
25 | if @current_resource.exists
26 | converge_by("Deleting #{@new_resource}") do
27 | delete_pool
28 | end
29 | else
30 | Chef::Log.info "#{@current_resource} does not exist - nothing to do."
31 | end
32 | end
33 |
34 | def load_current_resource
35 | @current_resource = Chef::Resource::CephPool.new(@new_resource.name)
36 | @current_resource.name(@new_resource.name)
37 | @current_resource.exists = pool_exists?(@current_resource.name)
38 | end
39 |
40 | def create_pool
41 | cmd_text = "ceph osd pool create #{new_resource.name} #{new_resource.pg_num}"
42 | cmd_text << " #{new_resource.create_options}" if new_resource.create_options
43 | cmd = Mixlib::ShellOut.new(cmd_text)
44 | cmd.run_command
45 | cmd.error!
46 | Chef::Log.debug "Pool created: #{cmd.stderr}"
47 | end
48 |
49 | def delete_pool
50 | cmd_text = "ceph osd pool delete #{new_resource.name}"
51 | cmd_text << " #{new_resource.name} --yes-i-really-really-mean-it" if
52 | new_resource.force
53 | cmd = Mixlib::ShellOut.new(cmd_text)
54 | cmd.run_command
55 | cmd.error!
56 | Chef::Log.debug "Pool deleted: #{cmd.stderr}"
57 | end
58 |
59 | def pool_exists?(name)
60 | cmd = Mixlib::ShellOut.new("ceph osd pool get #{name} size")
61 | cmd.run_command
62 | cmd.error!
63 | Chef::Log.debug "Pool exists: #{cmd.stdout}"
64 | true
65 | rescue
66 | Chef::Log.debug "Pool doesn't seem to exist: #{cmd.stderr}"
67 | false
68 | end
69 |
--------------------------------------------------------------------------------
/recipes/mds.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: mds
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | include_recipe 'ceph'
21 | include_recipe 'ceph::mds_install'
22 |
23 | cluster = 'ceph'
24 |
25 | directory "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}" do
26 | owner 'root'
27 | group 'root'
28 | mode 00755
29 | recursive true
30 | action :create
31 | end
32 |
33 | ceph_client 'mds' do
34 | caps('osd' => 'allow *', 'mon' => 'allow rwx')
35 | keyname "mds.#{node['hostname']}"
36 | filename "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}/keyring"
37 | end
38 |
39 | file "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}/done" do
40 | owner 'root'
41 | group 'root'
42 | mode 00644
43 | end
44 |
45 | service_type = node['ceph']['osd']['init_style']
46 |
47 | case service_type
48 | when 'upstart'
49 | filename = 'upstart'
50 | else
51 | filename = 'sysvinit'
52 | end
53 | file "/var/lib/ceph/mds/#{cluster}-#{node['hostname']}/#{filename}" do
54 | owner 'root'
55 | group 'root'
56 | mode 00644
57 | end
58 |
59 | service 'ceph_mds' do
60 | case service_type
61 | when 'upstart'
62 | service_name 'ceph-mds-all-starter'
63 | provider Chef::Provider::Service::Upstart
64 | else
65 | service_name 'ceph'
66 | end
67 | action [:enable, :start]
68 | supports :restart => true
69 | end
70 |
--------------------------------------------------------------------------------
/templates/default/ceph.conf.erb:
--------------------------------------------------------------------------------
1 | [global]
2 | <% unless node['ceph']['config']['fsid'].nil? -%>
3 | fsid = <%= node['ceph']['config']['fsid'] %>
4 | <% end -%>
5 | <% if node['ceph']['is_mon'] -%>
6 | mon initial members = <%= node['ceph']['config']['mon_initial_members'] %>
7 | <% end -%>
8 | mon host = <%= @mon_addresses.sort.join(', ') %>
9 | <% if (! node['ceph']['config']['global'].nil?) -%>
10 | <% node['ceph']['config']['global'].sort.each do |k, v| %>
11 | <%= k %> = <%= v %>
12 | <% end %>
13 | <% end -%>
14 |
15 | <% if (! node['ceph']['config']['osd'].nil?) -%>
16 | [osd]
17 | <% node['ceph']['config']['osd'].sort.each do |k, v| %>
18 | <%= k %> = <%= v %>
19 | <% end %>
20 | <% end -%>
21 |
22 | <% if (! node['ceph']['config']['mon'].nil?) -%>
23 | [mon]
24 | <% node['ceph']['config']['mon'].sort.each do |k, v| %>
25 | <%= k %> = <%= v %>
26 | <% end %>
27 | <% end -%>
28 |
29 | <% if (! node['ceph']['config']['mds'].nil?) -%>
30 | [mds]
31 | <% node['ceph']['config']['mds'].sort.each do |key, value| -%>
32 | <%= key %> = <%= value %>
33 | <% end -%>
34 | <% end -%>
35 |
36 | <% if (@is_rgw) -%>
37 | [client.radosgw.<%= node['hostname'] %>]
38 | <% if node['ceph']['radosgw']['webserver_companion'] == 'civetweb' -%>
39 | <% if node['ceph']['radosgw']['rgw_port'] == false %>
40 | rgw frontends = "civetweb port=80"
41 | <% else -%>
42 | rgw frontends = "civetweb port=<%=node['ceph']['radosgw']['rgw_port']%>"
43 | <% end -%>
44 | <% end -%>
45 | host = <%= node['hostname'] %>
46 | rgw socket path = /var/run/ceph-radosgw/radosgw.<%= node['hostname'] %>
47 | admin socket = /var/run/ceph-radosgw/ceph-client.radosgw.<%= node['hostname'] %>.asok
48 | pid file = /var/run/ceph-radosgw/$name.pid
49 | keyring = /etc/ceph/ceph.client.radosgw.<%= node['hostname'] %>.keyring
50 | log file = /var/log/radosgw/radosgw.log
51 | <% if (! node['ceph']['config']['rgw'].nil?) -%>
52 | <% node['ceph']['config']['rgw'].sort.each do |k, v| %>
53 | <%= k %> = <%= v %>
54 | <% end %>
55 | <% end -%>
56 | <% end -%>
57 |
58 | <% node['ceph']['config-sections'].sort.each do |name, sect| %>
59 | [<%= name %>]
60 | <% sect.sort.each do |k, v| %>
61 | <%= k %> = <%= v %>
62 | <% end %>
63 | <% end %>
64 |
--------------------------------------------------------------------------------
/recipes/radosgw.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: radosgw
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | node.default['ceph']['is_radosgw'] = true
21 |
22 | include_recipe 'ceph'
23 | include_recipe 'ceph::radosgw_install'
24 |
25 | directory '/var/log/radosgw' do
26 | owner node['apache']['user']
27 | group node['apache']['group']
28 | mode '0755'
29 | action :create
30 | end
31 |
32 | file '/var/log/radosgw/radosgw.log' do
33 | owner node['apache']['user']
34 | group node['apache']['group']
35 | end
36 |
37 | directory '/var/run/ceph-radosgw' do
38 | owner node['apache']['user']
39 | group node['apache']['group']
40 | mode '0755'
41 | action :create
42 | end
43 |
44 | if node['ceph']['radosgw']['webserver_companion']
45 | include_recipe "ceph::radosgw_#{node['ceph']['radosgw']['webserver_companion']}"
46 | end
47 |
48 | ceph_client 'radosgw' do
49 | caps('mon' => 'allow rw', 'osd' => 'allow rwx')
50 | owner 'root'
51 | group node['apache']['group']
52 | mode 0640
53 | end
54 |
55 | directory "/var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}" do
56 | recursive true
57 | only_if { node['platform'] == 'ubuntu' }
58 | end
59 |
60 | # needed by https://github.com/ceph/ceph/blob/master/src/upstart/radosgw-all-starter.conf
61 | file "/var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}/done" do
62 | action :create
63 | only_if { node['platform'] == 'ubuntu' }
64 | end
65 |
66 | service 'radosgw' do
67 | case node['ceph']['radosgw']['init_style']
68 | when 'upstart'
69 | service_name 'radosgw-all-starter'
70 | provider Chef::Provider::Service::Upstart
71 | else
72 | if node['platform'] == 'debian'
73 | service_name 'radosgw'
74 | else
75 | service_name 'ceph-radosgw'
76 | end
77 | end
78 | supports :restart => true
79 | action [:enable, :start]
80 | subscribes :restart, 'template[/etc/ceph/ceph.conf]'
81 | end
82 |
--------------------------------------------------------------------------------
/providers/cephfs.rb:
--------------------------------------------------------------------------------
1 | def create_client
2 | # Client settings
3 | client_name = "cephfs.#{node['hostname']}"
4 | filename = "/etc/ceph/ceph.client.#{client_name}.secret"
5 |
6 | name = 'cephfs'
7 | ceph_client name do
8 | filename filename
9 | caps('mon' => 'allow r', 'osd' => 'allow rw', 'mds' => 'allow')
10 | as_keyring false
11 | end
12 | end
13 |
14 | def manage_mount(directory, subdir, use_fuse, action)
15 | # Client settings
16 | client_name = "cephfs.#{node['hostname']}"
17 | filename = "/etc/ceph/ceph.client.#{client_name}.secret"
18 |
19 | if use_fuse
20 | if subdir != '/'
21 | Chef::Application.fatal!("Can't use a subdir with fuse mounts yet")
22 | end
23 | mount "#{action} #{directory}" do
24 | mount_point directory
25 | fstype 'fuse.ceph'
26 | # needs two slashes to indicate a network mount to chef
27 | device "conf=//etc/ceph/ceph.conf,id=#{client_name},keyfile=#{filename}"
28 | options 'defaults,_netdev'
29 | dump 0
30 | pass 0
31 | action action
32 | end
33 | else
34 | mons = mon_addresses.sort.join(',') + ':' + subdir
35 | mount "#{action} #{directory}" do
36 | mount_point directory
37 | fstype 'ceph'
38 | device mons
39 | options "_netdev,name=#{client_name},secretfile=#{filename}"
40 | dump 0
41 | pass 0
42 | action action
43 | end
44 | end
45 | end
46 |
47 | def whyrun_supported?
48 | true
49 | end
50 |
51 | def create_mount(action)
52 | create_client
53 | directory @new_resource.directory
54 | manage_mount(@new_resource.directory, @new_resource.cephfs_subdir, @new_resource.use_fuse, action)
55 | end
56 |
57 | action :mount do
58 | converge_by("Creating cephfs mount at #{@new_resource.directory}") do
59 | create_mount(:mount)
60 | end
61 | end
62 |
63 | action :remount do
64 | converge_by("Remounting cephfs mount at #{@new_resource.directory}") do
65 | create_mount(:remount)
66 | end
67 | end
68 |
69 | action :umount do
70 | converge_by("Unmounting cephfs mount at #{@new_resource.directory}") do
71 | manage_mount(@new_resource.directory, @new_resource.cephfs_subdir, @new_resource.use_fuse, :umount)
72 | end
73 | end
74 |
75 | action :enable do
76 | converge_by("Enabling cephfs mount at #{@new_resource.directory}") do
77 | create_mount(:enable)
78 | end
79 | end
80 |
81 | action :disable do
82 | converge_by("Disabling cephfs mount at #{@new_resource.directory}") do
83 | manage_mount(@new_resource.directory, @new_resource.cephfs_subdir, @new_resource.use_fuse, :disable)
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/recipes/radosgw_apache2.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: radosgw_apache2
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | # For EL, delete the current fastcgi configuration
21 | # and set the correct owners for dirs and logs
22 | # d_owner = d_group = 'root'
23 | # if node['platform_family'] == 'rhel'
24 | # file "#{node['apache']['dir']}/conf.d/fastcgi.conf" do
25 | # action :delete
26 | # backup false
27 | # end
28 | # d_owner = d_group = 'apache'
29 | # end
30 |
31 | # %W(/var/run/ceph
32 | # /var/lib/ceph/radosgw/ceph-radosgw.#{node['hostname']}
33 | # /var/lib/apache2/
34 | # ).each do |dir|
35 | # directory dir do
36 | # owner d_owner
37 | # group d_group
38 | # mode '0755'
39 | # recursive true
40 | # action :create
41 | # end
42 | # end
43 |
44 | include_recipe 'ceph'
45 | include_recipe 'ceph::radosgw_apache2_repo'
46 |
47 | node['ceph']['radosgw']['apache2']['packages'].each do |pck|
48 | package pck
49 | end
50 |
51 | include_recipe 'apache2'
52 |
53 | apache_module 'fastcgi' do
54 | conf true
55 | notifies :restart, 'service[apache2]'
56 | end
57 |
58 | apache_module 'rewrite' do
59 | conf false
60 | notifies :restart, 'service[apache2]'
61 | end
62 |
63 | web_app 'rgw' do
64 | template 'rgw.conf.erb'
65 | server_name node['ceph']['radosgw']['api_fqdn']
66 | admin_email node['ceph']['radosgw']['admin_email']
67 | ceph_rgw_addr node['ceph']['radosgw']['rgw_addr']
68 | end
69 |
70 | directory node['ceph']['radosgw']['path'] do
71 | owner 'root'
72 | group 'root'
73 | mode '0755'
74 | action :create
75 | end
76 |
77 | template "#{node['ceph']['radosgw']['path']}/s3gw.fcgi" do
78 | source 's3gw.fcgi.erb'
79 | owner 'root'
80 | group 'root'
81 | mode '0755'
82 | variables(
83 | :ceph_rgw_client => "client.radosgw.#{node['hostname']}"
84 | )
85 | end
86 |
87 | if node['platform_family'] == 'suse'
88 | bash 'Set MPM apache value' do
89 | code 'sed -i s/^[[:space:]]*APACHE_MPM=.*/APACHE_MPM=\"worker\"/ /etc/sysconfig/apache2'
90 | not_if 'grep -q "^[[:space:]]*APACHE_MPM=\"worker\"" /etc/sysconfig/apache2'
91 | notifies :restart, 'service[apache2]'
92 | end
93 | end
94 |
--------------------------------------------------------------------------------
/providers/client.rb:
--------------------------------------------------------------------------------
1 | use_inline_resources
2 |
3 | def whyrun_supported?
4 | true
5 | end
6 |
7 | action :add do
8 | filename = @current_resource.filename
9 | keyname = @current_resource.keyname
10 | as_keyring = @current_resource.as_keyring
11 | owner = @new_resource.owner
12 | group = @new_resource.group
13 | mode = @new_resource.mode
14 |
15 | if @current_resource.exists
16 | if @current_resource.keys_match && @current_resource.caps_match
17 | Chef::Log.info "Client #{@new_resource} already exists and matches "\
18 | 'specifications - nothing to do.'
19 | else
20 | converge_by("Recreating client #{@new_resource} as existing doesn't "\
21 | 'match specifications') do
22 | delete_entity(keyname)
23 | create_entity(keyname)
24 | end
25 | end
26 | else
27 | converge_by("Creating client #{@new_resource}") do
28 | create_entity(keyname)
29 | end
30 | end
31 |
32 | # Obtain the randomly generated key if one wasn't provided
33 | key = @new_resource.key || get_key(keyname)
34 |
35 | # update the key in the file
36 | file filename do # ~FC009
37 | content file_content(keyname, key, as_keyring)
38 | owner owner
39 | group group
40 | mode mode
41 | sensitive true if Chef::Resource::File.method_defined? :sensitive
42 | end
43 | end
44 |
45 | def load_current_resource
46 | @current_resource = Chef::Resource::CephClient.new(@new_resource.name)
47 | @current_resource.name(@new_resource.name)
48 | @current_resource.as_keyring(@new_resource.as_keyring)
49 | @current_resource.keyname(@new_resource.keyname || "client.#{@new_resource.name}.#{node['hostname']}")
50 | @current_resource.caps(get_caps(@current_resource.keyname))
51 | default_filename = "/etc/ceph/ceph.client.#{@new_resource.name}.#{node['hostname']}.#{@new_resource.as_keyring ? 'keyring' : 'secret'}"
52 | @current_resource.filename(@new_resource.filename || default_filename)
53 | @current_resource.key(get_key(@current_resource.keyname))
54 | @current_resource.caps_match = @current_resource.caps == @new_resource.caps
55 | @current_resource.keys_match = @new_resource.key.nil? || (@current_resource.key == @new_resource.key)
56 | @current_resource.exists = ! (@current_resource.key.nil? || @current_resource.key.empty?)
57 | end
58 |
59 | def file_content(keyname, key, as_keyring)
60 | if as_keyring
61 | "[#{keyname}]\n\tkey = #{key}\n"
62 | else
63 | key
64 | end
65 | end
66 |
67 | def get_key(keyname)
68 | cmd = "ceph auth print_key #{keyname} --name mon. --key='#{mon_secret}'"
69 | Mixlib::ShellOut.new(cmd).run_command.stdout
70 | end
71 |
72 | def get_caps(keyname)
73 | caps = {}
74 | cmd = "ceph auth get #{keyname} --name mon. --key='#{mon_secret}'"
75 | output = Mixlib::ShellOut.new(cmd).run_command.stdout
76 | output.scan(/caps\s*(\S+)\s*=\s*"([^"]*)"/) { |k, v| caps[k] = v }
77 | caps
78 | end
79 |
80 | def delete_entity(keyname)
81 | cmd_text = "ceph auth del #{keyname} --name mon. --key='#{mon_secret}'"
82 | cmd = Mixlib::ShellOut.new(cmd_text)
83 | cmd.run_command
84 | cmd.error!
85 | Chef::Log.debug "Client #{keyname} deleted"
86 | end
87 |
88 | def create_entity(keyname)
89 | tmp_keyring = "#{Chef::Config[:file_cache_path]}/.#{keyname}.keyring"
90 |
91 | if new_resource.key
92 | # store key provided in a temporary keyring file
93 | cmd_text = "ceph-authtool #{tmp_keyring} --create-keyring --name #{keyname} "\
94 | "--add-key '#{new_resource.key}'"
95 | cmd = Mixlib::ShellOut.new(cmd_text)
96 | cmd.run_command
97 | cmd.error!
98 |
99 | key_option = "-i #{tmp_keyring}"
100 | else
101 | key_option = ''
102 | end
103 |
104 | caps = new_resource.caps.map { |k, v| "#{k} '#{v}'" }.join(' ')
105 |
106 | cmd_text = "ceph auth #{key_option} add #{keyname} #{caps} --name mon. "\
107 | "--key='#{mon_secret}'"
108 | cmd = Mixlib::ShellOut.new(cmd_text)
109 | cmd.run_command
110 | cmd.error!
111 | Chef::Log.debug "Client #{keyname} created"
112 |
113 | # remove temporary keyring file
114 | file tmp_keyring do # ~FC009
115 | action :delete
116 | sensitive true if Chef::Resource::File.method_defined? :sensitive
117 | end
118 | end
119 |
--------------------------------------------------------------------------------
/recipes/mon.rb:
--------------------------------------------------------------------------------
1 | # This recipe creates a monitor cluster
2 | #
3 | # You should never change the mon default path or
4 | # the keyring path.
5 | # Don't change the cluster name either
6 | # Default path for mon data: /var/lib/ceph/mon/$cluster-$id/
7 | # which will be /var/lib/ceph/mon/ceph-`hostname`/
8 | # This path is used by upstart. If changed, upstart won't
9 | # start the monitor
10 | # The keyring files are created using the following pattern:
11 | # /etc/ceph/$cluster.client.$name.keyring
12 | # e.g. /etc/ceph/ceph.client.admin.keyring
13 | # The bootstrap-osd and bootstrap-mds keyring are a bit
14 | # different and are created in
15 | # /var/lib/ceph/bootstrap-{osd,mds}/ceph.keyring
16 |
17 | node.default['ceph']['is_mon'] = true
18 |
19 | include_recipe 'ceph'
20 | include_recipe 'ceph::mon_install'
21 |
22 | service_type = node['ceph']['mon']['init_style']
23 |
24 | directory '/var/run/ceph' do
25 | owner 'root'
26 | group 'root'
27 | mode 00755
28 | recursive true
29 | action :create
30 | end
31 |
32 | directory "/var/lib/ceph/mon/ceph-#{node['hostname']}" do
33 | owner 'root'
34 | group 'root'
35 | mode 00755
36 | recursive true
37 | action :create
38 | end
39 |
40 | # TODO: cluster name
41 | cluster = 'ceph'
42 |
43 | keyring = "#{Chef::Config[:file_cache_path]}/#{cluster}-#{node['hostname']}.mon.keyring"
44 |
45 | execute 'format mon-secret as keyring' do # ~FC009
46 | command lazy { "ceph-authtool '#{keyring}' --create-keyring --name=mon. --add-key='#{mon_secret}' --cap mon 'allow *'" }
47 | creates keyring
48 | only_if { mon_secret }
49 | sensitive true if Chef::Resource::Execute.method_defined? :sensitive
50 | end
51 |
52 | execute 'generate mon-secret as keyring' do # ~FC009
53 | command "ceph-authtool '#{keyring}' --create-keyring --name=mon. --gen-key --cap mon 'allow *'"
54 | creates keyring
55 | not_if { mon_secret }
56 | notifies :create, 'ruby_block[save mon_secret]', :immediately
57 | sensitive true if Chef::Resource::Execute.method_defined? :sensitive
58 | end
59 |
60 | execute 'add bootstrap-osd key to keyring' do
61 | command lazy { "ceph-authtool '#{keyring}' --name=client.bootstrap-osd --add-key='#{osd_secret}' --cap mon 'allow profile bootstrap-osd' --cap osd 'allow profile bootstrap-osd'" }
62 | only_if { node['ceph']['encrypted_data_bags'] && osd_secret }
63 | end
64 |
65 | ruby_block 'save mon_secret' do
66 | block do
67 | fetch = Mixlib::ShellOut.new("ceph-authtool '#{keyring}' --print-key --name=mon.")
68 | fetch.run_command
69 | key = fetch.stdout
70 | node.set['ceph']['monitor-secret'] = key
71 | node.save
72 | end
73 | action :nothing
74 | end
75 |
76 | execute 'ceph-mon mkfs' do
77 | command "ceph-mon --mkfs -i #{node['hostname']} --keyring '#{keyring}'"
78 | end
79 |
80 | ruby_block 'finalise' do
81 | block do
82 | ['done', service_type].each do |ack|
83 | ::File.open("/var/lib/ceph/mon/ceph-#{node['hostname']}/#{ack}", 'w').close
84 | end
85 | end
86 | end
87 |
88 | if service_type == 'upstart'
89 | service 'ceph-mon' do
90 | provider Chef::Provider::Service::Upstart
91 | action :enable
92 | end
93 | service 'ceph-mon-all' do
94 | provider Chef::Provider::Service::Upstart
95 | supports :status => true
96 | action [:enable, :start]
97 | end
98 | end
99 |
100 | service 'ceph_mon' do
101 | case service_type
102 | when 'upstart'
103 | service_name 'ceph-mon-all-starter'
104 | provider Chef::Provider::Service::Upstart
105 | else
106 | service_name 'ceph'
107 | end
108 | supports :restart => true, :status => true
109 | action [:enable, :start]
110 | end
111 |
112 | mon_addresses.each do |addr|
113 | execute "peer #{addr}" do
114 | command "ceph --admin-daemon '/var/run/ceph/ceph-mon.#{node['hostname']}.asok' add_bootstrap_peer_hint #{addr}"
115 | ignore_failure true
116 | end
117 | end
118 |
119 | # The key is going to be automatically created, We store it when it is created
120 | # If we're storing keys in encrypted data bags, then they've already been generated above
121 | if use_cephx? && !node['ceph']['encrypted_data_bags']
122 | ruby_block 'get osd-bootstrap keyring' do
123 | block do
124 | run_out = ''
125 | while run_out.empty?
126 | run_out = Mixlib::ShellOut.new('ceph auth get-key client.bootstrap-osd').run_command.stdout.strip
127 | sleep 2
128 | end
129 | node.set['ceph']['bootstrap_osd_key'] = run_out
130 | node.save
131 | end
132 | not_if { node['ceph']['bootstrap_osd_key'] }
133 | end
134 | end
135 |
--------------------------------------------------------------------------------
/attributes/repo.rb:
--------------------------------------------------------------------------------
1 | default['ceph']['branch'] = 'stable' # Can be stable, testing or dev.
2 | # Major release version to install or gitbuilder branch
3 | default['ceph']['version'] = 'firefly'
4 | default['ceph']['el_add_epel'] = true
5 | default['ceph']['repo_url'] = 'http://ceph.com'
6 | default['ceph']['extras_repo_url'] = 'http://ceph.com/packages/ceph-extras'
7 | default['ceph']['extras_repo'] = false
8 |
9 | case node['platform_family']
10 | when 'debian'
11 | # Debian/Ubuntu default repositories
12 | default['ceph']['debian']['stable']['repository'] = "#{node['ceph']['repo_url']}/debian-#{node['ceph']['version']}/"
13 | default['ceph']['debian']['stable']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
14 | default['ceph']['debian']['testing']['repository'] = "#{node['ceph']['repo_url']}/debian-testing/"
15 | default['ceph']['debian']['testing']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
16 | default['ceph']['debian']['dev']['repository'] = "http://gitbuilder.ceph.com/ceph-deb-#{node['lsb']['codename']}-x86_64-basic/ref/#{node['ceph']['version']}"
17 | default['ceph']['debian']['dev']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
18 | default['ceph']['debian']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/debian/"
19 | default['ceph']['debian']['extras']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
20 | when 'rhel'
21 | # Redhat/CentOS default repositories
22 | default['ceph']['rhel']['stable']['repository'] = "#{node['ceph']['repo_url']}/rpm-#{node['ceph']['version']}/el6/x86_64/"
23 | default['ceph']['rhel']['stable']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
24 | default['ceph']['rhel']['testing']['repository'] = "#{node['ceph']['repo_url']}/rpm-testing/el6/x86_64/"
25 | default['ceph']['rhel']['testing']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
26 | default['ceph']['rhel']['dev']['repository'] = "http://gitbuilder.ceph.com/ceph-rpm-centos6-x86_64-basic/ref/#{node['ceph']['version']}/x86_64/"
27 | default['ceph']['rhel']['dev']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
28 | default['ceph']['rhel']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/rpm/rhel6/x86_64/"
29 | default['ceph']['rhel']['extras']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
30 | when 'fedora'
31 | # Fedora default repositories
32 | default['ceph']['fedora']['stable']['repository'] = "#{node['ceph']['repo_url']}/rpm-#{node['ceph']['version']}/fc#{node['platform_version']}/x86_64/"
33 | default['ceph']['fedora']['stable']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
34 | default['ceph']['fedora']['testing']['repository'] = "#{node['ceph']['repo_url']}/rpm-testing/fc#{node['platform_version']}/x86_64/"
35 | default['ceph']['fedora']['testing']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
36 | 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/"
37 | default['ceph']['fedora']['dev']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/autobuild.asc'
38 | default['ceph']['fedora']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/rpm/fedora#{node['platform_version']}/x86_64/"
39 | default['ceph']['fedora']['extras']['repository_key'] = 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc'
40 | when 'suse'
41 | # (Open)SuSE default repositories
42 | # Chef doesn't make a difference between suse and opensuse
43 | suse = Mixlib::ShellOut.new("head -n1 /etc/SuSE-release| awk '{print $1}'").run_command.stdout.chomp.downcase
44 | suse = 'sles' if suse == 'suse'
45 | suse_version = suse << Mixlib::ShellOut.new("grep VERSION /etc/SuSE-release | awk -F'= ' '{print $2}'").run_command.stdout.chomp
46 |
47 | 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"
48 | default['ceph']['suse']['testing']['repository'] = "#{node['ceph']['repo_url']}/rpm-testing/#{suse_version}/x86_64/ceph-release-1-0.#{suse_version}.noarch.rpm"
49 | default['ceph']['suse']['extras']['repository'] = "#{node['ceph']['extras_repo_url']}/rpm/#{suse_version}/x86_64/"
50 | else
51 | fail "#{node['platform_family']} is not supported"
52 | end
53 |
--------------------------------------------------------------------------------
/recipes/osd.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Author:: Kyle Bader
3 | # Cookbook Name:: ceph
4 | # Recipe:: osd
5 | #
6 | # Copyright 2011, DreamHost Web Hosting
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 |
20 | # this recipe allows bootstrapping new osds, with help from mon
21 | # Sample environment:
22 | # #knife node edit ceph1
23 | # "osd_devices": [
24 | # {
25 | # "device": "/dev/sdc"
26 | # },
27 | # {
28 | # "device": "/dev/sdd",
29 | # "dmcrypt": true,
30 | # "journal": "/dev/sdd"
31 | # }
32 | # ]
33 |
34 | include_recipe 'ceph'
35 | include_recipe 'ceph::osd_install'
36 |
37 | package 'gdisk' do
38 | action :upgrade
39 | end
40 |
41 | package 'cryptsetup' do
42 | action :upgrade
43 | only_if { node['dmcrypt'] }
44 | end
45 |
46 | service_type = node['ceph']['osd']['init_style']
47 |
48 | directory '/var/lib/ceph/bootstrap-osd' do
49 | owner 'root'
50 | group 'root'
51 | mode '0755'
52 | end
53 |
54 | # TODO: cluster name
55 | cluster = 'ceph'
56 |
57 | execute 'format bootstrap-osd as keyring' do # ~FC009
58 | command lazy { "ceph-authtool '/var/lib/ceph/bootstrap-osd/#{cluster}.keyring' --create-keyring --name=client.bootstrap-osd --add-key='#{osd_secret}'" }
59 | creates "/var/lib/ceph/bootstrap-osd/#{cluster}.keyring"
60 | only_if { osd_secret }
61 | sensitive true if Chef::Resource::Execute.method_defined? :sensitive
62 | end
63 |
64 | if crowbar?
65 | node['crowbar']['disks'].each do |disk, _data|
66 | execute "ceph-disk-prepare #{disk}" do
67 | command "ceph-disk-prepare /dev/#{disk}"
68 | only_if { node['crowbar']['disks'][disk]['usage'] == 'Storage' }
69 | notifies :run, 'execute[udev trigger]', :immediately
70 | end
71 |
72 | ruby_block "set disk usage for #{disk}" do
73 | block do
74 | node.set['crowbar']['disks'][disk]['usage'] = 'ceph-osd'
75 | node.save
76 | end
77 | end
78 | end
79 |
80 | execute 'udev trigger' do
81 | command 'udevadm trigger --subsystem-match=block --action=add'
82 | action :nothing
83 | end
84 | else
85 | # Calling ceph-disk-prepare is sufficient for deploying an OSD
86 | # After ceph-disk-prepare finishes, the new device will be caught
87 | # by udev which will run ceph-disk-activate on it (udev will map
88 | # the devices if dm-crypt is used).
89 | # IMPORTANT:
90 | # - Always use the default path for OSD (i.e. /var/lib/ceph/
91 | # osd/$cluster-$id)
92 | # - $cluster should always be ceph
93 | # - The --dmcrypt option will be available starting w/ Cuttlefish
94 | if node['ceph']['osd_devices']
95 | devices = node['ceph']['osd_devices']
96 |
97 | devices = Hash[(0...devices.size).zip devices] unless devices.is_a? Hash
98 |
99 | devices.each do |index, osd_device|
100 | unless osd_device['status'].nil?
101 | Log.info("osd: osd_device #{osd_device} has already been setup.")
102 | next
103 | end
104 |
105 | directory osd_device['device'] do # ~FC022
106 | owner 'root'
107 | group 'root'
108 | recursive true
109 | only_if { osd_device['type'] == 'directory' }
110 | end
111 |
112 | dmcrypt = osd_device['encrypted'] == true ? '--dmcrypt' : ''
113 |
114 | execute "ceph-disk-prepare on #{osd_device['device']}" do
115 | command "ceph-disk-prepare #{dmcrypt} #{osd_device['device']} #{osd_device['journal']}"
116 | action :run
117 | notifies :create, "ruby_block[save osd_device status #{index}]", :immediately
118 | end
119 |
120 | execute "ceph-disk-activate #{osd_device['device']}" do
121 | only_if { osd_device['type'] == 'directory' }
122 | end
123 |
124 | # we add this status to the node env
125 | # so that we can implement recreate
126 | # and/or delete functionalities in the
127 | # future.
128 | ruby_block "save osd_device status #{index}" do
129 | block do
130 | node.normal['ceph']['osd_devices'][index]['status'] = 'deployed'
131 | node.save
132 | end
133 | action :nothing
134 | end
135 | end
136 | service 'ceph_osd' do
137 | case service_type
138 | when 'upstart'
139 | service_name 'ceph-osd-all-starter'
140 | provider Chef::Provider::Service::Upstart
141 | else
142 | service_name 'ceph'
143 | end
144 | action [:enable, :start]
145 | supports :restart => true
146 | end
147 | else
148 | Log.info('node["ceph"]["osd_devices"] empty')
149 | end
150 | end
151 |
--------------------------------------------------------------------------------
/libraries/default.rb:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | def crowbar?
4 | !defined?(Chef::Recipe::Barclamp).nil?
5 | end
6 |
7 | def mon_env_search_string
8 | if crowbar?
9 | mon_roles = search(:role, 'name:crowbar-* AND run_list:role\[ceph-mon\]')
10 | unless mon_roles.empty?
11 | search_string = mon_roles.map { |role_object| 'roles:' + role_object.name }.join(' OR ')
12 | search_string = "(#{search_string}) AND ceph_config_environment:#{node['ceph']['config']['environment']}"
13 | end
14 | else
15 | search_string = 'ceph_is_mon:true'
16 | if node['ceph']['search_environment'].is_a?(String)
17 | # search for nodes with this particular env
18 | search_string += " AND chef_environment:#{node['ceph']['search_environment']}"
19 | elsif node['ceph']['search_environment']
20 | # search for any nodes with this environment
21 | search_string += " AND chef_environment:#{node.chef_environment}"
22 | # search for any mon nodes
23 | end
24 | end
25 | search_string
26 | end
27 |
28 | def mon_nodes
29 | search_string = mon_env_search_string
30 |
31 | if use_cephx? && !node['ceph']['encrypted_data_bags']
32 | search_string = "(#{search_string}) AND (ceph_bootstrap_osd_key:*)"
33 | end
34 | search(:node, search_string)
35 | end
36 |
37 | def osd_secret
38 | if node['ceph']['encrypted_data_bags']
39 | secret = Chef::EncryptedDataBagItem.load_secret(node['ceph']['osd']['secret_file'])
40 | return Chef::EncryptedDataBagItem.load('ceph', 'osd', secret)['secret']
41 | elsif node['ceph']['bootstrap_osd_key']
42 | return node['ceph']['bootstrap_osd_key']
43 | else
44 | return mon_nodes[0]['ceph']['bootstrap_osd_key']
45 | end
46 | end
47 |
48 | # If public_network is specified with one or more networks, we need to
49 | # search for a matching monitor IP in the node environment.
50 | # 1. For each public network specified:
51 | # a. We look if the network is IPv6 or IPv4
52 | # b. We look for a route matching the network
53 | # c. If we found match, we return the IP with the port
54 | def find_node_ip_in_network(network, nodeish = nil)
55 | require 'netaddr'
56 | nodeish = node unless nodeish
57 | network.split(/\s*,\s*/).each do |n|
58 | net = NetAddr::CIDR.create(n)
59 | nodeish['network']['interfaces'].each do |_iface, addrs|
60 | addresses = addrs['addresses'] || []
61 | addresses.each do |ip, params|
62 | return ip_address_to_ceph_address(ip, params) if ip_address_in_network?(ip, params, net)
63 | end
64 | end
65 | end
66 | nil
67 | end
68 |
69 | def ip_address_in_network?(ip, params, net)
70 | # Find the IP on this interface that matches the public_network
71 | # Uses a few heuristics to find the primary IP that ceph would bind to
72 | # Most secondary IPs never have a broadcast value set
73 | # Other secondary IPs have a prefix of /32
74 | # Match the prefix that we want from the public_network prefix
75 | if params['family'] == 'inet' && net.version == 4
76 | ip4_address_in_network?(ip, params, net)
77 | elsif params['family'] == 'inet6' && net.version == 6
78 | ip6_address_in_network?(ip, params, net)
79 | else
80 | false
81 | end
82 | end
83 |
84 | def ip4_address_in_network?(ip, params, net)
85 | net.contains?(ip) && params.key?('broadcast') && params['prefixlen'].to_i == net.bits
86 | end
87 |
88 | def ip6_address_in_network?(ip, params, net)
89 | net.contains?(ip) && params['prefixlen'].to_i == net.bits
90 | end
91 |
92 | def ip_address_to_ceph_address(ip, params)
93 | if params['family'].eql?('inet')
94 | return "#{ip}:6789"
95 | elsif params['family'].eql?('inet6')
96 | return "[#{ip}]:6789"
97 | end
98 | end
99 |
100 | def mon_addresses
101 | mon_ips = []
102 |
103 | if File.exist?("/var/run/ceph/ceph-mon.#{node['hostname']}.asok")
104 | mon_ips = quorum_members_ips
105 | else
106 | mons = []
107 | # make sure if this node runs ceph-mon, it's always included even if
108 | # search is laggy; put it first in the hopes that clients will talk
109 | # primarily to local node
110 | mons << node if node['ceph']['is_mon']
111 |
112 | mons += mon_nodes
113 | if crowbar?
114 | mon_ips = mons.map { |node| Chef::Recipe::Barclamp::Inventory.get_network_by_type(node, 'admin').address }
115 | else
116 | if node['ceph']['config']['global'] && node['ceph']['config']['global']['public network']
117 | mon_ips = mons.map { |nodeish| find_node_ip_in_network(node['ceph']['config']['global']['public network'], nodeish) }
118 | else
119 | mon_ips = mons.map { |node| node['ipaddress'] + ':6789' }
120 | end
121 | end
122 | end
123 | mon_ips.reject(&:nil?).uniq
124 | end
125 |
126 | def mon_secret
127 | if node['ceph']['encrypted_data_bags']
128 | secret = Chef::EncryptedDataBagItem.load_secret(node['ceph']['mon']['secret_file'])
129 | Chef::EncryptedDataBagItem.load('ceph', 'mon', secret)['secret']
130 | elsif !mon_nodes.empty?
131 | mon_nodes[0]['ceph']['monitor-secret']
132 | elsif node['ceph']['monitor-secret']
133 | node['ceph']['monitor-secret']
134 | else
135 | Chef::Log.info('No monitor secret found')
136 | nil
137 | end
138 | end
139 |
140 | def quorum_members_ips
141 | mon_ips = []
142 | cmd = Mixlib::ShellOut.new("ceph --admin-daemon /var/run/ceph/ceph-mon.#{node['hostname']}.asok mon_status")
143 | cmd.run_command
144 | cmd.error!
145 |
146 | mons = JSON.parse(cmd.stdout)['monmap']['mons']
147 | mons.each do |k|
148 | mon_ips.push(k['addr'][0..-3])
149 | end
150 | mon_ips
151 | end
152 |
153 | def quorum?
154 | # "ceph auth get-or-create-key" would hang if the monitor wasn't
155 | # in quorum yet, which is highly likely on the first run. This
156 | # helper lets us delay the key generation into the next
157 | # chef-client run, instead of hanging.
158 | #
159 | # Also, as the UNIX domain socket connection has no timeout logic
160 | # in the ceph tool, this exits immediately if the ceph-mon is not
161 | # running for any reason; trying to connect via TCP/IP would wait
162 | # for a relatively long timeout.
163 | quorum_states = %w(leader, peon)
164 |
165 | cmd = Mixlib::ShellOut.new("ceph --admin-daemon /var/run/ceph/ceph-mon.#{node['hostname']}.asok mon_status")
166 | cmd.run_command
167 | cmd.error!
168 |
169 | state = JSON.parse(cmd.stdout)['state']
170 | quorum_states.include?(state)
171 | end
172 |
173 | # Cephx is on by default, but users can disable it.
174 | # type can be one of 3 values: cluster, service, or client. If the value is none of the above, set it to cluster
175 | def use_cephx?(type = nil)
176 | # Verify type is valid
177 | type = 'cluster' if %w(cluster service client).index(type).nil?
178 |
179 | # CephX is enabled if it's not configured at all, or explicity enabled
180 | node['ceph']['config'].nil? ||
181 | node['ceph']['config']['global'].nil? ||
182 | node['ceph']['config']['global']["auth #{type} required"].nil? ||
183 | node['ceph']['config']['global']["auth #{type} required"] == 'cephx'
184 | end
185 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2011-2015, Red Hat, Inc.
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chef cookbook [](https://travis-ci.org/ceph/ceph-cookbook) [](https://gitter.im/ceph/ceph-cookbook)
2 |
3 | ## DESCRIPTION
4 |
5 | Installs and configures Ceph, a distributed network storage and filesystem designed to provide excellent performance, reliability, and scalability.
6 |
7 | The current version is focused towards deploying Monitors and OSD on Ubuntu.
8 |
9 | For documentation on how to use this cookbook, refer to the [USAGE](#USAGE) section.
10 |
11 | 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)
12 |
13 | ## REQUIREMENTS
14 |
15 | ### Chef
16 |
17 | \>= 11.6.0
18 |
19 | ### Platform
20 |
21 | Tested as working:
22 |
23 | * Debian Wheezy (7)
24 | * Ubuntu Precise (12.04)
25 | * Ubuntu Trusty (14.04)
26 |
27 | ### Cookbooks
28 |
29 | The ceph cookbook requires the following cookbooks from Chef:
30 |
31 | https://supermarket.chef.io/
32 |
33 | * [apt](https://supermarket.chef.io/cookbooks/apt)
34 | * [apache2](https://supermarket.chef.io/cookbooks/apache2)
35 |
36 | ## TEMPLATES
37 |
38 | ## USAGE
39 |
40 | Ceph cluster design is beyond the scope of this README, please turn to the
41 | public wiki, mailing lists, visit our IRC channel, or contact Inktank:
42 |
43 | http://ceph.com/docs/master
44 | http://ceph.com/resources/mailing-list-irc/
45 | http://www.inktank.com/
46 |
47 | This cookbook can be used to implement a chosen cluster design. Most of the configuration is retrieved from node attributes, which can be set by an environment or by a wrapper cookbook. A basic cluster configuration will need most of the following attributes:
48 |
49 | * `node['ceph']['config']['fsid']` - the cluster UUID
50 | * `node['ceph']['config]'['global']['public network']` - a CIDR specification of the public network
51 | * `node['ceph']['config]'['global']['cluster network']` - a CIDR specification of a separate cluster replication network
52 | * `node['ceph']['config]'['global']['rgw dns name']` - the main domain of the radosgw daemon
53 |
54 | Most notably, the configuration does _NOT_ need to set the `mon_initial_members`, because the cookbook does a node search to find other mons in the same environment.
55 |
56 | The other set of attributes that this recipe needs is `node['ceph']['osd_devices']`, which is an array of OSD definitions, similar to the following:
57 |
58 | * {'device' => '/dev/sdb'} - Use a full disk for the OSD, with a small partition for the journal
59 | * {'type' => 'directory', 'device' => '/src/node/sdb1/ceph'} - Use a directory, and have a small file for the journal
60 | * {'device' => '/dev/sde', 'dmcrypt' => true} - Store the data encrypted by passing --dmcrypt to `ceph-disk-prepare`
61 | * {'device' => '/dev/sdc', 'journal' => '/dev/sdd2'} - use a full disk for the OSD with a custom partition for the journal
62 |
63 | ### Using a Policy Wrapper Cookbook
64 |
65 | To automate setting several of these node attributes, it is recommended to use a policy wrapper cookbook. This allows the ability to use Chef Server cookbook versions along with environment version restrictions to roll out configuration changes in an ordered fashion.
66 |
67 | It also can help with automating some settings. For example, a wrapper cookbook could peek at the list of harddrives that ohai has found and populate node['ceph']['osd_devices'] accordingly, instead of manually typing them all in:
68 |
69 | ```ruby
70 | node.override['ceph']['osd_devices'] = node['block_device'].each.reject{ |name, data| name !~ /^sd[b-z]/}.sort.map { |name, data| {'journal' => "/dev/#{name}"} }
71 | ```
72 |
73 | For best results, the wrapper cookbook's recipe should be placed before the Ceph cookbook in the node's runlist. This will ensure that any attributes are in place before the Ceph cookbook runs and consumes those attributes.
74 |
75 | ### Ceph Monitor
76 |
77 | Ceph monitor nodes should use the ceph-mon role.
78 |
79 | Includes:
80 |
81 | * ceph::default
82 |
83 | ### Ceph Metadata Server
84 |
85 | Ceph metadata server nodes should use the ceph-mds role.
86 |
87 | Includes:
88 |
89 | * ceph::default
90 |
91 | ### Ceph OSD
92 |
93 | Ceph OSD nodes should use the ceph-osd role
94 |
95 | Includes:
96 |
97 | * ceph::default
98 |
99 | ### Ceph Rados Gateway
100 |
101 | Ceph Rados Gateway nodes should use the ceph-radosgw role
102 |
103 | ## ATTRIBUTES
104 |
105 | ### General
106 |
107 | * `node['ceph']['search_environment']` - a custom Chef environment to search when looking for mon nodes. The cookbook defaults to searching the current environment
108 | * `node['ceph']['branch']` - selects whether to install the stable, testing, or dev version of Ceph
109 | * `node['ceph']['version']` - install a version of Ceph that is different than the cookbook default. If this is changed in a wrapper cookbook, some repository urls may also need to be replaced, and they are found in attributes/repo.rb. If the branch attribute is set to dev, this selects the gitbuilder branch to install
110 | * `node['ceph']['extras_repo']` - whether to install the ceph extras repo. The tgt recipe requires this
111 |
112 | * `node['ceph']['config']['fsid']` - the cluster UUID
113 | * `node['ceph']['config']['global']['public network']` - a CIDR specification of the public network
114 | * `node['ceph']['config']['global']['cluster network']` - a CIDR specification of a separate cluster replication network
115 | * `node['ceph']['config']['config-sections']` - add to this hash to add extra config sections to the ceph.conf
116 |
117 | * `node['ceph']['user_pools']` - an array of pool definitions, with attributes `name`, `pg_num` and `create_options` (optional), that are automatically created when a monitor is deployed
118 |
119 | ### Ceph MON
120 |
121 | * `node['ceph']['config']['mon']` - a hash of settings to save in ceph.conf in the [mon] section, such as `'mon osd nearfull ratio' => '0.70'`
122 |
123 | ### Ceph OSD
124 |
125 | * `node['ceph']['osd_devices']` - an array of OSD definitions for the current node
126 | * `node['ceph']['config']['osd']` - a hash of settings to save in ceph.conf in the [osd] section, such as `'osd max backfills' => 2`
127 | * `node['ceph']['config']['osd']['osd crush location']` - this attribute can be set on a per-node basis to maintain Crush map locations
128 |
129 | ### Ceph MDS
130 |
131 | * `node['ceph']['config']['mds']` - a hash of settings to save in ceph.conf in the [mds] section, such as `'mds cache size' => '100000'`
132 | * `node['ceph']['cephfs_mount']` - where the cephfs recipe should mount CephFS
133 | * `node['ceph']['cephfs_use_fuse']` - whether the cephfs recipe should use the fuse cephfs client. It will default to heuristics based on the kernel version
134 |
135 | ### Ceph Rados Gateway
136 |
137 | * `node['ceph']['radosgw']['api_fqdn']` - what vhost to configure in the web server
138 | * `node['ceph']['radosgw']['admin_email']` - the admin email address to configure in the web server
139 | * `node['ceph']['radosgw']['rgw_addr']` - the web server's bind address, such as *:80
140 | * `node['ceph']['radosgw']['rgw_port']` - if set, connects to the radosgw fastcgi over this port instead of a unix socket
141 | * `node['ceph']['radosgw']['webserver_companion']` - defaults to 'apache2', but it can be set to 'civetweb', or to false in order to leave it unconfigured
142 | * `node['ceph']['radosgw']['path']` - where to save the s3gw.fcgi file
143 | * `node['ceph']['config']['global']['rgw dns name']` - the main domain of the radosgw daemon, to calculate the bucket name from a subdomain
144 |
145 | ## Resources/Providers
146 |
147 | ### ceph\_client
148 |
149 | 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.
150 |
151 | #### Actions
152 |
153 | - :add - creates a client key with the given parameters
154 |
155 | #### Parameters
156 |
157 | - :name - name attribute. The name of the client key to create. This is used to provide a default for the other parameters
158 | - :caps - A hash of capabilities that should be granted to the client key. Defaults to `{ 'mon' => 'allow r', 'osd' => 'allow r' }`
159 | - :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
160 | - :keyname - The key name to register in Ceph. Defaults to `client.#{name}.#{hostname}`
161 | - :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`
162 | - :owner - Which owner should own the saved key file. Defaults to root
163 | - :group - Which group should own the saved key file. Defaults to root
164 | - :mode - What file mode should be applied. Defaults to '00640'
165 |
166 | ### ceph\_cephfs
167 |
168 | 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.
169 |
170 | #### Actions
171 |
172 | - :mount - mounts CephFS
173 | - :umount - unmounts CephFS
174 | - :remount - remounts CephFS
175 | - :enable - adds an fstab entry to mount CephFS
176 | - :disable - removes an fstab entry to mount CephFS
177 |
178 | #### Parameters
179 |
180 | - :directory - name attribute. Where to mount CephFS in the local filesystem
181 | - :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
182 | - :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
183 |
184 | ### ceph\_pool
185 |
186 | The ceph\_pool LWRP provides an easy way to create and delete Ceph pools.
187 |
188 | It assumes that connectivity to the cluster is setup and that admin credentials are available from default locations, e.g. /etc/ceph/ceph.client.admin.keyring.
189 |
190 | #### Actions
191 |
192 | - :add - creates a pool with the given number of placement groups
193 | - :delete - deletes an existing pool
194 |
195 | #### Parameters
196 |
197 | - :name - the name of the pool to create or delete
198 | - :pg_num - number of placement groups, when creating a new pool
199 | - :create_options - arguments for pool creation (optional)
200 | - :force - force the deletion of an exiting pool along with any data that is stored in it
201 |
202 | ## DEVELOPING
203 |
204 | ### Style Guide
205 |
206 | This cookbook requires a style guide for all contributions. Travis will automatically verify that every Pull Request follows the style guide.
207 |
208 | 1. Install [ChefDK](http://downloads.chef.io/chef-dk/)
209 | 2. Activate ChefDK's copy of ruby: `eval "$(chef shell-init bash)"`
210 | 3. `bundle install`
211 | 4. `bundle exec rake style`
212 |
213 | ### Testing
214 |
215 | This cookbook uses Test Kitchen to verify functionality. A Pull Request can't be merged if it causes any of the test configurations to fail.
216 |
217 | 1. Install [ChefDK](http://downloads.chef.io/chef-dk/)
218 | 2. Activate ChefDK's copy of ruby: `eval "$(chef shell-init bash)"`
219 | 3. `bundle install`
220 | 4. `bundle exec kitchen test aio-debian-74`
221 | 5. `bundle exec kitchen test aio-ubuntu-1204`
222 | 6. `bundle exec kitchen test aio-ubuntu-1404`
223 |
224 | ## LICENSE AND AUTHORS
225 |
226 | * Author: Kyle Bader
227 |
228 | * Copyright 2013, DreamHost Web Hosting and Inktank Storage Inc.
229 |
230 | Licensed under the Apache License, Version 2.0 (the "License");
231 | you may not use this file except in compliance with the License.
232 | You may obtain a copy of the License at
233 |
234 | http://www.apache.org/licenses/LICENSE-2.0
235 |
236 | Unless required by applicable law or agreed to in writing, software
237 | distributed under the License is distributed on an "AS IS" BASIS,
238 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
239 | See the License for the specific language governing permissions and
240 | limitations under the License.
241 |
--------------------------------------------------------------------------------