Skip to content

Commit 779f337

Browse files
author
gitlab
committed
Merge branch 'fix-local-migrate-state-roll-back' into 'master'
Add rollback for local volume migrate state change Closes ZSTAC-10519 See merge request zstackio/zstack!2396
2 parents 21e24c3 + 478ff47 commit 779f337

File tree

2 files changed

+126
-8
lines changed

2 files changed

+126
-8
lines changed

plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import org.zstack.core.componentloader.PluginRegistry;
88
import org.zstack.core.db.*;
99
import org.zstack.core.db.SimpleQuery.Op;
10+
import org.zstack.core.defer.Defer;
11+
import org.zstack.core.defer.Deferred;
1012
import org.zstack.core.thread.AsyncThread;
1113
import org.zstack.core.thread.ChainTask;
1214
import org.zstack.core.thread.SyncTaskChain;
@@ -49,6 +51,7 @@
4951
import org.zstack.storage.primary.local.MigrateBitsStruct.ResourceInfo;
5052
import org.zstack.utils.CollectionUtils;
5153
import org.zstack.utils.DebugUtils;
54+
import org.zstack.utils.ShellUtils;
5255
import org.zstack.utils.Utils;
5356
import org.zstack.utils.function.Function;
5457
import org.zstack.utils.gson.JSONObjectUtil;
@@ -268,7 +271,8 @@ class MigrateStruct {
268271
private boolean isRootVolume = false;
269272
private OverlayMessage message;
270273
private String vmUuid;
271-
private boolean isMigrated = false;
274+
private boolean volumeStatusChanged = false;
275+
private boolean vmStateChanged = false;
272276

273277
public String getVmOriginState() {
274278
return vmOriginState;
@@ -304,20 +308,28 @@ public void setVmUuid(String vmUuid) {
304308
this.vmUuid = vmUuid;
305309
}
306310

307-
public boolean isMigrated() {
308-
return isMigrated;
311+
public boolean isVolumeStatusChanged() {
312+
return volumeStatusChanged;
309313
}
310314

311-
public void setMigrated(boolean migrated) {
312-
isMigrated = migrated;
315+
public void setVolumeStatusChanged(boolean volumeStatusChanged) {
316+
this.volumeStatusChanged = volumeStatusChanged;
317+
}
318+
319+
public boolean isVmStateChanged() {
320+
return vmStateChanged;
321+
}
322+
323+
public void setVmStateChanged(boolean vmStateChanged) {
324+
this.vmStateChanged = vmStateChanged;
313325
}
314326
}
315327

316328
MigrateStruct struct = new MigrateStruct();
317329
VolumeStatus originStatus = Q.New(VolumeVO.class).select(VolumeVO_.status).eq(VolumeVO_.uuid, msg.getVolumeUuid()).findValue();
318330
FlowChain chain = new SimpleFlowChain();
319331
chain.setName(String.format("local-storage-%s-migrate-volume-%s-to-host-%s", msg.getPrimaryStorageUuid(), msg.getVolumeUuid(), msg.getDestHostUuid()));
320-
chain.then(new NoRollbackFlow() {
332+
chain.then(new Flow() {
321333
@Override
322334
public void run(FlowTrigger trigger, Map data) {
323335
String __name__ = "change-volume-status-to-migrating";
@@ -334,11 +346,25 @@ public void run(MessageReply reply) {
334346
return;
335347
}
336348

349+
struct.setVolumeStatusChanged(true);
337350
trigger.next();
338351
}
339352
});
340353
}
341-
}).then(new NoRollbackFlow() {
354+
355+
@Override
356+
public void rollback(FlowRollback trigger, Map data) {
357+
if (struct.isVolumeStatusChanged()) {
358+
ChangeVolumeStatusMsg rollbackMsg = new ChangeVolumeStatusMsg();
359+
rollbackMsg.setStatus(originStatus);
360+
rollbackMsg.setVolumeUuid(msg.getVolumeUuid());
361+
bus.makeTargetServiceIdByResourceUuid(rollbackMsg, VolumeConstant.SERVICE_ID, msg.getVolumeUuid());
362+
bus.send(rollbackMsg);
363+
}
364+
365+
trigger.rollback();
366+
}
367+
}).then(new Flow() {
342368
@Override
343369
public void run(FlowTrigger trigger, Map data) {
344370
String __name__ = "change-vm-state-to-volume-migrating";
@@ -370,10 +396,24 @@ public void run(MessageReply reply) {
370396
return;
371397
}
372398

399+
struct.setVmStateChanged(true);
373400
trigger.next();
374401
}
375402
});
376403
}
404+
405+
@Override
406+
public void rollback(FlowRollback trigger, Map data) {
407+
if (struct.isVmStateChanged()) {
408+
ChangeVmStateMsg rollbackMsg = new ChangeVmStateMsg();
409+
rollbackMsg.setStateEvent(struct.getVmOriginState());
410+
rollbackMsg.setVmInstanceUuid(struct.getVmUuid());
411+
bus.makeTargetServiceIdByResourceUuid(rollbackMsg, VmInstanceConstant.SERVICE_ID, struct.getVmUuid());
412+
bus.send(rollbackMsg);
413+
}
414+
415+
trigger.rollback();
416+
}
377417
}).then(new NoRollbackFlow() {
378418
@Override
379419
public void run(FlowTrigger trigger, Map data) {
@@ -412,7 +452,6 @@ public void run(MessageReply reply) {
412452

413453
MigrateVolumeOnLocalStorageReply mr = reply.castReply();
414454
evt.setInventory(mr.getInventory());
415-
struct.setMigrated(true);
416455
trigger.next();
417456
}
418457
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package org.zstack.test.integration.storage.primary.local
2+
3+
import org.zstack.core.db.Q
4+
import org.zstack.header.vm.VmInstanceState
5+
import org.zstack.header.vm.VmInstanceVO
6+
import org.zstack.header.vm.VmInstanceVO_
7+
import org.zstack.header.volume.VolumeStatus
8+
import org.zstack.header.volume.VolumeVO
9+
import org.zstack.header.volume.VolumeVO_
10+
import org.zstack.sdk.HostInventory
11+
import org.zstack.sdk.LocalStorageMigrateVolumeAction
12+
import org.zstack.sdk.VmInstanceInventory
13+
import org.zstack.sdk.VolumeInventory
14+
import org.zstack.storage.primary.local.LocalStorageKvmBackend
15+
import org.zstack.test.integration.storage.Env
16+
import org.zstack.test.integration.storage.primary.PrimaryStorageTest
17+
import org.zstack.testlib.EnvSpec
18+
import org.zstack.testlib.HttpError
19+
import org.zstack.testlib.SubCase
20+
21+
/**
22+
* Created by kayo on 2018/3/23.
23+
*/
24+
class LocalStorageVolumeMigrateFailureRollbackCase extends SubCase {
25+
EnvSpec env
26+
27+
@Override
28+
void clean() {
29+
env.delete()
30+
}
31+
32+
@Override
33+
void setup() {
34+
useSpring(PrimaryStorageTest.springSpec)
35+
}
36+
37+
@Override
38+
void environment() {
39+
env = Env.localStorageOneVmWithOneDataVolumeEnv()
40+
}
41+
42+
@Override
43+
void test() {
44+
env.create {
45+
testVolumeStatusAndVmStateRollback()
46+
}
47+
}
48+
49+
void testVolumeStatusAndVmStateRollback() {
50+
HostInventory hostInventory = env.inventoryByName("kvm1")
51+
VmInstanceInventory vm1 = (VmInstanceInventory) env.inventoryByName("vm")
52+
VolumeInventory dataVolume = vm1.getAllVolumes().find { i -> i.getUuid() != vm1.getRootVolumeUuid() }
53+
detachDataVolumeFromVm {
54+
uuid = dataVolume.getUuid()
55+
vmUuid = vm1.getUuid()
56+
}
57+
58+
stopVmInstance {
59+
uuid = vm1.uuid
60+
}
61+
62+
env.afterSimulator(LocalStorageKvmBackend.CHECK_MD5_PATH) { rsp ->
63+
throw new HttpError(403, "on purpose")
64+
}
65+
66+
def action = new LocalStorageMigrateVolumeAction()
67+
action.sessionId = adminSession()
68+
action.destHostUuid = hostInventory.uuid
69+
action.volumeUuid = vm1.getRootVolumeUuid()
70+
LocalStorageMigrateVolumeAction.Result ret = action.call()
71+
72+
assert ret.error != null
73+
74+
retryInSecs {
75+
assert Q.New(VmInstanceVO.class).eq(VmInstanceVO_.uuid, vm1.getUuid()).eq(VmInstanceVO_.state, VmInstanceState.Stopped).isExists()
76+
assert Q.New(VolumeVO.class).eq(VolumeVO_.uuid, vm1.getRootVolumeUuid()).eq(VolumeVO_.status, VolumeStatus.Ready).isExists()
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)