public boolean canStartNewInstance() { if (getErrorInfo() != null) { LOG.debug("Can't start new instance, if image is erroneous"); return false; } if (myImageDetails.getBehaviour().isUseOriginal()) { final VmwareCloudInstance myInstance = myInstances.get(myImageDetails.getSourceName()); if (myInstance == null) { return false; } return myInstance.getStatus() == InstanceStatus.STOPPED; } final boolean countStoppedVmsInLimit = TeamCityProperties.getBooleanOrTrue(VmwareConstants.CONSIDER_STOPPED_VMS_LIMIT) && myImageDetails.getBehaviour().isDeleteAfterStop(); final List<String> consideredInstances = new ArrayList<String>(); for (Map.Entry<String, VmwareCloudInstance> entry : myInstances.entrySet()) { if (entry.getValue().getStatus() != InstanceStatus.STOPPED || countStoppedVmsInLimit) consideredInstances.add(entry.getKey()); } final boolean canStartMore = consideredInstances.size() < myImageDetails.getMaxInstances(); LOG.debug( String.format( "Instances count: %d %s, can start more: %s", consideredInstances.size(), Arrays.toString(consideredInstances.toArray()), String.valueOf(canStartMore))); return canStartMore; }
@NotNull protected synchronized VmwareCloudInstance getOrCreateInstance() throws VmwareCheckedCloudException { if (!canStartNewInstance()) { throw new QuotaException("Unable to start more instances of image " + getName()); } if (myImageDetails.getBehaviour().isUseOriginal()) { LOG.info("Won't create a new instance - using original"); return myInstances.get(myImageDetails.getSourceName()); } final String latestSnapshotName = myApiConnector.getLatestSnapshot( myImageDetails.getSourceName(), myImageDetails.getSnapshotName()); if (!myImageDetails.useCurrentVersion() && latestSnapshotName == null) { updateErrors(new TypedCloudErrorInfo("No such snapshot: " + getSnapshotName())); throw new VmwareCheckedCloudException( "Unable to find snapshot: " + myImageDetails.getSnapshotName()); } if (!myImageDetails.getBehaviour().isDeleteAfterStop()) { // on demand clone final Map<String, VmwareInstance> vmClones = myApiConnector.listImageInstances(this); // start an existsing one. final VmwareInstance imageVm = myApiConnector.getInstanceDetails(myImageDetails.getSourceName()); for (VmwareInstance vmInstance : vmClones.values()) { if (vmInstance.getInstanceStatus() == InstanceStatus.STOPPED) { final String vmName = vmInstance.getName(); final VmwareCloudInstance instance = myInstances.get(vmName); if (instance == null) { LOG.warn("Unable to find instance " + vmName + " in myInstances."); continue; } // checking if this instance is already starting. if (instance.getStatus() != InstanceStatus.STOPPED) continue; if (myImageDetails.useCurrentVersion()) { if (imageVm.getChangeVersion() == null || !imageVm.getChangeVersion().equals(vmInstance.getChangeVersion())) { LOG.info( String.format( "Change version for %s is outdated: '%s' vs '%s'", vmName, vmInstance.getChangeVersion(), imageVm.getChangeVersion())); deleteInstance(instance); continue; } } else { final String snapshotName = vmInstance.getSnapshotName(); if (latestSnapshotName != null && !latestSnapshotName.equals(snapshotName)) { LOG.info( String.format( "VM %s Snapshot is not the latest one: '%s' vs '%s'", vmName, snapshotName, latestSnapshotName)); deleteInstance(instance); continue; } } LOG.info("Will use existing VM with name " + vmName); return instance; } } } // wasn't able to find an existing candidate, so will clone into a new VM final String newVmName = generateNewVmName(); LOG.info("Will create a new VM with name " + newVmName); return new VmwareCloudInstance(this, newVmName, latestSnapshotName); }