4242
4343import javax .inject .Inject ;
4444import javax .naming .ConfigurationException ;
45+ import javax .persistence .EntityExistsException ;
4546
4647import org .apache .cloudstack .affinity .dao .AffinityGroupVMMapDao ;
4748import org .apache .cloudstack .annotation .AnnotationService ;
@@ -3981,7 +3982,7 @@ public NicProfile addVmToNetwork(final VirtualMachine vm, final Network network,
39813982 if (jobContext .isJobDispatchedBy (VmWorkConstants .VM_WORK_JOB_DISPATCHER )) {
39823983 // avoid re-entrance
39833984 VmWorkJobVO placeHolder = null ;
3984- placeHolder = createPlaceHolderWork (vm .getId ());
3985+ placeHolder = createPlaceHolderWork (vm .getId (), network . getUuid () );
39853986 try {
39863987 return orchestrateAddVmToNetwork (vm , network , requested );
39873988 } finally {
@@ -4021,10 +4022,23 @@ public NicProfile addVmToNetwork(final VirtualMachine vm, final Network network,
40214022 }
40224023 }
40234024
4025+ /**
4026+ * duplicated in {@see UserVmManagerImpl} for a {@see UserVmVO}
4027+ */
4028+ private void checkIfNetworkExistsForVM (VirtualMachine virtualMachine , Network network ) {
4029+ List <NicVO > allNics = _nicsDao .listByVmId (virtualMachine .getId ());
4030+ for (NicVO nic : allNics ) {
4031+ if (nic .getNetworkId () == network .getId ()) {
4032+ throw new CloudRuntimeException ("A NIC already exists for VM:" + virtualMachine .getInstanceName () + " in network: " + network .getUuid ());
4033+ }
4034+ }
4035+ }
4036+
40244037 private NicProfile orchestrateAddVmToNetwork (final VirtualMachine vm , final Network network , final NicProfile requested ) throws ConcurrentOperationException , ResourceUnavailableException ,
40254038 InsufficientCapacityException {
40264039 final CallContext cctx = CallContext .current ();
40274040
4041+ checkIfNetworkExistsForVM (vm , network );
40284042 s_logger .debug ("Adding vm " + vm + " to network " + network + "; requested nic profile " + requested );
40294043 final VMInstanceVO vmVO = _vmDao .findById (vm .getId ());
40304044 final ReservationContext context = new ReservationContextImpl (null , null , cctx .getCallingUser (), cctx .getCallingAccount ());
@@ -5375,7 +5389,7 @@ public Outcome<VirtualMachine> migrateVmThroughJobQueue(final String vmUuid, fin
53755389 Map <Volume , StoragePool > volumeStorageMap = dest .getStorageForDisks ();
53765390 if (volumeStorageMap != null ) {
53775391 for (Volume vol : volumeStorageMap .keySet ()) {
5378- checkConcurrentJobsPerDatastoreThreshhold (volumeStorageMap .get (vol ));
5392+ checkConcurrentJobsPerDatastoreThreshold (volumeStorageMap .get (vol ));
53795393 }
53805394 }
53815395
@@ -5540,7 +5554,7 @@ public Outcome<VirtualMachine> migrateVmForScaleThroughJobQueue(
55405554 return new VmJobVirtualMachineOutcome (workJob , vm .getId ());
55415555 }
55425556
5543- private void checkConcurrentJobsPerDatastoreThreshhold (final StoragePool destPool ) {
5557+ private void checkConcurrentJobsPerDatastoreThreshold (final StoragePool destPool ) {
55445558 final Long threshold = VolumeApiService .ConcurrentMigrationsThresholdPerDatastore .value ();
55455559 if (threshold != null && threshold > 0 ) {
55465560 long count = _jobMgr .countPendingJobs ("\" storageid\" :\" " + destPool .getUuid () + "\" " , MigrateVMCmd .class .getName (), MigrateVolumeCmd .class .getName (), MigrateVolumeCmdByAdmin .class .getName ());
@@ -5561,7 +5575,7 @@ public Outcome<VirtualMachine> migrateVmStorageThroughJobQueue(
55615575 Set <Long > uniquePoolIds = new HashSet <>(poolIds );
55625576 for (Long poolId : uniquePoolIds ) {
55635577 StoragePoolVO pool = _storagePoolDao .findById (poolId );
5564- checkConcurrentJobsPerDatastoreThreshhold (pool );
5578+ checkConcurrentJobsPerDatastoreThreshold (pool );
55655579 }
55665580
55675581 final VMInstanceVO vm = _vmDao .findByUuid (vmUuid );
@@ -5608,35 +5622,61 @@ public Outcome<VirtualMachine> addVmToNetworkThroughJobQueue(
56085622
56095623 final List <VmWorkJobVO > pendingWorkJobs = _workJobDao .listPendingWorkJobs (
56105624 VirtualMachine .Type .Instance , vm .getId (),
5611- VmWorkAddVmToNetwork .class .getName ());
5625+ VmWorkAddVmToNetwork .class .getName (), network . getUuid () );
56125626
56135627 VmWorkJobVO workJob = null ;
56145628 if (pendingWorkJobs != null && pendingWorkJobs .size () > 0 ) {
5615- assert pendingWorkJobs .size () == 1 ;
5629+ if (pendingWorkJobs .size () > 1 ) {
5630+ s_logger .warn (String .format ("The number of jobs to add network %s to vm %s are %d" , network .getUuid (), vm .getInstanceName (), pendingWorkJobs .size ()));
5631+ }
56165632 workJob = pendingWorkJobs .get (0 );
56175633 } else {
5634+ if (s_logger .isTraceEnabled ()) {
5635+ s_logger .trace (String .format ("no jobs to add network %s for vm %s yet" , network , vm ));
5636+ }
56185637
5619- workJob = new VmWorkJobVO (context .getContextId ());
5638+ workJob = createVmWorkJobToAddNetwork (vm , network , requested , context , user , account );
5639+ }
5640+ AsyncJobExecutionContext .getCurrentExecutionContext ().joinJob (workJob .getId ());
56205641
5621- workJob . setDispatcher ( VmWorkConstants . VM_WORK_JOB_DISPATCHER );
5622- workJob . setCmd ( VmWorkAddVmToNetwork . class . getName ());
5642+ return new VmJobVirtualMachineOutcome ( workJob , vm . getId () );
5643+ }
56235644
5624- workJob .setAccountId (account .getId ());
5625- workJob .setUserId (user .getId ());
5626- workJob .setVmType (VirtualMachine .Type .Instance );
5627- workJob .setVmInstanceId (vm .getId ());
5628- workJob .setRelated (AsyncJobExecutionContext .getOriginJobId ());
5645+ private VmWorkJobVO createVmWorkJobToAddNetwork (
5646+ VirtualMachine vm ,
5647+ Network network ,
5648+ NicProfile requested ,
5649+ CallContext context ,
5650+ User user ,
5651+ Account account ) {
5652+ VmWorkJobVO workJob ;
5653+ workJob = new VmWorkJobVO (context .getContextId ());
56295654
5630- // save work context info (there are some duplications)
5631- final VmWorkAddVmToNetwork workInfo = new VmWorkAddVmToNetwork (user .getId (), account .getId (), vm .getId (),
5632- VirtualMachineManagerImpl .VM_WORK_JOB_HANDLER , network .getId (), requested );
5633- workJob .setCmdInfo (VmWorkSerializer .serialize (workInfo ));
5655+ workJob .setDispatcher (VmWorkConstants .VM_WORK_JOB_DISPATCHER );
5656+ workJob .setCmd (VmWorkAddVmToNetwork .class .getName ());
56345657
5658+ workJob .setAccountId (account .getId ());
5659+ workJob .setUserId (user .getId ());
5660+ workJob .setVmType (VirtualMachine .Type .Instance );
5661+ workJob .setVmInstanceId (vm .getId ());
5662+ workJob .setRelated (AsyncJobExecutionContext .getOriginJobId ());
5663+ workJob .setSecondaryObjectIdentifier (network .getUuid ());
5664+
5665+ // save work context info (there are some duplications)
5666+ final VmWorkAddVmToNetwork workInfo = new VmWorkAddVmToNetwork (user .getId (), account .getId (), vm .getId (),
5667+ VirtualMachineManagerImpl .VM_WORK_JOB_HANDLER , network .getId (), requested );
5668+ workJob .setCmdInfo (VmWorkSerializer .serialize (workInfo ));
5669+
5670+ try {
56355671 _jobMgr .submitAsyncJob (workJob , VmWorkConstants .VM_WORK_QUEUE , vm .getId ());
5672+ } catch (CloudRuntimeException e ) {
5673+ if (e .getCause () instanceof EntityExistsException ) {
5674+ String msg = String .format ("A job to add a nic for network %s to vm %s already exists" , network .getUuid (), vm .getUuid ());
5675+ s_logger .warn (msg , e );
5676+ }
5677+ throw e ;
56365678 }
5637- AsyncJobExecutionContext .getCurrentExecutionContext ().joinJob (workJob .getId ());
5638-
5639- return new VmJobVirtualMachineOutcome (workJob , vm .getId ());
5679+ return workJob ;
56405680 }
56415681
56425682 public Outcome <VirtualMachine > removeNicFromVmThroughJobQueue (
@@ -5945,6 +5985,10 @@ public Pair<JobInfo.Status, String> handleVmWorkJob(final VmWork work) throws Ex
59455985 }
59465986
59475987 private VmWorkJobVO createPlaceHolderWork (final long instanceId ) {
5988+ return createPlaceHolderWork (instanceId , null );
5989+ }
5990+
5991+ private VmWorkJobVO createPlaceHolderWork (final long instanceId , String secondaryObjectIdentifier ) {
59485992 final VmWorkJobVO workJob = new VmWorkJobVO ("" );
59495993
59505994 workJob .setDispatcher (VmWorkConstants .VM_WORK_JOB_PLACEHOLDER );
@@ -5956,6 +6000,9 @@ private VmWorkJobVO createPlaceHolderWork(final long instanceId) {
59566000 workJob .setStep (VmWorkJobVO .Step .Starting );
59576001 workJob .setVmType (VirtualMachine .Type .Instance );
59586002 workJob .setVmInstanceId (instanceId );
6003+ if (StringUtils .isNotBlank (secondaryObjectIdentifier )) {
6004+ workJob .setSecondaryObjectIdentifier (secondaryObjectIdentifier );
6005+ }
59596006 workJob .setInitMsid (ManagementServerNode .getManagementServerId ());
59606007
59616008 _workJobDao .persist (workJob );
0 commit comments