Closed sst-yde closed 3 months ago
To clarify this: Terraform will manage all attributes of the ldap entry except those listed in ignore_changes
. You need to import an entry to manage it with Terraform.
But what you're saying is that Terraform would also manage attributes of an imported entry although they're listed in ignore_changes
? Did I get that right?
Yes, exactly. Even though the entries are listed in ignore_changes
, Terraform tries to manage these entries.
I'm working on the same issue as @sst-yde who is currently out of office. The deployment error above clearly shows in the build plan that Terraform tries to manage all attributes, even those that should be ignored.
On the server side, we also see a list of various attributes in the modify request, but in the example only sstOpenStackId
is specified to be set (updated) by Terraform.
We tried several scenarios, with and without importing the state, swapping different attributes in the ignore_changes
list and even updated the read/write permissions for this user. It always ended up with the same issue, that the attributes in the ignore_changes
list are showing up in the build plan to be changed or deleted.
Our use case is that we want to only update (respectively let Terraform manage) a single attribute, leaving everything else as it is. So therefore we specified everything else in the ignore_changes
list.
Please let us know if you need any additional information.
The problem appears to only occur if you don't specify the attributes. So a current workaround could be to just add them to the "attributes" map with bogus values like "IGNORED" or something.
Working on a fix.
I've implemented a fix (hopefully) in https://github.com/dodevops/terraform-provider-ldap/tree/feature/logging-and-replace
Can you please try it?
Thank you for the update!
Unfortunately this did not fix the issue for us. With the patech applied, the provider fails in the planning step:
Planning failed. Terraform encountered an error while generating this plan.
╷
│ Error: Provider produced invalid plan
│
│ Provider "registry.terraform.io/dodevops/ldap" planned an invalid value for
│ ldap_object.ldap_write_openstack.attributes: planned value
│ cty.MapVal(map[string]cty.Value{"description":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstOpenStackId":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")})})
│ does not match config value
│ cty.MapVal(map[string]cty.Value{"sstOpenStackId":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")})})
│ nor prior value
│ cty.MapVal(map[string]cty.Value{"description":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstBelongsToCustomerUID":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstBelongsToDomainID":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstBelongsToResellerUID":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstBillable":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstConsolidatedBill":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstIsActive":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstIsIaaSProject":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstNetworkHostnameFormat":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstOpenStackId":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstOpenStackName":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstProvisioningExecutionDate":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstProvisioningMode":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstProvisioningState":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "sstRegion":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")}),
│ "uid":cty.ListVal([]cty.Value{cty.StringVal("REDACTED")})}).
│
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.
╵
Respectively the output below when setting everything else to IGNORED
:
This is really a hard one and I sadly don't have a solution currently. 😞
I'm sorry to tell you, but we have decided to discontinue this provider as we're not using it anymore. If you like or know somebody who might like to adopt it, we're open for that.
Thank you.
Current behaviour:
When you want to change a single attribute with the Terraform LDAP provider, it always tries to import the whole entry into the state and update all attributes.
Terraform example:
```tf # See http://wiki.stoney-cloud.org/wiki/stoney_cloud:_OpenLDAP_directory_data_organisation#Domain_.28reseller.29_example resource "ldap_object" "ldap_write" { dn = "uid=4000000,ou=domains,ou=openstack,ou=services,dc=stoney-cloud,dc=org" object_classes = [ "top", "sstOpenStackDomain", "sstProvisioning", "sstRelationship", ] attributes = { sstOpenStackId = [module.stepping_stone_ag_test.identity_project_v3_id] } # Ignore everything else: ignore_changes = [ "description", "sstBelongsToCustomerUID", "sstBelongsToDomainID", "sstBelongsToProjectID", "sstBelongsToResellerUID", "sstBusinessLogicRoleName", "sstCancellationDate", "sstDisplayName", "sstEnvironment", "sstIsActive", "sstIsIaaSDomain", "sstIsIaaSProject", "sstNetworkDomainName", "sstNetworkHostname", "sstOpenStackName", "sstOperatingSystem", "sstProvisioningExecutionDate", "sstProvisioningMode", "sstProvisioningState", "sstRegion", ] lifecycle { prevent_destroy = true } } ```Generated execution plan:
```tf Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # ldap_object.ldap_write will be created + resource "ldap_object" "ldap_write" { + attributes = { + "sstOpenStackId" = [ + "***REDACTED***", ] } + dn = "uid=4000000,ou=domains,ou=openstack,ou=services,dc=stoney-cloud,dc=org" + id = (known after apply) + ignore_changes = [ + "description", + "sstBelongsToCustomerUID", + "sstBelongsToDomainID", + "sstBelongsToProjectID", + "sstBelongsToResellerUID", + "sstBusinessLogicRoleName", + "sstCancellationDate", + "sstDisplayName", + "sstEnvironment", + "sstIsActive", + "sstIsIaaSDomain", + "sstIsIaaSProject", + "sstNetworkDomainName", + "sstNetworkHostname", + "sstOpenStackName", + "sstOperatingSystem", + "sstProvisioningExecutionDate", + "sstProvisioningMode", + "sstProvisioningState", + "sstRegion", ] + object_classes = [ + "top", + "sstOpenStackDomain", + "sstProvisioning", + "sstRelationship", ] } Plan: 1 to add, 0 to change, 0 to destroy. ```Deployment error:
```tf ldap_object.ldap_write: Creating... ╷ │ Error: Can not add resource │ │ with ldap_object.ldap_write, │ on main.tf line 17, in resource "ldap_object" "ldap_write": │ 17: resource "ldap_object" "ldap_write" { │ │ LDAP server reported: LDAP Result Code 65 "Object Class Violation": object │ class 'sstOpenStackDomain' requires attribute 'sstIsActive' ╵ ```We tried to work around this problem by importing the existing LDAP entry to the state. The following lines have been appended to the Terraform example above (requires Terraform >= 1.5.0):
Import state:
```tf import { to = ldap_object.ldap_write id = "uid=4000000,ou=domains,ou=openstack,ou=services,dc=stoney-cloud,dc=org" } ```But for some reason Terraform wants to remove all attributes then in the build plan and will fail because it cannot remove attributes like
uid
due the restricted permission.Deployment error:
```tf Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # ldap_object.ldap_write will be updated in-place # (imported from "uid=4000000,ou=domains,ou=openstack,ou=services,dc=stoney-cloud,dc=org") ~ resource "ldap_object" "ldap_write" { ~ attributes = { - "description" = [ - "***REDACTED***", ] -> null - "sstBelongsToCustomerUID" = [ - "***REDACTED***", ] -> null - "sstBelongsToResellerUID" = [ - "***REDACTED***", ] -> null - "sstIsActive" = [ - "***REDACTED***", ] -> null - "sstIsIaaSDomain" = [ - "***REDACTED***", ] -> null "sstOpenStackId" = [ "***REDACTED***", ] - "sstOpenStackName" = [ - "***REDACTED***", ] -> null - "sstProvisioningExecutionDate" = [ - "***REDACTED***", ] -> null - "sstProvisioningMode" = [ - "***REDACTED***", ] -> null - "sstProvisioningState" = [ - "***REDACTED***", ] -> null - "uid" = [ - "4000000", ] -> null } dn = "uid=4000000,ou=domains,ou=openstack,ou=services,dc=stoney-cloud,dc=org" id = "uid=4000000,ou=domains,ou=openstack,ou=services,dc=stoney-cloud,dc=org" + ignore_changes = [ + "description", + "sstBelongsToCustomerUID", + "sstBelongsToDomainID", + "sstBelongsToProjectID", + "sstBelongsToResellerUID", + "sstBusinessLogicRoleName", + "sstCancellationDate", + "sstDisplayName", + "sstEnvironment", + "sstIsActive", + "sstIsIaaSDomain", + "sstIsIaaSProject", + "sstNetworkDomainName", + "sstNetworkHostname", + "sstOpenStackName", + "sstOperatingSystem", + "sstProvisioningExecutionDate", + "sstProvisioningMode", + "sstProvisioningState", + "sstRegion", ] object_classes = [ "top", "sstOpenStackDomain", "sstProvisioning", "sstRelationship", ] } Plan: 1 to import, 0 to add, 1 to change, 0 to destroy. ```Expected behaviour:
Ignored attributes should not be touched by Terraform. If no values are specified, it should not import them into the state (they may also contain sensitive values like in your example). Maybe attributes that are not managed by Terraform shouldn't be touched at all if you don't create the whole entry. This may also need some clarification in documentation.
The showcase in this issue is related to: #36