@@ -44,6 +44,7 @@ def fetch_cached_hashes(cache, hashes)
4444 # @param context [Object] the Puppet runtime context to operate in and send feedback to
4545 # @param resources [Hash] the hash of the resource to canonicalize from either manifest or invocation
4646 # @return [Hash] returns a hash representing the current state of the object, if it exists
47+ # rubocop:disable Metrics/BlockLength, Metrics/MethodLength
4748 def canonicalize ( context , resources )
4849 canonicalized_resources = [ ]
4950 resources . collect do |r |
@@ -83,9 +84,18 @@ def canonicalize(context, resources)
8384 downcased_result . each do |key , value |
8485 # Canonicalize to the manifest value unless the downcased strings match and the attribute is not an enum:
8586 # - When the values don't match at all, the manifest value is desired;
86- # - When the values match case insensitively but the attribute is an enum, prefer the casing of the manifest enum.
87- # - When the values match case insensitively and the attribute is not an enum, prefer the casing from invoke_get_method
88- canonicalized [ key ] = r [ key ] unless same? ( value , downcased_resource [ key ] ) && !enum_attributes ( context ) . include? ( key )
87+ # - When the values match case insensitively but the attribute is an enum, and the casing from invoke_get_method
88+ # is not int the enum, prefer the casing of the manifest enum.
89+ # - When the values match case insensitively and the attribute is not an enum, or is an enum and invoke_get_method casing
90+ # is in the enum, prefer the casing from invoke_get_method
91+ is_enum = enum_attributes ( context ) . include? ( key )
92+ canonicalized_value_in_enum = if is_enum
93+ enum_values ( context , key ) . include? ( canonicalized [ key ] )
94+ else
95+ false
96+ end
97+ match_insensitively = same? ( value , downcased_resource [ key ] )
98+ canonicalized [ key ] = r [ key ] unless match_insensitively && ( canonicalized_value_in_enum || !is_enum )
8999 canonicalized . delete ( key ) unless downcased_resource . key? ( key )
90100 end
91101 # Cache the actually canonicalized resource separately
@@ -104,6 +114,7 @@ def canonicalize(context, resources)
104114 context . debug ( "Canonicalized Resources: #{ canonicalized_resources } " )
105115 canonicalized_resources
106116 end
117+ # rubocop:enable Metrics/BlockLength, Metrics/MethodLength
107118
108119 # Attempts to retrieve an instance of the DSC resource, invoking the `Get` method and passing any
109120 # namevars as the Properties to Invoke-DscResource. The result object, if any, is compared to the
@@ -686,6 +697,28 @@ def enum_attributes(context)
686697 context . type . attributes . select { |_name , properties | properties [ :type ] . include? ( 'Enum[' ) } . keys
687698 end
688699
700+ # Parses the DSC resource type definition to retrieve the values of any attributes which are specified as enums
701+ #
702+ # @param context [Object] the Puppet runtime context to operate in and send feedback to
703+ # @param attribute [String] the enum attribute to retrieve the allowed values from
704+ # @return [Array] returns an array of attribute names as symbols which are enums
705+ def enum_values ( context , attribute )
706+ # Get the attribute's type string for the given key
707+ type_string = context . type . attributes [ attribute ] [ :type ]
708+
709+ # Return an empty array if the key doesn't have an Enum type or doesn't exist
710+ return [ ] unless type_string &.include? ( 'Enum[' )
711+
712+ # Extract the enum values from the type string
713+ enum_content = type_string . match ( /Enum\[ (.*?)\] / ) &.[]( 1 )
714+
715+ # Return an empty array if we couldn't find the enum values
716+ return [ ] if enum_content . nil?
717+
718+ # Return an array of the enum values, stripped of extra whitespace and quote marks
719+ enum_content . split ( ',' ) . map { |val | val . strip . delete ( '\'' ) }
720+ end
721+
689722 # Look through a fully formatted string, replacing all instances where a value matches the formatted properties
690723 # of an instantiated variable with references to the variable instead. This allows us to pass complex and nested
691724 # CIM instances to the Invoke-DscResource parameter hash without constructing them *in* the hash.
0 commit comments