import { Component, Input, OnChanges, SimpleChanges, } from '@angular/core'; import { Host, Service } from '@overflow/commons-typescript/model/discovery'; import { TreeNode, Message } 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, toMetaInfraType, InfraZone, Target, Page, PageParams, InfraHostIP } from '@overflow/commons-typescript'; import { InfraService as InfraManageService } from '../../infra/service/infra.service'; import { Observable, of } 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() { this.infraManageService.readAllByProbeID(this.probeHost.probe.id) .pipe( tap(() => { this.pending$ = of(true); }), map((infras: Infra[]) => { this.generateTree(infras); }), catchError(error => { this.error$ = of(error); return of(); }), tap(() => { this.pending$ = of(false); }), take(1), ).subscribe(); } getTargets() { this.targetService.readAllByProbeID(this.probeHost.probe.id) .pipe( tap(() => { this.pending$ = of(true); }), map((targets: Target[]) => { this.targets = targets; 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) { if (infraHost.infraHostIPs[0].address.indexOf('/') >= 0) { return; } 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) { 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.splice(idx, 0, { type: 'SERVICE', label: infraService.metaTargetServiceType.name + ' (' + infraService.infraHostPort.port + ')', data: { target: target, date: infraService.createDate, portType: infraService.infraHostPort.metaPortType.name, portNumber: infraService.infraHostPort.port, object: infraService, infraID: infraService.id, name: infraService.metaTargetServiceType.name }, }); } 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() { console.log(this.discoveredHosts); console.log(this.discoveredServices); 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.key === service.key && infraService.infraHostPort.port === service.port.portNumber && infraService.infraHostPort.infraHostIP.address === service.port.host.address && infraService.infraHostPort.metaPortType.key === service.port.metaPortType.key ) { exist = true; return; } }); if (exist) { return; } const targetHostNode = this.findHostNodeByService(service.port.host.address); const idx = this.findServiceIndex(targetHostNode.children, service.key); targetHostNode.children.splice(idx, 0, { type: 'SERVICE', label: service.key + ' (' + service.port.portNumber + ')', data: { target: null, date: null, portType: service.port.metaPortType.name, portNumber: service.port.portNumber, object: service, InfraID: null, name: service.key }, }); 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): number { let index = 0; serviceNodes.forEach(node => { if (node.data.name.toUpperCase().localeCompare(serviceName.toUpperCase()) === -1) { index++; } }); return index; } findHostNodeByService(serviceAddress: string): TreeNode { let targetHost = null; this.hostNode.forEach((value, i) => { if (value.data.ip === this.convertIPtoNumber(serviceAddress)) { targetHost = value; return; } }); return targetHost; } convertIPtoNumber(ip: string): number { 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() { this.pending$ = of(true); const infraIDs: number[] = []; this.selectedItems.forEach(node => { let infraID = node.data.infraID; if (null === infraID) { // 새로 발견된 Host or Service for (const infra of this.savedInfras) { if (infra.metaInfraType.key === toMetaInfraType(MetaInfraTypeEnum.HOST).key) { const infraHost: InfraHost = infra; const host: Host = node.data.object; if (infraHost.infraHostIPs[0].address === host.address) { infraID = infraHost.id; } } else if (infra.metaInfraType.key === toMetaInfraType(MetaInfraTypeEnum.SERVICE).key) { const infraService: InfraService = infra; const service: Service = node.data.object; if (infraService.metaTargetServiceType.key === service.key && infraService.infraHostPort.infraHostIP.address === service.port.host.address && infraService.infraHostPort.port === service.port.portNumber && infraService.infraHostPort.metaPortType.key === service.port.metaPortType.key ) { infraID = infraService.id; } } } } if (null === infraID) { console.log('INFRA ID not found.'); return; } infraIDs.push(infraID); }); console.log(infraIDs); this.targetService.registAll(infraIDs, this.probeHost.probe.id) .pipe( tap(() => { }), map((targets: Target[]) => { if (targets) { this.targetSaved = true; this.pending$ = of(false); } }), catchError(error => { this.error$ = of(error); return of(); }), tap(() => { }), take(1), ).subscribe(); } }