package com.intrbiz.bergamot.ui.router.global; import java.io.File; import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import com.intrbiz.Util; import com.intrbiz.balsa.BalsaException; import com.intrbiz.balsa.engine.route.Router; import com.intrbiz.balsa.metadata.WithDataAdapter; import com.intrbiz.bergamot.config.BergamotConfigReader; import com.intrbiz.bergamot.config.model.BergamotCfg; import com.intrbiz.bergamot.config.model.ContactCfg; import com.intrbiz.bergamot.config.model.TemplatedObjectCfg.ObjectState; 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.Contact; import com.intrbiz.bergamot.model.GlobalSetting; 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.bergamot.ui.BergamotApp; import com.intrbiz.lamplighter.data.LamplighterDB; import com.intrbiz.metadata.Any; import com.intrbiz.metadata.Before; import com.intrbiz.metadata.Get; import com.intrbiz.metadata.Post; import com.intrbiz.metadata.Prefix; import com.intrbiz.metadata.Template; import com.intrbiz.queue.RPCClient; import com.intrbiz.queue.name.RoutingKey; @Prefix("/global/install") @Template("layout/install") public class FirstInstallRouter extends Router<BergamotApp> { private static final Logger logger = Logger.getLogger(FirstInstallRouter.class); @Before() @Any("**") @WithDataAdapter(BergamotDB.class) public void firstInstallFilter(BergamotDB db) { require(db.getGlobalSetting(GlobalSetting.NAME.FIRST_INSTALL) == null); } @Any("/") @WithDataAdapter(BergamotDB.class) public void showInstallSite(BergamotDB db) throws Exception { // do we have any existing sites? List<Site> sites = db.listSites(); if (! sites.isEmpty()) { // add all admins as global admins GlobalSetting globalAdmins = new GlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS); for (Site site : sites) { for (Contact contact : db.listContacts(site.getId())) { if (contact.hasPermission("ui.admin")) globalAdmins.addParameter(contact.getId().toString(), "true"); } } db.setGlobalSetting(globalAdmins); // mark first install as complete db.setGlobalSetting(new GlobalSetting(GlobalSetting.NAME.FIRST_INSTALL, "complete")); // redirect to dashboard redirect(path("/")); } // create our installation form model InstallBean install = createSessionModel("install", InstallBean.class); install.setSiteName(balsa().request().getServerName()); install.setSiteSummary("Bergamot Monitoring"); // show the first install step encode("global/install/index"); } @Post("/user") @WithDataAdapter(BergamotDB.class) public void setInstallSite(BergamotDB db) { // decode the form decodeOnly("global/install/index"); // next step encode("global/install/user"); } @Get("/user") @WithDataAdapter(BergamotDB.class) public void showInstallUser(BergamotDB db) { // next step encode("global/install/user"); } @Post("/confirm") @WithDataAdapter(BergamotDB.class) public void setInstallUser(BergamotDB db) { decodeOnly("global/install/user"); // next step encode("global/install/confirm"); } @Post("/go") @WithDataAdapter(BergamotDB.class) public void goCreateSite(BergamotDB db) throws Exception { // create the site this.createSite(sessionModel("install")); // done! encode("global/install/complete"); } private void createSite(InstallBean install) throws Exception { // the site name UUID siteId = Site.randomSiteId(); String siteName = install.getSiteName(); String siteSummary = install.getSiteSummary(); // TODO File templateConfigDir = new File(System.getProperty("bergamot.site.config.template", "cfg/template")); // 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 BalsaException("A site with the name '" + siteName + "' already exists!"); } } // create the admin user configuration ContactCfg admin = new ContactCfg(); admin.setName(install.getUsername()); admin.setEmail(install.getUserEmail()); admin.setFirstName(install.getUserFirstName()); admin.setFamilyName(install.getUserLastName()); admin.setFullName((Util.coalesce(admin.getFirstName(), "") + " " + Util.coalesce(admin.getFamilyName())).trim()); admin.setMobile(install.getUserMobile()); admin.setPager(install.getUserMobile()); admin.setSummary(admin.getFullName()); admin.setObjectState(ObjectState.PRESENT); admin.getInheritedTemplates().add("generic_contact"); admin.getTeams().add("bergamot-admins"); // load the site configuration template and inject our admin user Collection<ValidatedBergamotConfiguration> vbcfgs = new BergamotConfigReader().overrideSiteName(siteName).includeDir(templateConfigDir).inject(new BergamotCfg(siteName, admin)).build(); // assert the configuration is valid for (ValidatedBergamotConfiguration vbcfg : vbcfgs) { if (! vbcfg.getReport().isValid()) { throw new BalsaException(vbcfg.getReport().toString()); } else { logger.info(vbcfg.getReport().toString()); } } // now create the site try (BergamotDB db = BergamotDB.connect()) { db.setSite(new Site(siteId, siteName, siteSummary)); } // 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).offline().defaultPassword(install.getPassword()).requirePasswordChange(false).resetState(true).importConfiguration(); logger.info(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) { logger.info("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(30, TimeUnit.SECONDS); if (response instanceof InitedSite) { logger.info("Initialised site with UI cluster"); } } catch (Exception e) { logger.error("Failed to initialise site with UI cluster"); } } } // all done logger.info("Created the site '" + siteName + "' and imported the default configuration, have fun :)"); // mark first install as complete try (BergamotDB db = BergamotDB.connect()) { // add our newly created admin to the global admin list Contact theAdmin = db.getContactByName(siteId, admin.getName()); GlobalSetting globalAdmins = new GlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS); globalAdmins.addParameter(theAdmin.getId().toString(), "true"); db.setGlobalSetting(globalAdmins); // mark first install as complete db.setGlobalSetting(new GlobalSetting(GlobalSetting.NAME.FIRST_INSTALL, "complete")); } } }