/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /** * It caches cookbooks' metadata that being read from Github */ package se.kth.karamel.client.api; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import se.kth.karamel.backend.ClusterService; import se.kth.karamel.backend.dag.Dag; import se.kth.karamel.backend.dag.DagNode; import se.kth.karamel.common.clusterdef.Cookbook; import se.kth.karamel.common.clusterdef.json.JsonCluster; import se.kth.karamel.common.clusterdef.json.JsonCookbook; import se.kth.karamel.common.clusterdef.json.JsonGroup; import se.kth.karamel.common.clusterdef.yaml.YamlCluster; import se.kth.karamel.common.cookbookmeta.CookbookUrls; import se.kth.karamel.common.exception.KaramelException; import se.kth.karamel.common.cookbookmeta.KaramelizedCookbook; import se.kth.karamel.common.util.IoUtils; import se.kth.karamel.common.cookbookmeta.CookbookCache; import se.kth.karamel.common.exception.NoKaramelizedCookbookException; import se.kth.karamel.common.util.Settings; /** * * @author kamal */ public class CookbookCacheIml implements CookbookCache { private static final Logger logger = Logger.getLogger(CookbookCacheIml.class); public Map<String, KaramelizedCookbook> cookbooks = new HashMap<>(); public Set<String> problematics = new HashSet<>(); @Override public KaramelizedCookbook readNew(String cookbookUrl) throws KaramelException { if (problematics.contains(cookbookUrl)) { problematics.remove(cookbookUrl); } try { KaramelizedCookbook cookbook = new KaramelizedCookbook(cookbookUrl, false); cookbooks.put(cookbookUrl, cookbook); return cookbook; } catch (Exception e) { problematics.add(cookbookUrl); throw new NoKaramelizedCookbookException( String.format("Cookbook should problem in the metadata '%s'", cookbookUrl), e); } } @Override public KaramelizedCookbook get(String cookbookUrl) throws KaramelException { if (!problematics.contains(cookbookUrl)) { KaramelizedCookbook cb = cookbooks.get(cookbookUrl); if (cb == null) { cb = readNew(cookbookUrl); } return cb; } else { throw new NoKaramelizedCookbookException(String.format("Cookbook has problem in the metadata '%s'", cookbookUrl)); } } @Override public synchronized void prepareParallel(Set<String> urlsToPrepare) throws KaramelException { Set<String> allUrls = new HashSet<>(); for (String cookbookUrl : urlsToPrepare) { KaramelizedCookbook cb = cookbooks.get(cookbookUrl); if (cb == null) { CookbookUrls.Builder builder = new CookbookUrls.Builder(); CookbookUrls urls = builder.url(cookbookUrl).build(); allUrls.add(urls.attrFile); allUrls.add(urls.metadataFile); allUrls.add(urls.karamelFile); allUrls.add(urls.berksFile); } } Map<String, String> contents = IoUtils.readContentParallel(allUrls, ClusterService.SHARED_GLOBAL_TP); for (String cookbookUrl : urlsToPrepare) { KaramelizedCookbook cb = cookbooks.get(cookbookUrl); if (cb == null) { CookbookUrls.Builder builder = new CookbookUrls.Builder(); CookbookUrls urls = builder.url(cookbookUrl).build(); if (contents.containsKey(urls.attrFile) && contents.containsKey(urls.metadataFile) && contents.containsKey(urls.karamelFile) && contents.containsKey(urls.berksFile)) { KaramelizedCookbook kc = new KaramelizedCookbook(urls, contents.get(urls.attrFile), contents.get(urls.metadataFile), contents.get(urls.karamelFile), contents.get(urls.berksFile)); cookbooks.put(cookbookUrl, kc); } else { problematics.add(cookbookUrl); } } } } @Override public void prepareNewParallel(Set<String> cookbookUrls) throws KaramelException { Set<String> allUrls = new HashSet<>(); for (String cookbookUrl : cookbookUrls) { CookbookUrls.Builder builder = new CookbookUrls.Builder(); CookbookUrls urls = builder.url(cookbookUrl).build(); allUrls.add(urls.attrFile); allUrls.add(urls.metadataFile); allUrls.add(urls.karamelFile); allUrls.add(urls.berksFile); } Map<String, String> contents = IoUtils.readContentParallel(allUrls, ClusterService.SHARED_GLOBAL_TP); for (String cookbookUrl : cookbookUrls) { CookbookUrls.Builder builder = new CookbookUrls.Builder(); CookbookUrls urls = builder.url(cookbookUrl).build(); if (contents.containsKey(urls.attrFile) && contents.containsKey(urls.metadataFile) && contents.containsKey(urls.karamelFile) && contents.containsKey(urls.berksFile)) { KaramelizedCookbook kc = new KaramelizedCookbook(urls, contents.get(urls.attrFile), contents.get(urls.metadataFile), contents.get(urls.karamelFile), contents.get(urls.berksFile)); cookbooks.put(cookbookUrl, kc); } } } @Override public List<KaramelizedCookbook> loadRootKaramelizedCookbooks(JsonCluster jsonCluster) throws KaramelException { List<JsonGroup> jsonGroups = jsonCluster.getGroups(); Set<String> toLoad = new HashSet<>(); for (JsonGroup jsonGroup : jsonGroups) { for (JsonCookbook cb : jsonGroup.getCookbooks()) { toLoad.add(cb.getId()); } } for (JsonCookbook cb : jsonCluster.getCookbooks()) { toLoad.add(cb.getId()); } Dag dag = new Dag(); List<KaramelizedCookbook> kcbs = loadAllKaramelizedCookbooks(jsonCluster.getName(), toLoad, dag); List<KaramelizedCookbook> roots = new ArrayList<>(); for (DagNode node : dag.findRootNodes()) { String id = node.getId(); boolean found = false; for (KaramelizedCookbook kcb : kcbs) { if (kcb.getUrls().id.equals(id)) { roots.add(kcb); found = true; break; } } if (!found) { throw new NoKaramelizedCookbookException("Could not load a root cookbook, " + "make sure it is correctly karamelized " + id); } } return roots; } @Override public List<KaramelizedCookbook> loadAllKaramelizedCookbooks(JsonCluster jsonCluster) throws KaramelException { List<JsonGroup> jsonGroups = jsonCluster.getGroups(); Set<String> toLoad = new HashSet<>(); for (JsonGroup jsonGroup : jsonGroups) { for (JsonCookbook cb : jsonGroup.getCookbooks()) { toLoad.add(cb.getId()); } } for (JsonCookbook cb : jsonCluster.getCookbooks()) { toLoad.add(cb.getId()); } return loadAllKaramelizedCookbooks(jsonCluster.getName(), toLoad, new Dag()); } @Override public List<KaramelizedCookbook> loadAllKaramelizedCookbooks(YamlCluster cluster) throws KaramelException { Set<String> toLoad = new HashSet<>(); for (Cookbook cb : cluster.getCookbooks().values()) { toLoad.add(cb.getUrls().id); } return loadAllKaramelizedCookbooks(cluster.getName(), toLoad, new Dag()); } private List<KaramelizedCookbook> loadAllKaramelizedCookbooks(String clusterName, Set<String> toLoad, Dag dag) throws KaramelException { Set<String> loaded = new HashSet<>(); List<KaramelizedCookbook> all = new ArrayList<>(); int level = 0; while (!toLoad.isEmpty()) { logger.info(String.format("%d-level cookbooks for %s is %d", level++, clusterName, toLoad.size())); prepareParallel(toLoad); for (String tl : toLoad) { dag.addNode(tl); if (problematics.contains(tl)) { dag.updateLabel(tl, "NON_KARAMELIZED"); } else { dag.updateLabel(tl, "OK"); } } toLoad.removeAll(problematics); Set<String> depsToLoad = new HashSet(); for (String cbid : toLoad) { KaramelizedCookbook kc = get(cbid); all.add(kc); if (!Settings.CB_CLASSPATH_MODE) { Map<String, Cookbook> deps = kc.getBerksFile().getDeps(); for (Cookbook cb : deps.values()) { String depId = cb.getUrls().id; dag.addDependency(cbid, depId); if (!loaded.contains(depId) && !problematics.contains(depId)) { depsToLoad.add(depId); } } } } loaded.addAll(toLoad); toLoad.clear(); toLoad.addAll(depsToLoad); } logger.info(String.format("################## COOKBOOK TRANSIENT DEPENDENCIES FOR %s ############", clusterName)); logger.info(dag.print()); logger.info("############################################################################"); return all; } }