package io.cattle.platform.servicediscovery.deployment.impl.unit;
import static io.cattle.platform.core.model.tables.VolumeTable.*;
import static io.cattle.platform.core.model.tables.VolumeTemplateTable.*;
import io.cattle.platform.core.constants.AgentConstants;
import io.cattle.platform.core.constants.CommonStatesConstants;
import io.cattle.platform.core.constants.ExternalEventConstants;
import io.cattle.platform.core.constants.InstanceConstants;
import io.cattle.platform.core.constants.ServiceConstants;
import io.cattle.platform.core.constants.VolumeConstants;
import io.cattle.platform.core.model.Agent;
import io.cattle.platform.core.model.Host;
import io.cattle.platform.core.model.Instance;
import io.cattle.platform.core.model.Service;
import io.cattle.platform.core.model.Stack;
import io.cattle.platform.core.model.Volume;
import io.cattle.platform.core.model.VolumeTemplate;
import io.cattle.platform.core.util.SystemLabels;
import io.cattle.platform.docker.constants.DockerInstanceConstants;
import io.cattle.platform.engine.process.impl.ProcessCancelException;
import io.cattle.platform.iaas.api.auditing.AuditEventType;
import io.cattle.platform.lock.LockCallback;
import io.cattle.platform.object.meta.ObjectMetaDataManager;
import io.cattle.platform.object.process.StandardProcess;
import io.cattle.platform.object.util.DataAccessor;
import io.cattle.platform.object.util.TransitioningUtils;
import io.cattle.platform.process.common.util.ProcessUtils;
import io.cattle.platform.servicediscovery.api.util.ServiceDiscoveryUtil;
import io.cattle.platform.servicediscovery.deployment.DeploymentUnitInstance;
import io.cattle.platform.servicediscovery.deployment.DeploymentUnitInstanceIdGenerator;
import io.cattle.platform.servicediscovery.deployment.InstanceUnit;
import io.cattle.platform.servicediscovery.deployment.impl.DeploymentManagerImpl.DeploymentServiceContext;
import io.cattle.platform.servicediscovery.deployment.impl.lock.StackVolumeLock;
import io.cattle.platform.util.exception.ServiceInstanceAllocateException;
import io.cattle.platform.util.type.CollectionUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
public class DeploymentUnit {
public static class SidekickType {
public static List<SidekickType> supportedTypes = new ArrayList<>();
public static final SidekickType DATA = new SidekickType(DockerInstanceConstants.FIELD_VOLUMES_FROM,
ServiceConstants.FIELD_DATA_VOLUMES_LAUNCH_CONFIG, true);
public static final SidekickType NETWORK = new SidekickType(DockerInstanceConstants.FIELD_NETWORK_CONTAINER_ID,
ServiceConstants.FIELD_NETWORK_LAUNCH_CONFIG, false);
public String launchConfigFieldName;
public String launchConfigType;
public boolean isList;
public SidekickType(String launchConfigFieldName, String launchConfigType, boolean isList) {
this.launchConfigFieldName = launchConfigFieldName;
this.launchConfigType = launchConfigType;
this.isList = isList;
supportedTypes.add(this);
}
}
Service service;
Stack stack;
String uuid;
DeploymentServiceContext context;
Map<String, String> unitLabels = new HashMap<>();
Map<String, DeploymentUnitInstance> launchConfigToInstance = new HashMap<>();
List<String> launchConfigNames = new ArrayList<>();
Map<String, List<String>> sidekickUsedByMap = new HashMap<>();
io.cattle.platform.core.model.DeploymentUnit unit;
private static List<String> supportedUnitLabels = Arrays
.asList(ServiceConstants.LABEL_SERVICE_REQUESTED_HOST_ID);
/*
* This constructor is called to add existing unit
*/
public DeploymentUnit(DeploymentServiceContext context, String uuid,
Service service, List<DeploymentUnitInstance> deploymentUnitInstances, Map<String, String> labels,
Stack stack,
Map<String, io.cattle.platform.core.model.DeploymentUnit> uuidToUnit) {
this(context, uuid, service, stack, uuidToUnit.get(uuid));
for (DeploymentUnitInstance instance : deploymentUnitInstances) {
addDeploymentInstance(instance.getLaunchConfigName(), instance);
}
setLabels(labels);
}
protected DeploymentUnit(DeploymentServiceContext context, String uuid, Service service, Stack stack,
io.cattle.platform.core.model.DeploymentUnit unit) {
this.context = context;
this.service = service;
this.uuid = uuid;
this.unit = unit;
this.stack = stack;
this.launchConfigNames = ServiceDiscoveryUtil.getServiceLaunchConfigNames(service);
for (String launchConfigName : launchConfigNames) {
for (String sidekick : getSidekickRefs(service, launchConfigName)) {
List<String> usedBy = sidekickUsedByMap.get(sidekick);
if (usedBy == null) {
usedBy = new ArrayList<>();
}
usedBy.add(launchConfigName);
sidekickUsedByMap.put(sidekick, usedBy);
}
}
}
/*
* this constructor is called to create a new unit
*/
public DeploymentUnit(DeploymentServiceContext context, Service service, Map<String, String> labels,
DeploymentUnitInstanceIdGenerator svcInstanceIdGenerator, Stack stack) {
this(context, io.cattle.platform.util.resource.UUID.randomUUID().toString(), service, stack, null);
setLabels(labels);
if (StringUtils.equalsIgnoreCase(ServiceConstants.SERVICE_INDEX_DU_STRATEGY,
DataAccessor.fieldString(service, ServiceConstants.FIELD_SERVICE_INDEX_STRATEGY))) {
Map<String, Object> params = new HashMap<>();
// create deploymentunit
params.put("uuid", this.uuid);
params.put(ServiceConstants.FIELD_SERVICE_ID, service.getId());
params.put(InstanceConstants.FIELD_SERVICE_INSTANCE_SERVICE_INDEX,
svcInstanceIdGenerator.getNextAvailableId());
params.put("accountId", service.getAccountId());
params.put(InstanceConstants.FIELD_LABELS, this.unitLabels);
this.unit = context.objectManager.create(io.cattle.platform.core.model.DeploymentUnit.class, params);
}
}
protected void setLabels(Map<String, String> labels) {
if (labels != null) {
for (String label : labels.keySet()) {
if (supportedUnitLabels.contains(label)) {
this.unitLabels.put(label, labels.get(label));
}
}
}
}
private void createMissingUnitInstances(DeploymentUnitInstanceIdGenerator svcInstanceIdGenerator) {
Integer order = null;
for (String launchConfigName : launchConfigNames) {
if (!launchConfigToInstance.containsKey(launchConfigName)) {
if (this.unit != null) {
order = Integer.valueOf(this.unit.getServiceIndex());
} else if (order == null) {
order = svcInstanceIdGenerator.getNextAvailableId(launchConfigName);
}
String instanceName = ServiceDiscoveryUtil.generateServiceInstanceName(stack,
service, launchConfigName, order);
DeploymentUnitInstance deploymentUnitInstance = context.deploymentUnitInstanceFactory
.createDeploymentUnitInstance(context, uuid, service, instanceName, null, launchConfigName);
addDeploymentInstance(launchConfigName, deploymentUnitInstance);
}
}
}
public boolean isError() {
/*
* This should check for instances with an error transitioning state
*/
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
if (instance.isError()) {
return true;
}
}
return false;
}
private Host getDeploymentUnitHost() {
for (DeploymentUnitInstance deployUnitInstance : getDeploymentUnitInstances()) {
if (!(deployUnitInstance instanceof InstanceUnit)) {
// external deployment units do not have instances
return null;
}
Instance instance = ((InstanceUnit) deployUnitInstance).getInstance();
if (instance != null && instance.getId() != null) {
// TODO: Performance-wise, this is really bad! Especially, since we already
// know what host is going down from the host trigger.
// Check whether this instance has been deployed and if so, what is the state of the
// host?
Host host = context.exposeMapDao.getHostForInstance(instance.getId());
if (host != null) {
return host;
}
}
}
return null;
}
private boolean isRemovedHost(Host host) {
if (host == null) {
return false;
}
return CommonStatesConstants.REMOVING.equals(host.getState()) ||
CommonStatesConstants.REMOVED.equals(host.getState()) ||
CommonStatesConstants.PURGING.equals(host.getState()) ||
CommonStatesConstants.PURGED.equals(host.getState());
}
private boolean isAgentDisconnected(Host host) {
if (host == null) {
return false;
}
Agent agent = context.objectManager.loadResource(Agent.class, host.getAgentId());
if (agent != null && (AgentConstants.STATE_RECONNECTING.equals(agent.getState()) ||
AgentConstants.STATE_DISCONNECTED.equals(agent.getState()) || AgentConstants.STATE_DISCONNECTING
.equals(agent.getState()))) {
return true;
}
return false;
}
public void remove(String reason, String level) {
/*
* Delete all instances. This should be non-blocking (don't wait)
*/
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
String error = "";
if (instance instanceof InstanceUnit) {
error = TransitioningUtils.getTransitioningError(((DefaultDeploymentUnitInstance) instance).getInstance());
}
if (StringUtils.isNotBlank(error)) {
reason = reason + ": " + error;
}
instance.generateAuditLog(AuditEventType.delete, reason, level);
instance.remove();
}
if (unit != null) {
clenaupVolumes();
Map<String, Object> params = new HashMap<>();
params.put(ObjectMetaDataManager.REMOVED_FIELD, new Date());
params.put(ObjectMetaDataManager.REMOVE_TIME_FIELD, new Date());
params.put(ObjectMetaDataManager.STATE_FIELD, CommonStatesConstants.REMOVED);
context.objectManager.setFields(unit, params);
}
}
public void clenaupVolumes() {
if (unit == null) {
return;
}
List<? extends Volume> volumes = context.objectManager.find(Volume.class, VOLUME.REMOVED, null,
VOLUME.DEPLOYMENT_UNIT_ID, unit.getId());
for (Volume volume : volumes) {
if (!(volume.getState().equals(CommonStatesConstants.REMOVED) || volume.getState().equals(
CommonStatesConstants.REMOVING))) {
try {
context.objectProcessManager.scheduleStandardProcessAsync(StandardProcess.REMOVE, volume,
null);
} catch (ProcessCancelException e) {
context.objectProcessManager.scheduleStandardProcessAsync(StandardProcess.DEACTIVATE,
volume, ProcessUtils.chainInData(new HashMap<String, Object>(),
ExternalEventConstants.PROC_VOL_DEACTIVATE,
ExternalEventConstants.PROC_VOL_REMOVE));
}
}
}
}
public void waitForRemoval() {
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
instance.waitForRemoval();
}
}
public void cleanupUnit() {
/*
* Delete all the units having missing dependencies
*/
cleanupInstancesWithMissingDependencies();
}
public void stop() {
/*
* stops all instances. This should be non-blocking (don't wait)
*/
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
instance.stop();
}
}
public void start() {
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
instance.start();
}
}
public void create(DeploymentUnitInstanceIdGenerator svcInstanceIdGenerator) {
/*
* Start the instances in the correct order depending on the volumes from.
* Attempt to start things in parallel, but if not possible (like volumes-from) then start each service
* sequentially.
*
* If there are three services but only two containers, create the third
*
* If one of the containers service health is bad, then create another one (but don't delete the existing).
*
*/
createMissingUnitInstances(svcInstanceIdGenerator);
List<DeploymentUnitInstance> createdInstances = createServiceInstances();
for (DeploymentUnitInstance instance : createdInstances) {
instance.scheduleCreate();
}
}
protected List<DeploymentUnitInstance> createServiceInstances() {
List<DeploymentUnitInstance> createdInstances = new ArrayList<>();
for (String launchConfigName : launchConfigNames) {
createdInstances.add(createInstance(launchConfigName, service));
}
return createdInstances;
}
public void waitForStart(){
// sort based on dependencies
List<String> sortedLCs = new ArrayList<>();
for (String lc : launchConfigToInstance.keySet()) {
sortSidekicks(sortedLCs, lc);
}
List<DeploymentUnitInstance> sortedInstances = new ArrayList<>();
for (String lc : sortedLCs) {
sortedInstances.add(launchConfigToInstance.get(lc));
}
for (DeploymentUnitInstance instance : sortedInstances) {
instance.waitForStart();
}
}
protected void sortSidekicks(List<String> sorted, String lc) {
List<String> sidekicks = getSidekickRefs(service, lc);
for (String sidekick : sidekicks) {
sortSidekicks(sorted, sidekick);
}
if (!sorted.contains(lc)) {
sorted.add(lc);
}
}
protected DeploymentUnitInstance createInstance(String launchConfigName, Service service) {
List<Integer> volumesFromInstanceIds = getSidekickContainersId(service, launchConfigName, SidekickType.DATA);
List<Integer> networkContainerIds = getSidekickContainersId(service, launchConfigName, SidekickType.NETWORK);
Integer networkContainerId = networkContainerIds.isEmpty() ? null : networkContainerIds.get(0);
List<String> namedVolumes = getNamedVolumes(launchConfigName, service);
List<String> internalVolumes = new ArrayList<>();
Map<String, Long> volumeMounts = new HashMap<>();
for (String namedVolume : namedVolumes) {
createVolume(service, namedVolume, volumeMounts, internalVolumes);
}
launchConfigToInstance.get(launchConfigName)
.create(
populateDeployParams(launchConfigToInstance.get(launchConfigName),
volumesFromInstanceIds,
networkContainerId, internalVolumes, volumeMounts));
DeploymentUnitInstance toReturn = launchConfigToInstance.get(launchConfigName);
return toReturn;
}
protected void createVolume(final Service service, String volumeName, Map<String, Long> volumeMounts,
List<String> internalVolumes) {
if (this.unit == null) {
return;
}
String[] splitted = volumeName.split(":");
String volumeNamePostfix = splitted[0];
String volumePath = volumeName.replaceFirst(splitted[0] + ":", "");
final VolumeTemplate template = context.objectManager.findOne(VolumeTemplate.class, VOLUME_TEMPLATE.ACCOUNT_ID,
service.getAccountId(), VOLUME_TEMPLATE.REMOVED, null, VOLUME_TEMPLATE.NAME, splitted[0],
VOLUME_TEMPLATE.STACK_ID, stack.getId());
if (template == null) {
return;
}
Volume volume = null;
if (template.getExternal()) {
// external volume should exist, otherwise fail
volume = context.objectManager.findAny(Volume.class, VOLUME.ACCOUNT_ID, service.getAccountId(),
VOLUME.REMOVED, null, VOLUME.NAME, template.getName());
if (volume == null) {
throw new ServiceInstanceAllocateException("Failed to locate volume for instance of deployment unit ["
+ uuid + "]", null, null);
}
return;
} else {
final String postfix = io.cattle.platform.util.resource.UUID.randomUUID().toString();
if (template.getPerContainer()) {
String name = stack.getName() + "_" + volumeNamePostfix + "_" + this.unit.getServiceIndex() + "_"
+ uuid + "_";
// append 5 random chars
List<? extends Volume> volumes = context.objectManager
.find(Volume.class, VOLUME.ACCOUNT_ID, service.getAccountId(),
VOLUME.REMOVED, null, VOLUME.VOLUME_TEMPLATE_ID, template.getId(), VOLUME.STACK_ID,
stack.getId(), VOLUME.DEPLOYMENT_UNIT_ID, unit.getId());
for (Volume vol : volumes) {
if (vol.getName().startsWith(name)) {
volume = vol;
break;
}
}
if (volume == null) {
volume = createVolume(service, template, name + postfix.substring(0, 5));
}
} else {
final String name = stack.getName() + "_" + volumeNamePostfix + "_";
volume = context.lockMgr.lock(new StackVolumeLock(stack, name), new LockCallback<Volume>() {
@Override
public Volume doWithLock() {
Volume existing = null;
List<? extends Volume> volumes = context.objectManager
.find(Volume.class, VOLUME.ACCOUNT_ID, service.getAccountId(),
VOLUME.REMOVED, null, VOLUME.VOLUME_TEMPLATE_ID, template.getId(),
VOLUME.STACK_ID,
stack.getId());
for (Volume vol : volumes) {
if (vol.getName().startsWith(name)) {
existing = vol;
break;
}
}
if (existing != null) {
return existing;
}
return createVolume(service, template, new String(name + postfix.substring(0, 5)));
}
});
}
}
volumeMounts.put(volumePath, volume.getId());
internalVolumes.add(volumeName);
}
private Volume createVolume(Service service, VolumeTemplate template, String name) {
Map<String, Object> params = new HashMap<>();
if (template.getPerContainer()) {
params.put(ServiceConstants.FIELD_DEPLOYMENT_UNIT_ID, unit.getId());
}
params.put("name", name);
params.put("accountId", service.getAccountId());
params.put(ServiceConstants.FIELD_STACK_ID, service.getStackId());
params.put(ServiceConstants.FIELD_VOLUME_TEMPLATE_ID, template.getId());
params.put(VolumeConstants.FIELD_VOLUME_DRIVER_OPTS,
DataAccessor.fieldMap(template, VolumeConstants.FIELD_VOLUME_DRIVER_OPTS));
params.put(VolumeConstants.FIELD_VOLUME_DRIVER, template.getDriver());
return context.resourceDao.createAndSchedule(Volume.class, params);
}
@SuppressWarnings("unchecked")
protected List<String> getNamedVolumes(String launchConfigName, Service service) {
Object dataVolumesObj = ServiceDiscoveryUtil.getLaunchConfigObject(service, launchConfigName,
InstanceConstants.FIELD_DATA_VOLUMES);
List<String> namedVolumes = new ArrayList<>();
if (dataVolumesObj != null) {
for (String volume : (List<String>) dataVolumesObj) {
if (isNamedVolume(volume)) {
namedVolumes.add(volume);
}
}
}
return namedVolumes;
}
protected boolean isNamedVolume(String volumeName) {
String[] splitted = volumeName.split(":");
if (splitted.length < 2) {
return false;
}
if (splitted[0].contains("/")) {
return false;
}
return true;
}
@SuppressWarnings("unchecked")
protected List<Integer> getSidekickContainersId(Service service, String launchConfigName, SidekickType sidekickType) {
List<Integer> sidekickInstanceIds = new ArrayList<>();
Object sidekickInstances = ServiceDiscoveryUtil.getLaunchConfigObject(service, launchConfigName,
sidekickType.launchConfigFieldName);
if (sidekickInstances != null) {
if (sidekickType.isList) {
sidekickInstanceIds.addAll((List<Integer>) sidekickInstances);
} else {
sidekickInstanceIds.add((Integer) sidekickInstances);
}
}
Object sidekicksLaunchConfigObj = ServiceDiscoveryUtil.getLaunchConfigObject(service, launchConfigName,
sidekickType.launchConfigType);
if (sidekicksLaunchConfigObj != null) {
List<String> sidekicksLaunchConfigNames = new ArrayList<>();
if (sidekickType.isList) {
sidekicksLaunchConfigNames.addAll((List<String>) sidekicksLaunchConfigObj);
} else {
sidekicksLaunchConfigNames.add(sidekicksLaunchConfigObj.toString());
}
for (String sidekickLaunchConfigName : sidekicksLaunchConfigNames) {
// check if the service is present in the service map (it can be referenced, but removed already)
if (sidekickLaunchConfigName.toString().equalsIgnoreCase(service.getName())) {
sidekickLaunchConfigName = ServiceConstants.PRIMARY_LAUNCH_CONFIG_NAME;
}
DeploymentUnitInstance sidekickUnitInstance = launchConfigToInstance.get(sidekickLaunchConfigName
.toString());
if (sidekickUnitInstance != null && sidekickUnitInstance instanceof InstanceUnit) {
if (((InstanceUnit) sidekickUnitInstance).getInstance() == null) {
// request new instance creation
sidekickUnitInstance = createInstance(sidekickUnitInstance.getLaunchConfigName(), service);
}
sidekickInstanceIds.add(((InstanceUnit) sidekickUnitInstance).getInstance().getId()
.intValue());
}
}
}
return sidekickInstanceIds;
}
public boolean isStarted() {
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
if (!instance.isStarted()) {
return false;
}
}
return true;
}
public boolean isHealthCheckInitializing() {
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
if (instance.isHealthCheckInitializing()) {
return true;
}
}
return false;
}
public boolean isUnhealthy() {
// returns list of instances that need cleanup (having bad health)
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
if (instance.isUnhealthy()) {
return true;
}
}
// unhealthy when host is removed
Host host = getDeploymentUnitHost();
if (host == null) {
return false;
}
if (isRemovedHost(host)) {
return true;
}
// unhealthy when in transitioning state on inactive host
if (isTransitioning() && isAgentDisconnected(host)) {
return true;
}
return false;
}
protected boolean isTransitioning() {
for (DeploymentUnitInstance instance : getDeploymentUnitInstances()) {
if (instance.isTransitioning()) {
return true;
}
}
return false;
}
protected Map<String, Object> populateDeployParams(DeploymentUnitInstance instance,
List<Integer> volumesFromInstanceIds, Integer networkContainerId, List<String> namedVolumes, Map<String, Long> internalVolumes) {
Map<String, Object> deployParams = new HashMap<>();
Map<String, String> instanceLabels = getLabels(instance);
deployParams.put(InstanceConstants.FIELD_LABELS, instanceLabels);
if (volumesFromInstanceIds != null && !volumesFromInstanceIds.isEmpty()) {
deployParams.put(DockerInstanceConstants.FIELD_VOLUMES_FROM, volumesFromInstanceIds);
}
Object hostId = instanceLabels.get(ServiceConstants.LABEL_SERVICE_REQUESTED_HOST_ID);
if (hostId != null) {
deployParams.put(InstanceConstants.FIELD_REQUESTED_HOST_ID, hostId);
}
if (networkContainerId != null) {
deployParams.put(DockerInstanceConstants.FIELD_NETWORK_CONTAINER_ID, networkContainerId);
}
deployParams.put(InstanceConstants.FIELD_DEPLOYMENT_UNIT_UUID, this.uuid);
deployParams.put(ServiceConstants.FIELD_VERSION, ServiceDiscoveryUtil.getLaunchConfigObject(
instance.getService(), instance.getLaunchConfigName(), ServiceConstants.FIELD_VERSION));
addDns(instance, deployParams);
deployParams.put(ServiceConstants.FIELD_INTERNAL_VOLUMES, namedVolumes);
deployParams.put(InstanceConstants.FIELD_DATA_VOLUME_MOUNTS, internalVolumes);
return deployParams;
}
protected void addDns(DeploymentUnitInstance instance, Map<String, Object> deployParams) {
boolean addDns = true;
Object labelsObj = ServiceDiscoveryUtil.getLaunchConfigObject(
instance.getService(), instance.getLaunchConfigName(), InstanceConstants.FIELD_LABELS);
if (labelsObj != null) {
Map<String, Object> labels = CollectionUtils.toMap(labelsObj);
if (labels.containsKey(SystemLabels.LABEL_USE_RANCHER_DNS)
&& !Boolean.valueOf(SystemLabels.LABEL_USE_RANCHER_DNS))
addDns = false;
}
if (addDns) {
deployParams.put(DockerInstanceConstants.FIELD_DNS_SEARCH, instance.getSearchDomains());
}
}
protected Map<String, String> getLabels(DeploymentUnitInstance instance) {
Map<String, String> labels = new HashMap<>();
String serviceName = instance.getService().getName();
if (!ServiceConstants.PRIMARY_LAUNCH_CONFIG_NAME.equals(instance.getLaunchConfigName())) {
serviceName = serviceName + '/' + instance.getLaunchConfigName();
}
String envName = stack.getName();
labels.put(ServiceConstants.LABEL_STACK_NAME, envName);
labels.put(ServiceConstants.LABEL_STACK_SERVICE_NAME, envName + "/" + serviceName);
// LEGACY: keeping backwards compatibility with 'project'
labels.put(ServiceConstants.LABEL_PROJECT_NAME, envName);
labels.put(ServiceConstants.LABEL_PROJECT_SERVICE_NAME, envName + "/" + serviceName);
/*
* Put label 'io.rancher.deployment.unit=this.uuid' on each one. This way
* we can reference a set of containers later.
*/
labels.put(ServiceConstants.LABEL_SERVICE_DEPLOYMENT_UNIT, uuid);
/*
* Put label with launch config name
*/
labels.put(ServiceConstants.LABEL_SERVICE_LAUNCH_CONFIG, instance.getLaunchConfigName());
labels.putAll(this.unitLabels);
return labels;
}
public Map<String, String> getLabels() {
return unitLabels;
}
public List<DeploymentUnitInstance> getDeploymentUnitInstances() {
List<DeploymentUnitInstance> instances = new ArrayList<>();
instances.addAll(launchConfigToInstance.values());
return instances;
}
public long getCreateIndex() {
if (this.unit != null && getDeploymentUnitInstances().size() == 0) {
return Long.valueOf(this.unit.getServiceIndex());
}
long createIndex = 0L;
// find minimum created
for (DeploymentUnitInstance i : getDeploymentUnitInstances()) {
if (i.getCreateIndex() == null) {
continue;
}
if (createIndex == 0) {
createIndex = i.getCreateIndex();
continue;
}
if (i.getCreateIndex().longValue() < createIndex) {
createIndex = i.getCreateIndex();
}
}
return createIndex;
}
public void addDeploymentInstance(String launchConfig, DeploymentUnitInstance instance) {
this.launchConfigToInstance.put(launchConfig, instance);
}
public boolean isComplete() {
return launchConfigNames.size() == launchConfigToInstance.size();
}
public void cleanupInstancesWithMissingDependencies() {
for (String launchConfigName : launchConfigNames) {
if (!launchConfigToInstance.containsKey(launchConfigName)) {
cleanupInstanceWithMissingDep(launchConfigName);
}
}
}
protected void cleanupInstanceWithMissingDep(String launchConfigName) {
List<String> usedInLaunchConfigs = sidekickUsedByMap.get(launchConfigName);
if (usedInLaunchConfigs == null) {
return;
}
for (String usedInLaunchConfig : usedInLaunchConfigs) {
DeploymentUnitInstance usedByInstance = launchConfigToInstance.get(usedInLaunchConfig);
if (usedByInstance == null) {
continue;
}
clenaupDeploymentInstance(usedByInstance);
cleanupInstanceWithMissingDep(usedInLaunchConfig);
}
}
protected void clenaupDeploymentInstance(DeploymentUnitInstance instance) {
instance.remove();
launchConfigToInstance.remove(instance.getLaunchConfigName());
}
@SuppressWarnings("unchecked")
public List<String> getSidekickRefs(Service service, String launchConfigName) {
List<String> configNames = new ArrayList<>();
for (DeploymentUnit.SidekickType sidekickType : DeploymentUnit.SidekickType.supportedTypes) {
Object sidekicksLaunchConfigObj = ServiceDiscoveryUtil.getLaunchConfigObject(service, launchConfigName,
sidekickType.launchConfigType);
if (sidekicksLaunchConfigObj != null) {
if (sidekickType.isList) {
configNames.addAll((List<String>) sidekicksLaunchConfigObj);
} else {
configNames.add(sidekicksLaunchConfigObj.toString());
}
}
}
List<String> toReturn = new ArrayList<>();
for (String name : configNames) {
if (name.equalsIgnoreCase(service.getName())) {
toReturn.add(ServiceConstants.PRIMARY_LAUNCH_CONFIG_NAME);
} else {
toReturn.add(name);
}
}
return toReturn;
}
}