org.opensearch.gradle.test.NodeInfo.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of build-tools Show documentation
Show all versions of build-tools Show documentation
OpenSearch subproject :build-tools
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.opensearch.gradle.test
import com.sun.jna.Native
import com.sun.jna.WString
import org.apache.tools.ant.taskdefs.condition.Os
import org.opensearch.gradle.Version
import org.opensearch.gradle.VersionProperties
import org.gradle.api.Project
import org.opensearch.gradle.test.JNAKernel32Library
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
/**
* A container for the files and configuration associated with a single node in a test cluster.
*/
class NodeInfo {
/** Gradle project this node is part of */
Project project
/** common configuration for all nodes, including this one */
ClusterConfiguration config
/** node number within the cluster, for creating unique names and paths */
int nodeNum
/** name of the cluster this node is part of */
String clusterName
/** root directory all node files and operations happen under */
File baseDir
/** shared data directory all nodes share */
File sharedDir
/** the pid file the node will use */
File pidFile
/** a file written by opensearch containing the ports of each bound address for http */
File httpPortsFile
/** a file written by opensearch containing the ports of each bound address for transport */
File transportPortsFile
/** opensearch home dir */
File homeDir
/** config directory */
File pathConf
/** data directory (as an Object, to allow lazy evaluation) */
Object dataDir
/** THE config file */
File configFile
/** working directory for the node process */
File cwd
/** file that if it exists, indicates the node failed to start */
File failedMarker
/** stdout/stderr log of the opensearch process for this node */
File startLog
/** directory to install plugins from */
File pluginsTmpDir
/** Major version of java this node runs with, or {@code null} if using the runtime java version */
Integer javaVersion
/** environment variables to start the node with */
Map env
/** arguments to start the node with */
List args
/** Executable to run the bin/opensearch with, either cmd or sh */
String executable
/** Path to the opensearch start script */
private Object opensearchScript
/** script to run when running in the background */
private File wrapperScript
/** buffer for ant output when starting this node */
ByteArrayOutputStream buffer = new ByteArrayOutputStream()
/** the version of opensearch that this node runs */
Version nodeVersion
/** true if the node is not the current version */
boolean isBwcNode
/** Holds node configuration for part of a test cluster. */
NodeInfo(ClusterConfiguration config, int nodeNum, Project project, String prefix, String nodeVersion, File sharedDir) {
this.config = config
this.nodeNum = nodeNum
this.project = project
this.sharedDir = sharedDir
if (config.clusterName != null) {
clusterName = config.clusterName
} else {
clusterName = project.path.replace(':', '_').substring(1) + '_' + prefix
}
baseDir = new File(project.buildDir, "cluster/${prefix} node${nodeNum}")
pidFile = new File(baseDir, 'opensearch.pid')
this.nodeVersion = Version.fromString(nodeVersion)
this.isBwcNode = this.nodeVersion.before(VersionProperties.getOpenSearch())
homeDir = new File(baseDir, "opensearch-${nodeVersion}")
pathConf = new File(homeDir, 'config')
if (config.dataDir != null) {
dataDir = "${config.dataDir(nodeNum)}"
} else {
dataDir = new File(homeDir, "data")
}
configFile = new File(pathConf, 'opensearch.yml')
// even for rpm/deb, the logs are under home because we dont start with real services
File logsDir = new File(homeDir, 'logs')
httpPortsFile = new File(logsDir, 'http.ports')
transportPortsFile = new File(logsDir, 'transport.ports')
cwd = new File(baseDir, "cwd")
failedMarker = new File(cwd, 'run.failed')
startLog = new File(cwd, 'run.log')
pluginsTmpDir = new File(baseDir, "plugins tmp")
args = []
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
executable = 'cmd'
args.add('/C')
args.add('"') // quote the entire command
wrapperScript = new File(cwd, "run.bat")
/*
* We have to delay building the string as the path will not exist during configuration which will fail on Windows due to
* getting the short name requiring the path to already exist.
*/
opensearchScript = "${-> binPath().resolve('opensearch.bat').toString()}"
} else {
executable = 'bash'
wrapperScript = new File(cwd, "run")
opensearchScript = binPath().resolve('opensearch')
}
if (config.daemonize) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
/*
* We have to delay building the string as the path will not exist during configuration which will fail on Windows due to
* getting the short name requiring the path to already exist.
*/
args.add("${-> getShortPathName(wrapperScript.toString())}")
} else {
args.add("${wrapperScript}")
}
} else {
args.add("${opensearchScript}")
}
if (this.nodeVersion.before("6.2.0")) {
javaVersion = 8
} else if (this.nodeVersion.onOrAfter("6.2.0") && this.nodeVersion.before("6.3.0")) {
javaVersion = 9
} else if (this.nodeVersion.onOrAfter("6.3.0") && this.nodeVersion.before("6.5.0")) {
javaVersion = 10
}
args.addAll("-E", "node.portsfile=true")
env = [:]
env.putAll(config.environmentVariables)
for (Map.Entry property : System.properties.entrySet()) {
if (property.key.startsWith('tests.opensearch.')) {
args.add("-E")
args.add("${property.key.substring('tests.opensearch.'.size())}=${property.value}")
}
}
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
/*
* We have to delay building the string as the path will not exist during configuration which will fail on Windows due to
* getting the short name requiring the path to already exist.
*/
env.put('OPENSEARCH_PATH_CONF', "${-> getShortPathName(pathConf.toString())}")
}
else {
env.put('OPENSEARCH_PATH_CONF', pathConf)
}
if (!System.properties.containsKey("tests.opensearch.path.data")) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
/*
* We have to delay building the string as the path will not exist during configuration which will fail on Windows due to
* getting the short name requiring the path to already exist. This one is extra tricky because usually we rely on the node
* creating its data directory on startup but we simply can not do that here because getting the short path name requires
* the directory to already exist. Therefore, we create this directory immediately before getting the short name.
*/
args.addAll("-E", "path.data=${-> Files.createDirectories(Paths.get(dataDir.toString())); getShortPathName(dataDir.toString())}")
} else {
args.addAll("-E", "path.data=${-> dataDir.toString()}")
}
}
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
args.add('"') // end the entire command, quoted
}
}
Path binPath() {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
return Paths.get(getShortPathName(new File(homeDir, 'bin').toString()))
} else {
return Paths.get(new File(homeDir, 'bin').toURI())
}
}
static String getShortPathName(String path) {
assert Os.isFamily(Os.FAMILY_WINDOWS)
final WString longPath = new WString("\\\\?\\" + path)
// first we get the length of the buffer needed
final int length = JNAKernel32Library.getInstance().GetShortPathNameW(longPath, null, 0)
if (length == 0) {
throw new IllegalStateException("path [" + path + "] encountered error [" + Native.getLastError() + "]")
}
final char[] shortPath = new char[length]
// knowing the length of the buffer, now we get the short name
if (JNAKernel32Library.getInstance().GetShortPathNameW(longPath, shortPath, length) == 0) {
throw new IllegalStateException("path [" + path + "] encountered error [" + Native.getLastError() + "]")
}
// we have to strip the \\?\ away from the path for cmd.exe
return Native.toString(shortPath).substring(4)
}
/** Returns debug string for the command that started this node. */
String getCommandString() {
String esCommandString = "\nNode ${nodeNum} configuration:\n"
esCommandString += "|-----------------------------------------\n"
esCommandString += "| cwd: ${cwd}\n"
esCommandString += "| command: ${executable} ${args.join(' ')}\n"
esCommandString += '| environment:\n'
env.each { k, v -> esCommandString += "| ${k}: ${v}\n" }
if (config.daemonize) {
esCommandString += "|\n| [${wrapperScript.name}]\n"
wrapperScript.eachLine('UTF-8', { line -> esCommandString += " ${line}\n"})
}
esCommandString += '|\n| [opensearch.yml]\n'
configFile.eachLine('UTF-8', { line -> esCommandString += "| ${line}\n" })
esCommandString += "|-----------------------------------------"
return esCommandString
}
void writeWrapperScript() {
String argsPasser = '"$@"'
String exitMarker = "; if [ \$? != 0 ]; then touch run.failed; fi"
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
argsPasser = '%*'
exitMarker = "\r\n if \"%errorlevel%\" neq \"0\" ( type nul >> run.failed )"
}
wrapperScript.setText("\"${opensearchScript}\" ${argsPasser} > run.log 2>&1 ${exitMarker}", 'UTF-8')
}
/** Returns an address and port suitable for a uri to connect to this node over http */
String httpUri() {
return httpPortsFile.readLines("UTF-8").get(0)
}
/** Returns an address and port suitable for a uri to connect to this node over transport protocol */
String transportUri() {
return transportPortsFile.readLines("UTF-8").get(0)
}
/** Returns the file which contains the transport protocol ports for this node */
File getTransportPortsFile() {
return transportPortsFile
}
/** Returns the data directory for this node */
File getDataDir() {
if (!(dataDir instanceof File)) {
return new File(dataDir)
}
return dataDir
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy