-
Notifications
You must be signed in to change notification settings - Fork 118
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 a hash to random_password with StateUpgrader #254
Conversation
return diags | ||
} | ||
|
||
if d.Get("bcrypt_hash") == "" { |
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 attribute will always be empty on creation, so the conditional is unnecessary. 👍
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.
Removed conditional.
|
||
hash, err := generateHash(result) | ||
if err != nil { | ||
return nil, fmt.Errorf("resource password state upgrade failed, generate hash error: %v", err) |
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.
Conventionally after Go 1.13, it is recommended to use the %w
(wrapped error) formatter for errors.
This does leave an interesting question though, what errors can be generated and are they recoverable? If they are not recoverable (e.g. cannot be fixed by retrying), practitioners will be forever stuck with an unusable resource unless they pin to an older provider version or the state upgrade code is "fixed" or updated to skip on the generation error.
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.
Have wrapped the error.
The errors that can be generated relate to:
- checkCost - this should never return an error as we're using DefaultCost.
- io.ReadFull - this will return an error if maxSaltSize bytes cannot be read from rand.Reader.
- bcrypt - can return error if underlying cipher funcs return error.
) | ||
|
||
func resourcePassword() *schema.Resource { | ||
passwordSchema := stringSchemaV1(true) | ||
passwordSchema["bcrypt_hash"] = &schema.Schema{ |
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.
Since this new attribute is only handled on Create, e.g. not during Read, it will also need to be handled during Import.
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.
Have added handling of bcrypt_hash to import.
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.
Some nitpicks in regards to "function returning functions" that seems unnecessary, but seems like it's pretty much on the finish line.
) | ||
|
||
func resourcePassword() *schema.Resource { | ||
create := func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
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.
Nitpick: Why is this function defined inside inside the other function (lamba)?
I can't spot anything that would require this approach ❓
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.
Have removed.
} | ||
} | ||
|
||
func importPasswordFunc() schema.StateContextFunc { |
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 do you need a function that returns a function 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.
Have removed.
internal/provider/resource_string.go
Outdated
}, | ||
} | ||
} | ||
|
||
func importStringFunc() schema.StateContextFunc { |
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.
Same as above: having this function returning another function seem not necessary.
But I might be missing something.
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.
Have removed.
// passwordSchemaV1 uses passwordSchemaV0 to obtain the V0 version of the Schema key-value entries but requires that | ||
// the bcrypt_hash entry be configured. | ||
func passwordSchemaV1() map[string]*schema.Schema { | ||
passwordSchema := passwordSchemaV0() | ||
passwordSchema["bcrypt_hash"] = &schema.Schema{ | ||
Description: "A bcrypt hash of the generated random string.", | ||
Type: schema.TypeString, | ||
Computed: true, | ||
Sensitive: true, | ||
} | ||
|
||
return passwordSchema | ||
} | ||
|
||
// passwordSchemaV0 uses passwordStringSchema to obtain the default Schema key-value entries but requires that the id | ||
// description, result sensitive and bcrypt_hash entries be configured. | ||
func passwordSchemaV0() map[string]*schema.Schema { | ||
passwordSchema := passwordStringSchema() | ||
passwordSchema["id"].Description = "A static value used internally by Terraform, this should not be referenced in configurations." | ||
passwordSchema["result"].Sensitive = true | ||
|
||
return passwordSchema | ||
} | ||
|
||
// stringSchemaV1 uses passwordStringSchema to obtain the default Schema key-value entries but requires that the id | ||
// description be configured. | ||
func stringSchemaV1() map[string]*schema.Schema { | ||
stringSchema := passwordStringSchema() | ||
stringSchema["id"].Description = "The generated random string." | ||
|
||
return stringSchema | ||
} | ||
|
||
// passwordStringSchema returns map[string]*schema.Schema with all keys and values that are common to both the | ||
// password and string resources. |
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 like that all the schemas are now next to each other.
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.
After discussing the questions I had in my previous review, I'm providing an approval so you can proceed while you tweak those functions.
Co-authored-by: Ramon Rüttimann <[email protected]>
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.
👩🍳 😘
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.
Looks good to me 🚀 If you haven't already, I'd suggest running one last manual test using a real Terraform configuration that creates a password via 3.1.0, then uses development overrides with this branch to ensure the state upgrade goes smoothly.
I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions. |
This is evaluating whether the changes proposed in #73 can be combined with a StateUpgrader to avoid the situation where including the
bcrypt_hash
field generates an empty value in state on first use.Closes #73
Closes #102