From aa810aef68b206c237140ef3baf6c55d27599597 Mon Sep 17 00:00:00 2001 From: insanity Date: Thu, 21 Jun 2018 18:35:24 +0900 Subject: [PATCH] discovery --- @overflow/discovery/component/animation.ts | 2 +- .../discovery-infra-tree.component.html | 83 ++++ .../discovery-infra-tree.component.ts | 420 ++++++++++++++++++ .../component/discovery.component.html | 14 +- .../component/discovery.component.ts | 47 +- @overflow/discovery/component/index.ts | 4 +- .../component/search-filter.component.html | 2 +- .../component/search-result.component.ts | 32 +- @overflow/discovery/component2/animation.ts | 35 ++ .../component2/discovery.component.html | 34 ++ .../component2/discovery.component.ts | 121 +++++ @overflow/discovery/component2/index.ts | 17 + .../component2/ip-input.component.html | 11 + .../component2/ip-input.component.ts | 57 +++ .../component2/request-summary.component.html | 24 + .../component2/request-summary.component.ts | 33 ++ .../component2/search-config.component.html | 106 +++++ .../component2/search-config.component.ts | 311 +++++++++++++ .../component2/search-filter.component.html | 15 + .../component2/search-filter.component.ts | 68 +++ .../component2/search-result.component.html | 61 +++ .../component2/search-result.component.ts | 348 +++++++++++++++ .../service-selector.component.html | 27 ++ .../component2/service-selector.component.ts | 90 ++++ .../infra/component/infra-tree.component.ts | 85 ++-- @overflow/infra/service/infra.service.ts | 5 + 26 files changed, 1971 insertions(+), 81 deletions(-) create mode 100644 @overflow/discovery/component/discovery-infra-tree.component.html create mode 100644 @overflow/discovery/component/discovery-infra-tree.component.ts create mode 100644 @overflow/discovery/component2/animation.ts create mode 100644 @overflow/discovery/component2/discovery.component.html create mode 100644 @overflow/discovery/component2/discovery.component.ts create mode 100644 @overflow/discovery/component2/index.ts create mode 100644 @overflow/discovery/component2/ip-input.component.html create mode 100644 @overflow/discovery/component2/ip-input.component.ts create mode 100644 @overflow/discovery/component2/request-summary.component.html create mode 100644 @overflow/discovery/component2/request-summary.component.ts create mode 100644 @overflow/discovery/component2/search-config.component.html create mode 100644 @overflow/discovery/component2/search-config.component.ts create mode 100644 @overflow/discovery/component2/search-filter.component.html create mode 100644 @overflow/discovery/component2/search-filter.component.ts create mode 100644 @overflow/discovery/component2/search-result.component.html create mode 100644 @overflow/discovery/component2/search-result.component.ts create mode 100644 @overflow/discovery/component2/service-selector.component.html create mode 100644 @overflow/discovery/component2/service-selector.component.ts diff --git a/@overflow/discovery/component/animation.ts b/@overflow/discovery/component/animation.ts index 6d8f3ca..b168306 100644 --- a/@overflow/discovery/component/animation.ts +++ b/@overflow/discovery/component/animation.ts @@ -24,7 +24,7 @@ export const Anim = [ trigger('discoveryResultAnim', [ transition('void => *', [ query('*', style({ opacity: 0 }), { optional: true }), - query('*', stagger('30ms', [ + query('*', stagger('60ms', [ animate('0.08s ease-in', keyframes([ style({ opacity: 0, transform: 'translateX(-95%)', offset: 0 }), style({ opacity: .5, transform: 'translateX(95px)', offset: 0.3 }), diff --git a/@overflow/discovery/component/discovery-infra-tree.component.html b/@overflow/discovery/component/discovery-infra-tree.component.html new file mode 100644 index 0000000..beb2e13 --- /dev/null +++ b/@overflow/discovery/component/discovery-infra-tree.component.html @@ -0,0 +1,83 @@ + + + + + + + + + + + +
+ {{node.data.date | date: 'yy/MM/dd'}} +
+
+ + + + +
+ {{node.data.date | date: 'yy/MM/dd'}} +
+ +
+ New!! +
+ +
+ + + + +
+ {{node.data.date | date: 'yy/MM/dd'}} +
+ +
+ New!! +
+ +
+
+ + + +
+ + + + Target 지정이 완료되었습니다. 이어서 Sensor를 등록하시면 좋겠다능 + + + + + + \ No newline at end of file diff --git a/@overflow/discovery/component/discovery-infra-tree.component.ts b/@overflow/discovery/component/discovery-infra-tree.component.ts new file mode 100644 index 0000000..b1bd755 --- /dev/null +++ b/@overflow/discovery/component/discovery-infra-tree.component.ts @@ -0,0 +1,420 @@ +import { + Component, + Input, + OnChanges, + SimpleChanges, +} from '@angular/core'; +import { Host, Service } from '@overflow/commons-typescript/model/discovery'; +import { TreeNode, Message, Tree } from 'primeng/primeng'; +import { ProbeHost } from '@overflow/commons-typescript/model/probe'; +import { Anim } from './animation'; +import { TargetService } from '@overflow/target/service/target.service'; +import { InfraService, InfraHost, Infra, MetaInfraTypeEnum, toMetaInfraTypeEnum, toMetaInfraType, InfraZone, Target, Page, PageParams } from '@overflow/commons-typescript'; +import { InfraService as InfraManageService } from '../../infra/service/infra.service'; +import { Observable, of, Subscription } from 'rxjs'; +import { catchError, map, tap, take } from 'rxjs/operators'; + +@Component({ + selector: 'of-discovery-infra-tree', + templateUrl: './discovery-infra-tree.component.html', + animations: Anim, + providers: [ + TargetService, + InfraManageService + ] +}) +export class DiscoveryInfraTreeComponent implements OnChanges { + + @Input() probeHost: ProbeHost; + @Input() filterWord: string; + @Input() filterServices: Map; + + targets: Target[]; + infraZones: InfraZone[]; + infraHosts: InfraHost[]; + infraServices: InfraService[]; + + zoneNode: TreeNode[]; + hostNode: TreeNode[]; + selectedItems: TreeNode[] = []; + msgs: Message[]; + + savedInfras: Infra[]; + + discoveredHosts: Host[] = []; + discoveredServices: Service[] = []; + infraSaved: boolean; + targetSaved: boolean; + + pending$: Observable; + error$: Observable; + + constructor( + private infraManageService: InfraManageService, + private targetService: TargetService + ) { + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['probeHost']) { + this.getTargets(); + } + } + + getInfras() { + const pageParams: PageParams = { + pageNo: 0, + countPerPage: 99999, + sortCol: 'id', + sortDirection: 'descending' + }; + this.infraManageService.readAllByProbeID(this.probeHost.probe.id, pageParams) + .pipe( + tap(() => { + this.pending$ = of(true); + }), + map((infraPage: Page) => { + this.generateTree(infraPage.content); + }), + catchError(error => { + this.error$ = of(error); + return of(); + }), + tap(() => { + this.pending$ = of(false); + }), + take(1), + ).subscribe(); + } + + getTargets() { + const pageParams: PageParams = { + pageNo: 0, + countPerPage: 99999, + sortCol: 'id', + sortDirection: 'descending' + }; + this.targetService.readAllByProbeID(this.probeHost.probe.id, pageParams) + .pipe( + tap(() => { + this.pending$ = of(true); + }), + map((targetPage: Page) => { + this.targets = targetPage.content; + this.getInfras(); + }), + catchError(error => { + this.error$ = of(error); + return of(); + }), + tap(() => { + this.pending$ = of(false); + }), + take(1), + ).subscribe(); + } + + generateTree(infras: Infra[]) { + this.zoneNode = []; + this.hostNode = []; + this.infraZones = []; + this.infraHosts = []; + this.infraServices = []; + + for (const infra of infras) { + if (infra.metaInfraType.key === toMetaInfraType(MetaInfraTypeEnum.ZONE).key) { + this.infraZones.push(infra); + } else if (infra.metaInfraType.key === toMetaInfraType(MetaInfraTypeEnum.HOST).key) { + this.infraHosts.push(infra); + } else if (infra.metaInfraType.key === toMetaInfraType(MetaInfraTypeEnum.SERVICE).key) { + this.infraServices.push(infra); + } + } + this.infraZones.forEach(infraZone => { + this.addInfraZone(infraZone); + }); + this.infraHosts.forEach(infraHost => { + this.addInfraHost(infraHost); + }); + this.infraServices.forEach(infraService => { + this.addInfraService(infraService); + }); + } + + addInfraZone(infraZone: InfraZone) { + const target: Target = this.checkAlreadyTarget(infraZone.id); + this.zoneNode.push({ + label: this.probeHost.probe.cidr, + type: 'ZONE', + data: { + target: target, + date: infraZone.createDate, + object: infraZone, + infraID: infraZone.id, + }, + children: this.hostNode, + expanded: true + }); + } + + addInfraHost(infraHost: InfraHost) { + const target: Target = this.checkAlreadyTarget(infraHost.id); + const ip = infraHost.infraHostIPs[0].address + const idx = this.findHostIndex(ip); + this.hostNode.splice(idx, 0, { + type: 'HOST', + label: ip, + data: { + target: target, + date: infraHost.createDate, + ip: this.convertIPtoNumber(ip), + object: infraHost, + infraID: infraHost.id, + }, + expanded: true, + children: [] + }); + } + + addInfraService(infraService: InfraService) { + console.log(infraService); + const target: Target = this.checkAlreadyTarget(infraService.id); + const targetHostNode = this.findHostNodeByService(infraService.infraHostPort.infraHostIP.address); + // const idx = this.findServiceIndex(targetHostNode.children, infraService.metaTargetServiceType.name); + targetHostNode.children.push({ + type: 'SERVICE', + label: 'metaTargetServiceType이 현재 null ' + ' (' + infraService.infraHostPort.port + ')', + data: { + target: target, + date: infraService.createDate, + portType: infraService.infraHostPort.metaPortType.name, + portNumber: infraService.infraHostPort.port, + object: infraService, + infraID: infraService.id, + }, + }); + } + + checkAlreadyTarget(infraID: number): Target { + return this.targets.find(target => target.infra.id === infraID); + } + + discoveryStarted(startedAt: Date) { + console.log('Discovery Started at: ' + startedAt); + this.pending$ = of(true); + } + + discoveryStopped(stoppedAt: Date) { + console.log('Discovery Stopped at: ' + stoppedAt); + this.saveDiscoveredInfras(); + this.pending$ = of(false); + } + + saveDiscoveredInfras() { + this.infraManageService.registDiscoverd( + this.probeHost.probe.id, + this.discoveredHosts, + this.discoveredServices) + .pipe( + tap(() => { + this.infraSaved = false; + this.pending$ = of(true); + }), + map((infras: Infra[]) => { + if (infras) { + this.savedInfras = infras; + this.msgs = []; + this.msgs.push({ + severity: 'success', + summary: infras.length + '개의 Infra가 새로 저장되었습니다. 모니터링 대상(들)을 선택 후 저장하세요.', + }); + } + this.pending$ = of(false); + }), + catchError(error => { + this.error$ = of(error); + return of(); + }), + tap(() => { + this.infraSaved = true; + }), + take(1), + ).subscribe(); + } + + addHost(host: Host) { + let exist = false; + this.infraHosts.forEach(infraHost => { + if (infraHost.infraHostIPs[0].address === host.address) { + exist = true; + return; + } + }); + if (exist) { + return; + } + const idx = this.findHostIndex(host.address); + this.hostNode.splice(idx, 0, { + type: 'HOST', + label: host.address, + data: { + target: null, + date: null, + ip: this.convertIPtoNumber(host.address), + object: host, + infraID: null, + }, + expanded: true, + children: [] + }); + this.discoveredHosts.push(host); + } + + addService(service: Service) { + let exist = false; + this.infraServices.forEach(infraService => { + if (//infraService.metaTargetServiceType.name === service.name && + infraService.infraHostPort.port === service.port.portNumber && + infraService.infraHostPort.infraHostIP.address === service.port.host.address + ) { + exist = true; + return; + } + }); + if (exist) { + return; + } + + const targetHostNode = this.findHostNodeByService(service.port.host.address); + // const idx = this.findServiceIndex(targetHostNode.children, infraService.metaTargetServiceType.name); + targetHostNode.children.push({ + type: 'SERVICE', + label: service.name + ' (' + service.port.portNumber + ')', + data: { + target: null, + date: null, + portType: service.port.metaPortType.name, + portNumber: service.port.portNumber, + object: service, + InfraID: null, + }, + }); + + this.discoveredServices.push(service); + } + + + findHostIndex(hostIP: string): number { + let index = 0; + this.hostNode.forEach(node => { + if (node.data.ip < this.convertIPtoNumber(hostIP)) { + index++; + } + }); + return index; + } + + findServiceIndex(serviceNodes: TreeNode[], serviceName: string) { + let index = 0; + serviceNodes.forEach(node => { + // if (node.data.portNumber < service.port.portNumber) { + // index++; + // } + if (node.data.name.toUpperCase().localeCompare(serviceName.toUpperCase()) === -1) { + index++; + } + }); + return index; + } + + findHostNodeByService(serviceAddress: string) { + let targetHost = null; + this.hostNode.forEach((value, i) => { + if (value.data.ip === this.convertIPtoNumber(serviceAddress)) { + targetHost = value; + return; + } + }); + return targetHost; + } + + convertIPtoNumber(ip: string) { + return ip.split('.').map((octet, index, array) => { + return parseInt(octet) * Math.pow(256, (array.length - index - 1)); + }).reduce((prev, curr) => { + return prev + curr; + }); + } + + checkHighlight(label: string, type: number) { + let highlight = true; + if (this.filterWord && (label.toUpperCase().indexOf(this.filterWord.toUpperCase()) < 0)) { + highlight = false; + } + if (type === 1 && this.filterServices[label] === false) { + highlight = false; + } + return highlight; + } + + onTargetSelect(e, node: TreeNode) { + if (e.checked) { + this.selectedItems.push(node); + } else { + const index = this.selectedItems.indexOf(node); + this.selectedItems.splice(index, 1); + } + } + + saveTargets() { + const targets: Target[] = []; + this.selectedItems.forEach(node => { + const infraID = node.data.infraID; + if (null === infraID) { // 새로 발견된 Host / Service + + } + // const infra: Infra = value; + // let name: string; + // if (value.metaInfraType === toMetaInfraType(MetaInfraTypeEnum.ZONE)) { + // const infraZone: InfraZone = value; + // name = infraZone.network; + // } else if (value.metaInfraType === toMetaInfraType(MetaInfraTypeEnum.HOST)) { + // const infraHost: InfraHost = value; + // name = infraHost.infraHostIPs[0].address; + // } else if (value.metaInfraType === toMetaInfraType(MetaInfraTypeEnum.SERVICE)) { + // const infraService: InfraService = value; + // name = infraService.metaInfraType.name; + // } + + const target: Target = { + infra: { + id: infraID + }, + name: '', + sensorCount: 0, + }; + targets.push(target); + }); + + console.log(targets); + + // this.targetService.registAll(targets, this.probeHost.probe.id) + // .pipe( + // tap(() => { + // }), + // map((targets: Target[]) => { + // if (targets) { + // this.targetSaved = true; + // } + // }), + // catchError(error => { + // this.error$ = of(error); + // return of(); + // }), + // tap(() => { + // }), + // take(1), + // ).subscribe(); + } + +} diff --git a/@overflow/discovery/component/discovery.component.html b/@overflow/discovery/component/discovery.component.html index 2e1e66a..07b8d34 100644 --- a/@overflow/discovery/component/discovery.component.html +++ b/@overflow/discovery/component/discovery.component.html @@ -1,7 +1,7 @@

Discovery

- +
@@ -10,19 +10,19 @@ Choose a Probe to perform Discovery. - + - - + +
- - + +
diff --git a/@overflow/discovery/component/discovery.component.ts b/@overflow/discovery/component/discovery.component.ts index 7fcdf8e..bd79fba 100644 --- a/@overflow/discovery/component/discovery.component.ts +++ b/@overflow/discovery/component/discovery.component.ts @@ -1,10 +1,10 @@ import { - Component, Input, OnDestroy, ViewChild, + Component, Input, OnDestroy, OnInit, ViewChild, } from '@angular/core'; import { Observable, of, Subscription } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; +import { catchError, map, tap, take } from 'rxjs/operators'; import { ProbeHost } from '@overflow/commons-typescript/model/probe'; import { DiscoverZone, Zone, Host, Port, Service } from '@overflow/commons-typescript/model/discovery'; @@ -12,40 +12,46 @@ import { DiscoverZone, Zone, Host, Port, Service } from '@overflow/commons-types import { Anim } from './animation'; import { DiscoveryService } from '../service/discovery.service'; import { DiscoverySubscriber, DiscoveryNotify } from '../subscriber/discovery.subscriber'; -import { SearchResultComponent } from './search-result.component'; import { SearchFilterComponent } from './search-filter.component'; +import { DiscoveryInfraTreeComponent } from './discovery-infra-tree.component'; @Component({ selector: 'of-discovery', templateUrl: './discovery.component.html', animations: Anim, }) -export class DiscoveryComponent implements OnDestroy { + +export class DiscoveryComponent implements OnInit, OnDestroy { @Input() probeHostID; pending$: Observable; error$: Observable; discoverySubscription: Subscription; - selectedProbe: ProbeHost; - requested: boolean; discoverZone: DiscoverZone; - finished: boolean; + + startDate: Date; + stopDate: Date; filterWord: string; filterServices: Service[]; - @ViewChild('discoveryResult') discoveryResult: SearchResultComponent; - @ViewChild('discoveryFilter') discoveryFilter: SearchFilterComponent; + @ViewChild('infraTree') infraTree: DiscoveryInfraTreeComponent; + @ViewChild('filter') filter: SearchFilterComponent; constructor( private discoveryService: DiscoveryService, private discoverySubscriber: DiscoverySubscriber, ) { this.discoverySubscription = null; - this.finished = false; + this.startDate = null; + this.stopDate = null; } + ngOnInit(): void { + } + + ngOnDestroy(): void { if (null !== this.discoverySubscription) { this.discoverySubscription.unsubscribe(); @@ -53,9 +59,7 @@ export class DiscoveryComponent implements OnDestroy { } onRequestDiscovery(dz: DiscoverZone) { - this.requested = true; this.discoverZone = dz; - const zone: Zone = { network: this.selectedProbe.infraHost.infraZone.network, // this.selectedProbe.probe.cidr address: this.selectedProbe.infraHost.infraZone.address.split('/')[0], @@ -71,16 +75,16 @@ export class DiscoveryComponent implements OnDestroy { switch (discoveryNotify.method) { case 'DiscoveryService.discoveryStart': { const startDate = discoveryNotify.params as Date; - + this.startDate = startDate; + this.infraTree.discoveryStarted(startDate); break; } case 'DiscoveryService.discoveryStop': { const stopDate = discoveryNotify.params as Date; - - this.finished = true; + this.stopDate = stopDate; this.discoverySubscription.unsubscribe(); this.discoverySubscription = null; - + this.infraTree.discoveryStopped(stopDate); break; } case 'DiscoveryService.discoveredZone': { @@ -89,7 +93,7 @@ export class DiscoveryComponent implements OnDestroy { } case 'DiscoveryService.discoveredHost': { const host = discoveryNotify.params as Host; - this.discoveryResult.addHost(host); + this.infraTree.addHost(host); break; } case 'DiscoveryService.discoveredPort': { @@ -99,8 +103,8 @@ export class DiscoveryComponent implements OnDestroy { } case 'DiscoveryService.discoveredService': { const service = discoveryNotify.params as Service; - this.discoveryFilter.addService(service); - this.discoveryResult.addService(service); + this.infraTree.addService(service); + this.filter.addService(service); break; } default: { @@ -114,9 +118,4 @@ export class DiscoveryComponent implements OnDestroy { ).subscribe(); } - onRequestStop() { - this.discoverZone = null; - this.requested = false; - this.discoveryService.stopDiscovery(this.selectedProbe.probe.probeKey); - } } diff --git a/@overflow/discovery/component/index.ts b/@overflow/discovery/component/index.ts index 5a4df3a..531dbae 100644 --- a/@overflow/discovery/component/index.ts +++ b/@overflow/discovery/component/index.ts @@ -2,16 +2,16 @@ import { ServiceSelectorComponent } from './service-selector.component'; import { DiscoveryComponent } from './discovery.component'; import { SearchConfigComponent } from './search-config.component'; import { SearchFilterComponent } from './search-filter.component'; -import { SearchResultComponent } from './search-result.component'; import { IpInputComponent } from './ip-input.component'; import { RequestSummaryComponent } from './request-summary.component'; +import { DiscoveryInfraTreeComponent } from './discovery-infra-tree.component'; export const COMPONENTS = [ ServiceSelectorComponent, DiscoveryComponent, SearchConfigComponent, SearchFilterComponent, - SearchResultComponent, IpInputComponent, RequestSummaryComponent, + DiscoveryInfraTreeComponent ]; diff --git a/@overflow/discovery/component/search-filter.component.html b/@overflow/discovery/component/search-filter.component.html index 1300e62..6bb102a 100644 --- a/@overflow/discovery/component/search-filter.component.html +++ b/@overflow/discovery/component/search-filter.component.html @@ -4,7 +4,7 @@
+ [(ngModel)]="filterServices[service.name]"> diff --git a/@overflow/discovery/component/search-result.component.ts b/@overflow/discovery/component/search-result.component.ts index 9fbcdd9..ce80791 100644 --- a/@overflow/discovery/component/search-result.component.ts +++ b/@overflow/discovery/component/search-result.component.ts @@ -1,8 +1,6 @@ import { Component, Input, - SimpleChanges, OnInit, - OnChanges, } from '@angular/core'; import { Host, Port, Service } from '@overflow/commons-typescript/model/discovery'; import { TreeNode, Message, Tree } from 'primeng/primeng'; @@ -23,12 +21,11 @@ import { catchError, map, tap, take } from 'rxjs/operators'; InfraRegistService ] }) -export class SearchResultComponent implements OnInit, OnChanges { +export class SearchResultComponent implements OnInit { @Input() probeHost: ProbeHost; @Input() filterWord: string; @Input() filterServices: Map; - @Input() finished: boolean; infras: Infra[]; existTargets: Target[]; @@ -62,7 +59,16 @@ export class SearchResultComponent implements OnInit, OnChanges { children: this.hostNode, expanded: true }); - this.getExistTarget(); + // this.getExistTarget(); + } + + discoveryStarted(startedAt: Date) { + console.log('Discovery Started at: ' + startedAt); + } + + discoveryStopped(stoppedAt: Date) { + console.log('Discovery Stopped at: ' + stoppedAt); + this.saveDiscoveredInfras(); } getExistTarget() { @@ -89,11 +95,11 @@ export class SearchResultComponent implements OnInit, OnChanges { ).subscribe(); } - ngOnChanges(changes: SimpleChanges): void { - if (changes['finished'] && changes['finished'].currentValue === true) { - this.saveDiscoveredInfras(); - } - } + // ngOnChanges(changes: SimpleChanges): void { + // if (changes['finished'] && changes['finished'].currentValue === true) { + // this.saveDiscoveredInfras(); + // } + // } displayInform() { this.msgs = []; @@ -107,9 +113,9 @@ export class SearchResultComponent implements OnInit, OnChanges { this.hostNode = []; for (const infra of this.infras) { switch (infra.metaInfraType) { - case toMetaInfraType(MetaInfraTypeEnum.ZONE): - const infraZone: InfraZone = infra; - break; + // case toMetaInfraType(MetaInfraTypeEnum.ZONE): + // const infraZone: InfraZone = infra; + // break; case toMetaInfraType(MetaInfraTypeEnum.HOST): const infraHost: InfraHost = infra; this.addInfraHost(infraHost); diff --git a/@overflow/discovery/component2/animation.ts b/@overflow/discovery/component2/animation.ts new file mode 100644 index 0000000..6d8f3ca --- /dev/null +++ b/@overflow/discovery/component2/animation.ts @@ -0,0 +1,35 @@ +import { trigger, state, transition, style, animate, query, stagger, keyframes } from '@angular/animations'; + +export const Anim = [ + trigger('discoveryFilterAnim', [ + transition('void => *', [ + query('*', style({ opacity: 0 }), { optional: true }), + query('*', stagger('3ms', [ + animate('0.08s ease-in', keyframes([ + style({ opacity: 0, transform: 'translateY(-75%)', offset: 0 }), + style({ opacity: .5, transform: 'translateY(35px)', offset: 0.3 }), + style({ opacity: 1, transform: 'translateY(0)', offset: 1.0 }), + ]))]), { optional: true }), + ]), + // transition('* => void', [ + // query('*', style({ opacity: 1 }), { optional: true }), + // query('*', stagger('5ms', [ + // animate('0.08s ease-in', keyframes([ + // style({ opacity: 1, transform: 'translateY(0)', offset: 0 }), + // style({ opacity: .5, transform: 'translateY(35px)', offset: 0.3 }), + // style({ opacity: 0, transform: 'translateY(-75%)', offset: 1.0 }), + // ]))]), { optional: true }), + // ]) + ]), + trigger('discoveryResultAnim', [ + transition('void => *', [ + query('*', style({ opacity: 0 }), { optional: true }), + query('*', stagger('30ms', [ + animate('0.08s ease-in', keyframes([ + style({ opacity: 0, transform: 'translateX(-95%)', offset: 0 }), + style({ opacity: .5, transform: 'translateX(95px)', offset: 0.3 }), + style({ opacity: 1, transform: 'translateX(0)', offset: 1.0 }), + ]))]), { optional: true }), + ]), + ]), +]; diff --git a/@overflow/discovery/component2/discovery.component.html b/@overflow/discovery/component2/discovery.component.html new file mode 100644 index 0000000..5902ffc --- /dev/null +++ b/@overflow/discovery/component2/discovery.component.html @@ -0,0 +1,34 @@ +

Discovery

+
+
+ + +
+
+
+
+ + + Choose a Probe to perform Discovery. + + + + + + + +
+ +
+ + +
+
+ + + +
+ Network Discovery 설명 페이지 +
+
+
\ No newline at end of file diff --git a/@overflow/discovery/component2/discovery.component.ts b/@overflow/discovery/component2/discovery.component.ts new file mode 100644 index 0000000..87e2f5c --- /dev/null +++ b/@overflow/discovery/component2/discovery.component.ts @@ -0,0 +1,121 @@ +import { + Component, Input, OnDestroy, ViewChild, +} from '@angular/core'; + + +import { Observable, of, Subscription } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { ProbeHost } from '@overflow/commons-typescript/model/probe'; +import { DiscoverZone, Zone, Host, Port, Service } from '@overflow/commons-typescript/model/discovery'; + +import { Anim } from './animation'; +import { DiscoveryService } from '../service/discovery.service'; +import { DiscoverySubscriber, DiscoveryNotify } from '../subscriber/discovery.subscriber'; +import { SearchResultComponent } from './search-result.component'; +import { SearchFilterComponent } from './search-filter.component'; + +@Component({ + selector: 'of-discovery', + templateUrl: './discovery.component.html', + animations: Anim, +}) +export class DiscoveryComponent implements OnDestroy { + + @Input() probeHostID; + pending$: Observable; + error$: Observable; + discoverySubscription: Subscription; + + selectedProbe: ProbeHost; + requested: boolean; + discoverZone: DiscoverZone; + + filterWord: string; + filterServices: Service[]; + + startDate: Date; + stopDate: Date; + + @ViewChild('discoveryResult') discoveryResult: SearchResultComponent; + @ViewChild('discoveryFilter') discoveryFilter: SearchFilterComponent; + + constructor( + private discoveryService: DiscoveryService, + private discoverySubscriber: DiscoverySubscriber, + ) { + this.discoverySubscription = null; + } + + ngOnDestroy(): void { + if (null !== this.discoverySubscription) { + this.discoverySubscription.unsubscribe(); + } + } + + onRequestDiscovery(dz: DiscoverZone) { + this.requested = true; + this.discoverZone = dz; + + const zone: Zone = { + network: this.selectedProbe.infraHost.infraZone.network, // this.selectedProbe.probe.cidr + address: this.selectedProbe.infraHost.infraZone.address.split('/')[0], + iface: this.selectedProbe.infraHost.infraZone.iface, + mac: this.selectedProbe.infraHost.infraZone.mac, + metaIPType: this.selectedProbe.infraHost.infraZone.metaIPType, + }; + + this.discoveryService.discoverHost(this.selectedProbe.probe.probeKey, zone, dz.discoverHost); + + this.discoverySubscription = this.discoverySubscriber.observable().pipe( + map((discoveryNotify: DiscoveryNotify) => { + switch (discoveryNotify.method) { + case 'DiscoveryService.discoveryStart': { + const startDate = discoveryNotify.params as Date; + this.discoveryResult.discoveryStarted(startDate); + break; + } + case 'DiscoveryService.discoveryStop': { + const stopDate = discoveryNotify.params as Date; + this.discoveryResult.discoveryStopped(stopDate); + this.discoverySubscription.unsubscribe(); + this.discoverySubscription = null; + break; + } + case 'DiscoveryService.discoveredZone': { + const _zone = discoveryNotify.params as Zone; + break; + } + case 'DiscoveryService.discoveredHost': { + const host = discoveryNotify.params as Host; + this.discoveryResult.addHost(host); + break; + } + case 'DiscoveryService.discoveredPort': { + const port = discoveryNotify.params as Port; + // this.discoveryResult.addPort(port); + break; + } + case 'DiscoveryService.discoveredService': { + const service = discoveryNotify.params as Service; + this.discoveryFilter.addService(service); + this.discoveryResult.addService(service); + break; + } + default: { + break; + } + } + }), + catchError(error => { + return of(); + }), + ).subscribe(); + } + + onRequestStop() { + this.discoverZone = null; + this.requested = false; + this.discoveryService.stopDiscovery(this.selectedProbe.probe.probeKey); + } +} diff --git a/@overflow/discovery/component2/index.ts b/@overflow/discovery/component2/index.ts new file mode 100644 index 0000000..5a4df3a --- /dev/null +++ b/@overflow/discovery/component2/index.ts @@ -0,0 +1,17 @@ +import { ServiceSelectorComponent } from './service-selector.component'; +import { DiscoveryComponent } from './discovery.component'; +import { SearchConfigComponent } from './search-config.component'; +import { SearchFilterComponent } from './search-filter.component'; +import { SearchResultComponent } from './search-result.component'; +import { IpInputComponent } from './ip-input.component'; +import { RequestSummaryComponent } from './request-summary.component'; + +export const COMPONENTS = [ + ServiceSelectorComponent, + DiscoveryComponent, + SearchConfigComponent, + SearchFilterComponent, + SearchResultComponent, + IpInputComponent, + RequestSummaryComponent, +]; diff --git a/@overflow/discovery/component2/ip-input.component.html b/@overflow/discovery/component2/ip-input.component.html new file mode 100644 index 0000000..c0cf9df --- /dev/null +++ b/@overflow/discovery/component2/ip-input.component.html @@ -0,0 +1,11 @@ +
+ {{title}} + + . + + . + + . + +
+ diff --git a/@overflow/discovery/component2/ip-input.component.ts b/@overflow/discovery/component2/ip-input.component.ts new file mode 100644 index 0000000..f42577c --- /dev/null +++ b/@overflow/discovery/component2/ip-input.component.ts @@ -0,0 +1,57 @@ +import { + AfterContentInit, + Component, + EventEmitter, + Input, + Output, + OnInit, +} from '@angular/core'; + +@Component({ + selector: 'of-ip-input', + templateUrl: './ip-input.component.html', +}) +export class IpInputComponent implements OnInit, AfterContentInit { + + first: string; + second: string; + third: string; + fourth: string; + + @Input() hostIp: string; + @Input() title: string; + @Input() fixed: number; + @Output() inputIp = new EventEmitter(); + + constructor( + ) { + } + + ngOnInit() { + if (this.hostIp !== '' && this.hostIp !== null && this.hostIp !== undefined) { + const tempIp = this.hostIp.split('.'); + + this.first = tempIp[0]; + this.second = tempIp[1]; + this.third = tempIp[2]; + this.fourth = tempIp[3]; + } + } + + ngAfterContentInit() { + } + + onIpInput(event) { + if ( + (this.first !== '' && this.first !== undefined) && + (this.second !== '' && this.second !== undefined) && + (this.third !== '' && this.third !== undefined) && + (this.fourth !== '' && this.fourth !== undefined) ) { + event.value = this.first + '.' + this.second + '.' + this.third + '.' + this.fourth; + this.inputIp.emit(event); + } else { + return; + } + } + +} diff --git a/@overflow/discovery/component2/request-summary.component.html b/@overflow/discovery/component2/request-summary.component.html new file mode 100644 index 0000000..8acc404 --- /dev/null +++ b/@overflow/discovery/component2/request-summary.component.html @@ -0,0 +1,24 @@ +
+
+ + +
+ Port type + + TCP + UDP + +
+ + +
+ +
+ {{service}} +
+
+ + {{services.length}} services has selected. +
+
+
\ No newline at end of file diff --git a/@overflow/discovery/component2/request-summary.component.ts b/@overflow/discovery/component2/request-summary.component.ts new file mode 100644 index 0000000..93a6217 --- /dev/null +++ b/@overflow/discovery/component2/request-summary.component.ts @@ -0,0 +1,33 @@ +import { + Component, Input, OnChanges, SimpleChanges, +} from '@angular/core'; +import { DiscoverZone } from '@overflow/commons-typescript/model/discovery'; + +@Component({ + selector: 'of-discovery-request-summary', + templateUrl: './request-summary.component.html', +}) +export class RequestSummaryComponent implements OnChanges { + + @Input() discoverZone: DiscoverZone; + hostRange: string; + hostExclude: string; + portRange: string; + portExclude: string; + services: string[]; + + constructor( + ) { + } + + ngOnChanges(changes: SimpleChanges): void { + this.hostRange = this.discoverZone.discoverHost.firstScanRange + + ' ~ ' + + this.discoverZone.discoverHost.lastScanRange; + this.portRange = this.discoverZone.discoverHost.discoverPort.firstScanRange + + ' ~ ' + + this.discoverZone.discoverHost.discoverPort.lastScanRange; + this.services = this.discoverZone.discoverHost.discoverPort.discoverService.includeServices; + } + +} diff --git a/@overflow/discovery/component2/search-config.component.html b/@overflow/discovery/component2/search-config.component.html new file mode 100644 index 0000000..c2e3211 --- /dev/null +++ b/@overflow/discovery/component2/search-config.component.html @@ -0,0 +1,106 @@ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ {{ipErrMsg}} +
+
+ + + + + +
+
+ +
+
+
+
+ TCP   + +
+
+ UDP   + +
+
+ +
+ +
+ + +
+ {{portErrMsg}} +
+ +
+
+ +
+
+ +
+ + +
+ +
+ +
+
+ + + + Add Ports to exclude. + + + + + + \ No newline at end of file diff --git a/@overflow/discovery/component2/search-config.component.ts b/@overflow/discovery/component2/search-config.component.ts new file mode 100644 index 0000000..aee9738 --- /dev/null +++ b/@overflow/discovery/component2/search-config.component.ts @@ -0,0 +1,311 @@ +import { + Component, EventEmitter, Input, + Output, OnChanges, SimpleChanges +} from '@angular/core'; +import { ProbeHost } from '@overflow/commons-typescript/model/probe'; +import * as CIDR from 'ip-cidr'; +import * as ipRangeCheck from 'ip-range-check'; +import { DiscoverPort, DiscoverService, DiscoverZone } from '@overflow/commons-typescript/model/discovery'; +import { Checkbox } from 'primeng/primeng'; +import { MetaIPTypeEnum, toMetaIPType } from '@overflow/commons-typescript/model/meta'; + +@Component({ + selector: 'of-discovery-search-config', + templateUrl: './search-config.component.html', +}) +export class SearchConfigComponent implements OnChanges { + + SUPPORT_V6 = false; + + @Input() probeHost: ProbeHost; + @Output() requestDiscovery = new EventEmitter(); + + ipType: MetaIPTypeEnum; + startIP: string; + endIP: string; + startPort: string; + endPort: string; + excludeIPs = []; + excludePorts = []; + includeServices = []; + + hostChecked = true; + portChecked = true; + serviceChecked = true; + tcpChecked = true; + udpChecked = true; + + validation = false; + ipErrMsg: string; + portErrMsg: string; + + fixedIPrange: number; + ipArray = []; + portExcludeDisplay = false; + portChips = []; + + constructor( + ) { + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['probeHost']) { + this.initByProbe(); + } + this.validation = true; + } + + initByProbe() { + const cidr = new CIDR(this.probeHost.probe.cidr); + if (!cidr.isValid()) { + return; + } + this.ipType = MetaIPTypeEnum.V4; + this.startIP = cidr.start(); + this.endIP = cidr.end(); + this.startPort = '1'; + this.endPort = '1024'; + // TODO: Initialize services + + this.checkEditableIPrange(cidr); + } + + onIPExcludeFocus() { + const cidr = new CIDR(this.probeHost.probe.cidr); + this.ipArray = cidr.toArray().filter((value) => { + return this.inRange(value) || this.excludeIPs.find(obj => obj.ip === value); + }).map(value => { + return { ip: value }; + }); + + } + + inRange(value) { + const min = this.startIP; + const max = this.endIP; + if (this.ipToNum(min) <= this.ipToNum(value) && this.ipToNum(max) >= this.ipToNum(value)) { + return true; + } + return false; + } + + ipToNum(ip) { + return Number( + ip.split('.') + .map(d => ('000' + d).substr(-3)) + .join('') + ); + } + + onRequestDiscovery() { + let discoverPort: DiscoverPort = null; + let discoverService: DiscoverService = null; + + if (this.serviceChecked) { + const services = []; + for (const service of this.includeServices) { + services.push(service.key); + } + discoverService = { + includeServices: services, + }; + } + if (this.portChecked) { + discoverPort = { + firstScanRange: Number(this.startPort), + lastScanRange: Number(this.endPort), + includeTCP: this.tcpChecked, + includeUDP: this.udpChecked, + excludePorts: this.excludePorts, + discoverService: discoverService + }; + } + const discoverZone: DiscoverZone = { + discoverHost: { + metaIPType: toMetaIPType(this.ipType), + firstScanRange: this.startIP, + lastScanRange: this.endIP, + discoverPort: discoverPort, + excludeHosts: this.excludeIPs, + }, + }; + + console.log(discoverZone); + this.requestDiscovery.emit(discoverZone); + } + + checkEditableIPrange(cidr) { + const startIPArray = cidr.addressStart.parsedAddress; + const endIPArray = cidr.addressEnd.parsedAddress; + let count = 0; + endIPArray.forEach((element, idx) => { + if (element === startIPArray[idx]) { + count++; + } + }); + this.fixedIPrange = count; + } + + onPortCheckChange(serviceCheckbox: Checkbox, checked: boolean) { + if (!checked) { + serviceCheckbox.checked = false; + this.serviceChecked = false; + } else { + if (!this.tcpChecked && !this.udpChecked) { + this.tcpChecked = true; + this.udpChecked = true; + } + } + } + + onServiceCheckChange(portCheckbox: Checkbox, checked: boolean) { + if (checked) { + portCheckbox.checked = true; + this.portChecked = true; + } + } + + onPortTypeCheck(portCheckbox: Checkbox, serviceCheckbox: Checkbox): void { + if (!this.tcpChecked && !this.udpChecked) { + this.portChecked = false; + portCheckbox.checked = false; + this.serviceChecked = false; + serviceCheckbox.checked = false; + } + } + + onInputIP(e, idx: number) { + const value = e.value; + if (idx === 0) { + this.startIP = value; + } else { + this.endIP = value; + } + this.ipErrMsg = this.validateIP(value, idx); + + if (this.ipErrMsg) { + this.validation = false; + } else { + this.validation = true; + } + } + + validateIP(value: string, idx): string { + if (!this.isValidIPregex(value)) { + return 'Not valid IP format.'; + } + if (!ipRangeCheck(value, this.probeHost.probe.cidr)) { + return 'Not valid IP range.'; + } + const ipArray = [this.startIP, this.endIP]; + const sortedIpArray = this.sortIP([this.startIP, this.endIP]); + if (ipArray[0] !== sortedIpArray[0]) { + return 'Not valiad range'; + } + + return null; + } + + isValidIPregex(ip: string): boolean { + if (this.ipType === MetaIPTypeEnum.V4) { + return /^(?=\d+\.\d+\.\d+\.\d+$)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.?){4}$/.test(ip); + } + return false; + } + + sortIP(ipAddressArray) { + return ipAddressArray.sort((a, b) => { + a = a.split('.'); + b = b.split('.'); + for (let i = 0; i < a.length; i++) { + // tslint:disable-next-line:radix + if ((a[i] = parseInt(a[i])) < (b[i] = parseInt(b[i]))) { + return -1; + } else if (a[i] > b[i]) { + return 1; + } + } + return 0; + }); + } + + onInputPort(portNum: string, idx: number) { + if (idx === 0) { + this.startPort = portNum; + } else { + this.endPort = portNum; + } + this.portErrMsg = this.validatePort(portNum); + + if (this.portErrMsg) { + this.validation = false; + } else { + this.validation = true; + } + } + + validatePort(portNum): string { + if (Number(this.startPort) > Number(this.endPort)) { + return 'Not valid port range.'; + } + if (Number(portNum) <= 0 || Number(portNum) > 65535) { + return 'Not valid port range.'; + } + return null; + } + + + onAddExcludePort(event) { + const port = event.value.replace(/\s/g, ''); + if (port.indexOf('~') > 0) { // e.g. 1~3000 + const splited = port.split('~'); + this.portChips.pop(); + const from = Number(splited[0]); + const to = Number(splited[1]); + if (this.checkInvalidPort(from) + || this.checkInvalidPort(to) + || !Number.isInteger(from) + || !Number.isInteger(to)) { + return; + } + const chipItem = 'All ' + from + ' ~ ' + to; + this.portChips.push(chipItem); + for (let i = from; i <= to; i++) { + this.excludePorts.push(String(i)); + } + } else { + const num = Number(event.value); + if (!Number.isInteger(num) || this.checkInvalidPort(num) || this.checkExistExcludePort(event.value)) { + this.portChips.pop(); + return; + } + this.excludePorts.push(event.value); + } + } + + onRemoveExcludePort(event) { + if (event.value.indexOf('~') > 0) { + // e.g. 'All 1 ~ 30' + const splited = event.value.replace(/\s/g, '').replace('All', '').split('~'); + for (let i = Number(splited[0]); i <= Number(splited[1]); i++) { + console.log(String(i)); + const index = this.excludePorts.indexOf(String(i)); + this.excludePorts.splice(index, 1); + } + return; + } + const idx = this.excludePorts.indexOf(event.value); + this.excludePorts.splice(idx, 1); + } + + checkExistExcludePort(portNum) { + return this.excludePorts.find((value) => { + return value === portNum; + }); + } + + checkInvalidPort(port) { + return port <= 0 || port > 65535; + } + +} diff --git a/@overflow/discovery/component2/search-filter.component.html b/@overflow/discovery/component2/search-filter.component.html new file mode 100644 index 0000000..1300e62 --- /dev/null +++ b/@overflow/discovery/component2/search-filter.component.html @@ -0,0 +1,15 @@ +
+ + +
+
+ + + + +
+
+ + +
\ No newline at end of file diff --git a/@overflow/discovery/component2/search-filter.component.ts b/@overflow/discovery/component2/search-filter.component.ts new file mode 100644 index 0000000..9b354f2 --- /dev/null +++ b/@overflow/discovery/component2/search-filter.component.ts @@ -0,0 +1,68 @@ +import { + Component, + OnInit, + Output, + EventEmitter +} from '@angular/core'; +import { Anim } from './animation'; +import { Service } from '@overflow/commons-typescript/model/discovery'; + +@Component({ + selector: 'of-discovery-search-filter', + templateUrl: './search-filter.component.html', + animations: Anim +}) +export class SearchFilterComponent implements OnInit { + + services: Service[] = []; + filterWord: string; + filterServices = new Map(); + + @Output() search = new EventEmitter(); + @Output() serviceSelect = new EventEmitter>(); + + constructor( + ) { + } + + ngOnInit() { + } + + onSearch(e) { + if (e.key !== 'Enter') { + return; + } + this.search.emit(this.filterWord); + } + + addService(service: Service) { + if (service.name.indexOf('Not Supported Service') >= 0) { + const tempName = service.name.split('Perhaps ')[1].split('[')[0]; + service.name = '*' + tempName; + } + let exist = false; + this.services.forEach(value => { + if (value.name === service.name) { + exist = true; + return; + } + }); + if (!exist) { + this.services.push(service); + this.filterServices[service.name] = true; + } + this.serviceSelect.emit(this.filterServices); + } + + onServiceFilter(e, service: Service) { + // if (e.checked) { + // this.filterServices.push(service); + // } else { + // const index = this.filterServices.indexOf(service); + // this.filterServices.splice(index, 1); + // } + + this.serviceSelect.emit(this.filterServices); + } + +} diff --git a/@overflow/discovery/component2/search-result.component.html b/@overflow/discovery/component2/search-result.component.html new file mode 100644 index 0000000..7e17698 --- /dev/null +++ b/@overflow/discovery/component2/search-result.component.html @@ -0,0 +1,61 @@ + + + + + + + + + +
+ {{node.label}} +
+
+ + + +
+
+ +
+ + + + +
+
+ + + +
+
+ +
+ + + + + +
+
+
+ + + +
+ + + + Target 지정이 완료되었습니다. 이어서 Sensor를 등록하시면 좋겠다능 + + + + + + \ No newline at end of file diff --git a/@overflow/discovery/component2/search-result.component.ts b/@overflow/discovery/component2/search-result.component.ts new file mode 100644 index 0000000..ce80791 --- /dev/null +++ b/@overflow/discovery/component2/search-result.component.ts @@ -0,0 +1,348 @@ +import { + Component, Input, + OnInit, +} from '@angular/core'; +import { Host, Port, Service } from '@overflow/commons-typescript/model/discovery'; +import { TreeNode, Message, Tree } from 'primeng/primeng'; +import { ProbeHost } from '@overflow/commons-typescript/model/probe'; +import { Anim } from './animation'; +import { TargetService } from '@overflow/target/service/target.service'; +import { InfraService, InfraHost, MetaTargetHostTypeEnum, toMetaTargetHostType, Infra, MetaInfraTypeEnum, toMetaInfraTypeEnum, toMetaInfraType, InfraZone, Target, Page, PageParams } from '@overflow/commons-typescript'; +import { InfraService as InfraRegistService } from '../../infra/service/infra.service'; +import { Observable, of, Subscription } from 'rxjs'; +import { catchError, map, tap, take } from 'rxjs/operators'; + +@Component({ + selector: 'of-discovery-result', + templateUrl: './search-result.component.html', + animations: Anim, + providers: [ + TargetService, + InfraRegistService + ] +}) +export class SearchResultComponent implements OnInit { + + @Input() probeHost: ProbeHost; + @Input() filterWord: string; + @Input() filterServices: Map; + + infras: Infra[]; + existTargets: Target[]; + + discoverySubscription: Subscription; + zoneNode: TreeNode[] = []; + hostNode: TreeNode[] = []; + selectedItems = []; + msgs: Message[]; + error$: Observable; + + discoveredHosts: Host[] = []; + discoveredServices: Service[] = []; + infraSaved: boolean; + targetSaved: boolean; + + pending$: Observable; + + constructor( + private infraRegistService: InfraRegistService, + private targetService: TargetService + ) { + } + + ngOnInit(): void { + this.zoneNode.push({ + label: this.probeHost.probe.cidr, + type: 'ZONE', + data: { + }, + children: this.hostNode, + expanded: true + }); + // this.getExistTarget(); + } + + discoveryStarted(startedAt: Date) { + console.log('Discovery Started at: ' + startedAt); + } + + discoveryStopped(stoppedAt: Date) { + console.log('Discovery Stopped at: ' + stoppedAt); + this.saveDiscoveredInfras(); + } + + getExistTarget() { + const pageParams: PageParams = { + pageNo: 0, + countPerPage: 99999, + sortCol: 'id', + sortDirection: 'descending' + }; + this.targetService.readAllByProbeID(this.probeHost.probe.id, pageParams) + .pipe( + tap(() => { + }), + map((targetPage: Page) => { + this.existTargets = targetPage.content; + }), + catchError(error => { + this.error$ = of(error); + return of(); + }), + tap(() => { + }), + take(1), + ).subscribe(); + } + + // ngOnChanges(changes: SimpleChanges): void { + // if (changes['finished'] && changes['finished'].currentValue === true) { + // this.saveDiscoveredInfras(); + // } + // } + + displayInform() { + this.msgs = []; + this.msgs.push({ + severity: 'success', + summary: 'Discovery가 완료되었습니다. 모니터링 대상(들)을 선택 후 저장하세요.', + }); + } + + rerenderInfras() { + this.hostNode = []; + for (const infra of this.infras) { + switch (infra.metaInfraType) { + // case toMetaInfraType(MetaInfraTypeEnum.ZONE): + // const infraZone: InfraZone = infra; + // break; + case toMetaInfraType(MetaInfraTypeEnum.HOST): + const infraHost: InfraHost = infra; + this.addInfraHost(infraHost); + break; + case toMetaInfraType(MetaInfraTypeEnum.SERVICE): + const infraService: InfraService = infra; + this.addInfraService(infraService) + break; + default: + break; + } + } + } + + saveDiscoveredInfras() { + this.infraRegistService.registDiscoverd( + this.probeHost.probe.id, + this.discoveredHosts, + this.discoveredServices) + .pipe( + tap(() => { + this.infraSaved = false; + this.pending$ = of(true); + }), + map((infras: Infra[]) => { + if (infras) { + this.infras = infras; + this.rerenderInfras(); + this.displayInform(); + } + }), + catchError(error => { + this.error$ = of(error); + return of(); + }), + tap(() => { + this.infraSaved = true; + this.pending$ = of(false); + }), + take(1), + ).subscribe(); + } + + addHost(host: Host) { + const idx = this.findHostIndex(host); + this.hostNode.splice(idx, 0, { + type: 'HOST', + label: host.address, + data: { + ip: this.convertIPtoNumber(host.address), + mac: host.mac, + target: host + }, + expanded: true, + children: [] + }); + + this.discoveredHosts.push(host); + } + + addService(service: Service) { + const targetHostNode = this.findHostNodeByService(service.port.host.address); + const idx = this.findServiceIndex(targetHostNode.children, service.name); + targetHostNode.children.splice(idx, 0, { + type: 'SERVICE', + label: service.name + ' (' + service.port.portNumber + ')', + data: { + name: service.name, + portType: service.port.metaPortType.key, + portNumber: service.port.portNumber, + target: service + }, + }); + this.discoveredServices.push(service); + } + + addInfraHost(infraHost: InfraHost) { + const host: Host = { + address: infraHost.infraHostIPs[0].address, + } + const idx = this.findHostIndex(host); + this.hostNode.splice(idx, 0, { + type: 'HOST', + label: host.address, + data: { + ip: this.convertIPtoNumber(host.address), + target: infraHost + }, + expanded: true, + children: [] + }); + } + + addInfraService(infraService: InfraService) { + const targetHostNode = this.findHostNodeByService(infraService.infraHostPort.infraHostIP.address); + const idx = this.findServiceIndex(targetHostNode.children, infraService.metaTargetServiceType.name); + targetHostNode.children.splice(idx, 0, { + type: 'SERVICE', + label: infraService.metaTargetServiceType.name + ' (' + infraService.infraHostPort.port + ')', + data: { + name: infraService.metaTargetServiceType.name, + portType: infraService.infraHostPort.metaPortType.name, + portNumber: infraService.infraHostPort.port, + target: infraService + }, + }); + } + + + onTargetSelect(e, node: TreeNode) { + const data = node.data.target; + if (e.checked) { + this.selectedItems.push(data); + } else { + const index = this.selectedItems.indexOf(data); + this.selectedItems.splice(index, 1); + } + } + + + findHostIndex(host: Host): number { + let index = 0; + this.hostNode.forEach(node => { + if (node.data.ip < this.convertIPtoNumber(host.address)) { + index++; + } + }); + return index; + } + + findServiceIndex(serviceNodes: TreeNode[], serviceName: string) { + let index = 0; + serviceNodes.forEach(node => { + // if (node.data.portNumber < service.port.portNumber) { + // index++; + // } + if (node.data.name.toUpperCase().localeCompare(serviceName.toUpperCase()) === -1) { + index++; + } + }); + return index; + } + + findHostNodeByService(serviceAddress: string) { + let targetHost = null; + this.hostNode.forEach((value, i) => { + if (value.data.ip === this.convertIPtoNumber(serviceAddress)) { + targetHost = value; + return; + } + }); + return targetHost; + } + + convertIPtoNumber(ip: string) { + return ip.split('.').map((octet, index, array) => { + return parseInt(octet) * Math.pow(256, (array.length - index - 1)); + }).reduce((prev, curr) => { + return prev + curr; + }); + } + + checkHighlight(label: string, type: number) { + let highlight = true; + if (this.filterWord && (label.toUpperCase().indexOf(this.filterWord.toUpperCase()) < 0)) { + highlight = false; + } + if (type === 1 && this.filterServices[label] === false) { + highlight = false; + } + return highlight; + } + + checkExistTarget(infra: Infra): boolean { + if (!this.infraSaved) { + return false; + } + for (const target of this.existTargets) { + if (target.infra.id === infra.id) { + return true; + } + } + return false; + } + + saveTargets() { + const targets: Target[] = []; + this.selectedItems.forEach(value => { + const infra: Infra = value; + let name: string; + if (value.metaInfraType === toMetaInfraType(MetaInfraTypeEnum.ZONE)) { + const infraZone: InfraZone = value; + name = infraZone.network; + } else if (value.metaInfraType === toMetaInfraType(MetaInfraTypeEnum.HOST)) { + const infraHost: InfraHost = value; + name = infraHost.infraHostIPs[0].address; + } else if (value.metaInfraType === toMetaInfraType(MetaInfraTypeEnum.SERVICE)) { + const infraService: InfraService = value; + name = infraService.metaInfraType.name; + } + + const target: Target = { + infra: { + id: infra.id + }, + name: name, + sensorCount: 0, + }; + targets.push(target); + }); + this.targetService.registAll(targets, this.probeHost.probe.id) + .pipe( + tap(() => { + }), + map((targets: Target[]) => { + if (targets) { + this.targetSaved = true; + } + }), + catchError(error => { + this.error$ = of(error); + return of(); + }), + tap(() => { + }), + take(1), + ).subscribe(); + } + +} diff --git a/@overflow/discovery/component2/service-selector.component.html b/@overflow/discovery/component2/service-selector.component.html new file mode 100644 index 0000000..fb92a7b --- /dev/null +++ b/@overflow/discovery/component2/service-selector.component.html @@ -0,0 +1,27 @@ +
+ + + +
+ + +
+ + + + + + + + {{rowData.name}} + + + + +
+
\ No newline at end of file diff --git a/@overflow/discovery/component2/service-selector.component.ts b/@overflow/discovery/component2/service-selector.component.ts new file mode 100644 index 0000000..ee25973 --- /dev/null +++ b/@overflow/discovery/component2/service-selector.component.ts @@ -0,0 +1,90 @@ +import { + Component, + OnInit, + Input, + AfterContentInit, + Output, + EventEmitter, + OnDestroy +} from '@angular/core'; +import { Store, select, StateObservable } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, exhaustMap, map, tap, take } from 'rxjs/operators'; + +import { RPCClientError } from '@loafer/ng-rpc'; +import { MetaCrawler } from '@overflow/commons-typescript/model/meta'; + +import { MetaCrawlerService } from '@overflow/meta/service/meta-crawler.service'; + +@Component({ + selector: 'of-service-selector', + templateUrl: './service-selector.component.html', +}) +export class ServiceSelectorComponent implements OnInit, AfterContentInit, OnDestroy { + includeServices: MetaCrawler[]; + + @Output() change = new EventEmitter(); + @Input() disabled: boolean; + + metaCrawlers: MetaCrawler[]; + pending$: Observable; + error$: Observable; + + constructor( + protected store: Store, + protected metaCrawlerService: MetaCrawlerService, + ) { + this.includeServices = []; + } + + ngOnInit() { + this.metaCrawlerService.readAll() + .pipe( + tap(() => { + this.pending$ = of(true); + }), + map((metaCrawlers: MetaCrawler[]) => { + this.metaCrawlers = metaCrawlers; + }), + catchError(error => { + this.error$ = of(error); + return of(null); + }), + tap(() => { + this.pending$ = of(false); + this.includeServices = this.metaCrawlers.slice(); + this.change.emit(this.includeServices); + }), + take(1), + ).subscribe(); + } + + ngOnDestroy() { + + } + + ngAfterContentInit() { + // this.listStore.dispatch(new ListStore.ReadAll()); + } + + onSelectAll() { + this.includeServices = []; + this.metaCrawlers.forEach((value) => { + this.includeServices.push(value); + }); + this.change.emit(this.includeServices); + } + + onUnselectAll() { + this.includeServices = []; + this.change.emit(this.includeServices); + } + + onSelect(crawler: MetaCrawler) { + this.change.emit(this.includeServices); + } + onUnselect(crawler: MetaCrawler) { + this.change.emit(this.includeServices); + } + +} diff --git a/@overflow/infra/component/infra-tree.component.ts b/@overflow/infra/component/infra-tree.component.ts index 8ec9d22..7b3d6fe 100644 --- a/@overflow/infra/component/infra-tree.component.ts +++ b/@overflow/infra/component/infra-tree.component.ts @@ -3,10 +3,9 @@ import { } from '@angular/core'; import { InfraService, InfraHost, InfraZone, Infra } from '@overflow/commons-typescript/model/infra'; import { Observable, of } from 'rxjs'; -import { catchError, exhaustMap, map, tap, take } from 'rxjs/operators'; +import { catchError, map, tap, take } from 'rxjs/operators'; import { TreeNode, MenuItem, ContextMenu } from 'primeng/primeng'; -import { PageParams, Page } from '@overflow/commons-typescript/core/model'; -import { ProbeHost, MetaInfraTypeEnum } from '@overflow/commons-typescript'; +import { ProbeHost, MetaInfraTypeEnum, toMetaInfraType } from '@overflow/commons-typescript'; import { InfraService as InfraManageService } from '../service/infra.service'; @Component({ @@ -17,7 +16,10 @@ export class InfraTreeComponent implements OnInit, OnChanges { @Input() probeHost: ProbeHost; - infras: Infra[]; + infraZones: InfraZone[]; + infraHosts: InfraHost[]; + infraServices: InfraService[]; + pending$: Observable; error$: Observable; @@ -46,7 +48,11 @@ export class InfraTreeComponent implements OnInit, OnChanges { this.contextMenuZone = [ { label: 'Zone Menu', command: (event) => this.cmZone.hide() }, { separator: true }, - { label: 'Discovery', icon: 'fa-plus', command: (event) => alert('Discovery') }, + { + label: 'Discovery', icon: 'fa-plus', command: (event) => { + alert('discovery'); + } + }, ]; this.contextMenuHost = [ { label: 'Host Menu', command: (event) => this.cmHost.hide() }, @@ -66,26 +72,36 @@ export class InfraTreeComponent implements OnInit, OnChanges { if (changes['probeHost'].isFirstChange) { this.zoneNode = []; this.hostNode = []; - this.getInfras(); + this.getInfraWithInfraTypeKey(toMetaInfraType(MetaInfraTypeEnum.ZONE).key); + this.getInfraWithInfraTypeKey(toMetaInfraType(MetaInfraTypeEnum.HOST).key); + this.getInfraWithInfraTypeKey(toMetaInfraType(MetaInfraTypeEnum.SERVICE).key); } } - getInfras() { - const pageParams: PageParams = { - pageNo: 0, - countPerPage: 99999, - sortCol: 'id', - sortDirection: 'descending' - }; - this.infraService.readAllByProbeID(this.probeHost.probe.id, pageParams) + getInfraWithInfraTypeKey(metaInfraTypeKey: string) { + this.infraService.readAllByMetaInfraTypeKeyAndProbeID( + metaInfraTypeKey, this.probeHost.probe.id) .pipe( tap(() => { this.pending$ = of(true); }), - map((infraPage: Page) => { - this.infras = infraPage.content; - console.log(this.infras); - this.generateTreeData(this.infras); + map((infras: Infra[]) => { + switch (metaInfraTypeKey) { + case toMetaInfraType(MetaInfraTypeEnum.ZONE).key: + this.infraZones = infras; + break; + case toMetaInfraType(MetaInfraTypeEnum.HOST).key: + this.infraHosts = infras; + break; + case toMetaInfraType(MetaInfraTypeEnum.SERVICE).key: + this.infraServices = infras; + break; + default: + break; + } + if (this.infraZones && this.infraHosts && this.infraServices) { + this.generateTreeData(); + } }), catchError(error => { this.error$ = of(error); @@ -98,21 +114,24 @@ export class InfraTreeComponent implements OnInit, OnChanges { ).subscribe(); } - generateTreeData(infras: Infra[]) { - infras.forEach(infra => { - switch (infra.metaInfraType.key) { - case MetaInfraTypeEnum.ZONE: - this.addZone(infra); - break; - case MetaInfraTypeEnum.HOST: - this.addHost(infra); - break; - case MetaInfraTypeEnum.HOST: - this.addService(infra); - break; - default: - break; - } + generateTreeData() { + if (null === this.infraZones) { + return; + } + this.infraZones.forEach(infraZone => { + this.addZone(infraZone); + }); + if (null === this.infraHosts) { + return; + } + this.infraHosts.forEach(infraHost => { + this.addHost(infraHost); + }); + if (null === this.infraServices) { + return; + } + this.infraServices.forEach(infraService => { + this.addService(infraService); }); } diff --git a/@overflow/infra/service/infra.service.ts b/@overflow/infra/service/infra.service.ts index fbf6dd5..91d1955 100644 --- a/@overflow/infra/service/infra.service.ts +++ b/@overflow/infra/service/infra.service.ts @@ -48,4 +48,9 @@ export class InfraService { public readAllInfraZoneByProbeDomainID(probeDomainID: number): Observable { return this.rpcService.call('InfraService.readAllInfraZoneByProbeDomainID', probeDomainID); } + + public readAllByMetaInfraTypeKeyAndProbeID(metaInfraTypeKey: string, probeID: number): Observable { + return this.rpcService.call('InfraService.readAllByMetaInfraTypeKeyAndProbeID', metaInfraTypeKey, probeID); + } + }