Skip to content

Commit 6411a57

Browse files
author
Eugenio Grosso
committed
flasharray: fix delete() rejecting volumes with {name, destroyed} PATCH
FlashArrayAdapter.delete() builds one FlashArrayVolume, then issues two PATCH requests on it: first to rename the volume with a timestamp suffix so a recreated volume with the same name would not collide with the destroyed copy in FlashArrays 24h recycle bin, then to mark it destroyed. The second PATCH reuses the same object, which still has the new name set, so the request body carries both name and destroyed. Purity 6.x rejects that combination with 400 Bad Request Invalid combination of parameters specified. and every CloudStack-side volume delete ends with the volume renamed (first PATCH succeeded) but not destroyed (second PATCH rejected). That leaves the volume leaking on the array and the CloudStack volume row stuck in Destroy state with no clean way forward via the UI. Rename and destroy are still issued, but as two separate PATCHes each carrying only its own field, preserving the forensic value of the timestamp suffix while working around the API restriction.
1 parent 9f96c9d commit 6411a57

1 file changed

Lines changed: 14 additions & 10 deletions

File tree

  • plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray

plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,21 +204,25 @@ public void delete(ProviderAdapterContext context, ProviderAdapterDataObject dat
204204
removeVlunsAll(context, pod, dataObject.getExternalName());
205205
String fullName = normalizeName(pod, dataObject.getExternalName());
206206

207-
FlashArrayVolume volume = new FlashArrayVolume();
208-
209-
// rename as we delete so it doesn't conflict if the template or volume is ever recreated
210-
// pure keeps the volume(s) around in a Destroyed bucket for a period of time post delete
207+
// Rename then destroy: FlashArray keeps destroyed volumes in a recycle
208+
// bin (default 24h) from which they can be recovered. Renaming with a
209+
// deletion timestamp gives operators a forensic trail when browsing the
210+
// array - they can see when each destroyed copy was deleted on the
211+
// CloudStack side. FlashArray rejects a single PATCH that combines
212+
// {name, destroyed}, so the rename and the destroy must be issued as
213+
// two separate requests each carrying only its own field.
211214
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
212-
volume.setExternalName(fullName + "-" + timestamp);
215+
String renamedName = fullName + "-" + timestamp;
213216

214217
try {
215-
PATCH("/volumes?names=" + fullName, volume, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
218+
FlashArrayVolume rename = new FlashArrayVolume();
219+
rename.setExternalName(renamedName);
220+
PATCH("/volumes?names=" + fullName, rename, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
216221
});
217222

218-
// now delete it with new name
219-
volume.setDestroyed(true);
220-
221-
PATCH("/volumes?names=" + fullName + "-" + timestamp, volume, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
223+
FlashArrayVolume destroy = new FlashArrayVolume();
224+
destroy.setDestroyed(true);
225+
PATCH("/volumes?names=" + renamedName, destroy, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
222226
});
223227
} catch (CloudRuntimeException e) {
224228
if (e.toString().contains("Volume does not exist")) {

0 commit comments

Comments
 (0)