cookbooks/aws-parallelcluster-environment/resources/manage_ebs.rb (121 lines of code) (raw):
# frozen_string_literal: true
# Copyright:: 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
# with the License. A copy of the License is located at http://aws.amazon.com/apache2.0/
# or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and
# limitations under the License.
provides :manage_ebs
unified_mode true
property :shared_dir_array, Array, required: %i(mount export unmount unexport)
property :vol_array, Array, required: %i(mount unmount)
property :mode, String, default: "1777"
default_action :mount
action :mount do
return if on_docker?
shared_dir_array = new_resource.shared_dir_array.dup
vol_array = new_resource.vol_array.dup
# Mount each volume
dev_path = [] # device labels
vol_array.each_with_index do |volumeid, index|
dev_path[index] = "/dev/disk/by-ebs-volumeid/#{volumeid}"
volume "attach volume #{index}" do
volume_id volumeid
action :attach
end
# Setup disk, will be formatted xfs if empty
ruby_block "setup_disk_#{index}" do
block do
dev_path[index] = prepare_disk(dev_path[index])
end
action :nothing
subscribes :run, "volume[attach volume #{index}]", :immediately
end
volume "mount volume #{index}" do
action :mount
mode new_resource.mode
shared_dir shared_dir_array[index]
device(lazy_uuid(dev_path[index]))
fstype(DelayedEvaluator.new { node['cluster']['volume_fs_type'] })
device_type :uuid
options "_netdev"
retries 10
retry_delay 6
end
end
end
action :export do
return if on_docker?
new_resource.shared_dir_array.dup.each do |dir|
volume "export volume #{dir}" do
shared_dir dir
action :export
end
end
end
action :unmount do
return if on_docker?
new_resource.vol_array.each_with_index do |volumeid, index|
volume "unmount volume #{index}" do
shared_dir new_resource.shared_dir_array[index]
action :unmount
end
volume "detach volume #{index}" do
volume_id volumeid
action :detach
end
end
end
action :unexport do
return if on_docker?
new_resource.shared_dir_array.dup.each do |dir|
volume "unexport volume #{dir}" do
shared_dir dir
action :unexport
end
end
end
def lazy_uuid(device)
DelayedEvaluator.new { get_uuid(device) }
end
#
# Gets the uuid of a device
#
def get_uuid(device)
Chef::Log.info("Getting uuid for device: #{device}")
match = shell_out("blkid -c /dev/null #{device}").stdout.match(/\sUUID="(.*?)"/)
match = '' if match.nil?
Chef::Log.info("uuid for device: #{device} is #{match[1]}")
match[1]
end
#
# Checks if device is partitioned; if yes returns pt type
#
def get_pt_type(device)
match = shell_out("blkid -c /dev/null #{device}").stdout.match(/\sPTTYPE="(.*?)"/)
match = '' if match.nil?
Chef::Log.info("Partition type for device #{device}: #{match[1]}")
match[1]
end
#
# Check if block device has a filesystem
#
def get_fs_type(device)
match = shell_out("blkid -c /dev/null #{device}").stdout.match(/\sTYPE="(.*?)"/)
match = '' if match.nil?
Chef::Log.info("File system type for device #{device}: #{match[1]}")
match[1]
end
#
# Format a block device using the EXT4 file system if it is not already
# formatted.
#
def setup_disk(path)
dev = ::File.readlink(path)
full_path = ::File.absolute_path(dev, ::File.dirname(path))
fs_type = get_fs_type(full_path)
if fs_type.nil?
shell_out("mkfs.ext4 #{full_path}")
fs_type = 'ext4'
end
fs_type
end
#
# Returns the first partition of a device, provided via sym link
#
def get_1st_partition(device)
# Resolves the real device name (ex. /dev/sdg)
Chef::Log.info("Getting 1st partition for device: #{device}")
partition = "/dev/#{shell_out("lsblk -ln -o Name #{device}|awk 'NR==2'").stdout.strip}"
Chef::Log.info("1st partition for device: #{device} is: #{partition}")
partition
end
def prepare_disk(device_path)
pt_type = get_pt_type(device_path)
if pt_type.nil?
Chef::Log.info("device #{device_path} not partitioned, mounting directly")
fs_type = setup_disk(device_path)
else
# Partitioned device, mount 1st partition
Chef::Log.info("device #{device_path} partitioned, mounting first partition")
partition_dev = get_1st_partition(device_path)
Chef::Log.info("First partition for device #{device_path} is: #{partition_dev}")
fs_type = get_fs_type(partition_dev)
device_path = partition_dev
end
node.default['cluster']['volume_fs_type'] = fs_type
device_path
end