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

Add provider/google/google_storage_bucket lifecycle interface #6

Merged
merged 12 commits into from
Jul 25, 2017

Conversation

pdecat
Copy link
Contributor

@pdecat pdecat commented Jun 12, 2017

This PR adds support for the lifecycle of google_storage_bucket resources as described in hashicorp/terraform#13882

TODO:

  • handle update
  • update acceptance tests
  • documentation

Supersedes PR in terraform repo: hashicorp/terraform#14802

PS: this is my first attempt at contributing code to Terraform, thank you for your indulgence, all feedback welcome.

@pdecat
Copy link
Contributor Author

pdecat commented Jun 13, 2017

I've added tests for update case and everything seems to be working fine without specific handling.

Am I missing anything?

@pdecat
Copy link
Contributor Author

pdecat commented Jun 13, 2017

Documentation added,

@pdecat pdecat changed the title [WIP] Add provider/google/google_storage_bucket lifecycle interface Add provider/google/google_storage_bucket lifecycle interface Jun 13, 2017
@@ -378,3 +448,135 @@ func flattenCors(corsRules []*storage.BucketCors) []map[string]interface{} {
}
return corsRulesSchema
}

func resourceGCSBucketLifecycleCreateOrUpdate(d *schema.ResourceData, sb *storage.Bucket, update bool) error {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

update is not used as of now and may be removed. I added it initially as I thought a special treatment was required for update case as opposed to creation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds reasonable to remove it then

Copy link
Contributor

@selmanj selmanj left a comment

Choose a reason for hiding this comment

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

Looks really good so far. Giving this review a quick first pass before someone else takes a look.

Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"number_of_newer_versions": {
Copy link
Contributor

Choose a reason for hiding this comment

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

The api describes this field as 'numNewerVersions' so I suppose it should be 'num_newer_versions' for consistency sake (although I do prefer this name, it's probably better to match the API).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough, done.

@@ -378,3 +448,135 @@ func flattenCors(corsRules []*storage.BucketCors) []map[string]interface{} {
}
return corsRulesSchema
}

func resourceGCSBucketLifecycleCreateOrUpdate(d *schema.ResourceData, sb *storage.Bucket, update bool) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds reasonable to remove it then

lifecycle_rules := v.([]interface{})

if len(lifecycle_rules) > 100 {
return fmt.Errorf("At most 100 lifecycle_rule blocks are allowed")
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be nice to print how many lifecycle_rules were actually found in the error message


if v, ok := lifecycle_rule["condition"]; ok {
condition := v.(*schema.Set).List()[0].(map[string]interface{})
condition_elements := 0
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than counting the condition elements (which might be harder to track later) how about just asserting that the condition map contains at least one expected key?

Actually, correct me if I'm wrong, but can you just say something like

if len(condition) < 1 {
  // Error here
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point! Added a MinItems: 1 on matches_storage_class to ensure it is not empty if specified.


* `storage_class` - (Required if action type is `SetStorageClass`) The target [Storage Class](https://cloud.google.com/storage/docs/storage-classes) of objects affected by this Lifecycle Rule. Supported values include: `MULTI_REGIONAL`, `REGIONAL`, `NEARLINE`, `COLDLINE`.

The `condition` block supports:
Copy link
Contributor

Choose a reason for hiding this comment

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

You might also note that at least one condition map entry is required

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, clarified this part.

@pdecat pdecat force-pushed the f-google-storage-bucket-lifecycle branch from dda7b77 to e1044e3 Compare June 20, 2017 17:45
@selmanj selmanj requested a review from paddycarver June 22, 2017 22:09
@pdecat pdecat force-pushed the f-google-storage-bucket-lifecycle branch 3 times, most recently from d0b46ef to 1dcb414 Compare June 29, 2017 06:05
Copy link
Contributor

@paddycarver paddycarver left a comment

Choose a reason for hiding this comment

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

This looks great! I only have a couple of nitpicks. Thanks so much for diving into this and for the interest in contributing to Terraform!

Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Set: resourceGCSBucketLifecycleRuleActionHash,
Copy link
Contributor

Choose a reason for hiding this comment

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

In theory, I'm not sure this is required, but I doubt there's much harm to including it.

Copy link
Contributor Author

@pdecat pdecat Jul 4, 2017

Choose a reason for hiding this comment

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

I had to dig a bit to find out the constraints. The XML API doc looks a bit more precise than the JSON API about those facts, but I may be wrongly mixing those two.

From the XML API :

Action Defines the action to be taken, which must contain one and only one specific action element. Required.

cf. https://cloud.google.com/storage/docs/xml-api/put-bucket-lifecycle#request_body_elements

From the JSON API:

A lifecycle management rule, which is made of an action to take and the condition(s) under which the action will be taken.

cf. https://cloud.google.com/storage/docs/json_api/v1/buckets#resource-representations

Copy link
Contributor

Choose a reason for hiding this comment

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

I meant, specifically, the custom hashing function. :)

Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Set: resourceGCSBucketLifecycleRuleConditionHash,
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, in theory I don't think this is required, but I don't see much harm in including it.

Copy link
Contributor Author

@pdecat pdecat Jul 4, 2017

Choose a reason for hiding this comment

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

Same as above, the XML API doc looks a bit more precise than the JSON API about those facts.

XML API:

Condition Defines the condition under which the action will be taken, which must contain at least one specific condition element. Required.

cf. https://cloud.google.com/storage/docs/xml-api/put-bucket-lifecycle#request_body_elements

JSON API:

The condition(s) under which the action will be taken.

cf. https://cloud.google.com/storage/docs/json_api/v1/buckets#resource-representations

lifecycle_rules := v.([]interface{})

len_lifecycle_rules := len(lifecycle_rules)
if len_lifecycle_rules > 100 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can use MaxItems on the resource for this and it will catch this before apply time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point! Done.

sb.Lifecycle.Rule = make([]*storage.BucketLifecycleRule, 0, len_lifecycle_rules)

for _, lifecycle_rule := range lifecycle_rules {
lifecycle_rule := lifecycle_rule.(map[string]interface{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Eeek! This is a particularly confusing bit of shadowing. Any chance we can give this a distinct name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed, fixed.

target_lifecycle_rule := &storage.BucketLifecycleRule{}

if v, ok := lifecycle_rule["action"]; ok {
action := v.(*schema.Set).List()[0].(map[string]interface{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Check for an empty list here, to avoid panics?

Copy link
Contributor Author

@pdecat pdecat Jul 4, 2017

Choose a reason for hiding this comment

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

I was relying on the Required schema constraint there but can add the check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that still required with MinItems and MaxItems set to 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added checks on actions list length.

Copy link
Contributor

Choose a reason for hiding this comment

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

I apologise, you were correct--MaxItems and MinItems would have handled that constraint for you. But the extra check also doesn't hurt.

}

if v, ok := lifecycle_rule["condition"]; ok {
condition := v.(*schema.Set).List()[0].(map[string]interface{})
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, check for empty list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that still required with MinItems and MaxItems set to 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added checks on conditions list length.

condition := v.(*schema.Set).List()[0].(map[string]interface{})

if len(condition) < 1 {
return fmt.Errorf("At least one condition element is required")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we could use MinItems to catch this prior to apply time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Also, I forgot the same check on the action.

Copy link
Contributor Author

@pdecat pdecat Jul 4, 2017

Choose a reason for hiding this comment

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

I think I remember why I implemented this check differently at first by incrementing a counter: 545e5b5

From the XML API doc:

Condition Defines the condition under which the action will be taken, which must contain at least one specific condition element. Required.

cf. https://cloud.google.com/storage/docs/xml-api/put-bucket-lifecycle#request_body_elements

@pdecat pdecat force-pushed the f-google-storage-bucket-lifecycle branch from 1dcb414 to 3381e9f Compare July 4, 2017 11:13
@pdecat pdecat force-pushed the f-google-storage-bucket-lifecycle branch from 326e42e to a0ba61a Compare July 17, 2017 09:47
@pdecat
Copy link
Contributor Author

pdecat commented Jul 17, 2017

Hi, I believe all issues were addressed.

Copy link
Contributor

@paddycarver paddycarver left a comment

Choose a reason for hiding this comment

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

LGTM with the changes 👍 Great work @pdecat, thanks for tackling this. Sorry for the delay on finishing my review--I was off on vacation.

@selmanj anything further to add before we get this merged?

@selmanj
Copy link
Contributor

selmanj commented Jul 25, 2017

Looks good to me!

@paddycarver paddycarver merged commit 775d931 into hashicorp:master Jul 25, 2017
negz pushed a commit to negz/terraform-provider-google that referenced this pull request Oct 17, 2017
…fecycle

Add provider/google/google_storage_bucket lifecycle interface
@pdecat pdecat deleted the f-google-storage-bucket-lifecycle branch March 7, 2018 09:00
chrisst referenced this pull request in chrisst/terraform-provider-google Nov 9, 2018
Add provider/google/google_storage_bucket lifecycle interface
@ghost
Copy link

ghost commented Mar 29, 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. If you feel I made an error 🤖 🙉 , please reach out to my human friends 👉 [email protected]. Thanks!

@ghost ghost locked and limited conversation to collaborators Mar 29, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants