Skip to content

Commit

Permalink
Opensearch dist dir autodetection (Graylog2#15216)
Browse files Browse the repository at this point in the history
* Opensearch dist dir autodetection

* Add arm64 as supported architecture for datanode

* Added changelog
  • Loading branch information
todvora authored Apr 14, 2023
1 parent 0ce8e0b commit c36a634
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 41 deletions.
4 changes: 4 additions & 0 deletions changelog/unreleased/pr-15216.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type = "a"
message = "Added autodetection of opensearch distribution in datanode."

pulls = ["15216"]
31 changes: 5 additions & 26 deletions data-node/src/main/java/org/graylog/datanode/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@
import java.util.List;
import java.util.Optional;

import static org.graylog2.shared.utilities.StringUtils.f;

/**
* Helper class to hold configuration of Graylog
*/
Expand All @@ -74,10 +72,7 @@ public class Configuration extends BaseConfiguration {
private boolean disableNativeSystemStatsCollector = false;

@Parameter(value = "opensearch_location")
private String opensearchLocation = "dist/opensearch-2.5.0";

@Parameter(value = "opensearch_version")
private String opensearchVersion = "2.5.0";
private String opensearchDistributionRoot = "dist";

@Parameter(value = "opensearch_data_location")
private String opensearchDataLocation = "data";
Expand Down Expand Up @@ -153,28 +148,12 @@ public boolean isLeader() {
return isLeader;
}

public String getOpensearchConfigLocation() {
return opensearchConfigLocation;
}

public String getOpensearchLocation() {
// If the configured location exists, just use it.
if (Files.exists(Path.of(opensearchLocation))) {
return opensearchLocation;
}

// Otherwise check if the architecture dependent distribution exists.
final var osArch = System.getProperty("os.arch");
return switch (osArch) {
case "amd64" -> f("%s-linux-x64", opensearchLocation);
case "aarch64" -> f("%s-linux-aarch64", opensearchLocation);
default ->
throw new UnsupportedOperationException("Unsupported OpenSearch distribution architecture: " + osArch);
};
public String getOpensearchDistributionRoot() {
return opensearchDistributionRoot;
}

public String getOpensearchVersion() {
return opensearchVersion;
public String getOpensearchConfigLocation() {
return opensearchConfigLocation;
}

public String getOpensearchDataLocation() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.datanode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public record OpensearchDistribution(Path directory, String version, @Nullable String platform,
@Nullable String architecture) {

private static final Logger LOG = LoggerFactory.getLogger(OpensearchDistribution.class);
public static final Pattern FULL_NAME_PATTERN = Pattern.compile("opensearch-(.*)-(.+)-(.+)");
public static final Pattern SHORT_NAME_PATTERN = Pattern.compile("opensearch-(.*)");

public OpensearchDistribution(Path path, String version) {
this(path, version, null, null);
}

public static OpensearchDistribution detectInDirectory(Path directory) throws IOException {
final var osArch = System.getProperty("os.arch");
return detectInDirectory(directory, osArch);
}

static OpensearchDistribution detectInDirectory(Path rootDistDirectory, String osArch) throws IOException {
Objects.requireNonNull(rootDistDirectory, "Dist directory needs to be provided");

// if the base directory points directly to one opensearch distribution, we should return it directly.
// If the format doesn't fit, we'll look for opensearch distributions in this root directory.
final Optional<OpensearchDistribution> distDirectory = parse(rootDistDirectory);
return distDirectory.orElseGet(() -> detectInSubdirectory(rootDistDirectory, osArch));

}

private static OpensearchDistribution detectInSubdirectory(Path directory, String osArch) {
final List<OpensearchDistribution> opensearchDistributions;
try (
var files = Files.list(directory);
) {
opensearchDistributions = files
.filter(Files::isDirectory)
.flatMap(f -> parse(f).stream())
.toList();
} catch (IOException e) {
throw new RuntimeException("Failed to list content of provided directory " + directory.toAbsolutePath(), e);
}

if (opensearchDistributions.isEmpty()) {
throw new IllegalArgumentException("Could not detect any opensearch distribution in " + directory.toAbsolutePath());
}

LOG.info("Found following opensearch distributions: " + opensearchDistributions.stream().map(d -> d.directory().toAbsolutePath()).toList());

final var archCode = archCode(osArch);

return findByArchitecture(opensearchDistributions, archCode)
.orElseGet(() -> findWithoutArchitecture(opensearchDistributions)
.orElseThrow(() -> new IllegalArgumentException("No Opensearch distribution found for architecture " + osArch)));
}

private static String archCode(final String osArch) {
return switch (osArch) {
case "amd64" -> "x64";
case "x86_64" -> "x64";
case "aarch64" -> "aarch64";
case "arm64" -> "aarch64";
default ->
throw new UnsupportedOperationException("Unsupported OpenSearch distribution architecture: " + osArch);
};
}

private static Optional<OpensearchDistribution> findByArchitecture(List<OpensearchDistribution> available, String archCode) {
return available.stream()
.filter(d -> archCode.equals(d.architecture()))
.findAny();
}

private static Optional<OpensearchDistribution> findWithoutArchitecture(List<OpensearchDistribution> available) {
return available.stream().filter(d -> d.architecture() == null).findFirst();
}

private static Optional<OpensearchDistribution> parse(Path path) {
final String filename = path.getFileName().toString();
final Matcher matcher = FULL_NAME_PATTERN.matcher(filename);
if (matcher.matches()) {
return Optional.of(new OpensearchDistribution(path, matcher.group(1), matcher.group(2), matcher.group(3)));
} else {
final Matcher shortMatcher = SHORT_NAME_PATTERN.matcher(filename);
if (shortMatcher.matches()) {
return Optional.of(new OpensearchDistribution(path, shortMatcher.group(1)));
} else {
return Optional.empty();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.datanode;

import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.io.IOException;
import java.nio.file.Path;

@Singleton
public class OpensearchDistributionProvider implements Provider<OpensearchDistribution> {

private final OpensearchDistribution opensearchDistribution;

@Inject
public OpensearchDistributionProvider(Configuration configuration) throws IOException {
this.opensearchDistribution = OpensearchDistribution.detectInDirectory(Path.of(configuration.getOpensearchDistributionRoot()));
}

@Override
public OpensearchDistribution get() {
return opensearchDistribution;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog.datanode.bindings;

import com.google.inject.AbstractModule;
import org.graylog.datanode.OpensearchDistribution;
import org.graylog.datanode.OpensearchDistributionProvider;

public class OpensearchDistributionBindings extends AbstractModule {
@Override
protected void configure() {
bind(OpensearchDistribution.class).toProvider(OpensearchDistributionProvider.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
package org.graylog.datanode.bootstrap;

import org.graylog.datanode.Configuration;
import org.graylog.datanode.OpensearchDistribution;
import org.graylog2.bootstrap.preflight.PreflightCheck;
import org.graylog2.bootstrap.preflight.PreflightCheckException;
import org.slf4j.Logger;
Expand All @@ -37,8 +37,8 @@ public class OpensearchBinPreflightCheck implements PreflightCheck {
private static final Logger LOG = LoggerFactory.getLogger(OpensearchBinPreflightCheck.class);

@Inject
public OpensearchBinPreflightCheck(Configuration configuration) {
this(Path.of(configuration.getOpensearchLocation()));
public OpensearchBinPreflightCheck(OpensearchDistribution opensearchDistribution) {
this(opensearchDistribution.directory());
}

protected OpensearchBinPreflightCheck(Path opensearchBaseDirectory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.graylog.datanode.bindings.ConfigurationModule;
import org.graylog.datanode.bindings.GenericBindings;
import org.graylog.datanode.bindings.GenericInitializerBindings;
import org.graylog.datanode.bindings.OpensearchDistributionBindings;
import org.graylog.datanode.bindings.PreflightChecksBindings;
import org.graylog.datanode.bindings.SchedulerBindings;
import org.graylog2.bootstrap.preflight.MongoDBPreflightCheck;
Expand Down Expand Up @@ -155,7 +156,9 @@ private Injector getMongoPreFlightInjector() {
return Guice.createInjector(
new IsDevelopmentBindings(),
new NamedConfigParametersModule(jadConfig.getConfigurationBeans()),
new ConfigurationModule(configuration)
new ConfigurationModule(configuration),
new OpensearchDistributionBindings()

);
}

Expand All @@ -165,6 +168,7 @@ private Injector getPreflightInjector(List<Module> preflightCheckModules) {
new NamedConfigParametersModule(jadConfig.getConfigurationBeans()),
new ConfigurationModule(configuration),
new PreflightChecksBindings(),
new OpensearchDistributionBindings(),
new Module() {
@Override
public void configure(Binder binder) {
Expand Down Expand Up @@ -277,6 +281,7 @@ protected List<Module> getSharedBindingsModules() {
// result.add(new SharedPeriodicalBindings());
result.add(new SchedulerBindings());
result.add(new GenericInitializerBindings());
result.add(new OpensearchDistributionBindings());
// result.add(new SystemStatsModule(configuration.isDisableNativeSystemStatsCollector()));

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.graylog.datanode.Configuration;
import org.graylog.datanode.OpensearchDistribution;
import org.graylog.datanode.process.OpensearchConfiguration;
import org.graylog2.jackson.TypeReferences;
import org.graylog2.security.hashing.BCryptPasswordAlgorithm;
Expand Down Expand Up @@ -55,10 +56,10 @@ public class ConfigurationProvider implements Provider<OpensearchConfiguration>
private final OpensearchConfiguration configuration;

@Inject
public ConfigurationProvider(Configuration localConfiguration, DataNodeConfig sharedConfiguration) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
public ConfigurationProvider(Configuration localConfiguration, DataNodeConfig sharedConfiguration, OpensearchDistribution opensearchDistribution) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
final var cfg = sharedConfiguration.test();

final Path opensearchConfigDir = Path.of(localConfiguration.getOpensearchLocation()).resolve("config");
final Path opensearchConfigDir = opensearchDistribution.directory().resolve("config");

final LinkedHashMap<String, String> config = new LinkedHashMap<>();
config.put("path.data", Path.of(localConfiguration.getOpensearchDataLocation()).resolve(localConfiguration.getDatanodeNodeName()).toAbsolutePath().toString());
Expand Down Expand Up @@ -150,9 +151,10 @@ public ConfigurationProvider(Configuration localConfiguration, DataNodeConfig sh
config.put("plugins.security.ssl.http.pemtrustedcas_filepath", "http-ca.pem");
}


configuration = new OpensearchConfiguration(
localConfiguration.getOpensearchVersion(),
Path.of(localConfiguration.getOpensearchLocation()),
opensearchDistribution.version(),
opensearchDistribution.directory(),
localConfiguration.getOpensearchHttpPort(),
localConfiguration.getOpensearchTransportPort(),
localConfiguration.getRestApiUsername(),
Expand Down
Loading

0 comments on commit c36a634

Please sign in to comment.