package io.cattle.platform.systemstack.service; import static io.cattle.platform.core.model.tables.ProjectTemplateTable.*; import io.cattle.platform.archaius.util.ArchaiusUtil; import io.cattle.platform.async.utils.TimeoutException; import io.cattle.platform.core.dao.GenericResourceDao; import io.cattle.platform.core.model.ProjectTemplate; import io.cattle.platform.lock.LockCallbackWithException; import io.cattle.platform.lock.LockManager; import io.cattle.platform.object.ObjectManager; import io.cattle.platform.object.process.ObjectProcessManager; import io.cattle.platform.systemstack.catalog.CatalogService; import io.cattle.platform.systemstack.lock.ProjectTemplateLoadLock; import io.cattle.platform.task.Task; import io.cattle.platform.util.exception.ExceptionUtils; import io.cattle.platform.util.type.InitializationTask; import io.github.ibuildthecloud.gdapi.condition.Condition; import io.github.ibuildthecloud.gdapi.condition.ConditionType; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import javax.inject.Inject; import javax.inject.Named; import org.apache.cloudstack.managed.context.NoExceptionRunnable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.config.DynamicBooleanProperty; public class ProjectTemplateService implements InitializationTask, Task { private static final DynamicBooleanProperty CATALOG_URL = ArchaiusUtil.getBoolean("catalog.url"); private static final DynamicBooleanProperty LAUNCH_CATALOG = ArchaiusUtil.getBoolean("catalog.execute"); private static final DynamicBooleanProperty DEFAULTS = ArchaiusUtil.getBoolean("project.template.defaults"); private static final Logger log = LoggerFactory.getLogger(ProjectTemplateService.class); @Inject CatalogService catalogService; @Inject @Named("CoreExecutorService") ExecutorService executor; @Inject ObjectManager objectManager; @Inject ObjectProcessManager processManager; @Inject GenericResourceDao resourceDao; @Inject LockManager lockManager; boolean initialRun = true; @Override public void start() { Runnable run = new NoExceptionRunnable() { @Override protected void doRun() throws Exception { while (true) { try { reload(); log.info("Loaded project templates from the catalog"); break; } catch (IOException e) { } Thread.sleep(1000); } } }; CATALOG_URL.addCallback(run); LAUNCH_CATALOG.addCallback(run); DEFAULTS.addCallback(run); executor.submit(run); } @Override public void run() { try { reload(); } catch (IOException e) { } catch (InterruptedException e) { } } protected void reload() throws IOException, InterruptedException { try { lockManager.tryLock(new ProjectTemplateLoadLock(), new LockCallbackWithException<Object, Exception>() { @Override public Object doWithLock() throws Exception { reloadWithLock(); return null; } }, Exception.class); } catch (Exception e) { ExceptionUtils.rethrow(e, InterruptedException.class); ExceptionUtils.rethrow(e, IOException.class); ExceptionUtils.rethrowRuntime(e); } } protected void reloadWithLock() throws IOException, InterruptedException { if (!LAUNCH_CATALOG.get() || !DEFAULTS.get()) { return; } List<ProjectTemplate> installedTemplates = objectManager.find(ProjectTemplate.class, PROJECT_TEMPLATE.IS_PUBLIC, true, PROJECT_TEMPLATE.REMOVED, null, PROJECT_TEMPLATE.EXTERNAL_ID, new Condition(ConditionType.LIKE, "catalog://%")); Map<String, Map<Object, Object>> templatesToInstall = catalogService.getTemplates(installedTemplates); int i = 0; while (initialRun && templatesToInstall.size() == 0) { log.info("Waiting for project templates to load"); if (i++ > 120) { throw new TimeoutException("Waiting for project templates"); } Thread.sleep(2000); templatesToInstall = catalogService.getTemplates(installedTemplates); } for (ProjectTemplate installed : installedTemplates) { templatesToInstall.remove(installed.getExternalId()); } for (Map.Entry<String, Map<Object, Object>> entry : templatesToInstall.entrySet()) { Map<Object, Object> toInstall = entry.getValue(); toInstall.put(PROJECT_TEMPLATE.ACCOUNT_ID, null); toInstall.put(PROJECT_TEMPLATE.IS_PUBLIC, true); toInstall.put(PROJECT_TEMPLATE.EXTERNAL_ID, entry.getKey()); log.info("Adding project template [{}]", entry.getKey()); Map<String, Object> data = objectManager.convertToPropertiesFor(ProjectTemplate.class, toInstall); resourceDao.createAndSchedule(ProjectTemplate.class, data); } initialRun = false; } @Override public String getName() { return "project.template.reload"; } }