package io.cattle.platform.process.driver; import static io.cattle.platform.core.model.tables.ServiceTable.*; import io.cattle.platform.archaius.util.ArchaiusUtil; import io.cattle.platform.core.addon.InServiceUpgradeStrategy; import io.cattle.platform.core.addon.LbConfig; import io.cattle.platform.core.constants.AccountConstants; import io.cattle.platform.core.constants.AgentConstants; import io.cattle.platform.core.constants.CommonStatesConstants; import io.cattle.platform.core.constants.InstanceConstants; import io.cattle.platform.core.constants.ServiceConstants; import io.cattle.platform.core.dao.LoadBalancerInfoDao; import io.cattle.platform.core.model.Account; import io.cattle.platform.core.model.Service; import io.cattle.platform.core.util.PortSpec; import io.cattle.platform.core.util.SystemLabels; import io.cattle.platform.engine.handler.HandlerResult; import io.cattle.platform.engine.process.ProcessInstance; import io.cattle.platform.engine.process.ProcessState; import io.cattle.platform.json.JsonMapper; import io.cattle.platform.object.ObjectManager; import io.cattle.platform.object.resource.ResourceMonitor; import io.cattle.platform.object.util.DataAccessor; import io.cattle.platform.process.common.handler.AbstractObjectProcessHandler; import io.cattle.platform.process.common.util.ProcessUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import com.netflix.config.DynamicStringProperty; @Named public class EnvironmentUpgrade extends AbstractObjectProcessHandler { private static final DynamicStringProperty LB_IMAGE_UUID = ArchaiusUtil.getString("lb.instance.image.uuid"); @Inject LoadBalancerInfoDao lbDao; @Inject ObjectManager objMgr; @Inject JsonMapper jsonMapper; @Inject ResourceMonitor resourceMonitor; @Override public String[] getProcessNames() { return new String[] { "account.upgrade" }; } @Override public HandlerResult handle(ProcessState state, ProcessInstance process) { HandlerResult result = new HandlerResult(AccountConstants.FIELD_VERSION, AccountConstants.ACCOUNT_VERSION.get()); Account env = (Account) state.getResource(); if (AccountConstants.PROJECT_KIND.equals(env.getKind())) { upgradeServices(env); } return result; } @SuppressWarnings("unchecked") public void upgradeServices(Account env) { List<? extends Service> lbServices = objMgr.find(Service.class, SERVICE.REMOVED, null, SERVICE.ACCOUNT_ID, env.getId(), SERVICE.KIND, ServiceConstants.KIND_LOAD_BALANCER_SERVICE); List<Service> upgradeWaitList = new ArrayList<>(); for (Service lbService : lbServices) { LbConfig lbConfig = DataAccessor.field(lbService, ServiceConstants.FIELD_LB_CONFIG, jsonMapper, LbConfig.class); Map<String, Object> existingLaunchConfig = DataAccessor.fields(lbService) .withKey(ServiceConstants.FIELD_LAUNCH_CONFIG).withDefault(Collections.EMPTY_MAP) .as(Map.class); Object image = existingLaunchConfig.get(InstanceConstants.FIELD_IMAGE_UUID); if (image != null && image.toString().equalsIgnoreCase(LB_IMAGE_UUID.get())) { upgradeWaitList.add(lbService); continue; } else { List<String> validUpgradeStates = Arrays.asList(CommonStatesConstants.ACTIVE, CommonStatesConstants.INACTIVE, CommonStatesConstants.UPDATING_ACTIVE); if (validUpgradeStates.contains(lbService.getState())) { // 1. set lbconfig/new launch config on the service InServiceUpgradeStrategy strategy = getUpgradeStrategy(lbService); lbConfig = lbDao.generateLBConfig(lbService); Map<String, Object> params = new HashMap<>(); params.put(ServiceConstants.FIELD_LB_CONFIG, lbConfig); params.put(ServiceConstants.FIELD_LAUNCH_CONFIG, strategy.getLaunchConfig()); lbService = objectManager.setFields(objectManager.reload(lbService), params); // 2. call upgrade Map<String, Object> upgradeParams = new HashMap<>(); upgradeParams.put(ServiceConstants.FIELD_IN_SERVICE_STRATEGY, strategy); objectProcessManager.scheduleProcessInstanceAsync(ServiceConstants.PROCESS_SERVICE_UPGRADE, lbService, ProcessUtils.chainInData(upgradeParams, ServiceConstants.PROCESS_SERVICE_UPGRADE, ServiceConstants.PROCESS_SERVICE_FINISH_UPGRADE)); } upgradeWaitList.add(lbService); } } // wait for service to be upgraded for (Service service : upgradeWaitList) { Service reloaded = objectManager.reload(service); resourceMonitor.waitForState(reloaded, CommonStatesConstants.ACTIVE); } } @SuppressWarnings("unchecked") protected InServiceUpgradeStrategy getUpgradeStrategy(Service service) { Map<String, Object> existingLaunchConfig = DataAccessor.fields(service) .withKey(ServiceConstants.FIELD_LAUNCH_CONFIG).withDefault(Collections.EMPTY_MAP) .as(Map.class); Map<String, Object> newLaunchConfig = new HashMap<>(); newLaunchConfig.putAll(existingLaunchConfig); // set ports if (existingLaunchConfig.containsKey(InstanceConstants.FIELD_PORTS)) { List<String> newPorts = new ArrayList<>(); for (String port : (List<String>) existingLaunchConfig.get(InstanceConstants.FIELD_PORTS)) { PortSpec spec = new PortSpec(port); spec.setPrivatePort(spec.getPublicPort()); newPorts.add(spec.toSpec()); } newLaunchConfig.put(InstanceConstants.FIELD_PORTS, newPorts); } // set image newLaunchConfig.put(InstanceConstants.FIELD_IMAGE_UUID, LB_IMAGE_UUID.get()); // set labels Map<String, String> labels = new HashMap<>(); Object labelsObj = existingLaunchConfig.get(InstanceConstants.FIELD_LABELS); if (labelsObj != null) { labels = (Map<String, String>) labelsObj; } labels.put(SystemLabels.LABEL_AGENT_ROLE, AgentConstants.ENVIRONMENT_ADMIN_ROLE); labels.put(SystemLabels.LABEL_AGENT_CREATE, "true"); newLaunchConfig.put(InstanceConstants.FIELD_LABELS, labels); // generate version String version = io.cattle.platform.util.resource.UUID.randomUUID().toString(); newLaunchConfig.put(ServiceConstants.FIELD_VERSION, version); return new InServiceUpgradeStrategy(newLaunchConfig, new ArrayList<Object>(), existingLaunchConfig, new ArrayList<Object>(), false, 2000L, 1L); } }