package com.intrbiz.bergamot.command.admin;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import com.intrbiz.bergamot.BergamotCLI;
import com.intrbiz.bergamot.BergamotCLICommand;
import com.intrbiz.bergamot.BergamotCLIException;
import com.intrbiz.bergamot.config.BergamotConfigReader;
import com.intrbiz.bergamot.config.UICfg;
import com.intrbiz.bergamot.config.model.BergamotCfg;
import com.intrbiz.bergamot.config.validator.ValidatedBergamotConfiguration;
import com.intrbiz.bergamot.data.BergamotDB;
import com.intrbiz.bergamot.importer.BergamotConfigImporter;
import com.intrbiz.bergamot.importer.BergamotImportReport;
import com.intrbiz.bergamot.model.Site;
import com.intrbiz.bergamot.model.message.agent.manager.AgentManagerRequest;
import com.intrbiz.bergamot.model.message.agent.manager.AgentManagerResponse;
import com.intrbiz.bergamot.model.message.agent.manager.request.CreateSiteCA;
import com.intrbiz.bergamot.model.message.agent.manager.response.CreatedSiteCA;
import com.intrbiz.bergamot.model.message.cluster.manager.ClusterManagerRequest;
import com.intrbiz.bergamot.model.message.cluster.manager.ClusterManagerResponse;
import com.intrbiz.bergamot.model.message.cluster.manager.request.InitSite;
import com.intrbiz.bergamot.model.message.cluster.manager.response.InitedSite;
import com.intrbiz.bergamot.queue.BergamotAgentManagerQueue;
import com.intrbiz.bergamot.queue.BergamotClusterManagerQueue;
import com.intrbiz.data.DataManager;
import com.intrbiz.lamplighter.data.LamplighterDB;
import com.intrbiz.queue.QueueManager;
import com.intrbiz.queue.RPCClient;
import com.intrbiz.queue.name.RoutingKey;
import com.intrbiz.queue.rabbit.RabbitPool;
import com.intrbiz.util.pool.database.DatabasePool;
public class CreateSiteCommand extends BergamotCLICommand
{
public CreateSiteCommand()
{
super();
}
@Override
public String name()
{
return "create-site";
}
@Override
public boolean admin()
{
return true;
}
@Override
public String usage()
{
return "'<site-name>' '<site-summary>' [<site-alias>, ]";
}
@Override
public String help()
{
return "Create a Bergamot site with the given <site-name> and optional <site-alias>es.\n" +
" Eg: bergamot-cli create-site 'bergamot.local' 'bergamot.mydomain.com' 'localhost'\n" +
"\n" +
"Arguments:\n" +
" <site-name> the host name of this Bergamot site, Eg: 'bergamot.local'\n" +
" <site-summary> a short description of this site, Eg: 'Local Bergamot Instance'\n" +
" <site-alias> additional host names for this Bergamot site, Eg: 'bergamot.mydomain.com'\n" +
"\n" +
"Note: this command must to be run locally on the UI node.";
}
@Override
public int execute(BergamotCLI cli, List<String> args) throws Exception
{
if (args.size() < 2) throw new BergamotCLIException("No site name or summary given");
// the site name
UUID siteId = Site.randomSiteId();
String siteName = args.remove(0);
String siteSummary = args.remove(0);
// check for site config
File siteConfigDir = new File(new File(System.getProperty("bergamot.site.config.base", "/etc/bergamot/config/")), siteName);
if (siteConfigDir.exists()) throw new BergamotCLIException("Looks like the site '" + siteName + "' already exists, or at least it's config dir does: '" + siteConfigDir.getAbsolutePath() + "'");
// check that the template config dir exists
File templateConfigDir = new File(new File(System.getProperty("bergamot.site.config.base", "/etc/bergamot/config/")), "template");
if (! (templateConfigDir.exists() && templateConfigDir.isDirectory())) throw new BergamotCLIException("The Bergamot template configuration directory: '" + templateConfigDir.getAbsolutePath() + "' could not be found, please check your Bergamot installation!");
// read the UI config and connect to the database
UICfg config = UICfg.loadConfiguration();
// setup the data manager
DataManager.getInstance().registerDefaultServer(DatabasePool.Default.with().postgresql().url(config.getDatabase().getUrl()).username(config.getDatabase().getUsername()).password(config.getDatabase().getPassword()).build());
// setup the queue manager
QueueManager.getInstance().registerDefaultBroker(new RabbitPool(config.getBroker().getUrl(), config.getBroker().getUsername(), config.getBroker().getPassword()));
// ensure the DB schema is installed
BergamotDB.install();
// now check that we can create the site and it's aliases
try (BergamotDB db = BergamotDB.connect())
{
// check the site does not already exist!
if (db.getSiteByName(siteName) != null)
{
throw new BergamotCLIException("A site with the name '" + siteName + "' already exists!");
}
// check aliases
for (String alias : args)
{
if (db.getSiteByName(alias) != null)
{
throw new BergamotCLIException("A site with the name '" + alias + "' already exists!");
}
}
}
// now setup the site config dir by copying the templates over
if (! siteConfigDir.mkdirs() ) throw new BergamotCLIException("Failed to create the site configuration directory '" + siteConfigDir.getAbsolutePath() + "', can't create the site '" + siteName + "'");
this.copySiteTemplateConfiguration(templateConfigDir, siteConfigDir, siteName);
// load the site configuration
Collection<ValidatedBergamotConfiguration> vbcfgs = new BergamotConfigReader().includeDir(siteConfigDir).build();
// assert the configuration is valid
for (ValidatedBergamotConfiguration vbcfg : vbcfgs)
{
if (! vbcfg.getReport().isValid())
{
throw new BergamotCLIException(vbcfg.getReport().toString());
}
else
{
System.out.println(vbcfg.getReport().toString());
}
}
// now create the site
try (BergamotDB db = BergamotDB.connect())
{
// create it
Site site = new Site(siteId, siteName, siteSummary);
// aliases
for (String alias : args)
{
site.getAliases().add(alias);
}
// create
db.setSite(site);
}
// setup the readings
try (LamplighterDB db = LamplighterDB.connect())
{
db.setupSiteReadings(siteId);
}
// now import the site config
for (ValidatedBergamotConfiguration vbcfg : vbcfgs)
{
BergamotImportReport report = new BergamotConfigImporter(vbcfg).resetState(true).importConfiguration();
System.out.println(report.toString());
}
// create the Site CA
try (BergamotAgentManagerQueue queue = BergamotAgentManagerQueue.open())
{
try (RPCClient<AgentManagerRequest, AgentManagerResponse, RoutingKey> client = queue.createBergamotAgentManagerRPCClient())
{
try
{
AgentManagerResponse response = client.publish(new CreateSiteCA(siteId, siteName)).get(5, TimeUnit.SECONDS);
if (response instanceof CreatedSiteCA)
{
System.out.println("Created Bergamot Agent site Certificate Authority");
}
}
catch (Exception e)
{
}
}
}
// message the UI cluster to setup the site
try (BergamotClusterManagerQueue queue = BergamotClusterManagerQueue.open())
{
try (RPCClient<ClusterManagerRequest, ClusterManagerResponse, RoutingKey> client = queue.createBergamotClusterManagerRPCClient())
{
try
{
ClusterManagerResponse response = client.publish(new InitSite(siteId, siteName)).get(5, TimeUnit.SECONDS);
if (response instanceof InitedSite)
{
System.out.println("Initialised site with UI cluster");
}
}
catch (Exception e)
{
}
}
}
// all done
System.out.println("Created the site '" + siteName + "' and imported the default configuration, have fun :)");
// all ok
return 0;
}
protected void copySiteTemplateConfiguration(File templateConfigDir, File siteConfigDir, String siteName) throws Exception
{
// copy the template dir over to the site dir
// as we copy we load each config file and alter the site name
Stack<File> workQueue = new Stack<File>();
workQueue.push(templateConfigDir);
while (! workQueue.isEmpty())
{
File work = workQueue.pop();
if (work.isDirectory())
{
for (File file : work.listFiles())
{
workQueue.push(file);
}
}
else if (work.isFile())
{
if (work.getName().endsWith(".xml"))
{
try (FileInputStream in = new FileInputStream(work))
{
BergamotCfg cfg = BergamotCfg.read(BergamotCfg.class, in);
cfg.setSite(siteName);
// output the config
String destFileRelPath = work.getAbsolutePath().substring(templateConfigDir.getAbsolutePath().length() + 1);
File destFile = new File(siteConfigDir, destFileRelPath);
destFile.getParentFile().mkdirs();
// save the config out
try (FileOutputStream out = new FileOutputStream(destFile))
{
BergamotCfg.write(BergamotCfg.class, cfg, out);
}
}
}
}
}
}
}