package io.cattle.platform.servicediscovery.process; import io.cattle.platform.core.constants.InstanceConstants; import io.cattle.platform.core.constants.ServiceConstants; import io.cattle.platform.core.dao.InstanceDao; import io.cattle.platform.core.dao.NetworkDao; import io.cattle.platform.core.model.Instance; import io.cattle.platform.core.model.Port; import io.cattle.platform.core.model.Service; import io.cattle.platform.engine.handler.HandlerResult; import io.cattle.platform.engine.handler.ProcessPostListener; import io.cattle.platform.engine.process.ProcessInstance; import io.cattle.platform.engine.process.ProcessState; import io.cattle.platform.json.JsonMapper; import io.cattle.platform.process.common.handler.AbstractObjectProcessLogic; import io.cattle.platform.servicediscovery.api.dao.ServiceExposeMapDao; import io.cattle.platform.servicediscovery.api.util.ServiceDiscoveryUtil; import io.cattle.platform.servicediscovery.service.ServiceDiscoveryService; import io.cattle.platform.util.type.Priority; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; @Named public class LoadBalancerServiceUpdatePostListener extends AbstractObjectProcessLogic implements ProcessPostListener, Priority { @Inject ServiceDiscoveryService sdService; @Inject JsonMapper jsonMapper; @Inject ServiceExposeMapDao expMapDao; @Inject NetworkDao ntwkDao; @Inject InstanceDao instanceDao; @Override public String[] getProcessNames() { return new String[] { ServiceConstants.PROCESS_SERVICE_UPDATE }; } @Override public HandlerResult handle(ProcessState state, ProcessInstance process) { Service service = (Service) state.getResource(); if (!service.getKind().equalsIgnoreCase(ServiceConstants.KIND_LOAD_BALANCER_SERVICE)) { return null; } updateServicePorts(service, state); return null; } @SuppressWarnings("unchecked") private void updateServicePorts(Service service, ProcessState state) { sdService.setPorts(service); // only perform update when ports got changed Object oldObj = state.getData().get("old"); List<String> oldPortDefs = new ArrayList<>(); if (oldObj != null) { Map<String, Object> old = (Map<String, Object>) oldObj; if (old.containsKey(ServiceConstants.FIELD_LAUNCH_CONFIG)) { Map<String, Object> oldLC = (Map<String, Object>) old.get(ServiceConstants.FIELD_LAUNCH_CONFIG); if (oldLC.get(InstanceConstants.FIELD_PORTS) != null) { oldPortDefs = (List<String>) oldLC.get(InstanceConstants.FIELD_PORTS); } } } Map<String, Object> launchConfigData = ServiceDiscoveryUtil.getLaunchConfigDataAsMap(service, ServiceConstants.PRIMARY_LAUNCH_CONFIG_NAME); List<String> newPortDefs = new ArrayList<>(); if (launchConfigData.get(InstanceConstants.FIELD_PORTS) != null) { newPortDefs = (List<String>) launchConfigData.get(InstanceConstants.FIELD_PORTS); } if (newPortDefs.containsAll(oldPortDefs) && oldPortDefs.containsAll(newPortDefs)) { return; } List<? extends Instance> serviceContainers = expMapDao.listServiceManagedInstancesAll(service); for (Instance instance : serviceContainers) { List<Port> toCreate = new ArrayList<>(); List<Port> toRemove = new ArrayList<>(); Map<String, Port> toRetain = new HashMap<>(); // orchestrate port creation/removal ntwkDao.updateInstancePorts(instance, newPortDefs, toCreate, toRemove, toRetain); for (Port port : toCreate) { port = objectManager.create(port); } // trigger instance/metadata update instance = objectManager.setFields(instance, InstanceConstants.FIELD_PORTS, newPortDefs); instanceDao.clearCacheInstanceData(instance.getId()); for (Port port : toRetain.values()) { createThenActivate(port, new HashMap<String, Object>()); } for (Port port : toRemove) { deactivateThenRemove(port, new HashMap<String, Object>()); } } } @Override public int getPriority() { return Priority.DEFAULT; } protected void removePort(Port port) { deactivateThenRemove(port, null); } }