-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Adds support for creating KMS KeyRing resources #518
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is off to a really good start! Most of my comments are just nitpicks. I haven't run the tests yet; I'll wait until you feel this is ready for more review.
google/resource_kms_key_ring.go
Outdated
|
||
parent := createKmsResourceParentString(project, location) | ||
|
||
_, err = config.clientKms.Projects.Locations.KeyRings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: for consistency with other resources, I'd recommend either not breaking at all or breaking after Create(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm not sure what you mean by this. Could you give me another resource to look at as an example?
google/resource_kms_key_ring.go
Outdated
} | ||
} | ||
|
||
func createKmsResourceParentString(project, location string) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
readability nit: I'm not a huge fan of create
being used in functions that don't actually create something, especially in a code base like this where it realistically could be making API calls. How about just kmsResourceParentString
?
google/resource_kms_key_ring.go
Outdated
return fmt.Errorf("Error reading KeyRing: %s", err) | ||
} | ||
|
||
d.SetId(keyRing.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we usually set the id again on read- any reason why you needed it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I saw another resource do this, but I can't remember where I saw it. I'll remove this.
google/resource_kms_key_ring_test.go
Outdated
|
||
func testGoogleKmsKeyRing_basic(name string) string { | ||
return fmt.Sprintf(` | ||
resource "google_kms_key_ring" "key_ring" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit- can you align this all the way to the left?
google/resource_kms_key_ring_test.go
Outdated
}) | ||
} | ||
|
||
func testGoogleKmsKeyRing_basic(name string) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a good reason behind this, but we tend to keep these functions at the end of the file
google/resource_kms_key_ring_test.go
Outdated
|
||
// TODO | ||
// KMS KeyRings cannot be deleted. This will test if the resource can be added back to state after being removed | ||
func testGoogleKmsKeyRing_recreate(name string) resource.TestCheckFunc { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the resource already exists server-side, we can add import functionality instead of trying to get it to essentially import on create.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the expected behavior of attempting to create a KeyRing that already exists? Should it fail because the resource already exists on the server? Or should it handle it similar to how an import would?
I think most resources would fail here because you'd expect to have to use terraform import
for resources not managed by terraform. This seems like a special situation though, because for all other resources, you can do terraform destroy
and terraform apply
to re-create your infrastructure without having to modify the names of any of your resources. If calling Create
for a KMS Keyring fails for KeyRings that already exist on the server, you wouldn't be able to do this.
In either case, my intention was for this test to capture that logic, where I either expect a failure when re-creating, or for it to be handled gracefully.
Thanks for the comments @danawillow. I was planning on setting aside some time tonight to work on this some more, and I can address your comments then. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right, I consulted @paddycarver and we think the best option is to remove from state on delete, comment in the code why that's happening, log that the resource itself isn't actually being deleted and why, and make sure we have solid documentation around it. Then create should throw an error because we don't want users to assume they can actually delete+recreate a keyring (since if delete were real, then deleting and recreating would probably delete its contents, and we don't want users to be surprised that the contents of the keyring didn't actually get deleted when they delete+recreate). Sound reasonable?
google/resource_kms_key_ring_test.go
Outdated
parent := kmsResourceParentString(project, location) | ||
keyRingName := kmsResourceParentKeyRingName(project, location, name) | ||
|
||
listKeyRingsResponse, err := config.clientKms.Projects.Locations.KeyRings.List(parent).Do() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why list rather than get?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used list because I don't like it when my tests look similar to the production code. I thought this would be a good way to still test the intended functionality without making it too similar to Read
.
I am open to changing it if you would like me to.
That sounds good. I'm guessing that means |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For import- yup, it would work the same. Right now this one doesn't support import, so if it's not too much to ask you could add it, but I won't block this PR on import support.
$ make testacc TEST=./google TESTARGS='-run=TestAccGoogleKmsKeyRing_basic' GOOGLE_USE_DEFAULT_CREDENTIALS=true
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./google -v -run=TestAccGoogleKmsKeyRing_basic -timeout 120m
=== RUN TestAccGoogleKmsKeyRing_basic
--- PASS: TestAccGoogleKmsKeyRing_basic (57.63s)
PASS
ok github.com/terraform-providers/terraform-provider-google/google 57.789s
All that's missing now is docs for the website (and also you need to run make fmt
)
google/resource_kms_key_ring.go
Outdated
|
||
parent := kmsResourceParentString(project, location) | ||
|
||
keyRing, err := config.clientKms.Projects.Locations.KeyRings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry to point this out again, but mind fixing the style here and elsewhere? https://github.com/golang/go/wiki/CodeReviewComments#line-length
I think one line would be fine, two is also fine (we usually break after the left paren)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I don't think I understood before but I see what you're saying now. I'll change it to a single line.
google/resource_kms_key_ring.go
Outdated
func resourceKmsKeyRingDelete(d *schema.ResourceData, meta interface{}) error { | ||
keyRingName := d.Id() | ||
|
||
log.Printf("[INFO] KMS KeyRing resources cannot be deleted from GCP. This KeyRing %s will be removed from Terraform state, but will still be present on the server.", keyRingName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do WARNING juuuuuuust in case
google/resource_kms_key_ring_test.go
Outdated
func testGoogleKmsKeyRing_basic(projectId, projectOrg, projectBillingAccount, keyRingName string) string { | ||
return fmt.Sprintf(` | ||
resource "google_project" "acceptance" { | ||
name = "%s" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you fix the formatting here? I think you just have a mix of tabs and spaces
@danawillow Thanks for your comments. I went ahead and added import functionality, so if you could review that, I would appreciate it. I'll leave some comments myself where I had questions. Also, I just exceeded my project creation quota for the GCP free trial, so I won't be able to run my acceptance test locally anymore 😅 I will work on adding the docs tomorrow so this can get wrapped up. Thanks for your patience! |
@danawillow I addressed your comments and added the documentation page. Please let me know if there's anything you'd like me to change. If you could run the acceptance tests for me, I'd appreciate that as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$ make testacc TEST=./google TESTARGS='-run=TestAccGoogleKmsKeyRing' GOOGLE_USE_DEFAULT_CREDENTIALS=true
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./google -v -run=TestAccGoogleKmsKeyRing -timeout 120m
=== RUN TestAccGoogleKmsKeyRing_importBasic
--- FAIL: TestAccGoogleKmsKeyRing_importBasic (52.52s)
testing.go:435: Step 1 error: ImportStateVerify attributes not equivalent. Difference is shown below. Top is actual, bottom is expected.
(map[string]string) {
}
(map[string]string) (len=1) {
(string) (len=7) "project": (string) (len=20) "terraform-68vpmb0ovk"
}
=== RUN TestAccGoogleKmsKeyRing_basic
--- PASS: TestAccGoogleKmsKeyRing_basic (54.80s)
FAIL
exit status 1
FAIL github.com/terraform-providers/terraform-provider-google/google 107.520s
make: *** [testacc] Error 1
google/resource_kms_key_ring_test.go
Outdated
func testGoogleKmsKeyRing_basic(projectId, projectOrg, projectBillingAccount, keyRingName string) string { | ||
return fmt.Sprintf(` | ||
resource "google_project" "acceptance" { | ||
name = "%s" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you fix the formatting here? I think you've got a spaces vs tabs issue (we usually use tabs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, my editor automatically converts tabs to spaces for me. I can fix this.
google/resource_kms_key_ring_test.go
Outdated
func testGoogleKmsKeyRing_removed(projectId, projectOrg, projectBillingAccount string) string { | ||
return fmt.Sprintf(` | ||
resource "google_project" "acceptance" { | ||
name = "%s" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here too
--- | ||
layout: "google" | ||
page_title: "Google: google_kms_key_ring" | ||
sidebar_current: "docs-google-kms-key-ring-x" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why x?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file I was using as a reference had it as well. I'll remove it.
I'm not sure I understand this failure. Is it complaining because it tried to import the project as well? I ran this test last night without setting up the extra project (I just commented out the |
1320d98
to
3fbf0bb
Compare
It's checking that the resource that got imported has exactly the same configuration as the one in the test. Since the one in the test had
The other ways to solve this would be to add the set in the Read fn or just always do it in Import, but I kind of like the idea that you only need to set "project" on your resource if the project doesn't match the one in the config. |
That makes perfect sense, thank you for explaining it to me. I must be remembering incorrectly, because there's no way that test would have passed just by commenting out the I'll use the block of code you posted and add it to |
Looks good, thanks @mrparkers! |
@danawillow @mrparkers Sorry if this has already been addressed, but I am confirming behavior on v0.11.1 that due to the immutability of key rings, a destroy and subsequent create will fail with the following error:
What's the proper way to handle this kind of scenario? Any help appreciated. Thanks! |
Hey @jasonjho, is your goal to get the key ring back into your terraform state? If so, you can import it: https://www.terraform.io/docs/providers/google/r/google_kms_key_ring.html#import. It sounds like a data source would be a good fit for this type of scenario too- feel free to file a feature request for one. |
* Instantiate the cloudkms client * Implement Create and Read for the kms key ring resource * Expose the kms key ring resource * Create acceptance test for creating a KeyRing, fix read to use KeyRing ID * Add cloudkms library to vendor * Address style comments * Use fully-qualified keyring name in read operation * Remove call to SetId during read operation * Set ID as entire resource string * Spin up a new project for acceptance test * Use Getenv for billing and org environment variables * And test and logs around removal from state * Add comments * Fixes formatting * Log warning instead of info * Use a single line for cloudkms client actions * Add resource import test * Add ability to import resource, update helper functions to use keyRingId struct * Use shorter terraform ID for easier import * Update import test to use the same config as the basic test * Update KeyRing name regex to be consistent with API docs * Add documentation page for resource * Add KeyRing documentation to sidebar * Adds unit tests around parsing the KeyRing import id * Allow for project in id to be autopopulated from config * Throw error in import if project provider is not provided for location/name format * Consistent variable names * Use tabs in resource config instead of spaces * Remove "-x" suffix for docs * Set project attribute on import if different from the project config
Signed-off-by: Modular Magician <[email protected]>
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. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks! |
Discussion in #441
I'm mostly looking for advice on what I could be doing better as I continue to work on this in my spare time.