mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Improved error messages for lock-related problems in the s3
backend (#2410)
Signed-off-by: Bari, Haider <haider.bari@fmr.com> Co-authored-by: Bari, Haider <haider.bari@fmr.com>
This commit is contained in:
parent
4083fe2cc4
commit
6614782e6d
@ -406,6 +406,10 @@ func (c *RemoteClient) getLockInfo(ctx context.Context) (*statemgr.LockInfo, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(resp.Item) == 0 {
|
||||||
|
return nil, fmt.Errorf("no lock info found for: %q within the DynamoDB table: %s", c.lockPath(), c.ddbTable)
|
||||||
|
}
|
||||||
|
|
||||||
var infoData string
|
var infoData string
|
||||||
if v, ok := resp.Item["Info"]; ok {
|
if v, ok := resp.Item["Info"]; ok {
|
||||||
if v, ok := v.(*dtypes.AttributeValueMemberS); ok {
|
if v, ok := v.(*dtypes.AttributeValueMemberS); ok {
|
||||||
@ -430,9 +434,6 @@ func (c *RemoteClient) Unlock(id string) error {
|
|||||||
lockErr := &statemgr.LockError{}
|
lockErr := &statemgr.LockError{}
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
// TODO: store the path and lock ID in separate fields, and have proper
|
|
||||||
// projection expression only delete the lock if both match, rather than
|
|
||||||
// checking the ID from the info field first.
|
|
||||||
lockInfo, err := c.getLockInfo(ctx)
|
lockInfo, err := c.getLockInfo(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %w", err)
|
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %w", err)
|
||||||
@ -445,11 +446,16 @@ func (c *RemoteClient) Unlock(id string) error {
|
|||||||
return lockErr
|
return lockErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use a condition expression to ensure both the lock info and lock ID match
|
||||||
params := &dynamodb.DeleteItemInput{
|
params := &dynamodb.DeleteItemInput{
|
||||||
Key: map[string]dtypes.AttributeValue{
|
Key: map[string]dtypes.AttributeValue{
|
||||||
"LockID": &dtypes.AttributeValueMemberS{Value: c.lockPath()},
|
"LockID": &dtypes.AttributeValueMemberS{Value: c.lockPath()},
|
||||||
},
|
},
|
||||||
TableName: aws.String(c.ddbTable),
|
TableName: aws.String(c.ddbTable),
|
||||||
|
ConditionExpression: aws.String("Info = :info"),
|
||||||
|
ExpressionAttributeValues: map[string]dtypes.AttributeValue{
|
||||||
|
":info": &dtypes.AttributeValueMemberS{Value: string(lockInfo.Marshal())},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_, err = c.dynClient.DeleteItem(ctx, params)
|
_, err = c.dynClient.DeleteItem(ctx, params)
|
||||||
|
|
||||||
|
@ -163,6 +163,21 @@ func TestForceUnlock(t *testing.T) {
|
|||||||
if err = s2.Unlock(lockID); err != nil {
|
if err = s2.Unlock(lockID); err != nil {
|
||||||
t.Fatal("failed to force-unlock named state")
|
t.Fatal("failed to force-unlock named state")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No State lock information found for the new workspace. The client should throw the appropriate error message.
|
||||||
|
secondWorkspace := "new-workspace"
|
||||||
|
s2, err = b2.StateMgr(secondWorkspace)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = s2.Unlock(lockID)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected an error to occur:", err)
|
||||||
|
}
|
||||||
|
expectedErrorMsg := fmt.Errorf("failed to retrieve lock info: no lock info found for: \"%s/env:/%s/%s\" within the DynamoDB table: %s", bucketName, secondWorkspace, keyName, bucketName)
|
||||||
|
if err.Error() != expectedErrorMsg.Error() {
|
||||||
|
t.Errorf("Unlock() error = %v, want: %v", err, expectedErrorMsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoteClient_clientMD5(t *testing.T) {
|
func TestRemoteClient_clientMD5(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user