Skip to content
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

Non-deterministic provider output #67

Open
covracer opened this issue Dec 31, 2020 · 0 comments
Open

Non-deterministic provider output #67

covracer opened this issue Dec 31, 2020 · 0 comments

Comments

@covracer
Copy link

Thanks for the awesome software! Something I ran into while trying to automate managing user accounts across providers:

test.py:

import json
from terraformpy import Provider, compile
with Provider("github", alias="github"):
    pass
with Provider("aws", alias="aws"):
    pass
print(json.dumps(compile(), sort_keys=True))
$ for i in $(seq 10); do python test.py; done
{"provider": {"aws": {"alias": "aws"}, "github": {"alias": "github"}}}
{"provider": {"aws": {"alias": "aws"}, "github": {"alias": "github"}}}
{"provider": {"github": {"alias": "github"}, "aws": {"alias": "aws"}}}
{"provider": {"aws": {"alias": "aws"}, "github": {"alias": "github"}}}
{"provider": {"aws": {"alias": "aws"}, "github": {"alias": "github"}}}
{"provider": {"github": {"alias": "github"}, "aws": {"alias": "aws"}}}
{"provider": {"github": {"alias": "github"}, "aws": {"alias": "aws"}}}
{"provider": {"github": {"alias": "github"}, "aws": {"alias": "aws"}}}
{"provider": {"github": {"alias": "github"}, "aws": {"alias": "aws"}}}
{"provider": {"github": {"alias": "github"}, "aws": {"alias": "aws"}}}

It seems like this is because of how the comparison dunder methods in terraformpy.objects.DuplicateKey use the hash:

def __eq__(self, other):
return self.__class__ == other.__class__ and self._hash == other._hash
def __lt__(self, other):
if self.__class__ == other.__class__:
return self._hash < other._hash
return super(DuplicateKey, self).__lt__(other)
def __le__(self, other):
if self.__class__ == other.__class__:
return self._hash <= other._hash
return super(DuplicateKey, self).__le__(other)
def __gt__(self, other):
if self.__class__ == other.__class__:
return self._hash > other._hash
return super(DuplicateKey, self).__gt__(other)
def __ge__(self, other):
if self.__class__ == other.__class__:
return self._hash >= other._hash
return super(DuplicateKey, self).__ge__(other)

In the specific case of providers, it crossed my mind that sorting by alias could be appropriate. But maybe DuplicateKey is used in other situations where there isn't a good field to sort on?

In looking into the Terraform/duplicate key JSON side of the issue, I learned that a JSON array of objects is also accepted.

So here's my current workaround (which relies on the Python 3.7+ dictionary insertion order guarantee):

dictionaries = compile()
provider_items = dictionaries["provider"].items()
if len(provider_items) > 1:
    assert sys.version_info >= (3, 7)
    provider_list = [{str(key): value} for key, value in provider_items]
    dictionaries["provider"] = provider_list
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant