1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
# frozen_string_literal: true
require 'json'
# Helper class to facilitate exclusion of tests that use an Apache MOD on platforms it isn't supported on.
# All Apache MOD classes are defined under 'manifests/mod'. The exclusion should be in the format:
#
# @note Unsupported platforms: OS: ver, ver; OS: ver, ver, ver; OS: all'
# class apache::mod::foobar {
# ...
#
# For example:
# @note Unsupported platforms: RedHat: 5, 6; Ubuntu: 14.04; SLES: all; Scientific: 11 SP1'
# class apache::mod::actions {
# apache::mod { 'actions': }
# }
#
# Filtering is then performed during the test using RSpec's filtering, like so:
#
# describe 'auth_oidc', unless: mod_unsupported_on_platform('apache::mod::auth_openidc') do
# ...
# it 'applies cleanly', unless: mod_unsupported_on_platform('apache::mod::auth_openidc') do
# ...
class ApacheModPlatformCompatibility
ERROR_MSG = {
tag_parse: 'OS and version information in incorrect format:',
os_parse: 'OS name is not present in metadata.json:'
}.freeze
def initialize
@os = {}
@mapping = {}
@manifest_errors = []
@compatible_platform_versions = {}
@mod_platform_compatibility_mapping = {}
end
def register_running_platform(os)
@os = { family: os[:family], release: os[:release].to_i }
end
def generate_supported_platforms_versions
metadata = JSON.parse(File.read('metadata.json'))
metadata['operatingsystem_support'].each do |os|
@compatible_platform_versions[os['operatingsystem'].downcase] = os['operatingsystemrelease'].map(&:to_i)
end
end
# Class to hold the details of an error whilst parsing an unsupported tag
class ManifestError
attr_reader :manifest, :line_num, :error_type, :error_detail
def initialize(manifest, line_num, error_type, error_detail)
@manifest = manifest
@line_num = line_num
@error_type = error_type
@error_detail = error_detail
end
end
def print_parsing_errors
return if @manifest_errors.empty?
warn "The following errors were encountered when trying to parse the 'Unsupported platforms' tag(s) in 'manifests/mod':\n"
@manifest_errors.each do |manifest_error|
warn " * #{manifest_error.manifest} (line #{manifest_error.line_num}): #{ERROR_MSG[manifest_error.error_type]} #{manifest_error.error_detail}"
end
File.readlines('util/_resources/tag_format_help_msg.txt').each do |line|
warn line
end
end
def valid_os?(os)
@compatible_platform_versions.key?(os)
end
def register_error(manifest, line_num, error_type, error_detail)
@manifest_errors << ManifestError.new(manifest, line_num, error_type, error_detail)
end
def register_unsupported_platforms(manifest, line_num, mod, platforms_versions)
platforms_versions.each_key do |os|
unless valid_os?(os)
register_error(manifest, line_num, :os_parse, os)
next
end
if @mod_platform_compatibility_mapping.key? mod
@mod_platform_compatibility_mapping[mod].merge!(platforms_versions)
else
@mod_platform_compatibility_mapping[mod] = platforms_versions
end
end
end
def extract_os_ver_pairs(line)
platforms_versions = {}
os_ver_groups = line.delete(' ').downcase
# E.g. "debian:5,6;centos:5;sles:11sp1,12;scientific:all;ubuntu:14.04,16.04"
if %r{^((?:\w+:(?:(?:\d+(?:\.\d+|sp\d+)?|all),?)+;?)+)$}i.match?(os_ver_groups)
os_ver_groups.split(';').each do |os_vers|
os, vers = os_vers.split(':')
vers.gsub!(%r{sp\d+}, '') # Remove SP ver as we cannot determine this level of granularity from values from Litmus
platforms_versions[os] = vers.split(',').map(&:to_i) # 'all' will be converted to 0
end
end
platforms_versions
end
def process_line(line)
data = {}
return data unless %r{@note\sUnsupported\splatforms?:\s?|class\sapache::mod}i.match?(line)
if (match = %r{@note\sUnsupported\splatforms?:\s?(?<os_vers>.*)$}i.match(line))
data[:type] = :unsupported_platform_declaration
data[:value] = match[:os_vers]
elsif (match = %r{class\s(?<mod>apache::mod::\w+)}i.match(line))
data[:type] = :class_declaration
data[:value] = match[:mod]
end
data
end
def generate_mod_platform_exclusions
Dir.glob('manifests/mod/*.pp').each do |manifest|
platforms_versions = []
line_num = 0
File.readlines(manifest).each do |line|
line_num += 1
data = process_line(line)
next if data.empty?
if data[:type] == :unsupported_platform_declaration
platforms_versions = extract_os_ver_pairs(data[:value])
register_error(manifest, line_num, :tag_parse, line) if platforms_versions.empty?
next
elsif data[:type] == :class_declaration
register_unsupported_platforms(manifest, line_num, data[:value], platforms_versions) unless platforms_versions.empty?
break # Once we detect the class declaration, we can move on
end
end
end
end
# Called from within the context of a test run, making use of RSpec's filtering, e.g.:
# it 'should do some test', if: mod_supported_on_platform('apache::mod::foobar')
def mod_supported_on_platform?(mod)
return true if @mod_platform_compatibility_mapping.empty?
return true unless @mod_platform_compatibility_mapping.key? mod
return true unless @mod_platform_compatibility_mapping[mod].key? @os[:family]
return false if @mod_platform_compatibility_mapping[mod][@os[:family]] == [0]
!@mod_platform_compatibility_mapping[mod][@os[:family]].include? @os[:release]
end
end
|