diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 50d78f43033..dc54f543c32 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -187,6 +187,8 @@ public interface VirtualMachineManager extends Manager { */ boolean removeNicFromVm(VirtualMachine vm, Nic nic) throws ConcurrentOperationException, ResourceUnavailableException; + Boolean updateDefaultNicForVM(VirtualMachine vm, Nic nic, Nic defaultNic); + /** * @param vm * @param network diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 8f722c92fde..7ffd023383c 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -5741,4 +5741,116 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return new Pair(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(passwordMap)); } + @Override + public Boolean updateDefaultNicForVM(final VirtualMachine vm, final Nic nic, final Nic defaultNic) { + + final AsyncJobExecutionContext jobContext = AsyncJobExecutionContext.getCurrentExecutionContext(); + if (jobContext.isJobDispatchedBy(VmWorkConstants.VM_WORK_JOB_DISPATCHER)) { + VmWorkJobVO placeHolder = null; + placeHolder = createPlaceHolderWork(vm.getId()); + try { + return orchestrateUpdateDefaultNicForVM(vm, nic, defaultNic); + } finally { + if (placeHolder != null) { + _workJobDao.expunge(placeHolder.getId()); + } + } + } else { + final Outcome outcome = updateDefaultNicForVMThroughJobQueue(vm, nic, defaultNic); + + try { + outcome.get(); + } catch (final InterruptedException e) { + throw new RuntimeException("Operation is interrupted", e); + } catch (final java.util.concurrent.ExecutionException e) { + throw new RuntimeException("Execution exception", e); + } + + final Object jobResult = _jobMgr.unmarshallResultObject(outcome.getJob()); + if (jobResult != null) { + if (jobResult instanceof Boolean) { + return (Boolean)jobResult; + } + } + + throw new RuntimeException("Unexpected job execution result"); + } + } + + private Boolean orchestrateUpdateDefaultNicForVM(final VirtualMachine vm, final Nic nic, final Nic defaultNic) { + + s_logger.debug("Updating default nic of vm " + vm + " from nic " + defaultNic.getUuid() + " to nic " + nic.getUuid()); + Integer chosenID = nic.getDeviceId(); + Integer existingID = defaultNic.getDeviceId(); + NicVO nicVO = _nicsDao.findById(nic.getId()); + NicVO defaultNicVO = _nicsDao.findById(defaultNic.getId()); + + nicVO.setDefaultNic(true); + nicVO.setDeviceId(existingID); + defaultNicVO.setDefaultNic(false); + defaultNicVO.setDeviceId(chosenID); + + _nicsDao.persist(nicVO); + _nicsDao.persist(defaultNicVO); + return true; + } + + public Outcome updateDefaultNicForVMThroughJobQueue(final VirtualMachine vm, final Nic nic, final Nic defaultNic) { + + final CallContext context = CallContext.current(); + final User user = context.getCallingUser(); + final Account account = context.getCallingAccount(); + + final List pendingWorkJobs = _workJobDao.listPendingWorkJobs( + VirtualMachine.Type.Instance, vm.getId(), + VmWorkUpdateDefaultNic.class.getName()); + + VmWorkJobVO workJob = null; + if (pendingWorkJobs != null && pendingWorkJobs.size() > 0) { + assert pendingWorkJobs.size() == 1; + workJob = pendingWorkJobs.get(0); + } else { + + workJob = new VmWorkJobVO(context.getContextId()); + + workJob.setDispatcher(VmWorkConstants.VM_WORK_JOB_DISPATCHER); + workJob.setCmd(VmWorkUpdateDefaultNic.class.getName()); + + workJob.setAccountId(account.getId()); + workJob.setUserId(user.getId()); + workJob.setVmType(VirtualMachine.Type.Instance); + workJob.setVmInstanceId(vm.getId()); + workJob.setRelated(AsyncJobExecutionContext.getOriginJobId()); + + final VmWorkUpdateDefaultNic workInfo = new VmWorkUpdateDefaultNic(user.getId(), account.getId(), vm.getId(), + VirtualMachineManagerImpl.VM_WORK_JOB_HANDLER, nic.getId(), defaultNic.getId()); + workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + + _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vm.getId()); + } + AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId()); + + return new VmJobVirtualMachineOutcome(workJob, vm.getId()); + } + + @ReflectionUse + private Pair orchestrateUpdateDefaultNic(final VmWorkUpdateDefaultNic work) throws Exception { + final VMInstanceVO vm = _entityMgr.findById(VMInstanceVO.class, work.getVmId()); + if (vm == null) { + s_logger.info("Unable to find vm " + work.getVmId()); + } + assert vm != null; + final NicVO nic = _entityMgr.findById(NicVO.class, work.getNicId()); + if (nic == null) { + throw new CloudRuntimeException("Unable to find nic " + work.getNicId()); + } + final NicVO defaultNic = _entityMgr.findById(NicVO.class, work.getDefaultNicId()); + if (defaultNic == null) { + throw new CloudRuntimeException("Unable to find default nic " + work.getDefaultNicId()); + } + final boolean result = orchestrateUpdateDefaultNicForVM(vm, nic, defaultNic); + return new Pair(JobInfo.Status.SUCCEEDED, + _jobMgr.marshallResultObject(result)); + } + } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VmWorkUpdateDefaultNic.java b/engine/orchestration/src/main/java/com/cloud/vm/VmWorkUpdateDefaultNic.java new file mode 100644 index 00000000000..14f32399449 --- /dev/null +++ b/engine/orchestration/src/main/java/com/cloud/vm/VmWorkUpdateDefaultNic.java @@ -0,0 +1,39 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.vm; + +public class VmWorkUpdateDefaultNic extends VmWork { + private static final long serialVersionUID = -4265657031064437934L; + + Long nicId; + Long defaultNicId; + + public VmWorkUpdateDefaultNic(long userId, long accountId, long vmId, String handlerName, Long nicId, Long defaultNicId) { + super(userId, accountId, vmId, handlerName); + + this.nicId = nicId; + this.defaultNicId = defaultNicId; + } + + public Long getNicId() { + return nicId; + } + + public Long getDefaultNicId() { + return defaultNicId; + } +} diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 56eab1a065f..802ac1e0dd7 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -1477,16 +1477,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir Integer chosenID = nic.getDeviceId(); Integer existingID = existing.getDeviceId(); - nic.setDefaultNic(true); - nic.setDeviceId(existingID); - existingVO.setDefaultNic(false); - existingVO.setDeviceId(chosenID); - - nic = _nicDao.persist(nic); - existingVO = _nicDao.persist(existingVO); - Network newdefault = null; - newdefault = _networkModel.getDefaultNetworkForVm(vmId); + if (_itMgr.updateDefaultNicForVM(vmInstance, nic, existingVO)) { + newdefault = _networkModel.getDefaultNetworkForVm(vmId); + } if (newdefault == null) { nic.setDefaultNic(false);