File: runtime3_converter.rb

package info (click to toggle)
puppet-agent 7.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 19,092 kB
  • sloc: ruby: 245,074; sh: 456; makefile: 38; xml: 33
file content (221 lines) | stat: -rw-r--r-- 7,827 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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
module Puppet::Pops::Evaluator
# Converts nested 4x supported values to 3x values. This is required because
# resources and other objects do not know about the new type system, and does not support
# regular expressions. Unfortunately this has to be done for array and hash as well.
# A complication is that catalog types needs to be resolved against the scope.
#
# Users should not create instances of this class. Instead the class methods {Runtime3Converter.convert},
# {Runtime3Converter.map_args}, or {Runtime3Converter.instance} should be used
class Runtime3Converter
  MAX_INTEGER =  Puppet::Pops::MAX_INTEGER
  MIN_INTEGER = Puppet::Pops::MIN_INTEGER

  # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.map_args(...)
  #
  # @param args [Array] Array of values to convert
  # @param scope [Puppet::Parser::Scope] The scope to use when converting
  # @param undef_value [Object] The value that nil is converted to
  # @return [Array] The converted values
  #
  def self.map_args(args, scope, undef_value)
    @instance.map_args(args, scope, undef_value)
  end

  # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.convert(...)
  #
  # @param o [Object]The value to convert
  # @param scope [Puppet::Parser::Scope] The scope to use when converting
  # @param undef_value [Object] The value that nil is converted to
  # @return [Object] The converted value
  #
  def self.convert(o, scope, undef_value)
    @instance.convert(o, scope, undef_value)
  end

  # Returns the singleton instance of this class.
  # @return [Runtime3Converter] The singleton instance
  def self.instance
    @instance
  end

  # Converts 4x supported values to a 3x values.
  #
  # @param args [Array] Array of values to convert
  # @param scope [Puppet::Parser::Scope] The scope to use when converting
  # @param undef_value [Object] The value that nil is converted to
  # @return [Array] The converted values
  #
  def map_args(args, scope, undef_value)
    args.map {|a| convert(a, scope, undef_value) }
  end

  # Converts a 4x supported value to a 3x value.
  #
  # @param o [Object]The value to convert
  # @param scope [Puppet::Parser::Scope] The scope to use when converting
  # @param undef_value [Object] The value that nil is converted to
  # @return [Object] The converted value
  #
  def convert(o, scope, undef_value)
    @convert_visitor.visit_this_2(self, o, scope, undef_value)
  end

  def convert_NilClass(o, scope, undef_value)
    @inner ? nil : undef_value
  end

  def convert_Integer(o, scope, undef_value)
    return o unless o < MIN_INTEGER || o > MAX_INTEGER
    range_end = o > MAX_INTEGER ? 'max' : 'min'
    raise Puppet::Error, "Use of a Ruby Integer outside of Puppet Integer #{range_end} range, got '#{"0x%x" % o}'"
  end

  def convert_BigDecimal(o, scope, undef_value)
    # transform to same value float value if possible without any rounding error
    f = o.to_f
    return f unless f != o
    raise Puppet::Error, "Use of a Ruby BigDecimal value outside Puppet Float range, got '#{o}'"
  end

  def convert_String(o, scope, undef_value)
    # Although wasteful, a dup is needed because user code may mutate these strings when applying
    # Resources. This does not happen when in server mode since it only uses Resources that are
    # in puppet core and those are all safe.
    o.frozen? && !Puppet.run_mode.server? ? o.dup : o
  end

  def convert_Object(o, scope, undef_value)
    o
  end

  def convert_Array(o, scope, undef_value)
    ic = @inner_converter
    o.map {|x| ic.convert(x, scope, undef_value) }
  end

  def convert_Hash(o, scope, undef_value)
    result = {}
    ic = @inner_converter
    o.each {|k,v| result[ic.convert(k, scope, undef_value)] = ic.convert(v, scope, undef_value) }
    result
  end

  def convert_Iterator(o, scope, undef_value)
    raise Puppet::Error, _('Use of an Iterator is not supported here')
  end

  def convert_Symbol(o, scope, undef_value)
    return o unless o == :undef
    !@inner ? undef_value : nil
  end

  def convert_PAnyType(o, scope, undef_value)
    o
  end

  def convert_PCatalogEntryType(o, scope, undef_value)
    # Since 4x does not support dynamic scoping, all names are absolute and can be
    # used as is (with some check/transformation/mangling between absolute/relative form
    # due to Puppet::Resource's idiosyncratic behavior where some references must be
    # absolute and others cannot be.
    # Thus there is no need to call scope.resolve_type_and_titles to do dynamic lookup.
    t, title = catalog_type_to_split_type_title(o)
    t = Runtime3ResourceSupport.find_resource_type(scope, t) unless t == 'class' || t == 'node'
    Puppet::Resource.new(t, title)
  end

  # Produces an array with [type, title] from a PCatalogEntryType
  # This method is used to produce the arguments for creation of reference resource instances
  # (used when 3x is operating on a resource).
  # Ensures that resources are *not* absolute.
  #
  def catalog_type_to_split_type_title(catalog_type)
    split_type = catalog_type.is_a?(Puppet::Pops::Types::PTypeType) ? catalog_type.type : catalog_type
    case split_type
      when Puppet::Pops::Types::PClassType
        class_name = split_type.class_name
        ['class', class_name.nil? ? nil : class_name.sub(/^::/, '')]
      when Puppet::Pops::Types::PResourceType
        type_name = split_type.type_name
        title = split_type.title
        if type_name =~ /^(::)?[Cc]lass$/
          ['class', title.nil? ? nil : title.sub(/^::/, '')]
        else
          # Ensure that title is '' if nil
          # Resources with absolute name always results in error because tagging does not support leading ::
          [type_name.nil? ? nil : type_name.sub(/^::/, '').downcase, title.nil? ? '' : title]
        end
      else
        #TRANSLATORS 'PClassType' and 'PResourceType' are Puppet types and should not be translated
        raise ArgumentError, _("Cannot split the type %{class_name}, it represents neither a PClassType, nor a PResourceType.") %
            { class_name: catalog_type.class }
    end
  end

  protected

  def initialize(inner = false)
    @inner = inner
    @inner_converter = inner ? self : self.class.new(true)
    @convert_visitor = Puppet::Pops::Visitor.new(self, 'convert', 2, 2)
  end

  @instance = self.new
