starhawking / python-terrascript

Create Terraform files using Python scripts.
BSD 2-Clause "Simplified" License
515 stars 76 forks source link

Acess Azure built in role definition permissions.actions #45

Closed guillaumedsde closed 6 years ago

guillaumedsde commented 6 years ago

Hi, I am creating an Azure Terraform file for deployment (I'm at the "messing around with it" stage).

Specifically I'm trying to create a custom role with permissions based on a default Azure custom role.

As per the this terrafor documntation : https://www.terraform.io/docs/providers/azurerm/d/builtin_role_definition.html I would like to acess the variable "${data.azurerm_builtin_role_definition.contributor.permissions.actions}"

data "azurerm_builtin_role_definition" "contributor" {
  name = "Contributor"
}

output "contributor_role_definition_id" {
  value = "${data.azurerm_builtin_role_definition.contributor.permissions.actions}"
}

hence here are my relevant terrascript lines:

builtinrole = ts.add(d.azurerm_builtin_role_definition("Contributor", name="Contributor"))
subscription = ts.add(d.subscription("primary"))

customRoleName = "testRole"
customRole = ts.add(azurerm_role_definition(customRoleName,
                                            name=customRoleName,
                                            role_definition_id=None,
                                            scope=subscription.id,
                                            description="This is a custom role created via Terraform with the same permissions as a Contributor",
                                            permissions={"actions": [builtinrole.permissions.actions],
                                                         "not_actions": [builtinrole.permissions.not_actions],
                                                         },
                                            # permissions=[builtinrole.permissions],
                                            assignable_scopes=[subscription.id],
                                            )
                    )

however this results in

Traceback (most recent call last):
  File "/home/guillaumedsde/PycharmProjects/champollion/champollion.py", line 273, in <module>
    permissions={"actions": [builtinrole.permissions.actions],
AttributeError: 'str' object has no attribute 'actions'

So I'm assuming that I can't really access elements of builtinrole.permissions.actions because it is essentially a string of the list of allowed actions if I understand this corretly?

So I'm essentially asking, how do I access builtinrole.permissions.actions instead of simply accessing builtinrole.permissions?

guillaumedsde commented 6 years ago

So I have found a very VERY getto way of accessing builtinrole.permissions.actions, by merging string together to essentially create the variable name, this solution is a very dirty hack:

actions = builtinrole.permissions[:-1] + ".0.actions}"
notActions = builtinrole.permissions[:-1] + ".0.not_actions}"
customRoleName = "testRole"
customRole = ts.add(azurerm_role_definition(customRoleName,
                                            name=customRoleName,
                                            role_definition_id=None,
                                            scope=subscription.id,
                                            description="This is a custom role created via Terraform with the same permissions as a Contributor",
                                            permissions={"actions": [actions],
                                                         "not_actions": [notActions],
                                                         },
                                            assignable_scopes=[subscription.id],
                                            )
                    )

@mjuenema I feel like I am misunderstanding the terrascript syntax, or mabye its just not something you can do with terrascript?

mjuenema commented 6 years ago

Hi @guillaumedsde , I just moved house and started a new job and unfortunately that leaves me with very little time for other things at the moment. I promise that I am going to look into this as soon as I can. Sorry!

austin-millan commented 6 years ago

@guillaumedsde,

I've noticed Python-Terrascript is pretty bare-bones, leaving a lot of work to the end users. So don't be too surprised if you're forced to use various workarounds like this. One option is to fork the project and make local modifications to allow you more flexibility out of this project.

Just a heads up on a little detail:

I would like to acess the variable "${data.azurerm_builtin_role_definition.contributor.permissions.actions}"

This actually isn't a variable, it's a string that Terraform can interpolate.

But regarding your original code, accessing attributes of Terrascript objects derived from _base: if you're trying to access your original values you used during construction, the object still retains the original values within it's _kwargs attribute. Example: builtinrole._kwargs['permissions'].

But if you use the dot operator (without using kwargs, which is typically the case), then each object uses the __getattr__(...) method here, which does some string transformations on it in a way that Terraform itself can resolve the attribute.

The most important note when using these objects is appending .id to get a representation of an object. This is ultimately what Terraform will use to resolve references between objects, for example when one Azure resources requires a reference to a Azure data source.

Other than that, I think quirks naturally go to the user.

While Terrascript is useful, there definitely some things missing. if I were you I'd be careful to not create a big work around in a project using Terrascript, when making small changes within Terrascript_ could work best.

mjuenema commented 6 years ago

Thanks Austin. Terrascript really started as a proof-of-concept to show that it is possible to generate Terraform configurations through Python. Now that people start using it with many different Terraform providers and resources, more and more of Terrascript's limitations, bugs and quirks(!) show up. As this is a private project and I am the only maintainer (big thanks to everyone who submitted pull requests) I have very limited time to address any issues. Unfortunately I have to ask you to be very patient. Thanks, Markus

guillaumedsde commented 6 years ago

@mjuenema Yes no problem, I read your response to other issues afterwards, should have read that before tagging you, good luck with unpacking and hope you settle well. (awesome project btw, you're saving me from that awful HCL Hashicorp Langugae with no modules and weird syntax)

@austin-millan Thanks a lot for your answer, the variable being a string rather than an actual variable was what got me confused at first. Ok, I understand the dot operator for terracript better, I see that my builtInRole's kwargs is an empty dictionnary, and it has its interpolated attribute, I tried to print it, and I think I stumbled into what might be a bug (not sure) in terrascript, might look into it later, because I found another solution

builtInRole = ts.add(d.builtin_role_definition("Owner"))

print(builtInRole.interpolated)
print(dir(builtInRole))

results in

/home/guillaumedsde/.virtualenvs/champollion/bin/python /home/guillaumedsde/PycharmProjects/champollion/champollion.py
Traceback (most recent call last):
  File "/home/guillaumedsde/PycharmProjects/champollion/champollion.py", line 252, in <module>
    print(builtInRole.interpolated)
  File "/home/guillaumedsde/.virtualenvs/champollion/lib/python3.6/site-packages/terrascript/__init__.py", line 181, in interpolated
    return '${{{}}'.format(self._fullname)
ValueError: Single '}' encountered in format string

anyways, I suspect builtInRole is just an "empty shell" as you said with just the variable name as a string, that is OK, I found another solution for my data sources: I am getting Azure's built in role permission from the Azure Python SDK, it works like a charm

austin-millan commented 6 years ago

@guillaumedsde I also prefer Python syntax over HCL. Plus you can imperatively create objects instead of declaratively, which is a paradigm that I'm more comfortable with.

Regarding interpolated: I actually have never directly referenced the interpolated attribute. Maybe try using the interpolated method instead? And maybe check if it happens for all Terrascript data sources / resources?

guillaumedsde commented 6 years ago

I gave up on interpolation, closing this issue, as I solved my problem by "simply" fetching the permissions of the object I wanted through the python SDK for Azure, if you are looking to let terraform set these variables, scroll up and see my other solution (hacky).