Closed jeking3 closed 4 years ago
This is likely an internal error in the program I was using; I will investigate that and re-open this if necessary.
Reopened, this is not an issue in my code; it is happening in the library.
Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @Drewm3, @avirishuv, @axayjo, @vaibhav-agar.
Hi @jeking3 Assigning to myself since it touches the serialization part and not really the Compute specific part. I actually wrote that "double key" detection mechanism :). Your Github report is awesome, all the details I can dream of, I'll try to investigate that asap (can't promise date though I'm sorry).
Thanks!
My guess is in this case the metadata is wrong, or it is not reversible. i.e. when converting from python to rest you take the virtual_machine_extension_type and stuck it in properties.type, and the same on the way back out. But if you as_dict then from_dict a VirtualMachineExtension object, the content stays in python form, and the lookup is expecting server form:
1146 def last_rest_key_case_insensitive_extractor(attr, attr_desc, data):
1147 -> key = attr_desc['key']
1148 dict_keys = _FLATTEN.split(key)
1149 return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data)
1150
1151 def attribute_key_extractor(attr, _, data):
1152 return data.get(attr)
(Pdb) n
> /home/jking/confab/confab-cloud/.tox/debug/lib/python3.7/site-packages/msrest/serialization.py(1148)last_rest_key_case_insensitive_extractor()
-> dict_keys = _FLATTEN.split(key)
(Pdb) n
> /home/jking/confab/confab-cloud/.tox/debug/lib/python3.7/site-packages/msrest/serialization.py(1149)last_rest_key_case_insensitive_extractor()
-> return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data)
(Pdb) pp dict_keys
['properties', 'type']
In this case it ignores "attr" completely, and drops "properties." and returns the type field which is wrong.
I'd like to stress the urgency for a fix on this... Any virtual machine with an extension installed cannot be deserialized by azure-mgmt-compute 12.0 (the current version).
@jeking3 could you try downgrading msrest to 0.6.12 or below? I wonder if its a regression introduced in 0.6.13
Edit: tested myself and no difference 0.6.12/0.6.13
Hi @jeking3 Something I don't understand, why would you do that:
VirtualMachineExtension.from_dict(result._result.as_dict())
It seems you got result._result
as a correct instance of VirtualMachineExtension already from create_or_update, meaning you didn't get an exception from create_or_update
(which is what you title made me think).
I don't deny there is a bug somewhere of course, I'm just challenging the title to be misleading a little, since to me the create_or_update
operation didn't fail, it's further handling of the received model using as_dict
/ from_dict
that fails, which is not the same thing.
Do you agree?
So, this happens because from_string
has three extractors by default, you can workaround the issue specifying the one you want to use:
In [12]: from msrest.serialization import attribute_key_extractor
In [14]: v = VirtualMachineExtension.from_dict(raw, key_extractors=[attribute_key_extractor])
In [15]: v.type
Out[15]: 'Microsoft.Compute/virtualMachines/extensions'
In [16]: v.virtual_machine_extension_type
Out[16]: 'CustomScriptExtension'
attribute_key_extractor
is the opposite part of as_dict
, making it more deterministic.
I'm still unsure what is the best way to fix the issue, since it's deep inside the deserialization logic and any changes could update many MANY packages (there is hundreds, if not thousands if you count all versions, of packages that uses this code).
Hi @jeking3 I got a fix in PR, where instead of raise in case of duplicate, I apply extractors in order and precedence is most important. It means that the only change of behavior is when this exception was raised (the rest doesn't change). I added a log still.
In [2]: from azure.mgmt.compute.models import *
In [3]: v = VirtualMachineExtension.from_dict(raw)
Ignoring extracted value 'Microsoft.Compute/virtualMachines/extensions' from <function last_rest_key_case_insensitive_extractor at 0x000002403109FB88> for key 'virtual_machine_extension_type' (duplicate extraction, follow extractors order)
Could you give it a shot? https://github.com/Azure/msrest-for-python/pull/204
Thanks,
This fixes the issue I was seeing. Seems like a pretty major change to reorder the deserializer preferences?
It was not ordered before, we were trying all, and then, we were discarding None, and checking the remaining were all the same values. It's where your problem was, in this last scenario you get in a situation where when we check all the extracted values are consistent, they are not and we raised an exception. The new version will not raise an exception, but instead pick the first one in order and return (while logging a warning). I don't think this exception was bringing any values anyway, so people will see a change from an exception to a warning log, which I think it's fair.
It fixed a test in the repository that was expecting an error, so I would agree with you.
Fixed part of msrest 0.6.14 https://pypi.org/project/msrest/0.6.14/
Could you confirm before I close the issue?
Re-opening, since I want manual confirmation and Github closed it
Closing the issue after a few days since I strongly believed this is fixed, feel free to create a new issue if necessary. Thanks!
Describe the bug
After calling VirtualMachineExtension.create_or_update, the response coming back from the server cannot go through a deserialize/serialize cycle, likely due to something with the metadata handling (there are two fields with the key "type" in the structure, but at different levels):
Calling create_or_update with:
Note there is no "type" property; the server fills that in on the response:
Now if you attempt to deserialize this result it will fail with the error:
When I get the error indicating "Use twice the key", which is a KeyError ,I added a breakpoint so I could investigate:
It appears the metadata for "virtual_machine_extension_type" is referencing the "type" field instead of the "virtual_machine_extension_type" field. It extracts the wrong content, and then the code thinks that a key appears twice in the data.
To Reproduce Run the following script:
Result: