,
+ ) {}
+
+ onCloseClick() {
+ this.dialogRef.close();
+ }
+}
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.html b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.html
new file mode 100644
index 00000000..6bb4b4ce
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.html
@@ -0,0 +1,42 @@
+Packet filters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.scss b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.scss
new file mode 100644
index 00000000..4048e8c8
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.scss
@@ -0,0 +1,59 @@
+.item {
+ height: 25px;
+ font-size: 10pt;
+ margin-bottom: 10px;
+}
+
+.item-name {
+ margin-bottom: 10px;
+}
+
+.item-value {
+ width: 100%;
+ margin-bottom: 10px;
+}
+
+.input-field {
+ width: 100%;
+ margin-top: 10px;
+}
+
+.divider {
+ width: fit-content;
+ flex: 1 1 auto;
+}
+
+.input-color {
+ padding: 0px;
+ border-width: 0px;
+ width: 100%;
+ background-color: transparent;
+ outline: none;
+}
+
+input:focus {
+ outline: none;
+}
+
+input[type="color"] {
+ -webkit-appearance: none;
+ border: none;
+ height: 25px;
+}
+
+input[type="color"]::-webkit-color-swatch-wrapper {
+ padding: 0;
+}
+
+input[type="color"]::-webkit-color-swatch {
+ border: none;
+}
+
+.modal-form-container {
+ display: flex;
+ flex-direction: column;
+}
+
+.modal-form-container > * {
+ width: 100%;
+}
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.spec.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts
new file mode 100644
index 00000000..19cf6e7f
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/packet-filters/packet-filters.component.ts
@@ -0,0 +1,96 @@
+import { Component, OnInit } from '@angular/core';
+import { Link } from '../../../../models/link';
+import { Server } from '../../../../models/server';
+import { Project } from '../../../../models/project';
+import { MatDialogRef, MatDialog } from '@angular/material';
+import { LinkService } from '../../../../services/link.service';
+import { FilterDescription } from '../../../../models/filter-description';
+import { HelpDialogComponent } from '../../help-dialog/help-dialog.component';
+import { Message } from '../../../../models/message';
+import { Filter } from '../../../../models/filter';
+
+@Component({
+ selector: 'app-packet-filters',
+ templateUrl: './packet-filters.component.html',
+ styleUrls: ['./packet-filters.component.scss']
+})
+export class PacketFiltersDialogComponent implements OnInit{
+ server: Server;
+ project: Project;
+ link: Link;
+ filters: Filter;
+ availableFilters: FilterDescription[];
+
+ constructor(
+ private dialogRef: MatDialogRef,
+ private linkService: LinkService,
+ private dialog: MatDialog
+ ) {}
+
+ ngOnInit(){
+ this.linkService.getLink(this.server, this.link.project_id, this.link.link_id).subscribe((link: Link) => {
+ this.link = link;
+ this.filters = {
+ bpf: [],
+ corrupt: [0],
+ delay: [0, 0],
+ frequency_drop: [0],
+ packet_loss: [0]
+ };
+
+ if (this.link.filters) {
+ this.filters.bpf = this.link.filters.bpf ? this.link.filters.bpf : [];
+ this.filters.corrupt = this.link.filters.corrupt ? this.link.filters.corrupt : [0];
+ this.filters.delay = this.link.filters.delay ? this.link.filters.delay : [0, 0];
+ this.filters.frequency_drop = this.link.filters.frequency_drop ? this.link.filters.frequency_drop : [0];
+ this.filters.packet_loss = this.link.filters.packet_loss ? this.link.filters.packet_loss : [0];
+ }
+ });
+
+ this.linkService.getAvailableFilters(this.server, this.link).subscribe((availableFilters: FilterDescription[]) => {
+ this.availableFilters = availableFilters;
+ });
+ }
+
+ onNoClick() {
+ this.dialogRef.close();
+ }
+
+ onResetClick() {
+ this.link.filters = {
+ bpf: [],
+ corrupt: [0],
+ delay: [0, 0],
+ frequency_drop: [0],
+ packet_loss: [0]
+ };
+
+ this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => {
+ this.dialogRef.close();
+ });
+ }
+
+ onYesClick() {
+ this.link.filters = this.filters;
+ this.linkService.updateLink(this.server, this.link).subscribe((link: Link) => {
+ this.dialogRef.close();
+ });
+ }
+
+ onHelpClick() {
+ const dialogRef = this.dialog.open(HelpDialogComponent, {
+ width: '500px',
+ autoFocus: false
+ });
+ let instance = dialogRef.componentInstance;
+ instance.title = 'Help for filters';
+ let messages: Message[] = [];
+ this.availableFilters.forEach((filter: FilterDescription) => {
+ messages.push({
+ name: filter.name,
+ description: filter.description
+ });
+ });
+ instance.messages = messages;
+ }
+}
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.html b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.html
new file mode 100644
index 00000000..22a2a4af
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.html
@@ -0,0 +1,24 @@
+Packet capture
+
+
+
+
+
+ {{type[0]}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.scss b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.spec.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts
new file mode 100644
index 00000000..13314544
--- /dev/null
+++ b/src/app/components/project-map/packet-capturing/start-capture/start-capture.component.ts
@@ -0,0 +1,56 @@
+import { Component, OnInit } from '@angular/core';
+import { Server } from '../../../../models/server';
+import { Link } from '../../../../models/link';
+import { MatDialogRef } from '@angular/material';
+import { PacketFiltersDialogComponent } from '../packet-filters/packet-filters.component';
+import { LinkService } from '../../../../services/link.service';
+import { CapturingSettings } from '../../../../models/capturingSettings';
+
+@Component({
+ selector: 'app-start-capture',
+ templateUrl: './start-capture.component.html',
+ styleUrls: ['./start-capture.component.scss']
+})
+export class StartCaptureDialogComponent implements OnInit {
+ server: Server;
+ link: Link;
+ linkTypes = [];
+
+ linkType: string;
+ fileName: string;
+
+ constructor(
+ private dialogRef: MatDialogRef,
+ private linkService: LinkService
+ ) {}
+
+ ngOnInit() {
+ if (this.link.link_type === 'ethernet') {
+ this.linkTypes = [
+ ["Ethernet", "DLT_EN10MB"]
+ ];
+ } else {
+ this.linkTypes = [
+ ["Cisco HDLC", "DLT_C_HDLC"],
+ ["Cisco PPP", "DLT_PPP_SERIAL"],
+ ["Frame Relay", "DLT_FRELAY"],
+ ["ATM", "DLT_ATM_RFC1483"]
+ ];
+ }
+ }
+
+ onYesClick() {
+ let captureSettings: CapturingSettings = {
+ capture_file_name: this.fileName,
+ data_link_type: this.linkType
+ };
+
+ this.linkService.startCaptureOnLink(this.server, this.link, captureSettings).subscribe(() => {
+ this.dialogRef.close();
+ });
+ }
+
+ onNoClick() {
+ this.dialogRef.close();
+ }
+}
diff --git a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts
index 78a806b8..a346e751 100644
--- a/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts
+++ b/src/app/components/snapshots/snapshot-menu-item/snapshot-menu-item.component.ts
@@ -48,11 +48,6 @@ export class SnapshotMenuItemComponent implements OnInit {
(created_snapshot: Snapshot) => {
this.toaster.success(`Snapshot '${snapshot.name}' has been created.`);
progress.close();
- },
- response => {
- const error = response.json();
- this.toaster.error(`Cannot create snapshot: ${error.message}`);
- progress.close();
}
);
diff --git a/src/app/material.imports.ts b/src/app/material.imports.ts
index 9dc2260b..fdc33412 100644
--- a/src/app/material.imports.ts
+++ b/src/app/material.imports.ts
@@ -19,7 +19,8 @@ import {
MatTooltipModule,
MatStepperModule,
MatRadioModule,
- MatGridListModule
+ MatGridListModule,
+ MatTabsModule
} from '@angular/material';
export const MATERIAL_IMPORTS = [
@@ -43,5 +44,6 @@ export const MATERIAL_IMPORTS = [
MatTooltipModule,
MatStepperModule,
MatRadioModule,
- MatGridListModule
+ MatGridListModule,
+ MatTabsModule
];
diff --git a/src/app/models/capturingSettings.ts b/src/app/models/capturingSettings.ts
new file mode 100644
index 00000000..7cf85ba8
--- /dev/null
+++ b/src/app/models/capturingSettings.ts
@@ -0,0 +1,4 @@
+export class CapturingSettings {
+ capture_file_name: string;
+ data_link_type: string;
+}
diff --git a/src/app/models/filter-description.ts b/src/app/models/filter-description.ts
new file mode 100644
index 00000000..77238e27
--- /dev/null
+++ b/src/app/models/filter-description.ts
@@ -0,0 +1,14 @@
+export class FilterDescription {
+ description: string;
+ name: string;
+ parameters: Parameter[];
+ type: string;
+}
+
+interface Parameter {
+ maximum?: number;
+ minimum?: number;
+ name: string;
+ type: string;
+ unit?: string;
+}
diff --git a/src/app/models/filter.ts b/src/app/models/filter.ts
new file mode 100644
index 00000000..5a27c67a
--- /dev/null
+++ b/src/app/models/filter.ts
@@ -0,0 +1,7 @@
+export class Filter {
+ bpf?: string[];
+ corrupt?: number[];
+ delay?: number[];
+ frequency_drop?: number[];
+ packet_loss?: number[];
+}
diff --git a/src/app/models/link.ts b/src/app/models/link.ts
index d33d3845..afa7dc47 100644
--- a/src/app/models/link.ts
+++ b/src/app/models/link.ts
@@ -1,10 +1,12 @@
import { Node } from '../cartography/models/node';
import { LinkNode } from './link-node';
+import { Filter } from './filter';
export class Link {
capture_file_name: string;
capture_file_path: string;
capturing: boolean;
+ filters?: Filter;
link_id: string;
link_type: string;
nodes: LinkNode[];
diff --git a/src/app/models/message.ts b/src/app/models/message.ts
new file mode 100644
index 00000000..3d21b1cc
--- /dev/null
+++ b/src/app/models/message.ts
@@ -0,0 +1,4 @@
+export class Message {
+ name?: string;
+ description: string;
+}
diff --git a/src/app/services/link.service.ts b/src/app/services/link.service.ts
index 37d2ebfa..89735923 100644
--- a/src/app/services/link.service.ts
+++ b/src/app/services/link.service.ts
@@ -7,16 +7,13 @@ import { HttpServer } from './http-server.service';
import { Port } from '../models/port';
import { Link } from '../models/link';
import { LinkNode } from '../models/link-node';
+import { FilterDescription } from '../models/filter-description';
+import { CapturingSettings } from '../models/capturingSettings';
@Injectable()
export class LinkService {
constructor(private httpServer: HttpServer) {}
- deleteLink(server: Server, link: Link) {
- //return this.httpServer.delete(server, `/compute/projects/${link.project_id}/vpcs/nodes/${link.nodes[0].node_id}/adapters/0/ports/0/nio`)
- return this.httpServer.delete(server, `/projects/${link.project_id}/links/${link.link_id}`)
- }
-
createLink(server: Server, source_node: Node, source_port: Port, target_node: Node, target_port: Port) {
return this.httpServer.post(server, `/projects/${source_node.project_id}/links`, {
nodes: [
@@ -34,6 +31,22 @@ export class LinkService {
});
}
+ getLink(server: Server, projectId: string, linkId: string) {
+ return this.httpServer.get(server, `/projects/${projectId}/links/${linkId}`);
+ }
+
+ deleteLink(server: Server, link: Link) {
+ return this.httpServer.delete(server, `/projects/${link.project_id}/links/${link.link_id}`)
+ }
+
+ updateLink(server: Server, link: Link) {
+ return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, link);
+ }
+
+ getAvailableFilters(server: Server, link: Link) {
+ return this.httpServer.get(server, `/projects/${link.project_id}/links/${link.link_id}/available_filters`);
+ }
+
updateNodes(server: Server, link: Link, nodes: LinkNode[]) {
const requestNodes = nodes.map(linkNode => {
return {
@@ -52,4 +65,16 @@ export class LinkService {
return this.httpServer.put(server, `/projects/${link.project_id}/links/${link.link_id}`, { nodes: requestNodes });
}
+
+ startCaptureOnLink(server: Server, link: Link, settings: CapturingSettings) {
+ return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/start_capture`, settings);
+ }
+
+ stopCaptureOnLink(server: Server, link: Link) {
+ return this.httpServer.post(server, `/projects/${link.project_id}/links/${link.link_id}/stop_capture`, {});
+ }
+
+ streamPcap(server: Server, link: Link) {
+ return this.httpServer.get(server, `/projects/${link.project_id}/links/${link.link_id}/pcap`)
+ }
}