All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graylog.plugins.map.geoip.GeoIpDbFileChangeMonitorService Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/*
 * Copyright (C) 2020 Graylog, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Server Side Public License, version 1,
 * as published by MongoDB, Inc.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * Server Side Public License for more details.
 *
 * You should have received a copy of the Server Side Public License
 * along with this program. If not, see
 * .
 */
package org.graylog.plugins.map.geoip;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.AbstractIdleService;
import org.graylog.plugins.map.config.DatabaseType;
import org.graylog.plugins.map.config.DatabaseVendorType;
import org.graylog.plugins.map.config.GeoIpResolverConfig;
import org.graylog2.cluster.ClusterConfigChangedEvent;
import org.graylog2.plugin.cluster.ClusterConfigService;
import org.graylog2.plugin.utilities.FileInfo;
import org.graylog2.plugin.validate.ConfigValidationException;
import org.graylog2.rest.resources.system.GeoIpResolverConfigValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * A service to check whether the ASN and City MaxMind/IPInfo database files have changed, as well as whether the configuration has changed.
 *
 * 

* If the database files have changed, a {@link GeoIpDbFileChangedEvent} is posted, to which {@link org.graylog.plugins.map.geoip.processor.GeoIpProcessor} subscribes and reloads the {@link GeoIpResolverEngine}. *

* *

* This service also subscribes to {@link ClusterConfigChangedEvent} to update the database files to be monitored, as well as to update the scheduled task ({@link #refreshDatabases()}) which checks for file changes. *

*/ @Singleton public final class GeoIpDbFileChangeMonitorService extends AbstractIdleService { private static final Logger LOG = LoggerFactory.getLogger(GeoIpDbFileChangeMonitorService.class.getSimpleName()); private ScheduledFuture refreshTask; private final ScheduledExecutorService scheduler; private final GeoIpResolverConfigValidator geoIpResolverConfigValidator; private final ClusterConfigService clusterConfigService; private final EventBus eventBus; private Duration dbRefreshInterval = Duration.ZERO; private FileInfo cityDbFileInfo = FileInfo.empty(); private FileInfo asnDbFileInfo = FileInfo.empty(); private GeoIpResolverConfig config; @Inject public GeoIpDbFileChangeMonitorService(@Named("daemonScheduler") ScheduledExecutorService scheduler, EventBus eventBus, ClusterConfigService clusterConfigService, GeoIpVendorResolverService geoIpVendorResolverService) { this.scheduler = Objects.requireNonNull(scheduler); this.eventBus = Objects.requireNonNull(eventBus); this.clusterConfigService = Objects.requireNonNull(clusterConfigService); this.geoIpResolverConfigValidator = new GeoIpResolverConfigValidator(geoIpVendorResolverService); } @Subscribe @SuppressWarnings("unused") public void onClusterConfigChanged(ClusterConfigChangedEvent event) { if (GeoIpResolverConfig.class.getCanonicalName().equals(event.type())) { scheduler.schedule(this::updateConfiguration, 0, TimeUnit.SECONDS); } } @Override protected void startUp() throws Exception { eventBus.register(this); updateConfiguration(); } @Override protected void shutDown() throws Exception { eventBus.unregister(this); } private void refreshDatabases() { LOG.debug("Starting GeoIP database refresh"); Map changes = checkForChanges(); if (changes.isEmpty()) { LOG.debug("GeoIP Database files have not changed--will not refresh"); } else { GeoIpDbFileChangedEvent event = GeoIpDbFileChangedEvent.create(); eventBus.post(event); } } private Map checkForChanges() { FileInfo.Change cityDbChange = cityDbFileInfo.checkForChange(); FileInfo.Change asnDbChange = asnDbFileInfo.checkForChange(); if (config == null) { config = getCurrentConfig(); } DatabaseVendorType vendorType = config.databaseVendorType(); Map changes = new EnumMap<>(DatabaseType.class); if (cityDbChange.isChanged()) { changes.put(vendorType.getCityDbType(), cityDbChange); cityDbFileInfo = cityDbChange.fileInfo(); } if (asnDbChange.isChanged()) { changes.put(vendorType.getAsnDbType(), asnDbChange); asnDbFileInfo = asnDbChange.fileInfo(); } return changes; } private void updateConfiguration() { try { config = getCurrentConfig(); geoIpResolverConfigValidator.validate(config); if (config.enabled()) { reScheduleRefreshIfNeeded(); this.cityDbFileInfo = getDbFileInfo(config.cityDbPath()); this.asnDbFileInfo = getDbFileInfo(config.asnDbPath()); } else { LOG.debug("GeoIP Processor is disabled. Will not schedule GeoIP database file change monitor"); cancelScheduledRefreshTask(); // Set interval to ZERO to allow rescheduling when enabled again, even if interval is not changed. dbRefreshInterval = Duration.ZERO; } } catch (ConfigValidationException | IllegalArgumentException | IllegalStateException e) { LOG.error("Error validating GeoIP Database files. {}", e.getMessage(), e); } } private void cancelScheduledRefreshTask() { if (refreshTask != null) { boolean canceled = refreshTask.cancel(true); if (canceled) { LOG.debug("The GeoIP database file change monitor was running. It has been cancelled"); refreshTask = null; } else { LOG.warn("The GeoIP database file change monitor was running and failed to stop it"); } } } private void reScheduleRefreshIfNeeded() { if (!dbRefreshInterval.equals(config.refreshIntervalAsDuration())) { boolean reschedule = refreshTask == null || refreshTask.cancel(true); if (reschedule) { this.dbRefreshInterval = config.refreshIntervalAsDuration(); scheduleDbRefresh(); } else { LOG.warn("Failed to Cancel existing GeoIp Database Refresh Task. Will not update refresh interval."); } } } private FileInfo getDbFileInfo(String path) { try { return FileInfo.forPath(Paths.get(path)); } catch (Exception e) { return FileInfo.empty(); } } private void scheduleDbRefresh() { try { long millis = dbRefreshInterval.toMillis(); refreshTask = scheduler.scheduleAtFixedRate(this::refreshDatabases, millis, millis, TimeUnit.MILLISECONDS); LOG.debug("Scheduled GeoIP database refresh every '{}' Milliseconds", millis); } catch (Exception e) { LOG.error("Error scheduling GeoIP database refresh job. {}", e.getMessage(), e); } } private GeoIpResolverConfig getCurrentConfig() { return clusterConfigService.getOrDefault(GeoIpResolverConfig.class, GeoIpResolverConfig.defaultConfig()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy