package io.cattle.platform.servicediscovery.deployment.impl.planner; import io.cattle.platform.activity.ActivityLog; import io.cattle.platform.core.constants.ServiceConstants; import io.cattle.platform.core.model.Service; import io.cattle.platform.core.model.Stack; import io.cattle.platform.object.util.DataAccessor; import io.cattle.platform.servicediscovery.deployment.DeploymentUnitInstanceIdGenerator; import io.cattle.platform.servicediscovery.deployment.ServiceDeploymentPlanner; import io.cattle.platform.servicediscovery.deployment.impl.DeploymentManagerImpl.DeploymentServiceContext; import io.cattle.platform.servicediscovery.deployment.impl.unit.DeploymentUnit; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class DefaultServiceDeploymentPlanner extends ServiceDeploymentPlanner { protected Integer requestedScale = 0; public DefaultServiceDeploymentPlanner(Service service, Stack stack, List<DeploymentUnit> units, DeploymentServiceContext context) { super(service, units, context, stack); int scale; // internal desired scale populated by scale policy driven deployment Integer scaleInternal = DataAccessor.fieldInteger(service, ServiceConstants.FIELD_DESIRED_SCALE); if (scaleInternal != null) { scale = scaleInternal; } else { scale = DataAccessor.fieldInteger(service, ServiceConstants.FIELD_SCALE); } if (scale > this.requestedScale) { this.requestedScale = scale; } } @Override public List<DeploymentUnit> deployHealthyUnits(DeploymentUnitInstanceIdGenerator svcInstanceIdGenerator) { if (this.healthyUnits.size() < requestedScale) { addMissingUnits(svcInstanceIdGenerator); } else if (healthyUnits.size() > requestedScale) { removeExtraUnits(); } return healthyUnits; } private void addMissingUnits(DeploymentUnitInstanceIdGenerator svcInstanceIdGenerator) { while (this.healthyUnits.size() < this.requestedScale) { DeploymentUnit unit = new DeploymentUnit(context, service, null, svcInstanceIdGenerator, stack); this.healthyUnits.add(unit); } } private void removeExtraUnits() { // delete units int i = this.healthyUnits.size() - 1; List<DeploymentUnit> watchList = new ArrayList<>(); Collections.sort(this.healthyUnits, new Comparator<DeploymentUnit>() { @Override public int compare(DeploymentUnit d1, DeploymentUnit d2) { return Long.compare(d1.getCreateIndex(), d2.getCreateIndex()); } }); while (this.healthyUnits.size() > this.requestedScale) { DeploymentUnit toRemove = this.healthyUnits.get(i); watchList.add(toRemove); toRemove.remove(ServiceConstants.AUDIT_LOG_REMOVE_EXTRA, ActivityLog.INFO); this.healthyUnits.remove(i); i--; } for (DeploymentUnit toWatch : watchList) { toWatch.waitForRemoval(); } } @Override public boolean needToReconcileDeploymentImpl() { return (healthyUnits.size() != requestedScale); } @Override public String getStatus() { return String.format("Requested: %d, %s", requestedScale, super.getStatus()); } }