File: manager.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 (197 lines) | stat: -rw-r--r-- 6,795 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
require_relative '../../puppet'
require_relative '../../puppet/util/classgen'
require_relative '../../puppet/node/environment'

# This module defines methods dealing with Type management.
# This module gets included into the Puppet::Type class, it's just split out here for clarity.
# @api public
#
module Puppet::MetaType
module Manager
  include Puppet::Util::ClassGen

  # An implementation specific method that removes all type instances during testing.
  # @note Only use this method for testing purposes.
  # @api private
  #
  def allclear
    @types.each { |name, type|
      type.clear
    }
  end

  # Clears any types that were used but absent when types were last loaded.
  # @note Used after each catalog compile when always_retry_plugins is false
  # @api private
  #
  def clear_misses
    unless @types.nil?
      @types.delete_if {|_, v| v.nil? }
    end
  end

  # Iterates over all already loaded Type subclasses.
  # @yield [t] a block receiving each type
  # @yieldparam t [Puppet::Type] each defined type
  # @yieldreturn [Object] the last returned object is also returned from this method
  # @return [Object] the last returned value from the block.
  def eachtype
    @types.each do |name, type|
      # Only consider types that have names
      #if ! type.parameters.empty? or ! type.validproperties.empty?
        yield type
      #end
    end
  end

  # Loads all types.
  # @note Should only be used for purposes such as generating documentation as this is potentially a very
  #  expensive operation.
  # @return [void]
  #
  def loadall
    typeloader.loadall(Puppet.lookup(:current_environment))
  end

  # Defines a new type or redefines an existing type with the given name.
  # A convenience method on the form `new<name>` where name is the name of the type is also created.
  # (If this generated method happens to clash with an existing method, a warning is issued and the original
  # method is kept).
  #
  # @param name [String] the name of the type to create or redefine.
  # @param options [Hash] options passed on to {Puppet::Util::ClassGen#genclass} as the option `:attributes`.
  # @option options [Puppet::Type]
  #   Puppet::Type. This option is not passed on as an attribute to genclass.
  # @yield [ ] a block evaluated in the context of the created class, thus allowing further detailing of
  #   that class.
  # @return [Class<inherits Puppet::Type>] the created subclass
  # @see Puppet::Util::ClassGen.genclass
  #
  # @dsl type
  # @api public
  def newtype(name, options = {}, &block)
    @manager_lock.synchronize do
      # Handle backward compatibility
      unless options.is_a?(Hash)
        #TRANSLATORS 'Puppet::Type.newtype' should not be translated
        Puppet.warning(_("Puppet::Type.newtype(%{name}) now expects a hash as the second argument, not %{argument}") %
                       { name: name, argument: options.inspect})
      end

      # First make sure we don't have a method sitting around
      name = name.intern
      newmethod = "new#{name}"

      # Used for method manipulation.
      selfobj = singleton_class

      if @types.include?(name)
        if self.respond_to?(newmethod)
          # Remove the old newmethod
          selfobj.send(:remove_method,newmethod)
        end
      end

      # Then create the class.

      klass = genclass(
        name,
        :parent => Puppet::Type,
        :overwrite => true,
        :hash => @types,
        :attributes => options,
        &block
      )

      # Now define a "new<type>" method for convenience.
      if self.respond_to? newmethod
        # Refuse to overwrite existing methods like 'newparam' or 'newtype'.
        #TRANSLATORS 'new%{method}' will become a method name, do not translate this string
        Puppet.warning(_("'new%{method}' method already exists; skipping") % { method: name.to_s })
      else
        selfobj.send(:define_method, newmethod) do |*args|
          klass.new(*args)
        end
      end

      # If they've got all the necessary methods defined and they haven't
      # already added the property, then do so now.
      klass.ensurable if klass.ensurable? and ! klass.validproperty?(:ensure)

      # Now set up autoload any providers that might exist for this type.

      klass.providerloader = Puppet::Util::Autoload.new(klass, "puppet/provider/#{klass.name}")

      # We have to load everything so that we can figure out the default provider.
      klass.providerloader.loadall(Puppet.lookup(:current_environment))
      klass.providify unless klass.providers.empty?

      loc = block_given? ? block.source_location : nil
      uri = loc.nil? ? nil : URI("#{Puppet::Util.path_to_uri(loc[0])}?line=#{loc[1]}")
      Puppet::Pops::Loaders.register_runtime3_type(name, uri)

      klass
    end
  end

  # Removes an existing type.
  # @note Only use this for testing.
  # @api private
  def rmtype(name)
    # Then create the class.

    rmclass(name, :hash => @types)

    singleton_class.send(:remove_method, "new#{name}") if respond_to?("new#{name}")
  end

  # Returns a Type instance by name.
  # This will load the type if not already defined.
  # @param [String, Symbol] name of the wanted Type
  # @return [Puppet::Type, nil] the type or nil if the type was not defined and could not be loaded
  #
  def type(name)
    @manager_lock.synchronize do
      # Avoid loading if name obviously is not a type name
      if name.to_s.include?(':')
        return nil
      end

      # We are overwhelmingly symbols here, which usually match, so it is worth
      # having this special-case to return quickly.  Like, 25K symbols vs. 300
      # strings in this method. --daniel 2012-07-17
      return @types[name] if @types.include? name

      # Try mangling the name, if it is a string.
      if name.is_a? String
        name = name.downcase.intern
        return @types[name] if @types.include? name
      end
      # Try loading the type.
      if typeloader.load(name, Puppet.lookup(:current_environment))
        #TRANSLATORS 'puppet/type/%{name}' should not be translated
        Puppet.warning(_("Loaded puppet/type/%{name} but no class was created") % { name: name }) unless @types.include? name
      elsif !Puppet[:always_retry_plugins]
        # PUP-5482 - Only look for a type once if plugin retry is disabled
        @types[name] = nil
      end

      # ...and I guess that is that, eh.
      return @types[name]
    end
  end

  # Creates a loader for Puppet types.
  # Defaults to an instance of {Puppet::Util::Autoload} if no other auto loader has been set.
  # @return [Puppet::Util::Autoload] the loader to use.
  # @api private
  def typeloader
    unless defined?(@typeloader)
      @typeloader = Puppet::Util::Autoload.new(self, "puppet/type")
    end

    @typeloader
  end
end
end