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

org.graylog2.periodical.VersionCheckThread Maven / Gradle / Ivy

There is a newer version: 6.0.2
Show newest version
/**
 * This file is part of Graylog.
 *
 * Graylog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Graylog 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
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Graylog.  If not, see .
 */
package org.graylog2.periodical;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.net.HttpHeaders;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.graylog2.configuration.VersionCheckConfiguration;
import org.graylog2.notifications.Notification;
import org.graylog2.notifications.NotificationService;
import org.graylog2.plugin.ServerStatus;
import org.graylog2.plugin.Version;
import org.graylog2.plugin.periodical.Periodical;
import org.graylog2.plugin.system.NodeId;
import org.graylog2.shared.ServerVersion;
import org.graylog2.versioncheck.VersionCheckResponse;
import org.graylog2.versioncheck.VersionResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.concurrent.TimeUnit.MINUTES;

public class VersionCheckThread extends Periodical {
    private static final Logger LOG = LoggerFactory.getLogger(VersionCheckThread.class);
    private static final String USER_AGENT = String.format(Locale.ENGLISH, "graylog2-server (%s, %s, %s, %s)",
            System.getProperty("java.vendor"), System.getProperty("java.version"),
            System.getProperty("os.name"), System.getProperty("os.version"));

    private final NotificationService notificationService;
    private final ServerStatus serverStatus;
    private final VersionCheckConfiguration config;
    private final ObjectMapper objectMapper;
    private final OkHttpClient httpClient;
    private final URI versionCheckUri;

    @Inject
    public VersionCheckThread(NotificationService notificationService,
                              ServerStatus serverStatus,
                              VersionCheckConfiguration config,
                              ObjectMapper objectMapper,
                              OkHttpClient httpClient) throws URISyntaxException {
        this(
                notificationService,
                serverStatus,
                config,
                objectMapper,
                httpClient,
                buildURI(serverStatus.getNodeId(), config.getUri())
        );
    }

    private static URI buildURI(NodeId nodeId, URI baseUri) throws URISyntaxException {
        final String queryParams = "anonid=" + nodeId.anonymize() + "&version=" + ServerVersion.VERSION.toString();
        return new URI(
                baseUri.getScheme(),
                baseUri.getUserInfo(),
                baseUri.getHost(),
                baseUri.getPort(),
                baseUri.getPath(),
                isNullOrEmpty(baseUri.getQuery()) ? queryParams : baseUri.getQuery() + "&" + queryParams,
                baseUri.getFragment()
        );
    }

    @VisibleForTesting
    VersionCheckThread(NotificationService notificationService,
                       ServerStatus serverStatus,
                       VersionCheckConfiguration config,
                       ObjectMapper objectMapper,
                       OkHttpClient httpClient,
                       URI versionCheckUri) {
        this.notificationService = notificationService;
        this.serverStatus = serverStatus;
        this.config = config;
        this.objectMapper = objectMapper;
        this.httpClient = httpClient;
        this.versionCheckUri = versionCheckUri;
    }

    @Override
    public void doRun() {
        final Request request = new Request.Builder()
                .addHeader(HttpHeaders.USER_AGENT, USER_AGENT)
                .get()
                .url(versionCheckUri.toString())
                .build();

        final Response response;
        try {
            response = httpClient.newCall(request).execute();
        } catch (IOException e) {
            LOG.error("Couldn't perform version check", e);
            return;
        }

        if (response.isSuccessful()) {
            final VersionCheckResponse versionCheckResponse;
            try {
                versionCheckResponse = objectMapper.readValue(response.body().byteStream(), VersionCheckResponse.class);
            } catch (IOException e) {
                LOG.error("Couldn't parse version check response", e);
                return;
            }

            final VersionResponse version = versionCheckResponse.version;
            Version reportedVersion = new Version(version.major, version.minor, version.patch);

            LOG.debug("Version check reports current version: " + versionCheckResponse);
            if (reportedVersion.greaterMinor(ServerVersion.VERSION)) {
                LOG.debug("Reported version is higher than ours ({}). Writing notification.", ServerVersion.VERSION);

                Notification notification = notificationService.buildNow()
                        .addSeverity(Notification.Severity.NORMAL)
                        .addType(Notification.Type.OUTDATED_VERSION)
                        .addDetail("current_version", versionCheckResponse.toString());
                notificationService.publishIfFirst(notification);
            } else {
                LOG.debug("Reported version is not higher than ours ({}).", ServerVersion.VERSION);
                notificationService.fixed(Notification.Type.OUTDATED_VERSION);
            }
        } else {
            LOG.error("Version check unsuccessful (response code {}).", response.code());
        }
    }

    @Override
    protected Logger getLogger() {
        return LOG;
    }

    @Override
    public boolean runsForever() {
        return false;
    }

    @Override
    public boolean stopOnGracefulShutdown() {
        return true;
    }

    @Override
    public boolean masterOnly() {
        return true;
    }

    @Override
    public boolean startOnThisNode() {
        return config.isEnabled() && !serverStatus.hasCapability(ServerStatus.Capability.LOCALMODE);
    }

    @Override
    public boolean isDaemon() {
        return true;
    }

    @Override
    public int getInitialDelaySeconds() {
        return (int) MINUTES.toSeconds(5);
    }

    @Override
    public int getPeriodSeconds() {
        return (int) MINUTES.toSeconds(30);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy