Implement spotless gradle pre-commit hook (#105)

* Add precommit hook definition to perform basic formatting using spotless on indexer plugins

* Add formatter configuration file for spotless tool

* Update command-manager's build.gradle to use the spotless tool

* Update spotless implementation on setup plugin

- Order build.gradle blocks
- Add spotless plugin to build.gradle
- Update formatting.gradle for both plugins

* Add formatter config for spotless on setup plugin

* Add license header validation on java files

- Add license-header.txt file with the expected content of the headers
- Update formatting.gradle on both plugins to validate the license header
- Rename buildSrc directory to formatter

* Update formatter settings

* Implement custom import order based on wazuh-indexer defined convention

* Apply format-related changes requested by spotless formatter

* Initialize a gradle base project to handle generic processes for the subprojects

- Move spotless-related configuration to main project directory
- Add pre-commit hook script to run spotlessCheck
- Add block on build.gradle to automatically apply pre-commit script into local .git dir
- Remove duplicated spotless-related code

* Apply spotless formatting to command-manager classes
This commit is contained in:
Kevin Ledesma 2024-10-17 09:35:44 -03:00 committed by GitHub
parent 0ecde298a1
commit c38c054d7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 953 additions and 517 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
# Ignore Idea IDE directory
.idea/

4
NOTICE.txt Normal file
View File

@ -0,0 +1,4 @@
OpenSearch (https://opensearch.org/)
Copyright OpenSearch Contributors
Wazuh (https://wazuh.com/)
Copyright Wazuh Contributors

25
build.gradle Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright OpenSearch Contributors
* 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
* compatible open source license.
*/
plugins { id "com.diffplug.spotless" version "6.25.0" }
repositories { mavenCentral() }
apply plugin: 'java'
apply from: 'gradle/formatting.gradle'
task installLocalGitHook(type: Copy){
from new File(rootProject.rootDir, 'scripts/pre-commit')
into { new File(rootProject.rootDir, '.git/hooks')}
fileMode 0775
}
// Install git pre-commit hook on the project.
build.dependsOn installLocalGitHook
// Add the spotlessCheck to gradle check
check.dependsOn spotlessCheck

View File

@ -0,0 +1,8 @@
/*
* Copyright OpenSearch Contributors
* 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
* compatible open source license.
*/

39
gradle/formatting.gradle Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright OpenSearch Contributors
* 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
* compatible open source license.
*/
allprojects {
project.apply plugin: "com.diffplug.spotless"
spotless {
java {
licenseHeaderFile("${rootProject.file("formatter/license-header.txt")}")
googleJavaFormat().aosp()
removeUnusedImports()
importOrder(
'de.thetaphi',
'com.carrotsearch',
'com.fasterxml',
'com.avast',
'com.sun',
'com.maxmind|com.github|com.networknt|groovy|nebula',
'org.antlr',
'software.amazon',
'com.azure|com.microsoft|com.ibm|com.google|joptsimple|org.apache|org.bouncycastle|org.codehaus|org.opensearch|org.objectweb|org.joda|org.hamcrest|org.openjdk|org.gradle|org.junit',
'javax',
'java',
'',
'\\#java|\\#org.opensearch|\\#org.hamcrest|\\#'
)
trimTrailingWhitespace()
endWithNewline()
// add support for spotless:off and spotless:on tags to exclude sections of code
toggleOffOn()
}
}
}

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

252
gradlew vendored Executable file
View File

@ -0,0 +1,252 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed 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
#
# https://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.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

94
gradlew.bat vendored Normal file
View File

@ -0,0 +1,94 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -1,5 +1,24 @@
import org.opensearch.gradle.test.RestIntegTestTask
buildscript {
ext {
opensearch_version = System.getProperty("opensearch.version", "2.16.0")
wazuh_version = System.getProperty("version", "5.0.0")
revision = System.getProperty("revision", "0")
}
repositories {
mavenLocal()
maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" }
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.opensearch.gradle:build-tools:${opensearch_version}"
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
@ -80,25 +99,6 @@ thirdPartyAudit.enabled = false
//Skip checking for third party licenses
dependencyLicenses.enabled = false
buildscript {
ext {
opensearch_version = System.getProperty("opensearch.version", "2.16.0")
wazuh_version = System.getProperty("version", "5.0.0")
revision = System.getProperty("revision", "0")
}
repositories {
mavenLocal()
maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" }
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.opensearch.gradle:build-tools:${opensearch_version}"
}
}
repositories {
mavenLocal()
maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" }

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,10 +8,6 @@
*/
package com.wazuh.commandmanager;
import com.wazuh.commandmanager.index.CommandIndex;
import com.wazuh.commandmanager.rest.RestPostCommandAction;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClientDemo;
import org.opensearch.client.Client;
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
import org.opensearch.cluster.node.DiscoveryNodes;
@ -38,11 +35,15 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import com.wazuh.commandmanager.index.CommandIndex;
import com.wazuh.commandmanager.rest.RestPostCommandAction;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClientDemo;
/**
* The Command Manager plugin exposes an HTTP API with a single endpoint to
* receive raw commands from the Wazuh Server. These commands are processed,
* indexed and sent back to the Server for its delivery to, in most cases, the
* Agents.
* The Command Manager plugin exposes an HTTP API with a single endpoint to receive raw commands
* from the Wazuh Server. These commands are processed, indexed and sent back to the Server for its
* delivery to, in most cases, the Agents.
*/
public class CommandManagerPlugin extends Plugin implements ActionPlugin {
public static final String COMMAND_MANAGER_BASE_URI = "/_plugins/_command_manager";
@ -64,8 +65,7 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin {
NodeEnvironment nodeEnvironment,
NamedWriteableRegistry namedWriteableRegistry,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<RepositoriesService> repositoriesServiceSupplier
) {
Supplier<RepositoriesService> repositoriesServiceSupplier) {
this.commandIndex = new CommandIndex(client, clusterService, threadPool);
// HttpRestClient stuff
@ -82,8 +82,7 @@ public class CommandManagerPlugin extends Plugin implements ActionPlugin {
IndexScopedSettings indexScopedSettings,
SettingsFilter settingsFilter,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<DiscoveryNodes> nodesInCluster
) {
Supplier<DiscoveryNodes> nodesInCluster) {
return Collections.singletonList(new RestPostCommandAction(this.commandIndex));
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,9 +8,6 @@
*/
package com.wazuh.commandmanager.index;
import com.wazuh.commandmanager.CommandManagerPlugin;
import com.wazuh.commandmanager.model.Document;
import com.wazuh.commandmanager.utils.IndexTemplateUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.action.admin.indices.template.put.PutIndexTemplateRequest;
@ -31,9 +29,11 @@ import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
/**
* Class to manage the Command Manager index and index template.
*/
import com.wazuh.commandmanager.CommandManagerPlugin;
import com.wazuh.commandmanager.model.Document;
import com.wazuh.commandmanager.utils.IndexTemplateUtils;
/** Class to manage the Command Manager index and index template. */
public class CommandIndex implements IndexingOperationListener {
private static final Logger log = LogManager.getLogger(CommandIndex.class);
@ -45,9 +45,9 @@ public class CommandIndex implements IndexingOperationListener {
/**
* Default constructor
*
* @param client OpenSearch client.
* @param client OpenSearch client.
* @param clusterService OpenSearch cluster service.
* @param threadPool An OpenSearch ThreadPool.
* @param threadPool An OpenSearch ThreadPool.
*/
public CommandIndex(Client client, ClusterService clusterService, ThreadPool threadPool) {
this.client = client;
@ -69,30 +69,31 @@ public class CommandIndex implements IndexingOperationListener {
} else {
log.info(
"Index template {} already exists. Skipping creation.",
CommandManagerPlugin.COMMAND_MANAGER_INDEX_TEMPLATE_NAME
);
CommandManagerPlugin.COMMAND_MANAGER_INDEX_TEMPLATE_NAME);
}
log.info("Indexing command with id [{}]", document.getId());
try {
IndexRequest request = new IndexRequest()
.index(CommandManagerPlugin.COMMAND_MANAGER_INDEX_NAME)
.source(document.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS))
.id(document.getId())
.create(true);
IndexRequest request =
new IndexRequest()
.index(CommandManagerPlugin.COMMAND_MANAGER_INDEX_NAME)
.source(
document.toXContent(
XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS))
.id(document.getId())
.create(true);
executor.submit(
() -> {
try (ThreadContext.StoredContext ignored = this.threadPool.getThreadContext().stashContext()) {
try (ThreadContext.StoredContext ignored =
this.threadPool.getThreadContext().stashContext()) {
RestStatus restStatus = client.index(request).actionGet().status();
future.complete(restStatus);
} catch (Exception e) {
future.completeExceptionally(e);
}
}
);
});
} catch (IOException e) {
log.error(
"Error indexing command with id [{}] due to {}", document.getId(), e);
log.error("Error indexing command with id [{}] due to {}", document.getId(), e);
}
return future;
}
@ -104,10 +105,8 @@ public class CommandIndex implements IndexingOperationListener {
* @return whether the index template exists.
*/
public boolean indexTemplateExists(String template_name) {
Map<String, IndexTemplateMetadata> templates = this.clusterService
.state()
.metadata()
.templates();
Map<String, IndexTemplateMetadata> templates =
this.clusterService.state().metadata().templates();
log.debug("Existing index templates: {} ", templates);
return templates.containsKey(template_name);
@ -124,25 +123,25 @@ public class CommandIndex implements IndexingOperationListener {
// @throws IOException
Map<String, Object> template = IndexTemplateUtils.fromFile(templateName + ".json");
PutIndexTemplateRequest putIndexTemplateRequest = new PutIndexTemplateRequest()
.mapping(IndexTemplateUtils.get(template, "mappings"))
.settings(IndexTemplateUtils.get(template, "settings"))
.name(templateName)
.patterns((List<String>) template.get("index_patterns"));
PutIndexTemplateRequest putIndexTemplateRequest =
new PutIndexTemplateRequest()
.mapping(IndexTemplateUtils.get(template, "mappings"))
.settings(IndexTemplateUtils.get(template, "settings"))
.name(templateName)
.patterns((List<String>) template.get("index_patterns"));
executor.submit(() -> {
AcknowledgedResponse acknowledgedResponse = this.client
.admin()
.indices()
.putTemplate(putIndexTemplateRequest)
.actionGet();
if (acknowledgedResponse.isAcknowledged()) {
log.info(
"Index template [{}] created successfully",
templateName
);
}
});
executor.submit(
() -> {
AcknowledgedResponse acknowledgedResponse =
this.client
.admin()
.indices()
.putTemplate(putIndexTemplateRequest)
.actionGet();
if (acknowledgedResponse.isAcknowledged()) {
log.info("Index template [{}] created successfully", templateName);
}
});
} catch (IOException e) {
log.error("Error reading index template [{}] from filesystem", templateName);

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -14,9 +15,7 @@ import org.opensearch.core.xcontent.XContentParser;
import java.io.IOException;
import java.util.List;
/**
* Command's action fields.
*/
/** Command's action fields. */
public class Action implements ToXContentObject {
public static final String ACTION = "action";
public static final String NAME = "name";
@ -29,8 +28,8 @@ public class Action implements ToXContentObject {
/**
* Default constructor.
*
* @param name action to be executed on the target,
* @param args actual command.
* @param name action to be executed on the target,
* @param args actual command.
* @param version version of the action.
*/
public Action(String name, List<String> args, String version) {
@ -84,10 +83,15 @@ public class Action implements ToXContentObject {
@Override
public String toString() {
return "Action{" +
"name='" + name + '\'' +
", args=" + args +
", version='" + version + '\'' +
'}';
return "Action{"
+ "name='"
+ name
+ '\''
+ ", args="
+ args
+ ", version='"
+ version
+ '\''
+ '}';
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -14,9 +15,7 @@ import org.opensearch.core.xcontent.XContentParser;
import java.io.IOException;
import java.util.List;
/**
* Command's agent fields.
*/
/** Command's agent fields. */
public class Agent implements ToXContentObject {
public static final String AGENT = "agent";
public static final String GROUPS = "groups";
@ -63,8 +62,6 @@ public class Agent implements ToXContentObject {
@Override
public String toString() {
return "Agent{" +
"groups=" + groups +
'}';
return "Agent{" + "groups=" + groups + '}';
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -12,11 +13,12 @@ import org.opensearch.core.xcontent.ToXContent;
import org.opensearch.core.xcontent.ToXContentObject;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.core.xcontent.XContentParser;
import reactor.util.annotation.NonNull;
import java.io.IOException;
import java.util.ArrayList;
import reactor.util.annotation.NonNull;
public class Command implements ToXContentObject {
public static final String COMMAND = "command";
public static final String ORDER_ID = "order_id";
@ -37,19 +39,18 @@ public class Command implements ToXContentObject {
/**
* Default constructor
*
* @param source origin of the request.
* @param target {@link Target}
* @param source origin of the request.
* @param target {@link Target}
* @param timeout time window in which the command has to be sent to its target.
* @param user the user that originated the request
* @param action {@link Action}
* @param user the user that originated the request
* @param action {@link Action}
*/
public Command(
@NonNull String source,
@NonNull Target target,
@NonNull Integer timeout,
@NonNull String user,
@NonNull Action action
) {
@NonNull Action action) {
this.requestId = UUIDs.base64UUID();
this.orderId = UUIDs.base64UUID();
this.source = source;
@ -65,10 +66,11 @@ public class Command implements ToXContentObject {
*
* @param parser XContentParser from the Rest Request
* @return instance of Command
* @throws IOException error parsing request content
* @throws IOException error parsing request content
* @throws IllegalArgumentException missing arguments
*/
public static Command parse(XContentParser parser) throws IOException, IllegalArgumentException {
public static Command parse(XContentParser parser)
throws IOException, IllegalArgumentException {
String source = null;
Target target = null;
Integer timeout = null;
@ -121,13 +123,7 @@ public class Command implements ToXContentObject {
if (!nullArguments.isEmpty()) {
throw new IllegalArgumentException("Missing arguments: " + nullArguments);
} else {
return new Command(
source,
target,
timeout,
user,
action
);
return new Command(source, target, timeout, user, action);
}
}
@ -148,15 +144,27 @@ public class Command implements ToXContentObject {
@Override
public String toString() {
return "Command{" +
"orderId='" + orderId + '\'' +
", requestId='" + requestId + '\'' +
", source='" + source + '\'' +
", target=" + target +
", timeout=" + timeout +
", user='" + user + '\'' +
", status=" + status +
", action=" + action +
'}';
return "Command{"
+ "orderId='"
+ orderId
+ '\''
+ ", requestId='"
+ requestId
+ '\''
+ ", source='"
+ source
+ '\''
+ ", target="
+ target
+ ", timeout="
+ timeout
+ ", user='"
+ user
+ '\''
+ ", status="
+ status
+ ", action="
+ action
+ '}';
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -15,9 +16,7 @@ import org.opensearch.core.xcontent.XContentParser;
import java.io.IOException;
import java.util.List;
/**
* Command's target fields.
*/
/** Command's target fields. */
public class Document implements ToXContentObject {
private final Agent agent;
private final Command command;
@ -74,9 +73,6 @@ public class Document implements ToXContentObject {
@Override
public String toString() {
return "Document{" +
"agent=" + agent +
", command=" + command +
'}';
return "Document{" + "agent=" + agent + ", command=" + command + '}';
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -13,9 +14,7 @@ import org.opensearch.core.xcontent.XContentParser;
import java.io.IOException;
/**
* Command's target fields.
*/
/** Command's target fields. */
public class Target implements ToXContentObject {
public static final String TARGET = "target";
public static final String TYPE = "type";
@ -27,7 +26,7 @@ public class Target implements ToXContentObject {
* Default constructor.
*
* @param type The destination type. One of [`group`, `agent`, `server`]
* @param id Unique identifier of the destination to send the command to.
* @param id Unique identifier of the destination to send the command to.
*/
public Target(String type, String id) {
this.type = type;
@ -72,9 +71,6 @@ public class Target implements ToXContentObject {
@Override
public String toString() {
return "Target{" +
"type='" + type + '\'' +
", id='" + id + '\'' +
'}';
return "Target{" + "type='" + type + '\'' + ", id='" + id + '\'' + '}';
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,12 +8,6 @@
*/
package com.wazuh.commandmanager.rest;
import com.wazuh.commandmanager.CommandManagerPlugin;
import com.wazuh.commandmanager.index.CommandIndex;
import com.wazuh.commandmanager.model.Agent;
import com.wazuh.commandmanager.model.Command;
import com.wazuh.commandmanager.model.Document;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.core5.net.URIBuilder;
import org.apache.logging.log4j.LogManager;
@ -34,17 +29,24 @@ import java.util.Collections;
import java.util.List;
import java.util.Locale;
import com.wazuh.commandmanager.CommandManagerPlugin;
import com.wazuh.commandmanager.index.CommandIndex;
import com.wazuh.commandmanager.model.Agent;
import com.wazuh.commandmanager.model.Command;
import com.wazuh.commandmanager.model.Document;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
import static org.opensearch.core.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.opensearch.rest.RestRequest.Method.POST;
/**
* Handles HTTP requests to the POST
* {@value com.wazuh.commandmanager.CommandManagerPlugin#COMMANDS_URI}
* endpoint.
* Handles HTTP requests to the POST {@value
* com.wazuh.commandmanager.CommandManagerPlugin#COMMANDS_URI} endpoint.
*/
public class RestPostCommandAction extends BaseRestHandler {
public static final String POST_COMMAND_ACTION_REQUEST_DETAILS = "post_command_action_request_details";
public static final String POST_COMMAND_ACTION_REQUEST_DETAILS =
"post_command_action_request_details";
private static final Logger log = LogManager.getLogger(RestPostCommandAction.class);
private final CommandIndex commandIndex;
@ -55,7 +57,6 @@ public class RestPostCommandAction extends BaseRestHandler {
*/
public RestPostCommandAction(CommandIndex commandIndex) {
this.commandIndex = commandIndex;
}
public String getName() {
@ -66,21 +67,12 @@ public class RestPostCommandAction extends BaseRestHandler {
public List<Route> routes() {
return Collections.singletonList(
new Route(
POST,
String.format(
Locale.ROOT,
"%s",
CommandManagerPlugin.COMMANDS_URI
)
)
);
POST, String.format(Locale.ROOT, "%s", CommandManagerPlugin.COMMANDS_URI)));
}
@Override
protected RestChannelConsumer prepareRequest(
final RestRequest request,
final NodeClient client
) throws IOException {
protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client)
throws IOException {
switch (request.method()) {
case POST:
return handlePost(request);
@ -103,27 +95,27 @@ public class RestPostCommandAction extends BaseRestHandler {
request.method().name(),
request.uri(),
request.getRequestId(),
request.header("Host")
);
request.header("Host"));
// Get request details
XContentParser parser = request.contentParser();
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
Command command = Command.parse(parser);
Document document = new Document(
new Agent(List.of("groups000")), // TODO read agent from .agents index
command
);
Document document =
new Document(
new Agent(List.of("groups000")), // TODO read agent from .agents index
command);
// Commands delivery to the Management API.
// Note: needs to be decoupled from the Rest handler (job scheduler task).
HttpRestClient httpClient = HttpRestClient.getInstance();
try {
String uri = "https://httpbin.org/post";
// String uri = "https://127.0.0.1:5000";
URI receiverURI = new URIBuilder(uri)
.build();
String payload = document.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS).toString();
// String uri = "https://127.0.0.1:5000";
URI receiverURI = new URIBuilder(uri).build();
String payload =
document.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS)
.toString();
SimpleHttpResponse response = httpClient.post(receiverURI, payload, document.getId());
log.info("Received response to POST request with code [{}]", response.getCode());
log.info("Raw response:\n{}", response.getBodyText());
@ -135,27 +127,35 @@ public class RestPostCommandAction extends BaseRestHandler {
// Send response
return channel -> {
this.commandIndex.asyncCreate(document)
.thenAccept(restStatus -> {
try (XContentBuilder builder = channel.newBuilder()) {
builder.startObject();
builder.field("_index", CommandManagerPlugin.COMMAND_MANAGER_INDEX_NAME);
builder.field("_id", document.getId());
builder.field("result", restStatus.name());
builder.endObject();
channel.sendResponse(new BytesRestResponse(restStatus, builder));
} catch (IOException e) {
log.error("Error preparing response to [{}] request with id [{}] due to {}",
request.method().name(),
request.getRequestId(),
e.getMessage()
);
}
}).exceptionally(e -> {
channel.sendResponse(new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, e.getMessage()));
return null;
});
this.commandIndex
.asyncCreate(document)
.thenAccept(
restStatus -> {
try (XContentBuilder builder = channel.newBuilder()) {
builder.startObject();
builder.field(
"_index",
CommandManagerPlugin.COMMAND_MANAGER_INDEX_NAME);
builder.field("_id", document.getId());
builder.field("result", restStatus.name());
builder.endObject();
channel.sendResponse(
new BytesRestResponse(restStatus, builder));
} catch (IOException e) {
log.error(
"Error preparing response to [{}] request with id [{}] due to {}",
request.method().name(),
request.getRequestId(),
e.getMessage());
}
})
.exceptionally(
e -> {
channel.sendResponse(
new BytesRestResponse(
RestStatus.INTERNAL_SERVER_ERROR, e.getMessage()));
return null;
});
};
}
}

View File

@ -1,43 +1,37 @@
/*
* Copyright OpenSearch Contributors
* 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
* compatible open source license.
*/
package com.wazuh.commandmanager.utils;
import org.opensearch.common.xcontent.json.JsonXContent;
import org.opensearch.core.xcontent.DeprecationHandler;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.core.xcontent.XContentParser;
import reactor.util.annotation.NonNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Util functions to parse and manage index templates files.
*/
import reactor.util.annotation.NonNull;
/** Util functions to parse and manage index templates files. */
public class IndexTemplateUtils {
/**
* Default constructor
*/
public IndexTemplateUtils() {
}
/** Default constructor */
public IndexTemplateUtils() {}
/**
* Read index template file from the resources folder and returns its JSON
* content as a map.
* Read index template file from the resources folder and returns its JSON content as a map.
*
* @param filename name of the index template to read from the resources folder
* @return the JSON index template as a map
* @throws IOException file not found or could not be read
*/
public static Map<String, Object> fromFile(@NonNull String filename) throws IOException {
InputStream is = IndexTemplateUtils.class.getClassLoader().getResourceAsStream(filename);
return IndexTemplateUtils.toMap(is);
@ -45,29 +39,29 @@ public class IndexTemplateUtils {
/**
* Convert from a JSON InputStream into a String, Object map.
* <p>
* Used to convert the JSON index templates to the required format.
* </p>
*
* <p>Used to convert the JSON index templates to the required format.
*
* @param is: the JSON formatted InputStream
* @return a map with the json string contents.
* @throws IOException thrown by {@link JsonXContent#createParser(NamedXContentRegistry, DeprecationHandler, InputStream)}
* @throws IOException thrown by {@link JsonXContent#createParser(NamedXContentRegistry,
* DeprecationHandler, InputStream)}
*/
public static Map<String, Object> toMap(InputStream is) throws IOException {
XContentParser parser = JsonXContent.jsonXContent.createParser(
NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
is);
XContentParser parser =
JsonXContent.jsonXContent.createParser(
NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
is);
parser.nextToken();
return parser.map();
}
/**
* Cast map's element to a String, Object map.
* <p>
* Used to retrieve the settings and mappings from the index templates,
* which are a JSON object themselves.
* </p>
*
* <p>Used to retrieve the settings and mappings from the index templates, which are a JSON
* object themselves.
*
* @param map the index template as a map.
* @param key the element's key to retrieve and cast.
@ -76,6 +70,4 @@ public class IndexTemplateUtils {
public static Map<String, Object> get(Map<String, Object> map, String key) {
return (Map<String, Object>) map.get(key);
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -18,18 +19,13 @@ public class HttpResponseCallback implements FutureCallback<SimpleHttpResponse>
private static final Logger log = LogManager.getLogger(HttpResponseCallback.class);
/**
* The Http get request.
*/
/** The Http get request. */
SimpleHttpRequest httpRequest;
/**
* The Error message.
*/
/** The Error message. */
String errorMessage;
public HttpResponseCallback(SimpleHttpRequest httpRequest,
String errorMessage) {
public HttpResponseCallback(SimpleHttpRequest httpRequest, String errorMessage) {
this.httpRequest = httpRequest;
this.errorMessage = errorMessage;
}
@ -43,7 +39,7 @@ public class HttpResponseCallback implements FutureCallback<SimpleHttpResponse>
@Override
public void failed(Exception ex) {
log.error("{}->{}", httpRequest, ex);
// throw new HttpException(errorMessage, ex);
// throw new HttpException(errorMessage, ex);
}
@Override

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -26,10 +27,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* HTTP Rest client. Currently used to perform
* POST requests against the Wazuh Server.
*/
/** HTTP Rest client. Currently used to perform POST requests against the Wazuh Server. */
public class HttpRestClient {
public static final long TIMEOUT = 4;
@ -38,9 +36,7 @@ public class HttpRestClient {
private static HttpRestClient instance;
private CloseableHttpAsyncClient httpClient;
/**
* Private default constructor
*/
/** Private default constructor */
private HttpRestClient() {
startHttpAsyncClient();
}
@ -57,23 +53,21 @@ public class HttpRestClient {
return HttpRestClient.instance;
}
/**
* Starts http async client.
*/
/** Starts http async client. */
private void startHttpAsyncClient() {
if (this.httpClient == null) {
try {
PoolingAsyncClientConnectionManager cm =
PoolingAsyncClientConnectionManagerBuilder.create().build();
IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setSoTimeout(Timeout.ofSeconds(5))
.build();
IOReactorConfig ioReactorConfig =
IOReactorConfig.custom().setSoTimeout(Timeout.ofSeconds(5)).build();
httpClient = HttpAsyncClients.custom()
.setIOReactorConfig(ioReactorConfig)
.setConnectionManager(cm)
.build();
httpClient =
HttpAsyncClients.custom()
.setIOReactorConfig(ioReactorConfig)
.setConnectionManager(cm)
.build();
httpClient.start();
} catch (Exception e) {
@ -83,9 +77,7 @@ public class HttpRestClient {
}
}
/**
* Stop http async client.
*/
/** Stop http async client. */
public void stopHttpAsyncClient() {
if (this.httpClient != null) {
log.info("Shutting down.");
@ -98,26 +90,22 @@ public class HttpRestClient {
* Sends a POST request.
*
* @param receiverURI Well-formed URI
* @param payload data to send
* @param payloadId payload ID
* @param payload data to send
* @param payloadId payload ID
* @return SimpleHttpResponse response
*/
public SimpleHttpResponse post(URI receiverURI, String payload, String payloadId) {
try {
HttpHost httpHost = HttpHost.create(receiverURI);
log.info(
"Sending payload with id [{}] to [{}]",
payloadId,
receiverURI
);
log.info("Sending payload with id [{}] to [{}]", payloadId, receiverURI);
SimpleHttpRequest httpPostRequest = SimpleRequestBuilder
.post()
.setHttpHost(httpHost)
.setPath(receiverURI.getPath())
.setBody(payload, ContentType.APPLICATION_JSON)
.build();
SimpleHttpRequest httpPostRequest =
SimpleRequestBuilder.post()
.setHttpHost(httpHost)
.setPath(receiverURI.getPath())
.setBody(payload, ContentType.APPLICATION_JSON)
.build();
Future<SimpleHttpResponse> future =
this.httpClient.execute(
@ -125,9 +113,9 @@ public class HttpRestClient {
SimpleResponseConsumer.create(),
new HttpResponseCallback(
httpPostRequest,
"Failed to execute outgoing POST request with payload id [" + payloadId + "]"
)
);
"Failed to execute outgoing POST request with payload id ["
+ payloadId
+ "]"));
return future.get(TIMEOUT, TIME_UNIT);
} catch (InterruptedException e) {

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -17,9 +18,7 @@ import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Demo class to test the {@link HttpRestClient} class.
*/
/** Demo class to test the {@link HttpRestClient} class. */
public class HttpRestClientDemo {
private static final Logger log = LogManager.getLogger(HttpRestClientDemo.class);
@ -28,25 +27,28 @@ public class HttpRestClientDemo {
* Demo method to test the {@link HttpRestClient} class.
*
* @param endpoint POST's requests endpoint as a well-formed URI
* @param body POST's request body as a JSON string.
* @param body POST's request body as a JSON string.
*/
public static void run(String endpoint, String body) {
log.info("Executing POST request");
AccessController.doPrivileged(
(PrivilegedAction<SimpleHttpResponse>) () -> {
HttpRestClient httpClient = HttpRestClient.getInstance();
try {
URI host = new URIBuilder(endpoint).build();
SimpleHttpResponse response = httpClient.post(host, body, "randomId");
log.info("Received response to POST request with code {}", response.getCode());
log.info("Raw response:\n{}", response.getBodyText());
} catch (URISyntaxException e) {
log.error("Bad URI:{}", e.getMessage());
} catch (Exception e) {
log.error("Error reading response: {}", e.getMessage());
}
return null;
}
);
(PrivilegedAction<SimpleHttpResponse>)
() -> {
HttpRestClient httpClient = HttpRestClient.getInstance();
try {
URI host = new URIBuilder(endpoint).build();
SimpleHttpResponse response =
httpClient.post(host, body, "randomId");
log.info(
"Received response to POST request with code {}",
response.getCode());
log.info("Raw response:\n{}", response.getBodyText());
} catch (URISyntaxException e) {
log.error("Bad URI:{}", e.getMessage());
} catch (Exception e) {
log.error("Error reading response: {}", e.getMessage());
}
return null;
});
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -8,6 +9,7 @@
package com.wazuh.commandmanager;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import org.apache.http.ParseException;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,16 +8,17 @@
*/
package com.wazuh.commandmanager;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.junit.Assert;
import org.opensearch.test.OpenSearchTestCase;
import org.junit.Assert;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import com.wazuh.commandmanager.utils.httpclient.HttpRestClient;
public class CommandManagerTests extends OpenSearchTestCase {
// Add unit tests for your plugin
@ -25,26 +27,27 @@ public class CommandManagerTests extends OpenSearchTestCase {
public void testPost_success() {
try {
AccessController.doPrivileged(
(PrivilegedAction<SimpleHttpResponse>) () -> {
this.httpClient = HttpRestClient.getInstance();
URI uri;
try {
uri = new URI("https://httpbin.org/post");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
String payload = "{\"message\": \"Hello world!\"}";
SimpleHttpResponse postResponse = this.httpClient.post(uri, payload, "randomId");
(PrivilegedAction<SimpleHttpResponse>)
() -> {
this.httpClient = HttpRestClient.getInstance();
URI uri;
try {
uri = new URI("https://httpbin.org/post");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
String payload = "{\"message\": \"Hello world!\"}";
SimpleHttpResponse postResponse =
this.httpClient.post(uri, payload, "randomId");
String responseText = postResponse.getBodyText();
assertNotEquals(null, postResponse);
assertNotEquals(null, responseText);
assertEquals(200, postResponse.getCode());
assertNotEquals(0, responseText.length());
assertTrue(responseText.contains("Hello world!"));
return postResponse;
}
);
String responseText = postResponse.getBodyText();
assertNotEquals(null, postResponse);
assertNotEquals(null, responseText);
assertEquals(200, postResponse.getCode());
assertNotEquals(0, responseText.length());
assertTrue(responseText.contains("Hello world!"));
return postResponse;
});
} catch (Exception e) {
Assert.fail("Failed to execute HTTP request: " + e);
} finally {
@ -52,9 +55,7 @@ public class CommandManagerTests extends OpenSearchTestCase {
}
}
public void testPost_badUri() {
}
public void testPost_badUri() {}
public void testPost_badPayload() {
}
public void testPost_badPayload() {}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -9,13 +10,14 @@ package com.wazuh.commandmanager;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.opensearch.test.rest.yaml.ClientYamlTestCandidate;
import org.opensearch.test.rest.yaml.OpenSearchClientYamlSuiteTestCase;
public class CommandManagerClientYamlTestSuiteIT extends OpenSearchClientYamlSuiteTestCase {
public CommandManagerClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
public CommandManagerClientYamlTestSuiteIT(
@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}

View File

@ -1,5 +1,24 @@
import org.opensearch.gradle.test.RestIntegTestTask
buildscript {
ext {
opensearch_version = System.getProperty("opensearch.version", "2.16.0")
wazuh_version = System.getProperty("version", "5.0.0")
revision = System.getProperty("revision", "0")
}
repositories {
mavenLocal()
maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" }
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.opensearch.gradle:build-tools:${opensearch_version}"
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'
@ -13,7 +32,6 @@ def projectPath = 'com.wazuh'
def pathToPlugin = 'setup'
def pluginClassName = 'SetupPlugin'
publishing {
publications {
pluginZip(MavenPublication) { publication ->
@ -58,25 +76,6 @@ loggerUsageCheck.enabled = false
// No need to validate pom, as we do not upload to maven/sonatype
validateNebulaPom.enabled = false
buildscript {
ext {
opensearch_version = System.getProperty("opensearch.version", "2.16.0")
wazuh_version = System.getProperty("version", "5.0.0")
revision = System.getProperty("revision", "0")
}
repositories {
mavenLocal()
maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" }
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "org.opensearch.gradle:build-tools:${opensearch_version}"
}
}
repositories {
mavenLocal()
maven { url "https://aws.oss.sonatype.org/content/repositories/snapshots" }

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,7 +8,6 @@
*/
package com.wazuh.setup;
import com.wazuh.setup.index.WazuhIndices;
import org.opensearch.client.Client;
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
import org.opensearch.cluster.node.DiscoveryNode;
@ -27,20 +27,18 @@ import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import com.wazuh.setup.index.WazuhIndices;
/**
* Main class of the Indexer Setup plugin. This plugin is responsible for
* the creation of the index templates and indices required by Wazuh to
* work properly.
* Main class of the Indexer Setup plugin. This plugin is responsible for the creation of the index
* templates and indices required by Wazuh to work properly.
*/
public class SetupPlugin extends Plugin implements ClusterPlugin {
private WazuhIndices indices;
/**
* Default constructor
*/
public SetupPlugin() {
}
/** Default constructor */
public SetupPlugin() {}
@Override
public Collection<Object> createComponents(
@ -54,8 +52,7 @@ public class SetupPlugin extends Plugin implements ClusterPlugin {
NodeEnvironment nodeEnvironment,
NamedWriteableRegistry namedWriteableRegistry,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<RepositoriesService> repositoriesServiceSupplier
) {
Supplier<RepositoriesService> repositoriesServiceSupplier) {
this.indices = new WazuhIndices(client, clusterService);
return List.of(this.indices);
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,7 +8,6 @@
*/
package com.wazuh.setup.index;
import com.wazuh.setup.utils.IndexTemplateUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.action.admin.indices.create.CreateIndexRequest;
@ -22,25 +22,24 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.wazuh.setup.utils.IndexTemplateUtils;
/**
* This class contains the logic to create the index templates and the indices
* required by Wazuh.
* This class contains the logic to create the index templates and the indices required by Wazuh.
*/
public class WazuhIndices {
private static final Logger log = LogManager.getLogger(WazuhIndices.class);
/**
* | Key | value |
* | ------------------- | ---------- |
* | Index template name | index name |
*/
/** | Key | value | | ------------------- | ---------- | | Index template name | index name | */
public final Map<String, String> indexTemplates = new HashMap<>();
private final Client client;
private final ClusterService clusterService;
/**
* Constructor
*
* @param client Client
* @param client Client
* @param clusterService ClusterService
*/
public WazuhIndices(Client client, ClusterService clusterService) {
@ -67,23 +66,20 @@ public class WazuhIndices {
// @throws IOException
Map<String, Object> template = IndexTemplateUtils.fromFile(templateName + ".json");
PutIndexTemplateRequest putIndexTemplateRequest = new PutIndexTemplateRequest()
.mapping(IndexTemplateUtils.get(template, "mappings"))
.settings(IndexTemplateUtils.get(template, "settings"))
.name(templateName)
.patterns((List<String>) template.get("index_patterns"));
PutIndexTemplateRequest putIndexTemplateRequest =
new PutIndexTemplateRequest()
.mapping(IndexTemplateUtils.get(template, "mappings"))
.settings(IndexTemplateUtils.get(template, "settings"))
.name(templateName)
.patterns((List<String>) template.get("index_patterns"));
AcknowledgedResponse createIndexTemplateResponse = this.client
.admin()
.indices()
.putTemplate(putIndexTemplateRequest)
.actionGet();
AcknowledgedResponse createIndexTemplateResponse =
this.client.admin().indices().putTemplate(putIndexTemplateRequest).actionGet();
log.info(
"Index template created successfully: {} {}",
templateName,
createIndexTemplateResponse.isAcknowledged()
);
createIndexTemplateResponse.isAcknowledged());
} catch (IOException e) {
log.error("Error reading index template from filesystem {}", templateName);
@ -98,16 +94,12 @@ public class WazuhIndices {
public void putIndex(String indexName) {
if (!indexExists(indexName)) {
CreateIndexRequest request = new CreateIndexRequest(indexName);
CreateIndexResponse createIndexResponse = this.client
.admin()
.indices()
.create(request)
.actionGet();
CreateIndexResponse createIndexResponse =
this.client.admin().indices().create(request).actionGet();
log.info(
"Index created successfully: {} {}",
createIndexResponse.index(),
createIndexResponse.isAcknowledged()
);
createIndexResponse.isAcknowledged());
}
}
@ -121,16 +113,15 @@ public class WazuhIndices {
return this.clusterService.state().getRoutingTable().hasIndex(indexName);
}
/**
* Creates each index template and index in {@link #indexTemplates}.
*/
/** Creates each index template and index in {@link #indexTemplates}. */
public void initialize() {
// 1. Read index templates from files
// 2. Upsert index template
// 3. Create index
this.indexTemplates.forEach((k, v) -> {
this.putTemplate(k);
this.putIndex(v);
});
this.indexTemplates.forEach(
(k, v) -> {
this.putTemplate(k);
this.putIndex(v);
});
}
}

View File

@ -1,43 +1,37 @@
/*
* Copyright OpenSearch Contributors
* 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
* compatible open source license.
*/
package com.wazuh.setup.utils;
import org.opensearch.common.xcontent.json.JsonXContent;
import org.opensearch.core.xcontent.DeprecationHandler;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.core.xcontent.XContentParser;
import reactor.util.annotation.NonNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Util functions to parse and manage index templates files.
*/
import reactor.util.annotation.NonNull;
/** Util functions to parse and manage index templates files. */
public class IndexTemplateUtils {
/**
* Default constructor
*/
public IndexTemplateUtils() {
}
/** Default constructor */
public IndexTemplateUtils() {}
/**
* Read index template file from the resources folder and returns its JSON
* content as a map.
* Read index template file from the resources folder and returns its JSON content as a map.
*
* @param filename name of the index template to read from the resources folder
* @return the JSON index template as a map
* @throws IOException file not found or could not be read
*/
public static Map<String, Object> fromFile(@NonNull String filename) throws IOException {
InputStream is = IndexTemplateUtils.class.getClassLoader().getResourceAsStream(filename);
return IndexTemplateUtils.toMap(is);
@ -45,29 +39,29 @@ public class IndexTemplateUtils {
/**
* Convert from a JSON InputStream into a String, Object map.
* <p>
* Used to convert the JSON index templates to the required format.
* </p>
*
* <p>Used to convert the JSON index templates to the required format.
*
* @param is: the JSON formatted InputStream
* @return a map with the json string contents.
* @throws IOException thrown by {@link JsonXContent#createParser(NamedXContentRegistry, DeprecationHandler, InputStream)}
* @throws IOException thrown by {@link JsonXContent#createParser(NamedXContentRegistry,
* DeprecationHandler, InputStream)}
*/
public static Map<String, Object> toMap(InputStream is) throws IOException {
XContentParser parser = JsonXContent.jsonXContent.createParser(
NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
is);
XContentParser parser =
JsonXContent.jsonXContent.createParser(
NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
is);
parser.nextToken();
return parser.map();
}
/**
* Cast map's element to a String, Object map.
* <p>
* Used to retrieve the settings and mappings from the index templates,
* which are a JSON object themselves.
* </p>
*
* <p>Used to retrieve the settings and mappings from the index templates, which are a JSON
* object themselves.
*
* @param map the index template as a map.
* @param key the element's key to retrieve and cast.
@ -76,5 +70,4 @@ public class IndexTemplateUtils {
public static Map<String, Object> get(Map<String, Object> map, String key) {
return (Map<String, Object>) map.get(key);
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -8,28 +9,27 @@
package com.wazuh.setup;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import org.apache.http.ParseException;
import org.apache.http.util.EntityUtils;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.plugins.Plugin;
import org.opensearch.test.OpenSearchIntegTestCase;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
import org.opensearch.action.admin.cluster.health.ClusterHealthRequest;
import org.opensearch.action.admin.cluster.health.ClusterHealthResponse;
import org.opensearch.action.admin.cluster.node.info.NodeInfo;
import org.opensearch.action.admin.cluster.node.info.NodesInfoRequest;
import org.opensearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.opensearch.action.admin.cluster.node.info.PluginsAndModules;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.cluster.health.ClusterHealthStatus;
import org.opensearch.plugins.Plugin;
import org.opensearch.plugins.PluginInfo;
import org.opensearch.test.OpenSearchIntegTestCase;
import org.junit.Assert;
import java.util.Collections;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -54,36 +54,33 @@ public class SetupPluginIT extends OpenSearchIntegTestCase {
assertThat(body, containsString("wazuh-indexer-setup"));
}
public void testPluginsAreInstalled() {
ClusterHealthRequest request = new ClusterHealthRequest();
ClusterHealthResponse response = OpenSearchIntegTestCase
.client()
.admin().
cluster()
.health(request)
.actionGet();
ClusterHealthResponse response =
OpenSearchIntegTestCase.client().admin().cluster().health(request).actionGet();
Assert.assertEquals(ClusterHealthStatus.GREEN, response.getStatus());
NodesInfoRequest nodesInfoRequest = new NodesInfoRequest();
nodesInfoRequest.addMetric(NodesInfoRequest.Metric.PLUGINS.metricName());
NodesInfoResponse nodesInfoResponse = OpenSearchIntegTestCase
.client()
.admin()
.cluster().
nodesInfo(nodesInfoRequest)
.actionGet();
List<PluginInfo> pluginInfos = nodesInfoResponse.getNodes()
.stream()
.flatMap((Function<NodeInfo, Stream<PluginInfo>>) nodeInfo ->
nodeInfo
.getInfo(PluginsAndModules.class)
.getPluginInfos()
.stream()
)
.collect(Collectors.toList());
Assert.assertTrue(pluginInfos.stream().anyMatch(
pluginInfo -> pluginInfo.getName().equals("wazuh-indexer-setup"))
);
NodesInfoResponse nodesInfoResponse =
OpenSearchIntegTestCase.client()
.admin()
.cluster()
.nodesInfo(nodesInfoRequest)
.actionGet();
List<PluginInfo> pluginInfos =
nodesInfoResponse.getNodes().stream()
.flatMap(
(Function<NodeInfo, Stream<PluginInfo>>)
nodeInfo ->
nodeInfo
.getInfo(PluginsAndModules.class)
.getPluginInfos()
.stream())
.collect(Collectors.toList());
Assert.assertTrue(
pluginInfos.stream()
.anyMatch(
pluginInfo -> pluginInfo.getName().equals("wazuh-indexer-setup")));
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,9 +8,6 @@
*/
package com.wazuh.setup;
import com.wazuh.setup.index.WazuhIndices;
import org.junit.After;
import org.junit.Before;
import org.opensearch.action.admin.indices.create.CreateIndexRequest;
import org.opensearch.action.admin.indices.create.CreateIndexResponse;
import org.opensearch.action.admin.indices.template.put.PutIndexTemplateRequest;
@ -24,9 +22,13 @@ import org.opensearch.core.action.ActionListener;
import org.opensearch.test.OpenSearchTestCase;
import org.opensearch.threadpool.TestThreadPool;
import org.opensearch.threadpool.ThreadPool;
import org.junit.After;
import org.junit.Before;
import com.wazuh.setup.index.WazuhIndices;
import static org.mockito.Mockito.*;
import static org.opensearch.test.ClusterServiceUtils.createClusterService;
import static org.mockito.Mockito.*;
public class SetupPluginTests extends OpenSearchTestCase {
@ -36,9 +38,7 @@ public class SetupPluginTests extends OpenSearchTestCase {
private ThreadPool threadPool;
private Client mockClient;
/**
* Creates the necessary mocks and spies
*/
/** Creates the necessary mocks and spies */
@Before
public void setUp() throws Exception {
try {
@ -53,18 +53,14 @@ public class SetupPluginTests extends OpenSearchTestCase {
}
}
/**
* Shuts the test cluster down properly after tests are done
*/
/** Shuts the test cluster down properly after tests are done */
@After
public void testTearDown() {
this.threadPool.shutdownNow();
this.clusterService.close();
}
/**
* Tests the putTemplate method
*/
/** Tests the putTemplate method */
@AwaitsFix(bugUrl = "")
public void testPutTemplate() {
String mockTemplateName = "anIndexTemplateName";
@ -74,11 +70,15 @@ public class SetupPluginTests extends OpenSearchTestCase {
when(this.mockClient.admin()).thenReturn(mockAdminClient);
when(mockAdminClient.indices()).thenReturn(mockIndicesAdminClient);
doAnswer(invocation -> {
ActionListener<AcknowledgedResponse> listener = invocation.getArgument(1);
listener.onResponse(new AcknowledgedResponse(true));
return null;
}).when(mockIndicesAdminClient).putTemplate(any(PutIndexTemplateRequest.class), any(ActionListener.class));
doAnswer(
invocation -> {
ActionListener<AcknowledgedResponse> listener =
invocation.getArgument(1);
listener.onResponse(new AcknowledgedResponse(true));
return null;
})
.when(mockIndicesAdminClient)
.putTemplate(any(PutIndexTemplateRequest.class), any(ActionListener.class));
try {
this.wazuhIndices.putTemplate(mockTemplateName);
@ -86,11 +86,15 @@ public class SetupPluginTests extends OpenSearchTestCase {
fail(e.toString());
}
doAnswer(invocation -> {
ActionListener<AcknowledgedResponse> listener = invocation.getArgument(1);
listener.onFailure(new Exception("Mock exception on putTemplate"));
return null;
}).when(mockIndicesAdminClient).putTemplate(any(PutIndexTemplateRequest.class), any(ActionListener.class));
doAnswer(
invocation -> {
ActionListener<AcknowledgedResponse> listener =
invocation.getArgument(1);
listener.onFailure(new Exception("Mock exception on putTemplate"));
return null;
})
.when(mockIndicesAdminClient)
.putTemplate(any(PutIndexTemplateRequest.class), any(ActionListener.class));
try {
this.wazuhIndices.putTemplate(mockTemplateName);
@ -99,9 +103,7 @@ public class SetupPluginTests extends OpenSearchTestCase {
}
}
/**
* Tests creating an index
*/
/** Tests creating an index */
@AwaitsFix(bugUrl = "")
public void testCreate() {
AdminClient mockAdminClient = mock(AdminClient.class);
@ -109,24 +111,29 @@ public class SetupPluginTests extends OpenSearchTestCase {
when(this.mockClient.admin()).thenReturn(mockAdminClient);
when(mockAdminClient.indices()).thenReturn(mockIndicesAdminClient);
doAnswer(invocation -> {
ActionListener<CreateIndexResponse> listener = invocation.getArgument(1);
listener.onResponse(new CreateIndexResponse(true, true, INDEX_NAME));
return null;
}).when(mockIndicesAdminClient).create(any(CreateIndexRequest.class), any(ActionListener.class));
doAnswer(
invocation -> {
ActionListener<CreateIndexResponse> listener =
invocation.getArgument(1);
listener.onResponse(new CreateIndexResponse(true, true, INDEX_NAME));
return null;
})
.when(mockIndicesAdminClient)
.create(any(CreateIndexRequest.class), any(ActionListener.class));
ActionListener<CreateIndexResponse> actionListener = new ActionListener<>() {
@Override
public void onResponse(CreateIndexResponse createIndexResponse) {
logger.info("Mock successful index creation");
assertTrue(createIndexResponse.isAcknowledged());
}
ActionListener<CreateIndexResponse> actionListener =
new ActionListener<>() {
@Override
public void onResponse(CreateIndexResponse createIndexResponse) {
logger.info("Mock successful index creation");
assertTrue(createIndexResponse.isAcknowledged());
}
@Override
public void onFailure(Exception e) {
logger.error("Mock error creating index: {}", e.toString());
}
};
@Override
public void onFailure(Exception e) {
logger.error("Mock error creating index: {}", e.toString());
}
};
try {
this.wazuhIndices.putIndex(INDEX_NAME);
@ -134,11 +141,15 @@ public class SetupPluginTests extends OpenSearchTestCase {
fail(e.toString());
}
doAnswer(invocation -> {
ActionListener<CreateIndexResponse> listener = invocation.getArgument(1);
listener.onFailure(new Exception("Mock Exception"));
return null;
}).when(mockIndicesAdminClient).create(any(CreateIndexRequest.class), any(ActionListener.class));
doAnswer(
invocation -> {
ActionListener<CreateIndexResponse> listener =
invocation.getArgument(1);
listener.onFailure(new Exception("Mock Exception"));
return null;
})
.when(mockIndicesAdminClient)
.create(any(CreateIndexRequest.class), any(ActionListener.class));
try {
this.wazuhIndices.putIndex(INDEX_NAME);
@ -147,9 +158,7 @@ public class SetupPluginTests extends OpenSearchTestCase {
}
}
/**
* Tests the indexExists() method
*/
/** Tests the indexExists() method */
public void testIndexExists() {
ClusterState mockClusterState = mock(ClusterState.class);
RoutingTable mockRoutingTable = mock(RoutingTable.class);

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -7,9 +8,6 @@
*/
package com.wazuh.setup.index;
import com.wazuh.setup.utils.IndexTemplateUtils;
import org.junit.Before;
import org.mockito.*;
import org.opensearch.action.admin.indices.create.CreateIndexRequest;
import org.opensearch.action.admin.indices.create.CreateIndexResponse;
import org.opensearch.action.admin.indices.template.put.PutIndexTemplateRequest;
@ -21,43 +19,38 @@ import org.opensearch.cluster.ClusterState;
import org.opensearch.cluster.routing.RoutingTable;
import org.opensearch.cluster.service.ClusterService;
import org.opensearch.test.OpenSearchTestCase;
import org.junit.Before;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.wazuh.setup.utils.IndexTemplateUtils;
import org.mockito.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
public class WazuhIndicesTests extends OpenSearchTestCase {
@Mock
private Client client;
@Mock private Client client;
@Mock
private ClusterService clusterService;
@Mock private ClusterService clusterService;
@Mock
private AdminClient adminClient;
@Mock private AdminClient adminClient;
@Mock
private IndicesAdminClient indicesAdminClient;
@Mock private IndicesAdminClient indicesAdminClient;
@Mock
private ClusterState clusterState;
@Mock private ClusterState clusterState;
@Mock
private RoutingTable routingTable;
@Mock private RoutingTable routingTable;
@InjectMocks
private WazuhIndices wazuhIndices;
@InjectMocks private WazuhIndices wazuhIndices;
@Captor
private ArgumentCaptor<PutIndexTemplateRequest> putIndexTemplateRequestCaptor;
@Captor private ArgumentCaptor<PutIndexTemplateRequest> putIndexTemplateRequestCaptor;
@Captor
private ArgumentCaptor<CreateIndexRequest> createIndexRequestCaptor;
@Captor private ArgumentCaptor<CreateIndexRequest> createIndexRequestCaptor;
@Before
public void setup() {
@ -76,7 +69,8 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
this.wazuhIndices = new WazuhIndices(this.client, this.clusterService);
}
// FIXME The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks
// FIXME The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static
// mocks
// adding mockito-inline seems to have no effect
@AwaitsFix(bugUrl = "")
public void testPutTemplate_Successful() {
@ -88,8 +82,11 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
template.put("index_patterns", new HashMap<>());
// Mock the static method call
try (MockedStatic<IndexTemplateUtils> mockedStatic = Mockito.mockStatic(IndexTemplateUtils.class)) {
mockedStatic.when(() -> IndexTemplateUtils.fromFile(eq(templateName + ".json"))).thenReturn(template);
try (MockedStatic<IndexTemplateUtils> mockedStatic =
Mockito.mockStatic(IndexTemplateUtils.class)) {
mockedStatic
.when(() -> IndexTemplateUtils.fromFile(eq(templateName + ".json")))
.thenReturn(template);
when(indicesAdminClient.putTemplate(any(PutIndexTemplateRequest.class)).actionGet())
.thenReturn(mock(AcknowledgedResponse.class));
@ -107,7 +104,8 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
}
}
// FIXME The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks
// FIXME The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static
// mocks
// adding mockito-inline seems to have no effect
@AwaitsFix(bugUrl = "")
public void testPutTemplate_IOException() {
@ -115,8 +113,11 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
String templateName = "index-template-agent";
// Mock the static method to throw IOException
try (MockedStatic<IndexTemplateUtils> mockedStatic = Mockito.mockStatic(IndexTemplateUtils.class)) {
mockedStatic.when(() -> IndexTemplateUtils.fromFile(eq(templateName + ".json"))).thenThrow(IOException.class);
try (MockedStatic<IndexTemplateUtils> mockedStatic =
Mockito.mockStatic(IndexTemplateUtils.class)) {
mockedStatic
.when(() -> IndexTemplateUtils.fromFile(eq(templateName + ".json")))
.thenThrow(IOException.class);
// Act
wazuhIndices.putTemplate(templateName);
@ -126,16 +127,13 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
}
}
// FIXME the return value of "org.opensearch.client.IndicesAdminClient.create(org.opensearch.action.admin.indices.create.CreateIndexRequest)" is null
// FIXME the return value of
// "org.opensearch.client.IndicesAdminClient.create(org.opensearch.action.admin.indices.create.CreateIndexRequest)" is null
@AwaitsFix(bugUrl = "")
public void testPutIndex_IndexDoesNotExist() {
// Arrange
String indexName = ".agents";
CreateIndexResponse createIndexResponse = new CreateIndexResponse(
true,
true,
indexName
);
CreateIndexResponse createIndexResponse = new CreateIndexResponse(true, true, indexName);
when(routingTable.hasIndex(indexName)).thenReturn(false);
when(indicesAdminClient.create(any(CreateIndexRequest.class)).actionGet())
@ -151,7 +149,6 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
assertEquals(indexName, capturedRequest.index());
}
public void testPutIndex_IndexExists() {
// Arrange
String indexName = ".agents";
@ -164,7 +161,6 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
verify(indicesAdminClient, never()).create(any(CreateIndexRequest.class));
}
public void testIndexExists() {
// Arrange
String indexName = ".agents";
@ -177,7 +173,6 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
assertTrue(exists);
}
@AwaitsFix(bugUrl = "")
public void testInitialize() throws IOException {
// Arrange
@ -204,4 +199,3 @@ public class WazuhIndicesTests extends OpenSearchTestCase {
verify(indicesAdminClient).create(any(CreateIndexRequest.class));
}
}

View File

@ -1,4 +1,5 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
@ -9,10 +10,10 @@ package com.wazuh.setup;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.opensearch.test.rest.yaml.ClientYamlTestCandidate;
import org.opensearch.test.rest.yaml.OpenSearchClientYamlSuiteTestCase;
public class SetupPluginClientYamlTestSuiteIT extends OpenSearchClientYamlSuiteTestCase {
public SetupPluginClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {

21
scripts/pre-commit Normal file
View File

@ -0,0 +1,21 @@
#!/bin/bash
# Navigate to the root of the repository
cd "$(git rev-parse --show-toplevel)"
# Run spotlessCheck
./gradlew spotlessCheck
# Capture the exit code
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "======================================================================================"
echo "Spotless found some formatting issues. Please run ./gradlew spotlessApply to fix them."
echo "======================================================================================"
exit 1
else
echo "==================================="
echo "Spotless check passed successfully!"
echo "==================================="
fi

14
settings.gradle Normal file
View File

@ -0,0 +1,14 @@
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.10.2/userguide/multi_project_builds.html in the Gradle documentation.
*/
rootProject.name = "wazuh-indexer-plugins"
include(":setup")
project(":setup").projectDir = "plugins/setup/" as File
include(":command-manager")
project(":command-manager").projectDir = "plugins/command-manager/" as File