624 lines
19 KiB
TypeScript
624 lines
19 KiB
TypeScript
import { HttpClient } from '@angular/common/http';
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { ConfigService } from '@services/config.service';
|
|
import { ToastrService } from "ngx-toastr";
|
|
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
|
|
|
@Component({
|
|
selector: 'app-global-status',
|
|
templateUrl: './global-status.component.html',
|
|
styleUrl: './global-status.component.css'
|
|
})
|
|
export class GlobalStatusComponent implements OnInit {
|
|
baseUrl: string;
|
|
loading: boolean = false;
|
|
loadingOgBoot: boolean = false;
|
|
loadingDhcps: boolean = false;
|
|
loadingRepositories: boolean = false;
|
|
errorOgBoot: boolean = false;
|
|
errorDhcps: { [key: string]: boolean } = {};
|
|
errorRepositories: { [key: string]: boolean } = {};
|
|
installedOgLives: any[] = [];
|
|
subnets: any[] = [];
|
|
showLabels: boolean = true;
|
|
isDoughnut: boolean = true;
|
|
colorScheme: any = {
|
|
domain: ['#df200d', '#26a700']
|
|
};
|
|
view: [number, number] = [400, 220];
|
|
repositoriesUrl: string;
|
|
repositories: any[] = [];
|
|
repositoryStatuses: { [key: string]: any } = {};
|
|
lastUpdateTime: string = '';
|
|
selectedRepositoryUuid: string = '';
|
|
selectedSection: 'repositories' | 'ogboot' | 'dhcp' | 'ogcore' = 'repositories';
|
|
|
|
ogBootApiUrl: string;
|
|
ogBootDiskUsage: any = {};
|
|
ogBootServicesStatus: any = {};
|
|
ogBootDiskUsageChartData: any[] = [];
|
|
|
|
dhcpsApiUrl: string;
|
|
dhcps: any[] = [];
|
|
dhcpDiskUsage: any = {};
|
|
dhcpStatuses: { [key: string]: any } = {};
|
|
dhcpDiskUsageChartData: any[] = [];
|
|
selectedDhcpUuid: string = '';
|
|
isDhcp: boolean = false;
|
|
isRepository: boolean = false;
|
|
|
|
ogCoreApiUrl: string;
|
|
|
|
loadingOgBootOgLives: boolean = false;
|
|
loadingOgBootServices: boolean = false;
|
|
loadingOgBootDisk: boolean = false;
|
|
loadingDhcpSubnets: boolean = false;
|
|
loadingDhcpServices: boolean = false;
|
|
loadingDhcpDisk: boolean = false;
|
|
|
|
constructor(
|
|
private configService: ConfigService,
|
|
private toastService: ToastrService,
|
|
private http: HttpClient,
|
|
private sanitizer: DomSanitizer
|
|
) {
|
|
this.baseUrl = this.configService.apiUrl;
|
|
this.ogBootApiUrl = `${this.baseUrl}/og-boot/status`;
|
|
this.dhcpsApiUrl = `${this.baseUrl}/dhcp-servers`;
|
|
this.ogCoreApiUrl = `${this.baseUrl}`;
|
|
this.repositoriesUrl = `${this.baseUrl}/image-repositories`;
|
|
|
|
this.ogBootDiskUsageChartData = [];
|
|
this.dhcpDiskUsageChartData = [];
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.updateLastUpdateTime();
|
|
|
|
this.loadOgBootStatus();
|
|
this.loadDhcps(false);
|
|
this.loadRepositories(false);
|
|
|
|
this.syncSubnets();
|
|
this.syncTemplates();
|
|
this.syncOgLives();
|
|
}
|
|
|
|
syncSubnets() {
|
|
this.http.get<any>(`${this.dhcpsApiUrl}?page=1&itemsPerPage=10`).subscribe(data => {
|
|
const dhcps = data['hydra:member'] || [];
|
|
if (dhcps.length === 0) return;
|
|
|
|
let pending = dhcps.length;
|
|
let hasError = false;
|
|
|
|
const timeoutId = setTimeout(() => {
|
|
if (!hasError) {
|
|
this.toastService.error('Error al sincronizar las subredes: tiempo de espera agotado');
|
|
hasError = true;
|
|
}
|
|
}, 5000);
|
|
|
|
dhcps.forEach((dhcp: any) => {
|
|
this.http.post(`${this.baseUrl}/dhcp-servers/${dhcp.uuid}/sync`, {}).subscribe({
|
|
next: () => {
|
|
pending--;
|
|
if (pending === 0 && !hasError) {
|
|
clearTimeout(timeoutId);
|
|
this.toastService.success('Sincronización de subredes de servidores DHCP exitosa');
|
|
}
|
|
},
|
|
error: (error) => {
|
|
pending--;
|
|
if (!hasError) {
|
|
hasError = true;
|
|
clearTimeout(timeoutId);
|
|
this.toastService.error(error.error['hydra:description'] || `Error al sincronizar subredes del DHCP ${dhcp.name || dhcp.uuid}`);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}, error => {
|
|
console.error('Error fetching DHCP servers for subnet sync', error);
|
|
});
|
|
}
|
|
|
|
syncTemplates() {
|
|
const timeoutId = setTimeout(() => {
|
|
this.toastService.error('Error al sincronizar las plantillas Pxe: tiempo de espera agotado');
|
|
}, 3500);
|
|
|
|
this.http.post(`${this.baseUrl}/pxe-templates/sync`, {})
|
|
.subscribe(response => {
|
|
clearTimeout(timeoutId);
|
|
this.toastService.success('Sincronización de las plantillas Pxe completada');
|
|
}, error => {
|
|
clearTimeout(timeoutId);
|
|
this.toastService.error(error.error['hydra:description'] || 'Error al sincronizar las plantillas Pxe');
|
|
});
|
|
}
|
|
|
|
syncOgLives(): void {
|
|
const timeoutId = setTimeout(() => {
|
|
this.toastService.error('Error al sincronizar las imagenes ogLive : tiempo de espera agotado');
|
|
}, 3500);
|
|
|
|
this.http.post(`${this.baseUrl}/og-lives/sync`, {})
|
|
.subscribe(response => {
|
|
clearTimeout(timeoutId);
|
|
this.toastService.success('Sincronización con los ogLives completada');
|
|
}, error => {
|
|
clearTimeout(timeoutId);
|
|
this.toastService.error(error.error['hydra:description'] || 'Error al sincronizar las imagenes ogLive');
|
|
});
|
|
}
|
|
|
|
[key: string]: any;
|
|
|
|
loadStatus(apiUrl: string, diskUsage: any, servicesStatus: any, diskUsageChartData: any[], installedOgLives: any[], isDhcp: boolean, errorState: string, showLoading: boolean = true): void {
|
|
if (isDhcp) {
|
|
this.loadingDhcps = true;
|
|
} else {
|
|
this.loadingOgBoot = true;
|
|
}
|
|
|
|
if (showLoading) {
|
|
this.loading = true;
|
|
}
|
|
this[errorState] = false;
|
|
const timeoutId = setTimeout(() => {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
if (isDhcp) {
|
|
this.loadingDhcps = false;
|
|
} else {
|
|
this.loadingOgBoot = false;
|
|
}
|
|
this[errorState] = true;
|
|
}, 3500);
|
|
this.http.get<any>(apiUrl).subscribe({
|
|
next: data => {
|
|
diskUsage.used = data.message.disk_usage.used;
|
|
diskUsage.available = data.message.disk_usage.available;
|
|
diskUsage.total = data.message.disk_usage.total;
|
|
diskUsage.percentage = data.message.disk_usage.percentage;
|
|
|
|
Object.assign(servicesStatus, data.message.services_status);
|
|
|
|
if (isDhcp) {
|
|
this.subnets.length = 0;
|
|
if (data.message.subnets) {
|
|
this.subnets.push(...data.message.subnets);
|
|
}
|
|
} else {
|
|
installedOgLives.length = 0;
|
|
if (data.message.installed_oglives) {
|
|
installedOgLives.push(...data.message.installed_oglives);
|
|
}
|
|
this.loadingOgBootOgLives = false;
|
|
}
|
|
|
|
diskUsageChartData.length = 0;
|
|
diskUsageChartData.push(
|
|
{ name: 'Usado', value: parseFloat(diskUsage.used) },
|
|
{ name: 'Disponible', value: parseFloat(diskUsage.available) }
|
|
);
|
|
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
if (isDhcp) {
|
|
this.loadingDhcps = false;
|
|
} else {
|
|
this.loadingOgBoot = false;
|
|
}
|
|
clearTimeout(timeoutId);
|
|
},
|
|
error: error => {
|
|
this.toastService.error(error.error['hydra:description'] || 'Error al cargar el estado de ogBoot');
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
if (isDhcp) {
|
|
this.loadingDhcps = false;
|
|
} else {
|
|
this.loadingOgBoot = false;
|
|
}
|
|
this[errorState] = true;
|
|
clearTimeout(timeoutId);
|
|
}
|
|
});
|
|
}
|
|
|
|
loadRepositories(showLoading: boolean = true): void {
|
|
if (showLoading) {
|
|
this.loading = true;
|
|
}
|
|
this.errorRepositories = {};
|
|
|
|
this.http.get<any>(`${this.repositoriesUrl}?page=1&itemsPerPage=10`).subscribe(
|
|
data => {
|
|
this.repositories = data['hydra:member'] || [];
|
|
|
|
if (this.repositories.length === 0) {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
let remainingRepositories = this.repositories.length;
|
|
const timeoutId = setTimeout(() => {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
this.repositories.forEach(repository => {
|
|
if (!(repository.uuid in this.errorRepositories)) {
|
|
this.errorRepositories[repository.uuid] = true;
|
|
}
|
|
});
|
|
}, 5000);
|
|
|
|
this.repositories.forEach(repository => {
|
|
this.loadRepositoryStatus(repository.uuid, (errorOccurred: boolean) => {
|
|
remainingRepositories--;
|
|
|
|
this.errorRepositories[repository.uuid] = errorOccurred;
|
|
|
|
if (remainingRepositories === 0) {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
clearTimeout(timeoutId);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
error => {
|
|
this.loading = false;
|
|
this.repositories = [];
|
|
this.toastService.error('Error al cargar la lista de repositorios');
|
|
}
|
|
);
|
|
}
|
|
|
|
loadRepositoryStatus(repositoryUuid: string, callback: (errorOccurred: boolean) => void): void {
|
|
console.log(`Cargando estado del repositorio: ${repositoryUuid}`);
|
|
const timeoutId = setTimeout(() => {
|
|
callback(true);
|
|
}, 5000);
|
|
|
|
this.http.get<any>(`${this.baseUrl}/image-repositories/server/${repositoryUuid}/status`).subscribe(
|
|
data => {
|
|
|
|
if (!data.success) {
|
|
clearTimeout(timeoutId);
|
|
callback(true);
|
|
return;
|
|
}
|
|
|
|
const details = data.details;
|
|
const { disk, services, ram, cpu, processes } = details;
|
|
|
|
this.repositoryStatuses[repositoryUuid] = {
|
|
disk: {
|
|
...disk,
|
|
used: parseFloat(disk.used.replace('GB', '')),
|
|
available: parseFloat(disk.available.replace('GB', '')),
|
|
total: parseFloat(disk.total.replace('GB', '')),
|
|
percentage: disk.used_percentage
|
|
},
|
|
ram: {
|
|
...ram,
|
|
used: parseFloat(ram.used.replace('GB', '')),
|
|
available: parseFloat(ram.available.replace('GB', '')),
|
|
total: parseFloat(ram.total.replace('GB', '')),
|
|
percentage: ram.used_percentage
|
|
},
|
|
cpu: {
|
|
used_percentage: cpu.used_percentage
|
|
},
|
|
services: services,
|
|
processes: processes
|
|
};
|
|
clearTimeout(timeoutId);
|
|
callback(false);
|
|
},
|
|
error => {
|
|
this.toastService.error(error.error['hydra:description'] || 'Error al cargar el estado del repositorio');
|
|
clearTimeout(timeoutId);
|
|
callback(true);
|
|
}
|
|
);
|
|
}
|
|
|
|
loadOgBootStatus(): void {
|
|
this.isDhcp = false;
|
|
this.loadStatus(this.ogBootApiUrl, this.ogBootDiskUsage, this.ogBootServicesStatus, this.ogBootDiskUsageChartData, this.installedOgLives, this.isDhcp, 'errorOgBoot', false);
|
|
}
|
|
|
|
|
|
loadDhcps(showLoading: boolean = true): void {
|
|
if (showLoading) {
|
|
this.loading = true;
|
|
}
|
|
this.errorDhcps = {};
|
|
|
|
this.http.get<any>(`${this.dhcpsApiUrl}?page=1&itemsPerPage=10`).subscribe(
|
|
data => {
|
|
this.dhcps = data['hydra:member'] || [];
|
|
|
|
if (this.dhcps.length === 0) {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
let remainingDhcps = this.dhcps.length;
|
|
const timeoutId = setTimeout(() => {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
this.dhcps.forEach(dhcp => {
|
|
if (!(dhcp.uuid in this.errorDhcps)) {
|
|
this.errorDhcps[dhcp.uuid] = true;
|
|
}
|
|
});
|
|
}, 5000);
|
|
|
|
this.dhcps.forEach(dhcp => {
|
|
this.loadDhcpStatus(dhcp.uuid, (errorOccurred: boolean) => {
|
|
remainingDhcps--;
|
|
|
|
this.errorDhcps[dhcp.uuid] = errorOccurred;
|
|
|
|
if (remainingDhcps === 0) {
|
|
if (showLoading) {
|
|
this.loading = false;
|
|
}
|
|
clearTimeout(timeoutId);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
error => {
|
|
this.loading = false;
|
|
this.dhcps = [];
|
|
this.toastService.error('Error al cargar la lista de Dhcps');
|
|
}
|
|
);
|
|
}
|
|
|
|
loadDhcpStatus(dhcpUuid: string, callback: (errorOccurred: boolean) => void): void {
|
|
console.log(`Cargando estado del Dhcp: ${dhcpUuid}`);
|
|
const timeoutId = setTimeout(() => {
|
|
callback(true);
|
|
}, 5000);
|
|
|
|
this.http.get<any>(`${this.baseUrl}/dhcp-servers/server/${dhcpUuid}/status`).subscribe(
|
|
data => {
|
|
|
|
if (!data.success) {
|
|
clearTimeout(timeoutId);
|
|
callback(true);
|
|
return;
|
|
}
|
|
const disk = data.message.disk_usage;
|
|
const services = data.message.services_status;
|
|
let diskUsageChartData: any[] = [];
|
|
diskUsageChartData.length = 0;
|
|
diskUsageChartData.push(
|
|
{ name: 'Usado', value: parseFloat(disk.used) },
|
|
{ name: 'Disponible', value: parseFloat(disk.available) }
|
|
);
|
|
|
|
this.subnets.length = 0;
|
|
if (data.message.subnets) {
|
|
this.subnets.push(...data.message.subnets);
|
|
}
|
|
|
|
this.dhcpStatuses[dhcpUuid] = {
|
|
disk: {
|
|
...disk,
|
|
used: parseFloat(disk.used.replace('GB', '')),
|
|
available: parseFloat(disk.available.replace('GB', '')),
|
|
total: parseFloat(disk.total.replace('GB', '')),
|
|
percentage: disk.used_percentage
|
|
},
|
|
services: services,
|
|
diskUsageChartData: diskUsageChartData
|
|
};
|
|
clearTimeout(timeoutId);
|
|
callback(false);
|
|
},
|
|
error => {
|
|
this.toastService.error(error.error['hydra:description'] || 'Error al cargar el estado del dhcp');
|
|
clearTimeout(timeoutId);
|
|
callback(true);
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
onDhcpChange(dhcpUuid: string): void {
|
|
this.selectedDhcpUuid = dhcpUuid;
|
|
if (dhcpUuid && !this.dhcpStatuses[dhcpUuid]) {
|
|
this.loadDhcpStatus(dhcpUuid, (errorOccurred: boolean) => {
|
|
if (errorOccurred) {
|
|
this.errorDhcps[dhcpUuid] = true;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
getSelectedDhcpName(): string {
|
|
const selectedDhcp = this.dhcps.find(dhcp => dhcp.uuid === this.selectedDhcpUuid);
|
|
return selectedDhcp ? selectedDhcp.name : '';
|
|
}
|
|
|
|
|
|
onRepositoryChange(repositoryUuid: string): void {
|
|
this.selectedRepositoryUuid = repositoryUuid;
|
|
if (repositoryUuid && !this.repositoryStatuses[repositoryUuid]) {
|
|
this.loadRepositoryStatus(repositoryUuid, (errorOccurred: boolean) => {
|
|
if (errorOccurred) {
|
|
this.errorRepositories[repositoryUuid] = true;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
getSelectedRepositoryName(): string {
|
|
const selectedRepo = this.repositories.find(repo => repo.uuid === this.selectedRepositoryUuid);
|
|
return selectedRepo ? selectedRepo.name : '';
|
|
}
|
|
|
|
getRepositoryIframeUrl(): SafeResourceUrl {
|
|
const repositoryName = this.getSelectedRepositoryName();
|
|
if (repositoryName) {
|
|
const encodedName = encodeURIComponent(repositoryName);
|
|
const url = `${this.configService.logUrl}/d-solo/ogrepo-logs/ogrepo-logs?orgId=1&timezone=browser&refresh=5s&var-query0=&editIndex=0&var-hostname=${encodedName}&theme=dark&panelId=1&__feature.dashboardSceneSolo`;
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
}
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl('');
|
|
}
|
|
|
|
getOgBootIframeUrl(): SafeResourceUrl {
|
|
const url = `${this.configService.logUrl}/d-solo/ogboot-logs/ogboot-logs?orgId=1&timezone=browser&refresh=5s&theme=dark&panelId=1&__feature.dashboardSceneSolo`;
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
}
|
|
|
|
getDhcpIframeUrl(): SafeResourceUrl {
|
|
const dhcpName = this.getSelectedDhcpName();
|
|
if (dhcpName) {
|
|
const encodedName = encodeURIComponent(dhcpName);
|
|
const url = `${this.configService.logUrl}/d-solo/ogdhcp-logs/ogdhcp-logs?orgId=1&timezone=browser&refresh=5s&var-query0=&editIndex=0&var-hostname=${encodedName}&theme=dark&panelId=1&__feature.dashboardSceneSolo`;
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
}
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl('');
|
|
|
|
}
|
|
|
|
getOgCoreIframeUrl(): SafeResourceUrl {
|
|
const url = `${this.configService.logUrl}/d-solo/ogcore-logs/ogcore-logs?orgId=1&tab=transformations&theme=dark&panelId=1&__feature.dashboardSceneSolo&now-5m&to=now&timezone=browser`;
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
}
|
|
|
|
refreshAll(): void {
|
|
this.loading = true;
|
|
this.updateLastUpdateTime();
|
|
this.loadStatus(this.ogBootApiUrl, this.ogBootDiskUsage, this.ogBootServicesStatus, this.ogBootDiskUsageChartData, this.installedOgLives, false, 'errorOgBoot', true);
|
|
this.loadDhcps(true);
|
|
this.loadRepositories(true);
|
|
this.syncSubnets();
|
|
this.syncTemplates();
|
|
this.syncOgLives();
|
|
this.toastService.success('Datos actualizados correctamente');
|
|
}
|
|
|
|
updateLastUpdateTime(): void {
|
|
const now = new Date();
|
|
this.lastUpdateTime = now.toLocaleTimeString('es-ES', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
});
|
|
}
|
|
|
|
getCurrentTime(): string {
|
|
const now = new Date();
|
|
return now.toLocaleTimeString('es-ES', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
});
|
|
}
|
|
|
|
retryRepositoryStatus(repositoryUuid: string): void {
|
|
this.loadRepositoryStatus(repositoryUuid, (errorOccurred: boolean) => {
|
|
this.errorRepositories[repositoryUuid] = errorOccurred;
|
|
if (!errorOccurred) {
|
|
this.toastService.success('Estado del repositorio actualizado correctamente');
|
|
} else {
|
|
this.toastService.error('Error al cargar el estado del repositorio');
|
|
}
|
|
});
|
|
}
|
|
|
|
retryDhcpStatus(dhcpUuid: string): void {
|
|
this.loadDhcpStatus(dhcpUuid, (errorOccurred: boolean) => {
|
|
this.errorDhcps[dhcpUuid] = errorOccurred;
|
|
if (!errorOccurred) {
|
|
this.toastService.success('Estado del dhcp actualizado correctamente');
|
|
} else {
|
|
this.toastService.error('Error al cargar el estado del dhcp');
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
selectSection(section: 'repositories' | 'ogboot' | 'dhcp' | 'ogcore'): void {
|
|
this.selectedSection = section;
|
|
|
|
switch (section) {
|
|
case 'repositories':
|
|
break;
|
|
case 'ogboot':
|
|
if (!this.ogBootDiskUsage) {
|
|
this.loadOgBootStatus();
|
|
}
|
|
break;
|
|
case 'dhcp':
|
|
break;
|
|
case 'ogcore':
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
scrollToLogs(): void {
|
|
let logsSectionId: string;
|
|
switch (this.selectedSection) {
|
|
case 'repositories':
|
|
logsSectionId = 'repository-logs-section';
|
|
break;
|
|
case 'ogboot':
|
|
logsSectionId = 'ogboot-logs-section';
|
|
break;
|
|
case 'dhcp':
|
|
logsSectionId = 'dhcp-logs-section';
|
|
break;
|
|
case 'ogcore':
|
|
logsSectionId = 'ogcore-logs-section';
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
const checkAndScroll = () => {
|
|
const logsSection = document.getElementById(logsSectionId);
|
|
if (logsSection) {
|
|
logsSection.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start'
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
const interval = setInterval(() => {
|
|
if (checkAndScroll()) {
|
|
clearInterval(interval);
|
|
}
|
|
}, 100);
|
|
|
|
setTimeout(() => {
|
|
clearInterval(interval);
|
|
}, 3000);
|
|
}
|
|
}
|