onddo/ramdisk-cookbook

View on GitHub
libraries/mount_resource_helper.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: UTF-8
#
# Cookbook Name:: ramdisk
# Library:: lwrp_helpers
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
# Copyright:: Copyright (c) 2014 Onddo Labs, SL.
# License:: Apache License, Version 2.0
#
# 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.

require 'chef/mixin/shell_out'

class Chef
  module Ramdisk
    # Resource Helper class to read current mount options from the system
    class MountResourceHelper
      extend Chef::Mixin::ShellOut

      unless defined?(Chef::Ramdisk::MountResourceHelper::IGNORE_OPTIONS)
        IGNORE_OPTIONS = %w(rw relatime seclabel rootcontext)
      end

      attr_reader :resource

      def initialize(mount_point, device)
        @resource = Chef::Resource::Mount.new(device)
        @resource.mount_point(mount_point)
        @resource.device(device)
      end

      def bytes2integer(bytes)
        case bytes
        when /^[0-9]+k$/ then bytes.to_i * 1024
        when /^[0-9]+m$/ then bytes.to_i * 1_048_576
        when /^[0-9]+g$/ then bytes.to_i * 1_073_741_824
        else
          bytes.to_i
        end
      end

      def parse_options_string(options)
        parse_options_array(options.split(/, */))
      end

      def parse_options_array(options)
        options.each_with_object({}) do |option, memo|
          key, value = option.split('=', 2)
          key = key.sub(/^nr_/, '') # remove "nr_" prefix
          memo[key] = value.nil? ? true : value
        end
      end

      def parse_options_hash(options)
        options.each_with_object({}) do |(key, value), memo|
          key = key.to_s.sub(/^nr_/, '') # remove "nr_" prefix
          memo[key] = value
        end
      end

      def parse_options_to_hash(options)
        case options
        when String then parse_options_string(options)
        when Array then parse_options_array(options)
        when Hash then parse_options_hash(options)
        else
          options
        end
      end

      def ignore_options(options)
        return options unless options.respond_to?(:reject)
        options.reject { |x| IGNORE_OPTIONS.include?(x) }
      end

      def options_to_integers(options)
        return options unless options.respond_to?(:key?)
        %w(size inodes).each_with_object(options) do |key, memo|
          memo[key] = bytes2integer(memo[key]) if memo.key?(key)
        end
      end

      def parse_options(options)
        result = parse_options_to_hash(options)
        result = ignore_options(result)
        options_to_integers(result)
      end

      def real_mount_point
        if ::File.exist?(@resource.mount_point)
          ::File.realpath(@resource.mount_point)
        else
          @resource.mount_point
        end
      end

      def load_current_resource
        self.class.shell_out!('mount').stdout.each_line do |line|
          case line
          when /^#{Regexp.escape(@resource.device)}\s+on\s+
                #{Regexp.escape(real_mount_point)}\s+
                type\s+(\S+)\s+[(](\S+)[)]$/x
            @resource.fstype(Regexp.last_match[1])
            @resource.options(Regexp.last_match[2])
          end
        end
      end

      def mount_options_changed?(new)
        @resource.fstype != new.fstype ||
          parse_options(@resource.options) != parse_options(new.options)
      end
    end
  end
end