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

New Resource: aws_cognito_identity_provider #3601

Merged

Conversation

pawelsocha
Copy link

@pawelsocha pawelsocha commented Mar 2, 2018

Overview

New resource to create identity provider for Cognito user pool.

This PR solves #3279

Tests

TF_ACC=1 go test ./... -v -run=TestAccAWSCognitoIdentityProvider_basic -timeout 120m
?   	github.com/terraform-providers/terraform-provider-aws	[no test files]
=== RUN   TestAccAWSCognitoIdentityProvider_basic
--- PASS: TestAccAWSCognitoIdentityProvider_basic (42.71s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	42.747s```

@ghost ghost added the size/XS Managed by automation to categorize the size of a PR. label Mar 2, 2018
@bflad bflad added new-resource Introduces a new resource. service/cognito labels Mar 2, 2018
@ghost ghost added size/L Managed by automation to categorize the size of a PR. and removed size/XS Managed by automation to categorize the size of a PR. labels Mar 6, 2018
@pawelsocha
Copy link
Author

@bflad maybe you know how to handle perpetual diffs for TypeMap variable?

@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Mar 7, 2018
@pawelsocha pawelsocha changed the title [WIP] new resource aws_cognito_identity_provider new resource aws_cognito_identity_provider Mar 7, 2018
@radeksimko radeksimko changed the title new resource aws_cognito_identity_provider New Resource: aws_cognito_identity_provider Mar 23, 2018
@leonfs
Copy link

leonfs commented Apr 16, 2018

Any idea on when this PR will get merged?

At the moment as soon as you change/add/remove a Provider through the console terraform, for some unexpected reason, tries to recreate the user pool.

@pawelsocha
Copy link
Author

@leonfs thanks for your feedback. I will check this :-)

@leonfs
Copy link

leonfs commented Apr 16, 2018

@pawelsocha No worries, thanks for making this PR.

Though the bug I mentioned earlier does not have anything to do with your code but with the current implementation of the aws_cognito_user_pool_client.

I suspect that after adding an identity provider (let's say Google) to the user pool through AWS console, the api call to AWS from Terraform returns an array with Google as value in the suppoted-Idenityt_providers field. Therefore, terraform state is different from what it is in AWS.

For some reason Terraform tries to recreate the whole resource (it shouldn't as it's a value that can change after creation).

I'm wondering if with this PR the problem will actually be solved. Or it's a different problem.

@pawelsocha
Copy link
Author

@leonfs yeap, something is wrong.
I trying to catch this mismatch between plan and apply.

My example:

In aws_cognito_user_pool:
Mismatch reason: attribute mismatch: schema.1914614485.string_attribute_constraints.0.max_length

So, debugging in progress :-)

@pawelsocha
Copy link
Author

@leonfs Terraform recreate aws_cognito_user_pool_client resource every apply/plan because it's affected by TypeSet implementation in TF: hashicorp/terraform#15420 (comment)

And also in resource source attribute have ForceNew set to true:

		"schema": {
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,

@leonfs
Copy link

leonfs commented Apr 17, 2018

@pawelsocha That's interesting. What I don't understand this is when a change in the schema attributes happen.

What triggered for me the change was adding/changing and identity provider (Google). What link could exist between those 2 things?

@pawelsocha
Copy link
Author

@leonfs change is forced by resource definition in code.

@leonfs
Copy link

leonfs commented Apr 17, 2018

@pawelsocha - Not really sure if I get what you are saying.

I can see that there is a field ForceNew: true but that means that if the schema attribute has changed then the whole resource aws_cognito_user_pool would be recreated.

But when I change/add the identity provider I don't change the schema attribute. So why would that force the recreation?

@pawelsocha
Copy link
Author

@leonfs when tf recreating aws_cognito_user_pool generate new resource ID and this id is used in identity provider.

@leonfs
Copy link

leonfs commented Apr 17, 2018

@pawelsocha Not really sure about what you are saying. Does not really make sense. TF should not recreate the aws_cognito_user_pool in the first place, and that's the problem. But the good news is that I've found a solution to the problem by digging a bit more into the plan output.

It looks like AWS adds a custom attribute called identities as soon as you add an identity provider to the user pool. This is what's making the set of schemas to change.

The problem is fixed by adding the following schema attribute.

schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "identities"

    string_attribute_constraints {}
  }

Notice the empty string_attribute_constraint. This is a bug in the cognito module. You can't not include it as that would generate a change in the plan on every apply.

See issues:

In any case - thanks for the feedback and looking forward to your PR getting merged.

@pawelsocha
Copy link
Author

pawelsocha commented Apr 17, 2018

@leonfs :-) Today I had only a few hours to investigate this problem. But, in my case terraform recreate the whole resource and create new ID (exactly like in #3891)
And I found this info: https://github.com/terraform-providers/terraform-provider-aws/blob/b8857d88b3cc0fe2cb208c8a36508ec531251155/aws/structure.go#L3005-L3007

Now I know. Aws add some extra attributes to the resource.

One question: in your plan - terraform shows change in the schema with identity?

@skoop22
Copy link

skoop22 commented May 2, 2018

@pawelsocha
I had the same issue when creating a workaround for this not yet existing feature.
AWS adds identities to the schema "Automagically" could not find any doc on it ...
As a workaround I added identities to my aws_cognito_user_pool.

  resource "aws_cognito_user_pool" "cognito_userpool" {
  name = "${var.cognito_user_pool_name}"

  tags {
    Name = "Cognito Userpool"
    CreatedBy = "terraform"
    Environment = "${var.environment}"
    Application = "${var.application}"
  }
  schema {
    attribute_data_type = "String"
    name = "email"
    required = true
    mutable = true
    string_attribute_constraints {
      min_length = 0
      max_length = 2048
    }
  }
  schema {
    attribute_data_type = "String"
    name = "identities"
    mutable = true
    string_attribute_constraints {
    }
  }
}

resource "aws_cognito_user_pool_domain" "cognito_domain" {
  user_pool_id = "${aws_cognito_user_pool.cognito_userpool.id}"
  domain = "${var.cognito_user_pool_name}"
}


data "template_file" "cognito_userpool_template" {
  template = "${file("cognito_userpool_identityprovider_template/cognito_userpool_identityprovider_template.js")}"
  vars {
    userPoolId = "${aws_cognito_user_pool.cognito_userpool.id}"
    environment = "${var.environment}"
    metaDataUrl = "${var.saml_metadataurl}"

  }
}

resource "null_resource" "create_cognito_userpool_federation" {
  triggers {
    cognito_user_pool_id = "${aws_cognito_user_pool.cognito_userpool.id}"
  }

  provisioner "local-exec" {
    command = "aws cognito-idp create-identity-provider --region ${var.aws_region} --cli-input-json '${data.template_file.cognito_userpool_template.rendered}'"
  }
}

@pawelsocha
Copy link
Author

@skoop22 Thanks for your research.
Now I thinking how to solve this problem. The first thing is filter schema attributes in the aws_cognito_user_pool resource. Second, add identity provider directly to the aws_cognito_user_pool resource.

But, I'm not a terraform developer.

log.Print("[DEBUG] Updating Cognito Identity Provider")

params := &cognitoidentityprovider.UpdateIdentityProviderInput{
UserPoolId: aws.String(d.Get("UserPoolId").(string)),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering... is "d.Get("UserPoolId") correct? Or should it be: d.Get("user_pool_id")?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will change it.


"user_pool_id": {
Type: schema.TypeString,
Required: true,
Copy link

@ldenman ldenman May 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should user_pool_id be ForceNew? If the pool id changes, wouldn't a new provider need to be created?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label May 4, 2018
@skoop22
Copy link

skoop22 commented May 16, 2018

Any news on this one I want to remove my workaround :)

Copy link
Contributor

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @pawelsocha! 👋 Thanks for submitting this! I left some feedback below which I'll try to address myself right now. If I can get this fixed up tonight, I'll get this in for the v1.21.0 release.

"provider_details": {
Type: schema.TypeMap,
Optional: true,
Computed: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this was intentional, but it does not seem like we should be ignoring this from the API if its not in the Terraform configuration. I'll double check from the acceptance testing. Also, the API/SDK documentation seems to imply this should be Required: true.

return fmt.Errorf("Error creating Cognito Identity Provider: %s", err)
}

d.SetId(*name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to easily support import, let's prepend the resource ID with the user pool ID:

d.SetId(fmt.Sprintf("%s:%s", userPoolID, providerName))

Then with configuring the passthrough Importer in the resource, we can support import via terraform import aws_cognito_identity_provider.example xxx_yyyyyy:example

})

if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: we have a helper function to simplify this logic: isAWSErr(err, cognitoidentity.ErrCodeResourceNotFoundException, "")


if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" {
d.SetId("")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When removing a resource from the state, we prefer to provide a warning log, e.g.

log.Printf("[WARN] Cognito Identity Provider %q not found, removing from state", d.Id())

return err
}

ip := ret.IdentityProvider
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should perform a nil check here in the unlikely scenario that the API does not error and also omits this attribute.

Steps: []resource.TestStep{
{
Config: testAccAWSCognitoIdentityProviderConfig_basic(),
Check: resource.ComposeAggregateTestCheckFunc(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing an testAccCheckAWSCognitoIdentityProviderExists() function, which we usually call first in a set of checks to help determine if the physical resource exists in the API as well as pass back the API response object back as a variable we can later reference in other checks.

return nil
}

func testAccAWSCognitoIdentityProviderConfig_basic() string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: the formatting is fairly inconsistent throughout this test configuration which makes it harder to read

return m
}

func flattenCognitoIdentityProviderMap(config map[string]*string) map[string]string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AWS SDK already provides a helper function to perform this: aws.StringValueMap()

@@ -3035,6 +3035,23 @@ func flattenCognitoIdentityPoolRoles(config map[string]*string) map[string]strin
return m
}

func expandCognitoIdentityProviderMap(config map[string]interface{}) map[string]*string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a (admittedly hard to find) helper function to perform this already: stringMapToPointers()


```hcl
resource "aws_cognito_user_pool" "example" {
name = "example-pool"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nitpick: the formatting is slightly off in the example configuration here and below with email

@bflad bflad added this to the v1.21.0 milestone May 31, 2018
@bflad
Copy link
Contributor

bflad commented May 31, 2018

After implementing the above feedback, I was able to get the acceptance testing working by ignoring the identities schema attribute in the user pool resource -- I believe this will be the correct path forward rather than forcing everyone to define that attribute in their schema if they also implement this resource.

make testacc TEST=./aws TESTARGS='-run=TestAccAWSCognitoIdentityProvider_basic'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./aws -v -run=TestAccAWSCognitoIdentityProvider_basic -timeout 120m
=== RUN   TestAccAWSCognitoIdentityProvider_basic
--- PASS: TestAccAWSCognitoIdentityProvider_basic (16.53s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	16.567s

@bflad bflad merged commit e0bc329 into hashicorp:master May 31, 2018
bflad added a commit that referenced this pull request May 31, 2018
@bflad
Copy link
Contributor

bflad commented May 31, 2018

This has been released in version 1.21.0 of the AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

@pawelsocha
Copy link
Author

@bflad thanks for your review. it's lots of knowledge for me.

@pawelsocha pawelsocha deleted the aws_cognito_identity_provider branch May 31, 2018 06:17
@ghost
Copy link

ghost commented Apr 5, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

@ghost ghost locked and limited conversation to collaborators Apr 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
new-resource Introduces a new resource. size/L Managed by automation to categorize the size of a PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants