Create Method Clobbers Multiple List Values
harlanbarnes opened this issue · comments
It appears that the create method will collapse lists/arrays and only keep the last value. For example, I was trying to add a host to multiple hostgroups:
hostid = zabbix.hosts.create_or_update(
:host => host.fqdn,
:interfaces => interfaces,
:groups => [ {:group_id => 1}, {:group_id =>2} ]
)
With debug turned on, I could see the call create with multiple group hashes in the params:
[DEBUG] Call create with parametrs: {:host=>"foo", :interfaces=>[{:type=>1, :main=>1, :ip=>"192.168.1.1", :dns=>"foo", :port=>10050, :useip=>0}], :groups=>[{:groupid=>"1"}, {:groupid=>"2"}]}
but then I would see the request being created with just the second id group id:
[DEBUG] Send request: {"method":"host.create","params":[{"host":foo","interfaces":[{"type":1,"main":1,"ip":"192.168.1.1","dns":"foo","port":10050,"useip":0}],"status":0,"available":1,"groups":[{"groupid":"2"}], "auth":"......................", "id":69893, "jsonrpc":"2.0"}
I think I tracked it down to the merge_params in basic_func.rb (i'm using 2.0, but I presume 1.8 is like this too). I think this line is what does it ...
JSON.parse(result.gsub('},{', ','))
If I understand, the intent here is to let JSON do the merging of the default and given params into a single JSON doc and then reparse it. But it picks up and does the substiution on lists of hashes for things like groups, templates, macros, etc. ... and leaves only one in the list.
I know this isn't a proper PR, but this seems to work for me (and it gets JSON out of the picture too ... might be a little faster.)
def stringify_keys(obj)
return obj.inject({}){|memo,(k,v)| memo[k.to_s] = stringify_keys(v); memo} if obj.is_a? Hash
return obj.inject([]){|memo,v | memo << stringify_keys(v); memo} if obj.is_a? Array
obj
end
def merge_params(params)
stringify_keys(default_options.merge(params))
end
I presume you were also using the JSON conversion for converting all the symbols to strings too. If I'm wrong about the reasoning behind the JSON maneuvers, then this works too:
def merge_params(params)
new_params = default_options.merge(params)
JSON.parse(JSON.generate(new_params).to_s)
end