@Override public User load(final String username) { LOG.debug("Loading user {}", username); // special case for the locally defined user, we don't store that in MongoDB. if (configuration.getRootUsername().equals(username)) { LOG.debug("User {} is the built-in admin user", username); return new UserImpl.LocalAdminUser(configuration, roleService.getAdminRoleObjectId()); } final DBObject query = new BasicDBObject(); query.put(UserImpl.USERNAME, username); final List<DBObject> result = query(UserImpl.class, query); if (result == null || result.isEmpty()) { return null; } if (result.size() > 1) { final String msg = "There was more than one matching user for username " + username + ". This should never happen."; LOG.error(msg); throw new RuntimeException(msg); } final DBObject userObject = result.get(0); final Object userId = userObject.get("_id"); LOG.debug("Loaded user {}/{} from MongoDB", username, userId); return new UserImpl((ObjectId) userId, userObject.toMap()); }
@Inject public MongoConnection(final Configuration configuration) { this( configuration.getMongoDatabase(), configuration.getMongoHost(), configuration.getMongoPort(), configuration.getMongoReplicaSet(), configuration.isMongoUseAuth(), configuration.getMongoUser(), configuration.getMongoPassword(), configuration.getMongoMaxConnections(), configuration.getMongoThreadsAllowedToBlockMultiplier()); }
@Override protected Set<ServerStatus.Capability> capabilities() { if (configuration.isMaster()) { return EnumSet.of(ServerStatus.Capability.SERVER, ServerStatus.Capability.MASTER); } else { return EnumSet.of(ServerStatus.Capability.SERVER); } }
@Override protected boolean validateConfiguration() { if (configuration.getPasswordSecret().isEmpty()) { LOG.error( "No password secret set. Please define \"password_secret\" in your Graylog configuration."); return false; } return true; }
@Override public void setSystemPassword(String systemPassword) { // set new salt value, if we didn't have any. if (getSystemPasswordSalt().isEmpty()) { LOG.debug("Generating new salt for LDAP system password."); final SecureRandom random = new SecureRandom(); byte[] saltBytes = new byte[8]; random.nextBytes(saltBytes); setSystemPasswordSalt(Hex.encodeToString(saltBytes)); } final String encrypted = AESTools.encrypt( systemPassword, configuration.getPasswordSecret().substring(0, 16), getSystemPasswordSalt()); fields.put(SYSTEM_PASSWORD, encrypted); }
@Override public String getSystemPassword() { final Object o = fields.get(SYSTEM_PASSWORD); if (o == null) return ""; if (getSystemPasswordSalt().isEmpty()) { // this is an old version of the database that doesn't have the salt value, // simply return the password, because it's unencrypted. // The next time we will generate a salt and then re-use that value. // TODO remove this after 0.20 is out, and the RC versions are pulled. LOG.debug( "Old database version does not have salted, encrypted password. Please save the LDAP settings again."); return o.toString(); } String encryptedPw = o.toString(); return AESTools.decrypt( encryptedPw, configuration.getPasswordSecret().substring(0, 16), getSystemPasswordSalt()); }
@Override protected void startNodeRegistration(Injector injector) { // Register this node. final NodeService nodeService = injector.getInstance(NodeService.class); final ServerStatus serverStatus = injector.getInstance(ServerStatus.class); final ActivityWriter activityWriter = injector.getInstance(ActivityWriter.class); nodeService.registerServer( serverStatus.getNodeId().toString(), configuration.isMaster(), configuration.getRestTransportUri()); serverStatus.setLocalMode(isLocal()); if (configuration.isMaster() && !nodeService.isOnlyMaster(serverStatus.getNodeId())) { LOG.warn( "Detected another master in the cluster. Retrying in {} seconds to make sure it is not " + "an old stale instance.", TimeUnit.MILLISECONDS.toSeconds(configuration.getStaleMasterTimeout())); try { Thread.sleep(configuration.getStaleMasterTimeout()); } catch (InterruptedException e) { /* nope */ } if (!nodeService.isOnlyMaster(serverStatus.getNodeId())) { // All devils here. String what = "Detected other master node in the cluster! Starting as non-master! " + "This is a mis-configuration you should fix."; LOG.warn(what); activityWriter.write(new Activity(what, Server.class)); // Write a notification. final NotificationService notificationService = injector.getInstance(NotificationService.class); Notification notification = notificationService .buildNow() .addType(Notification.Type.MULTI_MASTER) .addSeverity(Notification.Severity.URGENT); notificationService.publishIfFirst(notification); configuration.setIsMaster(false); } else { LOG.warn("Stale master has gone. Starting as master."); } } }
@Override protected void shutDown() throws Exception { LOG.debug("Stopping BufferSynchronizerService"); if (cluster.isConnected() && cluster.isDeflectorHealthy()) { final ExecutorService executorService = executorService(metricRegistry); executorService.submit( new Runnable() { @Override public void run() { bufferSynchronizer.waitForEmptyBuffers( configuration.getShutdownTimeout(), TimeUnit.MILLISECONDS); } }); executorService.shutdown(); executorService.awaitTermination(configuration.getShutdownTimeout(), TimeUnit.MILLISECONDS); } else { LOG.warn( "Elasticsearch is unavailable. Not waiting to clear buffers and caches, as we have no healthy cluster."); } LOG.debug("Stopped BufferSynchronizerService"); }
@Override public void doRun() { if (!indexerSetupService.isRunning()) { LOG.error("Indexer is not running, not checking streams for alerts."); return; } LOG.debug("Running alert checks."); final List<Stream> alertedStreams = streamService.loadAllWithConfiguredAlertConditions(); LOG.debug("There are {} streams with configured alert conditions.", alertedStreams.size()); // Load all streams that have configured alert conditions. for (Stream stream : alertedStreams) { LOG.debug( "Stream [{}] has [{}] configured alert conditions.", stream, streamService.getAlertConditions(stream).size()); if (stream.isPaused()) { LOG.debug("Stream [{}] has been paused. Skipping alert check.", stream); continue; } // Check if a threshold is reached. for (AlertCondition alertCondition : streamService.getAlertConditions(stream)) { try { final AlertCondition.CheckResult result = alertService.triggered(alertCondition); if (result.isTriggered()) { // Alert is triggered! LOG.debug("Alert condition [{}] is triggered. Sending alerts.", alertCondition); // Persist alert. final Alert alert = alertService.factory(result); alertService.save(alert); final List<AlarmCallbackConfiguration> callConfigurations = alarmCallbackConfigurationService.getForStream(stream); // Checking if alarm callbacks have been defined if (callConfigurations.size() > 0) for (AlarmCallbackConfiguration configuration : callConfigurations) { AlarmCallbackHistory alarmCallbackHistory; AlarmCallback alarmCallback = null; try { alarmCallback = alarmCallbackFactory.create(configuration); alarmCallback.call(stream, result); alarmCallbackHistory = alarmCallbackHistoryService.success(configuration, alert, alertCondition); } catch (Exception e) { if (alarmCallback != null) { LOG.warn( "Alarm callback <" + alarmCallback.getName() + "> failed. Skipping.", e); } else { LOG.warn( "Alarm callback with id " + configuration.getId() + " failed. Skipping.", e); } alarmCallbackHistory = alarmCallbackHistoryService.error( configuration, alert, alertCondition, e.getMessage()); } try { alarmCallbackHistoryService.save(alarmCallbackHistory); } catch (Exception e) { LOG.warn("Unable to save history of alarm callback run: ", e); } } else { /* Using e-mail alarm callback per default if there are no alarm callbacks configured explicitly. This way we are supporting users who have upgraded from an old version where alarm callbacks were non-existent. It also helps for users who forgot to set up alarm callbacks for newly created alert conditions. */ emailAlarmCallback.call(stream, result); } } else { // Alert not triggered. LOG.debug("Alert condition [{}] is not triggered.", alertCondition); } } catch (Exception e) { LOG.error("Skipping alert check that threw an exception.", e); } } } }
@Override public int getPeriodSeconds() { return configuration.getAlertCheckInterval(); }
@Inject public NodeServiceImpl(final MongoConnection mongoConnection, final Configuration configuration) { super(mongoConnection); this.pingTimeout = TimeUnit.MILLISECONDS.toSeconds(configuration.getStaleMasterTimeout()); }