First commit

This commit is contained in:
yo 2024-02-20 19:50:45 +01:00
commit c7af8bd960
15 changed files with 767 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.mvn
target
template
dependency-reduced-pom.xml

56
README.md Normal file
View File

@ -0,0 +1,56 @@
# GetListValueByRegex Plugin for Graylog
Provide pipeline function get_list_val_by_regex which filter a list by regex. Matching strings in list will be returned as a list.
**Required Graylog version:** 5.2.0 and later
Installation
------------
[Download the plugin](https://github.com/git.nosd.in/yo/graylog-plugin-getlistvaluebyregex.git/releases)
and place the `.jar` file in your Graylog plugin directory. The plugin directory
is the `plugins/` folder relative from your `graylog-server` directory by default
and can be configured in your `graylog.conf` file.
Restart `graylog-server` and you are done.
Development
-----------
You can improve your development experience for the web interface part of your plugin
dramatically by making use of hot reloading. To do this, do the following:
* `git clone https://github.com/Graylog2/graylog2-server.git`
* `cd graylog2-server/graylog2-web-interface`
* `ln -s $YOURPLUGIN plugin/`
* `npm install && npm start`
Usage
-----
Put in graylo gplugin directory, use it in pipeline rules.
Getting started
---------------
This project is using Maven 3 and requires Java 17 or higher.
* Clone this repository.
* Run `mvn package` to build a JAR file.
* Optional: Run `mvn jdeb:jdeb` and `mvn rpm:rpm` to create a DEB and RPM package respectively.
* Copy generated JAR file in target directory to your Graylog plugin directory.
* Restart the Graylog.
Plugin Release
--------------
We are using the maven release plugin:
```
$ mvn release:prepare
[...]
$ mvn release:perform
```

6
build.config.js Normal file
View File

@ -0,0 +1,6 @@
const path = require('path');
module.exports = {
// Make sure that this is the correct path to the web interface part of the Graylog server repository.
web_src_path: path.resolve(__dirname, '../graylog2-server', 'graylog2-web-interface'),
};

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "GetListValueByRegex",
"version": "1.0.0-SNAPSHOT",
"description": "",
"repository": {
"type": "git",
"url": "git.nosd.in/yo/graylog-plugin-getlistvaluebyregex.git"
},
"scripts": {
"build": "webpack",
"lint": "eslint src",
"lint:path": "eslint",
"test": "jest"
},
"keywords": [
"graylog"
],
"author": "johan <johan@nosd.in>",
"license": "MIT",
"eslintConfig": {
"extends": "graylog"
},
"dependencies": {
},
"devDependencies": {
"graylog-web-plugin": "file:../graylog2-server/graylog2-web-interface/packages/graylog-web-plugin"
}
}

342
pom.xml Normal file
View File

