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:
Haider Bari 2025-01-29 16:20:28 +00:00 committed by GitHub
parent 4083fe2cc4
commit 6614782e6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 25 additions and 4 deletions

View File

@ -406,6 +406,10 @@ func (c *RemoteClient) getLockInfo(ctx context.Context) (*statemgr.LockInfo, 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
if v, ok := resp.Item["Info"]; ok {
if v, ok := v.(*dtypes.AttributeValueMemberS); ok {
@ -430,9 +434,6 @@ func (c *RemoteClient) Unlock(id string) error {
lockErr := &statemgr.LockError{}
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)
if err != nil {
lockErr.Err = fmt.Errorf("failed to retrieve lock info: %w", err)
@ -445,11 +446,16 @@ func (c *RemoteClient) Unlock(id string) error {
return lockErr
}
// Use a condition expression to ensure both the lock info and lock ID match
params := &dynamodb.DeleteItemInput{
Key: map[string]dtypes.AttributeValue{
"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)

View File

@ -163,6 +163,21 @@ func TestForceUnlock(t *testing.T) {
if err = s2.Unlock(lockID); err != nil {
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) {