METRON-1231 Separate Sensor name and topic in the Management UI (merrimanr) closes apache/metron#786
diff --git a/metron-interface/metron-config/src/app/model/sensor-parser-config-history.ts b/metron-interface/metron-config/src/app/model/sensor-parser-config-history.ts
index 0aed6fe..4854001 100644
--- a/metron-interface/metron-config/src/app/model/sensor-parser-config-history.ts
+++ b/metron-interface/metron-config/src/app/model/sensor-parser-config-history.ts
@@ -17,6 +17,7 @@
*/
import {SensorParserConfig} from './sensor-parser-config';
export class SensorParserConfigHistory {
+ sensorName: string;
createdBy: string;
modifiedBy: string;
createdDate: string;
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-config-readonly/sensor-parser-config-readonly.component.ts b/metron-interface/metron-config/src/app/sensors/sensor-parser-config-readonly/sensor-parser-config-readonly.component.ts
index f28a206..5db6d45 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-config-readonly/sensor-parser-config-readonly.component.ts
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-config-readonly/sensor-parser-config-readonly.component.ts
@@ -330,7 +330,7 @@
this.sensorParserConfigService.deleteSensorParserConfig(name).subscribe(result => {
this.metronAlerts.showSuccessMessage('Deleted sensor ' + name);
this.toggleStartStopInProgress();
- this.sensorParserConfigService.dataChangedSource.next([this.sensorParserConfigHistory.config]);
+ this.sensorParserConfigService.dataChangedSource.next([name]);
this.goBack();
},
error => {
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.html b/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.html
index 186e221..a784436 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.html
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.html
@@ -41,16 +41,25 @@
<div class="metron-slider-pane-edit fill load-right-to-left dialog1x" style="overflow: auto" >
<div style="height:100%">
- <div class="form-title">{{sensorParserConfig.sensorTopic}} </div>
+ <div class="form-title">{{sensorName}} </div>
<i class="fa fa-times pull-right main close-button" aria-hidden="true" (click)="goBack()"></i>
<form role="form" [formGroup]="sensorConfigForm">
<div class="form-group">
- <label attr.for="sensorTopic">NAME * </label>
- <input type="text" class="form-control" name="sensorTopic" formControlName="sensorTopic" [(ngModel)]="sensorParserConfig.sensorTopic" (ngModelChange)="onSetSensorName()" [readonly]="editMode">
- <label *ngIf="currentKafkaStatus !== null && currentKafkaStatus === kafkaStatus.NO_TOPIC"><span class="warning-text"> No Matching Kafka Topic </span></label>
- <label *ngIf="currentKafkaStatus !== null && currentKafkaStatus === kafkaStatus.EMITTING" ><span class="success-text-color"> Kafka Topic Exists. Emitting </span></label>
- <label *ngIf="currentKafkaStatus !== null && currentKafkaStatus === kafkaStatus.NOT_EMITTING"><span class="success-text-color"> Kafka Topic Exists. </span><span class="warning-text" > Not Emitting </span></label>
+ <label attr.for="sensorName">NAME * </label>
+ <input type="text" class="form-control" name="sensorName" formControlName="sensorName" [(ngModel)]="sensorName" (ngModelChange)="onSetSensorName()" [readonly]="editMode">
+ <div *ngIf="!sensorNameUnique"><label ><span class="warning-text"> Sensor already exists </span></label></div>
+ </div>
+
+ <div class="form-group">
+ <label attr.for="sensorTopic">KAFKA TOPIC </label>
+ <input type="text" class="form-control" name="sensorTopic" formControlName="sensorTopic" [(ngModel)]="sensorParserConfig.sensorTopic" (ngModelChange)="onSetKafkaTopic()">
+ <div *ngIf="!kafkaTopicValid"><label ><span class="warning-text"> Kafka Topic Name Is Invalid </span></label></div>
+ <div *ngIf="kafkaTopicValid">
+ <label *ngIf="currentKafkaStatus !== null && currentKafkaStatus === kafkaStatus.NO_TOPIC"><span class="warning-text"> No Matching Kafka Topic </span></label>
+ <label *ngIf="currentKafkaStatus !== null && currentKafkaStatus === kafkaStatus.EMITTING" ><span class="success-text-color"> Kafka Topic Exists. Emitting </span></label>
+ <label *ngIf="currentKafkaStatus !== null && currentKafkaStatus === kafkaStatus.NOT_EMITTING"><span class="success-text-color"> Kafka Topic Exists. </span><span class="warning-text" > Not Emitting </span></label>
+ </div>
</div>
<div class="form-group">
@@ -187,7 +196,7 @@
<div class="form-group">
<div class="form-seperator-edit"></div>
<div class="button-row">
- <button type="submit" class="btn save-button" [ngClass]="{'disabled':!configValid}" (click)="onSave()">SAVE</button>
+ <button type="submit" class="btn save-button" [ngClass]="{'disabled':!configValid}" [disabled]="!configValid" (click)="onSave()">SAVE</button>
<button class="btn form-enable-disable-button" (click)="goBack()" >CANCEL</button>
<span class="advanced-link" [hidden]="showAdvancedParserConfiguration" (click)="showAdvancedParserConfiguration = true">Advanced</span>
</div>
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.spec.ts b/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.spec.ts
index 6c4eab1..d5f3d67 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.spec.ts
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.spec.ts
@@ -64,6 +64,7 @@
}
class MockSensorParserConfigService extends SensorParserConfigService {
+ private name: string;
private sensorParserConfig: SensorParserConfig;
private parsedMessage: any;
private postedSensorParserConfig: SensorParserConfig;
@@ -73,7 +74,7 @@
super(http2, config2);
}
- public post(sensorParserConfig: SensorParserConfig): Observable<SensorParserConfig> {
+ public post(name: string, sensorParserConfig: SensorParserConfig): Observable<SensorParserConfig> {
if (this.throwError) {
let error = new RestError();
error.message = 'SensorParserConfig post error';
@@ -93,6 +94,15 @@
});
}
+ public getAll(): Observable<{}> {
+ return Observable.create(observer => {
+ let results = {};
+ results[this.name] = this.sensorParserConfig;
+ observer.next(results);
+ observer.complete();
+ });
+ }
+
public getAvailableParsers(): Observable<{}> {
return Observable.create(observer => {
observer.next({
@@ -110,8 +120,9 @@
});
}
- public setSensorParserConfig(result: any) {
- this.sensorParserConfig = result;
+ public setSensorParserConfig(name: string, sensorParserConfig: SensorParserConfig) {
+ this.name = name;
+ this.sensorParserConfig = sensorParserConfig;
}
public setParsedMessage(parsedMessage: any) {
@@ -570,7 +581,7 @@
component.sensorParserConfig = Object.assign(new SensorParserConfig(), squidSensorParserConfig);
component.createForms();
- expect(Object.keys(component.sensorConfigForm.controls).length).toEqual(15);
+ expect(Object.keys(component.sensorConfigForm.controls).length).toEqual(16);
expect(Object.keys(component.transformsValidationForm.controls).length).toEqual(2);
expect(component.showAdvancedParserConfiguration).toEqual(true);
@@ -594,6 +605,7 @@
}));
it('should init', async(() => {
+ sensorParserConfigService.setSensorParserConfig('squid', squidSensorParserConfig);
component.init('new');
let expectedSensorParserConfig = new SensorParserConfig();
@@ -602,10 +614,11 @@
expect(component.sensorEnrichmentConfig).toEqual(new SensorEnrichmentConfig());
expect(component.indexingConfigurations).toEqual(new IndexingConfigurations());
expect(component.editMode).toEqual(false);
+ expect(component.currentSensors).toEqual(['squid']);
spyOn(component, 'getKafkaStatus');
let sensorParserConfig = Object.assign(new SensorParserConfig(), squidSensorParserConfig);
- sensorParserConfigService.setSensorParserConfig(sensorParserConfig);
+ sensorParserConfigService.setSensorParserConfig('squid', sensorParserConfig);
sensorEnrichmentConfigService.setSensorEnrichmentConfig('squid',
Object.assign(new SensorEnrichmentConfig(), squidSensorEnrichmentConfig));
sensorIndexingConfigService.setSensorIndexingConfig('squid',
@@ -646,7 +659,7 @@
sensorParserConfig = new SensorParserConfig();
sensorParserConfig.sensorTopic = 'bro';
- sensorParserConfigService.setSensorParserConfig(sensorParserConfig);
+ sensorParserConfigService.setSensorParserConfig('bro', sensorParserConfig);
component.showAdvancedParserConfiguration = false;
component.init('bro');
@@ -664,22 +677,43 @@
fixture.destroy();
}));
- it('should handle onSetSensorName', async(() => {
+ it('should handle onSetKafkaTopic', async(() => {
spyOn(component, 'getKafkaStatus');
spyOn(component, 'isConfigValid');
- component.onSetSensorName();
+ component.onSetKafkaTopic();
expect(component.getKafkaStatus).not.toHaveBeenCalled();
expect(component.isConfigValid).toHaveBeenCalled();
component.sensorParserConfig.sensorTopic = 'bro';
- component.onSetSensorName();
- expect(component.sensorNameValid).toEqual(true);
+ component.onSetKafkaTopic();
+ expect(component.kafkaTopicValid).toEqual(true);
expect(component.getKafkaStatus).toHaveBeenCalled();
fixture.destroy();
}));
+ it('should handle onSetSensorName', async(() => {
+ spyOn(component, 'isConfigValid');
+
+ component.onSetSensorName();
+ expect(component.isConfigValid).toHaveBeenCalled();
+ expect(component.sensorNameValid).toEqual(false);
+
+ component.sensorName = 'squid';
+ component.currentSensors = ['squid'];
+ component.onSetSensorName();
+ expect(component.sensorNameUnique).toEqual(false);
+ expect(component.sensorNameValid).toEqual(false);
+
+ component.sensorName = 'squidUnique';
+ component.onSetSensorName();
+ expect(component.sensorNameUnique).toEqual(true);
+ expect(component.sensorNameValid).toEqual(true);
+
+ fixture.destroy();
+ }));
+
it('should handle onParserTypeChange', async(() => {
spyOn(component, 'hidePane');
spyOn(component, 'isConfigValid');
@@ -719,6 +753,7 @@
expect(component.configValid).toEqual(false);
component.sensorNameValid = true;
+ component.kafkaTopicValid = true;
component.parserClassValid = true;
component.isConfigValid();
@@ -770,7 +805,7 @@
}));
it('should handle onSaveGrokStatement', async(() => {
- component.sensorParserConfig.sensorTopic = 'squid';
+ component.sensorName = 'squid';
component.onSaveGrokStatement('grok statement');
expect(component.grokStatement).toEqual('grok statement');
@@ -979,7 +1014,7 @@
it('should handle onShowGrokPane', async(() => {
spyOn(component, 'showPane');
- component.sensorParserConfig.sensorTopic = 'squid';
+ component.sensorName = 'squid';
component.onShowGrokPane();
expect(component.patternLabel).toEqual('SQUID');
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.ts b/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.ts
index 679d057..647e02f 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.ts
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-config/sensor-parser-config.component.ts
@@ -52,6 +52,7 @@
sensorConfigForm: FormGroup;
transformsValidationForm: FormGroup;
+ sensorName: string = '';
sensorParserConfig: SensorParserConfig = new SensorParserConfig();
sensorEnrichmentConfig: SensorEnrichmentConfig = new SensorEnrichmentConfig();
indexingConfigurations: IndexingConfigurations = new IndexingConfigurations();
@@ -66,12 +67,15 @@
configValid = false;
sensorNameValid = false;
+ sensorNameUnique = true;
+ kafkaTopicValid = false;
parserClassValid = false;
grokStatementValid = false;
availableParsers = {};
availableParserNames = [];
grokStatement = '';
patternLabel = '';
+ currentSensors = [];
editMode: boolean = false;
@@ -100,6 +104,7 @@
init(id: string): void {
if (id !== 'new') {
this.editMode = true;
+ this.sensorName = id;
this.sensorParserConfigService.get(id).subscribe((results: SensorParserConfig) => {
this.sensorParserConfig = results;
this.sensorNameValid = true;
@@ -144,6 +149,9 @@
} else {
this.sensorParserConfig = new SensorParserConfig();
this.sensorParserConfig.parserClassName = 'org.apache.metron.parsers.GrokParser';
+ this.sensorParserConfigService.getAll().subscribe((results: {}) => {
+ this.currentSensors = Object.keys(results);
+ });
}
}
@@ -159,6 +167,7 @@
createSensorConfigForm(): FormGroup {
let group: any = {};
+ group['sensorName'] = new FormControl(this.sensorName, Validators.required);
group['sensorTopic'] = new FormControl(this.sensorParserConfig.sensorTopic, Validators.required);
group['parserClassName'] = new FormControl(this.sensorParserConfig.parserClassName, Validators.required);
group['grokStatement'] = new FormControl(this.grokStatement);
@@ -209,9 +218,16 @@
}
onSetSensorName(): void {
- this.sensorNameValid = this.sensorParserConfig.sensorTopic !== undefined &&
- this.sensorParserConfig.sensorTopic.length > 0;
- if (this.sensorNameValid) {
+ this.sensorNameUnique = this.currentSensors.indexOf(this.sensorName) === -1;
+ this.sensorNameValid = this.sensorName !== undefined &&
+ this.sensorName.length > 0 && this.sensorNameUnique;
+ this.isConfigValid();
+ }
+
+ onSetKafkaTopic(): void {
+ this.kafkaTopicValid = this.sensorParserConfig.sensorTopic !== undefined &&
+ /[a-zA-Z0-9._-]+$/.test(this.sensorParserConfig.sensorTopic);
+ if (this.kafkaTopicValid) {
this.getKafkaStatus();
}
this.isConfigValid();
@@ -237,7 +253,7 @@
isConfigValid() {
let isGrokParser = this.isGrokParser(this.sensorParserConfig);
- this.configValid = this.sensorNameValid && this.parserClassValid && (!isGrokParser || this.grokStatementValid);
+ this.configValid = this.sensorNameValid && this.kafkaTopicValid && this.parserClassValid && (!isGrokParser || this.grokStatementValid);
}
getKafkaStatus() {
@@ -282,7 +298,7 @@
this.grokStatement = grokStatement;
let grokPath = this.sensorParserConfig.parserConfig['grokPath'];
if (!grokPath || grokPath.indexOf('/patterns') === 0) {
- this.sensorParserConfig.parserConfig['grokPath'] = '/apps/metron/patterns/' + this.sensorParserConfig.sensorTopic;
+ this.sensorParserConfig.parserConfig['grokPath'] = '/apps/metron/patterns/' + this.sensorName;
}
}
@@ -293,34 +309,34 @@
onSave() {
if (!this.indexingConfigurations.hdfs.index) {
- this.indexingConfigurations.hdfs.index = this.sensorParserConfig.sensorTopic;
+ this.indexingConfigurations.hdfs.index = this.sensorName;
}
if (!this.indexingConfigurations.elasticsearch.index) {
- this.indexingConfigurations.elasticsearch.index = this.sensorParserConfig.sensorTopic;
+ this.indexingConfigurations.elasticsearch.index = this.sensorName;
}
if (!this.indexingConfigurations.solr.index) {
- this.indexingConfigurations.solr.index = this.sensorParserConfig.sensorTopic;
+ this.indexingConfigurations.solr.index = this.sensorName;
}
- this.sensorParserConfigService.post(this.sensorParserConfig).subscribe(
+ this.sensorParserConfigService.post(this.sensorName, this.sensorParserConfig).subscribe(
sensorParserConfig => {
if (this.isGrokParser(sensorParserConfig)) {
this.hdfsService.post(this.sensorParserConfig.parserConfig['grokPath'], this.grokStatement).subscribe(
response => {}, (error: RestError) => this.metronAlerts.showErrorMessage(error.message));
}
- this.sensorEnrichmentConfigService.post(sensorParserConfig.sensorTopic, this.sensorEnrichmentConfig).subscribe(
+ this.sensorEnrichmentConfigService.post(this.sensorName, this.sensorEnrichmentConfig).subscribe(
(sensorEnrichmentConfig: SensorEnrichmentConfig) => {
}, (error: RestError) => {
let msg = ' Sensor parser config but unable to save enrichment configuration: ';
this.metronAlerts.showErrorMessage(this.getMessagePrefix() + msg + error.message);
});
- this.sensorIndexingConfigService.post(sensorParserConfig.sensorTopic, this.indexingConfigurations).subscribe(
+ this.sensorIndexingConfigService.post(this.sensorName, this.indexingConfigurations).subscribe(
(indexingConfigurations: IndexingConfigurations) => {
}, (error: RestError) => {
let msg = ' Sensor parser config but unable to save indexing configuration: ';
this.metronAlerts.showErrorMessage(this.getMessagePrefix() + msg + error.message);
});
- this.metronAlerts.showSuccessMessage(this.getMessagePrefix() + ' Sensor ' + sensorParserConfig.sensorTopic);
- this.sensorParserConfigService.dataChangedSource.next([this.sensorParserConfig]);
+ this.metronAlerts.showSuccessMessage(this.getMessagePrefix() + ' Sensor ' + this.sensorName);
+ this.sensorParserConfigService.dataChangedSource.next([this.sensorName]);
this.goBack();
}, (error: RestError) => {
this.metronAlerts.showErrorMessage('Unable to save sensor config: ' + error.message);
@@ -385,7 +401,7 @@
onShowGrokPane() {
if (!this.patternLabel) {
- this.patternLabel = this.sensorParserConfig.sensorTopic.toUpperCase();
+ this.patternLabel = this.sensorName.toUpperCase();
}
this.showPane(this.pane.GROK);
}
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.html b/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.html
index bd0b1fd..576b5a3 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.html
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.html
@@ -40,7 +40,7 @@
<table class="table card-deck" metron-config-table #table (onSort)="onSort($event)">
<thead>
<tr>
- <th> <metron-config-sorter [sortBy]="'sensorTopic'"> Name </metron-config-sorter> </th>
+ <th> <metron-config-sorter [sortBy]="'sensorName'"> Name </metron-config-sorter> </th>
<th> <metron-config-sorter [sortBy]="'parserClassName'"> Parser </metron-config-sorter> </th>
<th> <metron-config-sorter [sortBy]="'status'"> Status </metron-config-sorter> </th>
<th> <metron-config-sorter [sortBy]="'latency'"> Latency </metron-config-sorter> </th>
@@ -52,8 +52,8 @@
</tr>
</thead>
<tbody>
- <tr *ngFor="let sensor of sensors;" (click)="onSensorRowSelect(sensor.config, $event)" [ngClass]="{'active': (selectedSensors.indexOf(sensor) != -1 || sensorParserConfigService.getSelectedSensor() == sensor.config)}">
- <td>{{ sensor.config.sensorTopic }}</td>
+ <tr *ngFor="let sensor of sensors;" (click)="onSensorRowSelect(sensor, $event)" [ngClass]="{'active': (selectedSensors.indexOf(sensor) != -1 || selectedSensor == sensor)}">
+ <td>{{ sensor.sensorName }}</td>
<td>{{ getParserType(sensor.config) }}</td>
<td [ngClass]="{'warning-text': (sensor.status == 'Stopped' || sensor.status == 'Disabled')}">{{ sensor.status }}</td>
<td>{{ sensor.latency }}</td>
@@ -69,11 +69,11 @@
<i data-toggle="tooltip" title="Start parser topology" class="fa fa-play fa-lg" aria-hidden="true" [hidden]="(sensor.status != 'Stopped' || sensor.config['startStopInProgress'])" (click)="onStartSensor(sensor, $event)"></i>
<i data-toggle="tooltip" title="Enable parser topology" class="fa fa-check-circle-o fa-lg" aria-hidden="true" [hidden]="(sensor.status != 'Disabled' || sensor.config['startStopInProgress'])" (click)="onEnableSensor(sensor, $event)"></i>
- <i data-toggle="tooltip" title="Edit parser topology" class="fa fa-pencil fa-lg" aria-hidden="true" (click)="navigateToSensorEdit(sensor.config, $event)"></i>
+ <i data-toggle="tooltip" title="Edit parser topology" class="fa fa-pencil fa-lg" aria-hidden="true" (click)="navigateToSensorEdit(sensor, $event)"></i>
- <i data-toggle="tooltip" title="Delete parser configuration" class="fa fa-trash-o fa-lg" aria-hidden="true" (click)="deleteSensor($event, [sensor.config])"></i>
+ <i data-toggle="tooltip" title="Delete parser configuration" class="fa fa-trash-o fa-lg" aria-hidden="true" (click)="deleteSensor($event, [sensor])"></i>
</td>
- <td><input id="{{ sensor.config.sensorTopic }}" class="fontawesome-checkbox" type="checkbox" name="{{sensor.config.sensorTopic}}" (click)="onRowSelected(sensor, $event)"><label attr.for="{{ sensor.config.sensorTopic }}"></label></td>
+ <td><input id="{{ sensor.sensorName }}" class="fontawesome-checkbox" type="checkbox" name="{{sensor.sensorName}}" (click)="onRowSelected(sensor, $event)"><label attr.for="{{ sensor.sensorName }}"></label></td>
</tr>
</tbody>
</table>
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.spec.ts b/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.spec.ts
index 5534bea..205d885 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.spec.ts
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.spec.ts
@@ -77,28 +77,28 @@
}
class MockSensorParserConfigService extends SensorParserConfigService {
- private sensorParserConfigs: SensorParserConfig[];
+ private sensorParserConfigs: {};
constructor(private http2: Http, @Inject(APP_CONFIG) private config2: IAppConfig) {
super(http2, config2);
}
- public setSensorParserConfigForTest(sensorParserConfigs: SensorParserConfig[]) {
+ public setSensorParserConfigForTest(sensorParserConfigs: {}) {
this.sensorParserConfigs = sensorParserConfigs;
}
- public getAll(): Observable<SensorParserConfig[]> {
+ public getAll(): Observable<{string: SensorParserConfig}> {
return Observable.create(observer => {
observer.next(this.sensorParserConfigs);
observer.complete();
});
}
- public deleteSensorParserConfigs(sensors: SensorParserConfig[]): Observable<{success: Array<string>, failure: Array<string>}> {
+ public deleteSensorParserConfigs(sensorNames: string[]): Observable<{success: Array<string>, failure: Array<string>}> {
let result: {success: Array<string>, failure: Array<string>} = {success: [], failure: []};
let observable = Observable.create((observer => {
- for (let i = 0; i < sensors.length; i++) {
- result.success.push(sensors[i].sensorTopic);
+ for (let i = 0; i < sensorNames.length; i++) {
+ result.success.push(sensorNames[i]);
}
observer.next(result);
observer.complete();
@@ -212,8 +212,8 @@
let sensorParserConfig1 = new SensorParserConfig();
let sensorParserConfig2 = new SensorParserConfig();
- sensorParserConfig1.sensorTopic = 'squid';
- sensorParserConfig2.sensorTopic = 'bro';
+ sensorParserConfigHistory1.sensorName = 'squid';
+ sensorParserConfigHistory2.sensorName = 'bro';
sensorParserConfigHistory1.config = sensorParserConfig1;
sensorParserConfigHistory2.config = sensorParserConfig2;
@@ -224,7 +224,7 @@
sensorParserStatus2.name = 'bro';
sensorParserStatus2.status = 'KILLED';
- sensorParserConfigHistoryService.setSensorParserConfigHistoryForTest([sensorParserConfigHistory1, sensorParserConfigHistory2]);
+ sensorParserConfigService.setSensorParserConfigForTest({'squid': sensorParserConfig1, 'bro': sensorParserConfig2});
stormService.setTopologyStatusForTest([sensorParserStatus1, sensorParserStatus2]);
let component: SensorParserListComponent = fixture.componentInstance;
@@ -233,8 +233,8 @@
component.ngOnInit();
- expect(component.sensors[0]).toEqual(sensorParserConfigHistory1);
- expect(component.sensors[1]).toEqual(sensorParserConfigHistory2);
+ expect(component.sensors[0].sensorName).toEqual(sensorParserConfigHistory1.sensorName);
+ expect(component.sensors[1].sensorName).toEqual(sensorParserConfigHistory2.sensorName);
expect(component.sensorsStatus[0]).toEqual(Object.assign(new TopologyStatus(), sensorParserStatus1));
expect(component.sensorsStatus[1]).toEqual(Object.assign(new TopologyStatus(), sensorParserStatus2));
expect(component.selectedSensors).toEqual([]);
@@ -270,9 +270,9 @@
let component: SensorParserListComponent = fixture.componentInstance;
- let sensorParserConfig1 = new SensorParserConfig();
- sensorParserConfig1.sensorTopic = 'squid';
- component.navigateToSensorEdit(sensorParserConfig1, event);
+ let sensorParserConfigHistory1 = new SensorParserConfigHistory();
+ sensorParserConfigHistory1.sensorName = 'squid';
+ component.navigateToSensorEdit(sensorParserConfigHistory1, event);
let expectStr = router.navigateByUrl['calls'].argsFor(0);
expect(expectStr).toEqual(['/sensors(dialog:sensors-config/squid)']);
@@ -353,27 +353,27 @@
it('onSensorRowSelect should change the url and updated the selected items stack', async(() => {
- let sensorParserConfig1 = new SensorParserConfig();
- sensorParserConfig1.sensorTopic = 'squid';
+ let sensorParserConfigHistory1 = new SensorParserConfigHistory();
+ sensorParserConfigHistory1.sensorName = 'squid';
let component: SensorParserListComponent = fixture.componentInstance;
let event = {target: {type: 'div', parentElement: {firstChild: {type: 'div'}}}};
- sensorParserConfigService.setSeletedSensor(sensorParserConfig1);
- component.onSensorRowSelect(sensorParserConfig1, event);
+ component.selectedSensor = sensorParserConfigHistory1;
+ component.onSensorRowSelect(sensorParserConfigHistory1, event);
- expect(sensorParserConfigService.getSelectedSensor()).toEqual(null);
+ expect(component.selectedSensor).toEqual(null);
- component.onSensorRowSelect(sensorParserConfig1, event);
+ component.onSensorRowSelect(sensorParserConfigHistory1, event);
- expect(sensorParserConfigService.getSelectedSensor()).toEqual(sensorParserConfig1);
+ expect(component.selectedSensor).toEqual(sensorParserConfigHistory1);
- sensorParserConfigService.setSeletedSensor(sensorParserConfig1);
+ component.selectedSensor = sensorParserConfigHistory1;
event = {target: {type: 'checkbox', parentElement: {firstChild: {type: 'div'}}}};
- component.onSensorRowSelect(sensorParserConfig1, event);
+ component.onSensorRowSelect(sensorParserConfigHistory1, event);
- expect(sensorParserConfigService.getSelectedSensor()).toEqual(sensorParserConfig1);
+ expect(component.selectedSensor).toEqual(sensorParserConfigHistory1);
fixture.destroy();
}));
@@ -409,8 +409,8 @@
let sensorParserConfig1 = new SensorParserConfig();
let sensorParserConfig2 = new SensorParserConfig();
- sensorParserConfig1.sensorTopic = 'squid';
- sensorParserConfig2.sensorTopic = 'bro';
+ sensorParserConfigHistory1.sensorName = 'squid';
+ sensorParserConfigHistory2.sensorName = 'bro';
sensorParserConfigHistory1.config = sensorParserConfig1;
sensorParserConfigHistory2.config = sensorParserConfig2;
@@ -421,7 +421,7 @@
expect(metronAlerts.showSuccessMessage).toHaveBeenCalled();
- component.deleteSensor(event, [sensorParserConfigHistory1.config]);
+ component.deleteSensor(event, [sensorParserConfigHistory1]);
expect(metronDialog.showConfirmationMessage).toHaveBeenCalled();
expect(metronDialog.showConfirmationMessage['calls'].count()).toEqual(2);
@@ -627,6 +627,7 @@
component.sensors = [
Object.assign(new SensorParserConfigHistory(), {
+ 'sensorName': 'abc',
'config': {
'parserClassName': 'org.apache.metron.parsers.GrokParser',
'sensorTopic': 'abc',
@@ -637,6 +638,7 @@
'modifiedByDate': '2016-11-25 09:09:12'
}),
Object.assign(new SensorParserConfigHistory(), {
+ 'sensorName': 'plm',
'config': {
'parserClassName': 'org.apache.metron.parsers.Bro',
'sensorTopic': 'plm',
@@ -647,6 +649,7 @@
'modifiedByDate': '2016-11-25 12:39:21'
}),
Object.assign(new SensorParserConfigHistory(), {
+ 'sensorName': 'xyz',
'config': {
'parserClassName': 'org.apache.metron.parsers.GrokParser',
'sensorTopic': 'xyz',
@@ -658,15 +661,15 @@
})
];
- component.onSort({sortBy: 'sensorTopic', sortOrder: Sort.ASC});
- expect(component.sensors[0].config.sensorTopic).toEqual('abc');
- expect(component.sensors[1].config.sensorTopic).toEqual('plm');
- expect(component.sensors[2].config.sensorTopic).toEqual('xyz');
+ component.onSort({sortBy: 'sensorName', sortOrder: Sort.ASC});
+ expect(component.sensors[0].sensorName).toEqual('abc');
+ expect(component.sensors[1].sensorName).toEqual('plm');
+ expect(component.sensors[2].sensorName).toEqual('xyz');
- component.onSort({sortBy: 'sensorTopic', sortOrder: Sort.DSC});
- expect(component.sensors[0].config.sensorTopic).toEqual('xyz');
- expect(component.sensors[1].config.sensorTopic).toEqual('plm');
- expect(component.sensors[2].config.sensorTopic).toEqual('abc');
+ component.onSort({sortBy: 'sensorName', sortOrder: Sort.DSC});
+ expect(component.sensors[0].sensorName).toEqual('xyz');
+ expect(component.sensors[1].sensorName).toEqual('plm');
+ expect(component.sensors[2].sensorName).toEqual('abc');
component.onSort({sortBy: 'parserClassName', sortOrder: Sort.ASC});
expect(component.sensors[0].config.parserClassName).toEqual('org.apache.metron.parsers.Bro');
@@ -695,6 +698,7 @@
component.sensors = [
Object.assign(new SensorParserConfigHistory(), {
+ 'sensorName': 'abc',
'config': {
'parserClassName': 'org.apache.metron.parsers.GrokParser',
'sensorTopic': 'abc',
diff --git a/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.ts b/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.ts
index ccc8aca..1129914 100644
--- a/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.ts
+++ b/metron-interface/metron-config/src/app/sensors/sensor-parser-list/sensor-parser-list.component.ts
@@ -41,6 +41,7 @@
count: number = 0;
sensors: SensorParserConfigHistory[] = [];
sensorsStatus: TopologyStatus[] = [];
+ selectedSensor: SensorParserConfigHistory;
selectedSensors: SensorParserConfigHistory[] = [];
enableAutoRefresh: boolean = true;
@@ -58,9 +59,15 @@
}
getSensors(justOnce: boolean) {
- this.sensorParserConfigHistoryService.getAll().subscribe(
- (results: SensorParserConfigHistory[]) => {
- this.sensors = results;
+ this.sensorParserConfigService.getAll().subscribe(
+ (results: {string: SensorParserConfig}) => {
+ this.sensors = [];
+ for (let sensorName of Object.keys(results)) {
+ let sensorParserConfigHistory = new SensorParserConfigHistory();
+ sensorParserConfigHistory.sensorName = sensorName;
+ sensorParserConfigHistory.config = results[sensorName];
+ this.sensors.push(sensorParserConfigHistory);
+ }
this.selectedSensors = [];
this.count = this.sensors.length;
if (!justOnce) {
@@ -76,12 +83,12 @@
onSort($event: SortEvent) {
switch ($event.sortBy) {
- case 'sensorTopic':
+ case 'sensorName':
this.sensors.sort((obj1: SensorParserConfigHistory, obj2: SensorParserConfigHistory) => {
if ($event.sortOrder === Sort.ASC) {
- return obj1.config[$event.sortBy].localeCompare(obj2.config[$event.sortBy]);
+ return obj1.sensorName.localeCompare(obj2.sensorName);
}
- return obj2.config[$event.sortBy].localeCompare(obj1.config[$event.sortBy]);
+ return obj2.sensorName.localeCompare(obj1.sensorName);
});
break;
case 'parserClassName':
@@ -139,7 +146,7 @@
for (let sensor of this.sensors) {
let status: TopologyStatus = this.sensorsStatus.find(status => {
- return status.name === sensor.config.sensorTopic;
+ return status.name === sensor.sensorName;
});
if (status) {
@@ -179,9 +186,9 @@
this.router.navigateByUrl('/sensors(dialog:sensors-config/new)');
}
- navigateToSensorEdit(selectedSensor: SensorParserConfig, event) {
- this.sensorParserConfigService.setSeletedSensor(selectedSensor);
- this.router.navigateByUrl('/sensors(dialog:sensors-config/' + selectedSensor.sensorTopic + ')');
+ navigateToSensorEdit(selectedSensor: SensorParserConfigHistory, event) {
+ this.selectedSensor = selectedSensor;
+ this.router.navigateByUrl('/sensors(dialog:sensors-config/' + selectedSensor.sensorName + ')');
event.stopPropagation();
}
@@ -207,31 +214,30 @@
}
}
- onSensorRowSelect(sensor: SensorParserConfig, $event) {
+ onSensorRowSelect(sensor: SensorParserConfigHistory, $event) {
if ($event.target.type !== 'checkbox' && $event.target.parentElement.firstChild.type !== 'checkbox') {
- if (this.sensorParserConfigService.getSelectedSensor() === sensor) {
- this.sensorParserConfigService.setSeletedSensor(null);
+ if (this.selectedSensor === sensor) {
+ this.selectedSensor = null;
this.router.navigateByUrl('/sensors');
return;
}
-
- this.sensorParserConfigService.setSeletedSensor(sensor);
- this.router.navigateByUrl('/sensors(dialog:sensors-readonly/' + sensor.sensorTopic + ')');
+ this.selectedSensor = sensor;
+ this.router.navigateByUrl('/sensors(dialog:sensors-readonly/' + sensor.sensorName + ')');
}
}
- deleteSensor($event, selectedSensorsToDelete: SensorParserConfig[]) {
+ deleteSensor($event, selectedSensorsToDelete: SensorParserConfigHistory[]) {
if ($event) {
$event.stopPropagation();
}
- let sensorNames = selectedSensorsToDelete.map(sensor => { return sensor.sensorTopic; });
+ let sensorNames = selectedSensorsToDelete.map(sensor => { return sensor.sensorName; });
let confirmationsMsg = 'Are you sure you want to delete sensor(s) ' + sensorNames.join(', ') + ' ?';
this.metronDialogBox.showConfirmationMessage(confirmationsMsg).subscribe(result => {
if (result) {
- this.sensorParserConfigService.deleteSensorParserConfigs(selectedSensorsToDelete)
+ this.sensorParserConfigService.deleteSensorParserConfigs(sensorNames)
.subscribe((deleteResult: {success: Array<string>, failure: Array<string>}) => {
if (deleteResult.success.length > 0) {
this.metronAlerts.showSuccessMessage('Deleted sensors: ' + deleteResult.success.join(', '));
@@ -246,10 +252,7 @@
}
onDeleteSensor() {
- let selectedSensorsToDelete = this.selectedSensors.map(info => {
- return info.config;
- });
- this.deleteSensor(null, selectedSensorsToDelete);
+ this.deleteSensor(null, this.selectedSensors);
}
onStopSensors() {
@@ -263,12 +266,12 @@
onStopSensor(sensor: SensorParserConfigHistory, event) {
this.toggleStartStopInProgress(sensor);
- this.stormService.stopParser(sensor.config.sensorTopic).subscribe(result => {
- this.metronAlerts.showSuccessMessage('Stopped sensor ' + sensor.config.sensorTopic);
+ this.stormService.stopParser(sensor.sensorName).subscribe(result => {
+ this.metronAlerts.showSuccessMessage('Stopped sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
},
error => {
- this.metronAlerts.showErrorMessage('Unable to stop sensor ' + sensor.config.sensorTopic);
+ this.metronAlerts.showErrorMessage('Unable to stop sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
});
@@ -288,17 +291,17 @@
onStartSensor(sensor: SensorParserConfigHistory, event) {
this.toggleStartStopInProgress(sensor);
- this.stormService.startParser(sensor.config.sensorTopic).subscribe(result => {
+ this.stormService.startParser(sensor.sensorName).subscribe(result => {
if (result['status'] === 'ERROR') {
- this.metronAlerts.showErrorMessage('Unable to start sensor ' + sensor.config.sensorTopic + ': ' + result['message']);
+ this.metronAlerts.showErrorMessage('Unable to start sensor ' + sensor.sensorName + ': ' + result['message']);
} else {
- this.metronAlerts.showSuccessMessage('Started sensor ' + sensor.config.sensorTopic);
+ this.metronAlerts.showSuccessMessage('Started sensor ' + sensor.sensorName);
}
this.toggleStartStopInProgress(sensor);
},
error => {
- this.metronAlerts.showErrorMessage('Unable to start sensor ' + sensor.config.sensorTopic);
+ this.metronAlerts.showErrorMessage('Unable to start sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
});
@@ -318,12 +321,12 @@
onDisableSensor(sensor: SensorParserConfigHistory, event) {
this.toggleStartStopInProgress(sensor);
- this.stormService.deactivateParser(sensor.config.sensorTopic).subscribe(result => {
- this.metronAlerts.showSuccessMessage('Disabled sensor ' + sensor.config.sensorTopic);
+ this.stormService.deactivateParser(sensor.sensorName).subscribe(result => {
+ this.metronAlerts.showSuccessMessage('Disabled sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
},
error => {
- this.metronAlerts.showErrorMessage('Unable to disable sensor ' + sensor.config.sensorTopic);
+ this.metronAlerts.showErrorMessage('Unable to disable sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
});
@@ -343,12 +346,12 @@
onEnableSensor(sensor: SensorParserConfigHistory, event) {
this.toggleStartStopInProgress(sensor);
- this.stormService.activateParser(sensor.config.sensorTopic).subscribe(result => {
- this.metronAlerts.showSuccessMessage('Enabled sensor ' + sensor.config.sensorTopic);
+ this.stormService.activateParser(sensor.sensorName).subscribe(result => {
+ this.metronAlerts.showSuccessMessage('Enabled sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
},
error => {
- this.metronAlerts.showErrorMessage('Unable to enabled sensor ' + sensor.config.sensorTopic);
+ this.metronAlerts.showErrorMessage('Unable to enabled sensor ' + sensor.sensorName);
this.toggleStartStopInProgress(sensor);
});
@@ -362,7 +365,7 @@
}
onNavigationStart() {
- this.sensorParserConfigService.setSeletedSensor(null);
+ this.selectedSensor = null;
this.selectedSensors = [];
}
}
diff --git a/metron-interface/metron-config/src/app/service/sensor-parser-config.service.spec.ts b/metron-interface/metron-config/src/app/service/sensor-parser-config.service.spec.ts
index bae4656..c42f127 100644
--- a/metron-interface/metron-config/src/app/service/sensor-parser-config.service.spec.ts
+++ b/metron-interface/metron-config/src/app/service/sensor-parser-config.service.spec.ts
@@ -93,7 +93,7 @@
it('post', async(inject([], () => {
mockBackend.connections.subscribe((c: MockConnection) => c.mockRespond(sensorParserConfigResponse));
- sensorParserConfigService.post(sensorParserConfig).subscribe(
+ sensorParserConfigService.post('bro', sensorParserConfig).subscribe(
result => {
expect(result).toEqual(sensorParserConfig);
}, error => console.log(error));
@@ -138,7 +138,7 @@
it('deleteSensorParserConfigs', async(inject([], () => {
mockBackend.connections.subscribe((c: MockConnection) => c.mockRespond(deleteResponse));
- sensorParserConfigService.deleteSensorParserConfigs([sensorParserConfig1, sensorParserConfig2]).subscribe(result => {
+ sensorParserConfigService.deleteSensorParserConfigs(['bro1', 'bro2']).subscribe(result => {
expect(result.success.length).toEqual(2);
});
})));
diff --git a/metron-interface/metron-config/src/app/service/sensor-parser-config.service.ts b/metron-interface/metron-config/src/app/service/sensor-parser-config.service.ts
index 25cd833..7f1afa2 100644
--- a/metron-interface/metron-config/src/app/service/sensor-parser-config.service.ts
+++ b/metron-interface/metron-config/src/app/service/sensor-parser-config.service.ts
@@ -31,15 +31,16 @@
defaultHeaders = {'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'};
selectedSensorParserConfig: SensorParserConfig;
- dataChangedSource = new Subject<SensorParserConfig[]>();
+ dataChangedSource = new Subject<string[]>();
dataChanged$ = this.dataChangedSource.asObservable();
constructor(private http: Http, @Inject(APP_CONFIG) private config: IAppConfig) {
}
- public post(sensorParserConfig: SensorParserConfig): Observable<SensorParserConfig> {
- return this.http.post(this.url, JSON.stringify(sensorParserConfig), new RequestOptions({headers: new Headers(this.defaultHeaders)}))
+ public post(name: string, sensorParserConfig: SensorParserConfig): Observable<SensorParserConfig> {
+ return this.http.post(this.url + '/' + name, JSON.stringify(sensorParserConfig),
+ new RequestOptions({headers: new Headers(this.defaultHeaders)}))
.map(HttpUtil.extractData)
.catch(HttpUtil.handleError);
}
@@ -50,7 +51,7 @@
.catch(HttpUtil.handleError);
}
- public getAll(): Observable<SensorParserConfig[]> {
+ public getAll(): Observable<{}> {
return this.http.get(this.url, new RequestOptions({headers: new Headers(this.defaultHeaders)}))
.map(HttpUtil.extractData)
.catch(HttpUtil.handleError);
@@ -73,7 +74,7 @@
.catch(HttpUtil.handleError);
}
- public deleteSensorParserConfigs(sensors: SensorParserConfig[]): Observable<{success: Array<string>, failure: Array<string>}> {
+ public deleteSensorParserConfigs(sensorNames: string[]): Observable<{success: Array<string>, failure: Array<string>}> {
let result: {success: Array<string>, failure: Array<string>} = {success: [], failure: []};
let observable = Observable.create((observer => {
@@ -83,18 +84,17 @@
observer.complete();
}
- this.dataChangedSource.next(sensors);
+ this.dataChangedSource.next(sensorNames);
};
-
- for (let i = 0; i < sensors.length; i++) {
- this.deleteSensorParserConfig(sensors[i].sensorTopic).subscribe(results => {
- result.success.push(sensors[i].sensorTopic);
- if (result.success.length + result.failure.length === sensors.length) {
+ for (let i = 0; i < sensorNames.length; i++) {
+ this.deleteSensorParserConfig(sensorNames[i]).subscribe(results => {
+ result.success.push(sensorNames[i]);
+ if (result.success.length + result.failure.length === sensorNames.length) {
completed();
}
}, error => {
- result.failure.push(sensors[i].sensorTopic);
- if (result.success.length + result.failure.length === sensors.length) {
+ result.failure.push(sensorNames[i]);
+ if (result.success.length + result.failure.length === sensorNames.length) {
completed();
}
});
@@ -105,12 +105,4 @@
return observable;
}
- public setSeletedSensor(sensor: SensorParserConfig): void {
- this.selectedSensorParserConfig = sensor;
- }
-
- public getSelectedSensor(): SensorParserConfig {
- return this.selectedSensorParserConfig;
- }
-
}
diff --git a/metron-interface/metron-rest/README.md b/metron-interface/metron-rest/README.md
index c9684a5..02cd946 100644
--- a/metron-interface/metron-rest/README.md
+++ b/metron-interface/metron-rest/README.md
@@ -581,10 +581,11 @@
* 200 - Returns SensorIndexingConfig
* 404 - SensorIndexingConfig is missing
-### `POST /api/v1/sensor/parser/config`
+### `POST /api/v1/sensor/parser/config/{name}`
* Description: Updates or creates a SensorParserConfig in Zookeeper
* Input:
* sensorParserConfig - SensorParserConfig
+ * name - SensorEnrichmentConfig name
* Returns:
* 200 - SensorParserConfig updated. Returns saved SensorParserConfig
* 201 - SensorParserConfig created. Returns saved SensorParserConfig
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/SensorParserConfigController.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/SensorParserConfigController.java
index 189e2af..ecbd034 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/SensorParserConfigController.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/controller/SensorParserConfigController.java
@@ -47,13 +47,13 @@
@ApiOperation(value = "Updates or creates a SensorParserConfig in Zookeeper")
@ApiResponses(value = { @ApiResponse(message = "SensorParserConfig updated. Returns saved SensorParserConfig", code = 200),
@ApiResponse(message = "SensorParserConfig created. Returns saved SensorParserConfig", code = 201) })
- @RequestMapping(method = RequestMethod.POST)
- ResponseEntity<SensorParserConfig> save(@ApiParam(name="sensorParserConfig", value="SensorParserConfig", required=true)@RequestBody SensorParserConfig sensorParserConfig) throws RestException {
- String name = sensorParserConfig.getSensorTopic();
+ @RequestMapping(value = "/{name}", method = RequestMethod.POST)
+ ResponseEntity<SensorParserConfig> save(@ApiParam(name="name", value="SensorParserConfig name", required=true)@PathVariable String name,
+ @ApiParam(name="sensorParserConfig", value="SensorParserConfig", required=true)@RequestBody SensorParserConfig sensorParserConfig) throws RestException {
if (sensorParserConfigService.findOne(name) == null) {
- return new ResponseEntity<>(sensorParserConfigService.save(sensorParserConfig), HttpStatus.CREATED);
+ return new ResponseEntity<>(sensorParserConfigService.save(name, sensorParserConfig), HttpStatus.CREATED);
} else {
- return new ResponseEntity<>(sensorParserConfigService.save(sensorParserConfig), HttpStatus.OK);
+ return new ResponseEntity<>(sensorParserConfigService.save(name, sensorParserConfig), HttpStatus.OK);
}
}
@@ -73,7 +73,7 @@
@ApiOperation(value = "Retrieves all SensorParserConfigs from Zookeeper")
@ApiResponse(message = "Returns all SensorParserConfigs", code = 200)
@RequestMapping(method = RequestMethod.GET)
- ResponseEntity<Iterable<SensorParserConfig>> findAll() throws RestException {
+ ResponseEntity<Map<String, SensorParserConfig>> findAll() throws RestException {
return new ResponseEntity<>(sensorParserConfigService.getAll(), HttpStatus.OK);
}
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/SensorParserConfigService.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/SensorParserConfigService.java
index 9b863b8..2389e09 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/SensorParserConfigService.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/SensorParserConfigService.java
@@ -27,11 +27,11 @@
public interface SensorParserConfigService {
- SensorParserConfig save(SensorParserConfig sensorParserConfig) throws RestException;
+ SensorParserConfig save(String name, SensorParserConfig sensorParserConfig) throws RestException;
SensorParserConfig findOne(String name) throws RestException;
- Iterable<SensorParserConfig> getAll() throws RestException;
+ Map<String, SensorParserConfig> getAll() throws RestException;
List<String> getAllTypes() throws RestException;
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImpl.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImpl.java
index 7e70344..c460e3c 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImpl.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImpl.java
@@ -69,9 +69,9 @@
@Override
- public SensorParserConfig save(SensorParserConfig sensorParserConfig) throws RestException {
+ public SensorParserConfig save(String name, SensorParserConfig sensorParserConfig) throws RestException {
try {
- ConfigurationsUtils.writeSensorParserConfigToZookeeper(sensorParserConfig.getSensorTopic(),
+ ConfigurationsUtils.writeSensorParserConfigToZookeeper(name,
objectMapper.writeValueAsString(sensorParserConfig).getBytes(), client);
} catch (Exception e) {
throw new RestException(e);
@@ -86,13 +86,13 @@
}
@Override
- public Iterable<SensorParserConfig> getAll() throws RestException {
- List<SensorParserConfig> sensorParserConfigs = new ArrayList<>();
+ public Map<String, SensorParserConfig> getAll() throws RestException {
+ Map<String, SensorParserConfig> sensorParserConfigs = new HashMap<>();
List<String> sensorNames = getAllTypes();
for (String name : sensorNames) {
SensorParserConfig config = findOne(name);
if(config != null) {
- sensorParserConfigs.add(config);
+ sensorParserConfigs.put(name, config);
}
}
return sensorParserConfigs;
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
index 88e5355..c9adac9 100644
--- a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
@@ -208,7 +208,7 @@
numFields.set(numFields.get() + 1);
}
}
- this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(squidJson))
+ this.mockMvc.perform(post(sensorParserConfigUrl + "/squidTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(squidJson))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(jsonPath("$.*", hasSize(numFields.get())))
@@ -242,18 +242,19 @@
this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
- .andExpect(jsonPath("$[?(@.parserClassName == 'org.apache.metron.parsers.GrokParser' &&" +
- "@.sensorTopic == 'squidTest' &&" +
- "@.parserConfig.grokPath == 'target/patterns/squidTest' &&" +
- "@.parserConfig.patternLabel == 'SQUIDTEST' &&" +
- "@.parserConfig.timestampField == 'timestamp' &&" +
- "@.fieldTransformations[0].transformation == 'STELLAR' &&" +
- "@.fieldTransformations[0].output[0] == 'full_hostname' &&" +
- "@.fieldTransformations[0].output[1] == 'domain_without_subdomains' &&" +
- "@.fieldTransformations[0].config.full_hostname == 'URL_TO_HOST(url)' &&" +
- "@.fieldTransformations[0].config.domain_without_subdomains == 'DOMAIN_REMOVE_SUBDOMAINS(full_hostname)')]").exists());
+ .andExpect(jsonPath("$.squidTest.*", hasSize(numFields.get())))
+ .andExpect(jsonPath("$.squidTest.parserClassName").value("org.apache.metron.parsers.GrokParser"))
+ .andExpect(jsonPath("$.squidTest.sensorTopic").value("squidTest"))
+ .andExpect(jsonPath("$.squidTest.parserConfig.grokPath").value("target/patterns/squidTest"))
+ .andExpect(jsonPath("$.squidTest.parserConfig.patternLabel").value("SQUIDTEST"))
+ .andExpect(jsonPath("$.squidTest.parserConfig.timestampField").value("timestamp"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].transformation").value("STELLAR"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].output[0]").value("full_hostname"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].output[1]").value("domain_without_subdomains"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].config.full_hostname").value("URL_TO_HOST(url)"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].config.domain_without_subdomains").value("DOMAIN_REMOVE_SUBDOMAINS(full_hostname)"));
- this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+ this.mockMvc.perform(post(sensorParserConfigUrl + "/broTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(jsonPath("$.*", hasSize(numFields.get())))
@@ -263,7 +264,7 @@
.andExpect(jsonPath("$.mergeMetadata").value("true"))
.andExpect(jsonPath("$.parserConfig").isEmpty());
- assertEventually(() -> this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+ assertEventually(() -> this.mockMvc.perform(post(sensorParserConfigUrl + "/broTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
.andExpect(jsonPath("$.*", hasSize(numFields.get())))
@@ -276,18 +277,24 @@
this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
- .andExpect(jsonPath("$[?(@.parserClassName == 'org.apache.metron.parsers.GrokParser' &&" +
- "@.sensorTopic == 'squidTest' &&" +
- "@.parserConfig.grokPath == 'target/patterns/squidTest' &&" +
- "@.parserConfig.patternLabel == 'SQUIDTEST' &&" +
- "@.parserConfig.timestampField == 'timestamp' &&" +
- "@.fieldTransformations[0].transformation == 'STELLAR' &&" +
- "@.fieldTransformations[0].output[0] == 'full_hostname' &&" +
- "@.fieldTransformations[0].output[1] == 'domain_without_subdomains' &&" +
- "@.fieldTransformations[0].config.full_hostname == 'URL_TO_HOST(url)' &&" +
- "@.fieldTransformations[0].config.domain_without_subdomains == 'DOMAIN_REMOVE_SUBDOMAINS(full_hostname)')]").exists())
- .andExpect(jsonPath("$[?(@.parserClassName == 'org.apache.metron.parsers.bro.BasicBroParser' && " +
- "@.sensorTopic == 'broTest')]").exists());
+ .andExpect(jsonPath("$.*", hasSize(2)))
+ .andExpect(jsonPath("$.squidTest.*", hasSize(numFields.get())))
+ .andExpect(jsonPath("$.squidTest.parserClassName").value("org.apache.metron.parsers.GrokParser"))
+ .andExpect(jsonPath("$.squidTest.sensorTopic").value("squidTest"))
+ .andExpect(jsonPath("$.squidTest.parserConfig.grokPath").value("target/patterns/squidTest"))
+ .andExpect(jsonPath("$.squidTest.parserConfig.patternLabel").value("SQUIDTEST"))
+ .andExpect(jsonPath("$.squidTest.parserConfig.timestampField").value("timestamp"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].transformation").value("STELLAR"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].output[0]").value("full_hostname"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].output[1]").value("domain_without_subdomains"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].config.full_hostname").value("URL_TO_HOST(url)"))
+ .andExpect(jsonPath("$.squidTest.fieldTransformations[0].config.domain_without_subdomains").value("DOMAIN_REMOVE_SUBDOMAINS(full_hostname)"))
+ .andExpect(jsonPath("$.broTest.parserClassName").value("org.apache.metron.parsers.bro.BasicBroParser"))
+ .andExpect(jsonPath("$.broTest.*", hasSize(numFields.get())))
+ .andExpect(jsonPath("$.broTest.sensorTopic").value("broTest"))
+ .andExpect(jsonPath("$.broTest.readMetadata").value("true"))
+ .andExpect(jsonPath("$.broTest.mergeMetadata").value("true"))
+ .andExpect(jsonPath("$.broTest.parserConfig").isEmpty());
this.mockMvc.perform(delete(sensorParserConfigUrl + "/squidTest").with(httpBasic(user,password)).with(csrf()))
.andExpect(status().isOk());
@@ -306,8 +313,8 @@
this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
- .andExpect(jsonPath("$[?(@.sensorTopic == 'squidTest')]").doesNotExist())
- .andExpect(jsonPath("$[?(@.sensorTopic == 'broTest')]").exists());
+ .andExpect(jsonPath("$.squidTest").doesNotExist())
+ .andExpect(jsonPath("$.broTest").exists());
this.mockMvc.perform(delete(sensorParserConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
.andExpect(status().isOk());
@@ -318,8 +325,8 @@
this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
- .andExpect(jsonPath("$[?(@.sensorTopic == 'squidTest')]").doesNotExist())
- .andExpect(jsonPath("$[?(@.sensorTopic == 'broTest')]").doesNotExist());
+ .andExpect(jsonPath("$.squidTest").doesNotExist())
+ .andExpect(jsonPath("$.broTest").doesNotExist());
this.mockMvc.perform(get(sensorParserConfigUrl + "/list/available").with(httpBasic(user,password)))
.andExpect(status().isOk())
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java
index a04444d..9a6022c 100644
--- a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java
@@ -185,7 +185,7 @@
SensorParserConfig sensorParserConfig = new SensorParserConfig();
sensorParserConfig.setParserClassName("org.apache.metron.parsers.bro.BasicBroParser");
sensorParserConfig.setSensorTopic("broTest");
- sensorParserConfigService.save(sensorParserConfig);
+ sensorParserConfigService.save("broTest", sensorParserConfig);
{
final SensorParserConfig expectedSensorParserConfig = sensorParserConfig;
//we must wait for the config to find its way into the config.
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImplTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImplTest.java
index 7998c21..e6163c0 100644
--- a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImplTest.java
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/impl/SensorParserConfigServiceImplTest.java
@@ -202,9 +202,9 @@
when(cache.get( eq(ParserConfigurations.class)))
.thenReturn(configs);
- assertEquals(new ArrayList() {{
- add(getTestBroSensorParserConfig());
- add(getTestSquidSensorParserConfig());
+ assertEquals(new HashMap() {{
+ put("bro", getTestBroSensorParserConfig());
+ put("squid", getTestSquidSensorParserConfig());
}}, sensorParserConfigService.getAll());
}
@@ -219,7 +219,7 @@
final SensorParserConfig sensorParserConfig = new SensorParserConfig();
sensorParserConfig.setSensorTopic("bro");
- sensorParserConfigService.save(sensorParserConfig);
+ sensorParserConfigService.save("bro", sensorParserConfig);
}
@Test
@@ -232,7 +232,7 @@
when(setDataBuilder.forPath(ConfigurationType.PARSER.getZookeeperRoot() + "/bro", broJson.getBytes())).thenReturn(new Stat());
when(curatorFramework.setData()).thenReturn(setDataBuilder);
- assertEquals(getTestBroSensorParserConfig(), sensorParserConfigService.save(sensorParserConfig));
+ assertEquals(getTestBroSensorParserConfig(), sensorParserConfigService.save("bro", sensorParserConfig));
verify(setDataBuilder).forPath(eq(ConfigurationType.PARSER.getZookeeperRoot() + "/bro"), eq(broJson.getBytes()));
}