Pull in att-cloud swift cookbook (forked from rcbops)

Change-Id: Icdee121c28a2fce0261b567eceaab4d46fd0b64c
This commit is contained in:
Alan Meadows
2013-06-04 14:37:03 -07:00
parent ad05d4a63e
commit c799676a38
56 changed files with 4297 additions and 5 deletions

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
Berksfile.lock
validation.pem
metadata.json
*~
.bundle/
cookbooks/
.cookbooks
.vagrant
*.swp

7
Berksfile Normal file
View File

@@ -0,0 +1,7 @@
site :opscode
cookbook 'swift', :path => '.'
cookbook 'apt', :git => 'git://github.com/opscode-cookbooks/apt.git'
cookbook 'statsd', :git => 'git://github.com/att-cloud/cookbook-statsd.git'
cookbook 'memcached'
cookbook 'sysctl'

9
Gemfile Normal file
View File

@@ -0,0 +1,9 @@
source "https://rubygems.org"
gem "chef", "~> 11.4.4"
gem "json", "<= 1.7.7" # chef dependency
gem "berkshelf", "~> 1.4.5"
gem "chefspec", "~> 1.3.0"
gem "foodcritic"
gem "strainer"
gem "webmock", "~> 1.11.0"

202
Gemfile.lock Normal file
View File

