onddo/encrypted_attributes-cookbook

View on GitHub
libraries/cookbook_helpers.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: UTF-8
#
# Cookbook Name:: encrypted_attributes
# Library:: cookbook_helpers
# Author:: Xabier de Zuazo (<xabier@onddo.com>)
# Copyright:: Copyright (c) 2014-2015 Onddo Labs, SL. (www.onddo.com)
# 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.
#

# Internal `encrypted_attributes` cookbook classes and modules.
class EncryptedAttributesCookbook
  # Some helpers used in the `encrypted_attribute` cookbook.
  module Helpers
    unless defined?(LATEST)
      # The latest chef-encrypted-attributes gem version, or at least the latest
      # that requires different installation steps.  This is used as a default
      # when a nil version is specified.
      # @api private
      LATEST = '0.7.0'
    end

    # Checks if the using Chef version meets a version requirement.
    #
    # @param req [String] Requirement string. For example: `'~> 12'
    # @return [Boolean] `true` if the chef version meets the requirement.
    # @api private
    def self.chef_version_satisfies?(req)
      Gem::Requirement.new(req).satisfied_by?(Gem::Version.new(Chef::VERSION))
    end

    # Determines which YAJL library is already available, based on the Chef
    # version.
    #
    # @return [String] the YAJL library that Chef supplies
    # @api private
    def self.chef_yajl_library
      if chef_version_satisfies?('< 11.13')
        'yajl-ruby'
      else
        'ffi-yajl'
      end
    end

    # Determines which yajl library, if any, the gem depends on.
    #
    # @param [String] gem_version the chef-encrypted-attributes gem version
    # @return [Hash<String, String>] the YAJL library that the gem depends on
    # @api private
    def self.yajl_dependency_of_gem(gem_version)
      version = make_gem_version(gem_version)

      case
      when Gem::Requirement.new('>= 0.6.0').satisfied_by?(version)
        {}
      when Gem::Requirement.new('>= 0.4.0').satisfied_by?(version)
        { 'ffi-yajl' => '1.0.2' }
      else
        { 'yajl-ruby' => nil }
      end
    end

    # Converts a string representing a gem version into a Gem::Version object
    #
    # @param [String] gem_version the chef-encrypted-attributes gem version
    # @return [Gem::Version] an object representing the version
    # @api private
    def self.make_gem_version(gem_version)
      Gem::Version.new(gem_version || LATEST)
    rescue ArgumentError
      raise 'EncryptedAttributesCookbook: Wrong gem version set in '\
            'node["encrypted_attributes"]["version"].'
    end

    # Checks if `build-essential` cookbook is required.
    #
    # This is used only for native gems compilation.
    #
    # | **Gem Version**       | **0.7.0** | **0.6.0** | **0.4.0** | **0.3.0** |
    # |-----------------------|-----------|-----------|-----------|-----------|
    # | **Chef `12`**         | no        | no        | no        | -         |
    # | **Chef `>= 11.16.4`** | no        | yes*      | no        | yes       |
    # | **Chef `< 11.16.4`**  | no        | yes*      | yes       | no        |
    #
    # [*] Using gem version `0.6.0` will return `true` only in Ruby `< 2`.
    #     This is required by the old gem extension that installs some
    #     dependencies dynamically.
    #
    # @param gem_version [String] gem version to install.
    # @return [Boolean] `true` if `build-essential` cookbook is required.
    # @raise [RuntimeError] if specified gem version is wrong.
    def self.require_build_essential?(gem_version)
      gem_version_obj = make_gem_version(gem_version)
      if RUBY_VERSION.to_i < 2 && chef_version_satisfies?('< 12') &&
         Gem::Requirement.new('~> 0.6.0').satisfied_by?(gem_version_obj)
        # Required by the old dynamic dependency installation gem extension.
        return true
      end
      !required_depends(gem_version).empty?
    end

    # Checks if gem dependencies should be installed or not.
    #
    # | **Gem Version**       | **0.6.0** *(latest)* | **0.4.0** | **0.3.0** |
    # |-----------------------|----------------------|-----------|-----------|
    # | **Chef `12`**         | yes                  | yes       | -         |
    # | **Chef `>= 11.16.4`** | yes                  | yes       | yes       |
    # | **Chef `< 11.16.4`**  | yes                  | yes       | yes       |
    #
    # @param gem_version [String] gem version to install.
    # @return [Boolean] `true` if dependencies installation should be skipped.
    def self.skip_gem_dependencies?(_gem_version)
      true
    end

    # Gets required gem dependencies.
    #
    # We should return no dependencies if already included by Chef.
    #
    # | **Gem Version**       | **0.6.0** *(latest)* | **0.4.0** | **0.3.0** |
    # |-----------------------|----------------------|-----------|-----------|
    # | **Chef `12`**         | -                    | -         | -         |
    # | **Chef `>= 11.16.4`** | -                    | -         | yajl-ruby |
    # | **Chef `< 11.16.4`**  | -                    | ffi-yajl  | -         |
    #
    # @param gem_version [String] gem version to install.
    # @return [Hash<String, String>] list of gem dependencies required as
    #   `Hash<Name, Version>`.
    # @raise [RuntimeError] if specified gem version is wrong.
    def self.required_depends(gem_version)
      yajl_dependency_of_gem(gem_version).reject do |gem_name, _|
        gem_name == chef_yajl_library
      end
    end

    # Checks if the gem version to install is a prerelease version.
    #
    # @param gem_version [String] gem version to install.
    # @return [Boolean] `true` if it is a prerelease version.
    def self.prerelease?(gem_version)
      gem_version.is_a?(String) && gem_version.match(/^[0-9.]+$/).nil?
    end
  end
end