package io.cattle.platform.systemstack.process; import static io.cattle.platform.core.model.tables.AccountTable.*; import static io.cattle.platform.core.model.tables.InstanceTable.*; import static io.cattle.platform.core.model.tables.PhysicalHostTable.*; import static io.cattle.platform.core.model.tables.ProjectTemplateTable.*; import io.cattle.platform.core.constants.AccountConstants; import io.cattle.platform.core.constants.InstanceConstants; import io.cattle.platform.core.constants.MachineConstants; import io.cattle.platform.core.constants.NetworkConstants; import io.cattle.platform.core.dao.NetworkDao; import io.cattle.platform.core.model.Account; import io.cattle.platform.core.model.Host; import io.cattle.platform.core.model.Instance; import io.cattle.platform.core.model.Network; import io.cattle.platform.core.model.PhysicalHost; import io.cattle.platform.core.model.ProjectTemplate; import io.cattle.platform.deferred.util.DeferredUtils; import io.cattle.platform.docker.constants.DockerInstanceConstants; import io.cattle.platform.engine.handler.HandlerResult; import io.cattle.platform.engine.handler.ProcessPreListener; import io.cattle.platform.engine.process.ProcessInstance; import io.cattle.platform.engine.process.ProcessState; import io.cattle.platform.object.meta.ObjectMetaDataManager; import io.cattle.platform.object.resource.ResourceMonitor; import io.cattle.platform.object.resource.ResourcePredicate; import io.cattle.platform.object.util.DataAccessor; import io.cattle.platform.object.util.DataUtils; import io.cattle.platform.process.common.handler.AbstractObjectProcessLogic; import io.cattle.platform.systemstack.catalog.CatalogService; import io.github.ibuildthecloud.gdapi.condition.Condition; import io.github.ibuildthecloud.gdapi.condition.ConditionType; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; @Named public class SystemStackEnvironmentUpgrade extends AbstractObjectProcessLogic implements ProcessPreListener { @Inject SystemStackTrigger systemStackTrigger; @Inject ResourceMonitor resourceMonitor; @Inject NetworkDao networkDao; @Override public String[] getProcessNames() { return new String[] { "account.upgrade" }; } @Override public HandlerResult handle(ProcessState state, ProcessInstance process) { Account env = (Account)state.getResource(); if (!AccountConstants.PROJECT_KIND.equals(env.getKind())) { return null; } String version = env.getVersion(); if (AccountConstants.ACCOUNT_VERSION.get().equals(version)) { return null; } checkDefaultNetwork(env); assignTemplate(env); Network network = getIpSectNetwork(env); networkDao.migrateToNetwork(network); migrateInstances(network); upgradeHosts(env); objectManager.reload(env); return null; } protected void migrateInstances(Network network) { List<Instance> instances = objectManager.find(Instance.class, INSTANCE.REMOVED, null, INSTANCE.ACCOUNT_ID, network.getAccountId()); for (Instance instance : instances) { String networkMode = DataAccessor.fieldString(instance, DockerInstanceConstants.FIELD_NETWORK_MODE); if ("managed".equals(networkMode)) { List<Long> networkIds = DataAccessor.fieldLongList(instance, InstanceConstants.FIELD_NETWORK_IDS); if (networkIds != null && networkIds.size() == 1 && !network.getId().equals(networkIds.get(0))) { DataAccessor.setField(instance, InstanceConstants.FIELD_NETWORK_IDS, Arrays.asList(network.getId())); objectManager.persist(instance); } } } } protected void upgradeHosts(Account account) { List<PhysicalHost> phyHosts = objectManager.find(PhysicalHost.class, PHYSICAL_HOST.DRIVER, new Condition(ConditionType.NOTNULL), PHYSICAL_HOST.REMOVED, null, PHYSICAL_HOST.ACCOUNT_ID, account.getId()); for (PhysicalHost physicalHost : phyHosts) { for (Host host : objectManager.children(physicalHost, Host.class)) { String driver = DataAccessor.fieldString(host, MachineConstants.FIELD_DRIVER); if (!physicalHost.getDriver().equals(driver)) { objectManager.setFields(host, MachineConstants.FIELD_DRIVER, physicalHost.getDriver()); } } } } protected void checkDefaultNetwork(Account account) { Map<String, Object> fields = DataUtils.getWritableFields(account); boolean changed = fields.remove(AccountConstants.FIELD_DEFAULT_NETWORK_ID) != null; if (changed) { objectManager.persist(account); } } protected Network getIpSectNetwork(final Account account) { resourceMonitor.waitFor(account, new ResourcePredicate<Account>() { @Override public boolean evaluate(Account obj) { return findIpSecNetwork(account) != null; } @Override public String getMessage() { return "default network to be create"; } }); return findIpSecNetwork(account); } protected Network findIpSecNetwork(Account account) { return objectManager.findAny(Network.class, ObjectMetaDataManager.ACCOUNT_FIELD, account.getId(), ObjectMetaDataManager.KIND_FIELD, NetworkConstants.KIND_CNI, ObjectMetaDataManager.REMOVED_FIELD, null); } protected void assignTemplate(final Account env) { if (env.getProjectTemplateId() != null) { return; } final ProjectTemplate template = objectManager.findAny(ProjectTemplate.class, PROJECT_TEMPLATE.IS_PUBLIC, true, PROJECT_TEMPLATE.REMOVED, null, PROJECT_TEMPLATE.NAME, CatalogService.DEFAULT_TEMPLATE.get()); if (template == null) { throw new IllegalStateException("Failed to find default template for upgrade"); } DeferredUtils.nest(new Runnable() { @Override public void run() { systemStackTrigger.trigger(env.getId()); objectManager.setFields(env, ACCOUNT.PROJECT_TEMPLATE_ID, template.getId()); } }); } }