@@ -0,0 +1,202 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (3.2.13)
i18n (= 0.6.1)
multi_json (~> 1.0)
addressable (2.3.4)
akami (1.2.0)
gyoku (>= 0.4.0)
nokogiri (>= 1.4.0)
berkshelf (1.4.5)
activesupport (>= 3.2.0)
addressable
celluloid (>= 0.14.0)
chozo (>= 0.6.1)
faraday (>= 0.8.5)
hashie (>= 2.0.2)
json (>= 1.5.0)
minitar
mixlib-config (~> 1.1)
mixlib-shellout (~> 1.1)
multi_json (~> 1.5)
retryable
ridley (~> 0.12.4)
solve (>= 0.4.2)
thor (~> 0.18.0)
yajl-ruby
builder (3.2.0)
celluloid (0.14.0)
timers (>= 1.0.0)
chef (11.4.4)
erubis
highline (>= 1.6.9)
json (>= 1.4.4, <= 1.7.7)
mixlib-authentication (>= 1.3.0)
mixlib-cli (~> 1.3.0)
mixlib-config (>= 1.1.2)
mixlib-log (>= 1.3.0)
mixlib-shellout
net-ssh (~> 2.6)
net-ssh-multi (~> 1.1.0)
ohai (>= 0.6.0)
rest-client (>= 1.0.4, < 1.7.0)
yajl-ruby (~> 1.1)
chefspec (1.3.0)
chef (>= 10.0)
erubis
fauxhai (>= 0.1.1, < 2.0)
minitest-chef-handler (>= 0.6.0)
rspec (~> 2.0)
chozo (0.6.1)
activesupport (>= 3.2.0)
hashie (>= 2.0.2)
multi_json (>= 1.3.0)
ci_reporter (1.8.4)
builder (>= 2.1.2)
crack (0.3.2)
diff-lcs (1.2.4)
erubis (2.7.0)
faraday (0.8.7)
multipart-post (~> 1.1)
fauxhai (1.1.1)
httparty
net-ssh
ohai
ffi (1.8.1)
foodcritic (2.1.0)
erubis
gherkin (~> 2.11.7)
nokogiri (~> 1.5.4)
rak (~> 1.4)
treetop (~> 1.4.10)
yajl-ruby (~> 1.1.0)
gherkin (2.11.8)
multi_json (~> 1.3)
gssapi (1.0.3)
ffi (>= 1.0.1)
gyoku (1.0.0)
builder (>= 2.1.2)
hashie (2.0.5)
highline (1.6.19)
httparty (0.11.0)
multi_json (~> 1.0)
multi_xml (>= 0.5.2)
httpclient (2.2.0.2)
httpi (0.9.7)
rack
i18n (0.6.1)
ipaddress (0.8.0)
json (1.7.7)
little-plugger (1.1.3)
logging (1.6.2)
little-plugger (>= 1.1.3)
mime-types (1.23)
minitar (0.5.4)
minitest (4.7.4)
minitest-chef-handler (1.0.1)
chef
ci_reporter
minitest (~> 4.7.3)
mixlib-authentication (1.3.0)
mixlib-log
mixlib-cli (1.3.0)
mixlib-config (1.1.2)
mixlib-log (1.6.0)
mixlib-shellout (1.1.0)
multi_json (1.7.4)
multi_xml (0.5.4)
multipart-post (1.2.0)
net-http-persistent (2.8)
net-ssh (2.6.7)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
net-ssh-multi (1.1)
net-ssh (>= 2.1.4)
net-ssh-gateway (>= 0.99.0)
nokogiri (1.5.9)
nori (1.1.5)
ohai (6.16.0)
ipaddress
mixlib-cli
mixlib-config
mixlib-log
mixlib-shellout
systemu
yajl-ruby
polyglot (0.3.3)
rack (1.5.2)
rak (1.4)
rest-client (1.6.7)
mime-types (>= 1.16)
retryable (1.3.3)
ridley (0.12.4)
addressable
celluloid (~> 0.14.0)
chozo (>= 0.6.0)
erubis
faraday (>= 0.8.4)
hashie (>= 2.0.2)
mixlib-authentication (>= 1.3.0)
mixlib-config (>= 1.1.0)
mixlib-log (>= 1.3.0)
mixlib-shellout (>= 1.1.0)
net-http-persistent (>= 2.8)
net-ssh
retryable
solve (>= 0.4.4)
winrm (~> 1.1.0)
rspec (2.13.0)
rspec-core (~> 2.13.0)
rspec-expectations (~> 2.13.0)
rspec-mocks (~> 2.13.0)
rspec-core (2.13.1)
rspec-expectations (2.13.0)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.13.1)
rubyntlm (0.1.1)
savon (0.9.5)
akami (~> 1.0)
builder (>= 2.1.2)
gyoku (>= 0.4.0)
httpi (~> 0.9)
nokogiri (>= 1.4.0)
nori (~> 1.0)
wasabi (~> 1.0)
solve (0.4.4)
json
strainer (2.1.0)
berkshelf (~> 1.3)
systemu (2.5.2)
thor (0.18.1)
timers (1.1.0)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
uuidtools (2.1.4)
wasabi (1.0.0)
nokogiri (>= 1.4.0)
webmock (1.11.0)
addressable (>= 2.2.7)
crack (>= 0.3.2)
winrm (1.1.2)
gssapi (~> 1.0.0)
httpclient (~> 2.2.0.2)
logging (~> 1.6.1)
nokogiri (~> 1.5.0)
rubyntlm (~> 0.1.1)
savon (= 0.9.5)
uuidtools (~> 2.1.2)
yajl-ruby (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
berkshelf (~> 1.4.5)
chef (~> 11.4.4)
chefspec (~> 1.3.0)
foodcritic
json (<= 1.7.7)
strainer
webmock (~> 1.11.0)

234
README.md
View File

@@ -1,37 +1,260 @@
Description
===========
Installs the OpenStack Object Storage service **Swift** as part of the OpenStack reference deployment Chef for OpenStack. The http://github.com/mattray/chef-openstack-repo contains documentation for using this cookbook in the context of a full OpenStack deployment. Swift is currently installed from packages.
Installs the OpenStack Object Storage service **Swift** as part of the OpenStack reference deployment Chef for OpenStack. The http://github.com/stackforge/chef-openstack-repo contains documentation for using this cookbook in the context of a full OpenStack deployment. Swift is currently installed from packages.
https://wiki.openstack.org/wiki/Swift
Requirements
============
Clients
--------
* CentOS >= 6.3
* Ubuntu >= 12.04
Chef
---------
* 11.4.4
Cookbooks
---------
Usage
* memcached
* sysctl
Roles
=====
* swift-account-server - storage node for account data
* swift-container-server - storage node for container data
* swift-object-server - storage node for object server
* swift-proxy-server - proxy for swift storge nodes
* swift-setup - server responsible for generating initial settings
* swift-management-server - responsible for ring generation
The swift-management-server role performs the following functions:
* proxy node that knows super admin password
* ring repository and ring building workstation
* generally always has the swift-setup role too
* there can only be _one_ swift-management-server
There *must* be node with the the swift-managment-server role to act
as the ring repository.
In small environments, it is likely that all storage machines will
have all-in-one roles, with a load balancer ahead of it
In larger environments, where it is cost effective to split the proxy
and storage layer, storage nodes will carry
swift-{account,container,object}-server roles, and there will be
dedicated hosts with the swift-proxy-server role.
In really really huge environments, it's possible that the storage
node will be split into swift-{container,accout}-server nodes and
swift-object-server nodes.
Attributes
==========
* ```default[:swift][:authmode]``` - "swauth" or "keystone" (default "swauth"). Right now, only swauth is supported (defaults to swauth)
* ```default[:swift][:swift_secret_databag_name]``` - this cookbook supports an optional secret databag where we will retrieve the following attributes overriding any default attributes below. (defaults to nil)
```
{
"id": "swift_dal2",
"swift_hash": "1a7c0568fa84"
"swift_authkey": "keY4all"
"dispersion_auth_user": "ops:dispersion",
"dispersion_auth_key": "dispersionpass"
}
```
* ```default[:swift][:swift_hash]``` - swift_hash_path_suffix in /etc/swift/swift.conf (defaults to 107c0568ea84)
* ```default[:swift][:audit_hour]``` - Hour to run swift_auditor on storage nodes (defaults to 5)
* ```default[:swift][:disk_enum_expr]``` - Eval-able expression that lists
candidate disk nodes for disk probing. The result shoule be a hash
with keys being the device name (without the leading "/dev/") and a
hash block of any extra info associated with the device. For
example: { "sdc" => { "model": "Hitachi 7K3000" }}. Largely,
though, if you are going to make a list of valid devices, you
probably know all the valid devices, and don't need to pass any
metadata about them, so { "sdc" => {}} is probably enough. Example
expression: Hash[('a'..'f').to_a.collect{|x| [ "sd{x}", {} ]}]
* ```default[:swift][:ring][:part_power]``` - controls the size of the ring (defaults to 18)
* ```default[:swift][:ring][:min_part_hours]``` - the minimum number of hours before swift is allowed to migrate a partition (defaults to 1)
* ```default[:swift][:ring][:replicas]``` - how many replicas swift should retain (defaults to 3)
* ```default[:swift][:disk_test_filter]``` - an array of expressions that must
all be true in order a block deviced to be considered for
formatting and inclusion in the cluster. Each rule gets evaluated
with "candidate" set to the device name (without the leading
"/dev/") and info set to the node hash value. Default rules:
* "candidate =~ /sd[^a]/ or candidate =~ /hd[^a]/ or candidate =~
/vd[^a]/"
* "File.exists?('/dev/ + candidate)"
* "not system('/sbin/sfdisk -V /dev/' + candidate + '>/dev/null 2>&2')"
* "info['removable'] = 0" ])
* ```default[:swift][:expected_disks]``` - an array of device names that the
operator expecs to be identified by the previous two values. This
acts as a second-check on discovered disks. If this array doesn't
match the found disks, then chef processing will be stopped.
Example: ("b".."f").collect{|x| "sd#{x}"}. Default: none.
There are other attributes that must be set depending on authmode.
For "swauth", the following attributes are used:
* ```default[:swift][:authkey]``` - swauth super admin key if using swauth (defaults to test)
In addition, because swift is typically deployed as a cluster
there are some attributes used to find interfaces and ip addresses
on storage nodes:
* ```default[:swift][:git_builder_ip]``` - the IP address of the management server which other cluster members will use as their git pull target for ring updates (defaults to 127.0.0.1)
* ```default[:swift][:network][:proxy-bind-ip]``` - the IP address to bind to
on the proxy servers (defaults to 0.0.0.0 for all addresses)
* ```default[:swift][:network][:proxy-bind-port]``` - the port to bind to
on the proxy servers (defaults to 8080)
* ```default[:swift][:network][:account-bind-ip]``` - the IP address to bind to
on the account servers (defaults to 0.0.0.0 for all addresses)
* ```default[:swift][:network][:account-bind-port]``` - the port to bind to
on the account servers (defaults to 6002)
* ```default[:swift][:network][:container-bind-ip]``` - the IP address to bind to
on the container servers (defaults to 0.0.0.0 for all addresses)
* ```default[:swift][:network][:container-bind-port]``` - the port to bind to
on the container servers (defaults to 6002)
* ```default[:swift][:network][:object-bind-ip]``` - the IP address to bind to
on the object servers (defaults to 0.0.0.0 for all addresses)
* ```default[:swift][:network][:object-bind-port]``` - the port to bind to
on the container servers (defaults to 6002)
* ```default[:swift][:network][:object-cidr]``` - the CIDR network for your object
servers in order to build the ring (defaults to 10.0.0.0/24)
Examples
========
Example environment
-------------------
```json
{
"default_attributes": {
"swift": {
"swift_hash": "107c0568ea84",
"authmode": "swauth",
"authkey": "test"
"auto_rebuild_rings": false
"git_builder_ip": "10.0.0.10"
"swauth": {
"url": "http://10.0.0.10:8080/v1/"
}
},
},
"name": "swift",
"chef_type": "environment",
"json_class": "Chef::Environment"
}
```
This sets up defaults for a swauth-based cluster with the storage
network on 10.0.0.0/24.
Example all-in-one
--------------------------
Example all-in-one storage node config (note there should only ever be
one node with the swift-setup and swift-management roles)
```json
{
"id": "storage1",
"name": "storage1",
"json_class": "Chef::Node",
"run_list": [
"role[swift-setup]",
"role[swift-management-server]",
"role[swift-account-server]",
"role[swift-object-server]",
"role[swift-container-server]",
"role[swift-proxy-server]"
],
"chef_environment": "development",
"normal": {
"swift": {
"zone": "1"
}
}
}
```
Standalone Storage Server
-------------------------
```json
{
"name": "swift-object-server",
"json_class": "Chef::Role",
"run_list": [
"recipe[swift::object-server]"
],
"description": "A storage server role.",
"chef_type": "role"
}
```
Standalone Proxy Server
-----------------------
```json
"run_list": [
"role[swift-proxy-server]"
]
```
Testing
=====
=======
This cookbook is using [ChefSpec](https://github.com/acrmp/chefspec) for testing. Run the following before commiting. It will run your tests, and check for lint errors.
$ ./run_tests.bash
There is also a Vagrant test environment that you can launch in order to integration
test this cookbook. See the <a href="tests/README.md" target="_blank">tests/README.md</a> file for more information on launching the environment.
Testing
=======
$ bundle install
$ bundle exec berks install
$ bundle exec strainer test
License and Author
==================
| | |
|:---------------------|:---------------------------------------------------|
| **Author** | Matt Ray (<matt@opscode.com>) |
| **Authors** | Alan Meadows (<am240k@att.com>) |
| | Oisin Feely (<of3434@att.com>) |
| | Ron Pedde (<ron.pedde@rackspace.com>) |
| | Will Kelly (<will.kelly@rackspace.com>) |
| | |
| **Copyright** | Copyright (c) 2013, Opscode, Inc. |
| **Copyright** | Copyright (c) 2013, AT&T, Inc. |
| | Copyright (c) 2012, Rackspace US, Inc. |
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -44,3 +267,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and⋅
limitations under the License.

4
Strainerfile Normal file
View File

@@ -0,0 +1,4 @@
# Strainerfile
knife test: bundle exec knife cookbook test $COOKBOOK
foodcritic: bundle exec foodcritic -f any -t ~FC003 -t ~FC023 $SANDBOX/$COOKBOOK
chefspec: bundle exec rspec $SANDBOX/$COOKBOOK

194
attributes/default.rb Normal file
View File

@@ -0,0 +1,194 @@
#--------------------
# node/ring settings
#--------------------
default["swift"]["state"] = {}
default["swift"]["swift_hash"] = "107c0568ea84"
default["swift"]["audit_hour"] = "5"
default["swift"]["disk_enum_expr"] = "node[:block_device]"
default["swift"]["auto_rebuild_rings"] = false
default["swift"]["git_builder_ip"] = "127.0.0.1"
# the release only has any effect on ubuntu, and must be
# a valid release on http://ubuntu-cloud.archive.canonical.com/ubuntu
default["swift"]["release"] = "folsom"
# we support an optional secret databag where we will retrieve the
# following attributes overriding any default attributes here
#
# {
# "id": "swift_dal2",
# "swift_hash": "107c0568ea84"
# "swift_authkey": "keW4all"
# "dispersion_auth_user": "test:test",
# "dispersion_auth_key": "test"
# }
default["swift"]["swift_secret_databag_name"] = nil
#--------------------
# authentication
#--------------------
default["swift"]["authmode"] = "swauth"
default["swift"]["authkey"] = "test"
default["swift"]["swift_url"] = "http://127.0.0.1:8080/v1/"
default["swift"]["swauth_url"] = "http://127.0.0.1:8080/v1/"
default["swift"]["auth_url"] = "http://127.0.0.1:8080/auth/v1.0"
#---------------------
# dispersion settings
#---------------------
default["swift"]["dispersion"]["auth_user"] = "test:test"
default["swift"]["dispersion"]["auth_key"] = "test"
# settings for the swift ring - these default settings are
# a safe setting for testing but part_power should be set to
# 26 in production to allow a swift cluster with 50,000 spindles
default["swift"]["ring"]["part_power"] = 18
default["swift"]["ring"]["min_part_hours"] = 1
default["swift"]["ring"]["replicas"] = 3
#------------------
# statistics
#------------------
default["swift"]["enable_statistics"] = true
#------------------
# network settings
#------------------
# the cidr configuration items are unimportant for a single server
# configuration, but in a multi-server setup, the cidr should match
# the interface appropriate to that service as they are used to
# resolve the appropriate addresses to use for internode
# communication
# proxy servers
default["swift"]["network"]["proxy-bind-ip"] = "0.0.0.0"
default["swift"]["network"]["proxy-bind-port"] = "8080"
default["swift"]["network"]["proxy-cidr"] = "10.0.0.0/24"
# account servers
default["swift"]["network"]["account-bind-ip"] = "0.0.0.0"
default["swift"]["network"]["account-bind-port"] = "6002"
# container servers
default["swift"]["network"]["container-bind-ip"] = "0.0.0.0"
default["swift"]["network"]["container-bind-port"] = "6001"
# object servers
default["swift"]["network"]["object-bind-ip"] = "0.0.0.0"
default["swift"]["network"]["object-bind-port"] = "6000"
default["swift"]["network"]["object-cidr"] = "10.0.0.0/24"
#------------------
# sysctl
#------------------
# set sysctl properties for time waits
default['sysctl']['params']['net']['ipv4']['tcp_tw_recycle'] = 1
default['sysctl']['params']['net']['ipv4']['tcp_tw_reuse'] = 1
default['sysctl']['params']['net']['ipv4']['tcp_syncookies'] = 0
# N.B. conntrack_max may also need to be adjusted if
# server is running a stateful firewall
#------------------
# disk search
#------------------
# disk_test_filter is an array of predicates to test against disks to
# determine if a disk should be formatted and configured for swift.
# Each predicate is evaluated in turn, and a false from the predicate
# will result in the disk not being considered as a candidate for
# formatting.
default["swift"]["disk_test_filter"] = [ "candidate =~ /sd[^a]/ or candidate =~ /hd[^a]/ or candidate =~ /vd[^a]/ or candidate =~ /xvd[^a]/",
"File.exist?('/dev/' + candidate)",
"not system('/sbin/parted /dev/' + candidate + ' -s print | grep linux-swap')",
"not info.has_key?('removable') or info['removable'] == 0.to_s" ]
#------------------
# packages
#------------------
# Leveling between distros
case platform
when "redhat"
default["swift"]["platform"] = {
"disk_format" => "ext4",
"proxy_packages" => ["openstack-swift-proxy", "sudo", "cronie", "python-memcached"],
"object_packages" => ["openstack-swift-object", "sudo", "cronie"],
"container_packages" => ["openstack-swift-container", "sudo", "cronie"],
"account_packages" => ["openstack-swift-account", "sudo", "cronie"],
"swift_packages" => ["openstack-swift", "sudo", "cronie"],
"swauth_packages" => ["openstack-swauth", "sudo", "cronie"],
"rsync_packages" => ["rsync"],
"git_packages" => ["xinetd", "git", "git-daemon"],
"service_prefix" => "openstack-",
"service_suffix" => "",
"git_dir" => "/var/lib/git",
"git_service" => "git",
"service_provider" => Chef::Provider::Service::Redhat,
"override_options" => ""
}
#
# python-iso8601 is a missing dependency for swift.
# https://bugzilla.redhat.com/show_bug.cgi?id=875948
when "centos"
default["swift"]["platform"] = {
"disk_format" => "xfs",
"proxy_packages" => ["openstack-swift-proxy", "sudo", "cronie", "python-iso8601", "python-memcached" ],
"object_packages" => ["openstack-swift-object", "sudo", "cronie", "python-iso8601" ],
"container_packages" => ["openstack-swift-container", "sudo", "cronie", "python-iso8601" ],
"account_packages" => ["openstack-swift-account", "sudo", "cronie", "python-iso8601" ],
"swift_packages" => ["openstack-swift", "sudo", "cronie", "python-iso8601" ],
"swauth_packages" => ["openstack-swauth", "sudo", "cronie", "python-iso8601" ],
"rsync_packages" => ["rsync"],
"git_packages" => ["xinetd", "git", "git-daemon"],
"service_prefix" => "openstack-",
"service_suffix" => "",
"git_dir" => "/var/lib/git",
"git_service" => "git",
"service_provider" => Chef::Provider::Service::Redhat,
"override_options" => ""
}
when "fedora"
default["swift"]["platform"] = {
"disk_format" => "xfs",
"proxy_packages" => ["openstack-swift-proxy", "python-memcached"],
"object_packages" => ["openstack-swift-object"],
"container_packages" => ["openstack-swift-container"],
"account_packages" => ["openstack-swift-account"],
"swift_packages" => ["openstack-swift"],
"swauth_packages" => ["openstack-swauth"],
"rsync_packages" => ["rsync"],
"git_packages" => ["git", "git-daemon"],
"service_prefix" => "openstack-",
"service_suffix" => ".service",
"git_dir" => "/var/lib/git",
"git_service" => "git",
"service_provider" => Chef::Provider::Service::Systemd,
"override_options" => ""
}
when "ubuntu"
default["swift"]["platform"] = {
"disk_format" => "xfs",
"proxy_packages" => ["swift-proxy", "python-memcache"],
"object_packages" => ["swift-object"],
"container_packages" => ["swift-container"],
"account_packages" => ["swift-account", "python-swiftclient"],
"swift_packages" => ["swift"],
"swauth_packages" => ["swauth"],
"rsync_packages" => ["rsync"],
"git_packages" => ["git-daemon-sysvinit"],
"service_prefix" => "",
"service_suffix" => "",
"git_dir" => "/var/cache/git",
"git_service" => "git-daemon",
"service_provider" => Chef::Provider::Service::Upstart,
"override_options" => "-o Dpkg::Options:='--force-confold' -o Dpkg::Option:='--force-confdef'"
}
end

View File

@@ -0,0 +1,53 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.11 (GNU/Linux)
mQINBFAqSlgBEADPKwXUwqbgoDYgR20zFypxSZlSbrttOKVPEMb0HSUx9Wj8VvNC
r+mT4E9wAyq7NTIs5ad2cUhXoyenrjcfGqK6k9R6yRHDbvAxCSWTnJjw7mzsajDN
ocXC6THKVW8BSjrh0aOBLpht6d5QCO2vyWxw65FKM65GOsbX03ZngUPMuOuiOEHQ
Zo97VSH2pSB+L+B3d9B0nw3QnU8qZMne+nVWYLYRXhCIxSv1/h39SXzHRgJoRUFH
vL2aiiVrn88NjqfDW15HFhVJcGOFuACZnRA0/EqTq0qNo3GziQO4mxuZi3bTVL5s
GABiYW9uIlokPqcS7Fa0FRVIU9R+bBdHZompcYnKAeGag+uRvuTqC3MMRcLUS9Oi
/P9I8fPARXUPwzYN3fagCGB8ffYVqMunnFs0L6td08BgvWwer+Buu4fPGsQ5OzMc
lgZ0TJmXyOlIW49lc1UXnORp4sm7HS6okA7P6URbqyGbaplSsNUVTgVbi+vc8/jY
dfExt/3HxVqgrPlq9htqYgwhYvGIbBAxmeFQD8Ak/ShSiWb1FdQ+f7Lty+4mZLfN
8x4zPZ//7fD5d/PETPh9P0msF+lLFlP564+1j75wx+skFO4v1gGlBcDaeipkFzeo
zndAgpegydKSNTF4QK9iTYobTIwsYfGuS8rV21zE2saLM0CE3T90aHYB/wARAQAB
tD1DYW5vbmljYWwgQ2xvdWQgQXJjaGl2ZSBTaWduaW5nIEtleSA8ZnRwbWFzdGVy
QGNhbm9uaWNhbC5jb20+iQI3BBMBCAAhBQJQKkpYAhsDBQsJCAcDBRUKCQgLBRYC
AwEAAh4BAheAAAoJEF7bG2LsSSbqKxkQAIKtgImrk02YCDldg6tLt3b69ZK0kIVI
3Xso/zCBZbrYFmgGQEFHAa58mIgpv5GcgHHxWjpX3n4tu2RM9EneKvFjFBstTTgo
yuCgFr7iblvs/aMW4jFJAiIbmjjXWVc0CVB/JlLqzBJ/MlHdR9OWmojN9ZzoIA+i
+tWlypgUot8iIxkR6JENxit5v9dN8i6anmnWybQ6PXFMuNi6GzQ0JgZIVs37n0ks
2wh0N8hBjAKuUgqu4MPMwvNtz8FxEzyKwLNSMnjLAhzml/oje/Nj1GBB8roj5dmw
7PSul5pAqQ5KTaXzl6gJN5vMEZzO4tEoGtRpA0/GTSXIlcx/SGkUK5+lqdQIMdyS
n8bImU6V6rDSoOaI9YWHZtpv5WeUsNTdf68jZsFCRD+2+NEmIqBVm11yhmUoasC6
dYw5l9P/PBdwmFm6NBUSEwxb+ROfpL1ICaZk9Jy++6akxhY//+cYEPLin02r43Z3
o5Piqujrs1R2Hs7kX84gL5SlBzTM4Ed+ob7KVtQHTefpbO35bQllkPNqfBsC8AIC
8xvTP2S8FicYOPATEuiRWs7Kn31TWC2iwswRKEKVRmN0fdpu/UPdMikyoNu9szBZ
RxvkRAezh3WheJ6MW6Fmg9d+uTFJohZt5qHdpxYa4beuN4me8LF0TYzgfEbFT6b9
D6IyTFoT0LequQINBFAqSlgBEADmL3TEq5ejBYrA+64zo8FYvCF4gziPa5rCIJGZ
/gZXQ7pm5zek/lOe9C80mhxNWeLmrWMkMOWKCeaDMFpMBOQhZZmRdakOnH/xxO5x
+fRdOOhy+5GTRJiwkuGOV6rB9eYJ3UN9caP2hfipCMpJjlg3j/GwktjhuqcBHXhA
HMhzxEOIDE5hmpDqZ051f8LGXld9aSL8RctoYFM8sgafPVmICTCq0Wh03dr5c2JA
gEXy3ushYm/8i2WFmyldo7vbtTfx3DpmJc/EMpGKV+GxcI3/ERqSkde0kWlmfPZb
o/5+hRqSryqfQtRKnFEQgAqAhPIwXwOkjCpPnDNfrkvzVEtl2/BWP/1/SOqzXjk9
TIb1Q7MHANeFMrTCprzPLX6IdC4zLp+LpV91W2zygQJzPgWqH/Z/WFH4gXcBBqmI
8bFpMPONYc9/67AWUABo2VOCojgtQmjxuFn+uGNw9PvxJAF3yjl781PVLUw3n66d
wHRmYj4hqxNDLywhhnL/CC7KUDtBnUU/CKn/0Xgm9oz3thuxG6i3F3pQgpp7MeMn
tKhLFWRXo9Bie8z/c0NV4K5HcpbGa8QPqoDseB5WaO4yGIBOt+nizM4DLrI+v07y
Xe3Jm7zBSpYSrGarZGK68qamS3XPzMshPdoXXz33bkQrTPpivGYQVRZuzd/R6b+6
IurV+QARAQABiQIfBBgBCAAJBQJQKkpYAhsMAAoJEF7bG2LsSSbq59EP/1U3815/
yHV3cf/JeHgh6WS/Oy2kRHp/kJt3ev/l/qIxfMIpyM3u/D6siORPTUXHPm3AaZrb
w0EDWByA3jHQEzlLIbsDGZgrnl+mxFuHwC1yEuW3xrzgjtGZCJureZ/BD6xfRuRc
mvnetAZv/z98VN/oj3rvYhUi71NApqSvMExpNBGrdO6gQlI5azhOu8xGNy4OSke8
J6pAsMUXIcEwjVEIvewJuqBW/3rj3Hh14tmWjQ7shNnYBuSJwbLeUW2e8bURnfXE
TxrCmXzDmQldD5GQWCcD5WDosk/HVHBmHlqrqy0VO2nE3c73dQlNcI4jVWeC4b4Q
SpYVsFz/6Iqy5ZQkCOpQ57MCf0B6P5nF92c5f3TYPMxHf0x3DrjDbUVZytxDiZZa
XsbZzsejbbc1bSNp4hb+IWhmWoFnq/hNHXzKPHBTapObnQju+9zUlQngV0BlPT62
hOHOw3Pv7suOuzzfuOO7qpz0uAy8cFKe7kBtLSFVjBwaG5JX89mgttYW+lw9Rmsb
p9Iw4KKFHIBLOwk7s+u0LUhP3d8neBI6NfkOYKZZCm3CuvkiOeQP9/2okFjtj+29
jEL+9KQwrGNFEVNe85Un5MJfYIjgyqX3nJcwypYxidntnhMhr2VD3HL2R/4CiswB
Oa4g9309p/+af/HU1smBrOfIeRoxb8jQoHu3
=xg4S
-----END PGP PUBLIC KEY BLOCK-----

88
files/default/cluster_stats.py Executable file
View File

@@ -0,0 +1,88 @@
#!/usr/bin/env python
import os
import re
import errno
import subprocess
USING_COLLECTD=0
try:
import collectd
USING_COLLECTD=1
except:
pass
# ===============================================================================
# [2012-06-19 21:37:04] Checking ring md5sum's on 3 hosts...
# 3/3 hosts matched, 0 error[s] while checking hosts.
# ===============================================================================
def get_md5sums():
retval = 0
output = subprocess.Popen(['swift-recon', '--objmd5'], stdout=subprocess.PIPE).communicate()[0]
for line in output.split("\n"):
result = re.search("([0-9]+) error", line)
if result:
retval = result.group(1)
return retval
# ===============================================================================
# [2012-06-19 21:36:27] Checking replication times on 3 hosts...
# [Replication Times] shortest: 0.00546943346659, longest: 0.00739345153173, avg: 0.00669538444943
# ===============================================================================
def get_replication_times():
retval = {}
output = subprocess.Popen(['swift-recon', '-r'], stdout=subprocess.PIPE).communicate()[0]
for line in output.split("\n"):
result = re.search("shortest: ([0-9\.]+), longest: ([0-9\.]+), avg: ([0-9\.]+)", line)
if result:
retval['shortest'] = float(result.group(1))
retval['longest'] = float(result.group(2))
retval['average'] = float(result.group(3))
return retval
def get_all():
stats = {}
stats['md5sums'] = get_md5sums()
stats['replication_times'] = get_replication_times()
return stats
def config_callback(conf):
pass
def read_callback():
stats = get_all()
if not stats:
return
# blarg, this should be fixed
for key in stats.keys():
path = '%s' % key
value = stats[key]
if type(value) != type({}):
# must be an int
val = collectd.Values(plugin=path)
val.type = 'gauge'
val.values = [int(value)]
val.dispatch()
else:
# must be a hash
for subvalue in value.keys():
path = '%s.%s' % (key, subvalue)
val = collectd.Values(plugin=path)
val.type = 'gauge'
if type(value[subvalue]) == type("string"):
val.values = [int(value[subvalue])]
else:
val.values = value[subvalue]
val.dispatch()
if not USING_COLLECTD:
stats = get_all()
print stats
else:
collectd.register_config(config_callback)
collectd.register_read(read_callback)

View File

@@ -0,0 +1,16 @@
# Defaults for git-daemon initscript
# sourced by /etc/init.d/git-daemon
# installed at /etc/default/git-daemon by the maintainer scripts
#
# This is a POSIX shell fragment
#
GIT_DAEMON_ENABLE=true
GIT_DAEMON_USER=gitdaemon
GIT_DAEMON_DIRECTORY=/var/cache/git
GIT_DAEMON_BASE_PATH=/var/cache/git
# Additional options that are passed to the Daemon.
GIT_DAEMON_OPTIONS=""

44
files/default/rsync.init Normal file
View File

@@ -0,0 +1,44 @@
#! /bin/sh
#
# chkconfig: 2345 50 50
# description: rsync service
# source function library
. /etc/rc.d/init.d/functions
PROG='/usr/bin/rsync'
BASE=${0##*/}
# Adapt the --config parameter to point to your rsync daemon configuration
# The config file must contain following line:
# pid file = /var/run/<filename>.pid
# Where <filename> is the filename of the init script (= this file)
OPTIONS="--daemon --config=/etc/rsyncd.conf"
case "$1" in
start)
echo -n $"Starting $BASE: "
daemon --check $BASE $PROG $OPTIONS
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$BASE
echo
;;
stop)
echo -n $"Shutting down $BASE: "
killproc $BASE
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$BASE
echo
;;
restart|force-reload)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

