package com.intrbiz.bergamot.ui.router.global;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import com.intrbiz.balsa.engine.route.Router;
import com.intrbiz.balsa.metadata.WithDataAdapter;
import com.intrbiz.bergamot.data.BergamotDB;
import com.intrbiz.bergamot.health.HealthTracker;
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.DeinitSite;
import com.intrbiz.bergamot.model.message.cluster.manager.request.InitSite;
import com.intrbiz.bergamot.model.message.cluster.manager.response.DeinitedSite;
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.metadata.Any;
import com.intrbiz.metadata.Before;
import com.intrbiz.metadata.CurrentPrincipal;
import com.intrbiz.metadata.IsaUUID;
import com.intrbiz.metadata.Param;
import com.intrbiz.metadata.Prefix;
import com.intrbiz.metadata.RequirePermission;
import com.intrbiz.metadata.RequireValidAccessTokenForURL;
import com.intrbiz.metadata.RequireValidPrincipal;
import com.intrbiz.metadata.Template;
import com.intrbiz.queue.RPCClient;
import com.intrbiz.queue.name.RoutingKey;
@Prefix("/global/admin")
@Template("layout/main")
@RequireValidPrincipal()
@RequirePermission("ui.admin")
public class GlobalAdminRouter extends Router<BergamotApp>
{
private static final Logger logger = Logger.getLogger(GlobalAdminRouter.class);
@Before()
@Any("**")
@WithDataAdapter(BergamotDB.class)
public void requireGlobalAdmin(BergamotDB db, @CurrentPrincipal Contact principal)
{
require(var("globalAdmin", principal.isGlobalAdmin()));
}
@Any("/")
@WithDataAdapter(BergamotDB.class)
public void index(BergamotDB db)
{
// the list of global daemons
var("daemons", HealthTracker.getInstance().getDaemons());
// list sites
List<Site> sites = var("sites", db.listSites());
// list global admins
var("globalAdmins", db.getGlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS).getParameters().keySet().stream().map((id) -> db.getContact(UUID.fromString(id))).filter((c) -> c != null).collect(Collectors.toList()));
// list all admins
List<Contact> allAdmins = new LinkedList<Contact>();
for (Site site : sites)
{
if (! site.isDisabled())
{
for (Contact contact : db.listContacts(site.getId()))
{
if (contact.hasPermission("ui.admin") && (! contact.isGlobalAdmin()))
allAdmins.add(contact);
}
}
}
var("allAdmins", allAdmins);
// render
encode("/global/admin/index");
}
@Any("/site/id/:id/disable")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void disableSite(BergamotDB db, @IsaUUID UUID id) throws Exception
{
// get the site
Site site = notNull(db.getSite(id));
logger.warn("Disabling site: " + site.getName() + " (" + site.getId() + ")");
// mark the site as disabled
site.setDisabled(true);
db.setSite(site);
// message the UI cluster to tear down the site
try (BergamotClusterManagerQueue queue = BergamotClusterManagerQueue.open())
{
try (RPCClient<ClusterManagerRequest, ClusterManagerResponse, RoutingKey> client = queue.createBergamotClusterManagerRPCClient())
{
try
{
ClusterManagerResponse response = client.publish(new DeinitSite(site.getId(), site.getName())).get(30, TimeUnit.SECONDS);
if (response instanceof DeinitedSite)
{
logger.info("Deinitialised site with UI cluster");
}
}
catch (Exception e)
{
logger.error("Failed to deinitialise site with UI cluster");
}
}
}
redirect(path("/global/admin/"));
}
@Any("/site/id/:id/enable")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void enableSite(BergamotDB db, @IsaUUID UUID id) throws Exception
{
// get the site
Site site = notNull(db.getSite(id));
logger.warn("Enabling site: " + site.getName() + " (" + site.getId() + ")");
// mark the site as enabled
site.setDisabled(false);
db.setSite(site);
// 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(site.getId(), site.getName())).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");
}
}
}
redirect(path("/global/admin/"));
}
@Any("/site/id/:id/generate-certificates")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void generateSiteCertificates(BergamotDB db, @IsaUUID UUID id) throws Exception
{
// get the site
Site site = notNull(db.getSite(id));
logger.warn("Generating certificates for site: " + site.getName() + " (" + site.getId() + ")");
// message the agent manager
try (BergamotAgentManagerQueue queue = BergamotAgentManagerQueue.open())
{
try (RPCClient<AgentManagerRequest, AgentManagerResponse, RoutingKey> client = queue.createBergamotAgentManagerRPCClient())
{
try
{
AgentManagerResponse response = client.publish(new CreateSiteCA(site.getId(), site.getName())).get(5, TimeUnit.SECONDS);
if (response instanceof CreatedSiteCA)
{
logger.info("Created Bergamot Agent site Certificate Authority");
}
}
catch (Exception e)
{
}
}
}
redirect(path("/global/admin/"));
}
@Any("/contact/id/:id/disable")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void disableContact(BergamotDB db, @IsaUUID UUID id) throws Exception
{
Contact contact = notNull(db.getContact(id));
GlobalSetting globalAdmins = db.getGlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS);
globalAdmins.setParameter(contact.getId().toString(), "false");
db.setGlobalSetting(globalAdmins);
redirect(path("/global/admin/"));
}
@Any("/contact/id/:id/enable")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void enableContact(BergamotDB db, @IsaUUID UUID id) throws Exception
{
Contact contact = notNull(db.getContact(id));
GlobalSetting globalAdmins = db.getGlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS);
globalAdmins.setParameter(contact.getId().toString(), "true");
db.setGlobalSetting(globalAdmins);
redirect(path("/global/admin/"));
}
@Any("/contact/id/:id/remove")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void removeContact(BergamotDB db, @IsaUUID UUID id) throws Exception
{
Contact contact = notNull(db.getContact(id));
GlobalSetting globalAdmins = db.getGlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS);
globalAdmins.removeParameter(contact.getId().toString());
db.setGlobalSetting(globalAdmins);
redirect(path("/global/admin/"));
}
@Any("/contact/add")
@RequireValidAccessTokenForURL(@Param("access-token"))
@WithDataAdapter(BergamotDB.class)
public void addContact(BergamotDB db, @IsaUUID @Param("id") UUID id) throws Exception
{
Contact contact = notNull(db.getContact(id));
GlobalSetting globalAdmins = db.getGlobalSetting(GlobalSetting.NAME.GLOBAL_ADMINS);
globalAdmins.setParameter(contact.getId().toString(), "true");
db.setGlobalSetting(globalAdmins);
redirect(path("/global/admin/"));
}
}