package io.cattle.platform.servicediscovery.deployment.impl.unit;
import static io.cattle.platform.core.model.tables.DeploymentUnitTable.*;
import static io.cattle.platform.core.model.tables.StackTable.*;
import io.cattle.platform.core.constants.InstanceConstants;
import io.cattle.platform.core.constants.ServiceConstants;
import io.cattle.platform.core.dao.GenericMapDao;
import io.cattle.platform.core.model.Instance;
import io.cattle.platform.core.model.Service;
import io.cattle.platform.core.model.ServiceExposeMap;
import io.cattle.platform.core.model.Stack;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.util.DataAccessor;
import io.cattle.platform.servicediscovery.api.dao.ServiceExposeMapDao;
import io.cattle.platform.servicediscovery.deployment.DeploymentUnitInstance;
import io.cattle.platform.servicediscovery.deployment.DeploymentUnitInstanceFactory;
import io.cattle.platform.servicediscovery.deployment.impl.DeploymentManagerImpl.DeploymentServiceContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.commons.lang3.tuple.Pair;
public class DeploymentUnitInstanceFactoryImpl implements DeploymentUnitInstanceFactory {
@Inject
ObjectManager objectMgr;
@Inject
ServiceExposeMapDao expMapDao;
@Inject
GenericMapDao mapDao;
@Override
@SuppressWarnings("unchecked")
public DeploymentUnitInstance createDeploymentUnitInstance(DeploymentServiceContext context, String uuid,
Service service, String instanceName, Object instanceObj, String launchConfigName) {
if (ServiceConstants.SERVICE_LIKE.contains(service.getKind())) {
Instance instance = null;
if (instanceObj != null) {
instance = (Instance) instanceObj;
}
return new DefaultDeploymentUnitInstance(context, uuid, service,
instanceName, instance, launchConfigName);
} else if (service.getKind().equalsIgnoreCase(ServiceConstants.KIND_EXTERNAL_SERVICE)) {
Pair<String, String> ipHostName = null;
if (instanceObj != null) {
ipHostName = (Pair<String, String>) instanceObj;
}
return new ExternalDeploymentUnitInstance(context, uuid, service, launchConfigName, ipHostName.getLeft(),
ipHostName.getRight());
}
return null;
}
@Override
public List<DeploymentUnit> collectDeploymentUnits(Service service, DeploymentServiceContext context) {
/*
* 1. find all containers related to the service through the serviceexposemaps
* Then group all the objects
* by the label 'io.rancher.deployment.unit'. When containers are deployed through service discovery that
* label will be placed on them.
*
* 2. put all the containers to the deploymentUnit
*/
Map<String, Map<String, String>> uuidToLabels = new HashMap<>();
Map<String, List<DeploymentUnitInstance>> uuidToInstances = new HashMap<>();
List<DeploymentUnit> units = new ArrayList<>();
Map<String, io.cattle.platform.core.model.DeploymentUnit> uuidToExistingDU = new HashMap<>();
if (ServiceConstants.SERVICE_LIKE.contains(service.getKind())) {
collectDefaultServiceInstances(context, uuidToLabels, uuidToInstances, service, uuidToExistingDU);
} else if (service.getKind().equalsIgnoreCase(ServiceConstants.KIND_EXTERNAL_SERVICE)) {
collectExternalServiceInstances(context, uuidToLabels, uuidToInstances, service, uuidToExistingDU);
}
Stack stack = context.objectManager.findOne(Stack.class, STACK.ID, service.getStackId());
for (String uuid : uuidToInstances.keySet()) {
DeploymentUnit unit = new DeploymentUnit(context, uuid, service, uuidToInstances.get(uuid),
uuidToLabels.get(uuid), stack, uuidToExistingDU);
units.add(unit);
}
return units;
}
protected void collectExternalServiceInstances(DeploymentServiceContext context,
Map<String, Map<String, String>> uuidToLabels, Map<String, List<DeploymentUnitInstance>> uuidToInstances,
Service service, Map<String, io.cattle.platform.core.model.DeploymentUnit> uuidToExistingDU) {
// 1. request deployment units for ips defined on the service
createExternalUnitsForIps(context, uuidToLabels, uuidToInstances, service);
// 2. request deployment units for hostname defined on the service
createDeploymentUnitsForHostname(context, uuidToLabels, uuidToInstances, service);
}
protected void createDeploymentUnitsForHostname(DeploymentServiceContext context,
Map<String, Map<String, String>> uuidToLabels, Map<String, List<DeploymentUnitInstance>> uuidToInstances,
Service service) {
String hostName = DataAccessor.fields(service)
.withKey(ServiceConstants.FIELD_HOSTNAME).as(String.class);
if (hostName != null) {
createExternalDeploymentUnit(context, uuidToLabels, uuidToInstances, service, null, hostName);
}
// get existing maps (they will be cleaned up later if ip is no longer on the service)
List<? extends ServiceExposeMap> exposeMaps = expMapDao.getNonRemovedServiceHostnameMaps(service.getId());
for (ServiceExposeMap exposeMap : exposeMaps) {
createExternalDeploymentUnit(context, uuidToLabels, uuidToInstances, service, null,
exposeMap.getHostName());
}
}
@SuppressWarnings("unchecked")
protected void createExternalUnitsForIps(DeploymentServiceContext context,
Map<String, Map<String, String>> uuidToLabels, Map<String, List<DeploymentUnitInstance>> uuidToInstances,
Service service) {
List<String> externalIps = DataAccessor.fields(service)
.withKey(ServiceConstants.FIELD_EXTERNALIPS).withDefault(Collections.EMPTY_LIST)
.as(List.class);
if (externalIps != null) {
for (String externalIp : externalIps) {
createExternalDeploymentUnit(context, uuidToLabels, uuidToInstances, service, externalIp, null);
}
}
// get existing maps (they will be cleaned up later if ip is no longer on the service)
List<? extends ServiceExposeMap> exposeMaps = expMapDao.getNonRemovedServiceIpMaps(service.getId());
for (ServiceExposeMap exposeMap : exposeMaps) {
createExternalDeploymentUnit(context, uuidToLabels, uuidToInstances, service, exposeMap.getIpAddress(),
null);
}
}
protected void createExternalDeploymentUnit(DeploymentServiceContext context,
Map<String, Map<String, String>> uuidToLabels, Map<String, List<DeploymentUnitInstance>> uuidToInstances,
Service service, String externalIp, String hostName) {
String uuid = io.cattle.platform.util.resource.UUID.randomUUID().toString();
DeploymentUnitInstance unitInstance = createDeploymentUnitInstance(context, uuid, service, null,
Pair.of(externalIp, hostName), ServiceConstants.PRIMARY_LAUNCH_CONFIG_NAME);
addToDeploymentUnitList(uuidToLabels, uuidToInstances, new HashMap<String, String>(), uuid,
unitInstance);
}
@SuppressWarnings("unchecked")
protected void collectDefaultServiceInstances(DeploymentServiceContext context,
Map<String, Map<String, String>> uuidToLabels, Map<String, List<DeploymentUnitInstance>> uuidToInstances,
Service service, Map<String, io.cattle.platform.core.model.DeploymentUnit> uuidToExistingDU) {
List<? extends Instance> serviceContainers = expMapDao.listServiceManagedInstancesAll(service);
for (Instance serviceContainer : serviceContainers) {
Map<String, String> instanceLabels = DataAccessor.fields(serviceContainer)
.withKey(InstanceConstants.FIELD_LABELS).withDefault(Collections.EMPTY_MAP).as(Map.class);
String deploymentUnitUUID = instanceLabels
.get(ServiceConstants.LABEL_SERVICE_DEPLOYMENT_UNIT);
String launchConfigName = instanceLabels
.get(ServiceConstants.LABEL_SERVICE_LAUNCH_CONFIG);
DeploymentUnitInstance unitInstance = createDeploymentUnitInstance(context, deploymentUnitUUID,
service, serviceContainer.getName(), serviceContainer, launchConfigName);
addToDeploymentUnitList(uuidToLabels, uuidToInstances, instanceLabels, deploymentUnitUUID,
unitInstance);
}
List<? extends io.cattle.platform.core.model.DeploymentUnit> units = context.objectManager.find(
io.cattle.platform.core.model.DeploymentUnit.class,
DEPLOYMENT_UNIT.ACCOUNT_ID,
service.getAccountId(), DEPLOYMENT_UNIT.REMOVED, null, DEPLOYMENT_UNIT.SERVICE_ID, service.getId());
for (io.cattle.platform.core.model.DeploymentUnit unit : units) {
if (!uuidToInstances.containsKey(unit.getUuid())) {
Map<String, String> labels = new HashMap<>();
Map<String, Object> labelsObj = DataAccessor.fieldMap(unit,
InstanceConstants.FIELD_LABELS);
for (String key : labelsObj.keySet()) {
labels.put(key, labelsObj.get(key).toString());
}
addToDeploymentUnitList(uuidToLabels, uuidToInstances, labels, unit.getUuid(),
null);
}
uuidToExistingDU.put(unit.getUuid(), unit);
}
}
protected void addToDeploymentUnitList(Map<String, Map<String, String>> uuidToLabels,
Map<String, List<DeploymentUnitInstance>> uuidToInstances, Map<String, String> instanceLabels,
String deploymentUnitUUID, DeploymentUnitInstance unitInstance) {
if (uuidToLabels.get(deploymentUnitUUID) == null) {
uuidToLabels.put(deploymentUnitUUID, instanceLabels);
}
List<DeploymentUnitInstance> deploymentUnitInstances = uuidToInstances.get(deploymentUnitUUID);
if (deploymentUnitInstances == null) {
deploymentUnitInstances = new ArrayList<>();
}
if (unitInstance != null) {
deploymentUnitInstances.add(unitInstance);
}
uuidToInstances.put(deploymentUnitUUID, deploymentUnitInstances);
}
}