View File

@@ -0,0 +1,11 @@
[Unit]
Description=Rsync Server
After=local-fs.target
[Service]
Type=forking
ExecStart=/usr/bin/rsync --daemon
PIDFile=/var/run/rsyncd.pid
[Install]
WantedBy=multi-user.target

98
files/default/swift_stats.py Executable file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python
import os
import errno
from resource import getpagesize
USING_COLLECTD=0
try:
import collectd
USING_COLLECTD=1
except:
pass
def get_unmounts(mountpath="/srv/node/"):
try:
candidates = [ x for x in os.listdir(mountpath) if os.path.isdir(mountpath + x) ]
except OSError as e:
if e.errno != errno.ENOENT:
raise
return 0
mounts = []
with open('/proc/mounts', 'r') as procmounts:
for line in procmounts:
_, mounted_path, _, _, _, _ = line.rstrip().split()
if mounted_path.startswith(mountpath):
mounts.append(mounted_path.split('/')[-1])
return len(set(candidates) - set(mounts))
def get_sockstats():
sockstat = {}
try:
with open('/proc/net/sockstat') as proc_sockstat:
for entry in proc_sockstat:
if entry.startswith("TCP: inuse"):
tcpstats = entry.split()
sockstat['tcp_in_use'] = int(tcpstats[2])
sockstat['orphan'] = int(tcpstats[4])
sockstat['time_wait'] = int(tcpstats[6])
sockstat['tcp_mem_allocated_bytes'] = \
int(tcpstats[10]) * getpagesize()
except OSError as e:
if e.errno != errno.ENOENT:
raise
try:
with open('/proc/net/sockstat6') as proc_sockstat6:
for entry in proc_sockstat6:
if entry.startswith("TCP6: inuse"):
sockstat['tcp6_in_use'] = int(entry.split()[2])
except IOError as e:
if e.errno != errno.ENOENT:
raise
return sockstat
def get_all():
stats = {}
stats['socket'] = get_sockstats()
stats['unmounts'] = get_unmounts()
return stats
def config_callback(conf):
pass
def read_callback():
stats = get_all()
if not stats:
return
# blarg, this should be fixed
for key in stats.keys():
path = "%s" % key
value = stats[key]
if type(value) != type({}):
# must be an int
val = collectd.Values(plugin=path)
val.type = 'gauge'
val.values = [int(value)]
val.dispatch()
else:
# must be a hash
for subvalue in value.keys():
path = '%s.%s' % (key, subvalue)
val = collectd.Values(plugin=path)
val.type = 'gauge'
val.values = [int(value[subvalue])]
val.dispatch()
if not USING_COLLECTD:
stats = get_all()
print stats
else:
collectd.register_config(config_callback)
collectd.register_read(read_callback)

34
libraries/drive_utils.rb Normal file
View File

