mirror of
https://github.com/optim-enterprises-bv/siembol.git
synced 2025-11-01 19:07:59 +00:00
adding Config-editor core and services projects (#15)
* adding config-editor-core project * cleaning config-editor-core pom file * adding config-editor-services project * increase nortem version * making ServiceAggregatorImpl Builder public * remove redundant JsonRuleConfigInfoProvider class from centrifuge service
This commit is contained in:
committed by
GitHub Enterprise
parent
61a5c51ecb
commit
9f68bea6f5
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>alerting</artifactId>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<version>1.05-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>nikita-core</artifactId>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>alerting</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-common</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.adrianwalker</groupId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>alerting</artifactId>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<version>1.05-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>nikita-spark</artifactId>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>alerting</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nikita-core</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>alerting</artifactId>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<version>1.05-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>nikita-storm</artifactId>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>alerting</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -70,7 +70,7 @@
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nikita-core</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>nikita-core</module>
|
||||
|
||||
1
config-editor/config-editor-core/README.md
Normal file
1
config-editor/config-editor-core/README.md
Normal file
@@ -0,0 +1 @@
|
||||
"# config-editor-core"
|
||||
113
config-editor/config-editor-core/pom.xml
Normal file
113
config-editor/config-editor-core/pom.xml
Normal file
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>config-editor-core</artifactId>
|
||||
<name>config-editor-core</name>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>config-editor</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jgit</groupId>
|
||||
<artifactId>org.eclipse.jgit</artifactId>
|
||||
<version>5.2.1.201812262042-r</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.mylyn.github</groupId>
|
||||
<artifactId>org.eclipse.egit.github.core</artifactId>
|
||||
<version>2.1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-actuator</artifactId>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>2.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.7.25</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.adrianwalker</groupId>
|
||||
<artifactId>multiline-string</artifactId>
|
||||
<version>0.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>${mockito_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,7 @@
|
||||
package uk.co.gresearch.nortem.configeditor.common;
|
||||
|
||||
public class AuthorisationException extends RuntimeException {
|
||||
public AuthorisationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package uk.co.gresearch.nortem.configeditor.common;
|
||||
|
||||
public interface AuthorisationProvider {
|
||||
enum AuthorisationResult {
|
||||
UNDEFINED,
|
||||
ALLOWED,
|
||||
FORBIDDEN,
|
||||
}
|
||||
|
||||
AuthorisationResult getUserAuthorisation(String user, String serviceName);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package uk.co.gresearch.nortem.configeditor.common;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConfigEditorUtils {
|
||||
private static final String EMPTY_UI_LAYOUT = "{\"layout\": {}}";
|
||||
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final String DOT_SEPARATOR_REGEX = "\\.";
|
||||
private static final String SCHEMA_FORM_LAYOUT_KEY = "x-schema-form";
|
||||
private static final String LAYOUT_FIELD_NAME = "layout";
|
||||
private static final String INDEX_REPLACE_REGEX = "\"minItems\"\\s*:\\s*1";
|
||||
private static final String INDEX_REPLACEMENT = "\"minItems\":0";
|
||||
|
||||
public static Optional<String> readTextFromResources(String filename) {
|
||||
ClassLoader classLoader = new Object(){}.getClass().getClassLoader();
|
||||
try (InputStream in = classLoader.getResourceAsStream(filename)) {
|
||||
int ch;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while ((ch = in.read()) != -1) {
|
||||
sb.append((char) ch);
|
||||
}
|
||||
return Optional.of(sb.toString());
|
||||
} catch (Exception e) {
|
||||
LOG.error("could not get file", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<String> readUiLayoutFile(String filePath) {
|
||||
try {
|
||||
return readTextFromFile(filePath);
|
||||
} catch (FileNotFoundException ex) {
|
||||
return Optional.of(EMPTY_UI_LAYOUT);
|
||||
} catch (IOException ex) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> readTextFromFile(String filePath) throws IOException{
|
||||
try (FileInputStream fs = new FileInputStream(filePath)) {
|
||||
int ch;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while ((ch = fs.read()) != -1) {
|
||||
sb.append((char) ch);
|
||||
}
|
||||
return Optional.of(sb.toString());
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOG.error("Could not find the file at %s", filePath, ex);
|
||||
throw ex;
|
||||
} catch (IOException ex) {
|
||||
LOG.error("An error occurred while trying to read file %s", filePath, ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<String> computeRulesSchema(String rulesSchema, String uiConfig) throws IOException {
|
||||
JsonNode schemaNode = MAPPER.readTree(rulesSchema);
|
||||
Map<String, Map<String, Object>> formAttributes = MAPPER.readValue(uiConfig,
|
||||
new TypeReference<HashMap<String, Map<String, Object>>>() {
|
||||
});
|
||||
|
||||
Set<String> layoutKeys = formAttributes.get(LAYOUT_FIELD_NAME).keySet();
|
||||
for (String key : layoutKeys) {
|
||||
String[] tree = key.split(DOT_SEPARATOR_REGEX);
|
||||
JsonNode nodeRef = schemaNode;
|
||||
for (String branch : tree) {
|
||||
nodeRef = nodeRef.findValue(branch);
|
||||
}
|
||||
((ObjectNode) nodeRef).putPOJO(SCHEMA_FORM_LAYOUT_KEY, formAttributes.get(LAYOUT_FIELD_NAME).get(key));
|
||||
}
|
||||
|
||||
String uiSchema = MAPPER.writeValueAsString(schemaNode);
|
||||
|
||||
//NOTE: we change min items in arrays to 0 so it displays better in the UI
|
||||
uiSchema = uiSchema.replaceAll(INDEX_REPLACE_REGEX, INDEX_REPLACEMENT);
|
||||
return Optional.ofNullable(uiSchema);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package uk.co.gresearch.nortem.configeditor.common;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
public interface ConfigSchemaService extends HealthCheckable {
|
||||
String NOT_IMPLEMENTED_MSG = "Not implemented";
|
||||
String SCHEMA_INIT_ERROR = "Error during computing json schema";
|
||||
|
||||
ConfigEditorResult getSchema();
|
||||
|
||||
ConfigEditorResult validateConfiguration(String configuration);
|
||||
|
||||
ConfigEditorResult validateConfigurations(String configurations);
|
||||
|
||||
default Health checkHealth() { return Health.up().build(); };
|
||||
|
||||
default ConfigEditorResult getFields() {
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR, NOT_IMPLEMENTED_MSG);
|
||||
}
|
||||
|
||||
default ConfigEditorResult testConfiguration(String configuration, String event ) {
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR, NOT_IMPLEMENTED_MSG);
|
||||
}
|
||||
|
||||
default ConfigEditorResult testConfigurations(String configurations, String event) {
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR, NOT_IMPLEMENTED_MSG);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package uk.co.gresearch.nortem.configeditor.common;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
|
||||
public interface HealthCheckable {
|
||||
Health checkHealth();
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigInfo {
|
||||
private Map<String, String> filesContent;
|
||||
private String commitMessage;
|
||||
private int oldVersion;
|
||||
private int version;
|
||||
private String committer;
|
||||
private String committerEmail;
|
||||
private String branchName = "master";
|
||||
private boolean shouldCleanDirectory = false;
|
||||
|
||||
public Map<String, String> getFilesContent() {
|
||||
return filesContent;
|
||||
}
|
||||
|
||||
public void setFilesContent(Map<String, String> filesContent) {
|
||||
this.filesContent = filesContent;
|
||||
}
|
||||
|
||||
public String getCommitMessage() {
|
||||
return commitMessage;
|
||||
}
|
||||
|
||||
public void setCommitMessage(String commitMessage) {
|
||||
this.commitMessage = commitMessage;
|
||||
}
|
||||
|
||||
public int getOldVersion() {
|
||||
return oldVersion;
|
||||
}
|
||||
|
||||
public void setOldVersion(int oldVersion) {
|
||||
this.oldVersion = oldVersion;
|
||||
}
|
||||
|
||||
public String getCommitter() {
|
||||
return committer;
|
||||
}
|
||||
|
||||
public void setCommitter(String committer) {
|
||||
this.committer = committer;
|
||||
}
|
||||
|
||||
public String getCommitterEmail() {
|
||||
return committerEmail;
|
||||
}
|
||||
|
||||
public void setCommitterEmail(String committerEmail) {
|
||||
this.committerEmail = committerEmail;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public boolean isNewConfig() {
|
||||
return oldVersion == 0;
|
||||
}
|
||||
|
||||
public String getBranchName() {
|
||||
return branchName;
|
||||
}
|
||||
|
||||
public void setBranchName(String branchName) {
|
||||
this.branchName = branchName;
|
||||
}
|
||||
|
||||
public boolean shouldCleanDirectory() {
|
||||
return shouldCleanDirectory;
|
||||
}
|
||||
|
||||
public void shouldCleanDirectory(boolean shouldCleanDirectory) {
|
||||
this.shouldCleanDirectory = shouldCleanDirectory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public interface ConfigInfoProvider {
|
||||
String RULE_COMMIT_TEMPLATE_NEW = "Adding new rule: %s";
|
||||
String RULE_COMMIT_TEMPLATE_UPDATE = "Updating rule: %s to version: %d";
|
||||
String RULE_COMMIT_TEMPLATE_RELEASE = "Rules released to version: %d";
|
||||
String CONFIG_COMMIT_TEMPLATE_NEW = "Adding new configuration: %s";
|
||||
String CONFIG_COMMIT_TEMPLATE_UPDATE = "Updating configuration: %s to version: %d";
|
||||
String CONFIG_COMMIT_TEMPLATE_RELEASE = "Configuration released to version: %d";
|
||||
String RELEASE_BRANCH_TEMPLATE = "release_%d_by_%s_on_%s";
|
||||
int MILLI_SECONDS = 1000;
|
||||
|
||||
ConfigInfo getConfigInfo(String user, String config);
|
||||
|
||||
ConfigInfo getReleaseInfo(String user, String release);
|
||||
|
||||
int getReleaseVersion(List<ConfigEditorFile> files);
|
||||
|
||||
ConfigEditorFile.ContentType getFileContentType();
|
||||
|
||||
default ConfigInfo configInfoFromUser(String userName) {
|
||||
int delimiter = userName.indexOf('@');
|
||||
if (delimiter <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Unexpected userName format: %s", userName));
|
||||
}
|
||||
|
||||
ConfigInfo ret = new ConfigInfo();
|
||||
String committer = userName.substring(0, delimiter);
|
||||
ret.setCommitter(committer);
|
||||
ret.setCommitterEmail(userName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
default String getLocalDateTime() {
|
||||
return LocalDateTime.ofInstant(Instant.ofEpochSecond(System.currentTimeMillis() / MILLI_SECONDS),
|
||||
TimeZone.getDefault().toZoneId())
|
||||
.toString()
|
||||
.replaceAll(":", "-");
|
||||
}
|
||||
|
||||
default boolean isStoreFile(String filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean isReleaseFile(String filename) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.configeditor.common.HealthCheckable;
|
||||
|
||||
public interface ConfigStore extends HealthCheckable {
|
||||
|
||||
ConfigEditorResult addConfig(String user, String newConfig);
|
||||
|
||||
ConfigEditorResult updateConfig(String user, String configToUpdate);
|
||||
|
||||
ConfigEditorResult getConfigs();
|
||||
|
||||
ConfigEditorResult getConfigsRelease();
|
||||
|
||||
ConfigEditorResult getConfigsReleaseStatus();
|
||||
|
||||
ConfigEditorResult submitConfigsRelease(String user, String rulesRelease);
|
||||
|
||||
ConfigEditorResult getRepositories();
|
||||
|
||||
ConfigEditorResult shutDown();
|
||||
|
||||
ConfigEditorResult awaitShutDown();
|
||||
|
||||
Health checkHealth();
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorRepositories;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult.StatusCode.BAD_REQUEST;
|
||||
import static uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult.StatusCode.OK;
|
||||
|
||||
public class ConfigStoreImpl implements ConfigStore, Closeable {
|
||||
private static final Logger LOG =
|
||||
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final int RELEASES_MAXIMUM_SHUTTING_DOWN_TIME = 60000; //1min
|
||||
private static final int RULES_MAXIMUM_SHUTTING_DOWN_TIME = 120000; //2min
|
||||
|
||||
private final ExecutorService gitStoreService =
|
||||
Executors.newSingleThreadExecutor();
|
||||
private final ExecutorService gitReleasesService =
|
||||
Executors.newSingleThreadExecutor();
|
||||
|
||||
private final AtomicReference<List<ConfigEditorFile>> filesCache =
|
||||
new AtomicReference<>();
|
||||
private final AtomicReference<Exception> exception =
|
||||
new AtomicReference<>();
|
||||
|
||||
private final GitRepository gitStoreRepo;
|
||||
private final GitRepository gitReleasesRepo;
|
||||
private final ReleasePullRequestService pullRequestService;
|
||||
private final ConfigInfoProvider configInfoProvider;
|
||||
|
||||
public ConfigStoreImpl(GitRepository gitStoreRepo,
|
||||
GitRepository gitReleasesRepo,
|
||||
ReleasePullRequestService pullRequestService,
|
||||
ConfigInfoProvider configInfoProvider) throws IOException, GitAPIException {
|
||||
this.gitStoreRepo = gitStoreRepo;
|
||||
this.gitReleasesRepo = gitReleasesRepo;
|
||||
this.pullRequestService = pullRequestService;
|
||||
this.configInfoProvider = configInfoProvider;
|
||||
//NOTE: we would like to init rules cache
|
||||
init();
|
||||
}
|
||||
|
||||
private List<ConfigEditorFile> getFiles(ConfigEditorResult result, Function<String, Boolean> filter) {
|
||||
List<ConfigEditorFile> ret = result.getAttributes().getFiles();
|
||||
ret.removeIf(x -> !filter.apply(x.getFileName()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void init() throws IOException, GitAPIException {
|
||||
ConfigEditorResult result = gitStoreRepo.getFiles();
|
||||
if (result.getStatusCode() != OK) {
|
||||
throw new IllegalStateException("Problem during initialisation");
|
||||
}
|
||||
|
||||
List<ConfigEditorFile> files = getFiles(result, configInfoProvider::isStoreFile);
|
||||
filesCache.set(files);
|
||||
}
|
||||
|
||||
private ConfigEditorResult updateConfigInternally(ConfigInfo configInfo) {
|
||||
try {
|
||||
Callable<ConfigEditorResult> command =
|
||||
() -> gitStoreRepo.transactCopyAndCommit(configInfo);
|
||||
|
||||
filesCache.set(getFiles(gitStoreService.submit(command).get(), configInfoProvider::isStoreFile));
|
||||
return getConfigs();
|
||||
} catch (Exception e) {
|
||||
exception.set(e);
|
||||
String msg = String.format("Exception %s\n during storing a config %s in git",
|
||||
ExceptionUtils.getStackTrace(e),
|
||||
configInfo.getFilesContent());
|
||||
LOG.error(msg);
|
||||
gitStoreService.shutdown();
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult addConfig(String user, String newConfig) {
|
||||
if (exception.get() != null) {
|
||||
return ConfigEditorResult.fromException(exception.get());
|
||||
}
|
||||
|
||||
LOG.info(String.format("User %s requested to add configuration", user));
|
||||
ConfigInfo configInfo;
|
||||
try {
|
||||
configInfo = configInfoProvider.getConfigInfo(user, newConfig);
|
||||
Set<String> intersection = filesCache.get().stream().map(x -> x.getFileName()).collect(Collectors.toSet());
|
||||
intersection.retainAll(configInfo.getFilesContent().keySet());
|
||||
if (!configInfo.isNewConfig()
|
||||
|| !intersection.isEmpty()) {
|
||||
String msg = "Configuration already exists or has wrong version";
|
||||
LOG.error(msg);
|
||||
return ConfigEditorResult.fromMessage(
|
||||
ConfigEditorResult.StatusCode.BAD_REQUEST,
|
||||
msg);
|
||||
}
|
||||
|
||||
return updateConfigInternally(configInfo);
|
||||
} catch (Exception e) {
|
||||
String msg = String.format("Exception %s\n during adding new configuration %s, user: %s",
|
||||
ExceptionUtils.getStackTrace(e),
|
||||
newConfig,
|
||||
user);
|
||||
LOG.error(msg);
|
||||
return ConfigEditorResult.fromMessage(
|
||||
ConfigEditorResult.StatusCode.BAD_REQUEST,
|
||||
msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult updateConfig(String user, String configToUpdate) {
|
||||
if (exception.get() != null) {
|
||||
return ConfigEditorResult.fromException(exception.get());
|
||||
}
|
||||
|
||||
LOG.info(String.format("User %s requested to update the configuration", user));
|
||||
ConfigInfo configInfo;
|
||||
try {
|
||||
configInfo = configInfoProvider.getConfigInfo(user, configToUpdate);
|
||||
Set<String> intersection = filesCache.get().stream().map(x -> x.getFileName()).collect(Collectors.toSet());
|
||||
intersection.retainAll(configInfo.getFilesContent().keySet());
|
||||
if (configInfo.isNewConfig()
|
||||
|| intersection.isEmpty()) {
|
||||
String msg = "Rule does not exist or has wrong version";
|
||||
LOG.error(msg);
|
||||
return ConfigEditorResult.fromMessage(
|
||||
ConfigEditorResult.StatusCode.BAD_REQUEST,
|
||||
msg);
|
||||
}
|
||||
return updateConfigInternally(configInfo);
|
||||
} catch (Exception e) {
|
||||
String msg = String.format("Exception %s\n during updating configuration %s, user: %s",
|
||||
ExceptionUtils.getStackTrace(e),
|
||||
configToUpdate,
|
||||
user);
|
||||
LOG.error(msg);
|
||||
return ConfigEditorResult.fromMessage(
|
||||
ConfigEditorResult.StatusCode.BAD_REQUEST,
|
||||
msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getConfigs() {
|
||||
if (exception.get() != null) {
|
||||
return ConfigEditorResult.fromException(exception.get());
|
||||
}
|
||||
|
||||
List<ConfigEditorFile> files = filesCache.get();
|
||||
if (files == null || files.isEmpty()) {
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR,
|
||||
"Empty rules");
|
||||
}
|
||||
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setFiles(files);
|
||||
return new ConfigEditorResult(OK, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getConfigsRelease() {
|
||||
if (exception.get() != null) {
|
||||
return ConfigEditorResult.fromException(exception.get());
|
||||
}
|
||||
|
||||
Callable<ConfigEditorResult> command = () -> gitReleasesRepo.getFiles();
|
||||
try {
|
||||
ConfigEditorResult ret = gitReleasesService
|
||||
.submit(command)
|
||||
.get();
|
||||
|
||||
int rulesVersion = configInfoProvider.getReleaseVersion(ret.getAttributes().getFiles());
|
||||
List<ConfigEditorFile> files = getFiles(ret, configInfoProvider::isReleaseFile);
|
||||
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setRulesVersion(rulesVersion);
|
||||
attributes.setFiles(files);
|
||||
return new ConfigEditorResult(files.isEmpty() ? ConfigEditorResult.StatusCode.ERROR : OK,
|
||||
attributes);
|
||||
} catch (Exception e) {
|
||||
exception.set(e);
|
||||
String msg = String.format("Exception %s\n during obtaining release files",
|
||||
ExceptionUtils.getStackTrace(e));
|
||||
LOG.error(msg);
|
||||
gitReleasesService.shutdown();
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getConfigsReleaseStatus() {
|
||||
if (exception.get() != null) {
|
||||
return ConfigEditorResult.fromException(exception.get());
|
||||
}
|
||||
|
||||
try {
|
||||
return pullRequestService.pendingPullRequest();
|
||||
} catch (IOException e) {
|
||||
exception.set(e);
|
||||
String msg = String.format("Exception %s\n during obtaining pull requests",
|
||||
ExceptionUtils.getStackTrace(e));
|
||||
LOG.error(msg);
|
||||
gitReleasesService.shutdown();
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult submitConfigsRelease(String user, String rulesRelease) {
|
||||
LOG.info(String.format("User %s would like submit release", user));
|
||||
|
||||
if (exception.get() != null) {
|
||||
return ConfigEditorResult.fromException(exception.get());
|
||||
}
|
||||
|
||||
ConfigInfo releaseInfo;
|
||||
try {
|
||||
releaseInfo = configInfoProvider.getReleaseInfo(user, rulesRelease);
|
||||
} catch (Exception e) {
|
||||
String msg = String.format("Exception %s\n processing config info %s, user: %s",
|
||||
ExceptionUtils.getStackTrace(e),
|
||||
rulesRelease,
|
||||
user);
|
||||
LOG.error(msg);
|
||||
return ConfigEditorResult.fromMessage(
|
||||
ConfigEditorResult.StatusCode.BAD_REQUEST, msg);
|
||||
}
|
||||
|
||||
Callable<ConfigEditorResult> command =
|
||||
() -> {
|
||||
ConfigEditorResult pending = pullRequestService.pendingPullRequest();
|
||||
if (pending.getStatusCode() != OK) {
|
||||
return pending;
|
||||
}
|
||||
if (pending.getAttributes().getPendingPullRequest()) {
|
||||
return new ConfigEditorResult(BAD_REQUEST, pending.getAttributes());
|
||||
}
|
||||
|
||||
gitReleasesRepo.transactCopyAndCommit(releaseInfo);
|
||||
return pullRequestService.createPullRequest(releaseInfo);
|
||||
};
|
||||
|
||||
try {
|
||||
return gitReleasesService
|
||||
.submit(command)
|
||||
.get();
|
||||
} catch (Exception e) {
|
||||
exception.set(e);
|
||||
String msg = String.format("Exception %s\n during submitting rule release %s in git",
|
||||
ExceptionUtils.getStackTrace(e),
|
||||
rulesRelease);
|
||||
LOG.error(msg);
|
||||
gitReleasesService.shutdown();
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getRepositories() {
|
||||
ConfigEditorRepositories repositories = new ConfigEditorRepositories(
|
||||
gitStoreRepo.getRepoUri(),
|
||||
gitReleasesRepo.getRepoUri());
|
||||
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setRulesRepositories(repositories);
|
||||
return new ConfigEditorResult(OK, attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult shutDown() {
|
||||
LOG.info("Initiating shutting down the config store service");
|
||||
gitStoreService.shutdown();
|
||||
gitReleasesService.shutdown();
|
||||
return new ConfigEditorResult(OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult awaitShutDown() {
|
||||
LOG.info("Initiating awaiting shutting down the config store service");
|
||||
try {
|
||||
String errorMsg = "";
|
||||
if (!gitReleasesService.awaitTermination(RELEASES_MAXIMUM_SHUTTING_DOWN_TIME,
|
||||
TimeUnit.MILLISECONDS)) {
|
||||
errorMsg = "Git releases services not shut down in the timeout.";
|
||||
}
|
||||
|
||||
if (!gitStoreService.awaitTermination(RULES_MAXIMUM_SHUTTING_DOWN_TIME,
|
||||
TimeUnit.MILLISECONDS)) {
|
||||
errorMsg += "Git store services not shut down in the timeout.";
|
||||
}
|
||||
|
||||
if (!errorMsg.isEmpty()) {
|
||||
LOG.error(errorMsg);
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR, errorMsg);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error(String.format("Exception during shutting down the config store services %s",
|
||||
ExceptionUtils.getStackTrace(e)));
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
|
||||
LOG.info("Shutting down the rule store services completed");
|
||||
return new ConfigEditorResult(OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health checkHealth() {
|
||||
Exception e = exception.get();
|
||||
return e == null
|
||||
? Health.up().build()
|
||||
: Health.down(e).build();
|
||||
}
|
||||
|
||||
public static ConfigStore createRuleStore(ConfigStoreProperties props,
|
||||
ConfigInfoProvider ruleInfoProvider) throws GitAPIException, IOException {
|
||||
LOG.info(String.format("Initialising git config store service for repositories: %s, %s",
|
||||
props.getStoreRepositoryName(),
|
||||
props.getReleaseRepositoryName()));
|
||||
|
||||
GitRepository gitStoreRepo = new GitRepository.Builder()
|
||||
.gitUrl(props.getGithubUrl())
|
||||
.repoFolder(props.getStoreRepositoryPath())
|
||||
.repoName(props.getStoreRepositoryName())
|
||||
.rulesDirectory(props.getStoreDirectory())
|
||||
.credentials(props.getGitUserName(), props.getGitPassword())
|
||||
.contentType(ruleInfoProvider.getFileContentType())
|
||||
.build();
|
||||
|
||||
GitRepository gitReleasesRepo = new GitRepository.Builder()
|
||||
.gitUrl(props.getGithubUrl())
|
||||
.repoFolder(props.getReleaseRepositoryPath())
|
||||
.repoName(props.getReleaseRepositoryName())
|
||||
.rulesDirectory(props.getReleaseDirectory())
|
||||
.credentials(props.getGitUserName(), props.getGitPassword())
|
||||
.contentType(ruleInfoProvider.getFileContentType())
|
||||
.build();
|
||||
|
||||
ReleasePullRequestService pullRequestService = new ReleasePullRequestService.Builder()
|
||||
.uri(props.getGithubUrl())
|
||||
.repoName(props.getReleaseRepositoryName())
|
||||
.credentials(props.getGitUserName(), props.getGitPassword())
|
||||
.build();
|
||||
|
||||
LOG.info("Initialising git config store service completed");
|
||||
return new ConfigStoreImpl(gitStoreRepo,
|
||||
gitReleasesRepo,
|
||||
pullRequestService,
|
||||
ruleInfoProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
gitStoreRepo.close();
|
||||
gitReleasesRepo.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
public class ConfigStoreProperties {
|
||||
private String githubUrl;
|
||||
private String gitUserName;
|
||||
private String gitPassword;
|
||||
private String storeRepositoryName;
|
||||
private String releaseRepositoryName;
|
||||
private String storeRepositoryPath;
|
||||
private String releaseRepositoryPath;
|
||||
private String storeDirectory;
|
||||
private String releaseDirectory;
|
||||
|
||||
public String getGithubUrl() {
|
||||
return githubUrl;
|
||||
}
|
||||
|
||||
public void setGithubUrl(String githubUrl) {
|
||||
this.githubUrl = githubUrl;
|
||||
}
|
||||
|
||||
public String getGitUserName() {
|
||||
return gitUserName;
|
||||
}
|
||||
|
||||
public void setGitUserName(String gitUserName) {
|
||||
this.gitUserName = gitUserName;
|
||||
}
|
||||
|
||||
public String getGitPassword() {
|
||||
return gitPassword;
|
||||
}
|
||||
|
||||
public void setGitPassword(String gitPassword) {
|
||||
this.gitPassword = gitPassword;
|
||||
}
|
||||
|
||||
public String getStoreRepositoryName() {
|
||||
return storeRepositoryName;
|
||||
}
|
||||
|
||||
public void setStoreRepositoryName(String storeRepositoryName) {
|
||||
this.storeRepositoryName = storeRepositoryName;
|
||||
}
|
||||
|
||||
public String getReleaseRepositoryName() {
|
||||
return releaseRepositoryName;
|
||||
}
|
||||
|
||||
public void setReleaseRepositoryName(String releaseRepositoryName) {
|
||||
this.releaseRepositoryName = releaseRepositoryName;
|
||||
}
|
||||
|
||||
public String getStoreRepositoryPath() {
|
||||
return storeRepositoryPath;
|
||||
}
|
||||
|
||||
public void setStoreRepositoryPath(String storeRepositoryPath) {
|
||||
this.storeRepositoryPath = storeRepositoryPath;
|
||||
}
|
||||
|
||||
public String getReleaseRepositoryPath() {
|
||||
return releaseRepositoryPath;
|
||||
}
|
||||
|
||||
public void setReleaseRepositoryPath(String releaseRepositoryPath) {
|
||||
this.releaseRepositoryPath = releaseRepositoryPath;
|
||||
}
|
||||
|
||||
public String getStoreDirectory() {
|
||||
return storeDirectory;
|
||||
}
|
||||
|
||||
public void setStoreDirectory(String storeDirectory) {
|
||||
this.storeDirectory = storeDirectory;
|
||||
}
|
||||
|
||||
public String getReleaseDirectory() {
|
||||
return releaseDirectory;
|
||||
}
|
||||
|
||||
public void setReleaseDirectory(String releaseDirectory) {
|
||||
this.releaseDirectory = releaseDirectory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.diff.DiffEntry;
|
||||
import org.eclipse.jgit.diff.DiffFormatter;
|
||||
import org.eclipse.jgit.diff.Edit;
|
||||
import org.eclipse.jgit.diff.RawTextComparator;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.filter.RevFilter;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.eclipse.jgit.util.io.DisabledOutputStream;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFileHistoryItem;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class GitRepository implements Closeable {
|
||||
public static final String MAIN_BRANCH = "master";
|
||||
private final CredentialsProvider credentialsProvider;
|
||||
private final Git git;
|
||||
private final Path rulesPath;
|
||||
private final String repoUri;
|
||||
private final ConfigEditorFile.ContentType contentType;
|
||||
|
||||
private static String readFile(Path path) throws IOException {
|
||||
return new String(Files.readAllBytes(path), UTF_8);
|
||||
}
|
||||
|
||||
private GitRepository(Builder builder) {
|
||||
credentialsProvider = builder.credentialsProvider;
|
||||
git = builder.git;
|
||||
rulesPath = builder.rulesPath;
|
||||
repoUri = builder.repoUri;
|
||||
contentType = builder.contentType;
|
||||
}
|
||||
|
||||
public ConfigEditorResult transactCopyAndCommit(
|
||||
ConfigInfo ruleInfo) throws GitAPIException, IOException {
|
||||
git.pull()
|
||||
.setCredentialsProvider(credentialsProvider)
|
||||
.call();
|
||||
|
||||
if (!MAIN_BRANCH.equals(ruleInfo.getBranchName())) {
|
||||
git.branchCreate().setName(ruleInfo.getBranchName()).call();
|
||||
git.checkout().setName(ruleInfo.getBranchName()).call();
|
||||
}
|
||||
|
||||
if (ruleInfo.shouldCleanDirectory()) {
|
||||
FileUtils.cleanDirectory(rulesPath.toFile());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> file : ruleInfo.getFilesContent().entrySet()) {
|
||||
Path filePath = Paths.get(rulesPath.toString(), file.getKey());
|
||||
Files.write(filePath, file.getValue().getBytes());
|
||||
}
|
||||
|
||||
git.add()
|
||||
.addFilepattern(rulesPath.getFileName().toString())
|
||||
.call();
|
||||
|
||||
git.commit()
|
||||
.setAll(true)
|
||||
.setAuthor(ruleInfo.getCommitter(), ruleInfo.getCommitterEmail())
|
||||
.setMessage(ruleInfo.getCommitMessage())
|
||||
.call();
|
||||
|
||||
git.push()
|
||||
.setCredentialsProvider(credentialsProvider)
|
||||
.call();
|
||||
|
||||
if (!MAIN_BRANCH.equals(ruleInfo.getBranchName())) {
|
||||
ConfigEditorResult branchFiles = getFiles();
|
||||
git.checkout()
|
||||
.setName(MAIN_BRANCH)
|
||||
.call();
|
||||
return branchFiles;
|
||||
}
|
||||
|
||||
return getFiles();
|
||||
}
|
||||
|
||||
public ConfigEditorResult getFiles() throws IOException, GitAPIException {
|
||||
git.pull()
|
||||
.setCredentialsProvider(credentialsProvider)
|
||||
.call();
|
||||
|
||||
Map<String, ConfigEditorFile> files = new HashMap<>();
|
||||
try (Stream<Path> paths = Files.walk(rulesPath)) {
|
||||
paths.filter(Files::isRegularFile)
|
||||
.forEach(x -> {
|
||||
try {
|
||||
files.put(x.getFileName().toString(),
|
||||
new ConfigEditorFile(x.getFileName().toString(), readFile(x), contentType));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Iterable<RevCommit> commits = git.log().setRevFilter(RevFilter.NO_MERGES).call();
|
||||
try (DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE)) {
|
||||
df.setRepository(git.getRepository());
|
||||
df.setDiffComparator(RawTextComparator.DEFAULT);
|
||||
for (RevCommit commit : commits) {
|
||||
if (commit.getParentCount() == 0) {
|
||||
//NOTE: we skip init commit
|
||||
continue;
|
||||
}
|
||||
|
||||
String author = commit.getAuthorIdent().getName();
|
||||
int commitTime = commit.getCommitTime();
|
||||
RevCommit parent = commit.getParent(0);
|
||||
|
||||
List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree());
|
||||
for (DiffEntry diff : diffs) {
|
||||
int linesAdded = 0, linesRemoved = 0;
|
||||
int lastSlashIndex = diff.getNewPath().lastIndexOf('/');
|
||||
String fileName = lastSlashIndex < 0
|
||||
? diff.getNewPath()
|
||||
: diff.getNewPath().substring(lastSlashIndex + 1);
|
||||
if (!files.containsKey(fileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Edit edit : df.toFileHeader(diff).toEditList()) {
|
||||
linesRemoved += edit.getEndA() - edit.getBeginA();
|
||||
linesAdded += edit.getEndB() - edit.getBeginB();
|
||||
}
|
||||
|
||||
ConfigEditorFileHistoryItem historyItem = new ConfigEditorFileHistoryItem();
|
||||
historyItem.setAuthor(author);
|
||||
historyItem.setTimestamp(commitTime);
|
||||
historyItem.setAddedLines(linesAdded);
|
||||
historyItem.setRemoved(linesRemoved);
|
||||
files.get(fileName).getFileHistory().add(historyItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setFiles(files.values().stream().collect(Collectors.toList()));
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
}
|
||||
|
||||
public String getRepoUri() {
|
||||
return repoUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
git.close();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private static final String GIT_REPO_URL_FORMAT = "%s/%s.git";
|
||||
private String repoName;
|
||||
private String repoUri;
|
||||
private String gitUrl;
|
||||
private String repoFolder;
|
||||
private Path rulesPath;
|
||||
private String rulesDirectory = "";
|
||||
private CredentialsProvider credentialsProvider;
|
||||
private Git git;
|
||||
private ConfigEditorFile.ContentType contentType = ConfigEditorFile.ContentType.RAW_JSON_STRING;
|
||||
|
||||
Builder repoName(String repoName) {
|
||||
this.repoName = repoName;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder gitUrl(String gitUrl) {
|
||||
this.gitUrl = gitUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder rulesDirectory(String directory) {
|
||||
this.rulesDirectory = directory;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder repoFolder(String repoFolder) {
|
||||
this.repoFolder = repoFolder;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder contentType(ConfigEditorFile.ContentType contentType) {
|
||||
this.contentType = contentType;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder credentials(String userName, String password) {
|
||||
credentialsProvider = new UsernamePasswordCredentialsProvider(userName, password);
|
||||
return this;
|
||||
}
|
||||
|
||||
GitRepository build() throws GitAPIException, IOException {
|
||||
if (repoName == null
|
||||
|| gitUrl == null
|
||||
|| repoFolder == null
|
||||
|| credentialsProvider == null) {
|
||||
throw new IllegalArgumentException("Not provided required properties");
|
||||
}
|
||||
|
||||
File repoFolderDir = new File(repoFolder);
|
||||
if (repoFolderDir.exists()) {
|
||||
FileUtils.cleanDirectory(repoFolderDir);
|
||||
} else {
|
||||
repoFolderDir.mkdir();
|
||||
}
|
||||
|
||||
repoUri = String.format(GIT_REPO_URL_FORMAT, gitUrl, repoName);
|
||||
|
||||
git = Git.cloneRepository()
|
||||
.setCredentialsProvider(credentialsProvider)
|
||||
.setURI(repoUri)
|
||||
.setDirectory(repoFolderDir)
|
||||
.call();
|
||||
|
||||
rulesPath = Paths.get(repoFolder, rulesDirectory);
|
||||
if (git == null || !repoFolderDir.exists()) {
|
||||
throw new IllegalStateException("Error during git rules repo initialisation");
|
||||
}
|
||||
|
||||
return new GitRepository(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class JsonConfigInfoProvider implements ConfigInfoProvider {
|
||||
private static final ObjectReader JSON_READER = new ObjectMapper()
|
||||
.readerFor(new TypeReference<Map<String, Object>>() { });
|
||||
private static final String WRONG_RELEASE_FORMAT = "Wrong config release json file format";
|
||||
private static final String WRONG_CONFIG_FORMAT = "Wrong config json file format";
|
||||
private static final String MISSING_FILENAME_MSG = "Missing filename: %s";
|
||||
private static final String WRONG_FILENAME_MSG = "Wrong config name: %s";
|
||||
|
||||
private final String configNameField;
|
||||
private final String configAuthorField;
|
||||
private final String configVersionField;
|
||||
private final String configsVersionField;
|
||||
private final String configFilenameFormat;
|
||||
private final String releaseFilename;
|
||||
private final String jsonFileSuffix;
|
||||
private final String ruleVersionRegex;
|
||||
private final String releaseVersionRegex;
|
||||
private final String ruleAuthorRegex;
|
||||
private final String ruleVersionFormat;
|
||||
private final String ruleAuthorFormat;
|
||||
private final String releaseVersionFormat;
|
||||
private final String commitTemplateNew;
|
||||
private final String commitTemplateUpdate;
|
||||
private final String commitTemplateRelease;
|
||||
private final Pattern ruleNamePattern;
|
||||
|
||||
JsonConfigInfoProvider(Builder builder) {
|
||||
this.configNameField = builder.configNameField;
|
||||
this.configAuthorField = builder.configAuthorField;
|
||||
this.configVersionField = builder.configVersionField;
|
||||
this.configsVersionField = builder.configsVersionField;
|
||||
this.configFilenameFormat = builder.configFilenameFormat;
|
||||
this.releaseFilename = builder.releaseFilename;
|
||||
this.jsonFileSuffix = builder.jsonFileSuffix;
|
||||
this.ruleVersionRegex = builder.ruleVersionRegex;
|
||||
this.releaseVersionRegex = builder.releaseVersionRegex;
|
||||
this.ruleAuthorRegex = builder.ruleAuthorRegex;
|
||||
this.ruleVersionFormat = builder.ruleVersionFormat;
|
||||
this.ruleAuthorFormat = builder.ruleAuthorFormat;
|
||||
this.releaseVersionFormat = builder.releaseVersionFormat;
|
||||
this.ruleNamePattern = builder.ruleNamePattern;
|
||||
this.commitTemplateNew = builder.commitTemplateNew;
|
||||
this.commitTemplateUpdate = builder.commitTemplateUpdate;
|
||||
this.commitTemplateRelease = builder.commitTemplateRelease;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigInfo getConfigInfo(String userName, String config) {
|
||||
ConfigInfo configInfo = configInfoFromUser(userName);
|
||||
|
||||
Map<String, Object> metadata;
|
||||
try {
|
||||
metadata = JSON_READER.readValue(config);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(WRONG_CONFIG_FORMAT);
|
||||
}
|
||||
if (metadata == null
|
||||
|| !(metadata.get(configVersionField) instanceof Number)
|
||||
|| !(metadata.get(configAuthorField) instanceof String)
|
||||
|| !(metadata.get(configNameField) instanceof String)) {
|
||||
throw new IllegalArgumentException(WRONG_CONFIG_FORMAT);
|
||||
}
|
||||
|
||||
String configName = (String)metadata.get(configNameField);
|
||||
String configAuthor = (String)metadata.get(configAuthorField);
|
||||
int configVersion = ((Number)metadata.get(configVersionField)).intValue();
|
||||
|
||||
|
||||
Matcher nameMatcher = ruleNamePattern.matcher(configName);
|
||||
if (!nameMatcher.matches()) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(WRONG_FILENAME_MSG, configName));
|
||||
}
|
||||
|
||||
int newConfigVersion = configVersion + 1;
|
||||
configInfo.setOldVersion(configVersion);
|
||||
configInfo.setVersion(newConfigVersion);
|
||||
String commitMsg = configVersion == 0
|
||||
? String.format(commitTemplateNew, configName)
|
||||
: String.format(commitTemplateUpdate, configName, newConfigVersion);
|
||||
configInfo.setCommitMessage(commitMsg);
|
||||
|
||||
Map<String, String> files = new HashMap<>();
|
||||
String updatedRule = config.replaceFirst(ruleVersionRegex,
|
||||
String.format(ruleVersionFormat, newConfigVersion));
|
||||
|
||||
if (!configAuthor.equals(configInfo.getCommitter())) {
|
||||
//NOTE: we consider author to be the last committer,
|
||||
// auth logic can be added here when needed
|
||||
updatedRule = updatedRule.replaceFirst(ruleAuthorRegex,
|
||||
String.format(ruleAuthorFormat, configInfo.getCommitter()));
|
||||
}
|
||||
|
||||
files.put(String.format(configFilenameFormat, configName), updatedRule);
|
||||
configInfo.setFilesContent(files);
|
||||
return configInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigInfo getReleaseInfo(String userName, String release) {
|
||||
ConfigInfo configInfo = configInfoFromUser(userName);
|
||||
|
||||
int releaseVersion = getReleaseVersion(release);
|
||||
|
||||
int newRulesVersion = releaseVersion + 1;
|
||||
configInfo.setVersion(newRulesVersion);
|
||||
configInfo.setOldVersion(releaseVersion);
|
||||
configInfo.setBranchName(String.format(RELEASE_BRANCH_TEMPLATE,
|
||||
newRulesVersion,
|
||||
configInfo.getCommitter(),
|
||||
getLocalDateTime()));
|
||||
|
||||
configInfo.setCommitMessage(String.format(commitTemplateRelease, newRulesVersion));
|
||||
|
||||
String updatedRelease = release.replaceFirst(releaseVersionRegex,
|
||||
String.format(releaseVersionFormat, newRulesVersion));
|
||||
|
||||
Map<String, String> files = new HashMap<>();
|
||||
files.put(releaseFilename, updatedRelease);
|
||||
configInfo.setFilesContent(files);
|
||||
|
||||
return configInfo;
|
||||
}
|
||||
|
||||
private int getReleaseVersion(String content) {
|
||||
Map<String, Object> metadata;
|
||||
try {
|
||||
metadata = JSON_READER.readValue(content);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(WRONG_RELEASE_FORMAT);
|
||||
}
|
||||
if (metadata == null
|
||||
|| !(metadata.get(configsVersionField) instanceof Number)) {
|
||||
throw new IllegalArgumentException(WRONG_RELEASE_FORMAT);
|
||||
}
|
||||
|
||||
return ((Number)metadata.get(configsVersionField)).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReleaseVersion(List<ConfigEditorFile> files) {
|
||||
Optional<ConfigEditorFile> release = files
|
||||
.stream()
|
||||
.filter(x -> x.getFileName().equals(releaseFilename))
|
||||
.findFirst();
|
||||
if (!release.isPresent()) {
|
||||
throw new IllegalArgumentException(String.format(MISSING_FILENAME_MSG, releaseFilename));
|
||||
}
|
||||
|
||||
return getReleaseVersion(release.get().getContent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorFile.ContentType getFileContentType() {
|
||||
return ConfigEditorFile.ContentType.RAW_JSON_STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStoreFile(String filename) {
|
||||
return filename.endsWith(jsonFileSuffix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReleaseFile(String filename) {
|
||||
return releaseFilename.equals(filename);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private static final String MISSING_ARGUMENTS = "Missing required argument for the builder";
|
||||
private static final String CONFIG_VERSION_REGEX_MSG = "\"%s\"\\s*:\\s*\\d+";
|
||||
private static final String RELEASE_VERSION_REGEX_MSG = "\"%s\"\\s*:\\s*\\d+";
|
||||
private static final String CONFIG_AUTHOR_REGEX_MSG = "\"%s\"\\s*:\\s*\"\\w+\"";
|
||||
private static final String CONFIG_VERSION_FORMAT_MSG = "\"%s\": %%d";
|
||||
private static final String CONFIG_AUTHOR_FORMAT_MSG = "\"%s\": \"%%s\"";
|
||||
private static final String RELEASE_VERSION_FORMAT = "\"%s\": %%d";
|
||||
private String configNameField;
|
||||
private String configAuthorField;
|
||||
private String configVersionField;
|
||||
private String configsVersionField;
|
||||
private String configFilenameFormat = "%s.json";
|
||||
private String releaseFilename = "rules.json";
|
||||
private String jsonFileSuffix = "json";
|
||||
private String ruleVersionRegex;
|
||||
private String releaseVersionRegex;
|
||||
private String ruleAuthorRegex;
|
||||
private String ruleVersionFormat;
|
||||
private String ruleAuthorFormat;
|
||||
private String releaseVersionFormat;
|
||||
private Pattern ruleNamePattern = Pattern.compile("^[a-zA-Z0-9_]+$");
|
||||
private String commitTemplateNew = RULE_COMMIT_TEMPLATE_NEW;
|
||||
private String commitTemplateUpdate = RULE_COMMIT_TEMPLATE_UPDATE;
|
||||
private String commitTemplateRelease = RULE_COMMIT_TEMPLATE_RELEASE;
|
||||
|
||||
public Builder configNameField(String configNameField) {
|
||||
this.configNameField = configNameField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder configAuthorField(String configAuthorField) {
|
||||
this.configAuthorField = configAuthorField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder configVersionField(String configVersionField) {
|
||||
this.configVersionField = configVersionField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder configsVersionField(String configsVersionField) {
|
||||
this.configsVersionField = configsVersionField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder configFilenameFormat(String configFilenameFormat) {
|
||||
this.configFilenameFormat = configFilenameFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder releaseFilename(String releaseFilename) {
|
||||
this.releaseFilename = releaseFilename;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder useConfigWordingInGitMessages() {
|
||||
commitTemplateNew = CONFIG_COMMIT_TEMPLATE_NEW;
|
||||
commitTemplateUpdate = CONFIG_COMMIT_TEMPLATE_UPDATE;
|
||||
commitTemplateRelease = CONFIG_COMMIT_TEMPLATE_RELEASE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonConfigInfoProvider build() {
|
||||
if (configNameField == null
|
||||
|| configAuthorField == null
|
||||
|| configVersionField == null
|
||||
|| configsVersionField == null
|
||||
|| configFilenameFormat == null
|
||||
|| releaseFilename == null
|
||||
|| jsonFileSuffix == null) {
|
||||
throw new IllegalArgumentException(MISSING_ARGUMENTS);
|
||||
}
|
||||
|
||||
ruleVersionRegex = String.format(CONFIG_VERSION_REGEX_MSG, configVersionField);
|
||||
ruleVersionFormat = String.format(CONFIG_VERSION_FORMAT_MSG, configVersionField);
|
||||
releaseVersionRegex = String.format(RELEASE_VERSION_REGEX_MSG, configsVersionField);
|
||||
ruleAuthorRegex = String.format(CONFIG_AUTHOR_REGEX_MSG, configAuthorField);
|
||||
ruleAuthorFormat = String.format(CONFIG_AUTHOR_FORMAT_MSG, configAuthorField);
|
||||
releaseVersionFormat = String.format(RELEASE_VERSION_FORMAT, configsVersionField);
|
||||
|
||||
return new JsonConfigInfoProvider(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
public class JsonRuleConfigInfoProvider {
|
||||
private static final String AUTHOR_FIELD = "rule_author";
|
||||
private static final String NAME_FIELD = "rule_name";
|
||||
private static final String VERSION_FIELD = "rule_version";
|
||||
private static final String RELEASE_VERSION_FIELD = "rules_version";
|
||||
|
||||
public static ConfigInfoProvider create() {
|
||||
return new JsonConfigInfoProvider.Builder()
|
||||
.configAuthorField(AUTHOR_FIELD)
|
||||
.configNameField(NAME_FIELD)
|
||||
.configsVersionField(RELEASE_VERSION_FIELD)
|
||||
.configVersionField(VERSION_FIELD)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import org.eclipse.egit.github.core.PullRequest;
|
||||
import org.eclipse.egit.github.core.PullRequestMarker;
|
||||
import org.eclipse.egit.github.core.RepositoryId;
|
||||
import org.eclipse.egit.github.core.client.GitHubClient;
|
||||
import org.eclipse.egit.github.core.service.PullRequestService;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class ReleasePullRequestService {
|
||||
private static final String BODY_TEMPLATE = "User %s would like to release rules version %d.";
|
||||
private static final String PR_STATE_OPEN = "open";
|
||||
|
||||
private final RepositoryId repoId;
|
||||
private final PullRequestService service;
|
||||
private final String branchTo;
|
||||
|
||||
private ReleasePullRequestService(Builder builder) {
|
||||
this.repoId = builder.repoId;
|
||||
this.service = builder.service;
|
||||
this.branchTo = builder.branchTo;
|
||||
}
|
||||
|
||||
public ConfigEditorResult createPullRequest(ConfigInfo info) throws IOException {
|
||||
PullRequest request = new PullRequest();
|
||||
request.setBody(String.format(BODY_TEMPLATE,
|
||||
info.getCommitter(),
|
||||
info.getVersion()));
|
||||
|
||||
request.setTitle(info.getCommitMessage());
|
||||
request.setHead(new PullRequestMarker().setLabel(info.getBranchName()));
|
||||
request.setBase(new PullRequestMarker().setLabel(branchTo));
|
||||
|
||||
PullRequest response = service.createPullRequest(repoId, request);
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setPullRequestUrl(response.getHtmlUrl());
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attributes);
|
||||
}
|
||||
|
||||
public ConfigEditorResult pendingPullRequest() throws IOException {
|
||||
List<PullRequest> requests = service.getPullRequests(repoId, PR_STATE_OPEN);
|
||||
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setPendingPullRequest(!requests.isEmpty());
|
||||
if (!requests.isEmpty()) {
|
||||
attributes.setPullRequestUrl(requests.get(0).getHtmlUrl());
|
||||
}
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attributes);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String uri;
|
||||
private String user;
|
||||
private String password;
|
||||
private String repoName;
|
||||
private RepositoryId repoId;
|
||||
private PullRequestService service;
|
||||
private String branchTo = GitRepository.MAIN_BRANCH;
|
||||
|
||||
public Builder uri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder repoName(String repoName) {
|
||||
this.repoName = repoName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder credentials(String user, String password) {
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReleasePullRequestService build() {
|
||||
if (uri == null
|
||||
|| user == null
|
||||
|| repoName == null
|
||||
|| password == null
|
||||
|| repoName == null) {
|
||||
throw new IllegalArgumentException("Missing required parameters");
|
||||
}
|
||||
|
||||
repoId = RepositoryId.createFromId(repoName);
|
||||
|
||||
GitHubClient client = GitHubClient.createClient(uri);
|
||||
client.setCredentials(user, password);
|
||||
service = new PullRequestService(client);
|
||||
|
||||
return new ReleasePullRequestService(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonRawValue;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ConfigEditorAttributes {
|
||||
private String exception;
|
||||
private String message;
|
||||
@JsonProperty("rules_schema")
|
||||
@JsonRawValue
|
||||
private String rulesSchema;
|
||||
|
||||
@JsonProperty("pull_request_pending")
|
||||
private Boolean pendingPullRequest;
|
||||
|
||||
@JsonProperty("pull_request_url")
|
||||
private String pullRequestUrl;
|
||||
|
||||
@JsonProperty("user_name")
|
||||
private String userName;
|
||||
|
||||
private List<ConfigEditorFile> files;
|
||||
|
||||
@JsonProperty("rules_version")
|
||||
private Integer rulesVersion;
|
||||
|
||||
@JsonProperty("rules_repositories")
|
||||
ConfigEditorRepositories rulesRepositories;
|
||||
|
||||
@JsonProperty("fields")
|
||||
@JsonRawValue
|
||||
private String fields;
|
||||
|
||||
@JsonProperty("template_fields")
|
||||
private List<TemplateField> templateFields;
|
||||
|
||||
@JsonProperty("sensor_template_fields")
|
||||
private List<SensorTemplateFields> sensorTemplateFields;
|
||||
|
||||
@JsonProperty("test_result_output")
|
||||
private String testResultOutput;
|
||||
|
||||
@JsonProperty("test_result_complete")
|
||||
private Boolean testResultComplete;
|
||||
|
||||
private String event;
|
||||
|
||||
private List<ConfigEditorService> services;
|
||||
|
||||
public String getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public void setException(String exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getRulesSchema() {
|
||||
return rulesSchema;
|
||||
}
|
||||
|
||||
public void setRulesSchema(String rulesSchema) {
|
||||
this.rulesSchema = rulesSchema;
|
||||
}
|
||||
|
||||
public List<ConfigEditorFile> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public void setFiles(List<ConfigEditorFile> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public Boolean getPendingPullRequest() {
|
||||
return pendingPullRequest;
|
||||
}
|
||||
|
||||
public void setPendingPullRequest(Boolean pendingPullRequest) {
|
||||
this.pendingPullRequest = pendingPullRequest;
|
||||
}
|
||||
|
||||
public String getPullRequestUrl() {
|
||||
return pullRequestUrl;
|
||||
}
|
||||
|
||||
public void setPullRequestUrl(String pullRequestUrl) {
|
||||
this.pullRequestUrl = pullRequestUrl;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public Integer getRulesVersion() {
|
||||
return rulesVersion;
|
||||
}
|
||||
|
||||
public void setRulesVersion(Integer rulesVersion) {
|
||||
this.rulesVersion = rulesVersion;
|
||||
}
|
||||
|
||||
public ConfigEditorRepositories getRulesRepositories() {
|
||||
return rulesRepositories;
|
||||
}
|
||||
|
||||
public void setRulesRepositories(ConfigEditorRepositories rulesRepositories) {
|
||||
this.rulesRepositories = rulesRepositories;
|
||||
}
|
||||
|
||||
public List<TemplateField> getTemplateFields() {
|
||||
return templateFields;
|
||||
}
|
||||
|
||||
public void setTemplateFields(List<TemplateField> templateFields) {
|
||||
this.templateFields = templateFields;
|
||||
}
|
||||
|
||||
public List<SensorTemplateFields> getSensorTemplateFields() {
|
||||
return sensorTemplateFields;
|
||||
}
|
||||
|
||||
public void setSensorTemplateFields(List<SensorTemplateFields> sensorTemplateFields) {
|
||||
this.sensorTemplateFields = sensorTemplateFields;
|
||||
}
|
||||
|
||||
public String getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(String fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public String getTestResultOutput() {
|
||||
return testResultOutput;
|
||||
}
|
||||
|
||||
public void setTestResultOutput(String testResultOutput) {
|
||||
this.testResultOutput = testResultOutput;
|
||||
}
|
||||
|
||||
public Boolean getTestResultComplete() {
|
||||
return testResultComplete;
|
||||
}
|
||||
|
||||
public void setTestResultComplete(Boolean testResultComplete) {
|
||||
this.testResultComplete = testResultComplete;
|
||||
}
|
||||
|
||||
public String getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
@JsonSetter("event")
|
||||
public void setEvent(JsonNode event) {
|
||||
this.event = event.toString();
|
||||
}
|
||||
|
||||
public void setEvent(String event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public List<ConfigEditorService> getServices() {
|
||||
return services;
|
||||
}
|
||||
|
||||
public void setServices(List<ConfigEditorService> services) {
|
||||
this.services = services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ConfigEditorFile {
|
||||
public enum ContentType {
|
||||
RAW_JSON_STRING,
|
||||
STRING
|
||||
}
|
||||
@JsonProperty("file_name")
|
||||
@NotNull
|
||||
private String fileName;
|
||||
@JsonRawValue
|
||||
private String content;
|
||||
private String stringContent;
|
||||
|
||||
@JsonProperty("file_history")
|
||||
private List<ConfigEditorFileHistoryItem> fileHistory = new ArrayList<>();
|
||||
|
||||
public ConfigEditorFile() {
|
||||
}
|
||||
|
||||
public ConfigEditorFile(String fileName, String content, ContentType type) {
|
||||
this.fileName = fileName;
|
||||
switch (type) {
|
||||
case RAW_JSON_STRING:
|
||||
this.content = content;
|
||||
break;
|
||||
case STRING:
|
||||
this.stringContent = content;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@JsonSetter("content")
|
||||
void setContent(JsonNode content) {
|
||||
this.content = content.toString();
|
||||
}
|
||||
|
||||
@JsonProperty("string_content")
|
||||
public String getStringContent() {
|
||||
return stringContent;
|
||||
}
|
||||
|
||||
@JsonSetter("string_content")
|
||||
public void setStringContent(String stringContent) {
|
||||
this.stringContent = stringContent;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String getContentValue() {
|
||||
return content != null ? content : stringContent;
|
||||
}
|
||||
|
||||
public List<ConfigEditorFileHistoryItem> getFileHistory() {
|
||||
return fileHistory;
|
||||
}
|
||||
|
||||
public void setFileHistory(List<ConfigEditorFileHistoryItem> fileHistory) {
|
||||
this.fileHistory = fileHistory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class ConfigEditorFileHistoryItem {
|
||||
private String author;
|
||||
private String date;
|
||||
@JsonProperty("added")
|
||||
private Integer addedLines;
|
||||
@JsonProperty("removed")
|
||||
private Integer removedLines;
|
||||
|
||||
@JsonIgnore
|
||||
private Integer timestamp;
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Integer getAddedLines() {
|
||||
return addedLines;
|
||||
}
|
||||
|
||||
public void setAddedLines(Integer addedLines) {
|
||||
this.addedLines = addedLines;
|
||||
}
|
||||
|
||||
public Integer getRemoved() {
|
||||
return removedLines;
|
||||
}
|
||||
|
||||
public void setRemoved(Integer removed) {
|
||||
this.removedLines = removed;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public Integer getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(Integer timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
date = LocalDateTime.ofInstant(Instant.ofEpochSecond(timestamp),
|
||||
TimeZone.getDefault().toZoneId()).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class ConfigEditorRepositories {
|
||||
@JsonProperty("rule_store_url")
|
||||
private String ruleStoreUrl;
|
||||
@JsonProperty("rules_release_url")
|
||||
private String rulesReleaseUrl;
|
||||
|
||||
public ConfigEditorRepositories(String ruleStoreUrl, String rulesReleaseUrl) {
|
||||
this.ruleStoreUrl = ruleStoreUrl;
|
||||
this.rulesReleaseUrl = rulesReleaseUrl;
|
||||
}
|
||||
|
||||
public String getRuleStoreUrl() {
|
||||
return ruleStoreUrl;
|
||||
}
|
||||
|
||||
public void setRuleStoreUrl(String ruleStoreUrl) {
|
||||
this.ruleStoreUrl = ruleStoreUrl;
|
||||
}
|
||||
|
||||
public String getRulesReleaseUrl() {
|
||||
return rulesReleaseUrl;
|
||||
}
|
||||
|
||||
public void setRulesReleaseUrl(String rulesReleaseUrl) {
|
||||
this.rulesReleaseUrl = rulesReleaseUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ConfigEditorResult {
|
||||
public enum StatusCode {
|
||||
OK,
|
||||
BAD_REQUEST,
|
||||
UNAUTHORISED,
|
||||
ERROR,
|
||||
}
|
||||
@JsonProperty("status_code")
|
||||
private final StatusCode statusCode;
|
||||
private final ConfigEditorAttributes attributes;
|
||||
|
||||
public ConfigEditorResult(StatusCode statusCode) {
|
||||
this(statusCode, null);
|
||||
}
|
||||
|
||||
public ConfigEditorResult(StatusCode statusCode, ConfigEditorAttributes attributes) {
|
||||
this.statusCode = statusCode;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public StatusCode getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public ConfigEditorAttributes getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public static ConfigEditorResult fromMessage(StatusCode statusCode,
|
||||
String message) {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setMessage(message);
|
||||
return new ConfigEditorResult(statusCode, attr);
|
||||
}
|
||||
|
||||
public static ConfigEditorResult fromException(Exception e) {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setException(ExceptionUtils.getStackTrace(e));
|
||||
return new ConfigEditorResult(StatusCode.ERROR, attr);
|
||||
}
|
||||
|
||||
public static ConfigEditorResult fromSchema(String schema) {
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setRulesSchema(schema);
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK,
|
||||
attributes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
public class ConfigEditorService {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SensorTemplateFields {
|
||||
@JsonProperty("sensor_name")
|
||||
private String sensorName;
|
||||
private List<TemplateField> fields;
|
||||
|
||||
public SensorTemplateFields(String sensorName, List<TemplateField> fields) {
|
||||
this.sensorName = sensorName;
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public String getSensorName() {
|
||||
return sensorName;
|
||||
}
|
||||
|
||||
public void setSensorName(String sensorName) {
|
||||
this.sensorName = sensorName;
|
||||
}
|
||||
|
||||
public List<TemplateField> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(List<TemplateField> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package uk.co.gresearch.nortem.configeditor.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
public class TemplateField {
|
||||
private String name;
|
||||
|
||||
public TemplateField(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package uk.co.gresearch.nortem.configeditor.serviceaggregator;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorService;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigSchemaService;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigStore;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ServiceAggregator {
|
||||
String UNSUPPORTED_USER_PRINCIPAL_FORMAT = "Unsupported principal format in the authentication structure";
|
||||
|
||||
ConfigStore getConfigStore(String user, String serviceName);
|
||||
|
||||
ConfigSchemaService getConfigSchema(String user, String serviceName);
|
||||
|
||||
List<ConfigStore> getConfigStoreServices();
|
||||
|
||||
List<ConfigSchemaService> getConfigSchemaServices();
|
||||
|
||||
List<ConfigEditorService> getConfigEditorServices(String user);
|
||||
|
||||
Health checkConfigStoreServicesHealth();
|
||||
|
||||
Health checkConfigSchemaServicesHealth();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package uk.co.gresearch.nortem.configeditor.serviceaggregator;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
|
||||
import uk.co.gresearch.nortem.configeditor.common.*;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigStore;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ServiceAggregatorImpl implements ServiceAggregator {
|
||||
private static final String UNSUPPORTED_SERVICE_MSG = "Unsupported service %s";
|
||||
private static final String AUTHORISATION_MSG = "User %s is unauthorised to access the service %s";
|
||||
private final AuthorisationProvider authProvider;
|
||||
private final Map<String, ConfigStore> configStores;
|
||||
private final Map<String, ConfigSchemaService> configSchemaServices;
|
||||
|
||||
ServiceAggregatorImpl(Builder builder) {
|
||||
this.authProvider = builder.authProvider;
|
||||
this.configStores = builder.configStores;
|
||||
this.configSchemaServices = builder.configSchemaServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigStore getConfigStore(String user, String serviceName) {
|
||||
return getService(user, serviceName, configStores);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigSchemaService getConfigSchema(String user, String serviceName) {
|
||||
return getService(user, serviceName, configSchemaServices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConfigStore> getConfigStoreServices() {
|
||||
return new ArrayList<>(configStores.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConfigSchemaService> getConfigSchemaServices() {
|
||||
return new ArrayList<>(configSchemaServices.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConfigEditorService> getConfigEditorServices(String user) {
|
||||
List<ConfigEditorService> ret = new ArrayList<>();
|
||||
for (String serviceName : configSchemaServices.keySet()) {
|
||||
try {
|
||||
ConfigSchemaService current = getConfigSchema(user, serviceName);
|
||||
ConfigEditorService configEditorService = new ConfigEditorService();
|
||||
configEditorService.setName(serviceName);
|
||||
ret.add(configEditorService);
|
||||
} catch (AuthorisationException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health checkConfigStoreServicesHealth() {
|
||||
return checkServiceHealth(configStores);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health checkConfigSchemaServicesHealth() {
|
||||
return checkServiceHealth(configSchemaServices);
|
||||
}
|
||||
|
||||
private <T> T getService(String user, String serviceName, Map<String, T> serviceMap) {
|
||||
if (!serviceMap.containsKey(serviceName)) {
|
||||
throw new UnsupportedOperationException(String.format(UNSUPPORTED_SERVICE_MSG, serviceName));
|
||||
}
|
||||
|
||||
AuthorisationProvider.AuthorisationResult authResult = authProvider.getUserAuthorisation(user, serviceName);
|
||||
if (authResult == AuthorisationProvider.AuthorisationResult.FORBIDDEN) {
|
||||
throw new AuthorisationException(String.format(AUTHORISATION_MSG, user, serviceName));
|
||||
}
|
||||
return serviceMap.get(serviceName);
|
||||
}
|
||||
|
||||
private <T extends HealthCheckable> Health checkServiceHealth(Map<String, T> serviceMap) {
|
||||
for (String name : serviceMap.keySet()) {
|
||||
Health current = serviceMap.get(name).checkHealth();
|
||||
try {
|
||||
if (current.getStatus() != Status.UP) {
|
||||
return current;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
new Health.Builder().down(e).build();
|
||||
}
|
||||
}
|
||||
return new Health.Builder().up().build();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private static final String SERVICE_ALREADY_REGISTERED = "Service is already registered";
|
||||
private static final String NO_SERVICE_REGISTERED = "No services registered in aggregator";
|
||||
private final AuthorisationProvider authProvider;
|
||||
private final Map<String, ConfigStore> configStores = new HashMap<>();
|
||||
private final Map<String, ConfigSchemaService> configSchemaServices = new HashMap<>();
|
||||
|
||||
public Builder(AuthorisationProvider authProvider) {
|
||||
this.authProvider = authProvider;
|
||||
}
|
||||
|
||||
public Builder addService(String name, ConfigStore store, ConfigSchemaService schemaService) {
|
||||
if (configStores.containsKey(name)) {
|
||||
throw new IllegalArgumentException(SERVICE_ALREADY_REGISTERED);
|
||||
}
|
||||
configStores.put(name, store);
|
||||
configSchemaServices.put(name, schemaService);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServiceAggregator build() {
|
||||
if (configStores.isEmpty()) {
|
||||
throw new IllegalArgumentException(NO_SERVICE_REGISTERED);
|
||||
}
|
||||
return new ServiceAggregatorImpl(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ConfigStoreImplTest {
|
||||
private GitRepository gitRulesRepo;
|
||||
private GitRepository gitReleasesRepo;
|
||||
private ReleasePullRequestService pullRequestService;
|
||||
private ConfigInfoProvider ruleInfoProvider;
|
||||
private ConfigStoreImpl ruleStore;
|
||||
private Map<String, String> filesContent = new HashMap<>();
|
||||
private List<ConfigEditorFile> files;
|
||||
private ConfigEditorResult getFilesResult;
|
||||
private ConfigInfo ruleInfo = new ConfigInfo();
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException, GitAPIException {
|
||||
gitRulesRepo = Mockito.mock(GitRepository.class);
|
||||
gitReleasesRepo = Mockito.mock(GitRepository.class);
|
||||
pullRequestService = Mockito.mock(ReleasePullRequestService.class);
|
||||
ruleInfoProvider = Mockito.mock(ConfigInfoProvider.class);
|
||||
|
||||
when(ruleInfoProvider.getConfigInfo(any(), any())).thenReturn(ruleInfo);
|
||||
when(ruleInfoProvider.getReleaseInfo(any(), any())).thenReturn(ruleInfo);
|
||||
when(ruleInfoProvider.isReleaseFile(any())).thenReturn(true);
|
||||
when(ruleInfoProvider.isStoreFile(any())).thenReturn(true);
|
||||
when(ruleInfoProvider.getFileContentType()).thenReturn(ConfigEditorFile.ContentType.STRING);
|
||||
|
||||
filesContent.put("File.json", "DUMMY_CONTENT");
|
||||
files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("File.json",
|
||||
"DUMMY_CONTENT",
|
||||
ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setFiles(files);
|
||||
getFilesResult = new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
|
||||
when(gitRulesRepo.getFiles()).thenReturn(getFilesResult);
|
||||
when(gitReleasesRepo.getFiles()).thenReturn(getFilesResult);
|
||||
when(gitRulesRepo.transactCopyAndCommit(any())).thenReturn(getFilesResult);
|
||||
|
||||
ruleStore = new ConfigStoreImpl(gitRulesRepo,
|
||||
gitReleasesRepo,
|
||||
pullRequestService,
|
||||
ruleInfoProvider);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ruleStore.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void AddRuleOK() throws GitAPIException, IOException {
|
||||
ruleInfo.setOldVersion(0);
|
||||
ruleInfo.setFilesContent(new HashMap<>());
|
||||
ConfigEditorResult ret = ruleStore.addConfig("john", "NEW");
|
||||
verify(ruleInfoProvider).getConfigInfo("john", "NEW");
|
||||
verify(gitRulesRepo).transactCopyAndCommit(ruleInfo);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(1, ret.getAttributes().getFiles().size());
|
||||
Assert.assertEquals("File.json", ret.getAttributes().getFiles().get(0).getFileName());
|
||||
Assert.assertEquals("DUMMY_CONTENT", ret.getAttributes().getFiles().get(0).getContentValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void AddRuleNotNew() {
|
||||
ruleInfo.setOldVersion(1);
|
||||
ruleInfo.setFilesContent(new HashMap<>());
|
||||
ConfigEditorResult ret = ruleStore.addConfig("john", "NEW");
|
||||
verify(ruleInfoProvider).getConfigInfo("john", "NEW");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getMessage().contains("wrong version"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void AddRuleExisting() {
|
||||
ruleInfo.setOldVersion(0);
|
||||
ruleInfo.setFilesContent(filesContent);
|
||||
ConfigEditorResult ret = ruleStore.addConfig("john", "NEW");
|
||||
verify(ruleInfoProvider).getConfigInfo("john", "NEW");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getMessage().contains("already exists"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void UpdateRuleOK() throws GitAPIException, IOException {
|
||||
ruleInfo.setOldVersion(1);
|
||||
ruleInfo.setFilesContent(filesContent);
|
||||
ConfigEditorResult ret = ruleStore.updateConfig("john", "UPDATE");
|
||||
|
||||
verify(ruleInfoProvider).getConfigInfo("john", "UPDATE");
|
||||
verify(gitRulesRepo).transactCopyAndCommit(ruleInfo);
|
||||
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(1, ret.getAttributes().getFiles().size());
|
||||
Assert.assertEquals("File.json", ret.getAttributes().getFiles().get(0).getFileName());
|
||||
Assert.assertEquals("DUMMY_CONTENT", ret.getAttributes().getFiles().get(0).getContentValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void UpdateNew() {
|
||||
ruleInfo.setOldVersion(0);
|
||||
ruleInfo.setFilesContent(filesContent);
|
||||
ConfigEditorResult ret = ruleStore.updateConfig("john", "UPDATE");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getMessage().contains("wrong version"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void UpdateNotExist() {
|
||||
ruleInfo.setOldVersion(0);
|
||||
ruleInfo.setFilesContent(new HashMap<>());
|
||||
ConfigEditorResult ret = ruleStore.updateConfig("john", "NEW");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getMessage().contains("does not exist"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRules() {
|
||||
ConfigEditorResult ret = ruleStore.getConfigs();
|
||||
verify(ruleInfoProvider).isStoreFile("File.json");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(1, ret.getAttributes().getFiles().size());
|
||||
Assert.assertEquals("File.json", ret.getAttributes().getFiles().get(0).getFileName());
|
||||
Assert.assertEquals("DUMMY_CONTENT", ret.getAttributes().getFiles().get(0).getContentValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesFiltered() throws IOException, GitAPIException {
|
||||
when(ruleInfoProvider.isStoreFile(any())).thenReturn(false);
|
||||
ruleStore = new ConfigStoreImpl(gitRulesRepo,
|
||||
gitReleasesRepo,
|
||||
pullRequestService,
|
||||
ruleInfoProvider);
|
||||
ConfigEditorResult ret = ruleStore.getConfigs();
|
||||
verify(ruleInfoProvider, times(2)).isStoreFile("File.json");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesRelease() throws IOException, GitAPIException {
|
||||
when(ruleInfoProvider.getReleaseVersion(any())).thenReturn(1234);
|
||||
ConfigEditorResult ret = ruleStore.getConfigsRelease();
|
||||
verify(gitReleasesRepo).getFiles();
|
||||
verify(ruleInfoProvider).isReleaseFile("File.json");
|
||||
verify(ruleInfoProvider).getReleaseVersion(files);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(1, ret.getAttributes().getFiles().size());
|
||||
Assert.assertEquals("File.json", ret.getAttributes().getFiles().get(0).getFileName());
|
||||
Assert.assertEquals("DUMMY_CONTENT", ret.getAttributes().getFiles().get(0).getContentValue());
|
||||
Assert.assertEquals(1234, ret.getAttributes().getRulesVersion().intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesReleaseFiltered() throws IOException, GitAPIException {
|
||||
when(ruleInfoProvider.isReleaseFile(any())).thenReturn(false);
|
||||
ConfigEditorResult ret = ruleStore.getConfigsRelease();
|
||||
verify(gitReleasesRepo).getFiles();
|
||||
verify(ruleInfoProvider).isReleaseFile("File.json");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesReleaseStatusPending() throws IOException {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setPendingPullRequest(true);
|
||||
attr.setPullRequestUrl("DUMMY_URL");
|
||||
ConfigEditorResult pullRequestResult = new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
when(pullRequestService.pendingPullRequest()).thenReturn(pullRequestResult);
|
||||
ConfigEditorResult ret = ruleStore.getConfigsReleaseStatus();
|
||||
|
||||
verify(pullRequestService).pendingPullRequest();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getPendingPullRequest());
|
||||
Assert.assertEquals("DUMMY_URL", ret.getAttributes().getPullRequestUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesReleaseStatusNoPullRequest() throws IOException {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setPendingPullRequest(false);
|
||||
ConfigEditorResult pullRequestResult = new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
when(pullRequestService.pendingPullRequest()).thenReturn(pullRequestResult);
|
||||
|
||||
ConfigEditorResult ret = ruleStore.getConfigsReleaseStatus();
|
||||
|
||||
verify(pullRequestService).pendingPullRequest();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertFalse(ret.getAttributes().getPendingPullRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void submitRulesRelease() throws IOException, GitAPIException {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setPendingPullRequest(true);
|
||||
attr.setPullRequestUrl("DUMMY_URL");
|
||||
ConfigEditorResult pullRequestResult = new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
|
||||
attr.setPendingPullRequest(false);
|
||||
ConfigEditorResult pendingPullRequestResult = new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
|
||||
when(pullRequestService.createPullRequest(ruleInfo)).thenReturn(pullRequestResult);
|
||||
when(pullRequestService.pendingPullRequest()).thenReturn(pendingPullRequestResult);
|
||||
|
||||
ConfigEditorResult ret = ruleStore.submitConfigsRelease("test", "dummy_rules");
|
||||
|
||||
verify(ruleInfoProvider).getReleaseInfo("test", "dummy_rules");
|
||||
verify(gitReleasesRepo).transactCopyAndCommit(ruleInfo);
|
||||
verify(pullRequestService).createPullRequest(ruleInfo);
|
||||
verify(pullRequestService).pendingPullRequest();
|
||||
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals("DUMMY_URL", ret.getAttributes().getPullRequestUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void submitRulesReleasePending() throws IOException {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
attr.setPendingPullRequest(true);
|
||||
attr.setPullRequestUrl("DUMMY_URL");
|
||||
ConfigEditorResult pendingPullRequestResult = new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
when(pullRequestService.pendingPullRequest()).thenReturn(pendingPullRequestResult);
|
||||
|
||||
ConfigEditorResult ret = ruleStore.submitConfigsRelease("test", "dummy_rules");
|
||||
|
||||
verify(ruleInfoProvider).getReleaseInfo("test", "dummy_rules");
|
||||
verify(pullRequestService).pendingPullRequest();
|
||||
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getPendingPullRequest());
|
||||
Assert.assertEquals("DUMMY_URL", ret.getAttributes().getPullRequestUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRepositoriesTest() {
|
||||
when(gitRulesRepo.getRepoUri()).thenReturn("RULES_URI");
|
||||
when(gitReleasesRepo.getRepoUri()).thenReturn("RELEASE_URI");
|
||||
ConfigEditorResult ret = ruleStore.getRepositories();
|
||||
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
|
||||
Assert.assertNotNull(ret.getAttributes().getRulesRepositories());
|
||||
Assert.assertEquals("RULES_URI", ret.getAttributes()
|
||||
.getRulesRepositories().getRuleStoreUrl());
|
||||
Assert.assertEquals("RELEASE_URI",
|
||||
ret.getAttributes().getRulesRepositories().getRulesReleaseUrl());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package uk.co.gresearch.nortem.configeditor.configstore;
|
||||
|
||||
import org.adrianwalker.multilinestring.Multiline;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class JsonRuleConfigInfoProviderTest {
|
||||
/**
|
||||
* {
|
||||
* "rule_name": "info_provider_test",
|
||||
* "rule_author": "john",
|
||||
* "rule_version": 12345,
|
||||
* "rule_description": "Test rule",
|
||||
* "enrichments": { },
|
||||
* "actions": { }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String testRule;
|
||||
/**
|
||||
* {
|
||||
* "rule_name": "info_provider_test",
|
||||
* "rule_author": "john",
|
||||
* "rule_version": 0,
|
||||
* "rule_description": "Test rule",
|
||||
* "enrichments": { },
|
||||
* "actions": { }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String testNewRule;
|
||||
|
||||
/**
|
||||
* {
|
||||
* "rules_version" : 1,
|
||||
* "rules": [{
|
||||
* "rule_name": "info_provider_test",
|
||||
* "rule_author": "mark",
|
||||
* "rule_version": 12,
|
||||
* "rule_description": "Test rule",
|
||||
* "enrichments": { },
|
||||
* "actions": { }
|
||||
* }]
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String release;
|
||||
|
||||
/**
|
||||
* {
|
||||
* "rule_name": "../../../test",
|
||||
* "rule_author": "steve",
|
||||
* "rule_version": 12345,
|
||||
* "rule_description": "Test rule",
|
||||
* "enrichments": { },
|
||||
* "actions": { }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String maliciousRule;
|
||||
|
||||
public static String user = "steve@secret.net";
|
||||
private final ConfigInfoProvider infoProvider = JsonRuleConfigInfoProvider.create();
|
||||
|
||||
@Test
|
||||
public void RuleInfoTestChangeAuthor() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, testRule);
|
||||
Assert.assertEquals(12345, info.getOldVersion());
|
||||
Assert.assertEquals(12346, info.getVersion());
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals("Updating rule: info_provider_test to version: 12346", info.getCommitMessage());
|
||||
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals(user, info.getCommitterEmail());
|
||||
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("info_provider_test.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("info_provider_test.json").indexOf("\"rule_version\": 12346,") > 0);
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("info_provider_test.json").indexOf("\"rule_author\": \"steve\",") > 0);
|
||||
Assert.assertFalse(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RuleInfoTestUnchangedAuthor() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo("john@secret.net", testRule);
|
||||
Assert.assertEquals(info.getOldVersion(), 12345);
|
||||
Assert.assertEquals(info.getCommitter(), "john");
|
||||
Assert.assertEquals(info.getCommitMessage(), "Updating rule: info_provider_test to version: 12346");
|
||||
Assert.assertEquals(info.getCommitterEmail(), "john@secret.net");
|
||||
Assert.assertEquals(info.getFilesContent().size(), 1);
|
||||
Assert.assertEquals(info.getFilesContent().containsKey("info_provider_test.json"), true);
|
||||
Assert.assertEquals(info.getFilesContent()
|
||||
.get("info_provider_test.json").indexOf("\"rule_version\": 12346,") > 0, true);
|
||||
Assert.assertEquals(info.getFilesContent()
|
||||
.get("info_provider_test.json").indexOf("\"rule_author\": \"john\",") > 0, true);
|
||||
Assert.assertEquals(info.isNewConfig(), false);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RuleInfoNewRule() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, testNewRule);
|
||||
Assert.assertEquals(info.getOldVersion(), 0);
|
||||
Assert.assertEquals(info.getCommitter(), "steve");
|
||||
Assert.assertEquals(info.getCommitMessage(), "Adding new rule: info_provider_test");
|
||||
Assert.assertEquals(info.getCommitterEmail(), user);
|
||||
Assert.assertEquals(info.getFilesContent().size(), 1);
|
||||
Assert.assertEquals(info.getFilesContent().containsKey("info_provider_test.json"), true);
|
||||
Assert.assertEquals(info.getFilesContent()
|
||||
.get("info_provider_test.json").indexOf("\"rule_version\": 1,") > 0, true);
|
||||
Assert.assertEquals(info.isNewConfig(), true);
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void RuleInfoWrongJson() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user,"WRONG JSON");
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void RuleInfoWrongMissingMetadata() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, maliciousRule);
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void RuleInfoWrongUser() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo("INVALID", testRule);
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ReleaseInfoWrongUser() {
|
||||
ConfigInfo info = infoProvider.getReleaseInfo("INVALID", testRule);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ReleaseTest() {
|
||||
ConfigInfo info = infoProvider.getReleaseInfo("steve@secret.net", release);
|
||||
|
||||
Assert.assertEquals(info.getOldVersion(), 1);
|
||||
Assert.assertEquals(info.getVersion(), 2);
|
||||
Assert.assertEquals(info.getCommitter(), "steve");
|
||||
Assert.assertEquals(info.getCommitMessage(), "Rules released to version: 2");
|
||||
|
||||
Assert.assertEquals(info.getCommitter(), "steve");
|
||||
Assert.assertEquals(info.getCommitterEmail(), user);
|
||||
|
||||
Assert.assertEquals(info.getFilesContent().size(), 1);
|
||||
Assert.assertEquals(info.getFilesContent().containsKey("rules.json"), true);
|
||||
Assert.assertEquals(info.getFilesContent()
|
||||
.get("rules.json").indexOf("\"rules_version\": 2,") > 0, true);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void FilterRulesTest() {
|
||||
Assert.assertEquals(infoProvider.isReleaseFile("a.json"), false);
|
||||
Assert.assertEquals(infoProvider.isReleaseFile("rules.json"), true);
|
||||
Assert.assertEquals(infoProvider.isStoreFile("abc.json"), true);
|
||||
Assert.assertEquals(infoProvider.isStoreFile("json.txt"), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RulesVersionTest() {
|
||||
List<ConfigEditorFile> files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("rules.json", release, ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
int version = infoProvider.getReleaseVersion(files);
|
||||
Assert.assertEquals(version, 1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void RulesVersionTestMissingFile() {
|
||||
List<ConfigEditorFile> files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("a.json", release, ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
int version = infoProvider.getReleaseVersion(files);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void RulesVersionMissingVersion() {
|
||||
List<ConfigEditorFile> files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("rules.json", "{}", ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
int version = infoProvider.getReleaseVersion(files);
|
||||
}
|
||||
}
|
||||
69
config-editor/config-editor-services/pom.xml
Normal file
69
config-editor/config-editor-services/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
|
||||
<artifactId>config-editor-services</artifactId>
|
||||
<name>config-editor-services</name>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>config-editor</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-common</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>config-editor-core</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nikita-core</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-parsing-app</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>${mockito_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,174 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.centrifuge;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.type.MapType;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.common.utils.HttpProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigSchemaService;
|
||||
import uk.co.gresearch.nortem.configeditor.service.centrifuge.model.RulesWrapperDto;
|
||||
import uk.co.gresearch.nortem.configeditor.service.centrifuge.model.CentrifugeResponseDto;
|
||||
import uk.co.gresearch.nortem.configeditor.model.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult.StatusCode.OK;
|
||||
|
||||
public class CentrifugeRuleSchemaImpl implements ConfigSchemaService {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final String EMPTY_UI_CONFIG = "Empty UI config provided";
|
||||
|
||||
private final CentrifugeSchemaService centrifugeSchemaService;
|
||||
private final AtomicReference<Exception> exception = new AtomicReference<>();
|
||||
|
||||
CentrifugeRuleSchemaImpl(CentrifugeSchemaService centrifugeSchemaService) {
|
||||
this.centrifugeSchemaService = centrifugeSchemaService;
|
||||
}
|
||||
|
||||
public static ConfigSchemaService createCentrifugeRuleSchemaImpl(String centrifugeUrl,
|
||||
Optional<String> uiConfig) throws IOException {
|
||||
HttpProvider httpProvider = new HttpProvider(centrifugeUrl, HttpProvider::getKerberosHttpClient);
|
||||
if (!uiConfig.isPresent()) {
|
||||
throw new IllegalArgumentException(EMPTY_UI_CONFIG);
|
||||
}
|
||||
|
||||
CentrifugeSchemaService centrifugeSchemaService = new CentrifugeSchemaService
|
||||
.Builder(httpProvider, uiConfig.get())
|
||||
.build();
|
||||
|
||||
return new CentrifugeRuleSchemaImpl(centrifugeSchemaService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getSchema() {
|
||||
String schema = this.centrifugeSchemaService.getRulesSchema();
|
||||
ConfigEditorAttributes result = new ConfigEditorAttributes();
|
||||
result.setRulesSchema(schema);
|
||||
return new ConfigEditorResult(OK, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getFields() {
|
||||
ConfigEditorAttributes result = new ConfigEditorAttributes();
|
||||
result.setFields(centrifugeSchemaService.getFields());
|
||||
return new ConfigEditorResult(OK, result);
|
||||
}
|
||||
|
||||
private String wrapSingleRuleAsRules(String rule) throws IOException{
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
TypeFactory typeFactory = mapper.getTypeFactory();
|
||||
MapType mapType = typeFactory.constructMapType(LinkedHashMap.class, String.class, Object.class);
|
||||
Map<String, Object> ruleObj = mapper.readValue(rule, mapType);
|
||||
RulesWrapperDto wrapper = new RulesWrapperDto();
|
||||
wrapper.addToRules(ruleObj);
|
||||
|
||||
return mapper.writeValueAsString(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfiguration(String rule) {
|
||||
try{
|
||||
String ruleAsRules = wrapSingleRuleAsRules(rule);
|
||||
return validateConfigurations(ruleAsRules);
|
||||
} catch (IOException e){
|
||||
LOG.error(e.getMessage());
|
||||
ConfigEditorAttributes result = new ConfigEditorAttributes();
|
||||
result.setException(e.toString());
|
||||
result.setMessage(ExceptionUtils.getMessage(e));
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.BAD_REQUEST, result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfigurations(String rules) {
|
||||
try {
|
||||
ConfigEditorAttributes result = new ConfigEditorAttributes();
|
||||
CentrifugeResponseDto response = this.centrifugeSchemaService.validateRules(rules);
|
||||
ConfigEditorResult.StatusCode statusCode;
|
||||
switch(response.getStatusCode()) {
|
||||
case OK:
|
||||
statusCode = OK;
|
||||
exception.set(null);
|
||||
break;
|
||||
case BAD_REQUEST:
|
||||
statusCode = ConfigEditorResult.StatusCode.BAD_REQUEST;
|
||||
break;
|
||||
case ERROR:
|
||||
statusCode = ConfigEditorResult.StatusCode.ERROR;
|
||||
break;
|
||||
case UNAUTHORISED:
|
||||
statusCode = ConfigEditorResult.StatusCode.UNAUTHORISED;
|
||||
break;
|
||||
default:
|
||||
statusCode = ConfigEditorResult.StatusCode.ERROR;
|
||||
}
|
||||
result.setException(response.getAttributes().getException());
|
||||
result.setMessage(response.getAttributes().getMessage());
|
||||
|
||||
return new ConfigEditorResult(statusCode, result);
|
||||
} catch (IOException e) {
|
||||
LOG.error(ExceptionUtils.getStackTrace(e));
|
||||
exception.set(e);
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult testConfiguration(String rule, String event) {
|
||||
try{
|
||||
String ruleAsRules = wrapSingleRuleAsRules(rule);
|
||||
return testConfigurations(ruleAsRules, event);
|
||||
} catch (IOException e){
|
||||
LOG.error(e.getMessage());
|
||||
ConfigEditorAttributes result = new ConfigEditorAttributes();
|
||||
result.setException(e.toString());
|
||||
result.setMessage(ExceptionUtils.getMessage(e));
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.BAD_REQUEST, result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult testConfigurations(String rules, String event) {
|
||||
try {
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
CentrifugeResponseDto response = this.centrifugeSchemaService.testRules(rules, event);
|
||||
ConfigEditorResult.StatusCode statusCode = ConfigEditorResult.StatusCode.ERROR;
|
||||
switch(response.getStatusCode()) {
|
||||
case OK:
|
||||
exception.set(null);
|
||||
attributes.setTestResultOutput(response.getAttributes().getMessage());
|
||||
attributes.setTestResultComplete(true);
|
||||
return new ConfigEditorResult(OK, attributes);
|
||||
case BAD_REQUEST:
|
||||
statusCode = ConfigEditorResult.StatusCode.BAD_REQUEST;
|
||||
break;
|
||||
}
|
||||
|
||||
attributes.setException(response.getAttributes().getException());
|
||||
attributes.setMessage(response.getAttributes().getMessage());
|
||||
return new ConfigEditorResult(statusCode, attributes);
|
||||
} catch (IOException e) {
|
||||
LOG.error(ExceptionUtils.getStackTrace(e));
|
||||
exception.set(e);
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health checkHealth() {
|
||||
Exception current = exception.get();
|
||||
return current == null
|
||||
? Health.up().build()
|
||||
: Health.down().withException(current).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.centrifuge;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import uk.co.gresearch.nortem.common.utils.HttpProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.service.centrifuge.model.CentrifugeResponseDto;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigEditorUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.*;
|
||||
|
||||
class CentrifugeSchemaService {
|
||||
private static final String GET_SCHEMA_PATH = "/api/v1/rules/schema";
|
||||
private static final String VALIDATE_RULES_PATH = "/api/v1/rules/validate";
|
||||
private static final String TEST_RULES_PATH = "/api/v1/rules/test";
|
||||
private static final String FIELDS_PATH = "/api/v1/fields";
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
private final HttpProvider httpProvider;
|
||||
private final String rulesSchema;
|
||||
private final String centrifugeFields;
|
||||
|
||||
CentrifugeSchemaService(Builder builder) {
|
||||
this.httpProvider = builder.httpProvider;
|
||||
this.rulesSchema = builder.rulesSchema;
|
||||
this.centrifugeFields = builder.centrifugeFields;
|
||||
}
|
||||
|
||||
public String getRulesSchema() {
|
||||
return rulesSchema;
|
||||
}
|
||||
|
||||
public String getFields() {
|
||||
return centrifugeFields;
|
||||
}
|
||||
|
||||
public CentrifugeResponseDto validateRules(String rules) throws IOException {
|
||||
String json = this.httpProvider.post(VALIDATE_RULES_PATH, rules);
|
||||
return MAPPER.readValue(json, CentrifugeResponseDto.class);
|
||||
}
|
||||
|
||||
public CentrifugeResponseDto testRules(String rules, String event) throws IOException {
|
||||
CentrifugeResponseDto.Attributes attr = new CentrifugeResponseDto.Attributes();
|
||||
attr.setEvent(event);
|
||||
attr.setJsonRules(rules);
|
||||
|
||||
String body = MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
.writeValueAsString(attr);
|
||||
String json = this.httpProvider.post(TEST_RULES_PATH, body);
|
||||
return MAPPER.readValue(json, CentrifugeResponseDto.class);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final HttpProvider httpProvider;
|
||||
private final String uiConfig;
|
||||
private String rulesSchema;
|
||||
private String centrifugeFields;
|
||||
|
||||
public Builder(HttpProvider httpProvider, String uiConfig) {
|
||||
this.httpProvider = httpProvider;
|
||||
this.uiConfig = uiConfig;
|
||||
}
|
||||
|
||||
public CentrifugeSchemaService build() throws IOException {
|
||||
LOG.info("Obtaining and computing centrifuge schema");
|
||||
Optional<String> schema = getAndComputeSchema();
|
||||
if (!schema.isPresent()) {
|
||||
throw new IllegalStateException("Error during obtaining centrifuge schema");
|
||||
}
|
||||
|
||||
rulesSchema = schema.get();
|
||||
LOG.info("Computation of Centrifuge schema completed");
|
||||
|
||||
LOG.info("Obtaining centrifuge fields");
|
||||
Optional<String> fields = getFields();
|
||||
if (!fields.isPresent()) {
|
||||
throw new IllegalStateException("Error during obtaining centrifuge fields");
|
||||
}
|
||||
centrifugeFields = fields.get();
|
||||
LOG.info("Obtaining centrifuge fields completed");
|
||||
return new CentrifugeSchemaService(this);
|
||||
}
|
||||
|
||||
private Optional<String> getSchema() throws IOException {
|
||||
String responseBody = this.httpProvider.get(GET_SCHEMA_PATH);
|
||||
CentrifugeResponseDto response = MAPPER.readValue(responseBody, CentrifugeResponseDto.class);
|
||||
|
||||
if (response == null
|
||||
|| response.getStatusCode() != CentrifugeResponseDto.StatusCode.OK
|
||||
|| response.getAttributes() == null) {
|
||||
throw new IllegalStateException("Empty schema response");
|
||||
}
|
||||
|
||||
return Optional.ofNullable(MAPPER.writeValueAsString(response.getAttributes().getSchema()));
|
||||
}
|
||||
|
||||
private Optional<String> computeRulesSchema(String rulesSchema, String uiConfig) throws IOException {
|
||||
return ConfigEditorUtils.computeRulesSchema(rulesSchema, uiConfig);
|
||||
}
|
||||
|
||||
private Optional<String> getAndComputeSchema() throws IOException {
|
||||
Optional<String> schema = getSchema();
|
||||
if (!schema.isPresent()) {
|
||||
throw new IllegalStateException("unable to retrieve valid schema");
|
||||
}
|
||||
return computeRulesSchema(schema.get(), uiConfig);
|
||||
}
|
||||
|
||||
private Optional<String> getFields() throws IOException {
|
||||
String responseBody = httpProvider.get(FIELDS_PATH);
|
||||
CentrifugeResponseDto response = MAPPER.readValue(responseBody, CentrifugeResponseDto.class);
|
||||
if (response == null
|
||||
|| response.getStatusCode() != CentrifugeResponseDto.StatusCode.OK
|
||||
|| response.getAttributes() == null) {
|
||||
throw new IllegalStateException("Empty fields response");
|
||||
}
|
||||
|
||||
return Optional.ofNullable(MAPPER.writeValueAsString(response.getAttributes().getFields()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.centrifuge.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonRawValue;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class CentrifugeResponseDto {
|
||||
public static class Attributes {
|
||||
private String exception;
|
||||
private String message;
|
||||
@JsonProperty("json_rules")
|
||||
@JsonRawValue
|
||||
private String jsonRules;
|
||||
@JsonRawValue
|
||||
private String event;
|
||||
|
||||
@JsonProperty("rules_schema")
|
||||
private LinkedHashMap<String, Object> schema;
|
||||
|
||||
private List<LinkedHashMap<String, Object>> fields;
|
||||
|
||||
public String getException(){ return exception; }
|
||||
public String getMessage(){ return message; }
|
||||
public void setException(String exception){
|
||||
this.exception = exception;
|
||||
}
|
||||
public void setMessage(String message){
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public LinkedHashMap<String, Object> getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
public void setSchema(LinkedHashMap<String, Object> schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public List<LinkedHashMap<String, Object>> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(List<LinkedHashMap<String, Object>> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public String getJsonRules() {
|
||||
return jsonRules;
|
||||
}
|
||||
|
||||
public void setJsonRules(String jsonRules) {
|
||||
this.jsonRules = jsonRules;
|
||||
}
|
||||
|
||||
public String getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
public void setEvent(String event) {
|
||||
this.event = event;
|
||||
}
|
||||
}
|
||||
|
||||
public enum StatusCode {
|
||||
OK,
|
||||
ERROR,
|
||||
BAD_REQUEST,
|
||||
UNAUTHORISED,
|
||||
}
|
||||
|
||||
private StatusCode statusCode;
|
||||
private Attributes attributes = new Attributes();
|
||||
|
||||
public StatusCode getStatusCode() {return this.statusCode;}
|
||||
public Attributes getAttributes() {return this.attributes;}
|
||||
|
||||
public void setStatusCode(StatusCode statusCode){
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
public void setAttributes(Attributes attributes){
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.centrifuge.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RulesWrapperDto {
|
||||
@JsonProperty("rules_version")
|
||||
private int rulesVersion = 1;
|
||||
@JsonProperty("rules")
|
||||
private List<Object> rules = new ArrayList<>();
|
||||
|
||||
public void setRulesVersion(int rulesVersion) {
|
||||
this.rulesVersion = rulesVersion;
|
||||
}
|
||||
public void setRules(List<Object> rules){
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
public int getRulesVersion() {return this.rulesVersion;}
|
||||
public List<Object> getRules() {return this.rules;}
|
||||
public void addToRules(Object rule){
|
||||
this.rules.add(rule);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.elk;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import uk.co.gresearch.nortem.common.utils.HttpProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.model.TemplateField;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class ElkProvider {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final String EMPTY_MSG = "Empty template fields";
|
||||
private static final String MAPPINGS_FIELD = "mappings";
|
||||
private static final String PROPERTIES_FIELD = "properties";
|
||||
private static final String TEMPLATE_SUFFIX = "_doc";
|
||||
|
||||
private final HttpProvider httpClient;
|
||||
private final String templatePath;
|
||||
|
||||
public ElkProvider(HttpProvider httpClient, String templatePath) {
|
||||
this.httpClient = httpClient;
|
||||
this.templatePath = templatePath;
|
||||
}
|
||||
|
||||
private Optional<String> getSensorName(Iterator<String> it) {
|
||||
for (; it.hasNext(); ) {
|
||||
String current = it.next();
|
||||
if (current.endsWith(TEMPLATE_SUFFIX)
|
||||
&& current.length() > TEMPLATE_SUFFIX.length()) {
|
||||
return Optional.of(
|
||||
current.substring(0, current.length() - TEMPLATE_SUFFIX.length()));
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private List<TemplateField> getFields(JsonNode properties) {
|
||||
List<TemplateField> ret = new ArrayList<>();
|
||||
properties.fieldNames().forEachRemaining(x -> ret.add(new TemplateField(x)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Map<String, List<TemplateField>> getTemplateFields() throws IOException {
|
||||
Map<String, List<TemplateField>> ret = new HashMap<>();
|
||||
String response = httpClient.get(templatePath);
|
||||
LOG.info(String.format("Template to init:\n%s", response));
|
||||
JsonNode template = MAPPER.readTree(response);
|
||||
for (Iterator<JsonNode> it = template.iterator(); it.hasNext(); ) {
|
||||
JsonNode mappings = it.next().get(MAPPINGS_FIELD);
|
||||
if (mappings == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<String> sensorName = getSensorName(mappings.fieldNames());
|
||||
if (!sensorName.isPresent()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<TemplateField> fields = getFields(mappings.findValue(PROPERTIES_FIELD));
|
||||
if (fields.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
ret.put(sensorName.get(), fields);
|
||||
}
|
||||
if (ret.isEmpty()) {
|
||||
throw new IllegalStateException(EMPTY_MSG);
|
||||
}
|
||||
|
||||
LOG.info(String.format("Computed fields:\n%s", ret.toString()));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.elk;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
|
||||
public interface ElkService {
|
||||
|
||||
ConfigEditorResult getTemplateFields(String sensor);
|
||||
|
||||
ConfigEditorResult getTemplateFields();
|
||||
|
||||
ConfigEditorResult shutDown();
|
||||
|
||||
ConfigEditorResult awaitShutDown();
|
||||
|
||||
Health checkHealth();
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.elk;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import uk.co.gresearch.nortem.common.utils.HttpProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.SensorTemplateFields;
|
||||
import uk.co.gresearch.nortem.configeditor.model.TemplateField;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ElkServiceImpl implements ElkService {
|
||||
private static final String NO_FIELDS_FOR_SENSOR = "No fields available for the sensor";
|
||||
private static final int TEMPLATE_UPDATE_PERIOD_IN_SEC = 4 * 3600;
|
||||
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final ElkProvider elkProvider;
|
||||
private final AtomicReference<Map<String, List<TemplateField>>> cache = new AtomicReference<>();
|
||||
private final AtomicReference<Exception> exception = new AtomicReference<>();
|
||||
private final ScheduledThreadPoolExecutor executor;
|
||||
|
||||
public ElkServiceImpl(ElkProvider elkProvider,
|
||||
Map<String, List<TemplateField>> template,
|
||||
int updatePeriodInSec) {
|
||||
this.elkProvider = elkProvider;
|
||||
this.cache.set(template);
|
||||
executor = new ScheduledThreadPoolExecutor(1);
|
||||
executor.setRemoveOnCancelPolicy(true);
|
||||
executor.scheduleAtFixedRate(() -> updateCache(),
|
||||
updatePeriodInSec,
|
||||
updatePeriodInSec,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getTemplateFields(String sensor) {
|
||||
Map<String, List<TemplateField>> current = cache.get();
|
||||
|
||||
if (!current.containsKey(sensor)) {
|
||||
return ConfigEditorResult.fromMessage(
|
||||
ConfigEditorResult.StatusCode.BAD_REQUEST,
|
||||
NO_FIELDS_FOR_SENSOR);
|
||||
}
|
||||
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setTemplateFields(current.get(sensor));
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getTemplateFields() {
|
||||
Map<String, List<TemplateField>> current = cache.get();
|
||||
|
||||
List<SensorTemplateFields> sensorTemplateFields = current
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(x -> new SensorTemplateFields(x, current.get(x)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ConfigEditorAttributes attributes = new ConfigEditorAttributes();
|
||||
attributes.setSensorTemplateFields(sensorTemplateFields);
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attributes);
|
||||
}
|
||||
|
||||
private void updateCache() {
|
||||
try {
|
||||
LOG.info("Initiating updating elk fields cache");
|
||||
Map<String, List<TemplateField>> update = elkProvider.getTemplateFields();
|
||||
cache.set(update);
|
||||
exception.set(null);
|
||||
LOG.info("Updating elk fields cache completed");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Problem during obtaining template fields from elk with exception {}",
|
||||
ExceptionUtils.getStackTrace(e));
|
||||
exception.set(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult shutDown() {
|
||||
executor.shutdown();
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult awaitShutDown() {
|
||||
executor.shutdownNow();
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Health checkHealth() {
|
||||
Exception current = exception.get();
|
||||
return current == null
|
||||
? Health.up().build()
|
||||
: Health.down().withException(current).build();
|
||||
}
|
||||
|
||||
public static ElkService createElkServiceImpl(String elkUrl, String templatePath) throws IOException {
|
||||
LOG.info("Initialising Elk Service");
|
||||
HttpProvider httpProvider = new HttpProvider(elkUrl, HttpProvider::getKerberosHttpClient);
|
||||
|
||||
ElkProvider elkProvider = new ElkProvider(httpProvider, templatePath);
|
||||
Map<String, List<TemplateField>> fields = elkProvider.getTemplateFields();
|
||||
|
||||
ElkService ret = new ElkServiceImpl(elkProvider, fields, TEMPLATE_UPDATE_PERIOD_IN_SEC);
|
||||
LOG.info("Initialising Elk Service completed");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.nikita;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigEditorUtils;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigSchemaService;
|
||||
import uk.co.gresearch.nortem.nikita.common.NikitaResult;
|
||||
import uk.co.gresearch.nortem.nikita.compiler.NikitaCompiler;
|
||||
import uk.co.gresearch.nortem.nikita.compiler.NikitaCorrelationRulesCompiler;
|
||||
import uk.co.gresearch.nortem.nikita.compiler.NikitaRulesCompiler;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Optional;
|
||||
|
||||
public class NikitaRuleSchemaServiceImpl implements ConfigSchemaService {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private static final String SCHEMA_INIT_ERROR = "Error during computing rules schema";
|
||||
private static final String TESTING_ERROR = "Unexpected rule testing service result";
|
||||
private final NikitaCompiler nikitaCompiler;
|
||||
private final String schema;
|
||||
|
||||
NikitaRuleSchemaServiceImpl(NikitaCompiler nikitaCompiler, String schema) {
|
||||
this.nikitaCompiler = nikitaCompiler;
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getSchema() {
|
||||
return ConfigEditorResult.fromSchema(schema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfiguration(String rule) {
|
||||
NikitaResult nikitaResult = nikitaCompiler.validateRule(rule);
|
||||
return fromNikitaValidateResult(nikitaResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfigurations(String rules) {
|
||||
NikitaResult nikitaResult = nikitaCompiler.validateRules(rules);
|
||||
return fromNikitaValidateResult(nikitaResult);
|
||||
}
|
||||
|
||||
public static ConfigSchemaService createNikitaRuleSchema(Optional<String> uiConfig) throws Exception {
|
||||
LOG.info("Initialising nikita rule schema service");
|
||||
NikitaCompiler compiler = NikitaRulesCompiler.createNikitaRulesCompiler();
|
||||
NikitaResult schemaResult = compiler.getSchema();
|
||||
|
||||
if (schemaResult.getStatusCode() != NikitaResult.StatusCode.OK
|
||||
|| schemaResult.getAttributes().getRulesSchema() == null
|
||||
|| !uiConfig.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
Optional<String> computedSchema = ConfigEditorUtils
|
||||
.computeRulesSchema(schemaResult.getAttributes().getRulesSchema(), uiConfig.get());
|
||||
|
||||
if (!computedSchema.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
LOG.info("Initialising nikita rule schema service completed");
|
||||
return new NikitaRuleSchemaServiceImpl(compiler, computedSchema.get());
|
||||
}
|
||||
|
||||
public static ConfigSchemaService createNikitaCorrelationRuleSchema(
|
||||
Optional<String> uiConfig) throws Exception {
|
||||
LOG.info("Initialising nikita correlation rule schema service");
|
||||
NikitaCompiler compiler = NikitaCorrelationRulesCompiler.createNikitaCorrelationRulesCompiler();
|
||||
NikitaResult schemaResult = compiler.getSchema();
|
||||
|
||||
if (schemaResult.getStatusCode() != NikitaResult.StatusCode.OK
|
||||
|| schemaResult.getAttributes().getRulesSchema() == null
|
||||
|| !uiConfig.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
Optional<String> computedSchema = ConfigEditorUtils
|
||||
.computeRulesSchema(schemaResult.getAttributes().getRulesSchema(), uiConfig.get());
|
||||
|
||||
if (!computedSchema.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
LOG.info("Initialising nikita correlation rule schema service completed");
|
||||
return new NikitaRuleSchemaServiceImpl(compiler, computedSchema.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult testConfiguration(String rule, String event) {
|
||||
return fromNikitaTestResult(nikitaCompiler.testRule(rule, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult testConfigurations(String rule, String event) {
|
||||
return fromNikitaTestResult(nikitaCompiler.testRules(rule, event));
|
||||
}
|
||||
|
||||
private ConfigEditorResult fromNikitaValidateResult(NikitaResult nikitaResult) {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
ConfigEditorResult.StatusCode statusCode = nikitaResult.getStatusCode() == NikitaResult.StatusCode.OK
|
||||
? ConfigEditorResult.StatusCode.OK
|
||||
: ConfigEditorResult.StatusCode.ERROR;
|
||||
|
||||
attr.setMessage(nikitaResult.getAttributes().getMessage());
|
||||
attr.setException(nikitaResult.getAttributes().getException());
|
||||
|
||||
return new ConfigEditorResult(statusCode, attr);
|
||||
}
|
||||
|
||||
private ConfigEditorResult fromNikitaTestResult(NikitaResult nikitaResult) {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
if (nikitaResult.getStatusCode() != NikitaResult.StatusCode.OK) {
|
||||
attr.setMessage(nikitaResult.getAttributes().getMessage());
|
||||
attr.setException(nikitaResult.getAttributes().getException());
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.ERROR, attr);
|
||||
}
|
||||
|
||||
if (nikitaResult.getAttributes().getMessage() == null) {
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR,
|
||||
TESTING_ERROR);
|
||||
}
|
||||
|
||||
attr.setTestResultComplete(true);
|
||||
attr.setTestResultOutput(nikitaResult.getAttributes().getMessage());
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parserconfig;
|
||||
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigInfoProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.JsonConfigInfoProvider;
|
||||
|
||||
public class ParserConfigConfigInfoProvider {
|
||||
private static final String AUTHOR_FIELD = "parser_author";
|
||||
private static final String NAME_FIELD = "parser_name";
|
||||
private static final String VERSION_FIELD = "parser_version";
|
||||
private static final String RELEASE_VERSION_FIELD = "parsers_version";
|
||||
private static final String PARSERS_FILENAME = "parsers.json";
|
||||
|
||||
public static ConfigInfoProvider create() {
|
||||
return new JsonConfigInfoProvider.Builder()
|
||||
.configAuthorField(AUTHOR_FIELD)
|
||||
.configNameField(NAME_FIELD)
|
||||
.configsVersionField(RELEASE_VERSION_FIELD)
|
||||
.configVersionField(VERSION_FIELD)
|
||||
.useConfigWordingInGitMessages()
|
||||
.releaseFilename(PARSERS_FILENAME)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parserconfig;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigEditorUtils;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigSchemaService;
|
||||
import uk.co.gresearch.nortem.parsers.common.ParserResult;
|
||||
import uk.co.gresearch.nortem.parsers.factory.ParserFactory;
|
||||
import uk.co.gresearch.nortem.parsers.factory.ParserFactoryImpl;
|
||||
import uk.co.gresearch.nortem.parsers.factory.ParserFactoryResult;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ParserConfigSchemaServiceImpl implements ConfigSchemaService {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private static final ObjectWriter JSON_WRITER = new ObjectMapper()
|
||||
.writerFor(new TypeReference<List<Map<String, Object>>>() { })
|
||||
.with(SerializationFeature.INDENT_OUTPUT);
|
||||
private static final ObjectReader TEST_LOG_READER = new ObjectMapper()
|
||||
.readerFor(TestSpecificationDto.class);
|
||||
|
||||
private final ParserFactory parserFactory;
|
||||
private final String schema;
|
||||
|
||||
ParserConfigSchemaServiceImpl(ParserFactory parserFactory, String schema) {
|
||||
this.parserFactory = parserFactory;
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getSchema() {
|
||||
return ConfigEditorResult.fromSchema(schema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfiguration(String config) {
|
||||
ParserFactoryResult parserResult = parserFactory.validateConfiguration(config);
|
||||
return fromParserFactoryValidateResult(parserResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfigurations(String configs) {
|
||||
ParserFactoryResult parserResult = parserFactory.validateConfigurations(configs);
|
||||
return fromParserFactoryValidateResult(parserResult);
|
||||
}
|
||||
|
||||
public static ConfigSchemaService createParserConfigSchemaServiceImpl(Optional<String> uiConfig) throws Exception {
|
||||
LOG.info("Initialising parser config schema service");
|
||||
|
||||
ParserFactory parserFactory = ParserFactoryImpl.createParserFactory();
|
||||
ParserFactoryResult schemaResult = parserFactory.getSchema();
|
||||
|
||||
if (schemaResult.getStatusCode() != ParserFactoryResult.StatusCode.OK
|
||||
|| schemaResult.getAttributes().getJsonSchema() == null
|
||||
|| !uiConfig.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
Optional<String> computedSchema = ConfigEditorUtils
|
||||
.computeRulesSchema(schemaResult.getAttributes().getJsonSchema(), uiConfig.get());
|
||||
|
||||
if (!computedSchema.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
LOG.info("Initialising parser config schema service completed");
|
||||
return new ParserConfigSchemaServiceImpl(parserFactory, computedSchema.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult testConfiguration(String config, String event) {
|
||||
TestSpecificationDto test;
|
||||
try {
|
||||
test = TEST_LOG_READER.readValue(event);
|
||||
} catch (IOException e) {
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
ParserFactoryResult parserResult = parserFactory.test(config, test.getLog().getBytes());
|
||||
return fromParserFactoryTestResult(parserResult);
|
||||
}
|
||||
|
||||
private ConfigEditorResult fromParserFactoryValidateResult(ParserFactoryResult parserResult) {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
ConfigEditorResult.StatusCode statusCode = parserResult.getStatusCode() == ParserFactoryResult.StatusCode.OK
|
||||
? ConfigEditorResult.StatusCode.OK
|
||||
: ConfigEditorResult.StatusCode.ERROR;
|
||||
|
||||
attr.setMessage(parserResult.getAttributes().getMessage());
|
||||
return new ConfigEditorResult(statusCode, attr);
|
||||
}
|
||||
|
||||
private ConfigEditorResult fromParserFactoryTestResult(ParserFactoryResult parserFactoryResult) {
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
if (parserFactoryResult.getStatusCode() != ParserFactoryResult.StatusCode.OK
|
||||
|| parserFactoryResult.getAttributes().getParserResult() == null) {
|
||||
attr.setMessage(parserFactoryResult.getAttributes().getMessage());
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.ERROR, attr);
|
||||
}
|
||||
|
||||
ParserResult result = parserFactoryResult.getAttributes().getParserResult();
|
||||
if (result.getException() != null) {
|
||||
return ConfigEditorResult.fromMessage(ConfigEditorResult.StatusCode.ERROR,
|
||||
ExceptionUtils.getStackTrace(result.getException()));
|
||||
}
|
||||
|
||||
attr.setTestResultComplete(true);
|
||||
try {
|
||||
String output = JSON_WRITER.writeValueAsString(result.getParsedMessages());
|
||||
attr.setTestResultOutput(output);
|
||||
} catch (JsonProcessingException e) {
|
||||
return ConfigEditorResult.fromException(e);
|
||||
}
|
||||
|
||||
return new ConfigEditorResult(ConfigEditorResult.StatusCode.OK, attr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parserconfig;
|
||||
|
||||
public class TestSpecificationDto {
|
||||
private String log;
|
||||
|
||||
public String getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public void setLog(String log) {
|
||||
this.log = log;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parsingapp;
|
||||
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigInfoProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.JsonConfigInfoProvider;
|
||||
|
||||
public class ParsingAppConfigInfoProvider {
|
||||
private static final String AUTHOR_FIELD = "parsing_app_author";
|
||||
private static final String NAME_FIELD = "parsing_app_name";
|
||||
private static final String VERSION_FIELD = "parsing_app_version";
|
||||
private static final String RELEASE_VERSION_FIELD = "parsing_applications_version";
|
||||
private static final String PARSERS_FILENAME = "parsing_applications.json";
|
||||
|
||||
public static ConfigInfoProvider create() {
|
||||
return new JsonConfigInfoProvider.Builder()
|
||||
.configAuthorField(AUTHOR_FIELD)
|
||||
.configNameField(NAME_FIELD)
|
||||
.configsVersionField(RELEASE_VERSION_FIELD)
|
||||
.configVersionField(VERSION_FIELD)
|
||||
.useConfigWordingInGitMessages()
|
||||
.releaseFilename(PARSERS_FILENAME)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parsingapp;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorAttributes;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigEditorUtils;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigSchemaService;
|
||||
import uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactory;
|
||||
import uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactoryImpl;
|
||||
import uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactoryResult;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult.StatusCode.ERROR;
|
||||
import static uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult.StatusCode.OK;
|
||||
|
||||
public class ParsingAppConfigSchemaServiceImpl implements ConfigSchemaService {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
private final ParsingApplicationFactory factory;
|
||||
private final String schema;
|
||||
|
||||
ParsingAppConfigSchemaServiceImpl(ParsingApplicationFactory factory, String schema) {
|
||||
this.factory = factory;
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult getSchema() {
|
||||
return ConfigEditorResult.fromSchema(schema);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfiguration(String configs) {
|
||||
return validate(configs, x -> factory.validateConfiguration(x));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEditorResult validateConfigurations(String configs) {
|
||||
return validate(configs, x -> factory.validateConfigurations(x));
|
||||
}
|
||||
|
||||
private ConfigEditorResult validate(String config, Function<String, ParsingApplicationFactoryResult> fun) {
|
||||
ParsingApplicationFactoryResult factoryResult = fun.apply(config);
|
||||
|
||||
ConfigEditorAttributes attr = new ConfigEditorAttributes();
|
||||
if (factoryResult.getStatusCode() == ParsingApplicationFactoryResult.StatusCode.ERROR) {
|
||||
attr.setMessage(factoryResult.getAttributes().getMessage());
|
||||
}
|
||||
|
||||
ConfigEditorResult.StatusCode statusCode =
|
||||
factoryResult.getStatusCode() == ParsingApplicationFactoryResult.StatusCode.OK
|
||||
? OK
|
||||
: ERROR;
|
||||
|
||||
return new ConfigEditorResult(statusCode, attr);
|
||||
}
|
||||
|
||||
public static ParsingAppConfigSchemaServiceImpl createParserConfigSchemaServiceImpl(
|
||||
Optional<String> uiConfig) throws Exception {
|
||||
LOG.info("Initialising parsing app config schema service");
|
||||
|
||||
ParsingApplicationFactory factory = new ParsingApplicationFactoryImpl();
|
||||
ParsingApplicationFactoryResult schemaResult = factory.getSchema();
|
||||
|
||||
if (schemaResult.getStatusCode() != ParsingApplicationFactoryResult.StatusCode.OK
|
||||
|| schemaResult.getAttributes().getJsonSchema() == null
|
||||
|| !uiConfig.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
Optional<String> computedSchema = ConfigEditorUtils
|
||||
.computeRulesSchema(schemaResult.getAttributes().getJsonSchema(), uiConfig.get());
|
||||
|
||||
if (!computedSchema.isPresent()) {
|
||||
LOG.error(SCHEMA_INIT_ERROR);
|
||||
throw new IllegalStateException(SCHEMA_INIT_ERROR);
|
||||
}
|
||||
|
||||
LOG.info("Initialising parsing app schema service completed");
|
||||
return new ParsingAppConfigSchemaServiceImpl(factory, computedSchema.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.centrifuge;
|
||||
|
||||
import org.adrianwalker.multilinestring.Multiline;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import uk.co.gresearch.nortem.common.utils.HttpProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigEditorUtils;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import uk.co.gresearch.nortem.configeditor.service.centrifuge.model.CentrifugeResponseDto;
|
||||
|
||||
import java.io.*;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
|
||||
|
||||
public class CentrifugeSchemaServiceTest {
|
||||
private HttpProvider mockHttp;
|
||||
private CentrifugeSchemaService centrifugeSchemaService;
|
||||
private String rulesSchemaResponse;
|
||||
private String fieldsResponse;
|
||||
private String uiConfigTest;
|
||||
|
||||
/**
|
||||
{
|
||||
"statusCode": "BAD_REQUEST",
|
||||
"attributes": {
|
||||
"exception": "com.fasterxml.jackson.core.JsonParseException: Unexpected character ..."
|
||||
}
|
||||
}
|
||||
*
|
||||
**/
|
||||
@Multiline
|
||||
private static String validateBadRequest;
|
||||
|
||||
/**
|
||||
{
|
||||
"statusCode": "OK"
|
||||
}
|
||||
*
|
||||
**/
|
||||
@Multiline
|
||||
private static String validateOK;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
mockHttp = Mockito.mock(HttpProvider.class);
|
||||
rulesSchemaResponse = ConfigEditorUtils.readTextFromResources("testSchema.json").get();
|
||||
fieldsResponse = ConfigEditorUtils.readTextFromResources("fieldsResponse.json").get();
|
||||
uiConfigTest = ConfigEditorUtils.readTextFromResources("uiConfigTest.json").get();
|
||||
Mockito.when(mockHttp.get("/api/v1/rules/schema")).thenReturn(rulesSchemaResponse);
|
||||
Mockito.when(mockHttp.get("/api/v1/fields")).thenReturn(fieldsResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceBuildOK() throws IOException {
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
Assert.assertNotNull(centrifugeSchemaService.getFields());
|
||||
Assert.assertNotNull(centrifugeSchemaService.getRulesSchema());
|
||||
verify(mockHttp, times(1)).get("/api/v1/rules/schema");
|
||||
verify(mockHttp, times(1)).get("/api/v1/fields");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonExistentFileReturnsDefault() {
|
||||
String defaultLayout = ConfigEditorUtils.readUiLayoutFile("INVALID").get();
|
||||
Assert.assertEquals("{\"layout\": {}}", defaultLayout);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void serviceExceptionRuleSchema() throws IOException {
|
||||
Mockito.when(mockHttp.get("/api/v1/rules/schema")).thenThrow(new IOException());
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void serviceWrongRuleSchema() throws IOException {
|
||||
Mockito.when(mockHttp.get("/api/v1/rules/schema")).thenReturn("INVALID JSON");
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void serviceEmptyRuleSchema2() throws IOException {
|
||||
Mockito.when(mockHttp.get("/api/v1/rules/schema")).thenReturn("{}");
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void serviceExceptionFields() throws IOException {
|
||||
Mockito.when(mockHttp.get("/api/v1/fields")).thenThrow(new IOException());
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void serviceWrongFields() throws IOException {
|
||||
Mockito.when(mockHttp.get("/api/v1/fields")).thenReturn("INVALID JSON");
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void serviceEmptyFields() throws IOException {
|
||||
Mockito.when(mockHttp.get("/api/v1/fields")).thenReturn("{}");
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test(expected = com.fasterxml.jackson.core.JsonParseException.class)
|
||||
public void wrongUIConfig() throws IOException {
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, "INVALID")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRuleOK() throws IOException {
|
||||
Mockito.when(mockHttp.post("/api/v1/rules/validate", "DUMMY")).thenReturn(validateOK);
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
CentrifugeResponseDto response = centrifugeSchemaService.validateRules("DUMMY");
|
||||
Assert.assertEquals(CentrifugeResponseDto.StatusCode.OK, response.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRuleBad() throws IOException {
|
||||
Mockito.when(mockHttp.post("/api/v1/rules/validate", "DUMMY")).thenReturn(validateBadRequest);
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
CentrifugeResponseDto response = centrifugeSchemaService.validateRules("DUMMY");
|
||||
Assert.assertEquals(CentrifugeResponseDto.StatusCode.BAD_REQUEST, response.getStatusCode());
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void validateRuleException() throws IOException {
|
||||
Mockito.when(mockHttp.post("/api/v1/rules/validate", "DUMMY")).thenThrow(new IOException());
|
||||
centrifugeSchemaService = new CentrifugeSchemaService.Builder(mockHttp, uiConfigTest)
|
||||
.build();
|
||||
centrifugeSchemaService.validateRules("DUMMY");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.centrifuge;
|
||||
|
||||
import org.adrianwalker.multilinestring.Multiline;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.configeditor.service.centrifuge.model.CentrifugeResponseDto;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
import static uk.co.gresearch.nortem.configeditor.service.centrifuge.model.CentrifugeResponseDto.StatusCode.ERROR;
|
||||
import static uk.co.gresearch.nortem.configeditor.service.centrifuge.model.CentrifugeResponseDto.StatusCode.OK;
|
||||
|
||||
public class RuleCentrifugeSchemaServiceImplTest {
|
||||
private CentrifugeSchemaService service;
|
||||
|
||||
/**
|
||||
*{"rule_name": "Walle_heartbeat","rule_author": "mariann","rule_version": 1,"rule_description": "A Rule for implementing health check.","conditions": [{"field_name": "ava:heartbeat","field_pattern": "true"}],"enrichments": {},"actions": {"elk_store": false,"heartbeat": true}}
|
||||
*/
|
||||
@Multiline
|
||||
private static String ruleJson;
|
||||
|
||||
/**
|
||||
*{"rules_version":1,"rules":[{"rule_name":"Walle_heartbeat","rule_author":"mariann","rule_version":1,"rule_description":"A Rule for implementing health check.","conditions":[{"field_name":"ava:heartbeat","field_pattern":"true"}],"enrichments":{},"actions":{"elk_store":false,"heartbeat":true}}]}*/
|
||||
@Multiline
|
||||
private static String expectedWrappedRuleJson;
|
||||
|
||||
private CentrifugeRuleSchemaImpl schemaServiceImpl;
|
||||
private CentrifugeResponseDto response;
|
||||
|
||||
@Before
|
||||
public void Setup() {
|
||||
service = Mockito.mock(CentrifugeSchemaService.class);
|
||||
this.schemaServiceImpl = new CentrifugeRuleSchemaImpl(service);
|
||||
response = new CentrifugeResponseDto();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesSchemaOK() {
|
||||
Mockito.when(service.getRulesSchema()).thenReturn("DUMMY");
|
||||
ConfigEditorResult ret = schemaServiceImpl.getSchema();
|
||||
verify(service, times(1)).getRulesSchema();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals("DUMMY", ret.getAttributes().getRulesSchema());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFieldsOK() {
|
||||
Mockito.when(service.getFields()).thenReturn("DUMMY");
|
||||
ConfigEditorResult ret = schemaServiceImpl.getFields();
|
||||
verify(service, times(1)).getFields();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals("DUMMY", ret.getAttributes().getFields());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRulesOK() throws IOException {
|
||||
Mockito.when(service.validateRules("DUMMY")).thenReturn(response);
|
||||
response.setStatusCode(OK);
|
||||
ConfigEditorResult ret = schemaServiceImpl.validateConfigurations("DUMMY");
|
||||
verify(service, times(1)).validateRules("DUMMY");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRulesBad() throws IOException {
|
||||
Mockito.when(service.validateRules("DUMMY")).thenReturn(response);
|
||||
response.setStatusCode(ERROR);
|
||||
response.getAttributes().setMessage("MESSAGE");
|
||||
response.getAttributes().setException("EXCEPTION");
|
||||
ConfigEditorResult ret = schemaServiceImpl.validateConfigurations("DUMMY");
|
||||
verify(service, times(1)).validateRules("DUMMY");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("MESSAGE", ret.getAttributes().getMessage() );
|
||||
Assert.assertEquals("EXCEPTION", ret.getAttributes().getException());
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRulesException() throws IOException {
|
||||
Mockito.when(service.validateRules("DUMMY")).thenThrow(new IOException());
|
||||
ConfigEditorResult ret = schemaServiceImpl.validateConfigurations("DUMMY");
|
||||
verify(service, times(1)).validateRules("DUMMY");
|
||||
Assert.assertEquals( ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getException().contains("java.io.IOException"));
|
||||
Assert.assertEquals(Status.DOWN, schemaServiceImpl.checkHealth().getStatus());
|
||||
|
||||
response.setStatusCode(OK);
|
||||
Mockito.when(service.validateRules("DUMMY2")).thenReturn(response);
|
||||
ret = schemaServiceImpl.validateConfigurations("DUMMY2");
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRule() throws IOException {
|
||||
response.setStatusCode(OK);
|
||||
Mockito.when(service.validateRules(anyString())).thenReturn(response);
|
||||
ConfigEditorResult ret = schemaServiceImpl.validateConfiguration(ruleJson);
|
||||
|
||||
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
|
||||
verify(service).validateRules(argument.capture());
|
||||
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
Assert.assertEquals(expectedWrappedRuleJson, argument.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRulesOK() throws IOException {
|
||||
Mockito.when(service.testRules("DUMMY_RULES", "DUMMY_EVENT")).thenReturn(response);
|
||||
response.setStatusCode(OK);
|
||||
response.getAttributes().setMessage("DUMMY_RESULT");
|
||||
ConfigEditorResult ret = schemaServiceImpl.testConfigurations("DUMMY_RULES", "DUMMY_EVENT");
|
||||
verify(service, times(1)).testRules("DUMMY_RULES", "DUMMY_EVENT");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getTestResultComplete());
|
||||
Assert.assertEquals("DUMMY_RESULT", ret.getAttributes().getTestResultOutput());
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRulesBad() throws IOException {
|
||||
Mockito.when(service.testRules("DUMMY_RULES", "DUMMY_EVENT")).thenReturn(response);
|
||||
response.setStatusCode(ERROR);
|
||||
response.getAttributes().setMessage("MESSAGE");
|
||||
response.getAttributes().setException("EXCEPTION");
|
||||
ConfigEditorResult ret = schemaServiceImpl.testConfigurations("DUMMY_RULES", "DUMMY_EVENT");
|
||||
verify(service, times(1)).testRules("DUMMY_RULES", "DUMMY_EVENT");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("MESSAGE", ret.getAttributes().getMessage());
|
||||
Assert.assertEquals("EXCEPTION", ret.getAttributes().getException());
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRulesException() throws IOException {
|
||||
Mockito.when(service.testRules("DUMMY_RULES", "DUMMY_EVENT"))
|
||||
.thenThrow(new IOException());
|
||||
ConfigEditorResult ret = schemaServiceImpl.testConfigurations("DUMMY_RULES", "DUMMY_EVENT");
|
||||
verify(service, times(1)).testRules("DUMMY_RULES", "DUMMY_EVENT");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getException().contains("java.io.IOException"));
|
||||
Assert.assertEquals(Status.DOWN, schemaServiceImpl.checkHealth().getStatus());
|
||||
|
||||
response.setStatusCode(OK);
|
||||
Mockito.when(service.testRules("DUMMY_RULES_2", "DUMMY_EVENT")).thenReturn(response);
|
||||
ret = schemaServiceImpl.testConfigurations("DUMMY_RULES_2", "DUMMY_EVENT");
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRule() throws IOException {
|
||||
response.setStatusCode(OK);
|
||||
Mockito.when(service.testRules(anyString(), anyString())).thenReturn(response);
|
||||
ConfigEditorResult ret = schemaServiceImpl.testConfiguration(ruleJson, "{}");
|
||||
|
||||
ArgumentCaptor<String> argument1 = ArgumentCaptor.forClass(String.class);
|
||||
ArgumentCaptor<String> argument2= ArgumentCaptor.forClass(String.class);
|
||||
verify(service).testRules(argument1.capture(), argument2.capture());
|
||||
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(Status.UP, schemaServiceImpl.checkHealth().getStatus());
|
||||
Assert.assertEquals(expectedWrappedRuleJson, argument1.getValue());
|
||||
Assert.assertEquals("{}", argument2.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuleBad() {
|
||||
ConfigEditorResult ret = schemaServiceImpl.testConfiguration("INVALID", "{}");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getException().contains("JsonParseException"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRuleBad() {
|
||||
ConfigEditorResult ret = schemaServiceImpl.validateConfiguration("INVALID");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getException().contains("JsonParseException"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.elk;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import uk.co.gresearch.nortem.common.utils.HttpProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.common.ConfigEditorUtils;
|
||||
import uk.co.gresearch.nortem.configeditor.model.TemplateField;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
|
||||
public class ElkProviderTest {
|
||||
private HttpProvider mockHttp;
|
||||
private String templateResponse;
|
||||
private ElkProvider provider;
|
||||
private String templatePath = "dummy_path";
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
mockHttp = Mockito.mock(HttpProvider.class);
|
||||
templateResponse = ConfigEditorUtils.readTextFromResources("getTemplateResponse.json").get();
|
||||
Mockito.when(mockHttp.get(templatePath)).thenReturn(templateResponse);
|
||||
provider = new ElkProvider(mockHttp, templatePath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTemplates() throws IOException {
|
||||
Map<String, List<TemplateField>> ret = provider.getTemplateFields();
|
||||
verify(mockHttp, times(1)).get(templatePath);
|
||||
Assert.assertEquals(2, ret.size());
|
||||
Assert.assertEquals(6, ret.get("secretlogs").size());
|
||||
Assert.assertEquals(4, ret.get("plaintext").size());
|
||||
Assert.assertEquals("security:category", ret.get("secretlogs").get(0).getName());
|
||||
Assert.assertEquals("security:level", ret.get("secretlogs").get(1).getName());
|
||||
Assert.assertEquals("ip_src_addr", ret.get("secretlogs").get(2).getName());
|
||||
Assert.assertEquals("ip_dst_addr", ret.get("secretlogs").get(3).getName());
|
||||
Assert.assertEquals("ip_dst_port", ret.get("secretlogs").get(4).getName());
|
||||
Assert.assertEquals("ip_src_port", ret.get("secretlogs").get(5).getName());
|
||||
|
||||
Assert.assertEquals("dlp:category", ret.get("plaintext").get(0).getName());
|
||||
Assert.assertEquals("dlp:level", ret.get("plaintext").get(1).getName());
|
||||
Assert.assertEquals("ip_src_addr", ret.get("plaintext").get(2).getName());
|
||||
Assert.assertEquals("ip_dst_port", ret.get("plaintext").get(3).getName());
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void getTemplatesHttpProviderException() throws IOException {
|
||||
Mockito.when(mockHttp.get(templatePath)).thenThrow(new IOException());
|
||||
provider.getTemplateFields();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void getTemplatesWrongJson() throws IOException {
|
||||
Mockito.when(mockHttp.get(templatePath)).thenReturn("INVALID");
|
||||
provider.getTemplateFields();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void getTemplatesEmptyJson() throws IOException {
|
||||
Mockito.when(mockHttp.get(templatePath)).thenReturn("{}");
|
||||
provider.getTemplateFields();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.elk;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.configeditor.model.SensorTemplateFields;
|
||||
import uk.co.gresearch.nortem.configeditor.model.TemplateField;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ElkServiceImplTest {
|
||||
private ElkProvider elkProvider;
|
||||
private ElkServiceImpl elkService;
|
||||
private final List<String> dummyFieldNames = Arrays.asList("a", "b", "c");
|
||||
private final List<String> updatedFieldNames = Arrays.asList("d");
|
||||
private final String sensorName = "secret";
|
||||
private Map<String, List<TemplateField>> template;
|
||||
private Map<String, List<TemplateField>> updateTemplate;
|
||||
|
||||
@Before
|
||||
public void Setup() throws IOException {
|
||||
elkProvider = Mockito.mock(ElkProvider.class);
|
||||
template = new HashMap<>();
|
||||
template.put(sensorName,
|
||||
dummyFieldNames.stream().map(x -> new TemplateField(x)).collect(Collectors.toList()));
|
||||
|
||||
updateTemplate = new HashMap<>();
|
||||
updateTemplate.put(sensorName,
|
||||
updatedFieldNames.stream().map(x -> new TemplateField(x)).collect(Collectors.toList()));
|
||||
|
||||
Mockito.when(elkProvider.getTemplateFields()).thenReturn(updateTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTemplateFieldsOK() throws IOException {
|
||||
elkService = new ElkServiceImpl(elkProvider, template, 1000);
|
||||
ConfigEditorResult ret = elkService.getTemplateFields();
|
||||
Assert.assertEquals( ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
List<SensorTemplateFields> sensorFields = ret.getAttributes().getSensorTemplateFields();
|
||||
Assert.assertEquals(1, sensorFields.size());
|
||||
Assert.assertEquals("secret", sensorFields.get(0).getSensorName());
|
||||
Assert.assertEquals(3, sensorFields.get(0).getFields().size());
|
||||
Assert.assertEquals("a", sensorFields.get(0).getFields().get(0).getName());
|
||||
Assert.assertEquals("b", sensorFields.get(0).getFields().get(1).getName());
|
||||
Assert.assertEquals("c", sensorFields.get(0).getFields().get(2).getName());
|
||||
elkService.shutDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSensorTemplateFieldsNotExisted() throws IOException {
|
||||
elkService = new ElkServiceImpl(elkProvider, template, 1000);
|
||||
ConfigEditorResult ret = elkService.getTemplateFields("UNKNOWN");
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.BAD_REQUEST, ret.getStatusCode());
|
||||
elkService.shutDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSensorTemplateFieldOK() throws IOException {
|
||||
elkService = new ElkServiceImpl(elkProvider, template, 1000);
|
||||
ConfigEditorResult ret = elkService.getTemplateFields(sensorName);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
List<TemplateField> fields = ret.getAttributes().getTemplateFields();
|
||||
Assert.assertEquals(3, fields.size());
|
||||
Assert.assertEquals("a", fields.get(0).getName());
|
||||
Assert.assertEquals("b", fields.get(1).getName());
|
||||
Assert.assertEquals("c", fields.get(2).getName());
|
||||
elkService.shutDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateOK() throws IOException, InterruptedException {
|
||||
elkService = new ElkServiceImpl(elkProvider, template, 1);
|
||||
Thread.sleep(3000);
|
||||
|
||||
ConfigEditorResult ret = elkService.getTemplateFields();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
List<SensorTemplateFields> sensorFields = ret.getAttributes().getSensorTemplateFields();
|
||||
Assert.assertEquals(1, sensorFields.size());
|
||||
Assert.assertEquals("secret", sensorFields.get(0).getSensorName());
|
||||
Assert.assertEquals(1, sensorFields.get(0).getFields().size());
|
||||
Assert.assertEquals("d", sensorFields.get(0).getFields().get(0).getName());
|
||||
|
||||
ret = elkService.getTemplateFields(sensorName);
|
||||
List<TemplateField> fields = ret.getAttributes().getTemplateFields();
|
||||
Assert.assertEquals(1, fields.size());
|
||||
Assert.assertEquals("d", fields.get(0).getName());
|
||||
elkService.shutDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void healthCheck() throws IOException, InterruptedException, ExecutionException {
|
||||
elkService = new ElkServiceImpl(elkProvider, template, 1);
|
||||
Health health = elkService.checkHealth();
|
||||
Assert.assertEquals( Status.UP, health.getStatus());
|
||||
|
||||
Mockito.when(elkProvider.getTemplateFields())
|
||||
.thenThrow(new IOException())
|
||||
.thenThrow(new IOException())
|
||||
.thenReturn(updateTemplate);
|
||||
Thread.sleep(1500);
|
||||
health = elkService.checkHealth();
|
||||
Assert.assertEquals( Status.DOWN, health.getStatus());
|
||||
Thread.sleep(3000);
|
||||
|
||||
health = elkService.checkHealth();
|
||||
Assert.assertEquals(Status.UP, health.getStatus());
|
||||
|
||||
elkService.shutDown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.nikita;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.nikita.common.NikitaAttributes;
|
||||
import uk.co.gresearch.nortem.nikita.common.NikitaResult;
|
||||
import uk.co.gresearch.nortem.nikita.compiler.NikitaCompiler;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
|
||||
|
||||
public class NikitaRuleSchemaServiceImplTest {
|
||||
private NikitaRuleSchemaServiceImpl nikitaRuleSchemaService;
|
||||
private final String ruleSchema = "dummmy schema";
|
||||
private final String testRule = "dummmy rule";
|
||||
private final String testRules = "dummmy rules";
|
||||
private final String testEvent = "dummy event";
|
||||
private final String testResultOutput = "test output";
|
||||
private NikitaCompiler nikitaCompiler;
|
||||
private NikitaResult nikitaResult;
|
||||
private NikitaAttributes nikitaAttributes;
|
||||
|
||||
@Before
|
||||
public void Setup() {
|
||||
nikitaCompiler = Mockito.mock(NikitaCompiler.class);
|
||||
this.nikitaRuleSchemaService = new NikitaRuleSchemaServiceImpl(nikitaCompiler, ruleSchema);
|
||||
nikitaAttributes = new NikitaAttributes();
|
||||
nikitaResult = new NikitaResult(NikitaResult.StatusCode.OK, nikitaAttributes);
|
||||
Mockito.when(nikitaCompiler.validateRules(any())).thenReturn(nikitaResult);
|
||||
Mockito.when(nikitaCompiler.validateRule(any())).thenReturn(nikitaResult);
|
||||
Mockito.when(nikitaCompiler.testRule(testRule, testEvent)).thenReturn(nikitaResult);
|
||||
Mockito.when(nikitaCompiler.testRule(testRules, testEvent)).thenReturn(nikitaResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRulesSchemaOK() {
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.getSchema();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(ret.getAttributes().getRulesSchema(), ruleSchema);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRulesOK() {
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.validateConfigurations(testRules);
|
||||
verify(nikitaCompiler, times(1)).validateRules(testRules);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRulesError() {
|
||||
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.validateConfigurations(testRules);
|
||||
verify(nikitaCompiler, times(1)).validateRules(testRules);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateRuleOK() {
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.validateConfiguration(testRule);
|
||||
verify(nikitaCompiler, times(1)).validateRule(testRule);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ValidateRulesError() {
|
||||
nikitaAttributes.setMessage("error");
|
||||
nikitaAttributes.setException("exception");
|
||||
nikitaResult = new NikitaResult(NikitaResult.StatusCode.ERROR, nikitaAttributes);
|
||||
Mockito.when(nikitaCompiler.validateRules(any())).thenReturn(nikitaResult);
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.validateConfigurations(testRules);
|
||||
verify(nikitaCompiler, times(1)).validateRules(testRules);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
Assert.assertEquals("exception", ret.getAttributes().getException());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ValidateRuleError() {
|
||||
nikitaAttributes.setMessage("error");
|
||||
nikitaAttributes.setException("exception");
|
||||
nikitaResult = new NikitaResult(NikitaResult.StatusCode.ERROR, nikitaAttributes);
|
||||
Mockito.when(nikitaCompiler.validateRule(any())).thenReturn(nikitaResult);
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.validateConfiguration(testRule);
|
||||
verify(nikitaCompiler, times(1)).validateRule(testRule);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
Assert.assertEquals("exception", ret.getAttributes().getException());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestRuleOK() {
|
||||
nikitaAttributes.setMessage(testResultOutput);
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.testConfiguration(testRule, testEvent);
|
||||
verify(nikitaCompiler, times(1)).testRule(testRule, testEvent);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getTestResultComplete());
|
||||
Assert.assertEquals(testResultOutput, ret.getAttributes().getTestResultOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestRulesError() {
|
||||
nikitaAttributes.setMessage("error");
|
||||
nikitaAttributes.setException("exception");
|
||||
nikitaResult = new NikitaResult(NikitaResult.StatusCode.ERROR, nikitaAttributes);
|
||||
Mockito.when(nikitaCompiler.testRules(testRules, testEvent)).thenReturn(nikitaResult);
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.testConfigurations(testRules, testEvent);
|
||||
verify(nikitaCompiler, times(1)).testRules(testRules, testEvent);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
Assert.assertEquals("exception", ret.getAttributes().getException());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestRuleError() {
|
||||
nikitaAttributes.setMessage("error");
|
||||
nikitaAttributes.setException("exception");
|
||||
nikitaResult = new NikitaResult(NikitaResult.StatusCode.ERROR, nikitaAttributes);
|
||||
Mockito.when(nikitaCompiler.testRule(testRule, testEvent)).thenReturn(nikitaResult);
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.testConfiguration(testRule, testEvent);
|
||||
verify(nikitaCompiler, times(1)).testRule(testRule, testEvent);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
Assert.assertEquals("exception", ret.getAttributes().getException());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestRuleInternalError() {
|
||||
nikitaResult = new NikitaResult(NikitaResult.StatusCode.OK, nikitaAttributes);
|
||||
Mockito.when(nikitaCompiler.testRule(testRule, testEvent)).thenReturn(nikitaResult);
|
||||
ConfigEditorResult ret = nikitaRuleSchemaService.testConfiguration(testRule, testEvent);
|
||||
verify(nikitaCompiler, times(1)).testRule(testRule, testEvent);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parserconfig;
|
||||
|
||||
import org.adrianwalker.multilinestring.Multiline;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigInfoProvider;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorFile;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ParserConfigConfigInfoProviderTest {
|
||||
/**
|
||||
* {
|
||||
* "parser_name": "test_parser",
|
||||
* "parser_author": "john",
|
||||
* "parser_version": 12345,
|
||||
* "parser_config": {
|
||||
* "parser_attributes": {
|
||||
* "parser_type": "syslog",
|
||||
* "syslog_config": {
|
||||
* "syslog_version": "RFC_3164",
|
||||
* "timezone": "UTC"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String testParser;
|
||||
/**
|
||||
* {
|
||||
* "parser_name": "test_parser",
|
||||
* "parser_author": "john",
|
||||
* "parser_version": 0,
|
||||
* "parser_config": {
|
||||
* "parser_attributes": {
|
||||
* "parser_type": "syslog",
|
||||
* "syslog_config": {
|
||||
* "syslog_version": "RFC_3164",
|
||||
* "timezone": "UTC"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String testNewParser;
|
||||
|
||||
/**
|
||||
* {
|
||||
* "parsers_version" : 1,
|
||||
* "parser_configurations": [
|
||||
* {
|
||||
* "parser_name": "test_parser",
|
||||
* "parser_author": "john",
|
||||
* "parser_version": 1,
|
||||
* "parser_config": {
|
||||
* "parser_attributes": {
|
||||
* "parser_type": "syslog",
|
||||
* "syslog_config": {
|
||||
* "syslog_version": "RFC_3164",
|
||||
* "timezone": "UTC"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }]
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String release;
|
||||
|
||||
/**
|
||||
* {
|
||||
* "parser_name": "../../../test_parser",
|
||||
* "parser_author": "john",
|
||||
* "parser_version": 12345,
|
||||
* "parser_config": {
|
||||
* "parser_attributes": {
|
||||
* "parser_type": "syslog",
|
||||
* "syslog_config": {
|
||||
* "syslog_version": "RFC_3164",
|
||||
* "timezone": "UTC"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
public static String maliciousConfig;
|
||||
|
||||
public static String user = "steve@secret.net";
|
||||
private final ConfigInfoProvider infoProvider = ParserConfigConfigInfoProvider.create();
|
||||
|
||||
@Test
|
||||
public void ConfigInfoTestChangeAuthor() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, testParser);
|
||||
Assert.assertEquals(12345, info.getOldVersion());
|
||||
Assert.assertEquals(12346, info.getVersion());
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals("Updating configuration: test_parser to version: 12346", info.getCommitMessage());
|
||||
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals(info.getCommitterEmail(), user);
|
||||
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("test_parser.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test_parser.json").indexOf("\"parser_version\": 12346,") > 0);
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test_parser.json").indexOf("\"parser_author\": \"steve\",") > 0);
|
||||
Assert.assertFalse(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ConfigInfoTestUnchangedAuthor() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo("john@secret.net", testParser);
|
||||
Assert.assertEquals(12345, info.getOldVersion());
|
||||
Assert.assertEquals("john", info.getCommitter());
|
||||
Assert.assertEquals("Updating configuration: test_parser to version: 12346", info.getCommitMessage());
|
||||
Assert.assertEquals("john@secret.net", info.getCommitterEmail());
|
||||
Assert.assertEquals( 1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("test_parser.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test_parser.json").indexOf("\"parser_version\": 12346,") > 0);
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test_parser.json").indexOf("\"parser_author\": \"john\",") > 0);
|
||||
Assert.assertFalse(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ConfigInfoNewRule() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, testNewParser);
|
||||
Assert.assertEquals(0, info.getOldVersion());
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals("Adding new configuration: test_parser", info.getCommitMessage());
|
||||
Assert.assertEquals(user, info.getCommitterEmail());
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("test_parser.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test_parser.json").indexOf("\"parser_version\": 1,") > 0);
|
||||
Assert.assertTrue(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ConfigInfoWrongJson() {
|
||||
infoProvider.getConfigInfo(user,"WRONG JSON");
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ConfigInfoWrongMissingMetadata() {
|
||||
infoProvider.getConfigInfo(user, maliciousConfig);
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ConfigInfoWrongUser() {
|
||||
infoProvider.getConfigInfo("INVALID", testParser);
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ReleaseInfoWrongUser() {
|
||||
infoProvider.getReleaseInfo("INVALID", testParser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ReleaseTest() {
|
||||
ConfigInfo info = infoProvider.getReleaseInfo("steve@secret.net", release);
|
||||
|
||||
Assert.assertEquals(1, info.getOldVersion());
|
||||
Assert.assertEquals(2, info.getVersion());
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals("Configuration released to version: 2", info.getCommitMessage());
|
||||
|
||||
Assert.assertEquals("steve", info.getCommitter());
|
||||
Assert.assertEquals(user, info.getCommitterEmail());
|
||||
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("parsers.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("parsers.json").indexOf("\"parsers_version\": 2,") > 0);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void FilterRulesTest() {
|
||||
Assert.assertFalse(infoProvider.isReleaseFile("a.json"));
|
||||
Assert.assertTrue(infoProvider.isReleaseFile("parsers.json"));
|
||||
Assert.assertTrue(infoProvider.isStoreFile("abc.json"));
|
||||
Assert.assertFalse(infoProvider.isStoreFile("json.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void RulesVersionTest() {
|
||||
List<ConfigEditorFile> files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("parsers.json", release, ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
int version = infoProvider.getReleaseVersion(files);
|
||||
Assert.assertEquals(1, version);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void RulesVersionTestMissingFile() {
|
||||
List<ConfigEditorFile> files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("a.json", release, ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
infoProvider.getReleaseVersion(files);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void RulesVersionMissingVersion() {
|
||||
List<ConfigEditorFile> files = new ArrayList<>();
|
||||
files.add(new ConfigEditorFile("parsers.json",
|
||||
"{}",
|
||||
ConfigEditorFile.ContentType.RAW_JSON_STRING));
|
||||
infoProvider.getReleaseVersion(files);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parserconfig;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.parsers.common.ParserResult;
|
||||
import uk.co.gresearch.nortem.parsers.factory.ParserFactory;
|
||||
import uk.co.gresearch.nortem.parsers.factory.ParserFactoryAttributes;
|
||||
import uk.co.gresearch.nortem.parsers.factory.ParserFactoryResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
public class ParserConfigSchemaServiceImplTest {
|
||||
private ParserConfigSchemaServiceImpl parserConfigSchemaService;
|
||||
private final String schema = "dummmy schema";
|
||||
private final String testConfig = "dummmy parser config";
|
||||
private final String testConfigs = "dummmy parser configs";
|
||||
private final String testLog = "dummy log";
|
||||
private final String testLogSpecification = "{ \"log\" : \"dummy log\"}";
|
||||
|
||||
private ParserFactory parserFactory;
|
||||
private ParserFactoryResult parserFactoryResult;
|
||||
private ParserFactoryAttributes parserFactoryAttributes;
|
||||
private ParserResult parserResult;
|
||||
|
||||
@Before
|
||||
public void Setup() {
|
||||
parserFactory = Mockito.mock(ParserFactory.class);
|
||||
this.parserConfigSchemaService = new ParserConfigSchemaServiceImpl(parserFactory, schema);
|
||||
parserFactoryAttributes = new ParserFactoryAttributes();
|
||||
parserFactoryResult = new ParserFactoryResult(ParserFactoryResult.StatusCode.OK, parserFactoryAttributes);
|
||||
parserResult = new ParserResult();
|
||||
Mockito.when(parserFactory.create(any())).thenReturn(parserFactoryResult);
|
||||
|
||||
Mockito.when(parserFactory.validateConfiguration(any())).thenReturn(parserFactoryResult);
|
||||
Mockito.when(parserFactory.validateConfigurations(any())).thenReturn(parserFactoryResult);
|
||||
Mockito.when(parserFactory.test(any(), any())).thenReturn(parserFactoryResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSchemaOK() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.getSchema();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(schema, ret.getAttributes().getRulesSchema());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateConfigurationsOK() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfigurations(testConfigs);
|
||||
Mockito.verify(parserFactory, times(1)).validateConfigurations(testConfigs);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateConfigurationsError() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfigurations(testConfigs);
|
||||
Mockito.verify(parserFactory, times(1)).validateConfigurations(testConfigs);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateConfigurationOK() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfiguration(testConfig);
|
||||
Mockito.verify(parserFactory, times(1)).validateConfiguration(testConfig);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ValidateRulesError() {
|
||||
parserFactoryAttributes.setMessage("error");
|
||||
parserFactoryResult = new ParserFactoryResult(ParserFactoryResult.StatusCode.ERROR, parserFactoryAttributes);
|
||||
Mockito.when(parserFactory.validateConfigurations(any())).thenReturn(parserFactoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfigurations(testConfigs);
|
||||
Mockito.verify(parserFactory, times(1)).validateConfigurations(testConfigs);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ValidateRuleError() {
|
||||
parserFactoryAttributes.setMessage("error");
|
||||
|
||||
parserFactoryResult = new ParserFactoryResult(ParserFactoryResult.StatusCode.ERROR, parserFactoryAttributes);
|
||||
Mockito.when(parserFactory.validateConfiguration(any())).thenReturn(parserFactoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfiguration(testConfig);
|
||||
Mockito.verify(parserFactory, times(1)).validateConfiguration(testConfig);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestConfigurationOK() {
|
||||
parserResult.setParsedMessages(new ArrayList<>());
|
||||
parserFactoryAttributes.setParserResult(parserResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.testConfiguration(testConfig, testLogSpecification);
|
||||
Mockito.verify(parserFactory, times(1)).test(testConfig, testLog.getBytes());
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getTestResultComplete());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestConfigurationsError() {
|
||||
parserFactoryAttributes.setMessage("error");
|
||||
parserFactoryResult = new ParserFactoryResult(ParserFactoryResult.StatusCode.ERROR, parserFactoryAttributes);
|
||||
Mockito.when(parserFactory.test(testConfigs, testLog.getBytes())).thenReturn(parserFactoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.testConfigurations(testConfigs, testLog);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("Not implemented", ret.getAttributes().getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestConfigurationError() {
|
||||
parserFactoryAttributes.setMessage("error");
|
||||
parserFactoryResult = new ParserFactoryResult(ParserFactoryResult.StatusCode.ERROR, parserFactoryAttributes);
|
||||
Mockito.when(parserFactory.test(testConfig, testLog.getBytes())).thenReturn(parserFactoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.testConfiguration(testConfig, testLogSpecification);
|
||||
Mockito.verify(parserFactory, times(1)).test(testConfig, testLog.getBytes());
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertEquals("error", ret.getAttributes().getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestConfigurationParserResultError() {
|
||||
parserResult.setException(new IllegalStateException("dummy"));
|
||||
parserFactoryAttributes.setParserResult(parserResult);
|
||||
|
||||
parserFactoryResult = new ParserFactoryResult(ParserFactoryResult.StatusCode.OK, parserFactoryAttributes);
|
||||
Mockito.when(parserFactory.test(testConfig, testLog.getBytes())).thenReturn(parserFactoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.testConfiguration(testConfig, testLogSpecification);
|
||||
Mockito.verify(parserFactory, times(1)).test(testConfig, testLog.getBytes());
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.ERROR, ret.getStatusCode());
|
||||
Assert.assertTrue(ret.getAttributes().getMessage().contains("dummy"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parsingapp;
|
||||
|
||||
import org.adrianwalker.multilinestring.Multiline;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigInfo;
|
||||
import uk.co.gresearch.nortem.configeditor.configstore.ConfigInfoProvider;
|
||||
|
||||
public class ParsingAppConfigInfoProviderTest {
|
||||
|
||||
/**
|
||||
*{
|
||||
* "parsing_app_name": "test",
|
||||
* "parsing_app_version": 12345,
|
||||
* "parsing_app_author": "dummy",
|
||||
* "parsing_app_description": "Description of parser application",
|
||||
* "parsing_app_settings": {
|
||||
* "input_topics": [
|
||||
* "secret"
|
||||
* ],
|
||||
* "error_topic": "error",
|
||||
* "input_parallelism": 1,
|
||||
* "parsing_parallelism": 2,
|
||||
* "output_parallelism": 3,
|
||||
* "parsing_app_type": "single_parser"
|
||||
* },
|
||||
* "parsing_settings": {
|
||||
* "single_parser": {
|
||||
* "parser_name": "single",
|
||||
* "output_topic": "output"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
static String simpleSingleApplicationParser;
|
||||
|
||||
/**
|
||||
*{
|
||||
* "parsing_app_name": "test",
|
||||
* "parsing_app_version": 0,
|
||||
* "parsing_app_author": "dummy",
|
||||
* "parsing_app_description": "Description of parser application",
|
||||
* "parsing_app_settings": {
|
||||
* "input_topics": [
|
||||
* "secret"
|
||||
* ],
|
||||
* "error_topic": "error",
|
||||
* "input_parallelism": 1,
|
||||
* "parsing_parallelism": 2,
|
||||
* "output_parallelism": 3,
|
||||
* "parsing_app_type": "single_parser"
|
||||
* },
|
||||
* "parsing_settings": {
|
||||
* "single_parser": {
|
||||
* "parser_name": "single",
|
||||
* "output_topic": "output"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
@Multiline
|
||||
static String simpleSingleApplicationParserNew;
|
||||
|
||||
/**
|
||||
*{
|
||||
* "parsing_applications_version" : 1,
|
||||
* "parsing_applications" : [
|
||||
* {
|
||||
* "parsing_app_name": "test",
|
||||
* "parsing_app_version": 12345,
|
||||
* "parsing_app_author": "dummy",
|
||||
* "parsing_app_description": "Description of parser application",
|
||||
* "parsing_app_settings": {
|
||||
* "input_topics": [
|
||||
* "secret"
|
||||
* ],
|
||||
* "error_topic": "error",
|
||||
* "input_parallelism": 1,
|
||||
* "parsing_parallelism": 2,
|
||||
* "output_parallelism": 3,
|
||||
* "parsing_app_type": "single_parser"
|
||||
* },
|
||||
* "parsing_settings": {
|
||||
* "single_parser": {
|
||||
* "parser_name": "single",
|
||||
* "output_topic": "output"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
**/
|
||||
@Multiline
|
||||
static String release;
|
||||
|
||||
|
||||
static String user = "unknown@secret.net";
|
||||
private final ConfigInfoProvider infoProvider = ParsingAppConfigInfoProvider.create();
|
||||
|
||||
@Test
|
||||
public void ConfigInfoTestChangeAuthor() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, simpleSingleApplicationParser);
|
||||
Assert.assertEquals(12345, info.getOldVersion());
|
||||
Assert.assertEquals(12346, info.getVersion());
|
||||
Assert.assertEquals("unknown", info.getCommitter());
|
||||
Assert.assertEquals("Updating configuration: test to version: 12346", info.getCommitMessage());
|
||||
|
||||
Assert.assertEquals("unknown", info.getCommitter());
|
||||
Assert.assertEquals(user, info.getCommitterEmail());
|
||||
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("test.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test.json").indexOf("\"parsing_app_version\": 12346,") > 0);
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test.json").indexOf("\"parsing_app_author\": \"unknown\",") > 0);
|
||||
Assert.assertFalse(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ConfigInfoTestUnchangedAuthor() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo("dummy@secret.net", simpleSingleApplicationParser);
|
||||
Assert.assertEquals(12345, info.getOldVersion());
|
||||
Assert.assertEquals("dummy", info.getCommitter());
|
||||
Assert.assertEquals("Updating configuration: test to version: 12346", info.getCommitMessage());
|
||||
Assert.assertEquals("dummy@secret.net", info.getCommitterEmail());
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("test.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test.json").indexOf("\"parsing_app_version\": 12346,") > 0);
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test.json").indexOf("\"parsing_app_author\": \"dummy\",") > 0);
|
||||
Assert.assertFalse(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ConfigInfoNewRule() {
|
||||
ConfigInfo info = infoProvider.getConfigInfo(user, simpleSingleApplicationParserNew);
|
||||
Assert.assertEquals(0, info.getOldVersion());
|
||||
Assert.assertEquals("unknown", info.getCommitter());
|
||||
Assert.assertEquals("Adding new configuration: test", info.getCommitMessage());
|
||||
Assert.assertEquals(user, info.getCommitterEmail());
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("test.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test.json").indexOf("\"parsing_app_version\": 1,") > 0);
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("test.json").indexOf("\"parsing_app_author\": \"unknown\",") > 0);
|
||||
Assert.assertTrue(info.isNewConfig());
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ConfigInfoWrongJson() {
|
||||
infoProvider.getConfigInfo(user, "WRONG JSON");
|
||||
}
|
||||
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ConfigInfoWrongUser() {
|
||||
infoProvider.getConfigInfo("INVALID", simpleSingleApplicationParser);
|
||||
}
|
||||
|
||||
@Test(expected = java.lang.IllegalArgumentException.class)
|
||||
public void ReleaseInfoWrongUser() {
|
||||
infoProvider.getReleaseInfo("INVALID", simpleSingleApplicationParser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ReleaseTest() {
|
||||
ConfigInfo info = infoProvider.getReleaseInfo("unknown@secret.net", release.trim());
|
||||
|
||||
Assert.assertEquals(1, info.getOldVersion());
|
||||
Assert.assertEquals(2, info.getVersion());
|
||||
Assert.assertEquals("unknown", info.getCommitter());
|
||||
Assert.assertEquals("Configuration released to version: 2", info.getCommitMessage());
|
||||
|
||||
Assert.assertEquals("unknown", info.getCommitter());
|
||||
Assert.assertEquals(user, info.getCommitterEmail());
|
||||
|
||||
Assert.assertEquals(1, info.getFilesContent().size());
|
||||
Assert.assertTrue(info.getFilesContent().containsKey("parsing_applications.json"));
|
||||
Assert.assertTrue(info.getFilesContent()
|
||||
.get("parsing_applications.json").indexOf("\"parsing_applications_version\": 2,") > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void FilterRulesTest() {
|
||||
Assert.assertFalse(infoProvider.isReleaseFile("a.json"));
|
||||
Assert.assertTrue(infoProvider.isReleaseFile("parsing_applications.json"));
|
||||
Assert.assertTrue(infoProvider.isStoreFile("abc.json"));
|
||||
Assert.assertFalse(infoProvider.isStoreFile("json.txt"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package uk.co.gresearch.nortem.configeditor.service.parsingapp;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import uk.co.gresearch.nortem.configeditor.model.ConfigEditorResult;
|
||||
import uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactory;
|
||||
import uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactoryAttributes;
|
||||
import uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactoryResult;
|
||||
import uk.co.gresearch.nortem.parsers.common.ParserResult;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactoryResult.StatusCode.ERROR;
|
||||
import static uk.co.gresearch.nortem.parsers.application.factory.ParsingApplicationFactoryResult.StatusCode.OK;
|
||||
|
||||
public class ParsingAppConfigSchemaServiceImplTest {
|
||||
private ParsingAppConfigSchemaServiceImpl parserConfigSchemaService;
|
||||
private final String schema = "dummmy schema";
|
||||
private final String testConfig = "dummmy config";
|
||||
private final String testConfigs = "dummmy configs";
|
||||
|
||||
private ParsingApplicationFactory parsingAppFactory;
|
||||
private ParsingApplicationFactoryResult factoryResult;
|
||||
private ParsingApplicationFactoryAttributes factoryAttributes;
|
||||
private ParserResult parsingAppResult;
|
||||
|
||||
@Before
|
||||
public void Setup() {
|
||||
parsingAppFactory = Mockito.mock(ParsingApplicationFactory.class);
|
||||
this.parserConfigSchemaService = new ParsingAppConfigSchemaServiceImpl(parsingAppFactory, schema);
|
||||
factoryAttributes = new ParsingApplicationFactoryAttributes();
|
||||
factoryResult = new ParsingApplicationFactoryResult(OK, factoryAttributes);
|
||||
parsingAppResult = new ParserResult();
|
||||
Mockito.when(parsingAppFactory.validateConfiguration(any())).thenReturn(factoryResult);
|
||||
Mockito.when(parsingAppFactory.validateConfigurations(any())).thenReturn(factoryResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSchemaOK() {
|
||||
factoryAttributes.setJsonSchema(schema);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.getSchema();
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
Assert.assertEquals(schema, ret.getAttributes().getRulesSchema());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateConfigurationsOK() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfigurations(testConfigs);
|
||||
Mockito.verify(parsingAppFactory, times(1)).validateConfigurations(testConfigs);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateConfigurationsError() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfigurations(testConfigs);
|
||||
Mockito.verify(parsingAppFactory, times(1)).validateConfigurations(testConfigs);
|
||||
Assert.assertEquals(ret.getStatusCode(), ConfigEditorResult.StatusCode.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateConfigurationOK() {
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfiguration(testConfig);
|
||||
Mockito.verify(parsingAppFactory, times(1)).validateConfiguration(testConfig);
|
||||
Assert.assertEquals(ConfigEditorResult.StatusCode.OK, ret.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ValidateConfigsError() {
|
||||
factoryAttributes.setMessage("error");
|
||||
factoryResult = new ParsingApplicationFactoryResult(ERROR, factoryAttributes);
|
||||
Mockito.when(parsingAppFactory.validateConfigurations(any())).thenReturn(factoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfigurations(testConfigs);
|
||||
Mockito.verify(parsingAppFactory, times(1)).validateConfigurations(testConfigs);
|
||||
Assert.assertEquals(ret.getStatusCode(), ConfigEditorResult.StatusCode.ERROR);
|
||||
Assert.assertEquals(ret.getAttributes().getMessage(), "error");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ValidateCongError() {
|
||||
factoryAttributes.setMessage("error");
|
||||
factoryResult = new ParsingApplicationFactoryResult(ERROR, factoryAttributes);
|
||||
Mockito.when(parsingAppFactory.validateConfiguration(any())).thenReturn(factoryResult);
|
||||
ConfigEditorResult ret = parserConfigSchemaService.validateConfiguration(testConfig);
|
||||
Mockito.verify(parsingAppFactory, times(1)).validateConfiguration(testConfig);
|
||||
Assert.assertEquals(ret.getStatusCode(), ConfigEditorResult.StatusCode.ERROR);
|
||||
Assert.assertEquals(ret.getAttributes().getMessage(), "error");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"statusCode": "OK",
|
||||
"attributes": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "centrifuge:id",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:waiting_ms",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:original_msg",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:elk_search:count",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:elk_search:result",
|
||||
"type": "json_array"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:array_reducer",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:hive_alert:id",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:hive_alert:created_at",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:hive_case:id",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:hive_case:case_id",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:hive_case:created_at",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:ad_groups:user_info",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:ad_groups:membership",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:jira_issue:id",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "centrifuge:jira_issue:url",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:jira_search:count",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:jira_search:result",
|
||||
"type": "json_array"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:cortex_analysis:value",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:cortex_analysis:level",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"suffix_required": true,
|
||||
"name": "centrifuge:cortex_analysis:full_report",
|
||||
"type": "json_object"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"dummy1": {
|
||||
"order": 0,
|
||||
"template": "nortem-dummy1*",
|
||||
"settings": {
|
||||
"index": {
|
||||
"routing": {
|
||||
"allocation": {
|
||||
"total_shards_per_node": "1"
|
||||
}
|
||||
},
|
||||
"mapping": {
|
||||
"ignore_malformed": "true"
|
||||
},
|
||||
"refresh_interval": "1s",
|
||||
"number_of_shards": "3",
|
||||
"merge": {
|
||||
"scheduler": {
|
||||
"max_thread_count": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mappings": {
|
||||
"secretlogs_doc": {
|
||||
"dynamic_templates": [
|
||||
{
|
||||
"timestamps": {
|
||||
"match": "*:time",
|
||||
"match_mapping_type": "*",
|
||||
"mapping": {
|
||||
"type": "date",
|
||||
"format": "epoch_millis"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"security:category": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"security:level": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip_src_addr": {
|
||||
"type": "ip"
|
||||
},
|
||||
"ip_dst_addr": {
|
||||
"type": "ip"
|
||||
},
|
||||
"ip_dst_port": {
|
||||
"type": "integer"
|
||||
},
|
||||
"ip_src_port": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"aliases": {}
|
||||
},
|
||||
"dummy2": {
|
||||
"order": 0,
|
||||
"template": "nortem-dummy2*",
|
||||
"settings": {
|
||||
"index": {
|
||||
"routing": {
|
||||
"allocation": {
|
||||
"total_shards_per_node": "1"
|
||||
}
|
||||
},
|
||||
"mapping": {
|
||||
"ignore_malformed": "true"
|
||||
},
|
||||
"refresh_interval": "1s",
|
||||
"number_of_shards": "3",
|
||||
"merge": {
|
||||
"scheduler": {
|
||||
"max_thread_count": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mappings": {
|
||||
"plaintext_doc": {
|
||||
"dynamic_templates": [
|
||||
{
|
||||
"timestamps": {
|
||||
"match": "*:time",
|
||||
"match_mapping_type": "*",
|
||||
"mapping": {
|
||||
"type": "date",
|
||||
"format": "epoch_millis"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"dlp:category": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"dlp:level": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip_src_addr": {
|
||||
"type": "ip"
|
||||
},
|
||||
"ip_dst_port": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"aliases": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,768 @@
|
||||
{
|
||||
"statusCode": "OK",
|
||||
"attributes": {
|
||||
"rules_schema": {
|
||||
"type": "object",
|
||||
"description": "Centrifuge Rules",
|
||||
"title": "rules",
|
||||
"properties": {
|
||||
"rules_version": {
|
||||
"type": "integer",
|
||||
"description": "Centrifuge rules version",
|
||||
"default": 0
|
||||
},
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Centrifuge rule that should handle response to AVA alert",
|
||||
"title": "rule",
|
||||
"properties": {
|
||||
"rule_name": {
|
||||
"type": "string",
|
||||
"description": "Rule name that uniquely identifies the rule"
|
||||
},
|
||||
"rule_author": {
|
||||
"type": "string",
|
||||
"description": "The owner of the rule"
|
||||
},
|
||||
"rule_version": {
|
||||
"type": "integer",
|
||||
"description": "The version of the rule",
|
||||
"default": 0
|
||||
},
|
||||
"rule_description": {
|
||||
"type": "string",
|
||||
"description": "The description of the rule"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Field pattern used to match patterns on the field",
|
||||
"title": "field pattern",
|
||||
"properties": {
|
||||
"field_name": {
|
||||
"type": "string",
|
||||
"description": "The field on which the pattern is applied"
|
||||
},
|
||||
"field_pattern": {
|
||||
"type": "string",
|
||||
"description": "Regular expression pattern applied on the field"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"field_name",
|
||||
"field_pattern"
|
||||
]
|
||||
},
|
||||
"description": "Conditions required for evaluating the rule",
|
||||
"minItems": 1
|
||||
},
|
||||
"enrichments": {
|
||||
"type": "object",
|
||||
"description": "Enrichments applied for the alert",
|
||||
"title": "enrichments",
|
||||
"properties": {
|
||||
"elk_search": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Elk query can specify an elk query and further processing of the result",
|
||||
"title": "elk query",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the query"
|
||||
},
|
||||
"index": {
|
||||
"type": "string",
|
||||
"description": "The index used in the query"
|
||||
},
|
||||
"query_type": {
|
||||
"type": "string",
|
||||
"description": "The query type",
|
||||
"enum": [
|
||||
"lucene",
|
||||
"json"
|
||||
],
|
||||
"default": "json"
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The elk search query"
|
||||
},
|
||||
"source": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Requested fields in elk query result. All fields will be used if not provided",
|
||||
"minItems": 1
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"description": "The maximum size of the query result",
|
||||
"maximum": 500,
|
||||
"minimum": 1,
|
||||
"default": 100
|
||||
},
|
||||
"sort": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Sort specifies the order of the elk query result",
|
||||
"title": "sort",
|
||||
"properties": {
|
||||
"field_name": {
|
||||
"type": "string",
|
||||
"description": "The field name used for sorting"
|
||||
},
|
||||
"order": {
|
||||
"type": "string",
|
||||
"description": "The order of sorting",
|
||||
"enum": [
|
||||
"asc",
|
||||
"desc"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"field_name",
|
||||
"order"
|
||||
]
|
||||
},
|
||||
"description": "The sort of the result, sorted by timestamp/desc if not provided",
|
||||
"minItems": 1
|
||||
},
|
||||
"reducers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "The array reducer reduces a query result from an array to a single field",
|
||||
"title": "array reducer",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the reducer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "The type of the reducer",
|
||||
"enum": [
|
||||
"first",
|
||||
"concatenate"
|
||||
]
|
||||
},
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "The field from the query result on which the reducer will be applied"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"field",
|
||||
"name",
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"description": "List of reducers specified individually",
|
||||
"minItems": 1
|
||||
},
|
||||
"all_sources_reducer_first": {
|
||||
"type": "boolean",
|
||||
"description": "First reducers will be generated for all fields from the source list",
|
||||
"default": false
|
||||
},
|
||||
"all_sources_reducer_concatenate": {
|
||||
"type": "boolean",
|
||||
"description": "Concatenate reducers will be generated for all fields from the source list",
|
||||
"default": false
|
||||
},
|
||||
"required_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of fields of the alert required for evaluating the query. The query is skipped if a field is missing",
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"index",
|
||||
"query",
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"description": "The list of elk search queries",
|
||||
"minItems": 1
|
||||
},
|
||||
"jira_search": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Jira query can specify a jira query and further processing of the result",
|
||||
"title": "jira query",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of the query"
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "Query in JQL - Jira Query Language"
|
||||
},
|
||||
"fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Fields required in the response",
|
||||
"minItems": 1
|
||||
},
|
||||
"max_result": {
|
||||
"type": "integer",
|
||||
"description": "Max result of the response",
|
||||
"default": 50
|
||||
},
|
||||
"reducers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "The array reducer reduces a query result from an array to a single field",
|
||||
"title": "array reducer",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the reducer"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "The type of the reducer",
|
||||
"enum": [
|
||||
"first",
|
||||
"concatenate"
|
||||
]
|
||||
},
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "The field from the query result on which the reducer will be applied"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"field",
|
||||
"name",
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"description": "List of reducers specified individually",
|
||||
"minItems": 1
|
||||
},
|
||||
"all_fields_reducer_first": {
|
||||
"type": "boolean",
|
||||
"description": "First reducers will be generated for all specific fields from the fields list",
|
||||
"default": false
|
||||
},
|
||||
"all_fields_reducer_concatenate": {
|
||||
"type": "boolean",
|
||||
"description": "Concatenate reducers will be generated for all specific fields from the source list",
|
||||
"default": false
|
||||
},
|
||||
"required_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of alert fields required for evaluating the query. The query is skipped if a field is missing",
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"fields",
|
||||
"max_result",
|
||||
"query",
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"description": "The list of jira search queries",
|
||||
"minItems": 1
|
||||
},
|
||||
"cortex_analysis": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Cortex analysis enrichment that runs the cortex analyzer and waits for the report",
|
||||
"title": "cortex analysis",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Report name that should identify the analysis"
|
||||
},
|
||||
"analyzer": {
|
||||
"type": "string",
|
||||
"description": "The name of the analyser - without version"
|
||||
},
|
||||
"force_cache": {
|
||||
"type": "boolean",
|
||||
"description": "Force the cache of the analyser and re-run the analysis",
|
||||
"default": false
|
||||
},
|
||||
"wait_time": {
|
||||
"type": "integer",
|
||||
"description": "Maximum time to wait for analysis in minutes",
|
||||
"maximum": 5,
|
||||
"minimum": 1,
|
||||
"default": 1
|
||||
},
|
||||
"data_type": {
|
||||
"type": "string",
|
||||
"description": "Type of the data for analysis",
|
||||
"enum": [
|
||||
"url",
|
||||
"ip",
|
||||
"domain",
|
||||
"fqdn"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"description": "Content of the observable"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Description of the item of analysis"
|
||||
},
|
||||
"tlp": {
|
||||
"type": "integer",
|
||||
"description": "Traffic Light Protocol 0: white, 1: green, 2: amber, 3: red",
|
||||
"maximum": 3,
|
||||
"minimum": 0,
|
||||
"default": 2
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"analyzer",
|
||||
"data",
|
||||
"data_type",
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"description": "The list of cortex analysis",
|
||||
"minItems": 1
|
||||
},
|
||||
"ad_groups_enrichment": {
|
||||
"type": "object",
|
||||
"description": "AD user info and group membership queries",
|
||||
"title": "ad groups",
|
||||
"properties": {
|
||||
"user_name": {
|
||||
"type": "string",
|
||||
"description": "The username from the alert - it should be a variable",
|
||||
"pattern": "^\\$\\{\\w+\\}$"
|
||||
},
|
||||
"compute_user_info": {
|
||||
"type": "boolean",
|
||||
"description": "Request AD info about the user",
|
||||
"default": false
|
||||
},
|
||||
"membership_queries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Predicate for user membership to AD groups",
|
||||
"title": "AD groups membership query",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the query"
|
||||
},
|
||||
"predicate": {
|
||||
"type": "string",
|
||||
"description": "The type of the predicate",
|
||||
"enum": [
|
||||
"isMemberOfAny",
|
||||
"IsMemberOfAll"
|
||||
]
|
||||
},
|
||||
"ad_groups": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The list of groups",
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"ad_groups",
|
||||
"name",
|
||||
"predicate"
|
||||
]
|
||||
},
|
||||
"description": "Queries about user AD group membership"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"user_name"
|
||||
]
|
||||
},
|
||||
"wait_in_ms": {
|
||||
"type": "integer",
|
||||
"description": "Time in milliseconds the rule will wait before being evaluated"
|
||||
}
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Field pattern used to match patterns on the field",
|
||||
"title": "field pattern",
|
||||
"properties": {
|
||||
"field_name": {
|
||||
"type": "string",
|
||||
"description": "The field on which the pattern is applied"
|
||||
},
|
||||
"field_pattern": {
|
||||
"type": "string",
|
||||
"description": "Regular expression pattern applied on the field"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"field_name",
|
||||
"field_pattern"
|
||||
]
|
||||
},
|
||||
"description": "Filters applied to the execution of rule actions",
|
||||
"minItems": 1
|
||||
},
|
||||
"actions": {
|
||||
"type": "object",
|
||||
"description": "Actions to be performed as a response to the alert",
|
||||
"title": "actions",
|
||||
"properties": {
|
||||
"create_the_hive_alert": {
|
||||
"type": "object",
|
||||
"description": "Create the hive alert",
|
||||
"title": "the hive alert",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Title of the alert"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the alert"
|
||||
},
|
||||
"source": {
|
||||
"type": "string",
|
||||
"description": "Source of the alert"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"New",
|
||||
"Updated",
|
||||
"Ignored",
|
||||
"Imported"
|
||||
],
|
||||
"default": "New"
|
||||
},
|
||||
"severity": {
|
||||
"type": "integer",
|
||||
"maximum": 3,
|
||||
"minimum": 1,
|
||||
"default": 2
|
||||
},
|
||||
"tlp": {
|
||||
"type": "integer",
|
||||
"description": "Traffic Light Protocol 0: white, 1: green, 2: amber, 3: red",
|
||||
"maximum": 3,
|
||||
"minimum": 0,
|
||||
"default": 2
|
||||
},
|
||||
"caseTemplate": {
|
||||
"type": "string",
|
||||
"description": "Case template to use when a case is created from this alert"
|
||||
},
|
||||
"artifacts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "The hive alert artifact - observable",
|
||||
"title": "the hive alert artifact",
|
||||
"properties": {
|
||||
"dataType": {
|
||||
"type": "string",
|
||||
"description": "Type of the observable",
|
||||
"enum": [
|
||||
"url",
|
||||
"other",
|
||||
"user-agent",
|
||||
"regexp",
|
||||
"mail_subject",
|
||||
"registry",
|
||||
"mail",
|
||||
"domain",
|
||||
"autonomous-system",
|
||||
"ip",
|
||||
"uri_path",
|
||||
"filename",
|
||||
"hash",
|
||||
"file",
|
||||
"fqdn",
|
||||
"phone_number"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"description": "Content of the observable"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Description of the artifact in the context of the case"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The tags of the observable"
|
||||
},
|
||||
"tlp": {
|
||||
"type": "integer",
|
||||
"description": "Traffic Light Protocol 0: white, 1: green, 2: amber, 3: red",
|
||||
"maximum": 3,
|
||||
"minimum": 0,
|
||||
"default": 2
|
||||
},
|
||||
"ioc": {
|
||||
"type": "boolean",
|
||||
"description": "Indicator of Compromise",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"data",
|
||||
"dataType",
|
||||
"ioc"
|
||||
]
|
||||
},
|
||||
"description": "Artifacts (Observables) of the alert"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The tags of the alert"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of alert is used if markdown table is not provided"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"source",
|
||||
"title",
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"create_the_hive_case": {
|
||||
"type": "object",
|
||||
"description": "Create the hive case",
|
||||
"title": "the hive case",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Title of the case"
|
||||
},
|
||||
"severity": {
|
||||
"type": "integer",
|
||||
"description": "Severity of the case",
|
||||
"maximum": 3,
|
||||
"minimum": 1,
|
||||
"default": 2
|
||||
},
|
||||
"tlp": {
|
||||
"type": "integer",
|
||||
"description": "Traffic Light Protocol 0: white, 1: green, 2: amber, 3: red",
|
||||
"maximum": 3,
|
||||
"minimum": 0,
|
||||
"default": 2
|
||||
},
|
||||
"flag": {
|
||||
"type": "boolean",
|
||||
"description": "Flag case as important",
|
||||
"default": false
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The tags of the alert"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of alert. It is used if markdown table is not provided"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"description": "The user to whom the case has been assigned"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title"
|
||||
]
|
||||
},
|
||||
"the_hive_custom_fields": {
|
||||
"type": "object",
|
||||
"description": "Specification of the custom fields used in the hive actions",
|
||||
"title": "field filter",
|
||||
"properties": {
|
||||
"including_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The list of regular expression patterns for including fields",
|
||||
"minItems": 1,
|
||||
"default": [
|
||||
".*"
|
||||
]
|
||||
},
|
||||
"excluding_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The list of regular expression patterns for excluding fields"
|
||||
}
|
||||
}
|
||||
},
|
||||
"the_hive_description_tables": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "Markdown table used for formatting the description in the hive actions",
|
||||
"title": "markdown table",
|
||||
"properties": {
|
||||
"table_name": {
|
||||
"type": "string",
|
||||
"description": "The name of the table"
|
||||
},
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "The array field of the alert printed in the table"
|
||||
},
|
||||
"field_filter": {
|
||||
"type": "object",
|
||||
"description": "The field filters used for filtering the alert fields in the table",
|
||||
"title": "field filter",
|
||||
"properties": {
|
||||
"including_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The list of regular expression patterns for including fields",
|
||||
"minItems": 1,
|
||||
"default": [
|
||||
".*"
|
||||
]
|
||||
},
|
||||
"excluding_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "The list of regular expression patterns for excluding fields"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"including_fields": [
|
||||
".*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"suffix_name_only": {
|
||||
"type": "boolean",
|
||||
"description": "If the flag is set, the formatter will use the suffix of centrifuge fields",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"table_name"
|
||||
]
|
||||
},
|
||||
"description": "List of the markdown tables used in the hive actions"
|
||||
},
|
||||
"create_jira_issue": {
|
||||
"type": "object",
|
||||
"description": "Create Jira issue",
|
||||
"title": "create jira issue",
|
||||
"properties": {
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "The project of the issue"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "The type of the issue",
|
||||
"enum": [
|
||||
"Task",
|
||||
"Query/Question",
|
||||
"Misc",
|
||||
"Bug"
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"description": "The summary of the issue"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "The description of the issue"
|
||||
},
|
||||
"reporter": {
|
||||
"type": "string",
|
||||
"description": "The reporter of the issue"
|
||||
},
|
||||
"assignee": {
|
||||
"type": "string",
|
||||
"description": "The assignee of the issue"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"project",
|
||||
"summary",
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"elk_store": {
|
||||
"type": "boolean",
|
||||
"description": "Store the enriched alert in the elk store",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"actions",
|
||||
"enrichments",
|
||||
"rule_author",
|
||||
"rule_name",
|
||||
"rule_version"
|
||||
]
|
||||
},
|
||||
"description": "Centrifuge rules",
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"rules",
|
||||
"rules_version"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"layout": {
|
||||
"the_hive_description_tables.excluding_fields": {
|
||||
"type": "expansion-panel"
|
||||
},
|
||||
"conditions": {
|
||||
"type": "card",
|
||||
"options": {
|
||||
"expandable": true,
|
||||
"expanded": true
|
||||
}
|
||||
},
|
||||
"create_the_hive_alert.artifacts.items": {
|
||||
"type": "expansion-panel"
|
||||
}
|
||||
}
|
||||
}
|
||||
1
config-editor/config-editor-spring/README.md
Normal file
1
config-editor/config-editor-spring/README.md
Normal file
@@ -0,0 +1 @@
|
||||
"# config-editor-spring"
|
||||
@@ -1 +0,0 @@
|
||||
"# config-editor"
|
||||
38
config-editor/pom.xml
Normal file
38
config-editor/pom.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>config-editor</artifactId>
|
||||
<name>config-editor</name>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
</properties>
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem</artifactId>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>config-editor-core</module>
|
||||
<module>config-editor-services</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<forceJavacCompilerUse>true</forceJavacCompilerUse>
|
||||
<source>${java_version}</source>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
<target>${java_version}</target>
|
||||
<showWarnings>true</showWarnings>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -17,6 +17,11 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
@@ -109,13 +114,13 @@
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<version>${mockito_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<version>${mockito_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package uk.co.gresearch.nortem.common.utils;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.auth.AuthSchemeProvider;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.config.AuthSchemes;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.auth.SPNegoSchemeFactory;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.security.Principal;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class HttpProvider {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private static final int TIMEOUT_MILLI = 120000;
|
||||
private final String host;
|
||||
private final Supplier<CloseableHttpClient> clientFactory;
|
||||
|
||||
public HttpProvider(String uri, Supplier<CloseableHttpClient> clientFactory) {
|
||||
this.host = uri;
|
||||
this.clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
private String readBody(InputStream input) throws IOException {
|
||||
try (BufferedReader rd = new BufferedReader(
|
||||
new InputStreamReader(input))) {
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
String line = "";
|
||||
while ((line = rd.readLine()) != null) {
|
||||
result.append(line);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public String get(String path) throws IOException {
|
||||
try (CloseableHttpClient httpClient = clientFactory.get()) {
|
||||
String url = host + path;
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
|
||||
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||
LOG.error(String.format("unsuccessful get request on url: %s return status line: %s",
|
||||
url, response.getStatusLine().toString()));
|
||||
throw new IOException("Unsuccessful GET");
|
||||
}
|
||||
|
||||
return readBody(response.getEntity().getContent());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(String.format("Exception during executing GET request on url: %s%s",
|
||||
host, path));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public String post(String path, String jsonBody) throws IOException {
|
||||
try (CloseableHttpClient httpClient = getKerberosHttpClient()) {
|
||||
String url = host + path;
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
|
||||
StringEntity requestEntity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
|
||||
httpPost.setEntity(requestEntity);
|
||||
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED &&
|
||||
response.getStatusLine().getStatusCode() != HttpStatus.SC_OK &&
|
||||
response.getStatusLine().getStatusCode() != HttpStatus.SC_BAD_REQUEST) {
|
||||
LOG.error(String.format(
|
||||
"Unsuccessful post request on url: %s, req body %s, status line: %s",
|
||||
url, jsonBody, response.getStatusLine().toString()));
|
||||
throw new IOException("Unsuccessful POST");
|
||||
}
|
||||
return readBody(response.getEntity().getContent());
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(String.format("Exception during executing POST request on url: %s%s\nbody: %s\nstack_trace: %s",
|
||||
host, path, jsonBody, ExceptionUtils.getStackTrace(e)));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static CloseableHttpClient getKerberosHttpClient() {
|
||||
Credentials useJaasCreds = new Credentials() {
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Principal getUserPrincipal() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
CredentialsProvider credsProvider = new BasicCredentialsProvider();
|
||||
credsProvider.setCredentials(new AuthScope(null, -1, null), useJaasCreds);
|
||||
Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
|
||||
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true, false))
|
||||
.build();
|
||||
|
||||
final RequestConfig params = RequestConfig.custom()
|
||||
.setConnectTimeout(TIMEOUT_MILLI)
|
||||
.setSocketTimeout(TIMEOUT_MILLI).build();
|
||||
|
||||
CloseableHttpClient httpclient = HttpClients
|
||||
.custom()
|
||||
.setDefaultAuthSchemeRegistry(authSchemeRegistry)
|
||||
.setDefaultCredentialsProvider(credsProvider)
|
||||
.setDefaultRequestConfig(params)
|
||||
.build();
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>parsing</artifactId>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<version>1.05-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>nortem-parsing-app</artifactId>
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>parsing</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-common</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-parsing</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.adrianwalker</groupId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>parsing</artifactId>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<version>1.05-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>nortem-parsing-storm</artifactId>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>parsing</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-parsing-app</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>parsing</artifactId>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<version>1.05-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>nortem-parsing</artifactId>
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>parsing</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem-common</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem</artifactId>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>nortem-parsing</module>
|
||||
|
||||
3
pom.xml
3
pom.xml
@@ -7,7 +7,7 @@
|
||||
<groupId>uk.co.gresearch.nortem</groupId>
|
||||
<artifactId>nortem</artifactId>
|
||||
<name>nortem</name>
|
||||
<version>1.06-SNAPSHOT</version>
|
||||
<version>1.07-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@@ -26,6 +26,7 @@
|
||||
<module>nortem-common</module>
|
||||
<module>parsing</module>
|
||||
<module>alerting</module>
|
||||
<module>config-editor</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
|
||||
Reference in New Issue
Block a user