package io.cattle.platform.systemstack.service; import static io.cattle.platform.core.model.tables.ScheduledUpgradeTable.*; import io.cattle.platform.archaius.util.ArchaiusUtil; import io.cattle.platform.core.dao.GenericResourceDao; import io.cattle.platform.core.dao.StackDao; import io.cattle.platform.core.model.ScheduledUpgrade; import io.cattle.platform.core.model.Stack; import io.cattle.platform.lock.LockManager; import io.cattle.platform.object.process.ObjectProcessManager; import io.cattle.platform.systemstack.catalog.CatalogService; import io.cattle.platform.systemstack.lock.ScheduledUpgradeLock; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.config.DynamicBooleanProperty; import com.netflix.config.DynamicIntProperty; public class UpgradeManager { private static final DynamicIntProperty MAX_UPGRADE = ArchaiusUtil.getInt("concurrent.scheduled.upgrades"); public static final DynamicBooleanProperty UPGRADE_MANAGER = ArchaiusUtil.getBoolean("upgrade.manager"); public static final String METADATA = "library:infra*network-services"; private static final DynamicBooleanProperty LAUNCH_CATALOG = ArchaiusUtil.getBoolean("catalog.execute"); private static final Logger log = LoggerFactory.getLogger(UpgradeManager.class); private static final Set<String> OLD_METADATAS = new HashSet<>(Arrays.asList( "library:infra*network-services:0", "library:infra*network-services:1", "library:infra*network-services:2", "library:infra*network-services:3", "library:infra*network-services:4", "library:infra*network-services:5", "library:infra*network-services:6", "library:infra*network-services:7", "library:infra*network-services:8", "library:infra*network-services:9", "library:infra*network-services:11", "library:infra*network-services:12", "library:infra*network-services:13", "library:infra*network-services:14", "library:infra*network-services:18" )); @Inject CatalogService catalogService; @Inject StackDao stackDao; @Inject GenericResourceDao resourceDao; @Inject LockManager lockManager; @Inject ObjectProcessManager processManager; public void schedule() throws IOException { lockManager.lock(new ScheduledUpgradeLock(), ()->{ try { scheduleWithLock(); runWithLock(false); } catch (Exception e) { throw new IllegalStateException(e); } return null; }); } protected void scheduleWithLock() throws IOException { if (!LAUNCH_CATALOG.get()) { return; } Map<String, String> catalogs = null; while (true) { try { catalogs = catalogService.latestInfraTemplates(); break; } catch (IOException e) { log.info("Waiting for catalog service"); try { Thread.sleep(2000); } catch (InterruptedException e1) { throw new IllegalStateException(e1); } } } if (catalogs.size() == 0) { return; } List<? extends Stack> stacks = UPGRADE_MANAGER.get() ? stackDao.getStacksToUpgrade(catalogs.values()) : stackDao.getStacksThatMatch(OLD_METADATAS); for (Stack stack : stacks) { String templateId = catalogService.getTemplateIdFromExternalId(stack.getExternalId()); if (StringUtils.isBlank(templateId)) { continue; } if (catalogs.containsKey(templateId)) { resourceDao.createAndSchedule(ScheduledUpgrade.class, SCHEDULED_UPGRADE.ACCOUNT_ID, stack.getAccountId(), SCHEDULED_UPGRADE.STACK_ID, stack.getId()); } } } public void run() throws IOException { lockManager.tryLock(new ScheduledUpgradeLock(), ()->{ try { runWithLock(true); } catch (Exception e) { throw new IllegalStateException(e); } return null; }); } protected void runWithLock(boolean scheduleNext) throws IOException { int max = MAX_UPGRADE.get(); if (scheduleNext) { max++; } List<? extends ScheduledUpgrade> running = stackDao.getRunningUpgrades(); if (running.size() >= max) { return; } Set<Long> runningAccounts = running.stream() .map((x)-> x.getAccountId()) .collect(Collectors.toSet()); List<? extends ScheduledUpgrade> toRun = stackDao.getReadyUpgrades(runningAccounts, max-running.size()); for (ScheduledUpgrade upgrade : toRun) { processManager.scheduleProcessInstance("scheduledupgrade.start", upgrade, null); } } }