File: apache_mod_platform_support.rb

package info (click to toggle)
puppet-module-puppetlabs-apache 12.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,664 kB
  • sloc: ruby: 275; sh: 32; makefile: 2
file content (153 lines) | stat: -rw-r--r-- 5,603 bytes parent folder | download
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