package com.intrbiz.bergamot.worker.engine.agent; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; import com.intrbiz.bergamot.agent.server.BergamotAgentServer; import com.intrbiz.bergamot.agent.server.BergamotAgentServer.RegisterAgentCallback.SendAgentRegistrationMessage; import com.intrbiz.bergamot.agent.server.config.BergamotAgentServerCfg; import com.intrbiz.bergamot.model.message.SiteMO; 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.GetServer; import com.intrbiz.bergamot.model.message.agent.manager.response.AgentManagerError; import com.intrbiz.bergamot.model.message.agent.manager.response.GotServer; import com.intrbiz.bergamot.model.message.agent.registration.AgentRegistrationComplete; import com.intrbiz.bergamot.model.message.agent.registration.AgentRegistrationFailed; import com.intrbiz.bergamot.model.message.agent.registration.AgentRegistrationFailed.ErrorCode; import com.intrbiz.bergamot.model.message.agent.registration.AgentRegistrationRequest; import com.intrbiz.bergamot.model.message.command.GeneralCommandError; import com.intrbiz.bergamot.model.message.command.RegisterBergamotAgent; import com.intrbiz.bergamot.model.message.command.RegisteredBergamotAgent; import com.intrbiz.bergamot.queue.BergamotAgentManagerQueue; import com.intrbiz.bergamot.worker.config.AgentWorkerCfg; import com.intrbiz.bergamot.worker.engine.AbstractEngine; import com.intrbiz.queue.RPCClient; import com.intrbiz.queue.name.RoutingKey; /** * Execute Bergamot Agent checks via the Bergamot Agent Server */ public class AgentEngine extends AbstractEngine { private static final Logger logger = Logger.getLogger(AgentEngine.class); public static final String NAME = "agent"; private BergamotAgentServer agentServer; public AgentEngine() { super(NAME); } @Override public boolean isAgentRouted() { return true; } @Override protected void configure() throws Exception { super.configure(); // setup executors if (this.executors.isEmpty()) { this.addExecutor(new PresenceExecutor()); this.addExecutor(new CPUExecutor()); this.addExecutor(new MemoryExecutor()); this.addExecutor(new DiskExecutor()); this.addExecutor(new DisksExecutor()); this.addExecutor(new OSExecutor()); this.addExecutor(new UptimeExecutor()); this.addExecutor(new NagiosExecutor()); this.addExecutor(new UsersExecutor()); this.addExecutor(new ProcessesExecutor()); this.addExecutor(new ProcessStatsExecutor()); this.addExecutor(new AgentExecutor()); this.addExecutor(new AgentMemoryExecutor()); this.addExecutor(new NetConExecutor()); this.addExecutor(new PortListenerExecutor()); this.addExecutor(new NetIOExecutor()); this.addExecutor(new DiskIOExecutor()); this.addExecutor(new LoadExecutor()); } } @Override public void start() throws Exception { // create our agent server this.agentServer = new BergamotAgentServer(); AgentWorkerCfg workerCfg = (AgentWorkerCfg) this.getWorker().getConfiguration(); BergamotAgentServerCfg serverCfg = workerCfg.getAgentServer(); // use a static configuration or dynamically request certificates from the agent manager if (serverCfg == null) { logger.info("Requesting agent server certificate from agent manager, for: " + workerCfg.getName()); serverCfg = requestAgentServerCertificates(workerCfg.getName(), workerCfg.getPort()); } // configure the agent server with a static configuration logger.info("Listening for Bergamot Agent connections on port: " + serverCfg.getPort()); this.agentServer.configure(serverCfg); // handle binding / unbinding agent routes when an agent connects and disconnects this.agentServer.setOnAgentRegisterHandler((handler) -> { this.bindAgent(handler.getAgentId()); }); this.agentServer.setOnAgentUnregisterHandler((handler) -> { // unbind the agent from this worker so that active checks will not be routed to us this.unbindAgent(handler.getAgentId()); }); // setup the registration callback this.agentServer.setOnRequestAgentRegistration(this::registerAgent); // setup queues etc super.start(); // start the agent server this.agentServer.start(); } protected BergamotAgentServerCfg requestAgentServerCertificates(String name, int port) throws Exception { try (BergamotAgentManagerQueue agentManager = BergamotAgentManagerQueue.open()) { try (RPCClient<AgentManagerRequest, AgentManagerResponse, RoutingKey> client = agentManager.createBergamotAgentManagerRPCClient()) { BergamotAgentServerCfg cfg = new BergamotAgentServerCfg(); cfg.setPort(port); cfg.setName(name); // get the root CA GotServer server = this.callAgentManager(client, new GetServer(name).withRoot().withKey().withGenerate(), 60); // complete the config cfg.setCaCertificate(server.getRootCertificatePEM()); cfg.setCertificate(server.getCertificatePEM()); cfg.setKey(server.getKeyPEM()); return cfg; } } catch (Exception e) { throw new RuntimeException("Failed to request agent server certificates from the agent manager", e); } } @SuppressWarnings("unchecked") protected <T extends AgentManagerResponse> T callAgentManager(RPCClient<AgentManagerRequest, AgentManagerResponse, RoutingKey> client, AgentManagerRequest request, int timeoutSeconds) throws Exception { AgentManagerResponse response = client.publish(request).get(timeoutSeconds, TimeUnit.SECONDS); if (response instanceof AgentManagerError) { AgentManagerError error = (AgentManagerError) response; throw new RuntimeException("Failed to call agent manager: " + error.getMessage()); } return (T) response; } public BergamotAgentServer getAgentServer() { return this.agentServer; } public void registerAgent(UUID templateId, final AgentRegistrationRequest request, final SendAgentRegistrationMessage callback) { // mask the agentId with the siteId from the template UUID agentId = SiteMO.setSiteId(SiteMO.getSiteId(templateId), request.getAgentId()); // build the command RegisterBergamotAgent command = new RegisterBergamotAgent(); command.setAgentId(agentId); command.setCommonName(request.getCommonName()); command.setTemplateId(templateId); command.setPublicKey(request.getPublicKey()); // log logger.info("Got request to register agent using template: " + templateId + ", agent id: " + request.getAgentId() + " common name: " + request.getCommonName()); // send the command this.getCommandRPCClient().publish(60_000L, command, (response) -> { if (response instanceof RegisteredBergamotAgent) { // all good RegisteredBergamotAgent rba = (RegisteredBergamotAgent) response; callback.send(new AgentRegistrationComplete(request, rba.getAgentId(), rba.getCommonName(), rba.getCertificate())); } else if (response instanceof GeneralCommandError) { callback.send(new AgentRegistrationFailed(request, ErrorCode.GENERAL, ((GeneralCommandError) response).getMessage())); } else { callback.send(new AgentRegistrationFailed(request, ErrorCode.GENERAL, "Unknown")); } }, (error) -> { callback.send(new AgentRegistrationFailed(request, ErrorCode.GENERAL, error.getMessage())); }); } }