mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2024-12-23 14:52:22 +00:00
Merge pull request #504 from GNS3/node-configurator
Configurators for nodes & template preferences for TraceNG & Qemu image creator
This commit is contained in:
commit
b55d5ff59f
@ -53,6 +53,10 @@ import { CopyIouTemplateComponent } from './components/preferences/ios-on-unix/c
|
|||||||
import { ListOfSnapshotsComponent } from './components/snapshots/list-of-snapshots/list-of-snapshots.component';
|
import { ListOfSnapshotsComponent } from './components/snapshots/list-of-snapshots/list-of-snapshots.component';
|
||||||
import { ConsoleComponent } from './components/settings/console/console.component';
|
import { ConsoleComponent } from './components/settings/console/console.component';
|
||||||
import { HelpComponent } from './components/help/help.component';
|
import { HelpComponent } from './components/help/help.component';
|
||||||
|
import { TracengPreferencesComponent } from './components/preferences/traceng/traceng-preferences/traceng-preferences.component';
|
||||||
|
import { TracengTemplatesComponent } from './components/preferences/traceng/traceng-templates/traceng-templates.component';
|
||||||
|
import { AddTracengTemplateComponent } from './components/preferences/traceng/add-traceng/add-traceng-template.component';
|
||||||
|
import { TracengTemplateDetailsComponent } from './components/preferences/traceng/traceng-template-details/traceng-template-details.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -111,6 +115,11 @@ const routes: Routes = [
|
|||||||
{ path: 'server/:server_id/preferences/vmware/templates/:template_id', component: VmwareTemplateDetailsComponent },
|
{ path: 'server/:server_id/preferences/vmware/templates/:template_id', component: VmwareTemplateDetailsComponent },
|
||||||
{ path: 'server/:server_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent },
|
{ path: 'server/:server_id/preferences/vmware/addtemplate', component: AddVmwareTemplateComponent },
|
||||||
|
|
||||||
|
// { path: 'server/:server_id/preferences/traceng', component: TracengPreferencesComponent },
|
||||||
|
// { path: 'server/:server_id/preferences/traceng/templates', component: TracengTemplatesComponent },
|
||||||
|
// { path: 'server/:server_id/preferences/traceng/templates/:template_id', component: TracengTemplateDetailsComponent },
|
||||||
|
// { path: 'server/:server_id/preferences/traceng/addtemplate', component: AddTracengTemplateComponent },
|
||||||
|
|
||||||
{ path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent },
|
{ path: 'server/:server_id/preferences/docker/templates', component: DockerTemplatesComponent },
|
||||||
{ path: 'server/:server_id/preferences/docker/templates/:template_id', component: DockerTemplateDetailsComponent },
|
{ path: 'server/:server_id/preferences/docker/templates/:template_id', component: DockerTemplateDetailsComponent },
|
||||||
{ path: 'server/:server_id/preferences/docker/templates/:template_id/copy', component: CopyDockerTemplateComponent },
|
{ path: 'server/:server_id/preferences/docker/templates/:template_id/copy', component: CopyDockerTemplateComponent },
|
||||||
|
@ -211,6 +211,30 @@ import { ProjectsFilter } from './filters/projectsFilter.pipe';
|
|||||||
import { ComputeService } from './services/compute.service';
|
import { ComputeService } from './services/compute.service';
|
||||||
import { ReloadNodeActionComponent } from './components/project-map/context-menu/actions/reload-node-action/reload-node-action.component';
|
import { ReloadNodeActionComponent } from './components/project-map/context-menu/actions/reload-node-action/reload-node-action.component';
|
||||||
import { SuspendNodeActionComponent } from './components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component';
|
import { SuspendNodeActionComponent } from './components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component';
|
||||||
|
import { ConfigActionComponent } from './components/project-map/context-menu/actions/config-action/config-action.component';
|
||||||
|
import { ConfiguratorDialogVpcsComponent } from './components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component';
|
||||||
|
import { ConfiguratorDialogEthernetHubComponent } from './components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component';
|
||||||
|
import { ConfiguratorDialogEthernetSwitchComponent } from './components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component';
|
||||||
|
import { PortsComponent } from './components/preferences/common/ports/ports.component';
|
||||||
|
import { ConfiguratorDialogSwitchComponent } from './components/project-map/node-editors/configurator/switch/configurator-switch.component';
|
||||||
|
import { ConfiguratorDialogVirtualBoxComponent } from './components/project-map/node-editors/configurator/virtualbox/configurator-virtualbox.component';
|
||||||
|
import { CustomAdaptersTableComponent } from './components/preferences/common/custom-adapters-table/custom-adapters-table.component';
|
||||||
|
import { ConfiguratorDialogQemuComponent } from './components/project-map/node-editors/configurator/qemu/configurator-qemu.component';
|
||||||
|
import { ConfiguratorDialogCloudComponent } from './components/project-map/node-editors/configurator/cloud/configurator-cloud.component';
|
||||||
|
import { UdpTunnelsComponent } from './components/preferences/common/udp-tunnels/udp-tunnels.component';
|
||||||
|
import { ConfiguratorDialogAtmSwitchComponent } from './components/project-map/node-editors/configurator/atm_switch/configurator-atm-switch.component';
|
||||||
|
import { ConfiguratorDialogVmwareComponent } from './components/project-map/node-editors/configurator/vmware/configurator-vmware.component';
|
||||||
|
import { ConfiguratorDialogIouComponent } from './components/project-map/node-editors/configurator/iou/configurator-iou.component';
|
||||||
|
import { ConfiguratorDialogIosComponent } from './components/project-map/node-editors/configurator/ios/configurator-ios.component';
|
||||||
|
import { ConfiguratorDialogDockerComponent } from './components/project-map/node-editors/configurator/docker/configurator-docker.component';
|
||||||
|
import { ConfiguratorDialogNatComponent } from './components/project-map/node-editors/configurator/nat/configurator-nat.component';
|
||||||
|
import { ConfiguratorDialogTracengComponent } from './components/project-map/node-editors/configurator/traceng/configurator-traceng.component';
|
||||||
|
import { AddTracengTemplateComponent } from './components/preferences/traceng/add-traceng/add-traceng-template.component';
|
||||||
|
import { TracengPreferencesComponent } from './components/preferences/traceng/traceng-preferences/traceng-preferences.component';
|
||||||
|
import { TracengTemplatesComponent } from './components/preferences/traceng/traceng-templates/traceng-templates.component';
|
||||||
|
import { TracengService } from './services/traceng.service';
|
||||||
|
import { TracengTemplateDetailsComponent } from './components/preferences/traceng/traceng-template-details/traceng-template-details.component';
|
||||||
|
import { QemuImageCreatorComponent } from './components/project-map/node-editors/configurator/qemu/qemu-image-creator/qemu-image-creator.component';
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||||
@ -349,7 +373,30 @@ if (environment.production) {
|
|||||||
ChangeSymbolActionComponent,
|
ChangeSymbolActionComponent,
|
||||||
EditProjectDialogComponent,
|
EditProjectDialogComponent,
|
||||||
ReloadNodeActionComponent,
|
ReloadNodeActionComponent,
|
||||||
SuspendNodeActionComponent
|
SuspendNodeActionComponent,
|
||||||
|
ConfigActionComponent,
|
||||||
|
ConfiguratorDialogVpcsComponent,
|
||||||
|
ConfiguratorDialogEthernetHubComponent,
|
||||||
|
ConfiguratorDialogEthernetSwitchComponent,
|
||||||
|
PortsComponent,
|
||||||
|
ConfiguratorDialogSwitchComponent,
|
||||||
|
ConfiguratorDialogVirtualBoxComponent,
|
||||||
|
CustomAdaptersTableComponent,
|
||||||
|
ConfiguratorDialogQemuComponent,
|
||||||
|
ConfiguratorDialogCloudComponent,
|
||||||
|
UdpTunnelsComponent,
|
||||||
|
ConfiguratorDialogAtmSwitchComponent,
|
||||||
|
ConfiguratorDialogVmwareComponent,
|
||||||
|
ConfiguratorDialogIouComponent,
|
||||||
|
ConfiguratorDialogIosComponent,
|
||||||
|
ConfiguratorDialogDockerComponent,
|
||||||
|
ConfiguratorDialogNatComponent,
|
||||||
|
ConfiguratorDialogTracengComponent,
|
||||||
|
AddTracengTemplateComponent,
|
||||||
|
TracengPreferencesComponent,
|
||||||
|
TracengTemplatesComponent,
|
||||||
|
TracengTemplateDetailsComponent,
|
||||||
|
QemuImageCreatorComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
@ -428,7 +475,8 @@ if (environment.production) {
|
|||||||
RotationValidator,
|
RotationValidator,
|
||||||
MapSettingsService,
|
MapSettingsService,
|
||||||
InfoService,
|
InfoService,
|
||||||
ComputeService
|
ComputeService,
|
||||||
|
TracengService
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
AddServerDialogComponent,
|
AddServerDialogComponent,
|
||||||
@ -449,7 +497,22 @@ if (environment.production) {
|
|||||||
SaveProjectDialogComponent,
|
SaveProjectDialogComponent,
|
||||||
InfoDialogComponent,
|
InfoDialogComponent,
|
||||||
ChangeSymbolDialogComponent,
|
ChangeSymbolDialogComponent,
|
||||||
EditProjectDialogComponent
|
EditProjectDialogComponent,
|
||||||
|
ConfiguratorDialogVpcsComponent,
|
||||||
|
ConfiguratorDialogEthernetHubComponent,
|
||||||
|
ConfiguratorDialogEthernetSwitchComponent,
|
||||||
|
ConfiguratorDialogSwitchComponent,
|
||||||
|
ConfiguratorDialogVirtualBoxComponent,
|
||||||
|
ConfiguratorDialogQemuComponent,
|
||||||
|
ConfiguratorDialogCloudComponent,
|
||||||
|
ConfiguratorDialogAtmSwitchComponent,
|
||||||
|
ConfiguratorDialogVmwareComponent,
|
||||||
|
ConfiguratorDialogIouComponent,
|
||||||
|
ConfiguratorDialogIosComponent,
|
||||||
|
ConfiguratorDialogDockerComponent,
|
||||||
|
ConfiguratorDialogNatComponent,
|
||||||
|
ConfiguratorDialogTracengComponent,
|
||||||
|
QemuImageCreatorComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@ -1,12 +1,71 @@
|
|||||||
import { Label } from './label';
|
import { Label } from './label';
|
||||||
import { Port } from '../../models/port';
|
import { Port } from '../../models/port';
|
||||||
|
import { CustomAdapter } from '../../models/qemu/qemu-custom-adapter';
|
||||||
|
|
||||||
|
export class PortsMapping {
|
||||||
|
name: string;
|
||||||
|
interface?: string;
|
||||||
|
port_number: number;
|
||||||
|
type?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Properties {
|
||||||
|
adapter_type: string;
|
||||||
|
adapters: number;
|
||||||
|
headless: boolean;
|
||||||
|
linked_clone: boolean;
|
||||||
|
on_close: string;
|
||||||
|
ram: number;
|
||||||
|
nvram: number;
|
||||||
|
usage: string;
|
||||||
|
use_any_adapter: boolean;
|
||||||
|
vmname: string;
|
||||||
|
ports_mapping: PortsMapping[];
|
||||||
|
mappings: any;
|
||||||
|
bios_image: string;
|
||||||
|
bios_image_md5sum?: any;
|
||||||
|
boot_priority: string;
|
||||||
|
cdrom_image: string;
|
||||||
|
cdrom_image_md5sum?: any;
|
||||||
|
cpu_throttling: number;
|
||||||
|
cpus: number;
|
||||||
|
hda_disk_image: string;
|
||||||
|
hda_disk_image_md5sum: string;
|
||||||
|
hda_disk_interface: string;
|
||||||
|
hdb_disk_image: string;
|
||||||
|
hdb_disk_image_md5sum?: any;
|
||||||
|
hdb_disk_interface: string;
|
||||||
|
hdc_disk_image: string;
|
||||||
|
hdc_disk_image_md5sum?: any;
|
||||||
|
hdc_disk_interface: string;
|
||||||
|
hdd_disk_image: string;
|
||||||
|
hdd_disk_image_md5sum?: any;
|
||||||
|
hdd_disk_interface: string;
|
||||||
|
initrd: string;
|
||||||
|
initrd_md5sum?: any;
|
||||||
|
kernel_command_line: string;
|
||||||
|
kernel_image: string;
|
||||||
|
kernel_image_md5sum?: any;
|
||||||
|
legacy_networking: boolean;
|
||||||
|
mac_address: string;
|
||||||
|
options: string;
|
||||||
|
platform: string;
|
||||||
|
process_priority: string;
|
||||||
|
qemu_path: string;
|
||||||
|
environment: string;
|
||||||
|
extra_hosts: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class Node {
|
export class Node {
|
||||||
command_line: string;
|
command_line: string;
|
||||||
compute_id: string;
|
compute_id: string;
|
||||||
console: number;
|
console: number;
|
||||||
|
console_auto_start: boolean;
|
||||||
console_host: string;
|
console_host: string;
|
||||||
console_type: string;
|
console_type: string;
|
||||||
|
custom_adapters?: CustomAdapter[];
|
||||||
|
ethernet_adapters?: any;
|
||||||
|
serial_adapters?: any;
|
||||||
first_port_name: string;
|
first_port_name: string;
|
||||||
height: number;
|
height: number;
|
||||||
label: Label;
|
label: Label;
|
||||||
@ -18,6 +77,7 @@ export class Node {
|
|||||||
port_segment_size: number;
|
port_segment_size: number;
|
||||||
ports: Port[];
|
ports: Port[];
|
||||||
project_id: string;
|
project_id: string;
|
||||||
|
properties: Properties;
|
||||||
status: string;
|
status: string;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
symbol_url: string; // @TODO: full URL to symbol, move to MapNode once converters are moved to app module
|
symbol_url: string; // @TODO: full URL to symbol, move to MapNode once converters are moved to app module
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
placeholder="Ethernet interface"
|
placeholder="Ethernet interface"
|
||||||
[ngModelOptions]="{standalone: true}"
|
[ngModelOptions]="{standalone: true}"
|
||||||
[(ngModel)]="ethernetInterface">
|
[(ngModel)]="ethernetInterface">
|
||||||
<mat-option *ngFor="let type of " [value]="type">
|
<mat-option *ngFor="let type of ethernetInterfaces" [value]="type">
|
||||||
{{type}}
|
{{type}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
@ -57,69 +57,13 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
<mat-expansion-panel *ngIf="newPort">
|
<mat-expansion-panel>
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title>
|
<mat-panel-title>
|
||||||
Port settings
|
Port settings
|
||||||
</mat-panel-title>
|
</mat-panel-title>
|
||||||
</mat-expansion-panel-header>
|
</mat-expansion-panel-header>
|
||||||
<table class="table" mat-table [dataSource]="dataSource">
|
<app-ports #ports [ethernetPorts]="ethernetSwitchTemplate.ports_mapping"></app-ports>
|
||||||
<ng-container matColumnDef="port_number">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Port number </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.port_number}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="vlan">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> VLAN </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.vlan}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="type">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Type </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.type}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="ethertype">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> EtherType </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{element.ethertype}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table><br/>
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<input
|
|
||||||
matInput type="number"
|
|
||||||
[(ngModel)]="newPort.port_number"
|
|
||||||
placeholder="Port">
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="form-field">
|
|
||||||
<input
|
|
||||||
matInput type="number"
|
|
||||||
[(ngModel)]="newPort.vlan"
|
|
||||||
placeholder="VLAN">
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="select">
|
|
||||||
<mat-select
|
|
||||||
placeholder="Type"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
[(ngModel)]="newPort.type">
|
|
||||||
<mat-option *ngFor="let type of portTypes" [value]="type">
|
|
||||||
{{type}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<mat-form-field class="select">
|
|
||||||
<mat-select
|
|
||||||
placeholder="EtherType"
|
|
||||||
[ngModelOptions]="{standalone: true}"
|
|
||||||
[(ngModel)]="newPort.ethertype">
|
|
||||||
<mat-option *ngFor="let type of etherTypes" [value]="type">
|
|
||||||
{{type}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
<button mat-button class="form-field" (click)="onAdd()">Add</button>
|
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</mat-accordion>
|
</mat-accordion>
|
||||||
<div class="buttons-bar">
|
<div class="buttons-bar">
|
||||||
|
@ -17,6 +17,7 @@ import { BuiltInTemplatesService } from '../../../../../services/built-in-templa
|
|||||||
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
import { EthernetSwitchesTemplateDetailsComponent } from './ethernet-switches-template-details.component';
|
import { EthernetSwitchesTemplateDetailsComponent } from './ethernet-switches-template-details.component';
|
||||||
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
import { PortsComponent } from '../../../common/ports/ports.component';
|
||||||
|
|
||||||
export class MockedBuiltInTemplatesService {
|
export class MockedBuiltInTemplatesService {
|
||||||
public getTemplate(server: Server, template_id: string) {
|
public getTemplate(server: Server, template_id: string) {
|
||||||
@ -68,6 +69,7 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => {
|
|||||||
|
|
||||||
it('should call save template', () => {
|
it('should call save template', () => {
|
||||||
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
|
component.portsComponent = {ethernetPorts: []} as PortsComponent;
|
||||||
component.inputForm.controls['templateName'].setValue('template name');
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
component.inputForm.controls['defaultName'].setValue('default name');
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
component.inputForm.controls['symbol'].setValue('symbol');
|
component.inputForm.controls['symbol'].setValue('symbol');
|
||||||
@ -102,7 +104,7 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => {
|
|||||||
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call save template when symbol path is empty', () => {
|
it('should not call save template when symbol path is empty', () => {
|
||||||
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate));
|
||||||
component.inputForm.controls['templateName'].setValue('template name');
|
component.inputForm.controls['templateName'].setValue('template name');
|
||||||
component.inputForm.controls['defaultName'].setValue('default name');
|
component.inputForm.controls['defaultName'].setValue('default name');
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ServerService } from '../../../../../services/server.service';
|
import { ServerService } from '../../../../../services/server.service';
|
||||||
import { Server } from '../../../../../models/server';
|
import { Server } from '../../../../../models/server';
|
||||||
@ -6,8 +6,8 @@ import { ToasterService } from '../../../../../services/toaster.service';
|
|||||||
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service';
|
||||||
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template';
|
||||||
import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity';
|
|
||||||
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
import { PortsComponent } from '../../../common/ports/ports.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -16,20 +16,13 @@ import { BuiltInTemplatesConfigurationService } from '../../../../../services/bu
|
|||||||
styleUrls: ['./ethernet-switches-template-details.component.scss', '../../../preferences.component.scss']
|
styleUrls: ['./ethernet-switches-template-details.component.scss', '../../../preferences.component.scss']
|
||||||
})
|
})
|
||||||
export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
||||||
|
@ViewChild(PortsComponent, {static: false}) portsComponent: PortsComponent;
|
||||||
server: Server;
|
server: Server;
|
||||||
ethernetSwitchTemplate: EthernetSwitchTemplate;
|
ethernetSwitchTemplate: EthernetSwitchTemplate;
|
||||||
inputForm: FormGroup;
|
inputForm: FormGroup;
|
||||||
ethernetPorts: PortsMappingEntity[] = [];
|
|
||||||
dataSource: PortsMappingEntity[] = [];
|
|
||||||
newPort: PortsMappingEntity;
|
|
||||||
|
|
||||||
isSymbolSelectionOpened: boolean = false;
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
categories = [];
|
categories = [];
|
||||||
consoleTypes: string[] = [];
|
consoleTypes: string[] = [];
|
||||||
portTypes: string[] = [];
|
|
||||||
etherTypes: string[] = [];
|
|
||||||
displayedColumns: string[] = ['port_number', 'vlan', 'type', 'ethertype'];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -45,11 +38,6 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
|||||||
defaultName: new FormControl('', Validators.required),
|
defaultName: new FormControl('', Validators.required),
|
||||||
symbol: new FormControl('', Validators.required)
|
symbol: new FormControl('', Validators.required)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.newPort = {
|
|
||||||
name: '',
|
|
||||||
port_number: 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -61,8 +49,6 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
|||||||
this.getConfiguration();
|
this.getConfiguration();
|
||||||
this.builtInTemplatesService.getTemplate(this.server, template_id).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => {
|
this.builtInTemplatesService.getTemplate(this.server, template_id).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => {
|
||||||
this.ethernetSwitchTemplate = ethernetSwitchTemplate;
|
this.ethernetSwitchTemplate = ethernetSwitchTemplate;
|
||||||
this.ethernetPorts = this.ethernetSwitchTemplate.ports_mapping;
|
|
||||||
this.dataSource = this.ethernetSwitchTemplate.ports_mapping;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -70,18 +56,6 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
|||||||
getConfiguration() {
|
getConfiguration() {
|
||||||
this.categories = this.builtInTemplatesConfigurationService.getCategoriesForEthernetSwitches();
|
this.categories = this.builtInTemplatesConfigurationService.getCategoriesForEthernetSwitches();
|
||||||
this.consoleTypes = this.builtInTemplatesConfigurationService.getConsoleTypesForEthernetSwitches();
|
this.consoleTypes = this.builtInTemplatesConfigurationService.getConsoleTypesForEthernetSwitches();
|
||||||
this.portTypes = this.builtInTemplatesConfigurationService.getPortTypesForEthernetSwitches();
|
|
||||||
this.etherTypes = this.builtInTemplatesConfigurationService.getEtherTypesForEthernetSwitches();
|
|
||||||
}
|
|
||||||
|
|
||||||
onAdd() {
|
|
||||||
this.ethernetPorts.push(this.newPort);
|
|
||||||
this.dataSource = [...this.ethernetPorts];
|
|
||||||
|
|
||||||
this.newPort = {
|
|
||||||
name: '',
|
|
||||||
port_number: 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goBack() {
|
goBack() {
|
||||||
@ -92,6 +66,7 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit {
|
|||||||
if (this.inputForm.invalid) {
|
if (this.inputForm.invalid) {
|
||||||
this.toasterService.error(`Fill all required fields`);
|
this.toasterService.error(`Fill all required fields`);
|
||||||
} else {
|
} else {
|
||||||
|
this.ethernetSwitchTemplate.ports_mapping = this.portsComponent.ethernetPorts;
|
||||||
this.builtInTemplatesService.saveTemplate(this.server, this.ethernetSwitchTemplate).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => {
|
this.builtInTemplatesService.saveTemplate(this.server, this.ethernetSwitchTemplate).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => {
|
||||||
this.toasterService.success("Changes saved");
|
this.toasterService.success("Changes saved");
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
<table class="table" mat-table [dataSource]="adapters">
|
||||||
|
<ng-container matColumnDef="adapter_number">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Adapter number </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> Adapter {{element.adapter_number}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="port_name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port name </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> Ethernet {{element.adapter_number}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="adapter_type">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Adapter type </th>
|
||||||
|
<td mat-cell *matCellDef="let element; let i = index;">
|
||||||
|
<mat-select placeholder="Type" [(ngModel)]="element.adapter_type">
|
||||||
|
<mat-option *ngFor="let type of networkTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button matTooltip="Delete adapter" (click)="delete(element)">
|
||||||
|
<mat-icon aria-label="Delete adapter">delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
<button mat-button class="form-field" (click)="onAdd()">Add</button>
|
@ -0,0 +1,28 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-custom-adapters-table',
|
||||||
|
templateUrl: './custom-adapters-table.component.html',
|
||||||
|
styleUrls: ['../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class CustomAdaptersTableComponent {
|
||||||
|
@Input() networkTypes = [];
|
||||||
|
@Input() displayedColumns: string[] = [];
|
||||||
|
@Input() adapters: CustomAdapter[] = [];
|
||||||
|
|
||||||
|
public numberOfAdapters: number;
|
||||||
|
|
||||||
|
onAdd() {
|
||||||
|
let adapter: CustomAdapter = {
|
||||||
|
adapter_number: this.adapters.length,
|
||||||
|
adapter_type: this.networkTypes[0]
|
||||||
|
}
|
||||||
|
this.adapters = this.adapters.concat([adapter]);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(adapter: CustomAdapter) {
|
||||||
|
this.adapters = this.adapters.filter(elem => elem!== adapter);
|
||||||
|
}
|
||||||
|
}
|
@ -6,31 +6,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="default-content">
|
<div class="default-content">
|
||||||
<div class="container mat-elevation-z8">
|
<div class="container mat-elevation-z8">
|
||||||
<table class="table" mat-table [dataSource]="adapters">
|
<app-custom-adapters-table
|
||||||
<ng-container matColumnDef="adapter_number">
|
#customAdapters
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter number </th>
|
[networkTypes]="networkTypes"
|
||||||
<td mat-cell *matCellDef="let element"> Adapter {{element.adapter_number}} </td>
|
[displayedColumns]="displayedColumns"
|
||||||
</ng-container>
|
[adapters]="adapters"
|
||||||
|
></app-custom-adapters-table>
|
||||||
<ng-container matColumnDef="port_name">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Port name </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> Ethernet {{element.adapter_number}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="adapter_type">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> Adapter type </th>
|
|
||||||
<td mat-cell *matCellDef="let element; let i = index;">
|
|
||||||
<mat-select placeholder="Type" [(ngModel)]="adapters[i].adapter_type">
|
|
||||||
<mat-option *ngFor="let type of networkTypes" [value]="type[0]">
|
|
||||||
{{type[1]}} ({{type[0]}})
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons-bar">
|
<div class="buttons-bar">
|
||||||
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
<button mat-button (click)="cancelConfigureCustomAdapters()">Cancel</button>
|
||||||
|
@ -4,6 +4,7 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { CustomAdaptersComponent } from './custom-adapters.component';
|
import { CustomAdaptersComponent } from './custom-adapters.component';
|
||||||
|
import { CustomAdaptersTableComponent } from '../custom-adapters-table/custom-adapters-table.component';
|
||||||
|
|
||||||
describe('Custom adapters component', () => {
|
describe('Custom adapters component', () => {
|
||||||
let component: CustomAdaptersComponent;
|
let component: CustomAdaptersComponent;
|
||||||
@ -31,6 +32,7 @@ describe('Custom adapters component', () => {
|
|||||||
|
|
||||||
it('should emit event when apply clicked', () => {
|
it('should emit event when apply clicked', () => {
|
||||||
spyOn(component.saveConfigurationEmitter, 'emit');
|
spyOn(component.saveConfigurationEmitter, 'emit');
|
||||||
|
component.customAdapters = {adapters: []} as CustomAdaptersTableComponent;
|
||||||
|
|
||||||
component.configureCustomAdapters();
|
component.configureCustomAdapters();
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
||||||
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
import { CustomAdapter } from '../../../../models/qemu/qemu-custom-adapter';
|
||||||
|
import { CustomAdaptersTableComponent } from '../custom-adapters-table/custom-adapters-table.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -13,14 +14,30 @@ export class CustomAdaptersComponent {
|
|||||||
@Output() closeConfiguratorEmitter = new EventEmitter<boolean>();
|
@Output() closeConfiguratorEmitter = new EventEmitter<boolean>();
|
||||||
@Output() saveConfigurationEmitter = new EventEmitter<CustomAdapter[]>();
|
@Output() saveConfigurationEmitter = new EventEmitter<CustomAdapter[]>();
|
||||||
|
|
||||||
|
@ViewChild("customAdapters", {static: false}) customAdapters: CustomAdaptersTableComponent;
|
||||||
|
|
||||||
public adapters: CustomAdapter[];
|
public adapters: CustomAdapter[];
|
||||||
public numberOfAdapters: number;
|
public numberOfAdapters: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
console.log(this.networkTypes);
|
||||||
|
}
|
||||||
|
|
||||||
cancelConfigureCustomAdapters(){
|
cancelConfigureCustomAdapters(){
|
||||||
this.closeConfiguratorEmitter.emit(false);
|
this.closeConfiguratorEmitter.emit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
configureCustomAdapters(){
|
configureCustomAdapters(){
|
||||||
|
this.adapters = [];
|
||||||
|
console.log(this.customAdapters);
|
||||||
|
|
||||||
|
this.customAdapters.adapters.forEach(n => {
|
||||||
|
this.adapters.push({
|
||||||
|
adapter_number: n.adapter_number,
|
||||||
|
adapter_type: n.adapter_type
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
this.saveConfigurationEmitter.emit(this.adapters);
|
this.saveConfigurationEmitter.emit(this.adapters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
<table class="table" mat-table [dataSource]="ethernetPorts">
|
||||||
|
<ng-container matColumnDef="port_number">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port number </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.port_number}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="vlan">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> VLAN </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.vlan}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="type">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.type}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="ethertype">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> EtherType </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.ethertype}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="action">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
||||||
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.port_number"
|
||||||
|
placeholder="Port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.vlan"
|
||||||
|
placeholder="VLAN">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="newPort.type">
|
||||||
|
<mat-option *ngFor="let type of portTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="EtherType"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="newPort.ethertype">
|
||||||
|
<mat-option *ngFor="let type of etherTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAdd()">Add</button>
|
@ -0,0 +1,48 @@
|
|||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { PortsMappingEntity } from '../../../../models/ethernetHub/ports-mapping-enity';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ports',
|
||||||
|
templateUrl: './ports.component.html',
|
||||||
|
styleUrls: ['../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class PortsComponent implements OnInit {
|
||||||
|
@Input() ethernetPorts: PortsMappingEntity[] = [];
|
||||||
|
newPort: PortsMappingEntity = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
portTypes: string[] = [];
|
||||||
|
etherTypes: string[] = [];
|
||||||
|
displayedColumns: string[] = ['port_number', 'vlan', 'type', 'ethertype', 'action'];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.etherTypes = this.builtInTemplatesConfigurationService.getEtherTypesForEthernetSwitches();
|
||||||
|
this.portTypes = this.builtInTemplatesConfigurationService.getPortTypesForEthernetSwitches();
|
||||||
|
}
|
||||||
|
|
||||||
|
onAdd() {
|
||||||
|
this.ethernetPorts.push(this.newPort);
|
||||||
|
|
||||||
|
this.newPort = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(port: PortsMappingEntity) {
|
||||||
|
this.ethernetPorts = this.ethernetPorts.filter(n => n !== port);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<table *ngIf="dataSourceUdp.length" class="table" mat-table [dataSource]="dataSourceUdp">
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="rport">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Local port </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.rport}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="rhost">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Type </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.rhost}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="lport">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Remote port </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.lport}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="action">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
||||||
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
<br *ngIf="dataSourceUdp.length"/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="newPort.name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.lport"
|
||||||
|
placeholder="Local port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="newPort.rhost"
|
||||||
|
placeholder="Remote host">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="newPort.rport"
|
||||||
|
placeholder="Remote port">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAddUdpInterface()">Add</button>
|
@ -0,0 +1,47 @@
|
|||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { PortsMappingEntity } from '../../../../models/ethernetHub/ports-mapping-enity';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../services/built-in-templates-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-udp-tunnels',
|
||||||
|
templateUrl: './udp-tunnels.component.html',
|
||||||
|
styleUrls: ['../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class UdpTunnelsComponent implements OnInit {
|
||||||
|
@Input() dataSourceUdp: PortsMappingEntity[] = [];
|
||||||
|
displayedColumns: string[] = ['name', 'lport', 'rhost', 'rport', 'action'];
|
||||||
|
newPort: PortsMappingEntity = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
portTypes: string[] = [];
|
||||||
|
etherTypes: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.etherTypes = this.builtInTemplatesConfigurationService.getEtherTypesForEthernetSwitches();
|
||||||
|
this.portTypes = this.builtInTemplatesConfigurationService.getPortTypesForEthernetSwitches();
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddUdpInterface() {
|
||||||
|
this.dataSourceUdp = this.dataSourceUdp.concat([this.newPort]);
|
||||||
|
|
||||||
|
this.newPort = {
|
||||||
|
name: '',
|
||||||
|
port_number: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(port: PortsMappingEntity) {
|
||||||
|
this.dataSourceUdp = this.dataSourceUdp.filter(n => n !== port);
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,9 @@
|
|||||||
<mat-list-item routerLink="/server/{{serverId}}/preferences/docker/templates">
|
<mat-list-item routerLink="/server/{{serverId}}/preferences/docker/templates">
|
||||||
Docker
|
Docker
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
|
<!-- <mat-list-item routerLink="/server/{{serverId}}/preferences/traceng/templates">
|
||||||
|
TraceNG
|
||||||
|
</mat-list-item> -->
|
||||||
</mat-nav-list>
|
</mat-nav-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,7 +31,7 @@ export class QemuVmTemplateDetailsComponent implements OnInit {
|
|||||||
binaries: QemuBinary[] = [];
|
binaries: QemuBinary[] = [];
|
||||||
activateCpuThrottling: boolean = true;
|
activateCpuThrottling: boolean = true;
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
generalSettingsForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
@ViewChild("customAdaptersConfigurator", {static: false})
|
@ViewChild("customAdaptersConfigurator", {static: false})
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">New VPCS node template</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="templateNameForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="templateName" type="text" placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="ipAddress" type="text" placeholder="IP address">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button mat-button class="cancel-button" (click)="goBack()">Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="addTemplate()">Add template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,67 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { TemplateMocksService } from '../../../../services/template-mocks.service';
|
||||||
|
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
|
import { TracengService } from '../../../../services/traceng.service';
|
||||||
|
import { TracengTemplate } from '../../../../models/templates/traceng-template';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-traceng-template',
|
||||||
|
templateUrl: './add-traceng-template.component.html',
|
||||||
|
styleUrls: ['./add-traceng-template.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class AddTracengTemplateComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
templateName: string = '';
|
||||||
|
ipAddress: string = '';
|
||||||
|
templateNameForm: FormGroup
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private tracengService: TracengService,
|
||||||
|
private router: Router,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private templateMocksService: TemplateMocksService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.templateNameForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl(null, [Validators.required]),
|
||||||
|
ipAddress: new FormControl(null, [Validators.required])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'traceng', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate() {
|
||||||
|
if (!this.templateNameForm.invalid) {
|
||||||
|
this.templateName = this.templateNameForm.get('templateName').value;
|
||||||
|
this.ipAddress = this.templateNameForm.get('ipAddress').value;
|
||||||
|
let tracengTemplate: TracengTemplate = this.templateMocksService.getTracengTemplate();
|
||||||
|
|
||||||
|
tracengTemplate.template_id = uuid();
|
||||||
|
tracengTemplate.name = this.templateName;
|
||||||
|
tracengTemplate.ip_address = this.ipAddress;
|
||||||
|
|
||||||
|
this.tracengService.addTemplate(this.server, tracengTemplate).subscribe(() => {
|
||||||
|
this.goBack();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">TraceNG preferences</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" [(ngModel)]="tracengExecutable" placeholder="Path to TraceNG executable"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
.form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-traceng-preferences',
|
||||||
|
templateUrl: './traceng-preferences.component.html',
|
||||||
|
styleUrls: ['./traceng-preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class TracengPreferencesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
tracengExecutable: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreDefaults(){
|
||||||
|
this.tracengExecutable = '';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
<div class="content" [ngClass]="{ shadowed: isSymbolSelectionOpened }">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">TraceNG device configuration</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="default-content" *ngIf="tracengTemplate">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="tracengTemplate.name"
|
||||||
|
formControlName="templateName"
|
||||||
|
placeholder="Template name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="tracengTemplate.default_name_format"
|
||||||
|
formControlName="defaultName"
|
||||||
|
placeholder="Default name format">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="tracengTemplate.symbol"
|
||||||
|
formControlName="symbol"
|
||||||
|
placeholder="Symbol">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="symbolSelectionButton" (click)="chooseSymbol()">Choose symbol</button><br/><br/>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
<div class="buttons-bar">
|
||||||
|
<button class="cancel-button" (click)="goBack()" mat-button>Cancel</button>
|
||||||
|
<button mat-raised-button color="primary" (click)="onSave()">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-symbols-menu *ngIf="isSymbolSelectionOpened && tracengTemplate" [server]="server" [symbol]="tracengTemplate.symbol" (symbolChangedEmitter)="symbolChanged($event)"></app-symbols-menu>
|
@ -0,0 +1,71 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ToasterService } from '../../../../services/toaster.service';
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { TracengService } from '../../../../services/traceng.service';
|
||||||
|
import { TracengTemplate } from '../../../../models/templates/traceng-template';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-traceng-template-details',
|
||||||
|
templateUrl: './traceng-template-details.component.html',
|
||||||
|
styleUrls: ['./traceng-template-details.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class TracengTemplateDetailsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
tracengTemplate: TracengTemplate;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
isSymbolSelectionOpened: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private tracengService: TracengService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
templateName: new FormControl('', Validators.required),
|
||||||
|
defaultName: new FormControl('', Validators.required),
|
||||||
|
symbol: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
const template_id = this.route.snapshot.paramMap.get("template_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.tracengService.getTemplate(this.server, template_id).subscribe((tracengTemplate: TracengTemplate) => {
|
||||||
|
this.tracengTemplate = tracengTemplate;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.router.navigate(['/server', this.server.id, 'preferences', 'traceng', 'templates']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSave() {
|
||||||
|
if (this.inputForm.invalid) {
|
||||||
|
this.toasterService.error(`Fill all required fields`);
|
||||||
|
} else {
|
||||||
|
this.tracengService.saveTemplate(this.server, this.tracengTemplate).subscribe((tracengTemplate: TracengTemplate) => {
|
||||||
|
this.toasterService.success("Changes saved");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chooseSymbol() {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
symbolChanged(chosenSymbol: string) {
|
||||||
|
this.isSymbolSelectionOpened = !this.isSymbolSelectionOpened;
|
||||||
|
this.tracengTemplate.symbol = chosenSymbol;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<div class="content">
|
||||||
|
<div class="default-header">
|
||||||
|
<div class="row">
|
||||||
|
<h1 class="col">TraceNG node templates</h1>
|
||||||
|
<button *ngIf="server" class="top-button" class="cancel-button" routerLink="/server/{{server.id}}/preferences" mat-button>Back</button>
|
||||||
|
<button *ngIf="server" class="top-button" routerLink="/server/{{server.id}}/preferences/traceng/addtemplate" mat-raised-button color="primary">Add TraceNG template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-empty-templates-list *ngIf="!tracengTemplates.length"></app-empty-templates-list>
|
||||||
|
<div class="default-content" *ngIf="tracengTemplates.length">
|
||||||
|
<div class="listcontainer mat-elevation-z8">
|
||||||
|
<mat-nav-list *ngIf="server">
|
||||||
|
<div class="list-item" *ngFor='let template of tracengTemplates'>
|
||||||
|
<mat-list-item class="template-name" routerLink="{{template.template_id}}">{{template.name}}</mat-list-item>
|
||||||
|
<button mat-button class="menu-button" [matMenuTriggerFor]="menu">
|
||||||
|
<mat-icon>more_vert</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #menu="matMenu">
|
||||||
|
<button mat-menu-item (click)="deleteTemplate(template)">
|
||||||
|
<mat-icon>delete</mat-icon><span>Delete</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</div>
|
||||||
|
</mat-nav-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-delete-template
|
||||||
|
#deleteComponent
|
||||||
|
[server]="server"
|
||||||
|
(deleteEvent)="onDeleteEvent()">
|
||||||
|
</app-delete-template>
|
@ -0,0 +1,46 @@
|
|||||||
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
|
import { Server } from '../../../../models/server';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ServerService } from '../../../../services/server.service';
|
||||||
|
import { DeleteTemplateComponent } from '../../common/delete-template-component/delete-template.component';
|
||||||
|
import { TracengTemplate } from '../../../../models/templates/traceng-template';
|
||||||
|
import { TracengService } from '../../../../services/traceng.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-traceng-templates',
|
||||||
|
templateUrl: './traceng-templates.component.html',
|
||||||
|
styleUrls: ['./traceng-templates.component.scss', '../../preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class TracengTemplatesComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
tracengTemplates: TracengTemplate[] = [];
|
||||||
|
@ViewChild(DeleteTemplateComponent, {static: false}) deleteComponent: DeleteTemplateComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private tracengService: TracengService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const server_id = this.route.snapshot.paramMap.get("server_id");
|
||||||
|
this.serverService.get(parseInt(server_id, 10)).then((server: Server) => {
|
||||||
|
this.server = server;
|
||||||
|
this.getTemplates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplates() {
|
||||||
|
this.tracengService.getTemplates(this.server).subscribe((tracengTemplates: TracengTemplate[]) => {
|
||||||
|
this.tracengTemplates = tracengTemplates.filter((elem) => elem.template_type === 'traceng' && !elem.builtin);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteTemplate(template: TracengTemplate) {
|
||||||
|
this.deleteComponent.deleteItem(template.name, template.template_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteEvent() {
|
||||||
|
this.getTemplates();
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ export class VirtualBoxTemplateDetailsComponent implements OnInit {
|
|||||||
onCloseOptions = [];
|
onCloseOptions = [];
|
||||||
categories = [];
|
categories = [];
|
||||||
networkTypes = [];
|
networkTypes = [];
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
generalSettingsForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
networkForm: FormGroup
|
networkForm: FormGroup
|
||||||
|
@ -20,7 +20,7 @@ export class VmwareTemplateDetailsComponent implements OnInit {
|
|||||||
server: Server;
|
server: Server;
|
||||||
vmwareTemplate: VmwareTemplate;
|
vmwareTemplate: VmwareTemplate;
|
||||||
generalSettingsForm: FormGroup;
|
generalSettingsForm: FormGroup;
|
||||||
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type'];
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
isConfiguratorOpened: boolean = false;
|
isConfiguratorOpened: boolean = false;
|
||||||
isSymbolSelectionOpened: boolean = false;
|
isSymbolSelectionOpened: boolean = false;
|
||||||
consoleTypes: string[] = [];
|
consoleTypes: string[] = [];
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
<button mat-menu-item (click)="configureNode()">
|
||||||
|
<mat-icon>settings_applications</mat-icon>
|
||||||
|
<span>Configure</span>
|
||||||
|
</button>
|
@ -0,0 +1,71 @@
|
|||||||
|
import { Component, Input, OnInit, OnChanges } from '@angular/core';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { MatDialog, MatDialogRef } from '@angular/material';
|
||||||
|
import { ConfiguratorDialogVpcsComponent } from '../../../node-editors/configurator/vpcs/configurator-vpcs.component';
|
||||||
|
import { ConfiguratorDialogEthernetHubComponent } from '../../../node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component';
|
||||||
|
import { ConfiguratorDialogEthernetSwitchComponent } from '../../../node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component';
|
||||||
|
import { ConfiguratorDialogSwitchComponent } from '../../../node-editors/configurator/switch/configurator-switch.component';
|
||||||
|
import { ConfiguratorDialogVirtualBoxComponent } from '../../../node-editors/configurator/virtualbox/configurator-virtualbox.component';
|
||||||
|
import { ConfiguratorDialogQemuComponent } from '../../../node-editors/configurator/qemu/configurator-qemu.component';
|
||||||
|
import { ConfiguratorDialogCloudComponent } from '../../../node-editors/configurator/cloud/configurator-cloud.component';
|
||||||
|
import { ConfiguratorDialogAtmSwitchComponent } from '../../../node-editors/configurator/atm_switch/configurator-atm-switch.component';
|
||||||
|
import { ConfiguratorDialogVmwareComponent } from '../../../node-editors/configurator/vmware/configurator-vmware.component';
|
||||||
|
import { ConfiguratorDialogIouComponent } from '../../../node-editors/configurator/iou/configurator-iou.component';
|
||||||
|
import { ConfiguratorDialogIosComponent } from '../../../node-editors/configurator/ios/configurator-ios.component';
|
||||||
|
import { ConfiguratorDialogDockerComponent } from '../../../node-editors/configurator/docker/configurator-docker.component';
|
||||||
|
import { ConfiguratorDialogNatComponent } from '../../../node-editors/configurator/nat/configurator-nat.component';
|
||||||
|
import { ConfiguratorDialogTracengComponent } from '../../../node-editors/configurator/traceng/configurator-traceng.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-config-node-action',
|
||||||
|
templateUrl: './config-action.component.html'
|
||||||
|
})
|
||||||
|
export class ConfigActionComponent {
|
||||||
|
@Input() server: Server;
|
||||||
|
@Input() node: Node;
|
||||||
|
private conf = {
|
||||||
|
autoFocus: false,
|
||||||
|
width: '800px'
|
||||||
|
};
|
||||||
|
dialogRef;
|
||||||
|
|
||||||
|
constructor(private dialog: MatDialog) {}
|
||||||
|
|
||||||
|
configureNode() {
|
||||||
|
if (this.node.node_type === 'vpcs') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogVpcsComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'ethernet_hub') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogEthernetHubComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'ethernet_switch') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogEthernetSwitchComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'cloud') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogCloudComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'dynamips') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogIosComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'iou') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogIouComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'qemu') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogQemuComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'virtualbox') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogVirtualBoxComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'vmware') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogVmwareComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'docker') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogDockerComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'nat') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogNatComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'frame_relay_switch') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogSwitchComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'atm_switch') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogAtmSwitchComponent, this.conf);
|
||||||
|
} else if (this.node.node_type === 'traceng') {
|
||||||
|
this.dialogRef = this.dialog.open(ConfiguratorDialogTracengComponent, this.conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
let instance = this.dialogRef.componentInstance;
|
||||||
|
instance.server = this.server;
|
||||||
|
instance.node = this.node;
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,10 @@
|
|||||||
[server]="server"
|
[server]="server"
|
||||||
[node]="nodes[0]"
|
[node]="nodes[0]"
|
||||||
></app-show-node-action>
|
></app-show-node-action>
|
||||||
|
<app-config-node-action *ngIf="nodes.length===1"
|
||||||
|
[server]="server"
|
||||||
|
[node]="nodes[0]"
|
||||||
|
></app-config-node-action>
|
||||||
<app-start-node-action *ngIf="nodes.length && labels.length===0" [server]="server" [nodes]="nodes"></app-start-node-action>
|
<app-start-node-action *ngIf="nodes.length && labels.length===0" [server]="server" [nodes]="nodes"></app-start-node-action>
|
||||||
<app-suspend-node-action *ngIf="nodes.length && labels.length===0" [server]="server" [nodes]="nodes"></app-suspend-node-action>
|
<app-suspend-node-action *ngIf="nodes.length && labels.length===0" [server]="server" [nodes]="nodes"></app-suspend-node-action>
|
||||||
<app-stop-node-action *ngIf="nodes.length && labels.length===0" [server]="server" [nodes]="nodes"></app-stop-node-action>
|
<app-stop-node-action *ngIf="nodes.length && labels.length===0" [server]="server" [nodes]="nodes"></app-stop-node-action>
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card>
|
||||||
|
<table *ngIf="nodeMappingsDataSource.length" class="table" mat-table [dataSource]="nodeMappingsDataSource">
|
||||||
|
<ng-container matColumnDef="portIn">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port : VPI : VCI </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.portIn}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="portOut">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port : VPI : VCI </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.portOut}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
||||||
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table><br/>
|
||||||
|
|
||||||
|
<form [formGroup]="nameForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<mat-checkbox [(ngModel)]="useVpiOnly">
|
||||||
|
Use VPI only (VP tunnel)
|
||||||
|
</mat-checkbox>
|
||||||
|
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
Source
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="sourcePort"
|
||||||
|
formControlName="sourcePort"
|
||||||
|
placeholder="Port">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<form [formGroup]="abstractForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="sourceVpi"
|
||||||
|
formControlName="sourceVpi"
|
||||||
|
placeholder="VPI">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="sourceVci"
|
||||||
|
formControlName="sourceVci"
|
||||||
|
placeholder="VCI">
|
||||||
|
</mat-form-field>
|
||||||
|
Destination
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="destinationPort"
|
||||||
|
formControlName="destinationPort"
|
||||||
|
placeholder="Port">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<form [formGroup]="abstractForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="destinationVpi"
|
||||||
|
formControlName="destinationVpi"
|
||||||
|
placeholder="VPI">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="destinationVci"
|
||||||
|
formControlName="destinationVci"
|
||||||
|
placeholder="VCI">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button mat-button class="form-field" (click)="add()">Add</button>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,164 @@
|
|||||||
|
import { Component, OnInit, Input } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-atm-switch',
|
||||||
|
templateUrl: './configurator-atm-switch.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss', '../../../../preferences/preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogAtmSwitchComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
nameForm: FormGroup;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
abstractForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
nodeMappings = new Map<string, string>();
|
||||||
|
nodeMappingsDataSource: NodeMapping[] = [];
|
||||||
|
dataSource = [];
|
||||||
|
displayedColumns = ['portIn', 'portOut', 'actions']
|
||||||
|
|
||||||
|
sourcePort: string = '';
|
||||||
|
sourceVpi: string = '';
|
||||||
|
sourceVci: string = '';
|
||||||
|
destinationPort: string = '';
|
||||||
|
destinationVpi: string = '';
|
||||||
|
destinationVci: string = '';
|
||||||
|
|
||||||
|
useVpiOnly: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogAtmSwitchComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.nameForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
sourcePort: new FormControl('', Validators.required),
|
||||||
|
sourceVci: new FormControl('', Validators.required),
|
||||||
|
destinationPort: new FormControl('', Validators.required),
|
||||||
|
destinationVci: new FormControl('', Validators.required),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.abstractForm = this.formBuilder.group({
|
||||||
|
sourceVpi: new FormControl('', Validators.required),
|
||||||
|
destinationVpi: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
|
||||||
|
let mappings = node.properties.mappings;
|
||||||
|
Object.keys(mappings).forEach(key => {
|
||||||
|
this.nodeMappings.set(key, mappings[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.nodeMappings.forEach((value: string, key: string) => {
|
||||||
|
this.nodeMappingsDataSource.push({
|
||||||
|
portIn: key,
|
||||||
|
portOut: value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(elem: NodeMapping) {
|
||||||
|
this.nodeMappingsDataSource = this.nodeMappingsDataSource.filter(n => n !== elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
add() {
|
||||||
|
if (this.inputForm.valid) {
|
||||||
|
let nodeMapping: NodeMapping;
|
||||||
|
if (!this.useVpiOnly) {
|
||||||
|
if (this.abstractForm.valid) {
|
||||||
|
nodeMapping = {
|
||||||
|
portIn: `${this.sourcePort}:${this.sourceVpi}:${this.sourceVci}`,
|
||||||
|
portOut: `${this.destinationPort}:${this.destinationVpi}:${this.destinationVci}`
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.nodeMappingsDataSource.filter(n => n.portIn === nodeMapping.portIn).length > 0) {
|
||||||
|
this.toasterService.error('Mapping already defined.');
|
||||||
|
} else {
|
||||||
|
this.nodeMappingsDataSource = this.nodeMappingsDataSource.concat([nodeMapping]);
|
||||||
|
this.clearUserInput();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.toasterService.error('Fill all required fields.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodeMapping = {
|
||||||
|
portIn: `${this.sourcePort}:${this.sourceVci}`,
|
||||||
|
portOut: `${this.destinationPort}:${this.destinationVci}`
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.nodeMappingsDataSource.filter(n => n.portIn === nodeMapping.portIn).length > 0) {
|
||||||
|
this.toasterService.error('Mapping already defined.');
|
||||||
|
} else {
|
||||||
|
this.nodeMappingsDataSource = this.nodeMappingsDataSource.concat([nodeMapping]);
|
||||||
|
this.clearUserInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.toasterService.error('Fill all required fields.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearUserInput() {
|
||||||
|
this.sourcePort = '0';
|
||||||
|
this.sourceVpi = '0';
|
||||||
|
this.sourceVci = '0';
|
||||||
|
this.destinationPort = '0';
|
||||||
|
this.destinationVpi = '0';
|
||||||
|
this.sourceVci = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
strMapToObj(strMap) {
|
||||||
|
let obj = Object.create(null);
|
||||||
|
for (let [k,v] of strMap) {
|
||||||
|
obj[k] = v;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.nameForm.valid) {
|
||||||
|
this.nodeMappings.clear();
|
||||||
|
this.nodeMappingsDataSource.forEach(elem => {
|
||||||
|
this.nodeMappings.set(elem.portIn, elem.portOut);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.node.properties.mappings = Array.from(this.nodeMappings).reduce((obj, [key, value]) => (Object.assign(obj, { [key]: value })), {});
|
||||||
|
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeMapping {
|
||||||
|
portIn: string,
|
||||||
|
portOut: string
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="Ethernet interfaces">
|
||||||
|
<div class="form-field" *ngFor="let port of portsMappingEthernet">
|
||||||
|
<div class="form-field">{{port.name}}</div><br/><br/>
|
||||||
|
</div>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Ethernet interface"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="ethernetInterface">
|
||||||
|
<mat-option *ngFor="let type of ethernetInterfaces" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAddEthernetInterface()">Add</button>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="TAP interfaces">
|
||||||
|
<div class="form-field" *ngFor="let port of portsMappingTap">
|
||||||
|
<div class="form-field">{{port.name}}</div><br/><br/>
|
||||||
|
</div>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="tapInterface"
|
||||||
|
placeholder="TAP interface">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button class="form-field" (click)="onAddTapInterface()">Add</button>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="UDP tunnels">
|
||||||
|
<app-udp-tunnels #udpTunnels [dataSourceUdp]="portsMappingUdp" ></app-udp-tunnels>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Miscellaneous">
|
||||||
|
<form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.properties.remote_console_host"
|
||||||
|
placeholder="Console host">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.properties.remote_console_port"
|
||||||
|
placeholder="Console port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.properties.remote_console_http_path"
|
||||||
|
placeholder="Console HTTP path">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,105 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component';
|
||||||
|
import { QemuBinary } from '../../../../../models/qemu/qemu-binary';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity';
|
||||||
|
import { UdpTunnelsComponent } from '../../../../../components/preferences/common/udp-tunnels/udp-tunnels.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-cloud',
|
||||||
|
templateUrl: './configurator-cloud.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogCloudComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
binaries: QemuBinary[] = [];
|
||||||
|
onCloseOptions = [];
|
||||||
|
bootPriorities = [];
|
||||||
|
diskInterfaces: string[] = [];
|
||||||
|
|
||||||
|
portsMappingEthernet: PortsMappingEntity[] = [];
|
||||||
|
portsMappingTap: PortsMappingEntity[] = [];
|
||||||
|
portsMappingUdp: PortsMappingEntity[] = [];
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
|
networkTypes = [];
|
||||||
|
tapInterface: string = '';
|
||||||
|
ethernetInterface: string = '';
|
||||||
|
ethernetInterfaces: string[] = ['Ethernet 2', 'Ethernet 3'];
|
||||||
|
|
||||||
|
@ViewChild("udpTunnels", {static: false}) udpTunnels: UdpTunnelsComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogCloudComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService,
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
|
||||||
|
this.portsMappingEthernet = this.node.properties.ports_mapping
|
||||||
|
.filter((elem) => elem.type === 'ethernet');
|
||||||
|
|
||||||
|
this.portsMappingTap = this.node.properties.ports_mapping
|
||||||
|
.filter((elem) => elem.type === 'tap');
|
||||||
|
|
||||||
|
this.portsMappingUdp = this.node.properties.ports_mapping
|
||||||
|
.filter((elem) => elem.type === 'udp');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.builtInTemplatesConfigurationService.getConsoleTypesForCloudNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddTapInterface() {
|
||||||
|
if (this.tapInterface) {
|
||||||
|
this.portsMappingTap.push({
|
||||||
|
interface: this.tapInterface,
|
||||||
|
name: this.tapInterface,
|
||||||
|
port_number: 0,
|
||||||
|
type: "tap"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.portsMappingUdp = this.udpTunnels.dataSourceUdp;
|
||||||
|
|
||||||
|
this.node.properties.ports_mapping = this.portsMappingUdp.concat(this.portsMappingEthernet).concat(this.portsMappingTap);
|
||||||
|
|
||||||
|
this.nodeService. updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
.form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.configButton {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.default-content {
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
scrollbar-color: darkgrey #263238;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-button {
|
||||||
|
width: 18%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-name-form-field {
|
||||||
|
padding-left: 2%;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nonvisible {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-radio-button {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: darkgrey;
|
||||||
|
outline: 1px solid #263238;
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="General settings">
|
||||||
|
<br/><form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="name" type="text" [(ngModel)]="node.name" placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input formControlName="adapter" matInput type="number" [(ngModel)]="node.properties.adapters" placeholder="Adapters">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Console type" [(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="node.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
</form>
|
||||||
|
<h6>Environment</h6>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.environment"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Advanced">
|
||||||
|
<h6>Extra hosts</h6>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.extra_hosts"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Usage">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,63 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { DockerConfigurationService } from '../../../../../services/docker-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-docker',
|
||||||
|
templateUrl: './configurator-docker.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogDockerComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogDockerComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private dockerConfigurationService: DockerConfigurationService
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required),
|
||||||
|
adapter: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.dockerConfigurationService.getConsoleTypes();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content" *ngIf="node">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<app-ports *ngIf="node.properties" #ports [ethernetPorts]="node.properties.ports_mapping"></app-ports>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,64 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service';
|
||||||
|
import { PortsComponent } from '../../../../../components/preferences/common/ports/ports.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-ethernet-switch',
|
||||||
|
templateUrl: './configurator-ethernet-switch.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogEthernetSwitchComponent implements OnInit {
|
||||||
|
@ViewChild(PortsComponent, {static: false}) portsComponent: PortsComponent;
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogEthernetSwitchComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private ethernetSwitchesConfigurationService: BuiltInTemplatesConfigurationService
|
||||||
|
) {
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = this.node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.ethernetSwitchesConfigurationService.getConsoleTypesForEthernetSwitches();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.inputForm.valid) {
|
||||||
|
this.node.properties.ports_mapping = this.portsComponent.ethernetPorts;
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="numberOfPorts"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
placeholder="Number of ports">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,73 @@
|
|||||||
|
import { Component, OnInit, Input } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-ethernet-hub',
|
||||||
|
templateUrl: './configurator-ethernet-hub.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogEthernetHubComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
numberOfPorts: number;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
categories = [];
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogEthernetHubComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private vpcsConfigurationService: VpcsConfigurationService
|
||||||
|
) {
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = this.node.name;
|
||||||
|
this.numberOfPorts = this.node.ports.length;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.vpcsConfigurationService.getConsoleTypes();
|
||||||
|
this.categories = this.vpcsConfigurationService.getCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.inputForm.valid) {
|
||||||
|
this.node.properties.ports_mapping = [];
|
||||||
|
for(let i=0; i<this.numberOfPorts; i++){
|
||||||
|
this.node.properties.ports_mapping.push({
|
||||||
|
name: `Ethernet${i}`,
|
||||||
|
port_number: i
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="General settings">
|
||||||
|
<br/><form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="name" [(ngModel)]="node.name" placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select placeholder="Console type" [(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [(ngModel)]="node.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox><br/>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Memories and disks">
|
||||||
|
<br/><form [formGroup]="memoryForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="ram" [(ngModel)]="node.properties.ram" placeholder="RAM size">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="nvram" [(ngModel)]="node.properties.nvram" placeholder="NVRAM size">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Usage">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,67 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { IosConfigurationService } from '../../../../../services/ios-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-ios',
|
||||||
|
templateUrl: './configurator-ios.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogIosComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
memoryForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogIosComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private configurationService: IosConfigurationService
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.memoryForm = this.formBuilder.group({
|
||||||
|
ram: new FormControl('', Validators.required),
|
||||||
|
nvram: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.configurationService.getConsoleTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid && this.memoryForm.valid) {
|
||||||
|
this.nodeService. updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="General settings">
|
||||||
|
<br/><form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="name" [(ngModel)]="node.name" placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select placeholder="Console type" [(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [(ngModel)]="node.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox><br/>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" [(ngModel)]="node.properties.ram" placeholder="RAM size">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" [(ngModel)]="node.properties.nvram" placeholder="NVRAM size">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Network">
|
||||||
|
<br/><form [formGroup]="networkForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="ethernetAdapters" type="number" [(ngModel)]="node.ethernet_adapters" placeholder="Ethernet adapters">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="serialAdapters" type="number" [(ngModel)]="node.serial_adapters" placeholder="Serial adapters">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-tab>
|
||||||
|
|
||||||
|
<mat-tab label="Usage">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,67 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { IouConfigurationService } from '../../../../../services/iou-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-iou',
|
||||||
|
templateUrl: './configurator-iou.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogIouComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
networkForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogIouComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private configurationService: IouConfigurationService
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.networkForm = this.formBuilder.group({
|
||||||
|
ethernetAdapters: new FormControl('', Validators.required),
|
||||||
|
serialAdapters: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.configurationService.getConsoleTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid && this.networkForm.valid) {
|
||||||
|
this.nodeService. updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,53 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-nat',
|
||||||
|
templateUrl: './configurator-nat.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogNatComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogNatComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,276 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="General settings">
|
||||||
|
<br/><form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" formControlName="name" [(ngModel)]="node.name" placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" formControlName="ram" [(ngModel)]="node.properties.ram" placeholder="RAM">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="number" [(ngModel)]="node.properties.cpus" placeholder="vCPUs">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Qemu binary" [(ngModel)]="node.properties.qemu_path">
|
||||||
|
<mat-option *ngFor="let binary of binaries" [value]="binary.path">
|
||||||
|
{{binary.path}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Boot priority" [(ngModel)]="node.properties.boot_priority">
|
||||||
|
<mat-option *ngFor="let priority of bootPriorities" [value]="priority[1]">
|
||||||
|
{{priority[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="On close" [(ngModel)]="node.properties.on_close">
|
||||||
|
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
||||||
|
{{option[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select placeholder="Console type" [(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [(ngModel)]="node.properties.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="HDD">
|
||||||
|
<mat-card>
|
||||||
|
<!-- to do -->
|
||||||
|
<button mat-raised-button color="primary" (click)="openQemuImageCreator()" class="create-button">Create Qemu image</button>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
HDA (Primary Master)
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-select placeholder="Disk image" [(ngModel)]="node.properties.hda_disk_image">
|
||||||
|
<mat-option *ngFor="let image of qemuImages" [value]="image.filename">
|
||||||
|
{{image.filename}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Disk interface" [(ngModel)]="node.properties.hda_disk_interface">
|
||||||
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
|
{{interface}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
HDB (Primary Slave)
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-select placeholder="Disk image" [(ngModel)]="node.properties.hdb_disk_image">
|
||||||
|
<mat-option *ngFor="let image of qemuImages" [value]="image.filename">
|
||||||
|
{{image.filename}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Disk interface" [(ngModel)]="node.properties.hdb_disk_interface">
|
||||||
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
|
{{interface}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
HDC (Secondary Master)
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-select placeholder="Disk image" [(ngModel)]="node.properties.hdc_disk_image">
|
||||||
|
<mat-option *ngFor="let image of qemuImages" [value]="image.filename">
|
||||||
|
{{image.filename}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Disk interface" [(ngModel)]="node.properties.hdc_disk_interface">
|
||||||
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
|
{{interface}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
HDD (Secondary Slave)
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-select placeholder="Disk image" [(ngModel)]="node.properties.hdd_disk_image">
|
||||||
|
<mat-option *ngFor="let image of qemuImages" [value]="image.filename">
|
||||||
|
{{image.filename}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Disk interface" [(ngModel)]="node.properties.hdd_disk_interface">
|
||||||
|
<mat-option *ngFor="let interface of diskInterfaces" [value]="interface">
|
||||||
|
{{interface}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="CD/DVD">
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="filecdrom.click()" class="file-button">Browse</button>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
#filecdrom
|
||||||
|
class="nonvisible"
|
||||||
|
(change)="uploadCdromImageFile($event)"/>
|
||||||
|
<mat-form-field class="file-name-form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="node.properties.cdrom_image"
|
||||||
|
placeholder="Image"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Network">
|
||||||
|
<br/><mat-checkbox [(ngModel)]="node.properties.legacy_networking">
|
||||||
|
Use the legacy networking mode
|
||||||
|
</mat-checkbox>
|
||||||
|
<app-custom-adapters-table
|
||||||
|
#customAdapters
|
||||||
|
[networkTypes]="networkTypes"
|
||||||
|
[displayedColumns]="displayedColumns"
|
||||||
|
[adapters]="node.ports"
|
||||||
|
></app-custom-adapters-table>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Advanced">
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
Linux boot specific settings
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="fileinitrd.click()" class="file-button">Browse</button>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
#fileinitrd
|
||||||
|
class="nonvisible"
|
||||||
|
(change)="uploadInitrdFile($event)"/>
|
||||||
|
<mat-form-field class="file-name-form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="node.properties.initrd"
|
||||||
|
placeholder="Initial RAM disk (initrd)"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="filekerenelimage.click()" class="file-button">Browse</button>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
#filekernelimage
|
||||||
|
class="nonvisible"
|
||||||
|
(change)="uploadKernelImageFile($event)"/>
|
||||||
|
<mat-form-field class="file-name-form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="node.properties.kernel_image"
|
||||||
|
placeholder="Kernel image"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" [(ngModel)]="node.properties.kernel_command_line" placeholder="Kernel command line">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
Bios
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<div>
|
||||||
|
<button mat-raised-button color="primary" (click)="filebios.click()" class="file-button">Browse</button>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
#filebios
|
||||||
|
class="nonvisible"
|
||||||
|
(change)="uploadBiosFile($event)"/>
|
||||||
|
<mat-form-field class="file-name-form-field">
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[(ngModel)]="node.properties.bios_image"
|
||||||
|
placeholder="Bios image"/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
Optimization
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-checkbox [(ngModel)]="activateCpuThrottling">
|
||||||
|
Activate CPU throttling
|
||||||
|
</mat-checkbox>
|
||||||
|
<mat-form-field *ngIf="activateCpuThrottling" class="form-field">
|
||||||
|
<input matInput type="number" [(ngModel)]="node.properties.cpu_throttling" placeholder="Perecentage of CPU allowed">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Process priority" [(ngModel)]="node.properties.process_priority">
|
||||||
|
<mat-option *ngFor="let priority of priorities" [value]="priority">
|
||||||
|
{{priority}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-title></mat-card-title>
|
||||||
|
<mat-card-subtitle>
|
||||||
|
Additional settings
|
||||||
|
</mat-card-subtitle>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput type="text" [(ngModel)]="node.properties.options" placeholder="Options">
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Usage">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,131 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef, MatDialog } from '@angular/material';
|
||||||
|
import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component';
|
||||||
|
import { QemuService } from '../../../../../services/qemu.service';
|
||||||
|
import { QemuConfigurationService } from '../../../../../services/qemu-configuration.service';
|
||||||
|
import { QemuBinary } from '../../../../../models/qemu/qemu-binary';
|
||||||
|
import { QemuImageCreatorComponent } from './qemu-image-creator/qemu-image-creator.component';
|
||||||
|
import { QemuImage } from '../../../../../models/qemu/qemu-image';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-qemu',
|
||||||
|
templateUrl: './configurator-qemu.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogQemuComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
binaries: QemuBinary[] = [];
|
||||||
|
onCloseOptions = [];
|
||||||
|
bootPriorities = [];
|
||||||
|
diskInterfaces: string[] = [];
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
|
networkTypes = [];
|
||||||
|
qemuImages: QemuImage[] = [];
|
||||||
|
|
||||||
|
private conf = {
|
||||||
|
autoFocus: false,
|
||||||
|
width: '800px'
|
||||||
|
};
|
||||||
|
dialogRefQemuImageCreator;
|
||||||
|
|
||||||
|
@ViewChild("customAdapters", {static: false}) customAdapters: CustomAdaptersTableComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private dialog: MatDialog,
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogQemuComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private qemuService: QemuService,
|
||||||
|
private qemuConfigurationService: QemuConfigurationService
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required),
|
||||||
|
ram: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
|
||||||
|
this.qemuService.getBinaries(this.server).subscribe((qemuBinaries: QemuBinary[]) => {
|
||||||
|
this.binaries = qemuBinaries;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.qemuService.getImages(this.server).subscribe((qemuImages: QemuImage[]) => {
|
||||||
|
this.qemuImages = qemuImages;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openQemuImageCreator() {
|
||||||
|
this.dialogRefQemuImageCreator = this.dialog.open(QemuImageCreatorComponent, this.conf);
|
||||||
|
let instance = this.dialogRefQemuImageCreator.componentInstance;
|
||||||
|
instance.server = this.server;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadCdromImageFile(event){
|
||||||
|
this.node.properties.cdrom_image = event.target.files[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadInitrdFile(event){
|
||||||
|
this.node.properties.initrd = event.target.files[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadKernelImageFile(event){
|
||||||
|
this.node.properties.kernel_image = event.target.files[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadBiosFile(event){
|
||||||
|
this.node.properties.bios_image = event.target.files[0].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.qemuConfigurationService.getConsoleTypes();
|
||||||
|
this.onCloseOptions = this.qemuConfigurationService.getOnCloseOptions();
|
||||||
|
this.qemuConfigurationService.getNetworkTypes().forEach(n => {
|
||||||
|
this.networkTypes.push(n[0]);
|
||||||
|
});
|
||||||
|
this.bootPriorities = this.qemuConfigurationService.getBootPriorities();
|
||||||
|
this.diskInterfaces = this.qemuConfigurationService.getDiskInterfaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.node.custom_adapters = [];
|
||||||
|
this.customAdapters.adapters.forEach(n => {
|
||||||
|
this.node.custom_adapters.push({
|
||||||
|
adapter_number: n.adapter_number,
|
||||||
|
adapter_type: n.adapter_type
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
this.node.properties.adapters = this.node.custom_adapters.length;
|
||||||
|
|
||||||
|
this.nodeService. updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
<h1 mat-dialog-title>Qemu image configurator</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="qemuImg.qemu_img"
|
||||||
|
formControlName="qemu_img"
|
||||||
|
placeholder="Qemu image path">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Image format" [(ngModel)]="qemuImg.format">
|
||||||
|
<mat-option *ngFor="let format of formatOptions" [value]="format">
|
||||||
|
{{format}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<div *ngIf="qemuImg.format==='qcow2'">
|
||||||
|
Size options
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Image format" [(ngModel)]="qemuImg.preallocation">
|
||||||
|
<mat-option *ngFor="let preallocation of preallocationsOptions" [value]="preallocation">
|
||||||
|
{{preallocation}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Cluster size" [(ngModel)]="qemuImg.cluster_size">
|
||||||
|
<mat-option *ngFor="let clusterSize of clusterSizeOptions" [value]="clusterSize.value">
|
||||||
|
{{clusterSize.name}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
Refcounts
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Lazy refcounts" [(ngModel)]="qemuImg.lazy_refcounts">
|
||||||
|
<mat-option *ngFor="let lazyRefcount of lazyRefcountsOptions" [value]="lazyRefcount">
|
||||||
|
{{lazyRefcount}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select placeholder="Refcount entry size" [(ngModel)]="qemuImg.refcount_bits">
|
||||||
|
<mat-option *ngFor="let clusterSize of clusterSizeOptions" [value]="clusterSize.value">
|
||||||
|
{{clusterSize.name}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="qemuImg.format==='vhd' || qemuImg.format==='vdi'">
|
||||||
|
<mat-radio-group aria-label="Image file sizing mode" class="radio-selection">
|
||||||
|
<mat-radio-button value="1" (click)="setSubformat('dynamic')" checked>Dynamic</mat-radio-button>
|
||||||
|
<mat-radio-button value="2" (click)="setSubformat('fixed')">Fixed</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="qemuImg.format==='vmdk'">
|
||||||
|
Adapter type<br/>
|
||||||
|
<mat-radio-group aria-label="Adapter type" class="radio-selection">
|
||||||
|
<mat-radio-button value="1" (click)="setAdapterType('ide')" checked>IDE</mat-radio-button>
|
||||||
|
<mat-radio-button value="2" (click)="setAdapterType('lsilogic')">LSI Logic</mat-radio-button>
|
||||||
|
<mat-radio-button value="3" (click)="setAdapterType('buslogic')">BusLogic</mat-radio-button>
|
||||||
|
<mat-radio-button value="4" (click)="setAdapterType('legacyESX')">Legacy (ESX)</mat-radio-button>
|
||||||
|
</mat-radio-group><br/><br/>
|
||||||
|
Image file sizing mode<br/>
|
||||||
|
<mat-radio-group aria-label="Image file sizing mode" class="radio-selection">
|
||||||
|
<mat-radio-button value="1" (click)="setSubformat('streamOptimized')" checked>Stream optimized</mat-radio-button>
|
||||||
|
<mat-radio-button value="2" (click)="setSubformat('twoGbMaxExtentSparse')">Split every 2GB (sparse)</mat-radio-button>
|
||||||
|
<mat-radio-button value="3" (click)="setSubformat('twoGbMaxExtentFlat')">Split every 2GB (flat)</mat-radio-button>
|
||||||
|
<mat-radio-button value="4" (click)="setSubformat('monolithicSparse')">Monolithic sparse</mat-radio-button>
|
||||||
|
<mat-radio-button value="5" (click)="setSubformat('monolithicFlat')">Monolithic flat</mat-radio-button>
|
||||||
|
</mat-radio-group><br/><br/>
|
||||||
|
<mat-select placeholder="Zeroed grain" [(ngModel)]="qemuImg.zeroed_grain">
|
||||||
|
<mat-option *ngFor="let option of zeroedGrainOptions" [value]="option">
|
||||||
|
{{option}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</div>
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="qemuImg.path"
|
||||||
|
formControlName="path"
|
||||||
|
placeholder="File location">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="qemuImg.size"
|
||||||
|
formControlName="size"
|
||||||
|
placeholder="Disk size">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,121 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Server } from '../../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { QemuService } from '../../../../../../services/qemu.service';
|
||||||
|
import { QemuImg } from '../../../../../../models/qemu/qemu-img';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-qemu-image-creator',
|
||||||
|
templateUrl: './qemu-image-creator.component.html',
|
||||||
|
styleUrls: ['../../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class QemuImageCreatorComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
qemuImg: QemuImg;
|
||||||
|
|
||||||
|
formatOptions: string[] = ['qcow2', 'qcow', 'vhd', 'vdi', 'vmdk', 'raw'];
|
||||||
|
preallocationsOptions: string[] = ['off', 'metadata', 'falloc', 'full'];
|
||||||
|
clusterSizeOptions: ClusterSize[] = [
|
||||||
|
{
|
||||||
|
name: '512',
|
||||||
|
value: 512
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '1k',
|
||||||
|
value: 1024
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2k',
|
||||||
|
value: 2048
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '4k',
|
||||||
|
value: 4096
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '8k',
|
||||||
|
value: 8192
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '16k',
|
||||||
|
value: 16384
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '32k',
|
||||||
|
value: 32768
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '64k',
|
||||||
|
value: 65536
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '128k',
|
||||||
|
value: 131072
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '256k',
|
||||||
|
value: 262144
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '512k',
|
||||||
|
value: 524288
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '1024k',
|
||||||
|
value: 1048576
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '2048k',
|
||||||
|
value: 2097152
|
||||||
|
}
|
||||||
|
];
|
||||||
|
lazyRefcountsOptions: string[] = ['off', 'on'];
|
||||||
|
refcountBitsOptions: number[] = [1,2,4,8,16,32,64];
|
||||||
|
zeroedGrainOptions: string[] = ['on', 'off'];
|
||||||
|
inputForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<QemuImageCreatorComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private qemuService: QemuService
|
||||||
|
) {
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
qemu_img: new FormControl('', Validators.required),
|
||||||
|
path: new FormControl('', Validators.required),
|
||||||
|
size: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.qemuImg = {} as QemuImg;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSubformat(subformat: string) {
|
||||||
|
this.qemuImg.subformat = subformat;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.inputForm.valid && this.qemuImg.format) {
|
||||||
|
this.qemuService.addImage(this.server, this.qemuImg).subscribe(() => {
|
||||||
|
this.dialogRef.close();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error('Fill all required fields.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClusterSize {
|
||||||
|
name: string;
|
||||||
|
value: number;
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card>
|
||||||
|
<table *ngIf="nodeMappingsDataSource.length" class="table" mat-table [dataSource]="nodeMappingsDataSource">
|
||||||
|
<ng-container matColumnDef="portIn">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port : DLCI</th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.portIn}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="portOut">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Port : DLCI </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.portOut}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button matTooltip="Delete port" (click)="delete(element)">
|
||||||
|
<mat-icon aria-label="Delete port">delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table><br/>
|
||||||
|
|
||||||
|
<form [formGroup]="nameForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
Source
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="sourcePort"
|
||||||
|
formControlName="sourcePort"
|
||||||
|
placeholder="Port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="sourceDlci"
|
||||||
|
formControlName="sourceDlci"
|
||||||
|
placeholder="DLCI">
|
||||||
|
</mat-form-field>
|
||||||
|
Destination
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="destinationPort"
|
||||||
|
formControlName="destinationPort"
|
||||||
|
placeholder="Port">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="number"
|
||||||
|
[(ngModel)]="destinationDlci"
|
||||||
|
formControlName="destinationDlci"
|
||||||
|
placeholder="DLCI">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button mat-button class="form-field" (click)="add()">Add</button>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,133 @@
|
|||||||
|
import { Component, OnInit, Input } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-switch',
|
||||||
|
templateUrl: './configurator-switch.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss', '../../../../preferences/preferences.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogSwitchComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
nameForm: FormGroup;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
nodeMappings = new Map<string, string>();
|
||||||
|
nodeMappingsDataSource: NodeMapping[] = [];
|
||||||
|
dataSource = [];
|
||||||
|
displayedColumns = ['portIn', 'portOut', 'actions']
|
||||||
|
|
||||||
|
sourcePort: string = '';
|
||||||
|
sourceDlci: string = '';
|
||||||
|
destinationPort: string = '';
|
||||||
|
destinationDlci: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogSwitchComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.nameForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required),
|
||||||
|
});
|
||||||
|
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
sourcePort: new FormControl('', Validators.required),
|
||||||
|
sourceDlci: new FormControl('', Validators.required),
|
||||||
|
destinationPort: new FormControl('', Validators.required),
|
||||||
|
destinationDlci: new FormControl('', Validators.required),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
|
||||||
|
let mappings = node.properties.mappings;
|
||||||
|
Object.keys(mappings).forEach(key => {
|
||||||
|
this.nodeMappings.set(key, mappings[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.nodeMappings.forEach((value: string, key: string) => {
|
||||||
|
this.nodeMappingsDataSource.push({
|
||||||
|
portIn: key,
|
||||||
|
portOut: value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(elem: NodeMapping) {
|
||||||
|
this.nodeMappingsDataSource = this.nodeMappingsDataSource.filter(n => n !== elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
add() {
|
||||||
|
if (this.inputForm.valid) {
|
||||||
|
let nodeMapping: NodeMapping = {
|
||||||
|
portIn: `${this.sourcePort}:${this.sourceDlci}`,
|
||||||
|
portOut: `${this.destinationPort}:${this.destinationDlci}`
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.nodeMappingsDataSource.filter(n => n.portIn === nodeMapping.portIn).length > 0) {
|
||||||
|
this.toasterService.error('Mapping already defined.');
|
||||||
|
} else {
|
||||||
|
this.nodeMappingsDataSource = this.nodeMappingsDataSource.concat([nodeMapping]);
|
||||||
|
this.clearUserInput();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.toasterService.error('Fill all required fields.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearUserInput() {
|
||||||
|
this.sourcePort = '0';
|
||||||
|
this.sourceDlci = '0';
|
||||||
|
this.destinationPort = '0';
|
||||||
|
this.destinationDlci = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
strMapToObj(strMap) {
|
||||||
|
let obj = Object.create(null);
|
||||||
|
for (let [k,v] of strMap) {
|
||||||
|
obj[k] = v;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.nameForm.valid) {
|
||||||
|
this.nodeMappings.clear();
|
||||||
|
this.nodeMappingsDataSource.forEach(elem => {
|
||||||
|
this.nodeMappings.set(elem.portIn, elem.portOut);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.node.properties.mappings = Array.from(this.nodeMappings).reduce((obj, [key, value]) => (Object.assign(obj, { [key]: value })), {});
|
||||||
|
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeMapping {
|
||||||
|
portIn: string,
|
||||||
|
portOut: string
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,53 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-traceng',
|
||||||
|
templateUrl: './configurator-traceng.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogTracengComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogTracengComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="General settings">
|
||||||
|
<br/><form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="name" type="text" [(ngModel)]="node.name" placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Console type" [(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="node.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="ram" type="number" [(ngModel)]="node.properties.ram" placeholder="RAM">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="On close" [(ngModel)]="node.properties.on_close">
|
||||||
|
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
||||||
|
{{option[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-checkbox [(ngModel)]="node.properties.headless">
|
||||||
|
Start VM in headless mode
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Network">
|
||||||
|
<br/><mat-checkbox [(ngModel)]="node.properties.use_any_adapter">
|
||||||
|
Allow GNS3 to use any configured VirtualBox adapter
|
||||||
|
</mat-checkbox>
|
||||||
|
<app-custom-adapters-table
|
||||||
|
#customAdapters
|
||||||
|
[networkTypes]="networkTypes"
|
||||||
|
[displayedColumns]="displayedColumns"
|
||||||
|
[adapters]="node.ports"
|
||||||
|
></app-custom-adapters-table>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Usage">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,81 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { VirtualBoxConfigurationService } from '../../../../../services/virtual-box-configuration.service';
|
||||||
|
import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-virtualbox',
|
||||||
|
templateUrl: './configurator-virtualbox.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogVirtualBoxComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
onCloseOptions = [];
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
|
networkTypes = [];
|
||||||
|
|
||||||
|
@ViewChild("customAdapters", {static: false}) customAdapters: CustomAdaptersTableComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogVirtualBoxComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private virtualBoxConfigurationService: VirtualBoxConfigurationService
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required),
|
||||||
|
ram: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.virtualBoxConfigurationService.getConsoleTypes();
|
||||||
|
this.onCloseOptions = this.virtualBoxConfigurationService.getOnCloseoptions();
|
||||||
|
this.networkTypes = this.virtualBoxConfigurationService.getNetworkTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.node.custom_adapters = [];
|
||||||
|
this.customAdapters.adapters.forEach(n => {
|
||||||
|
this.node.custom_adapters.push({
|
||||||
|
adapter_number: n.adapter_number,
|
||||||
|
adapter_type: n.adapter_type
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
this.node.properties.adapters = this.node.custom_adapters.length;
|
||||||
|
|
||||||
|
this.nodeService.updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<mat-tab-group *ngIf="name">
|
||||||
|
<mat-tab label="General settings">
|
||||||
|
<br/><form [formGroup]="generalSettingsForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input matInput formControlName="name" type="text" [(ngModel)]="node.name" placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="Console type" [(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="node.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<mat-select [ngModelOptions]="{standalone: true}" placeholder="On close" [(ngModel)]="node.properties.on_close">
|
||||||
|
<mat-option *ngFor="let option of onCloseOptions" [value]="option[1]">
|
||||||
|
{{option[0]}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
<mat-checkbox [(ngModel)]="node.properties.headless">
|
||||||
|
Start VM in headless mode
|
||||||
|
</mat-checkbox><br/>
|
||||||
|
<mat-checkbox [(ngModel)]="node.properties.linked_clone">
|
||||||
|
Use a linked base VM (experimental)
|
||||||
|
</mat-checkbox>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Network">
|
||||||
|
<br/><mat-checkbox [(ngModel)]="node.properties.use_any_adapter">
|
||||||
|
Allow GNS3 to override non custom VMware adapter
|
||||||
|
</mat-checkbox>
|
||||||
|
<app-custom-adapters-table
|
||||||
|
#customAdapters
|
||||||
|
[networkTypes]="networkTypes"
|
||||||
|
[displayedColumns]="displayedColumns"
|
||||||
|
[adapters]="node.ports"
|
||||||
|
></app-custom-adapters-table>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="Usage">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<textarea matInput type="text" [(ngModel)]="node.properties.usage"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,80 @@
|
|||||||
|
import { Component, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
import { CustomAdaptersTableComponent } from '../../../../../components/preferences/common/custom-adapters-table/custom-adapters-table.component';
|
||||||
|
import { VmwareConfigurationService } from '../../../../../services/vmware-configuration.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-vmware',
|
||||||
|
templateUrl: './configurator-vmware.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogVmwareComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
generalSettingsForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
onCloseOptions = [];
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['adapter_number', 'port_name', 'adapter_type', 'actions'];
|
||||||
|
networkTypes = [];
|
||||||
|
|
||||||
|
@ViewChild("customAdapters", {static: false}) customAdapters: CustomAdaptersTableComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogVmwareComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private vmwareConfigurationService: VmwareConfigurationService
|
||||||
|
) {
|
||||||
|
this.generalSettingsForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.vmwareConfigurationService.getConsoleTypes();
|
||||||
|
this.onCloseOptions = this.vmwareConfigurationService.getOnCloseoptions();
|
||||||
|
this.networkTypes = this.vmwareConfigurationService.getNetworkTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.generalSettingsForm.valid) {
|
||||||
|
this.node.custom_adapters = [];
|
||||||
|
this.customAdapters.adapters.forEach(n => {
|
||||||
|
this.node.custom_adapters.push({
|
||||||
|
adapter_number: n.adapter_number,
|
||||||
|
adapter_type: n.adapter_type
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
this.node.properties.adapters = this.node.custom_adapters.length;
|
||||||
|
|
||||||
|
this.nodeService.updateNodeWithCustomAdapters(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<h1 mat-dialog-title>Configurator for node {{name}}</h1>
|
||||||
|
|
||||||
|
<div class="modal-form-container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="default-content">
|
||||||
|
<mat-card class="matCard">
|
||||||
|
<form [formGroup]="inputForm">
|
||||||
|
<mat-form-field class="form-field">
|
||||||
|
<input
|
||||||
|
matInput type="text"
|
||||||
|
[(ngModel)]="node.name"
|
||||||
|
formControlName="name"
|
||||||
|
placeholder="Name">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="select">
|
||||||
|
<mat-select
|
||||||
|
placeholder="Console type"
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="node.console_type">
|
||||||
|
<mat-option *ngFor="let type of consoleTypes" [value]="type">
|
||||||
|
{{type}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox
|
||||||
|
[ngModelOptions]="{standalone: true}"
|
||||||
|
[(ngModel)]="node.console_auto_start">
|
||||||
|
Auto start console
|
||||||
|
</mat-checkbox>
|
||||||
|
</form>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="onCancelClick()" color="accent">Cancel</button>
|
||||||
|
<button mat-button (click)="onSaveClick()" tabindex="2" mat-raised-button color="primary">Apply</button>
|
||||||
|
</div>
|
@ -0,0 +1,61 @@
|
|||||||
|
import { Component, OnInit, Input } from "@angular/core";
|
||||||
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
|
import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service';
|
||||||
|
import { Node } from '../../../../../cartography/models/node';
|
||||||
|
import { Server } from '../../../../../models/server';
|
||||||
|
import { NodeService } from '../../../../../services/node.service';
|
||||||
|
import { ToasterService } from '../../../../../services/toaster.service';
|
||||||
|
import { MatDialogRef } from '@angular/material';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-configurator-vpcs',
|
||||||
|
templateUrl: './configurator-vpcs.component.html',
|
||||||
|
styleUrls: ['../configurator.component.scss']
|
||||||
|
})
|
||||||
|
export class ConfiguratorDialogVpcsComponent implements OnInit {
|
||||||
|
server: Server;
|
||||||
|
node: Node;
|
||||||
|
name: string;
|
||||||
|
inputForm: FormGroup;
|
||||||
|
consoleTypes: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<ConfiguratorDialogVpcsComponent>,
|
||||||
|
public nodeService: NodeService,
|
||||||
|
private toasterService: ToasterService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private vpcsConfigurationService: VpcsConfigurationService
|
||||||
|
) {
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
name: new FormControl('', Validators.required)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => {
|
||||||
|
this.node = node;
|
||||||
|
this.name = node.name;
|
||||||
|
this.getConfiguration();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getConfiguration() {
|
||||||
|
this.consoleTypes = this.vpcsConfigurationService.getConsoleTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveClick() {
|
||||||
|
if (this.inputForm.valid) {
|
||||||
|
this.nodeService.updateNode(this.server, this.node).subscribe(() => {
|
||||||
|
this.toasterService.success(`Node ${this.node.name} updated.`);
|
||||||
|
this.onCancelClick();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.toasterService.error(`Fill all required fields.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancelClick() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
export class Port {
|
export class Port {
|
||||||
adapter_number: number;
|
adapter_number: number;
|
||||||
|
adapter_type: string;
|
||||||
link_type: string;
|
link_type: string;
|
||||||
name: string;
|
name: string;
|
||||||
port_number: number;
|
port_number: number;
|
||||||
|
12
src/app/models/qemu/qemu-img.ts
Normal file
12
src/app/models/qemu/qemu-img.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export class QemuImg {
|
||||||
|
cluster_size: number;
|
||||||
|
format: string;
|
||||||
|
lazy_refcounts: string;
|
||||||
|
path: string;
|
||||||
|
preallocation: string;
|
||||||
|
qemu_img: string;
|
||||||
|
refcount_bits: number;
|
||||||
|
size: number;
|
||||||
|
subformat: string;
|
||||||
|
zeroed_grain: string;
|
||||||
|
}
|
12
src/app/models/templates/traceng-template.ts
Normal file
12
src/app/models/templates/traceng-template.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export interface TracengTemplate {
|
||||||
|
builtin: boolean;
|
||||||
|
category: string;
|
||||||
|
compute_id: string;
|
||||||
|
console_type: string;
|
||||||
|
default_name_format: string;
|
||||||
|
ip_address: string;
|
||||||
|
name: string;
|
||||||
|
symbol: string;
|
||||||
|
template_id: string;
|
||||||
|
template_type: string;
|
||||||
|
}
|
@ -86,6 +86,25 @@ export class NodeService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateNode(server: Server, node: Node): Observable<Node> {
|
||||||
|
return this.httpServer.put<Node>(server, `/projects/${node.project_id}/nodes/${node.node_id}`, {
|
||||||
|
console_type: node.console_type,
|
||||||
|
console_auto_start: node.console_auto_start,
|
||||||
|
name: node.name,
|
||||||
|
properties: node.properties
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodeWithCustomAdapters(server: Server, node: Node): Observable<Node> {
|
||||||
|
return this.httpServer.put<Node>(server, `/projects/${node.project_id}/nodes/${node.node_id}`, {
|
||||||
|
console_type: node.console_type,
|
||||||
|
console_auto_start: node.console_auto_start,
|
||||||
|
custom_adapters: node.custom_adapters,
|
||||||
|
name: node.name,
|
||||||
|
properties: node.properties
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
delete(server: Server, node: Node) {
|
delete(server: Server, node: Node) {
|
||||||
return this.httpServer.delete<Node>(server, `/projects/${node.project_id}/nodes/${node.node_id}`);
|
return this.httpServer.delete<Node>(server, `/projects/${node.project_id}/nodes/${node.node_id}`);
|
||||||
}
|
}
|
||||||
@ -99,6 +118,10 @@ export class NodeService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNode(server: Server, node: Node) {
|
||||||
|
return this.httpServer.get(server, `/projects/${node.project_id}/nodes/${node.node_id}`)
|
||||||
|
}
|
||||||
|
|
||||||
getConfiguration(server: Server, node: Node) {
|
getConfiguration(server: Server, node: Node) {
|
||||||
let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}`
|
let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}`
|
||||||
|
|
||||||
|
@ -11,26 +11,48 @@ export class QemuConfigurationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNetworkTypes() {
|
getNetworkTypes() {
|
||||||
let networkTypes = [["e1000", "Intel Gigabit Ethernet"],
|
// needs extending of custom adapter component
|
||||||
["i82550", "Intel i82550 Ethernet"],
|
// let networkTypes = [["e1000", "Intel Gigabit Ethernet"],
|
||||||
["i82551", "Intel i82551 Ethernet"],
|
// ["i82550", "Intel i82550 Ethernet"],
|
||||||
["i82557a", "Intel i82557A Ethernet"],
|
// ["i82551", "Intel i82551 Ethernet"],
|
||||||
["i82557b", "Intel i82557B Ethernet"],
|
// ["i82557a", "Intel i82557A Ethernet"],
|
||||||
["i82557c", "Intel i82557C Ethernet"],
|
// ["i82557b", "Intel i82557B Ethernet"],
|
||||||
["i82558a", "Intel i82558A Ethernet"],
|
// ["i82557c", "Intel i82557C Ethernet"],
|
||||||
["i82558b", "Intel i82558B Ethernet"],
|
// ["i82558a", "Intel i82558A Ethernet"],
|
||||||
["i82559a", "Intel i82559A Ethernet"],
|
// ["i82558b", "Intel i82558B Ethernet"],
|
||||||
["i82559b", "Intel i82559B Ethernet"],
|
// ["i82559a", "Intel i82559A Ethernet"],
|
||||||
["i82559c", "Intel i82559C Ethernet"],
|
// ["i82559b", "Intel i82559B Ethernet"],
|
||||||
["i82559er", "Intel i82559ER Ethernet"],
|
// ["i82559c", "Intel i82559C Ethernet"],
|
||||||
["i82562", "Intel i82562 Ethernet"],
|
// ["i82559er", "Intel i82559ER Ethernet"],
|
||||||
["i82801", "Intel i82801 Ethernet"],
|
// ["i82562", "Intel i82562 Ethernet"],
|
||||||
["ne2k_pci", "NE2000 Ethernet"],
|
// ["i82801", "Intel i82801 Ethernet"],
|
||||||
["pcnet", "AMD PCNet Ethernet"],
|
// ["ne2k_pci", "NE2000 Ethernet"],
|
||||||
["rtl8139", "Realtek 8139 Ethernet"],
|
// ["pcnet", "AMD PCNet Ethernet"],
|
||||||
["virtio", "Legacy paravirtualized Network I/O"],
|
// ["rtl8139", "Realtek 8139 Ethernet"],
|
||||||
["virtio-net-pci", "Paravirtualized Network I/O"],
|
// ["virtio", "Legacy paravirtualized Network I/O"],
|
||||||
["vmxnet3", "VMWare Paravirtualized Ethernet v3"]];
|
// ["virtio-net-pci", "Paravirtualized Network I/O"],
|
||||||
|
// ["vmxnet3", "VMWare Paravirtualized Ethernet v3"]];
|
||||||
|
|
||||||
|
let networkTypes = ["e1000", "Intel Gigabit Ethernet",
|
||||||
|
"i82550",
|
||||||
|
"i82551",
|
||||||
|
"i82557a",
|
||||||
|
"i82557b",
|
||||||
|
"i82557c",
|
||||||
|
"i82558a",
|
||||||
|
"i82558b",
|
||||||
|
"i82559a",
|
||||||
|
"i82559b",
|
||||||
|
"i82559c",
|
||||||
|
"i82559er",
|
||||||
|
"i82562",
|
||||||
|
"i82801",
|
||||||
|
"ne2k_pci",
|
||||||
|
"pcnet",
|
||||||
|
"rtl8139",
|
||||||
|
"virtio",
|
||||||
|
"virtio-net-pci",
|
||||||
|
"vmxnet3"];
|
||||||
|
|
||||||
return networkTypes;
|
return networkTypes;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { QemuTemplate } from '../models/templates/qemu-template';
|
|||||||
import { Server } from '../models/server';
|
import { Server } from '../models/server';
|
||||||
import { QemuBinary } from '../models/qemu/qemu-binary';
|
import { QemuBinary } from '../models/qemu/qemu-binary';
|
||||||
import { QemuImage } from '../models/qemu/qemu-image';
|
import { QemuImage } from '../models/qemu/qemu-image';
|
||||||
|
import { QemuImg } from '../models/qemu/qemu-img';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QemuService {
|
export class QemuService {
|
||||||
@ -26,6 +27,10 @@ export class QemuService {
|
|||||||
return this.httpServer.get<QemuImage[]>(server, '/compute/qemu/images') as Observable<QemuImage[]>;
|
return this.httpServer.get<QemuImage[]>(server, '/compute/qemu/images') as Observable<QemuImage[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addImage(server: Server, qemuImg: QemuImg): Observable<QemuImg> {
|
||||||
|
return this.httpServer.post<QemuImg>(server, '/compute/qemu/img', qemuImg) as Observable<QemuImg>;
|
||||||
|
}
|
||||||
|
|
||||||
addTemplate(server: Server, qemuTemplate: QemuTemplate): Observable<QemuTemplate> {
|
addTemplate(server: Server, qemuTemplate: QemuTemplate): Observable<QemuTemplate> {
|
||||||
return this.httpServer.post<QemuTemplate>(server, `/templates`, qemuTemplate) as Observable<QemuTemplate>;
|
return this.httpServer.post<QemuTemplate>(server, `/templates`, qemuTemplate) as Observable<QemuTemplate>;
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,27 @@ import { VmwareTemplate } from '../models/templates/vmware-template';
|
|||||||
import { DockerTemplate } from '../models/templates/docker-template';
|
import { DockerTemplate } from '../models/templates/docker-template';
|
||||||
import { CustomAdapter } from '../models/qemu/qemu-custom-adapter';
|
import { CustomAdapter } from '../models/qemu/qemu-custom-adapter';
|
||||||
import { IouTemplate } from '../models/templates/iou-template';
|
import { IouTemplate } from '../models/templates/iou-template';
|
||||||
|
import { TracengTemplate } from '../models/templates/traceng-template';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TemplateMocksService {
|
export class TemplateMocksService {
|
||||||
|
getTracengTemplate() : TracengTemplate {
|
||||||
|
let template: TracengTemplate = {
|
||||||
|
builtin: false,
|
||||||
|
category: 'guest',
|
||||||
|
compute_id: 'local',
|
||||||
|
console_type: 'none',
|
||||||
|
default_name_format: 'TraceNG{0}',
|
||||||
|
ip_address: '',
|
||||||
|
name: '',
|
||||||
|
symbol: ':/symbols/classic/traceng.svg',
|
||||||
|
template_id: '',
|
||||||
|
template_type: 'traceng'
|
||||||
|
};
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
getQemuTemplate() : Observable<QemuTemplate> {
|
getQemuTemplate() : Observable<QemuTemplate> {
|
||||||
let template : QemuTemplate = {
|
let template : QemuTemplate = {
|
||||||
adapter_type: 'e1000',
|
adapter_type: 'e1000',
|
||||||
|
0
src/app/services/traceng.service.spec.ts
Normal file
0
src/app/services/traceng.service.spec.ts
Normal file
27
src/app/services/traceng.service.ts
Normal file
27
src/app/services/traceng.service.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from "@angular/core";
|
||||||
|
import { HttpServer } from './http-server.service';
|
||||||
|
import { Server } from '../models/server';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
|
import { TracengTemplate } from '../models/templates/traceng-template';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TracengService {
|
||||||
|
constructor(private httpServer: HttpServer) {}
|
||||||
|
|
||||||
|
getTemplates(server: Server): Observable<TracengTemplate[]> {
|
||||||
|
return this.httpServer.get<TracengTemplate[]>(server, '/templates') as Observable<TracengTemplate[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTemplate(server: Server, template_id: string): Observable<TracengTemplate> {
|
||||||
|
return this.httpServer.get<TracengTemplate>(server, `/templates/${template_id}`) as Observable<TracengTemplate>;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTemplate(server: Server, vpcsTemplate: TracengTemplate): Observable<TracengTemplate> {
|
||||||
|
return this.httpServer.post<TracengTemplate>(server, `/templates`, vpcsTemplate) as Observable<TracengTemplate>;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTemplate(server: Server, vpcsTemplate: TracengTemplate): Observable<TracengTemplate> {
|
||||||
|
return this.httpServer.put<TracengTemplate>(server, `/templates/${vpcsTemplate.template_id}`, vpcsTemplate) as Observable<TracengTemplate>;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user