-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Array of Hashes comparison result in a change at each run #327
Comments
Hi, I spent some time trying to find a way to handle this. I would suggest a piece of code that is best effort Code location : https://github.com/puppetlabs/ruby-pwsh/blob/main/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb#L391 # Special handling for CIM Instances
if data[type_key].is_a?(Enumerable)
downcase_hash_keys!(data[type_key])
munge_cim_instances!(data[type_key])
if data[type_key].respond_to?('each') and name_hash[type_key].respond_to?('each')
if data[type_key].length() == name_hash[type_key].length()
name_hash_merged=name_hash[type_key].zip(data[type_key]).map do |hash1, hash2|
hash1 ||= {}
hash2.merge(hash1 || {})
end
name_hash_merged_sorted = recursively_sort(name_hash_merged)
data_sorted = recursively_sort(data[type_key])
if name_hash_merged_sorted == data_sorted
name_hash[type_key] = name_hash_merged_sorted
end
end
end
end Current behavior (without this piece of code)If the INPUT array of hash is not strictly the same as the one retrieved (each key, each value) => There is a change Behavior with the piece of codeCase 1 : Ressources are different length==> Run as current behavior Case 2 : Ressources are same length but after merge, ressources are still different==> Run as current behavior Case 3 : Ressources are same length and are equal after merge==> Replace current declaration (name_hash) with the merge. This ends up considering ressource are equal and no changes are done This implies that [name: john, surname: doe] will overwrite [surname: doe, name: john]. But if the system reads in the order it was written, it will not redo this on subsequent runs. In my opinion it is not perfect but still better than always rewriting the resource. |
Hi, I have spent a bit more time on this recently. I have sort of a "good enough" solution. # Special handling for CIM Instances
if data[type_key].is_a?(Enumerable)
downcase_hash_keys!(data[type_key])
munge_cim_instances!(data[type_key])
# Partially handle nested Arrays/Hashes
# Should properly compare (ie. not try to make a permanent change on the ressource) the following format
# - Arrays (my_object = ['foo', 'bar'])
# - Nested Arrays (my_object = [['foo1', 'bar1'], ['foo2','bar2']])
# - Array of Hash (my_object = [{:foo1 => 'bar1'}, {:foo2 => 'bar2'}])
# Deeper nested object may not work and require "validation_mode => resource" to avoid permanent changes
# This is a "good enough" handling of nested object, to avoid an increasing amount of computing the deeper the nest is.
if data[type_key].class == name_hash[type_key].class && data[type_key].length() == name_hash[type_key].length()
if name_hash[type_key].is_a?(Array)
if name_hash[type_key][0].is_a?(Hash)
merge = name_hash[type_key].zip(data[type_key]).map do |h1, h2|
h1 ||= {}
h2.merge(h1 || {})
end
else
merge = name_hash[type_key] | data[type_key]
end
elsif name_hash[type_key].is_a?(Hash)
merge = name_hash[type_key].merge(data[type_key] || {})
end
merge_sorted = recursively_sort(merge)
data_sorted = recursively_sort(data[type_key])
if merge_sorted == data_sorted
name_hash[type_key] = merge_sorted
end
end
end |
Upon further testing I found one use case where you can trigger a permanent change (though it seems a bit convoluted) First : dsc_bindinginfo:
- hostname: "machin.fr"
protocol: http
port: 80
- hostname: "machin.es"
protocol: http
port: 80
- hostname: "machin.fr"
protocol: http
port: 8080
- hostname: "machin.lt"
protocol: http
port: 8080 then run puppet. The resources is applied Second run and following run : no permanent change Update your declaration by changing the order (but not changing or addind anything) dsc_bindinginfo:
- hostname: "machin.es"
protocol: http
port: 80
- hostname: "machin.fr"
protocol: http
port: 80
- hostname: "machin.fr"
protocol: http
port: 8080
- hostname: "machin.lt"
protocol: http
port: 8080 This would trigger a permanent change because the comparison will always check the order it was written at first. But given order does not really matter, nothing is actually changed. However, if you add an element or change any value, then the order will be written with the last one you declared. I guess it is acceptable. (Given now we have always a permanent change) |
Describe the Bug
When setting a resource that have a parameter with an Array of Hash, it compares with every entry of the hash, even though they are optional. This results in a perma-change (each run sets the resource again and again)
Expected Behavior
The values in the Array of Hash should not be set at each run
Steps to Reproduce
Module : webadministration dsc
Resource : dsc_website (assuming you have already set a pool to host the website)
The part that is interesting is dsc_bindinginfo
The run (each run in fact) results with this
Environment
Additional Context
There is an easy fix, but I do not find it acceptable. (It is using validation_mode: resource). It does resolve the issue but the execution time skyrockets from 0.1 sec to 1.5 sec. per website. Moreover, I think it concerns each parameter in every resources that has
mof_is_embedded: true
So having each resource taking a full second, you end up easily with 5 min runs when you handle many resources. So I hope there is an alternativeSo here is the type definition of dsc_bindinginfo
The sub parameters are almost all optional.
I did try to specifiy them all by the way, but I can't specify undef for certificatestorename :( (and this would be a poor workaround)
I this the handling of this type of resources is link to
mof_is_embedded: true
(with a dedicated handling for pscredential)I tried to debug dsc_base_provider.rb to understand what is causing this issue, but could not figure it out yet. :/
The text was updated successfully, but these errors were encountered: