Skip to content

Commit 4746c8c

Browse files
authored
server: move UpdateDefaultNic to vm work job queue (#4020)
While remove secondary nic from a Running vm, if update the default nic to the secondary nic before the nic is removed, the vm will not have default nic (and cannot be started) when both operations are completed. It is because UpdateDefaultNic api is not handled as a vm work job (AddNicToVMCmd and RemoveNicFromVMCmd are), it is processed before nic is removed. The result is that secondary nic becomes default nic and got removed.
1 parent 749e302 commit 4746c8c

4 files changed

Lines changed: 156 additions & 9 deletions

File tree

engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ NicProfile addVmToNetwork(VirtualMachine vm, Network network, NicProfile request
187187
*/
188188
boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException;
189189

190+
Boolean updateDefaultNicForVM(VirtualMachine vm, Nic nic, Nic defaultNic);
191+
190192
/**
191193
* @param vm
192194
* @param network

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5741,4 +5741,116 @@ private Pair<JobInfo.Status, String> orchestrateRestoreVirtualMachine(final VmWo
57415741
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(passwordMap));
57425742
}
57435743

5744+
@Override
5745+
public Boolean updateDefaultNicForVM(final VirtualMachine vm, final Nic nic, final Nic defaultNic) {
5746+
5747+
final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext();
5748+
if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) {
5749+
VmWorkJobVO placeHolder = null;
5750+
placeHolder = createPlaceHolderWork(vm.getId());
5751+
try {
5752+
return orchestrateUpdateDefaultNicForVM(vm, nic, defaultNic);
5753+
} finally {
5754+
if (placeHolder != null) {
5755+
_workJobDao.expunge(placeHolder.getId());
5756+
}
5757+
}
5758+
} else {
5759+
final Outcome<VirtualMachine> outcome = updateDefaultNicForVMThroughJobQueue(vm, nic, defaultNic);
5760+
5761+
try {
5762+
outcome.get();
5763+
} catch (final InterruptedException e) {
5764+
throw new RuntimeException("Operation is interrupted", e);
5765+
} catch (final java.util.concurrent.ExecutionException e) {
5766+
throw new RuntimeException("Execution exception", e);
5767+
}
5768+
5769+
final Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob());
5770+
if (jobResult != null) {
5771+
if (jobResult instanceof Boolean) {
5772+
return (Boolean)jobResult;
5773+
}
5774+
}
5775+
5776+
throw new RuntimeException("Unexpected job execution result");
5777+
}
5778+
}
5779+
5780+
private Boolean orchestrateUpdateDefaultNicForVM(final VirtualMachine vm, final Nic nic, final Nic defaultNic) {
5781+
5782+
s_logger.debug("Updating default nic of vm " + vm + " from nic " + defaultNic.getUuid() + " to nic " + nic.getUuid());
5783+
Integer chosenID = nic.getDeviceId();
5784+
Integer existingID = defaultNic.getDeviceId();
5785+
NicVO nicVO = _nicsDao.findById(nic.getId());
5786+
NicVO defaultNicVO = _nicsDao.findById(defaultNic.getId());
5787+
5788+
nicVO.setDefaultNic(true);
5789+
nicVO.setDeviceId(existingID);
5790+
defaultNicVO.setDefaultNic(false);
5791+
defaultNicVO.setDeviceId(chosenID);
5792+
5793+
_nicsDao.persist(nicVO);
5794+
_nicsDao.persist(defaultNicVO);
5795+
return true;
5796+
}
5797+
5798+
public Outcome<VirtualMachine> updateDefaultNicForVMThroughJobQueue(final VirtualMachine vm, final Nic nic, final Nic defaultNic) {
5799+
5800+
final CallContext context = CallContext.current();
5801+
final User user = context.getCallingUser();
5802+
final Account account = context.getCallingAccount();
5803+
5804+
final List<VmWorkJobVO> pendingWorkJobs = _workJobDao.listPendingWorkJobs(
5805+
VirtualMachine.Type.Instance, vm.getId(),
5806+
VmWorkUpdateDefaultNic.class.getName());
5807+
5808+
VmWorkJobVO workJob = null;
5809+
if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) {
5810+
assert pendingWorkJobs.size() == 1;
5811+
workJob = pendingWorkJobs.get(0);
5812+
} else {
5813+
5814+
workJob = new VmWorkJobVO(context.getContextId());
5815+
5816+
workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER);
5817+
workJob.setCmd(VmWorkUpdateDefaultNic.class.getName());
5818+
5819+
workJob.setAccountId(account.getId());
5820+
workJob.setUserId(user.getId());
5821+
workJob.setVmType(VirtualMachine.Type.Instance);
5822+
workJob.setVmInstanceId(vm.getId());
5823+
workJob.setRelated(AsyncJobExecutionContext.getOriginJobId());
5824+
5825+
final VmWorkUpdateDefaultNic workInfo = new VmWorkUpdateDefaultNic(user.getId(), account.getId(), vm.getId(),
5826+
VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, nic.getId(), defaultNic.getId());
5827+
workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
5828+
5829+
_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId());
5830+
}
5831+
AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId());
5832+
5833+
return new VmJobVirtualMachineOutcome(workJob, vm.getId());
5834+
}
5835+
5836+
@ReflectionUse
5837+
private Pair<JobInfo.Status, String> orchestrateUpdateDefaultNic(final VmWorkUpdateDefaultNic work) throws Exception {
5838+
final VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId());
5839+
if (vm == null) {
5840+
s_logger.info("Unable to find vm " + work.getVmId());
5841+
}
5842+
assert vm != null;
5843+
final NicVO nic = _entityMgr.findById(NicVO.class, work.getNicId());
5844+
if (nic == null) {
5845+
throw new CloudRuntimeException("Unable to find nic " + work.getNicId());
5846+
}
5847+
final NicVO defaultNic = _entityMgr.findById(NicVO.class, work.getDefaultNicId());
5848+
if (defaultNic == null) {
5849+
throw new CloudRuntimeException("Unable to find default nic " + work.getDefaultNicId());
5850+
}
5851+
final boolean result = orchestrateUpdateDefaultNicForVM(vm, nic, defaultNic);
5852+
return new Pair<JobInfo.Status, String>(JobInfo.Status.SUCCEEDED,
5853+
_jobMgr.marshallResultObject(result));
5854+
}
5855+
57445856
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.vm;
18+
19+
public class VmWorkUpdateDefaultNic extends VmWork {
20+
private static final long serialVersionUID = -4265657031064437934L;
21+
22+
Long nicId;
23+
Long defaultNicId;
24+
25+
public VmWorkUpdateDefaultNic(long userId, long accountId, long vmId, String handlerName, Long nicId, Long defaultNicId) {
26+
super(userId, accountId, vmId, handlerName);
27+
28+
this.nicId = nicId;
29+
this.defaultNicId = defaultNicId;
30+
}
31+
32+
public Long getNicId() {
33+
return nicId;
34+
}
35+
36+
public Long getDefaultNicId() {
37+
return defaultNicId;
38+
}
39+
}

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,16 +1477,10 @@ public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) th
14771477
Integer chosenID = nic.getDeviceId();
14781478
Integer existingID = existing.getDeviceId();
14791479

1480-
nic.setDefaultNic(true);
1481-
nic.setDeviceId(existingID);
1482-
existingVO.setDefaultNic(false);
1483-
existingVO.setDeviceId(chosenID);
1484-
1485-
nic = _nicDao.persist(nic);
1486-
existingVO = _nicDao.persist(existingVO);
1487-
14881480
Network newdefault = null;
1489-
newdefault = _networkModel.getDefaultNetworkForVm(vmId);
1481+
if (_itMgr.updateDefaultNicForVM(vmInstance, nic, existingVO)) {
1482+
newdefault = _networkModel.getDefaultNetworkForVm(vmId);
1483+
}
14901484

14911485
if (newdefault == null) {
14921486
nic.setDefaultNic(false);

0 commit comments

Comments
 (0)