end

# A Ruby function written for the 3.x API cannot be expected to handle extended data types. This
# converter ensures that they are converted to String format
# @api private
class Runtime3FunctionArgumentConverter < Runtime3Converter

  def convert_Regexp(o, scope, undef_value)
    # Puppet 3x cannot handle parameter values that are regular expressions. Turn into regexp string in
    # source form
    o.inspect
  end

  def convert_Version(o, scope, undef_value)
    # Puppet 3x cannot handle SemVers. Use the string form
    o.to_s
  end

  def convert_VersionRange(o, scope, undef_value)
    # Puppet 3x cannot handle SemVerRanges. Use the string form
    o.to_s
  end

  def convert_Binary(o, scope, undef_value)
    # Puppet 3x cannot handle Binary. Use the string form
    o.to_s
  end

  def convert_Timespan(o, scope, undef_value)
    # Puppet 3x cannot handle Timespans. Use the string form
    o.to_s
  end

  def convert_Timestamp(o, scope, undef_value)
    # Puppet 3x cannot handle Timestamps. Use the string form
    o.to_s
  end

  # Converts result back to 4.x by replacing :undef with nil in Array and Hash objects
  #
  def self.convert_return(val3x)
    if val3x == :undef
      nil
    elsif val3x.is_a?(Array)
      val3x.map {|v| convert_return(v) }
    elsif val3x.is_a?(Hash)
      hsh = {}
      val3x.each_pair {|k,v| hsh[convert_return(k)] = convert_return(v)}
      hsh
    else
      val3x
    end
  end

  @instance = self.new
end

end