package com.hubspot.baragon.agent.lbs;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.hubspot.baragon.agent.BaragonAgentServiceModule;
import com.hubspot.baragon.agent.config.LoadBalancerConfiguration;
import com.hubspot.baragon.agent.models.LbConfigTemplate;
import com.hubspot.baragon.exceptions.MissingTemplateException;
import com.hubspot.baragon.models.BaragonAgentMetadata;
import com.hubspot.baragon.models.BaragonConfigFile;
import com.hubspot.baragon.models.BaragonService;
import com.hubspot.baragon.models.ServiceContext;
import com.github.jknack.handlebars.Context;
@Singleton
public class LbConfigGenerator {
private final LoadBalancerConfiguration loadBalancerConfiguration;
private final Map<String, List<LbConfigTemplate>> templates;
private final BaragonAgentMetadata agentMetadata;
@Inject
public LbConfigGenerator(LoadBalancerConfiguration loadBalancerConfiguration,
BaragonAgentMetadata agentMetadata,
@Named(BaragonAgentServiceModule.AGENT_TEMPLATES) Map<String, List<LbConfigTemplate>> templates) {
this.loadBalancerConfiguration = loadBalancerConfiguration;
this.agentMetadata = agentMetadata;
this.templates = templates;
}
public Collection<BaragonConfigFile> generateConfigsForProject(ServiceContext snapshot) throws MissingTemplateException {
final Collection<BaragonConfigFile> files = Lists.newArrayList();
String templateName = snapshot.getService().getTemplateName().or(BaragonAgentServiceModule.DEFAULT_TEMPLATE_NAME);
List<LbConfigTemplate> matchingTemplates = templates.get(templateName);
if (templates.get(templateName) != null) {
for (LbConfigTemplate template : matchingTemplates) {
final List<String> filenames = getFilenames(template, snapshot.getService());
final StringWriter sw = new StringWriter();
final Context context = Context.newBuilder(snapshot).combine("agentProperties", agentMetadata).build();
try {
template.getTemplate().apply(context, sw);
} catch (Exception e) {
throw Throwables.propagate(e);
}
for (String filename : filenames) {
files.add(new BaragonConfigFile(String.format("%s/%s", loadBalancerConfiguration.getRootPath(), filename), sw.toString()));
}
}
} else {
throw new MissingTemplateException(String.format("MissingTemplateException : Template %s could not be found", templateName));
}
return files;
}
public Set<String> getConfigPathsForProject(BaragonService service) {
final Set<String> paths = new HashSet<>();
for (Map.Entry<String,List<LbConfigTemplate>> entry : templates.entrySet()) {
for (LbConfigTemplate template : entry.getValue()) {
final List<String> filenames = getFilenames(template, service);
for (String filename : filenames) {
paths.add(String.format("%s/%s", loadBalancerConfiguration.getRootPath(), filename));
}
}
}
return paths;
}
private List<String> getFilenames(LbConfigTemplate template, BaragonService service) {
switch (template.getFormatType()) {
case NONE:
return Collections.singletonList(template.getFilename());
case SERVICE:
return Collections.singletonList(String.format(template.getFilename(), service.getServiceId()));
case DOMAIN_SERVICE:
default:
List<String> filenames = new ArrayList<>();
if (!service.getDomains().isEmpty() && (!loadBalancerConfiguration.getDomains().isEmpty() || loadBalancerConfiguration.getDefaultDomain().isPresent())) {
for (String domain : service.getDomains()) {
if (isDomainServed(domain)) {
filenames.add(String.format(template.getFilename(), domain, service.getServiceId()));
}
}
if (filenames.isEmpty()) {
if (loadBalancerConfiguration.getDefaultDomain().isPresent()) {
filenames.add(String.format(template.getFilename(), loadBalancerConfiguration.getDefaultDomain().get(), service.getServiceId()));
} else {
throw new IllegalStateException("No domain served for template file that requires domain");
}
}
} else if (loadBalancerConfiguration.getDefaultDomain().isPresent()){
filenames.add(String.format(template.getFilename(), loadBalancerConfiguration.getDefaultDomain().get(), service.getServiceId()));
} else {
throw new IllegalStateException("No domain present for template file that requires domain");
}
return filenames;
}
}
private boolean isDomainServed(String domain) {
return loadBalancerConfiguration.getDomains().contains(domain) || (loadBalancerConfiguration.getDefaultDomain().isPresent() && domain.equals(loadBalancerConfiguration.getDefaultDomain().get()));
}
}