chef/cookbooks/swift/recipes/disks.rb
#
# 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
#
f = package "xfsprogs" do
action :nothing
end
f.run_action(:install)
def get_uuid(disk)
uuid = nil
IO.popen("blkid -c /dev/null -s UUID -o value #{disk}"){ |f|
uuid=f.read.strip
}
return uuid if uuid && (uuid != "")
nil
end
unclaimed_disks = BarclampLibrary::Barclamp::Inventory::Disk.unclaimed(node)
to_use_disks = []
unclaimed_disks.each do |k|
to_use_disks << k
end
claimed_disks = BarclampLibrary::Barclamp::Inventory::Disk.claimed(node, "Swift")
claimed_disks.each do |k|
to_use_disks << k
end
node[:swift] ||= Mash.new
node[:swift][:devs] ||= Mash.new
found_disks=[]
wait_for_format = false
to_use_disks.each do |d|
k = d.device
disk_name = k.gsub(/!/, "/") # "cciss!c0d0"
partition_suffix = "1" # by default, will use format first partition.
partition_suffix = "p1" if k =~ /cciss/
target_dev = "/dev/#{disk_name}"
target_dev_part = "/dev/#{disk_name}#{partition_suffix}"
disk = Hash.new
disk[:device] = target_dev_part
disk[:device_disk_name] = k
disk[:device_disk_partition] = k + partition_suffix
disk[:uuid] = get_uuid(target_dev_part)
# Test to see if there is a partition table on the disk.
# If not, create a shiny new GPT partition table for the disk.
if ::Kernel.system("parted -s -m #{target_dev} print 1 2>&1 | grep -q '^Error:'")
Chef::Log.info("Swift - Creating partition table on #{target_dev}")
::Kernel.system("parted -s #{target_dev} -- unit s mklabel gpt mkpart primary ext2 2048s -1M")
::Kernel.system("partprobe #{target_dev}")
sleep 3
::Kernel.system("dd if=/dev/zero of=#{target_dev_part} bs=1024 count=65")
disk[:uuid] = nil
end
# Test to see if there is a file system, and create one if there is not.
if disk[:uuid] && ! node[:swift][:devs][disk[:uuid]]
# If there is already a file system and we don't already know about it,
# then it belongs to someone else. Print a log entry and skip it.
Chef::Log.info("Swift - drive #{target_dev_part} alreay exists, and we don't own it.")
Chef::Log.info("Please zero out the first and last meg of the drive if you want to use it for Swift")
next
elsif disk[:uuid].nil?
# No filesystem. Format that bad boy and claim it as our own.
d.claim("Swift")
Chef::Log.info("Swift - formatting #{target_dev_part}")
::Kernel.exec "mkfs.xfs -i size=1024 -f #{target_dev_part}" unless ::Process.fork
disk[:state] = "Fresh"
wait_for_format = true
found_disks << disk.dup
else
Chef::Log.info("Swift - #{target_dev_part} already known and used by Swift.")
end
end
if found_disks.empty? && claimed_disks.empty?
message = "No disk available for swift"
Chef::Log.fatal(message)
raise message
end
if wait_for_format
Chef::Log.info("Swift -- Waiting on all disks to finish formatting")
::Process.waitall
end
dirty = false
# If we have freshly-claimed disks, add them and save them.
found_disks.each do |disk|
# Disk was freshly created. Grab its UUID and create a mount point.
disk[:uuid] = get_uuid(disk[:device])
unless disk[:uuid].nil?
# notify udev that there is a new UUID
::Kernel.system("echo change > /sys/block/#{disk[:device_disk_name]}/#{disk[:device_disk_partition]}/uevent")
::Kernel.system("/sbin/udevadm settle")
disk[:state] = "Operational"
disk[:name] = disk[:uuid].delete("-")
Chef::Log.info("Adding new disk #{disk[:device]} with UUID #{disk[:uuid]} to the Swift config")
node.set[:swift][:devs][disk[:uuid]] = disk.dup
dirty = true
end
end
# Now clean up list of claimed disks and remove those that do not
# exist anymore.
node[:swift][:devs].each do |uuid,disk|
if disk[:state] == "Operational"
Chef::Log.info("Checking disk #{disk[:device]}")
# Verify that UUID still matches
current_uuid = get_uuid(disk[:device])
if current_uuid != disk[:uuid]
Chef::Log.warn("Disk #{disk[:device]} with UUID #{current_uuid} not matching expected UUID #{disk[:uuid]}")
Chef::Log.info("Setting disk #{disk[:device]} to Stale")
disk[:state] = "UUID_Stale"
node.set[:swift][:devs][disk[:uuid]] = disk.dup
dirty = true
end
end
end
# Save that data
node.save if dirty
# Take appropriate action for each disk.
node[:swift][:devs].each do |uuid,disk|
# We always want a mountpoint created.
directory "/srv/node/#{disk[:name]}" do
group node[:swift][:group]
owner node[:swift][:user]
recursive true
action :create
end
case disk[:state]
when "Operational"
# We want to use this disk.
mount "/srv/node/#{disk[:name]}" do
device disk[:uuid]
device_type :uuid
options "noatime,nodiratime,nobarrier,nofail,logbufs=8"
dump 0
pass 0
fstype "xfs"
action [:mount, :enable]
end
else
# We don't want this disk right now. Maybe it is about to die.
mount "/srv/node/#{disk[:name]}" do
device disk[:uuid]
device_type :uuid
options "noatime,nodiratime,nobarrier,logbufs=8"
dump 0
pass 0
fstype "xfs"
action [:umount, :disable]
end
end
end