@@ -0,0 +1,34 @@
#
# Cookbook Name:: swift
# Library:: drive_utils
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Ron Pedde <ron.pedde@rackspace.com>
#
module DriveUtils
def locate_disks(enum_expression, filter_expressions)
candidate_disks = eval(enum_expression)
candidate_expression = "candidate_disks.select{|candidate,info| (" +
filter_expressions.map{|x| "(#{x})"}.join(" and ") + ")}"
# TODO(mancdaz): fix this properly so the above works in the first place
candidate_expression.gsub!(/\[\'removable\'\] = 0/, "['removable'].to_i == 0")
drives = Hash[eval(candidate_expression)]
Chef::Log.info("Using candidate drives: #{drives.keys.join(", ")}")
drives.keys
end
end

45
libraries/ip_utils.rb Normal file
View File

@@ -0,0 +1,45 @@
#
# Cookbook Name:: swift
# Library:: ip_utils
#
# Copyright 2013, ATT Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Alan Meadows <alan.meadows@gmail.com>
#
require "ipaddr"
module IPUtils
def locate_ip_in_cidr(network, node)
Chef::Log.debug("Searching for ip within #{network} on node #{node.name}")
net = IPAddr.new(network)
node["network"]["interfaces"].each do |interface|
if interface[1].has_key?("addresses") then
interface[1]["addresses"].each do |k,v|
if v["family"] == "inet6" or (v["family"] == "inet" and v["prefixlen"] != "32") then
addr=IPAddr.new(k)
if net.include?(addr) then
return k
end
end
end
end
end
error = "Can't find address within network #{network} for node #{node.name}"
Chef::Log.error(error)
raise error
end
end

19
metadata.rb Normal file
View File

@@ -0,0 +1,19 @@
name "swift"
maintainer "ATT, Inc."
license "Apache 2.0"
description "Installs and configures Openstack Swift"
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version "1.0.16"
recipe "swift::account-server", "Installs the swift account server"
recipe "swift::object-server", "Installs the swift object server"
recipe "swift::proxy-server", "Installs the swift proxy server"
recipe "swift::container-server", "Installs the swift container server"
%w{ centos ubuntu }.each do |os|
supports os
end
depends "memcached"
depends "sysctl"
depends "statsd"
depends "apt"

264
providers/disk.rb Normal file
View File

@@ -0,0 +1,264 @@
#
# Copyright 2011, Dell
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: andi abes
#
require 'chef/mixin/shell_out'
include Chef::Mixin::ShellOut
def load_current_resource
dev_name = @new_resource.name
@current = Chef::Resource::SwiftDisk.new(dev_name)
parted_partition_parse dev_name
parts = @current.part()
if not @current.blocks
# parted didn't return anything -- empty disk.
# get size from sfdisk
sfdisk_get_size(dev_name)
end
Chef::Log.info("About to print partition table")
s = <<EOF
current state for dev #{dev_name}
Size in 1K blocks: #{@current.blocks}
EOF
Chef::Log.info("Printing partition table")
num = 0
parts.each { | p |
s << "partition " << num
s << " start/end/size (1k): #{p[:start]}/#{p[:end]}/#{p[:size]}"
s << " type: #{p[:type]}"
s << "\n"
num+=1
} if !parts.nil?
Chef::Log.info(s)
end
=begin
sample output
# sfdisk /dev/sdb -g
/dev/sdb: 261 cylinders, 255 heads, 63 sectors/track
=end
def sfdisk_get_size(dev_name)
out = %x{sfdisk #{dev_name} -s}
Chef::Log.info("updating geo using sfdisk: #{out}")
# sfdisk sees the world as 1k blocks
@current.blocks(out.to_i)
end
def parted_partition_parse(dev_name)
Chef::Log.debug("reading partition table for #{dev_name}")
=begin
Run parted to get basic info about the disk
sample output:
~# parted -m -s /dev/sda unit b print
BYT;
/dev/vda:8589934592B:virtblk:512:512:msdos:Virtio Block Device;
1:1048576B:8589934591B:8588886016B:ext3::;
=end
pipe= IO.popen("parted -m -s #{dev_name} unit b print") # this can return 1, but it's ok (if no partition table present, we'll create it)
result = pipe.readlines
parted_parse_results result
end
def parted_parse_results(input)
Chef::Log.debug("read:" + input.inspect)
input = input.to_a
part_tab = []
catch (:parse_error) do
line = input.shift # Error or BYT;
throw :parse_error if line =~ /^Error:/
line = input.shift
throw :parse_error unless line =~ /\/dev\/([^\/]+):([0-9]+)B:(.*):.*$/
dev = Regexp.last_match(1)
blocks = Regexp.last_match(2).to_i / 1024
if(@current.blocks and @current.blocks != blocks)
throw "Our disk size changed. Expecting: #{@current.blocks}, got #{blocks}"
end
@current.blocks(blocks)
input.each { |line|
# 1:1048576B:8589934591B:8588886016B:ext3::;
throw :parse_error unless line =~ /([0-9]):([0-9]+)B:([0-9]+)B:([0-9]+)B:(.*):(.*):(.*);$/
part_num = Regexp.last_match(1).to_i
part_info = {
:num => part_num,
:start => Regexp.last_match(2).to_i / 1024,
:end => Regexp.last_match(3).to_i / 1024,
:size => Regexp.last_match(4).to_i / 1024,
:type => Regexp.last_match(5),
:system => Regexp.last_match(6),
:flags => Regexp.last_match(7) }
part_tab << part_info
}
end
@current.part(part_tab)
part_tab
end
action :list do
Chef::Log.info("at some point there'll be a list")
end
####
# compare the requested partition table parameters to what exists
# if differences found - remove all current partitions, and create new ones.
# An existing partition is considered a match if:
# - it has the same serial # (1,2,3)
# - it has the same size
#
# We also want to start to partition at 1M to be correctly aligned
# even due to 4K sector size and controller stripe sizes.
#
# Plus, then parted doesn't bitch every time you run it.
action :ensure_exists do
Chef::Log.info("Entering :ensure_exists")
req = @new_resource.part
cur = @current.part
dev_name = @new_resource.name
update = false
recreate, delete_existing = false
disk_blocks = @current.blocks #1k blocks
if (cur.nil?)
recreate = true;
else
idx = 0
current_block=0
Chef::Log.info("Checking partition #{idx}")
req.each { |params|
if (cur[idx].nil?)
recreate = true
Chef::Log.info("no current #{idx}")
next
end
req_size = params[:size] # size in Mb - convert to blocks
if (req_size == :remaining)
req_size = disk_blocks - current_block
else
req_size = req_size * 1024
end
cur_size = cur[idx][:size]
cur_min, cur_max = req_size*0.9, req_size*1.1
if !(cur_size > cur_min and cur_size < cur_max)
recreate = true
end
current_block += cur[idx][:size]
Chef::Log.info("partition #{idx} #{(recreate ? 'differs' : 'is same')}: #{cur_size}/#{req_size}")
idx+=1
}
end
if !recreate
Chef::Log.info("partition table matches - not recreating")
else
### make sure to ensure that there are no mounted
### filesystems on the device
re = /^(#{Regexp.escape(dev_name)}[0-9]+)/
mounted = []
shell_out!("mount").stdout.each_line { |line|
md = re.match(line)
next unless md
mounted << md[1]
}
mounted.each { |m|
Chef::Log.info("unmounting #{m}")
shell_out!("umount #{m}")
}
# Nuke current partition table.
execute "create new partition table" do
command "parted -s -m #{dev_name} mktable gpt"
end
# create new partitions
idx = 0
req.each { | params |
start_block = 0
if idx == 0
start_block = "1M"
end
if (params[:size] == :remaining)
requested_size = "100%"
else
requested_size = "#{params[:size]}M"
end
s = "parted -m -s #{dev_name} "
s << "mkpart #{idx} #{start_block} #{requested_size}" # #{params[:type]}
Chef::Log.info("creating new partition #{idx+1} with:" + s)
execute "creating partition #{idx}" do
command s
end
idx+=1
}
update = true
end
# walk through the partitions and enforce disk format
idx=1
req.each do |params|
device = "#{dev_name}#{idx}"
Chef::Log.info("Checking #{device}")
if ::File.exist?(device)
# FIXME: check the format on the file system. This should be
# handled by a disk format provider. Maybe the xfs/btrfs/etc
# providers?
Chef::Log.info("Testing file system on #{device} for type #{params[:type]}")
case params[:type]
when "xfs"
if not system("xfs_admin -l #{device}")
Mixlib::ShellOut.new("mkfs.xfs -f -i size=512 #{device}").run_command
update = true
end
when "ext4"
if not system("tune2fs -l #{device} | grep \"Filesystem volume name:\" | awk \'{print $4}\' | grep -v \"<none>\"")
Mixlib::ShellOut.new("mkfs.ext4 #{device}").run_command
update = true
end
end
end
end
new_resource.updated_by_last_action(update)
end

168
providers/mounts.rb Normal file
View File

@@ -0,0 +1,168 @@
#
# Cookbook Name:: swift
# Provider:: mounts
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Ron Pedde <ron.pedde@rackspace.com>
#
require "chef/util/file_edit"
action :ensure_exists do
proposed_devices = @new_resource.devices
path = @new_resource.name
dev_info = {}
Chef::Log.info("IN MOUNTS")
new_resource.updated_by_last_action(false)
# walk through the devices, gathering information
proposed_devices.each do |device|
next if !::File.exists?("/dev/#{device}")
info = {}
info["device"] = device
info["ip"] = @new_resource.ip
info["format"] = @new_resource.format
info["uuid"] = `blkid /dev/#{device} -s UUID -o value`.strip
info["mountpoint"] = info["uuid"].split("-").join("")
info["mounted"] = system("mount | grep '#{path}/#{info["mountpoint"]}\'")
info["size"] = `sfdisk -s /dev/#{device}`.to_i / 1024
next if (info["uuid"] == '')
dev_info[info["uuid"]] = info
end
Chef::Log.info("Physical Inventory:")
dev_info.each do |_,v|
Chef::Log.info("Device: #{v['device']}, UUID: #{v['uuid']}, Mounted: #{v['mounted']}, Format: #{v['format']}")
end
# make sure we have a "path"
Directory(path) do
group "swift"
owner "swift"
recursive true
end.run_action(:create)
# find what should be mounted, and what IS mounted
mounts=node["filesystem"].inject({}) { |hsh, (k,v)| hsh.merge(v["mount"] => k) }
valid_mounts = dev_info.inject([]) {|ary, (_,v)| ary << "#{path}/#{v['mountpoint']}"}
mountpoints = Dir.new(path).reject {|x| x[/^\./] }.collect { |d| "#{path}/#{d}" }
inverted_mounts = dev_info.inject({}) {|hsh,(k,v)| hsh.merge({v["mountpoint"] => v.merge("uuid" => k)})}
fstabs=::File.readlines("/etc/fstab").inject({}) do |hash,line|
line = line.split("#")[0].split()
Chef::Log.info("#{line[0]} ... #{line[1]}")
hash.merge(line[1] => line[0])
end.reject { |k,v| !k or !v or !k.length or !v.length }
Chef::Log.info("Mounts: #{mounts}")
Chef::Log.info("Valid Mounts: #{valid_mounts}")
Chef::Log.info("Mountpoints: #{mountpoints}")
Chef::Log.info("Fstabs: #{fstabs}")
# mounts in /srv/node that shouldn't be there
(mounts.keys.select{|x| x and x[/^#{path}/]} - valid_mounts).each do |dev|
Chef::Log.info("Unmounting #{dev}")
system("umount #{dev}") if system("mount | grep '#{dev}'")
new_resource.updated_by_last_action(true)
end
# fstab entries that don't need to be there anymore
(fstabs.keys.select {|k| k.start_with? path} - valid_mounts).each do |dev|
fe = Chef::Util::FileEdit.new("/etc/fstab")
fe.search_file_delete_line(Regexp.new(dev.gsub("/","\/")))
fe.write_file
new_resource.updated_by_last_action(true)
end
# directories/mountpoints in /srv/node that are now useless
(mountpoints - valid_mounts).each do |mountpoint|
Chef::Log.info("rmdiring #{mountpoint}")
begin
Dir.rmdir(mountpoint)
rescue SystemCallError
Chef::Log.info("Directory #{mountpoint} appears non-empty")
end
new_resource.updated_by_last_action(true)
end
# new, unmounted devices
(valid_mounts - mounts.keys).each do |mountpoint|
info = inverted_mounts[mountpoint.gsub("#{path}/","")]
Chef::Log.info("mounting #{mountpoint} (#{info['device']})")
mount_path = "#{path}/#{info['mountpoint']}"
Directory(mount_path) do
group "swift"
owner "swift"
recursive true
end.run_action(:create)
case info['format']
when 'ext4'
mount_options = "noatime,nodiratime,nobarrier,user_xattr"
when 'xfs'
case node["platform"]
when "ubuntu","debian"
mount_options = "noatime,nodiratime,nobarrier,logbufs=8,nobootwait"
else
mount_options = "noatime,nodiratime,nobarrier,logbufs=8"
end
end
mt = Mount(mount_path) do
device info['uuid']
device_type :uuid
options mount_options
dump 0
fstype info['format']
action :nothing
end
if not fstabs.has_key?(mount_path)
# then its a brand-new drive, freshly formatted
Chef::Log.info("Mounting new device #{info['mountpoint']}")
mt.run_action(:enable)
mt.run_action(:mount)
end
new_resource.updated_by_last_action(true)
end
dev_info.reject { |k,v| v["mounted"] }.keys.each do |uuid|
dev_info[uuid]["mounted"] = system("mount | grep '#{path}/#{dev_info[uuid]["mountpoint"]}\'")
end
if @new_resource.publish_attributes and dev_info != {}
dev_info.each do |k,v|
node.set["swift"]["state"]["devs"][k] = {
:device => v["device"],
:size => v["size"],
:uuid => v["uuid"],
:mounted => v["mounted"],
:format => v["format"],
:mountpoint => v["mountpoint"],
:ip => v["ip"]
}
end
end
end

262
providers/ring_script.rb Normal file
View File

@@ -0,0 +1,262 @@
#
# Cookbook Name:: swift
# Resource:: ring_script
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Ron Pedde <ron.pedde@rackspace.com>
#
require "pp"
def generate_script
# need to load and parse the existing rings.
ports = { "object" => "6000", "container" => "6001", "account" => "6002" }
must_rebalance = false
ring_path = @new_resource.ring_path
ring_data = { :raw => {}, :parsed => {}, :in_use => {} }
disk_data = {}
dirty_cluster_reasons = []
[ "account", "container", "object" ].each do |which|
ring_data[:raw][which] = nil
if ::File.exist?("#{ring_path}/#{which}.builder")
IO.popen("su swift -c 'swift-ring-builder #{ring_path}/#{which}.builder'") do |pipe|
ring_data[:raw][which] = pipe.readlines
# Chef::Log.debug("#{ which.capitalize } Ring data: #{ring_data[:raw][which]}")
ring_data[:parsed][which] = parse_ring_output(ring_data[:raw][which])
node.set["swift"]["state"]["ring"][which] = ring_data[:parsed][which]
end
else
Chef::Log.info("#{which.capitalize} ring builder files do not exist!")
end
# collect all the ring data, and note what disks are in use. All I really
# need is a hash of device and id
ring_data[:in_use][which] ||= {}
if ring_data[:parsed][which][:hosts]
ring_data[:parsed][which][:hosts].each do |ip, dev|
dev.each do |dev_id, devhash|
ring_data[:in_use][which].store(devhash[:device], devhash[:id])
end
end
end
Chef::Log.debug("#{which.capitalize} Ring - In use: #{PP.pp(ring_data[:in_use][which],dump='')}")
# figure out what's present in the cluster
disk_data[which] = {}
disk_state,_,_ = Chef::Search::Query.new.search(:node,"chef_environment:#{node.chef_environment} AND roles:swift-#{which}-server")
# for a running track of available disks
disk_data[:available] ||= {}
disk_data[:available][which] ||= {}
disk_state.each do |swiftnode|
if swiftnode[:swift][:state] and swiftnode[:swift][:state][:devs]
swiftnode[:swift][:state][:devs].each do |k,v|
disk_data[which][v[:ip]] = disk_data[which][v[:ip]] || {}
disk_data[which][v[:ip]][k] = {}
v.keys.each { |x| disk_data[which][v[:ip]][k].store(x,v[x]) }
if swiftnode[:swift].has_key?("#{which}-zone")
disk_data[which][v[:ip]][k]["zone"]=swiftnode[:swift]["#{which}-zone"]
elsif swiftnode[:swift].has_key?("zone")
disk_data[which][v[:ip]][k]["zone"]=swiftnode[:swift]["zone"]
else
raise "Node #{swiftnode[:hostname]} has no zone assigned"
end
disk_data[:available][which][v[:mountpoint]] = v[:ip]
if not v[:mounted]
dirty_cluster_reasons << "Disk #{v[:name]} (#{v[:uuid]}) is not mounted on host #{v[:ip]} (#{swiftnode[:hostname]})"
end
end
end
end
Chef::Log.debug("#{which.capitalize} Ring - Avail: #{PP.pp(disk_data[:available][which],dump='')}")
end
# Have the raw data, now bump it together and drop the script
s = "#!/bin/bash\n\n# This script is automatically generated.\n"
s << "# Running it will likely blow up your system if you don't review it carefully.\n"
s << "# You have been warned.\n\n"
if not node["swift"]["auto_rebuild_rings"]
s << "if [ \"$1\" != \"--force\" ]; then\n"
s << " echo \"Auto rebuild rings is disabled, so you must use --force to generate rings\"\n"
s << " exit 0\n"
s << "fi\n\n"
end
# Chef::Log.debug("#{PP.pp(disk_data, dump='')}")
new_disks = {}
missing_disks = {}
new_servers = []
[ "account", "container", "object" ].each do |which|
# remove available disks that are already in the ring
new_disks[which] = disk_data[:available][which].reject{ |k,v| ring_data[:in_use][which].has_key?(k) }
# find all in-ring disks that are not in the cluster
missing_disks[which] = ring_data[:in_use][which].reject{ |k,v| disk_data[:available][which].has_key?(k) }
Chef::Log.debug("#{which.capitalize} Ring - Missing: #{PP.pp(missing_disks[which],dump='')}")
Chef::Log.debug("#{which.capitalize} Ring - New: #{PP.pp(new_disks[which],dump='')}")
s << "\n# -- #{which.capitalize} Servers --\n\n"
disk_data[which].keys.sort.each do |ip|
s << "# #{ip}\n"
disk_data[which][ip].keys.sort.each do |k|
v = disk_data[which][ip][k]
s << "# " + v.keys.sort.select{|x| ["ip", "device", "uuid"].include?(x)}.collect{|x| v[x] }.join(", ")
if new_disks[which].has_key?(v["mountpoint"])
s << " (NEW!)"
new_servers << ip unless new_servers.include?(ip)
end
s << "\n"
end
end
# for all those servers, check if they are already in the ring. If not,
# then we need to add them to the ring. For those that *were* in the
# ring, and are no longer in the ring, we need to delete those.
s << "\n"
# add the new disks
disk_data[which].keys.sort.each do |ip|
disk_data[which][ip].keys.sort.each do |uuid|
v = disk_data[which][ip][uuid]
if new_disks[which].has_key?(v['mountpoint'])
s << "swift-ring-builder #{ring_path}/#{which}.builder add z#{v['zone']}-#{v['ip']}:#{ports[which]}/#{v['mountpoint']} #{v['size']}\n"
must_rebalance = true
end
end
end
# remove the disks -- sort to ensure consistent order
missing_disks[which].keys.sort.each do |mountpoint|
diskinfo=ring_data[:parsed][which][:hosts].select{|k,v| v.has_key?(mountpoint)}.collect{|_,v| v[mountpoint]}[0]
Chef::Log.debug("Missing diskinfo: #{PP.pp(diskinfo,dump='')}")
description = Hash[diskinfo.select{|k,v| [:zone, :ip, :device].include?(k)}].collect{|k,v| "#{k}: #{v}" }.join(", ")
s << "# #{description}\n"
s << "swift-ring-builder #{ring_path}/#{which}.builder remove d#{missing_disks[which][mountpoint]}\n"
must_rebalance = true
end
s << "\n"
if(must_rebalance)
s << "swift-ring-builder #{ring_path}/#{which}.builder rebalance\n\n\n"
else
s << "# #{which.capitalize} ring has no outstanding changes!\n\n"
end
# we'll only rebalance if we meet the minimums for new adds
if node["swift"].has_key?("wait_for")
if node["swift"]["wait_for"] > new_servers.count
Chef::Log.debug("New servers, but not enough to force a rebalance")
must_rebalance = false
end
end
end
[ s, must_rebalance ]
end
# Parse the raw output of swift-ring-builder
def parse_ring_output(ring_data)
output = { :state => {} }
ring_data.each do |line|
if line =~ /build version ([0-9]+)/
output[:state][:build_version] = $1
elsif line =~ /^Devices:\s+id\s+region\s+zone\s+/
next
elsif line =~ /^Devices:\s+id\s+zone\s+/
next
elsif line =~ /^\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+)\s+(\S+)\s+([0-9.]+)\s+(\d+)\s+([-0-9.]+)\s*$/
output[:hosts] ||= {}
output[:hosts][$3] ||= {}
output[:hosts][$3][$5] = {}
output[:hosts][$3][$5][:id] = $1
output[:hosts][$3][$5][:region] = $2
output[:hosts][$3][$5][:zone] = $3
output[:hosts][$3][$5][:ip] = $4
output[:hosts][$3][$5][:port] = $5
output[:hosts][$3][$5][:device] = $6
output[:hosts][$3][$5][:weight] = $7
output[:hosts][$3][$5][:partitions] = $8
output[:hosts][$3][$5][:balance] = $9
elsif line =~ /^\s+(\d+)\s+(\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+)\s+(\S+)\s+([0-9.]+)\s+(\d+)\s+([-0-9.]+)\s*$/
output[:hosts] ||= {}
output[:hosts][$3] ||= {}
output[:hosts][$3][$5] = {}
output[:hosts][$3][$5][:id] = $1
output[:hosts][$3][$5][:zone] = $2
output[:hosts][$3][$5][:ip] = $3
output[:hosts][$3][$5][:port] = $4
output[:hosts][$3][$5][:device] = $5
output[:hosts][$3][$5][:weight] = $6
output[:hosts][$3][$5][:partitions] = $7
output[:hosts][$3][$5][:balance] = $8
elsif line =~ /(\d+) partitions, (\d+\.\d+) replicas, (\d+) regions, (\d+) zones, (\d+) devices, (\d+\.\d+) balance$/
output[:state][:partitions] = $1
output[:state][:replicas] = $2
output[:state][:regions] = $3
output[:state][:zones] = $4
output[:state][:devices] = $5
output[:state][:balance] = $6
elsif line =~ /(\d+) partitions, (\d+) replicas, (\d+) zones, (\d+) devices, (\d+\.\d+) balance$/
output[:state][:partitions] = $1
output[:state][:replicas] = $2
output[:state][:zones] = $3
output[:state][:devices] = $4
output[:state][:balance] = $5
elsif line =~ /^The minimum number of hours before a partition can be reassigned is (\d+)$/
output[:state][:min_part_hours] = $1
else
raise "Cannot parse ring builder output for #{line}"
end
end
output
end
action :ensure_exists do
Chef::Log.debug("Ensuring #{new_resource.name}")
new_resource.updated_by_last_action(false)
s,must_update = generate_script
script_file = File new_resource.name do
owner new_resource.owner
group new_resource.group
mode new_resource.mode
content s
end
script_file.run_action(:create)
new_resource.updated_by_last_action(must_update)
end

96
recipes/account-server.rb Normal file
View File

@@ -0,0 +1,96 @@
#
# Cookbook Name:: swift
# Recipe:: account-server
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "swift::common"
include_recipe "swift::storage-common"
include_recipe "swift::disks"
platform_options = node["swift"]["platform"]
platform_options["account_packages"].each.each do |pkg|
package pkg do
action :install
options platform_options["override_options"] # retain configs
end
end
# epel/f-17 missing init scripts for the non-major services.
# https://bugzilla.redhat.com/show_bug.cgi?id=807170
%w{auditor reaper replicator}.each do |svc|
template "/etc/systemd/system/openstack-swift-account-#{svc}.service" do
owner "root"
group "root"
mode "0644"
source "simple-systemd-config.erb"
variables({ :description => "OpenStack Object Storage (swift) - " +
"Account #{svc.capitalize}",
:user => "swift",
:exec => "/usr/bin/swift-account-#{svc} " +
"/etc/swift/account-server.conf"
})
only_if { platform?(%w{fedora}) }
end
end
# TODO(breu): track against upstream epel packages to determine if this
# is still necessary
# https://bugzilla.redhat.com/show_bug.cgi?id=807170
%w{auditor reaper replicator}.each do |svc|
template "/etc/init.d/openstack-swift-account-#{svc}" do
owner "root"
group "root"
mode "0755"
source "simple-redhat-init-config.erb"
variables({ :description => "OpenStack Object Storage (swift) - " +
"Account #{svc.capitalize}",
:exec => "account-#{svc}"
})
only_if { platform?(%w{redhat centos}) }
end
end
%w{swift-account swift-account-auditor swift-account-reaper swift-account-replicator}.each do |svc|
service_name = platform_options["service_prefix"] + svc + platform_options["service_suffix"]
service svc do
service_name service_name
provider platform_options["service_provider"]
supports :status => true, :restart => true
action [:enable, :start]
only_if "[ -e /etc/swift/account-server.conf ] && [ -e /etc/swift/account.ring.gz ]"
end
end
# retrieve bind information from node
bind_ip = node["swift"]["network"]["bind_ip"]
bind_port = node["swift"]["network"]["bind_port"]
# create account server template
template "/etc/swift/account-server.conf" do
source "account-server.conf.erb"
owner "swift"
group "swift"
mode "0600"
variables("bind_ip" => node["swift"]["network"]["account-bind-ip"],
"bind_port" => node["swift"]["network"]["account-bind-port"])
notifies :restart, "service[swift-account]", :immediately
notifies :restart, "service[swift-account-auditor]", :immediately
notifies :restart, "service[swift-account-reaper]", :immediately
notifies :restart, "service[swift-account-replicator]", :immediately
end

110
recipes/common.rb Normal file
View File

@@ -0,0 +1,110 @@
#
# Cookbook Name:: swift
# Recipe:: swift-common
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class Chef::Recipe
include DriveUtils
end
include_recipe 'sysctl::default'
# optionally statsd daemon for stats collection
if node["swift"]["enable_statistics"]
include_recipe 'statsd::server'
end
platform_options = node["swift"]["platform"]
# update repository if requested with the ubuntu cloud
case node["platform"]
when "ubuntu"
Chef::Log.info("Creating apt repository for http://ubuntu-cloud.archive.canonical.com/ubuntu")
Chef::Log.info("chefspec: #{node['lsb']['codename']}-updates/#{node['swift']['release']}")
apt_repository "ubuntu_cloud" do
uri "http://ubuntu-cloud.archive.canonical.com/ubuntu"
distribution "#{node['lsb']['codename']}-updates/#{node['swift']['release']}"
components ["main"]
key "5EDB1B62EC4926EA"
action :add
end
end
platform_options["swift_packages"].each do |pkg|
package pkg do
action :install
end
end
directory "/etc/swift" do
action :create
owner "swift"
group "swift"
mode "0700"
only_if "/usr/bin/id swift"
end
# determine hash
if node['swift']['swift_secret_databag_name'].nil?
swifthash = node['swift']['swift_hash']
else
swift_secrets = Chef::EncryptedDataBagItem.load "secrets", node['swift']['swift_secret_databag_name']
swifthash = swift_secrets['swift_hash']
end
file "/etc/swift/swift.conf" do
action :create
owner "swift"
group "swift"
mode "0700"
content "[swift-hash]\nswift_hash_path_suffix=#{swifthash}\n"
only_if "/usr/bin/id swift"
end
# need a swift user
user "swift" do
shell "/bin/bash"
action :modify
only_if "/usr/bin/id swift"
end
package "git" do
action :install
end
# drop a ring puller script
# TODO: make this smarter
git_builder_ip = node["swift"]["git_builder_ip"]
template "/etc/swift/pull-rings.sh" do
source "pull-rings.sh.erb"
owner "swift"
group "swift"
mode "0700"
variables({
:builder_ip => git_builder_ip,
:service_prefix => platform_options["service_prefix"]
})
only_if "/usr/bin/id swift"
end
execute "/etc/swift/pull-rings.sh" do
cwd "/etc/swift"
only_if "[ -x /etc/swift/pull-rings.sh ]"
end

View File

@@ -0,0 +1,93 @@
#
# Cookbook Name:: swift
# Recipe:: swift-container-server
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "swift::common"
include_recipe "swift::storage-common"
include_recipe "swift::disks"
platform_options = node["swift"]["platform"]
platform_options["container_packages"].each do |pkg|
package pkg do
action :install
options platform_options["override_options"]
end
end
# epel/f-17 missing init scripts for the non-major services.
# https://bugzilla.redhat.com/show_bug.cgi?id=807170
%w{auditor updater replicator}.each do |svc|
template "/etc/systemd/system/openstack-swift-container-#{svc}.service" do
owner "root"
group "root"
mode "0644"
source "simple-systemd-config.erb"
variables({ :description => "OpenStack Object Storage (swift) - " +
"Container #{svc.capitalize}",
:user => "swift",
:exec => "/usr/bin/swift-container-#{svc} " +
"/etc/swift/container-server.conf"
})
only_if { platform?(%w{fedora}) }
end
end
# TODO(breu): track against upstream epel packages to determine if this
# is still necessary
# https://bugzilla.redhat.com/show_bug.cgi?id=807170
%w{auditor updater replicator}.each do |svc|
template "/etc/init.d/openstack-swift-container-#{svc}" do
owner "root"
group "root"
mode "0755"
source "simple-redhat-init-config.erb"
variables({ :description => "OpenStack Object Storage (swift) - " +
"Container #{svc.capitalize}",
:exec => "container-#{svc}"
})
only_if { platform?(%w{redhat centos}) }
end
end
%w{swift-container swift-container-auditor swift-container-replicator swift-container-updater}.each do |svc|
service_name=platform_options["service_prefix"] + svc + platform_options["service_suffix"]
service svc do
service_name service_name
provider platform_options["service_provider"]
supports :status => true, :restart => true
action [:enable, :start]
only_if "[ -e /etc/swift/container-server.conf ] && [ -e /etc/swift/container.ring.gz ]"
end
end
template "/etc/swift/container-server.conf" do
source "container-server.conf.erb"
owner "swift"
group "swift"
mode "0600"
variables("bind_ip" => node["swift"]["network"]["container-bind-ip"],
"bind_port" => node["swift"]["network"]["container-bind-port"])
notifies :restart, "service[swift-container]", :immediately
notifies :restart, "service[swift-container-replicator]", :immediately
notifies :restart, "service[swift-container-updater]", :immediately
notifies :restart, "service[swift-container-auditor]", :immediately
end

66
recipes/disks.rb Normal file
View File

@@ -0,0 +1,66 @@
#
# Cookbook Name:: swift
# Recipe:: disks
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Ron Pedde <ron.pedde@rackspace.com>
# Inspired by: Andi Abes @ Dell
class Chef::Recipe
include IPUtils
end
platform_options = node["swift"]["platform"]
package "xfsprogs" do
action :install
only_if { platform?(%w{ubuntu debian fedora centos}) }
end
%w(parted util-linux).each do |pkg|
package pkg do
action :install
end
end
disk_enum_expr = node["swift"]["disk_enum_expr"]
disk_test_filter = node["swift"]["disk_test_filter"]
disks = locate_disks(disk_enum_expr, disk_test_filter)
disks.each do |disk|
swift_disk "/dev/#{disk}" do
part [{:type => platform_options["disk_format"] , :size => :remaining}]
action :ensure_exists
end
end
# FIXME: "#{x}1" is only really valid for {v,s,h}dx. Doesn't
# work for loop or probably for hp-style /dev/cciss/c0d0p1x0t0g0m1whatever
#
# additionally, there is an implicit assumption that bind ports
# for all object/container/account services are on the same net
disk_ip = locate_ip_in_cidr(node["swift"]["network"]["object-cidr"], node)
swift_mounts "/srv/node" do
action :ensure_exists
publish_attributes "swift/state/devs"
devices disks.collect { |x| "#{x}1" }
ip disk_ip
format platform_options["disk_format"]
end

View File

@@ -0,0 +1,55 @@
#
# Cookbook Name:: swift
# Recipe:: management-server
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "swift::common"
# FIXME: This should probably be a role (ring-builder?), so you don't end up
# with multiple repos!
include_recipe "swift::ring-repo"
platform_options = node["swift"]["platform"]
if node["swift"]["authmode"] == "swauth"
platform_options["swauth_packages"].each.each do |pkg|
package pkg do
action :install
options platform_options["override_options"] # retain configs
end
end
end
# determine where to find dispersion login information
if node['swift']['swift_secret_databag_name'].nil?
auth_user = node["swift"]["dispersion"]["auth_user"]
auth_key = node["swift"]["dispersion"]["auth_key"]
else
swift_secrets = Chef::EncryptedDataBagItem.load "secrets", node['swift']['swift_secret_databag_name']
auth_user = swift_secrets['dispersion_auth_user']
auth_key = swift_secrets['dispersion_auth_key']
end
template "/etc/swift/dispersion.conf" do
source "dispersion.conf.erb"
owner "swift"
group "swift"
mode "0600"
variables("auth_url" => node["swift"]["auth_url"],
"auth_user" => auth_user,
"auth_key" => auth_key)
end

20
recipes/memcached.rb Normal file
View File

@@ -0,0 +1,20 @@
#
# Cookbook Name:: swift
# Recipe:: memcached
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "memcached"

101
recipes/object-server.rb Normal file
View File

@@ -0,0 +1,101 @@
#
# Cookbook Name:: swift
# Recipe:: swift-object-server
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "swift::common"
include_recipe "swift::storage-common"
include_recipe "swift::disks"
platform_options = node["swift"]["platform"]
platform_options["object_packages"].each do |pkg|
package pkg do
action :install
options platform_options["override_options"] # retain configs
end
end
# epel/f-17 missing init scripts for the non-major services.
# https://bugzilla.redhat.com/show_bug.cgi?id=807170
%w{auditor updater replicator}.each do |svc|
template "/etc/systemd/system/openstack-swift-object-#{svc}.service" do
owner "root"
group "root"
mode "0644"
source "simple-systemd-config.erb"
variables({ :description => "OpenStack Object Storage (swift) - " +
"Object #{svc.capitalize}",
:user => "swift",
:exec => "/usr/bin/swift-object-#{svc} " +
"/etc/swift/object-server.conf"
})
only_if { platform?(%w{fedora})}
end
end
# TODO(breu): track against upstream epel packages to determine if this
# is still necessary
# https://bugzilla.redhat.com/show_bug.cgi?id=807170
%w{auditor updater replicator}.each do |svc|
template "/etc/init.d/openstack-swift-object-#{svc}" do
owner "root"
group "root"
mode "0755"
source "simple-redhat-init-config.erb"
variables({ :description => "OpenStack Object Storage (swift) - " +
"Object #{svc.capitalize}",
:exec => "object-#{svc}"
})
only_if { platform?(%w{redhat centos}) }
end
end
%w{swift-object swift-object-replicator swift-object-auditor swift-object-updater}.each do |svc|
service_name=platform_options["service_prefix"] + svc + platform_options["service_suffix"]
service svc do
service_name service_name
provider platform_options["service_provider"]
# the default ubuntu provider uses invoke-rc.d, which apparently is
# status-illy broken in ubuntu
supports :status => false, :restart => true
action [:enable, :start]
only_if "[ -e /etc/swift/object-server.conf ] && [ -e /etc/swift/object.ring.gz ]"
end
end
template "/etc/swift/object-server.conf" do
source "object-server.conf.erb"
owner "swift"
group "swift"
mode "0600"
variables("bind_ip" => node["swift"]["network"]["object-bind-ip"],
"bind_port" => node["swift"]["network"]["object-bind-port"])
notifies :restart, "service[swift-object]", :immediately
notifies :restart, "service[swift-object-replicator]", :immediately
notifies :restart, "service[swift-object-updater]", :immediately
notifies :restart, "service[swift-object-auditor]", :immediately
end
cron "swift-recon" do
minute "*/5"
command "swift-recon-cron /etc/swift/object-server.conf"
user "swift"
end

116
recipes/proxy-server.rb Normal file
View File

@@ -0,0 +1,116 @@
#
# Cookbook Name:: swift
# Recipe:: proxy-server
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include_recipe "swift::common"
include_recipe "swift::memcached"
class Chef::Recipe
include IPUtils
end
if node.run_list.expand(node.chef_environment).recipes.include?("swift::setup")
Chef::Log.info("I ran the swift::setup so I will use my own swift passwords")
else
setup = search(:node, "chef_environment:#{node.chef_environment} AND roles:swift-setup")
if setup.length == 0
Chef::Application.fatal! "You must have run the swift::setup recipe (on this or another node) before running the swift::proxy recipe on this node"
elsif setup.length == 1
Chef::Log.info "Found swift::setup node: #{setup[0].name}"
node.set["swift"]["service_pass"] = setup[0]["swift"]["service_pass"]
elsif setup.length >1
Chef::Application.fatal! "You have multiple nodes in your environment that have run swift-setup, and that is not allowed"
end
end
platform_options = node["swift"]["platform"]
# install platform-specific packages
platform_options["proxy_packages"].each do |pkg|
package pkg do
action :install
options platform_options["override_options"]
end
end
package "python-swauth" do
action :install
only_if { node["swift"]["authmode"] == "swauth" }
end
package "python-swift-informant" do
action :install
only_if { node["swift"]["use_informant"] }
end
package "python-keystone" do
action :install
only_if { node["swift"]["authmode"] == "keystone" }
end
directory "/var/cache/swift" do
owner "swift"
group "swift"
mode 00700
end
swift_proxy_service = platform_options["service_prefix"] + "swift-proxy" + platform_options["service_suffix"]
service "swift-proxy" do
# openstack-swift-proxy.service on fedora-17, swift-proxy on ubuntu
service_name swift_proxy_service
provider platform_options["service_provider"]
supports :status => true, :restart => true
action [ :enable, :start ]
only_if "[ -e /etc/swift/proxy-server.conf ] && [ -e /etc/swift/object.ring.gz ]"
end
# use localhost when using chef solo otherwise, include all memcache
# servers from all known proxies
if Chef::Config[:solo]
memcache_servers = [ "127.0.0.1:11211" ]
else
memcache_servers = []
proxy_nodes = search(:node, "chef_environment:#{node.chef_environment} AND roles:swift-proxy-server")
proxy_nodes.each do |proxy|
proxy_ip = locate_ip_in_cidr(node["swift"]["network"]["proxy-cidr"], proxy)
next if not proxy_ip # skip nil ips so we dont break the config
server_str = "#{proxy_ip}:11211"
memcache_servers << server_str unless memcache_servers.include?(server_str)
end
end
# determine authkey to use
if node['swift']['swift_secret_databag_name'].nil?
authkey = node['swift']['authkey']
else
swift_secrets = Chef::EncryptedDataBagItem.load "secrets", node['swift']['swift_secret_databag_name']
authkey = swift_secrets['swift_authkey']
end
# create proxy config file
template "/etc/swift/proxy-server.conf" do
source "proxy-server.conf.erb"
owner "swift"
group "swift"
mode "0600"
variables("authmode" => node["swift"]["authmode"],
"bind_host" => node["swift"]["network"]["proxy-bind-ip"],
"bind_port" => node["swift"]["network"]["proxy-bind-port"],
"authkey" => authkey,
"memcache_servers" => memcache_servers)
notifies :restart, "service[swift-proxy]", :immediately
end

183
recipes/ring-repo.rb Normal file
View File

@@ -0,0 +1,183 @@
#
# Cookbook Name:: swift
# Recipe:: ring-repo
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This recipe creates a git ring repository on the management node
# for purposes of ring synchronization
#
platform_options = node["swift"]["platform"]
ring_options = node["swift"]["ring"]
platform_options["git_packages"].each do |pkg|
package pkg do
action :install
end
end
service "xinetd" do
supports :status => false, :restart => true
action [ :enable, :start ]
only_if { platform?(%w{centos redhat fedora}) }
end
execute "create empty git repo" do
cwd "/tmp"
umask 022
command "mkdir $$; cd $$; git init; echo \"backups\" \> .gitignore; git add .gitignore; git commit -m 'initial commit' --author='chef <chef@openstack>'; git push file:///#{platform_options["git_dir"]}/rings master"
user "swift"
action :nothing
end
directory "git-directory" do
path "#{platform_options["git_dir"]}/rings"
owner "swift"
group "swift"
mode "0755"
recursive true
action :create
end
execute "initialize git repo" do
cwd "#{platform_options["git_dir"]}/rings"
umask 022
user "swift"
command "git init --bare && touch git-daemon-export-ok"
creates "#{platform_options["git_dir"]}/rings/config"
action :run
notifies :run, "execute[create empty git repo]", :immediately
end
# epel/f-17 missing systemd-ified inits
# https://bugzilla.redhat.com/show_bug.cgi?id=737183
template "/etc/systemd/system/git.service" do
owner "root"
group "root"
mode "0644"
source "simple-systemd-config.erb"
variables({ :description => "Git daemon service",
:user => "nobody",
:exec => "/usr/libexec/git-core/git-daemon " +
"--base-path=/var/lib/git --export-all --user-path=public_git" +
"--syslog --verbose"
})
only_if { platform?(%w{fedora}) }
end
case node["platform"]
when "centos","redhat","fedora"
service "git-daemon" do
service_name platform_options["git_service"]
action [ :enable ]
end
when "ubuntu","debian"
service "git-daemon" do
service_name platform_options["git_service"]
action [ :enable, :start ]
end
end
cookbook_file "/etc/default/git-daemon" do
owner "root"
group "root"
mode "644"
source "git-daemon.default"
action :create
notifies :restart, "service[git-daemon]", :immediately
not_if { platform?(%w{fedora centos redhat}) }
end
directory "/etc/swift/ring-workspace" do
owner "swift"
group "swift"
mode "0755"
action :create
end
execute "checkout-rings" do
cwd "/etc/swift/ring-workspace"
command "git clone file://#{platform_options["git_dir"]}/rings"
user "swift"
creates "/etc/swift/ring-workspace/rings"
end
[ "account", "container", "object" ].each do |ring_type|
part_power = ring_options["part_power"]
min_part_hours = ring_options["min_part_hours"]
replicas = ring_options["replicas"]
Chef::Log.info("Building initial ring #{ring_type} using part_power=#{part_power}, " +
"min_part_hours=#{min_part_hours}, replicas=#{replicas}")
execute "add #{ring_type}.builder" do
cwd "/etc/swift/ring-workspace/rings"
command "git add #{ring_type}.builder && git commit -m 'initial ring builders' --author='chef <chef@openstack>'"
user "swift"
action :nothing
end
execute "create #{ring_type} builder" do
cwd "/etc/swift/ring-workspace/rings"
command "swift-ring-builder #{ring_type}.builder create #{part_power} #{replicas} #{min_part_hours}"
user "swift"
creates "/etc/swift/ring-workspace/rings/#{ring_type}.builder"
notifies :run, "execute[add #{ring_type}.builder]", :immediate
end
end
bash "rebuild-rings" do
action :nothing
cwd "/etc/swift/ring-workspace/rings"
user "swift"
code <<-EOF
set -x
# Should this be done?
git reset --hard
git clean -df
../generate-rings.sh
for d in object account container; do swift-ring-builder ${d}.builder; done
add=0
if test -n "$(find . -maxdepth 1 -name '*gz' -print -quit)"
then
git add *builder *gz
add=1
else
git add *builder
add=1
fi
if [ $add -ne 0 ]
then
git commit -m "Autobuild of rings on $(date +%Y%m%d) by Chef" --author="chef <chef@openstack>"
git push
fi
EOF
end
swift_ring_script "/etc/swift/ring-workspace/generate-rings.sh" do
owner "swift"
group "swift"
mode "0700"
ring_path "/etc/swift/ring-workspace/rings"
action :ensure_exists
notifies :run, "bash[rebuild-rings]", :immediate
end

85
recipes/rsync.rb Normal file
View File

@@ -0,0 +1,85 @@
#
# Cookbook Name:: swift
# Recipe:: rsync
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
platform_options = node["swift"]["platform"]
platform_options["rsync_packages"].each do |pkg|
package pkg do
action :install
options platform_options["override_options"]
end
end
# epel/f-17 broken: https://bugzilla.redhat.com/show_bug.cgi?id=737710
cookbook_file "/etc/systemd/system/rsync.service" do
owner "root"
group "root"
mode "0644"
source "rsync.service"
action :create
only_if { platform?(%w{fedora}) }
end
# rhel based systems install rsync and run it with rsync. We don't want to do that
cookbook_file "/etc/init.d/rsyncd" do
owner "root"
group "root"
mode "0755"
source "rsync.init"
action :create
only_if { platform?(%w{centos redhat scientific}) }
end
# FIXME: chicken and egg
case node["platform"]
when "centos","redhat","fedora"
# enable rsyncd
rsync_servicename = "rsyncd"
service "rsyncd" do
supports :status => false, :restart => true, :start => true, :stop => true
action [ :enable, :start ]
only_if "[ -f /etc/rsyncd.conf ]"
end
# disable rsync (the one via xinetd)
service "rsync" do
supports :status => false, :restart => false, :start => false, :stop => false
action [ :disable ]
end
when "ubuntu","debian"
rsync_servicename = "rsync"
service "rsync" do
supports :status => false, :restart => true
action [ :enable, :start ]
only_if "[ -f /etc/rsyncd.conf ]"
end
end
template "/etc/rsyncd.conf" do
source "rsyncd.conf.erb"
mode "0644"
notifies :restart, "service[#{rsync_servicename}]", :immediately
end
execute "enable rsync" do
command "sed -i 's/RSYNC_ENABLE=false/RSYNC_ENABLE=true/' /etc/default/rsync"
only_if "grep -q 'RSYNC_ENABLE=false' /etc/default/rsync"
notifies :restart, "service[rsync]", :immediately
action :run
not_if { platform?(%w{fedora centos redhat scientific}) }
end

58
recipes/setup.rb Normal file
View File

@@ -0,0 +1,58 @@
#
# Cookbook Name:: swift
# Recipe:: setup
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include_recipe "swift::common"
# make sure we die if there are multiple swift-setups
if Chef::Config[:solo]
Chef::Application.fatal! "This recipe uses search. Chef Solo does not support search."
else
setup_role_count = search(:node, "chef_environment:#{node.chef_environment} AND roles:swift-setup").length
if setup_role_count > 1
Chef::Application.fatal! "You can only have one node with the swift-setup role"
end
end
unless node["swift"]["service_pass"]
Chef::Log.info("Running swift setup - setting swift passwords")
end
platform_options = node["swift"]["platform"]
# install platform-specific packages
platform_options["proxy_packages"].each do |pkg|
package pkg do
action :upgrade
options platform_options["override_options"]
end
end
package "python-swauth" do
action :upgrade
only_if { node["swift"]["authmode"] == "swauth" }
end
package "python-swift-informant" do
action :upgrade
only_if { node["swift"]["use_informant"] }
end
package "python-keystone" do
action :upgrade
only_if { node["swift"]["authmode"] == "keystone" }
end

41
recipes/storage-common.rb Normal file
View File

@@ -0,0 +1,41 @@
#
# Cookbook Name:: swift
# Recipe:: storage-common
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include_recipe "swift::rsync"
template "/etc/swift/drive-audit.conf" do
source "drive-audit.conf.erb"
owner "swift"
group "swift"
mode "0600"
end
cron "drive-audit" do
hour node["swift"]["audit_hour"]
minute "10"
command "swift-drive-audit /etc/swift/drive-audit.conf"
end
directory "/var/cache/swift" do
group "swift"
owner "swift"
recursive true
action :create
mode 00700
end

44
resources/disk.rb Normal file
View File

@@ -0,0 +1,44 @@
#
# Copyright 2011, Dell
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: andi abes
#
=begin
Ensure that a disk's partition table matches expectations.
Sample use:
swift_disk "/dev/sdb" do
part(
{[:type => "xfs", :size =>swift_disk::ONE_GIG*4 ],
[:type => "xfs", :size =>swift_disk::remaining})
action :ensure_exists
end
=end
actions :ensure_exists
def initialize(*args)
super
@action = :ensure_exists
end
attribute :name, :kind_of => String
attribute :size, :kind_of => Integer
attribute :blocks, :kind_of => Integer
attribute :device, :kind_of => String
attribute :part, :kind_of => Array
attribute :status, :kind_of => Symbol

71
resources/mounts.rb Normal file
View File

@@ -0,0 +1,71 @@
#
# Cookbook Name:: swift
# Resource:: mounts
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Ron Pedde <ron.pedde@rackspace.com>
#
=begin
Ensure that swift mounts are strongly enforced. This
will ensure specified drives are mounted, and unspecified
drives are not mounted. In addition, if there is a stale
mountpoint (from disk failure, maybe?), then that mountpoint
will try to be unmounted
Sample use:
swift_mounts "/srv/node" do
devices [ "sdb1", "sdc1" ]
action :ensure_exists
ip "10.1.1.1"
end
It will force mounts based on fs uuid (mangled to remove
dashes) and return a structure that describes the disks
mounted.
As this is expected to be consumed for the purposes of
swift, the ip address should be the address that gets
embedded into the ring (i.e. the listen port of the storage server)
Example return structure:
{ "2a9452c5-d929-43d9-9631-4340ace45279": {
"device": "sdb1",
"ip": "10.1.1.1",
"mounted": "true",
"mountpoint": "2a9452c5d92943d996314340ace45279",
"size": 1022 (in 1k increments)
"uuid": "2a9452c5-d929-43d9-9631-4340ace45279"
},
...
}
=end
actions :ensure_exists
def initialize(*args)
super
@action = :ensure_exists
end
attribute :name, :kind_of => String
attribute :devices, :kind_of => Array
attribute :ip, :kind_of => String, :default => "127.0.0.1"
attribute :publish_attributes, :kind_of => String, :default => nil
attribute :format, :kind_of => String, :default => "xfs"

44
resources/ring_script.rb Normal file
View File

@@ -0,0 +1,44 @@
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Author: Ron Pedde <ron.pedde@rackspace.com>
#
=begin
Build a proposed ring-building script
Sample use:
swift_ring_script "/tmp/build-rings.sh" do
owner "root"
group "swift"
mode "0700"
ring_path "/etc/swift/ring-workspace"
action :ensure_exists
end
=end
actions :ensure_exists
def initialize(*args)
super
@action = :ensure_exists
end
attribute :name, :kind_of => String
attribute :owner, :kind_of => String, :default => "root"
attribute :group, :kind_of => String, :default => "root"
attribute :mode, :kind_of => String, :default => "0600"
attribute :ring_path, :kind_of => String, :default => "/etc/swift"

23
run_tests.bash Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# A script to run tests locally before committing.
set -e
COOKBOOK=$(awk '/^name/ {print $NF}' metadata.rb |tr -d \"\')
if [ -z $COOKBOOK ]; then
echo "Cookbook name not defined in metadata.rb"
    exit 1
fi
BUNDLE_PATH=${BUNDLE_PATH:-.bundle}
BERKSHELF_PATH=${BERKSHELF_PATH:-.cookbooks}
echo "Using bundle path: $BUNDLE_PATH"
echo "Using berkshelf path: $BERKSHELF_PATH"
bundle install --path=${BUNDLE_PATH}
bundle exec berks install --path=${BERKSHELF_PATH}
bundle exec rspec ${BERKSHELF_PATH}/${COOKBOOK}
bundle exec foodcritic -f any -t ~FC003 -t ~FC023 ${BERKSHELF_PATH}/${COOKBOOK}

67
spec/account_spec.rb Normal file
View File

@@ -0,0 +1,67 @@
require 'spec_helper'
describe 'swift::account-server' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['lsb']['code'] = 'precise'
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['network']['account-bind-ip'] = '10.0.0.1'
@node.set['swift']['network']['account-bind-port'] = '8080'
@node.set['swift']['disk_enum_expr'] = "[{ 'sda' => {}}]"
@node.set['swift']['disk_test_filter'] = [ "candidate =~ /sd[^a]/ or candidate =~ /hd[^a]/ or candidate =~ /vd[^a]/ or candidate =~ /xvd[^a]/",
"File.exist?('/dev/' + candidate)",
"not system('/sbin/parted /dev/' + candidate + ' -s print | grep linux-swap')",
"not info.has_key?('removable') or info['removable'] == 0.to_s"]
# mock out an interface on the storage node
@node.set["network"] = MOCK_NODE_NETWORK_DATA['network']
@chef_run.converge "swift::account-server"
end
it "installs swift account packages" do
expect(@chef_run).to install_package "swift-account"
end
it "installs swiftclient package" do
expect(@chef_run).to install_package "python-swiftclient"
end
it "starts swift account services on boot" do
%w{swift-account swift-account-auditor swift-account-reaper swift-account-replicator}.each do |svc|
expect(@chef_run).to set_service_to_start_on_boot svc
end
end
describe "/etc/swift/account-server.conf" do
before do
@file = @chef_run.template "/etc/swift/account-server.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "600"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

92
spec/common_spec.rb Normal file
View File

@@ -0,0 +1,92 @@
require 'spec_helper'
describe 'swift::common' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['platform_family'] = "debian"
@node.set['lsb']['codename'] = "precise"
@node.set['swift']['release'] = "folsom"
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['git_builder_ip'] = '10.0.0.10'
# TODO: this does not work
# ::Chef::Log.should_receive(:info).with("chefspec: precise-updates/folsom")
@chef_run.converge "swift::common"
end
it 'should set syctl paramaters' do
# N.B. we could examine chef log
pending "TODO: right now theres no way to do lwrp and test for this"
end
it 'installs git package for ring management' do
expect(@chef_run).to install_package "git"
end
describe "/etc/swift" do
before do
@file = @chef_run.directory "/etc/swift"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "700"
end
end
describe "/etc/swift/swift.conf" do
before do
@file = @chef_run.file "/etc/swift/swift.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "700"
end
end
describe "/etc/swift/pull-rings.sh" do
before do
@file = @chef_run.template "/etc/swift/pull-rings.sh"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "700"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

63
spec/container_spec.rb Normal file
View File

@@ -0,0 +1,63 @@
require 'spec_helper'
describe 'swift::container-server' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['lsb']['code'] = 'precise'
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['network']['container-bind-ip'] = '10.0.0.1'
@node.set['swift']['network']['container-bind-port'] = '8080'
@node.set['swift']['disk_enum_expr'] = "[{ 'sda' => {}}]"
@node.set['swift']['disk_test_filter'] = [ "candidate =~ /sd[^a]/ or candidate =~ /hd[^a]/ or candidate =~ /vd[^a]/ or candidate =~ /xvd[^a]/",
"File.exist?('/dev/' + candidate)",
"not system('/sbin/parted /dev/' + candidate + ' -s print | grep linux-swap')",
"not info.has_key?('removable') or info['removable'] == 0.to_s"]
# mock out an interface on the storage node
@node.set["network"] = MOCK_NODE_NETWORK_DATA['network']
@chef_run.converge "swift::container-server"
end
it "installs swift container packages" do
expect(@chef_run).to install_package "swift-container"
end
it "starts swift container services on boot" do
%w{swift-container swift-container-auditor swift-container-replicator swift-container-updater}.each do |svc|
expect(@chef_run).to set_service_to_start_on_boot svc
end
end
describe "/etc/swift/container-server.conf" do
before do
@file = @chef_run.template "/etc/swift/container-server.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "600"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

43
spec/disks_spec.rb Normal file
View File

@@ -0,0 +1,43 @@
require 'spec_helper'
describe 'swift::disks' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['platform_family'] = "debian"
@node.set['lsb']['codename'] = "precise"
@node.set['swift']['release'] = "folsom"
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['git_builder_ip'] = '10.0.0.10'
@node.set['swift']['disk_enum_expr'] = "[{ 'sda' => {}}]"
@node.set['swift']['disk_test_filter'] = [ "candidate =~ /sd[^a]/ or candidate =~ /hd[^a]/ or candidate =~ /vd[^a]/ or candidate =~ /xvd[^a]/",
"File.exist?('/dev/' + candidate)",
"not system('/sbin/parted /dev/' + candidate + ' -s print | grep linux-swap')",
"not info.has_key?('removable') or info['removable'] == 0.to_s"]
# mock out an interface on the storage node
@node.set["network"] = MOCK_NODE_NETWORK_DATA['network']
@chef_run.converge "swift::disks"
end
it 'installs xfs progs package' do
expect(@chef_run).to install_package "xfsprogs"
end
it 'installs parted package' do
expect(@chef_run).to install_package "parted"
end
end
end

47
spec/management_spec.rb Normal file
View File

@@ -0,0 +1,47 @@
require 'spec_helper'
describe 'swift::management-server' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['lsb']['code'] = 'precise'
@node.set['swift']['authmode'] = 'swauth'
@chef_run.converge "swift::management-server"
end
it "installs swift swauth package" do
expect(@chef_run).to install_package "swauth"
end
describe "/etc/swift/dispersion.conf" do
before do
@file = @chef_run.template "/etc/swift/dispersion.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "600"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

71
spec/object_spec.rb Normal file
View File

@@ -0,0 +1,71 @@
require 'spec_helper'
describe 'swift::object-server' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['lsb']['code'] = 'precise'
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['network']['object-bind-ip'] = '10.0.0.1'
@node.set['swift']['network']['object-bind-port'] = '8080'
@node.set['swift']['disk_enum_expr'] = "[{ 'sda' => {}}]"
@node.set['swift']['disk_test_filter'] = [ "candidate =~ /sd[^a]/ or candidate =~ /hd[^a]/ or candidate =~ /vd[^a]/ or candidate =~ /xvd[^a]/",
"File.exist?('/dev/' + candidate)",
"not system('/sbin/parted /dev/' + candidate + ' -s print | grep linux-swap')",
"not info.has_key?('removable') or info['removable'] == 0.to_s"]
# mock out an interface on the storage node
@node.set["network"] = MOCK_NODE_NETWORK_DATA['network']
@chef_run.converge "swift::object-server"
end
it "installs swift packages" do
expect(@chef_run).to install_package "swift-object"
end
it "starts swift object services on boot" do
%w{swift-object swift-object-replicator swift-object-auditor swift-object-updater}.each do |svc|
expect(@chef_run).to set_service_to_start_on_boot svc
end
end
describe "/var/spool/crontab/root" do
it "template contents" do
pending "TODO: check for recon script"
end
end
describe "/etc/swift/object-server.conf" do
before do
@file = @chef_run.template "/etc/swift/object-server.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "600"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

60
spec/proxy_spec.rb Normal file
View File

@@ -0,0 +1,60 @@
require 'spec_helper'
describe 'swift::proxy-server' do
#--------------
# UBUNTU
#--------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['lsb']['code'] = 'precise'
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['network']['proxy-bind-ip'] = '10.0.0.1'
@node.set['swift']['network']['proxy-bind-port'] = '8080'
@chef_run.converge "swift::proxy-server"
end
it "installs memcache python packages" do
expect(@chef_run).to install_package "python-memcache"
end
it "installs swift packages" do
expect(@chef_run).to install_package "swift-proxy"
end
it "installs swauth package if swauth is selected" do
expect(@chef_run).to install_package "python-swauth"
end
it "starts swift-proxy on boot" do
expect(@chef_run).to set_service_to_start_on_boot "swift-proxy"
end
describe "/etc/swift/proxy-server.conf" do
before do
@file = @chef_run.template "/etc/swift/proxy-server.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "600"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

43
spec/ring-repo_spec.rb Normal file
View File

@@ -0,0 +1,43 @@
require 'spec_helper'
describe 'swift::ring-repo' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['platform_family'] = "debian"
@node.set['lsb']['codename'] = "precise"
@node.set['swift']['release'] = "folsom"
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['git_builder_ip'] = '10.0.0.10'
@chef_run.converge "swift::ring-repo"
end
it 'installs git package for ring management' do
expect(@chef_run).to install_package "git-daemon-sysvinit"
end
it "starts xinetd services on boot" do
%w{xinetd}.each do |svc|
expect(@chef_run).to set_service_to_start_on_boot svc
end
end
describe "/etc/swift/ring-workspace/generate-rings.sh" do
it "gets installed" do
pending "TODO: determine some way to ensure this LWRP script gets created"
end
end
end
end

51
spec/rsync_spec.rb Normal file
View File

@@ -0,0 +1,51 @@
require 'spec_helper'
describe 'swift::rsync' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['platform_family'] = "debian"
@node.set['lsb']['codename'] = "precise"
@node.set['swift']['release'] = "folsom"
@node.set['swift']['authmode'] = 'swauth'
@node.set['swift']['git_builder_ip'] = '10.0.0.10'
@chef_run.converge "swift::rsync"
end
it 'installs git package for ring management' do
expect(@chef_run).to install_package "rsync"
end
it "starts rsync service on boot" do
%w{rsync}.each do |svc|
expect(@chef_run).to set_service_to_start_on_boot svc
end
end
describe "/etc/rsyncd.conf" do
before do
@file = @chef_run.template "/etc/rsyncd.conf"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "644"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

49
spec/spec_helper.rb Normal file
View File

@@ -0,0 +1,49 @@
require "chefspec"
::LOG_LEVEL = :fatal
::REDHAT_OPTS = {
:platform => "redhat",
:log_level => ::LOG_LEVEL
}
::UBUNTU_OPTS = {
:platform => "ubuntu",
:version => "12.04",
:log_level => ::LOG_LEVEL
}
MOCK_NODE_NETWORK_DATA =
{
"ipaddress" => '10.0.0.2',
"fqdn" => 'localhost.localdomain',
"hostname" => 'localhost',
"network" => {
"default_interface" => "eth0",
"interfaces" => {
"eth0" => {
"addresses" => {
"fe80::a00:27ff:feca:ab08" => {"scope" => "Link", "prefixlen" => "64", "family" => "inet6"},
"10.0.0.2" => {"netmask" => "255.255.255.0", "broadcast" => "10.0.0.255", "family" => "inet"},
"08:00:27:CA:AB:08" => {"family" => "lladdr"}
},
},
"lo" => {
"addresses" => {
"::1" => {"scope" => "Node", "prefixlen" => "128", "family" => "inet6"},
"127.0.0.1" => {"netmask" => "255.0.0.0", "family" => "inet"}
},
},
},
}
}
def swift_stubs
# create mock cluster
n = Chef::Node.new()
n.name('manager')
n.default_attrs = {
"swift" => {
"service_pass" => "foobar"
}
}
Chef::Recipe.any_instance.stub(:search).with(:node, 'chef_environment:_default AND roles:swift-setup').and_return([n])
end

View File

@@ -0,0 +1,58 @@
require 'spec_helper'
describe 'swift::storage-common' do
#-------------------
# UBUNTU
#-------------------
describe "ubuntu" do
before do
swift_stubs
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set['lsb']['code'] = 'precise'
@node.set['swift']['authmode'] = 'swauth'
@chef_run.converge "swift::storage-common"
end
describe "/var/cache/swift" do
before do
@file = @chef_run.directory "/var/cache/swift"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "700"
end
end
describe "/etc/swift/drive-audit.conf" do
before do
@file = @chef_run.template "/etc/swift/drive-audit.conf"
end
it "has proper owner" do
expect(@file).to be_owned_by "swift", "swift"
end
it "has proper modes" do
expect(sprintf("%o", @file.mode)).to eq "600"
end
it "template contents" do
pending "TODO: implement"
end
end
end
end

View File

@@ -0,0 +1,78 @@
[DEFAULT]
# bind_ip = 0.0.0.0
# bind_port = 6002
# backlog = 4096
# workers = 1
# user = swift
# swift_dir = /etc/swift
# devices = /srv/node
# mount_check = true
# You can specify default log routing here if you want:
# log_name = swift
# log_facility = LOG_LOCAL0
# log_level = INFO
#####
bind_ip = <%= @bind_ip %>
bind_port = <%= @bind_port %>
workers = 10
<% if node[:swift][:enable_statistics] -%>
log_statsd_host = localhost
log_statsd_port = 8125
log_statsd_default_sample_rate = 1
log_statsd_metric_prefix = openstack.swift.<%= node[:hostname] %>
<% end %>
[pipeline:main]
pipeline = account-server
[app:account-server]
use = egg:swift#account
# You can override the default log routing for this app here:
# set log_name = account-server
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_requests = True
[account-replicator]
# You can override the default log routing for this app here (don't use set!):
# log_name = account-replicator
# log_facility = LOG_LOCAL0
# log_level = INFO
# vm_test_mode = no
# log_facility = LOG_LOCAL0
# log_level = INFO
# per_diff = 1000
# max_diffs = 100
# concurrency = 8
# interval = 30
# How long without an error before a node's error count is reset. This will
# also be how long before a node is reenabled after suppression is triggered.
# error_suppression_interval = 60
# How many errors can accumulate before a node is temporarily ignored.
# error_suppression_limit = 10
# node_timeout = 10
# conn_timeout = 0.5
# The replicator also performs reclamation
# reclaim_age = 86400
[account-auditor]
# You can override the default log routing for this app here (don't use set!):
# log_name = account-auditor
# log_facility = LOG_LOCAL0
# log_level = INFO
# Will audit, at most, 1 account per device per interval
# interval = 1800
# log_facility = LOG_LOCAL0
# log_level = INFO
[account-reaper]
# You can override the default log routing for this app here (don't use set!):
# log_name = account-reaper
# log_facility = LOG_LOCAL0
# log_level = INFO
# concurrency = 25
# interval = 3600
# node_timeout = 10
# conn_timeout = 0.5
# log_facility = LOG_LOCAL0
# log_level = INFO

View File

@@ -0,0 +1,88 @@
[DEFAULT]
# bind_ip = 0.0.0.0
# bind_port = 6001
# backlog = 4096
# workers = 1
# user = swift
# swift_dir = /etc/swift
# devices = /srv/node
# mount_check = true
# This is a comma separated list of hosts allowed in the X-Container-Sync-To
# field for containers.
# allowed_sync_hosts = 127.0.0.1
# You can specify default log routing here if you want:
# log_name = swift
# log_facility = LOG_LOCAL0
# log_level = INFO
####
bind_ip = <%= @bind_ip %>
bind_port = <%= @bind_port %>
workers = 10
<% if node[:swift][:enable_statistics] -%>
log_statsd_host = localhost
log_statsd_port = 8125
log_statsd_default_sample_rate = 1
log_statsd_metric_prefix = openstack.swift.<%= node[:hostname] %>
<% end %>
[pipeline:main]
pipeline = container-server
[app:container-server]
use = egg:swift#container
# You can override the default log routing for this app here:
# set log_name = container-server
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_requests = True
# node_timeout = 3
# conn_timeout = 0.5
[container-replicator]
# You can override the default log routing for this app here (don't use set!):
# log_name = container-replicator
# log_facility = LOG_LOCAL0
# log_level = INFO
# vm_test_mode = no
# per_diff = 1000
# max_diffs = 100
# concurrency = 8
# interval = 30
# node_timeout = 10
# conn_timeout = 0.5
# The replicator also performs reclamation
# reclaim_age = 604800
[container-updater]
# You can override the default log routing for this app here (don't use set!):
# log_name = container-updater
# log_facility = LOG_LOCAL0
# log_level = INFO
# interval = 300
# concurrency = 4
# node_timeout = 3
# conn_timeout = 0.5
# slowdown will sleep that amount between containers
# slowdown = 0.01
# Seconds to suppress updating an account that has generated an error
# account_suppression_time = 60
[container-auditor]
# You can override the default log routing for this app here (don't use set!):
# log_name = container-auditor
# log_facility = LOG_LOCAL0
# log_level = INFO
# Will audit, at most, 1 container per device per interval
# interval = 1800
[container-sync]
# You can override the default log routing for this app here (don't use set!):
# log_name = container-sync
# log_facility = LOG_LOCAL0
# log_level = INFO
# If you need to use an HTTP Proxy, set it here; defaults to no proxy.
# sync_proxy = http://127.0.0.1:8888
# Will sync, at most, each container once per interval
# interval = 300
# Maximum amount of time to spend syncing each container per pass
# container_time = 60

View File

@@ -0,0 +1,13 @@
[dispersion]
auth_url = <%= @auth_url %>
auth_user = <%= @auth_user %>
auth_key = <%= @auth_key %>
auth_version = 1.0
endpoint_type = publicURL
swift_dir = /etc/swift
dispersion_coverage = 5
retries = 5
concurrency = 25
container_report = yes
object_report = yes
dump_json = no

View File

@@ -0,0 +1,5 @@
[drive-audit]
log_facility = LOG_LOCAL0
log_level = INFO
device_dir = /srv/node
minutes = 60

View File

@@ -0,0 +1,104 @@
[DEFAULT]
# bind_ip = 0.0.0.0
# bind_port = 6000
# backlog = 4096
# workers = 1
# user = swift
# swift_dir = /etc/swift
# devices = /srv/node
# mount_check = true
# expiring_objects_container_divisor = 86400
# You can specify default log routing here if you want:
# log_name = swift
# log_facility = LOG_LOCAL0
# log_level = INFO
#####
bind_ip = <%= @bind_ip %>
bind_port = <%= @bind_port %>
workers = 10
<% if node[:swift][:enable_statistics] -%>
log_statsd_host = localhost
log_statsd_port = 8125
log_statsd_default_sample_rate = 1
log_statsd_metric_prefix = openstack.swift.<%= node[:hostname] %>
<% end %>
[pipeline:main]
pipeline = recon object-server
[app:object-server]
use = egg:swift#object
# You can override the default log routing for this app here:
# set log_name = object-server
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_requests = True
# node_timeout = 3
# conn_timeout = 0.5
# network_chunk_size = 65536
# disk_chunk_size = 65536
# max_upload_time = 86400
# slow = 1
# on PUTs, sync data every n MB
# mb_per_sync = 512
# Comma separated list of headers that can be set in metadata on an object.
# This list is in addition to X-Object-Meta-* headers and cannot include
# Content-Type, etag, Content-Length, or deleted
# allowed_headers = Content-Disposition, Content-Encoding, X-Delete-At, X-Object-Manifest
[filter:recon]
use = egg:swift#recon
recon_cache_path = /var/cache/swift
[object-replicator]
# You can override the default log routing for this app here (don't use set!):
# log_name = object-replicator
# log_facility = LOG_LOCAL0
# log_level = INFO
# vm_test_mode = no
# daemonize = on
# run_pause = 30
# concurrency = 1
# stats_interval = 300
# max duration of a partition rsync
# rsync_timeout = 900
# passed to rsync for io op timeout
# rsync_io_timeout = 30
# max duration of an http request
# http_timeout = 60
# attempts to kill all workers if nothing replicates for lockup_timeout seconds
# lockup_timeout = 1800
# The replicator also performs reclamation
# reclaim_age = 604800
# enable logging of replication stats for recon
# recon_enable = no
# recon_cache_path = /var/cache/swift
#####
recon_enable = yes
recon_cache_path = /var/cache/swift
concurrency = 2
[object-updater]
# You can override the default log routing for this app here (don't use set!):
# log_name = object-updater
# log_facility = LOG_LOCAL0
# log_level = INFO
# interval = 300
# concurrency = 1
# node_timeout = 10
# conn_timeout = 0.5
# slowdown will sleep that amount between objects
# slowdown = 0.01
concurrency = 2
[object-auditor]
# You can override the default log routing for this app here (don't use set!):
# log_name = object-auditor
# log_facility = LOG_LOCAL0
# log_level = INFO
# files_per_second = 20
# bytes_per_second = 10000000
# log_time = 3600
# zero_byte_files_per_second = 50

View File

@@ -0,0 +1,262 @@
<%
case @authmode
when "keystone"
pipeline="authtoken keystoneauth"
when "swauth"
pipeline="swauth"
end
account_management=false
if node[:roles].include?("swift-management-server") and node[:swift][:authmode] == "swauth" then
account_management="true"
end
-%>
# This file is managed by chef. Do not edit it.
#
# Cluster info:
# Auth mode: <%= node[:swift][:authmode] %>
# Management server: <%= node[:roles].include?("swift-management-server") %>
# Account management enabled: <%= account_management %>
# Auth pipeline: <%= pipeline %>
[DEFAULT]
# bind_ip = 0.0.0.0
# bind_port = 8080
# backlog = 4096
# swift_dir = /etc/swift
# workers = 1
# user = swift
# cert_file = /etc/swift/proxy.crt
# key_file = /etc/swift/proxy.key
# expiring_objects_container_divisor = 86400
# You can specify default log routing here if you want:
# log_name = swift
# log_facility = LOG_LOCAL0
# log_level = INFO
######
workers = <%= [ node[:cpu][:total] - 1, 1 ].max %>
bind_ip = <%= @bind_host %>
bind_port = <%= @bind_port %>
<% if node[:swift][:enable_statistics] -%>
log_statsd_host = localhost
log_statsd_port = 8125
log_statsd_default_sample_rate = 1
log_statsd_metric_prefix = openstack.swift.<%= node[:hostname] %>
<% end %>
[pipeline:main]
pipeline = catch_errors healthcheck cache ratelimit <%= pipeline %> proxy-logging proxy-server
[app:proxy-server]
use = egg:swift#proxy
# You can override the default log routing for this app here:
# set log_name = proxy-server
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set access_log_name = proxy-server
# set access_log_facility = LOG_LOCAL0
# set access_log_level = INFO
# set log_headers = False
# recheck_account_existence = 60
# recheck_container_existence = 60
# object_chunk_size = 8192
# client_chunk_size = 8192
# node_timeout = 10
# client_timeout = 60
# conn_timeout = 0.5
# How long without an error before a node's error count is reset. This will
# also be how long before a node is reenabled after suppression is triggered.
# error_suppression_interval = 60
# How many errors can accumulate before a node is temporarily ignored.
# error_suppression_limit = 10
# If set to 'true' any authorized user may create and delete accounts; if
# 'false' no one, even authorized, can.
# allow_account_management = false
# Set object_post_as_copy = false to turn on fast posts where only the metadata
# changes are stored anew and the original data file is kept in place. This
# makes for quicker posts; but since the container metadata isn't updated in
# this mode, features like container sync won't be able to sync posts.
# object_post_as_copy = true
# If set to 'true' authorized accounts that do not yet exist within the Swift
# cluster will be automatically created.
# account_autocreate = false
######
#
# N.B. ideally allow_account_management would only be set on the
# management server, but swauth will delete using the cluster url
# and not the local url
# allow_account_managemnet = <%= account_management %>
allow_account_management = true
<% if @authmode == "keystone" -%>
account_autocreate = true
<% end %>
<% if @authmode == "swauth" -%>
[filter:swauth]
use = egg:swauth#swauth
# set log_name = swauth
# super_admin_key = <secret_key>
######
<% if account_management -%>
super_admin_key = <%= @authkey %>
default_swift_cluster = local#<%= node[:swift][:swift_url] %>#<%= node[:swift][:swauth_url] %>
<% else %>
default_swift_cluster = local#<%= node[:swift][:swift_url] %>
<% end %>
<% end %>
[filter:healthcheck]
use = egg:swift#healthcheck
# You can override the default log routing for this filter here:
# set log_name = healthcheck
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_headers = False
[filter:cache]
use = egg:swift#memcache
# You can override the default log routing for this filter here:
# set log_name = cache
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_headers = False
# Default for memcache_servers is to try to read the property from
# memcache.conf (see memcache.conf-sample) or lacking that file, it will
# default to the value below. You can specify multiple servers separated with
# commas, as in: 10.1.2.3:11211,10.1.2.4:11211
# memcache_servers = 127.0.0.1:11211
#####
memcache_servers = <%= @memcache_servers.join(",") %>
[filter:ratelimit]
use = egg:swift#ratelimit
# You can override the default log routing for this filter here:
# set log_name = ratelimit
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_headers = False
# clock_accuracy should represent how accurate the proxy servers' system clocks
# are with each other. 1000 means that all the proxies' clock are accurate to
# each other within 1 millisecond. No ratelimit should be higher than the
# clock accuracy.
# clock_accuracy = 1000
# max_sleep_time_seconds = 60
# log_sleep_time_seconds of 0 means disabled
# log_sleep_time_seconds = 0
# allows for slow rates (e.g. running up to 5 sec's behind) to catch up.
# rate_buffer_seconds = 5
# account_ratelimit of 0 means disabled
# account_ratelimit = 0
# these are comma separated lists of account names
# account_whitelist = a,b
# account_blacklist = c,d
# with container_limit_x = r
# for containers of size x limit requests per second to r. The container
# rate will be linearly interpolated from the values given. With the values
# below, a container of size 5 will get a rate of 75.
# container_ratelimit_0 = 100
# container_ratelimit_10 = 50
# container_ratelimit_50 = 20
[filter:domain_remap]
use = egg:swift#domain_remap
# You can override the default log routing for this filter here:
# set log_name = domain_remap
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_headers = False
# storage_domain = example.com
# path_root = v1
# reseller_prefixes = AUTH
[filter:catch_errors]
use = egg:swift#catch_errors
# You can override the default log routing for this filter here:
# set log_name = catch_errors
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_headers = False
[filter:cname_lookup]
# Note: this middleware requires python-dnspython
use = egg:swift#cname_lookup
# You can override the default log routing for this filter here:
# set log_name = cname_lookup
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set log_headers = False
# storage_domain = example.com
# lookup_depth = 1
# Note: Put staticweb just after your auth filter(s) in the pipeline
[filter:staticweb]
use = egg:swift#staticweb
# Seconds to cache container x-container-meta-web-* header values.
# cache_timeout = 300
# You can override the default log routing for this filter here:
# set log_name = staticweb
# set log_facility = LOG_LOCAL0
# set log_level = INFO
# set access_log_name = staticweb
# set access_log_facility = LOG_LOCAL0
# set access_log_level = INFO
# set log_headers = False
# Note: Put tempurl just before your auth filter(s) in the pipeline
[filter:tempurl]
use = egg:swift#tempurl
#
# The headers to remove from incoming requests. Simply a whitespace delimited
# list of header names and names can optionally end with '*' to indicate a
# prefix match. incoming_allow_headers is a list of exceptions to these
# removals.
# incoming_remove_headers = x-timestamp
#
# The headers allowed as exceptions to incoming_remove_headers. Simply a
# whitespace delimited list of header names and names can optionally end with
# '*' to indicate a prefix match.
# incoming_allow_headers =
#
# The headers to remove from outgoing responses. Simply a whitespace delimited
# list of header names and names can optionally end with '*' to indicate a
# prefix match. outgoing_allow_headers is a list of exceptions to these
# removals.
# outgoing_remove_headers = x-object-meta-*
#
# The headers allowed as exceptions to outgoing_remove_headers. Simply a
# whitespace delimited list of header names and names can optionally end with
# '*' to indicate a prefix match.
# outgoing_allow_headers = x-object-meta-public-*
# Note: Put formpost just before your auth filter(s) in the pipeline
[filter:formpost]
use = egg:swift#formpost
[filter:keystoneauth]
operator_roles = Member,admin
use = egg:swift#keystoneauth
[filter:proxy-logging]
use = egg:swift#proxy_logging
# access_log_name = proxy
# access_log_facility = LOG_LOCAL0
# access_log_level = INFO
# access_log_address = /dev/log
# If set, access_log_udp_host will override access_log_address
# access_log_udp_host =
# access_log_udp_port = 514
# You can use log_statsd_* from [DEFAULT] or override them here:
# access_log_statsd_host = localhost
# access_log_statsd_port = 8125
# access_log_statsd_default_sample_rate = 1
# access_log_statsd_metric_prefix =
# access_log_headers = False
# What HTTP methods are allowed for StatsD logging (comma-sep); request methods
# not in this list will have "BAD_METHOD" for the <verb> portion of the metric.
# log_statsd_valid_http_methods = GET,HEAD,POST,PUT,DELETE,COPY

View File

@@ -0,0 +1,29 @@
#!/bin/bash
# this has to be run as root to restart the services...
if [ ! -d /etc/swift/rings ] || [ ! -e /etc/swift/rings/.git/config ]; then
rm -rf /etc/swift/rings
git clone git://<%= @builder_ip %>/rings /etc/swift/rings
fi
cd /etc/swift/rings
git reset --hard
git clean -df
git pull
[ -e /etc/swift/rings ] && chown -R swift: /etc/swift/rings
for d in object account container; do
if [ -e /etc/swift/rings/${d}.ring.gz ]; then
if [ ! -e ../${d}.ring.gz ] || [ "$(md5sum ${d}.ring.gz | cut -f1 -d' ')" != "$(md5sum ../${d}.ring.gz | cut -f1 -d' ')" ]; then
cp ${d}.ring.gz ../${d}.ring.new
chown swift: ../${d}.ring.new
mv ../${d}.ring.new ../${d}.ring.gz
if [ -e /etc/swift/${d}-server.conf ]; then
service <%= @service_prefix %>swift-${d}-replicator restart
fi
fi
fi
done

View File

@@ -0,0 +1,24 @@
uid = swift
gid = swift
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
address = 0.0.0.0
[account]
max connections = 10
path = /srv/node/
read only = false
lock file = /var/lock/account.lock
[container]
max connections = 10
path = /srv/node/
read only = false
lock file = /var/lock/container.lock
[object]
max connections = 10
path = /srv/node/
read only = false
lock file = /var/lock/object.lock

View File

@@ -0,0 +1,77 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: <%= @exec %>
# Required-Start: $remote_fs
# Required-Stop: $remote_fs
# Default-Stop: 0 1 6
# Description: <%= @description %>
### END INIT INFO
# chkconfig: - 98 02
. /etc/rc.d/init.d/functions
name="<%= @exec =%>"
[ -e "/etc/sysconfig/openstack-swift-$name" ] && . "/etc/sysconfig/openstack-swift-$name"
lockfile="/var/lock/subsys/openstack-swift-$name"
start() {
swift-init "$name" start
retval=$?
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
swift-init "$name" stop
retval=$?
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
stop
start
}
rh_status() {
swift-init "$name" status
retval=$?
return $retval
}
rh_status_q() {
rh_status &> /dev/null
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart)
$1
;;
reload)
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart}"
exit 2
esac
exit $?

View File

@@ -0,0 +1,11 @@
[Unit]
Description=<%= @description %>
After=syslog.target network.target
[Service]
Type=simple
User=<%= @user %>
ExecStart=<%= @exec %>
[Install]
WantedBy=multi-user.target