Skip to content

Commit 2aee868

Browse files
openstack destroy: account for BULK DELETE limits on object-storage
Some object-storage instances may be set to have a limit to the LIST operation that is higher to the limit to the BULK DELETE operation. On those clouds, objects in the BULK DELETE call beyond the limit are silently ignored. As a consequence, the call to destroy the container fails and object deletion is re-queued after a growing waiting time, potentially dilating deletion by hours. With this change, object bulk deletion is put in a loop. After checking that no errors were encountered, we reduce the BULK DELETE list by the number of processed objects, and send it back to the server. As a consequence, the object deletion routines should only complete when the container is emtpy, thus avoiding the 409 error that causes a retry.
1 parent c0166e8 commit 2aee868

File tree

1 file changed

+23
-13
lines changed

1 file changed

+23
-13
lines changed

pkg/destroy/openstack/openstack.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,21 +1099,31 @@ func deleteContainers(opts *clientconfig.ClientOpts, filter Filter, logger logru
10991099
return false, err
11001100
}
11011101
queue.Add(func() {
1102-
logger.Debugf("Initiating bulk deletion of %d objects in container %q", len(objectsOnPage), container)
1103-
resp, err := objects.BulkDelete(conn, container, objectsOnPage).Extract()
1104-
if err != nil {
1105-
errCh <- err
1106-
return
1107-
}
1108-
if len(resp.Errors) > 0 {
1109-
// Convert resp.Errors to golang errors.
1110-
// Each error is represented by a list of 2 strings, where the first one
1111-
// is the object name, and the second one contains an error message.
1112-
for _, objectError := range resp.Errors {
1113-
errCh <- fmt.Errorf("cannot delete object %q: %s", objectError[0], objectError[1])
1102+
for len(objectsOnPage) > 0 {
1103+
logger.Debugf("Initiating bulk deletion of %d objects in container %q", len(objectsOnPage), container)
1104+
resp, err := objects.BulkDelete(conn, container, objectsOnPage).Extract()
1105+
if err != nil {
1106+
errCh <- err
1107+
return
1108+
}
1109+
if len(resp.Errors) > 0 {
1110+
// Convert resp.Errors to golang errors.
1111+
// Each error is represented by a list of 2 strings, where the first one
1112+
// is the object name, and the second one contains an error message.
1113+
for _, objectError := range resp.Errors {
1114+
errCh <- fmt.Errorf("cannot delete object %q: %s", objectError[0], objectError[1])
1115+
}
1116+
logger.Debugf("Terminating object deletion routine with error. Deleted %d objects out of %d.", resp.NumberDeleted, len(objectsOnPage))
11141117
}
1118+
1119+
// Some object-storage instances may be set to have a limit to the LIST operation
1120+
// that is higher to the limit to the BULK DELETE operation. On those clouds, objects
1121+
// in the BULK DELETE call beyond the limit are silently ignored. In this loop, after
1122+
// checking that no errors were encountered, we reduce the BULK DELETE list by the
1123+
// number of processed objects, and send it back to the server if it's not empty.
1124+
objectsOnPage = objectsOnPage[resp.NumberDeleted+resp.NumberNotFound:]
11151125
}
1116-
logger.Debugf("Terminating object deletion routine. Deleted %d objects out of %d.", resp.NumberDeleted, len(objectsOnPage))
1126+
logger.Debugf("Terminating object deletion routine.")
11171127
})
11181128
return true, nil
11191129
})

0 commit comments

Comments
 (0)