@ -0,0 +1,342 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.graylog.plugins</groupId>
<artifactId>graylog-plugin-web-parent</artifactId>
<version>5.2.0</version>
<relativePath>../graylog2-server/graylog-plugin-parent/graylog-plugin-web-parent</relativePath>
</parent>
<groupId>in.nosd.graylog</groupId>
<artifactId>graylog-plugin-getlistvaluebyregex</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>Graylog ${project.artifactId} plugin.</description>
<url>https://www.graylog.org</url>
<developers>
<developer>
<name>johan</name>
<email>johan@nosd.in</email>
</developer>
</developers>
<scm>
<connection>scm:git:git@github.com:git.nosd.in/yo/graylog-plugin-getlistvaluebyregex.git.git</connection>
<developerConnection>scm:git:git@github.com:git.nosd.in/yo/graylog-plugin-getlistvaluebyregex.git.git</developerConnection>
<url>https://github.com/git.nosd.in/yo/graylog-plugin-getlistvaluebyregex.git</url>
<tag>HEAD</tag>
</scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<!-- Plugins will not be deployed by default - set to `false` if you actually want to deploy it -->
<maven.deploy.skip>true</maven.deploy.skip>
<graylog.version>${project.parent.version}</graylog.version>
<graylog.plugin-dir>/usr/share/graylog-server/plugin</graylog.plugin-dir>
</properties>
<!-- <distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
-->
<!-- <repositories>
--><!-- to make our snapshot releases work with Travis et al -->
<!-- <repository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-nexus-releases</id>
<name>Sonatype Nexus Releases</name>
<url>https://oss.sonatype.org/content/repositories/releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
-->
<dependencies>
<dependency>
<groupId>org.graylog2</groupId>
<artifactId>graylog2-server</artifactId>
<version>${graylog.version}</version>
<scope>provided</scope>
</dependency>
<!-- Include source from test-jar to reuse test classes. -->
<dependency>
<groupId>org.graylog2</groupId>
<artifactId>graylog2-server</artifactId>
<version>${graylog.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>${auto-value.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.graylog.autovalue</groupId>
<artifactId>auto-value-javabean</artifactId>
<version>${auto-value-javabean.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
<build>
<resources>
<resource><directory>${web.build-dir}</directory></resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>de.thetaphi</groupId>
<artifactId>forbiddenapis</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<skipAssembly>true</skipAssembly>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifestEntries>
<Graylog-Plugin-Properties-Path>${project.groupId}.${project.artifactId}</Graylog-Plugin-Properties-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<minimizeJar>false</minimizeJar>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<mavenExecutorId>forked-path</mavenExecutorId>
<tagNameFormat>@{project.version}</tagNameFormat>
<preparationGoals>clean test</preparationGoals>
<goals>package</goals>
</configuration>
</plugin>
<plugin>
<artifactId>jdeb</artifactId>
<groupId>org.vafer</groupId>
<version>1.4</version>
<configuration>
<deb>${project.build.directory}/${project.artifactId}-${project.version}.deb</deb>
<dataSet>
<data>
<src>${project.build.directory}/${project.build.finalName}.jar</src>
<type>file</type>
<mapper>
<type>perm</type>
<prefix>${graylog.plugin-dir}</prefix>
<filemode>644</filemode>
<user>root</user>
<group>root</group>
</mapper>
</data>
</dataSet>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<version>2.1.4</version>
<configuration>
<group>Application/Internet</group>
<prefixes>
<prefix>/usr</prefix>
</prefixes>
<defineStatements>
<defineStatement>_unpackaged_files_terminate_build 0</defineStatement>
<defineStatement>_binaries_in_noarch_packages_terminate_build 0</defineStatement>
</defineStatements>
<defaultFilemode>644</defaultFilemode>
<defaultDirmode>755</defaultDirmode>
<defaultUsername>root</defaultUsername>
<defaultGroupname>root</defaultGroupname>
<mappings>
<mapping>
<directory>${graylog.plugin-dir}</directory>
<sources>
<source>
<location>${project.build.directory}/</location>
<includes>
<include>${project.build.finalName}.jar</include>
</includes>
</source>
</sources>
</mapping>
</mappings>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>web-interface-build</id>
<activation>
<property>
<name>!skip.web.build</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>install node and yarn</id>
<goals>
<goal>install-node-and-yarn</goal>
</goals>
<configuration>
<nodeVersion>${nodejs.version}</nodeVersion>
<yarnVersion>${yarn.version}</yarnVersion>
</configuration>
</execution>
<execution>
<id>yarn install</id>
<goals>
<goal>yarn</goal>
</goals>
<!-- Optional configuration which provides for running any npm command -->
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>yarn run build</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>run build</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

8
src/deb/control/control Normal file
View File

@ -0,0 +1,8 @@
Package: [[name]]
Version: [[version]]
Architecture: all
Maintainer: johan <johan@nosd.in>
Section: web
Priority: optional
Depends: graylog-server | graylog-radio
Description: [[description]]

View File

@ -0,0 +1,8 @@
package in.nosd.graylog;
/**
* This is the plugin. Your class should implement one of the existing plugin
* interfaces. (i.e. AlarmCallback, MessageInput, MessageOutput)
*/
public class GetListValueByRegex {
}

View File

@ -0,0 +1,127 @@
package in.nosd.graylog;
import org.graylog.plugins.pipelineprocessor.EvaluationContext;
import org.graylog.plugins.pipelineprocessor.ast.expressions.Expression;
import org.graylog.plugins.pipelineprocessor.ast.functions.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.regex.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.inject.Inject;
import com.fasterxml.jackson.databind.node.ValueNode;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;
import static org.graylog.plugins.pipelineprocessor.ast.functions.ParameterDescriptor.object;
import static org.graylog.plugins.pipelineprocessor.ast.functions.ParameterDescriptor.type;
import static org.graylog.plugins.pipelineprocessor.ast.functions.ParameterDescriptor.string;
public class GetListValueByRegexFunction extends AbstractFunction<List<String>> {
Logger LOG = LoggerFactory.getLogger(Function.class);
public static final String NAME = "get_list_val_by_regex";
private static final String LIST_ARG = "list";
private static final String PATTERN_ARG = "pattern";
@SuppressWarnings("unchecked")
private static final Class<List<String>> LIST_RETURN_TYPE = (Class<List<String>>) new TypeToken<List<String>>() {
}.getRawType();
private final ParameterDescriptor<Object, List<String>> listParam;
private final ParameterDescriptor<String, String> patternParam;
public GetListValueByRegexFunction() {
listParam = ParameterDescriptor.object(LIST_ARG, LIST_RETURN_TYPE)
.transform(this::transformToList)
.description("The list of string to search regex in.")
.build();
patternParam = ParameterDescriptor.string(PATTERN_ARG)
.description("The regex pattern to search in string list. Special characters needs to be double escaped.")
.build();
}
private List<String> transformToList(Object value) {
if (value instanceof Collection<?>) {
return ((Collection<?>) value).stream()
.map(GetListValueByRegexFunction::convertValue)
// Non-text JSON nodes will return null, and type conversions are intentionally not done,
// since only string inputs are supported.
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
if (value == null) {
LOG.debug("get_list_val_by_regex: parameter \"list\" is null");
return Collections.singletonList("");
}
return Collections.singletonList(value.toString());
}
private static String convertValue(Object o) {
if (o instanceof ValueNode node) {
return node.textValue();
}
return o.toString();
}
@Override
public Object preComputeConstantArgument(FunctionArgs functionArgs, String s, Expression expression) {
return expression.evaluateUnsafe(EvaluationContext.emptyContext());
}
@Override
public List<String> evaluate(FunctionArgs functionArgs, EvaluationContext evaluationContext) {
final List<String> list = listParam.required(functionArgs, evaluationContext);
final String regexPattern = patternParam.required(functionArgs, evaluationContext);
List<String> resultList = new ArrayList<String>();
List<String> blankList = new ArrayList<String>();
Pattern pattern;
if (!(list instanceof List)) {
LOG.error("get_list_val_by_regex: parameter \"list\" is of wrong type");
return blankList;
}
try {
pattern = Pattern.compile(regexPattern);
}
catch(PatternSyntaxException e) {
LOG.error("get_list_val_by_regex: invalid pattern {}", regexPattern);
return blankList;
}
Matcher match;
for (String s : list) {
LOG.debug("get_list_val_by_regex: in loop, processing '{}'", s);
match = pattern.matcher(s);
if (match.matches()) {
LOG.debug("get_list_val_by_regex match: {}", s);
resultList.add(s);
}
}
if (resultList.size() > 0) {
return resultList;
}
LOG.debug("get_list_val_by_regex: No results");
return blankList;
}
@Override
public FunctionDescriptor<List<String>> descriptor() {
return FunctionDescriptor.<List<String>>builder()
.name(NAME)
.description("Search values matching a regex in a string list, and return matching strings in form of a list. Match should be complete (no partial).")
.params(ImmutableList.of(listParam, patternParam))
.returnType(LIST_RETURN_TYPE)
.build();
}
}

View File

@ -0,0 +1,57 @@
package in.nosd.graylog;
import org.graylog2.plugin.PluginMetaData;
import org.graylog2.plugin.ServerStatus;
import org.graylog2.plugin.Version;
import java.net.URI;
import java.util.Collections;
import java.util.Set;
/**
* Implement the PluginMetaData interface here.
*/
public class GetListValueByRegexMetaData implements PluginMetaData {
private static final String PLUGIN_PROPERTIES = "in.nosd.graylog.graylog-plugin-getlistvaluebyregex/graylog-plugin.properties";
@Override
public String getUniqueId() {
return "in.nosd.graylog.GetListValueByRegexPlugin";
}
@Override
public String getName() {
return "GetListValueByRegex";
}
@Override
public String getAuthor() {
return "johan <johan@nosd.in>";
}
@Override
public URI getURL() {
return URI.create("https://github.com/git.nosd.in/yo/graylog-plugin-getlistvaluebyregex.git");
}
@Override
public Version getVersion() {
return Version.fromPluginProperties(getClass(), PLUGIN_PROPERTIES, "version", Version.from(0, 0, 0, "unknown"));
}
@Override
public String getDescription() {
// TODO Insert correct plugin description
return "Description of GetListValueByRegex plugin";
}
@Override
public Version getRequiredVersion() {
return Version.fromPluginProperties(getClass(), PLUGIN_PROPERTIES, "graylog.version", Version.from(0, 0, 0, "unknown"));
}
@Override
public Set<ServerStatus.Capability> getRequiredCapabilities() {
return Collections.emptySet();
}
}

View File

@ -0,0 +1,60 @@
package in.nosd.graylog;
import com.google.inject.Binder;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.MapBinder;
import org.graylog.plugins.pipelineprocessor.ast.functions.Function;
import org.graylog2.plugin.PluginConfigBean;
import org.graylog2.plugin.PluginModule;
import java.util.Collections;
import java.util.Set;
/**
* Extend the PluginModule abstract class here to add you plugin to the system.
*/
public class GetListValueByRegexModule extends PluginModule {
/**
* Returns all configuration beans required by this plugin.
*
* Implementing this method is optional. The default method returns an empty {@link Set}.
*/
@Override
public Set<? extends PluginConfigBean> getConfigBeans() {
return Collections.emptySet();
}
@Override
protected void configure() {
/*
* Register your plugin types here.
*
* Examples:
*
* addMessageInput(Class<? extends MessageInput>);
* addMessageFilter(Class<? extends MessageFilter>);
* addMessageOutput(Class<? extends MessageOutput>);
* addPeriodical(Class<? extends Periodical>);
* addAlarmCallback(Class<? extends AlarmCallback>);
* addInitializer(Class<? extends Service>);
* addRestResource(Class<? extends PluginRestResource>);
*
*
* Add all configuration beans returned by getConfigBeans():
*
* addConfigBeans();
*/
addMessageProcessorFunction(GetListValueByRegexFunction.NAME, GetListValueByRegexFunction.class);
}
private void addMessageProcessorFunction(String name, Class<? extends Function<?>> functionClass) {
addMessageProcessorFunction(binder(), name, functionClass);
}
private MapBinder<String, Function<?>> processorFunctionBinder(Binder binder) {
return MapBinder.newMapBinder(binder, TypeLiteral.get(String.class), new TypeLiteral<Function<?>>() {});
}
private void addMessageProcessorFunction(Binder binder, String name, Class<? extends Function<?>> functionClass) {
processorFunctionBinder(binder).addBinding(name).to(functionClass);
}
}

View File

@ -0,0 +1,23 @@
package in.nosd.graylog;
import org.graylog2.plugin.Plugin;
import org.graylog2.plugin.PluginMetaData;
import org.graylog2.plugin.PluginModule;
import java.util.Collection;
import java.util.Collections;
/**
* Implement the Plugin interface here.
*/
public class GetListValueByRegexPlugin implements Plugin {
@Override
public PluginMetaData metadata() {
return new GetListValueByRegexMetaData();
}
@Override
public Collection<PluginModule> modules () {
return Collections.<PluginModule>singletonList(new GetListValueByRegexModule());
}
}

View File

@ -0,0 +1 @@
in.nosd.graylog.GetListValueByRegexPlugin

View File

@ -0,0 +1,12 @@
# The plugin version
version=${project.version}
# The required Graylog server version
graylog.version=${graylog.version}
# When set to true (the default) the plugin gets a separate class loader
# when loading the plugin. When set to false, the plugin shares a class loader
# with other plugins that have isolated=false.
#
# Do not disable this unless this plugin depends on another plugin!
isolated=true

26
src/web/index.jsx Normal file
View File

@ -0,0 +1,26 @@
import 'webpack-entry';
import { PluginManifest, PluginStore } from 'graylog-web-plugin/plugin';
import packageJson from '../../package.json';
const manifest = new PluginManifest(packageJson, {
/* This is the place where you define which entities you are providing to the web interface.
Right now you can add routes and navigation elements to it.
Examples: */
// Adding a route to /sample, rendering YourReactComponent when called:
// routes: [
// { path: '/sample', component: YourReactComponent, permissions: 'inputs:create' },
// ],
// Adding an element to the top navigation pointing to /sample named "Sample":
// navigation: [
// { path: '/sample', description: 'Sample' },
// ]
});
PluginStore.register(manifest);

8
webpack.config.js Normal file
View File

@ -0,0 +1,8 @@
const path = require('path');
const { PluginWebpackConfig } = require('graylog-web-plugin');
const { loadBuildConfig } = require('graylog-web-plugin');
// Remember to use the same name here and in `getUniqueId()` in the java MetaData class
module.exports = new PluginWebpackConfig(__dirname, 'in.nosd.graylog.GetListValueByRegexPlugin', loadBuildConfig(path.resolve(__dirname, './build.config')), {
// Here goes your additional webpack configuration.
});