feat: Veeam VSPC backup integration - sync, compliance, UI
- Database: 7 Veeam tables + backup_type_udf column on configuration_items - API Client: VSPC REST API v3 client with pagination, rate limiting, Bearer auth - Sync Service: full/incremental sync for orgs, servers, repos, jobs, agent jobs, workloads - Scheduler: veeam-incremental (30min) and veeam-full (daily 2AM) schedules - Compliance Engine: cross-references Autotask config items vs Veeam workloads - API Endpoints: backup-status, companies, workloads, jobs, repos, compliance, sync - UI: Backup Status page with Overview + Contract Compliance tabs - Navigation: added Backup Status link with HardDrive icon - Docker: added VEEAM_VSPC_URL and VEEAM_VSPC_API_KEY env vars to compose
This commit is contained in:
parent
a1e0e7c7c0
commit
5dc7a7e66b
27 changed files with 3408 additions and 7 deletions
369
lib/types/veeam.ts
Normal file
369
lib/types/veeam.ts
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/**
|
||||
* Veeam Service Provider Console (VSPC) Type Definitions
|
||||
* Based on VSPC REST API v3 response shapes
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// VSPC API Response Types (raw API shapes)
|
||||
// ============================================================================
|
||||
|
||||
export interface VspcPagingInfo {
|
||||
total: number;
|
||||
count: number;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface VspcMeta {
|
||||
pagingInfo: VspcPagingInfo;
|
||||
}
|
||||
|
||||
export interface VspcListResponse<T> {
|
||||
meta: VspcMeta;
|
||||
data: T[];
|
||||
}
|
||||
|
||||
export interface VspcSingleResponse<T> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// VSPC Entity Types (API response shapes)
|
||||
// ============================================================================
|
||||
|
||||
export interface VspcOrganization {
|
||||
instanceUid: string;
|
||||
name: string;
|
||||
alias: string | null;
|
||||
type: string; // 'Provider' | 'Company'
|
||||
taxId: string;
|
||||
email: string | null;
|
||||
phone: string;
|
||||
country: number | null;
|
||||
state: number | null;
|
||||
countryName: string;
|
||||
regionName: string;
|
||||
city: string;
|
||||
street: string;
|
||||
locationAdmin0Code: string;
|
||||
locationAdmin1Code: string;
|
||||
locationAdmin2Code: string;
|
||||
notes: string;
|
||||
zipCode: string;
|
||||
website: string;
|
||||
veeamTenantId: string;
|
||||
companyId: string; // Autotask Company ID (string, needs parseInt)
|
||||
}
|
||||
|
||||
export interface VspcBackupServer {
|
||||
instanceUid: string;
|
||||
name: string;
|
||||
organizationUid: string;
|
||||
locationUid: string;
|
||||
managementAgentUid: string;
|
||||
version: string;
|
||||
displayVersion: string;
|
||||
installationUid: string;
|
||||
backupServerRoleType: string; // 'Client' | 'Hosted' | etc.
|
||||
status: string; // 'Healthy' | 'Warning' | 'Error'
|
||||
inHighAvailabilityCluster: boolean;
|
||||
}
|
||||
|
||||
export interface VspcBackupJobSchedule {
|
||||
startDateTime: string;
|
||||
startDateTimeUtc: string;
|
||||
dailyScheduleOptions: unknown | null;
|
||||
monthlyScheduleOptions: unknown | null;
|
||||
periodicallyScheduleOptions: unknown | null;
|
||||
backupWindowOptions: unknown | null;
|
||||
continuousScheduleEnabled: boolean;
|
||||
chainingOptions: unknown | null;
|
||||
}
|
||||
|
||||
export interface VspcBackupJob {
|
||||
instanceUid: string;
|
||||
uniqueUid: string;
|
||||
name: string;
|
||||
description: string;
|
||||
createdBy: string;
|
||||
creationTime: string;
|
||||
backupServerUid: string;
|
||||
locationUid: string;
|
||||
siteUid: string;
|
||||
organizationUid: string;
|
||||
mappedOrganizationUid: string;
|
||||
status: string; // 'Success' | 'Warning' | 'Failed' | 'Running' | 'Idle' | 'None'
|
||||
type: string; // 'BackupVm' | 'SimpleBackupCopy' | 'Replica' | etc.
|
||||
lastRun: string | null;
|
||||
lastEndTime: string | null;
|
||||
lastDuration: number; // seconds
|
||||
processingRate: number;
|
||||
avgDuration: number;
|
||||
transferredData: number; // bytes
|
||||
backupChainSize: number; // bytes
|
||||
bottleneck: string; // 'None' | 'Source' | 'Target' | 'Network' | 'Proxy'
|
||||
isEnabled: boolean;
|
||||
scheduleType: string; // 'Continuously' | 'Periodically' | 'Daily' | etc.
|
||||
schedule: VspcBackupJobSchedule;
|
||||
failureMessage: string | null;
|
||||
targetType: string; // 'Local' | 'Cloud'
|
||||
destination: string;
|
||||
retentionLimit: number;
|
||||
retentionLimitType: string; // 'Days' | 'RestorePoints'
|
||||
isGfsOptionEnabled: boolean;
|
||||
lastSessionTasks: unknown[];
|
||||
}
|
||||
|
||||
export interface VspcBackupAgentJob {
|
||||
instanceUid: string;
|
||||
originalUid: string;
|
||||
backupAgentUid: string;
|
||||
organizationUid: string;
|
||||
name: string;
|
||||
description: string;
|
||||
configUid: string;
|
||||
systemType: string; // 'Windows' | 'Linux' | 'Mac'
|
||||
backupPolicyUid: string;
|
||||
backupPolicyName: string;
|
||||
backupPolicyAssignStatus: string; // 'Success' | 'Warning' | 'Failed'
|
||||
backupPolicyFailureMessage: string | null;
|
||||
status: string; // 'Success' | 'Warning' | 'Failed' | 'Running' | 'None'
|
||||
operationMode: string; // 'Workstation' | 'Server'
|
||||
destination: string;
|
||||
restorePoints: number;
|
||||
lastRun: string | null;
|
||||
lastEndTime: string | null;
|
||||
lastDuration: number; // seconds
|
||||
nextRun: string | null;
|
||||
avgDuration: number;
|
||||
backupMode: string; // 'File' | 'EntireComputer' | 'Volume'
|
||||
targetType: string; // 'CloudRepository' | 'Local'
|
||||
isEnabled: boolean;
|
||||
scheduleType: string; // 'Daily' | 'Periodically' | etc.
|
||||
scheduleDisplayName: string;
|
||||
lastModifiedDate: string | null;
|
||||
lastModifiedBy: string | null;
|
||||
failureMessage: string | null;
|
||||
backedUpSize: number; // bytes
|
||||
freeSpace: number; // bytes
|
||||
}
|
||||
|
||||
export interface VspcProtectedWorkload {
|
||||
instanceUid: string;
|
||||
backupServerUid: string;
|
||||
organizationUid: string;
|
||||
name: string;
|
||||
hierarchyRef: string;
|
||||
parentHostRef: string;
|
||||
objectUid: string;
|
||||
ipAddresses: string[];
|
||||
provisionedSourceSize: number; // bytes
|
||||
usedSourceSize: number; // bytes
|
||||
totalRestorePointSize: number; // bytes
|
||||
latestRestorePointSize: number; // bytes
|
||||
restorePoints: number;
|
||||
latestRestorePointDate: string | null;
|
||||
jobUid: string;
|
||||
malwareState: string; // 'Unverified' | 'Clean' | 'Suspicious' | 'Infected'
|
||||
immutable: boolean;
|
||||
}
|
||||
|
||||
export interface VspcRepository {
|
||||
instanceUid: string;
|
||||
name: string;
|
||||
backupServerUid: string;
|
||||
capacityBytes?: number;
|
||||
freeSpaceBytes?: number;
|
||||
usedSpaceBytes?: number;
|
||||
repositoryType?: string;
|
||||
_embedded: unknown | null;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Database Entity Types (PostgreSQL row shapes)
|
||||
// ============================================================================
|
||||
|
||||
export interface VeeamOrganization {
|
||||
instance_uid: string;
|
||||
name: string;
|
||||
type: string | null;
|
||||
company_id: number | null;
|
||||
tax_id: string | null;
|
||||
email: string | null;
|
||||
phone: string | null;
|
||||
country: string | null;
|
||||
state: string | null;
|
||||
city: string | null;
|
||||
street: string | null;
|
||||
zip_code: string | null;
|
||||
website: string | null;
|
||||
notes: string | null;
|
||||
synced_at: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface VeeamBackupServer {
|
||||
instance_uid: string;
|
||||
name: string;
|
||||
organization_uid: string | null;
|
||||
version: string | null;
|
||||
display_version: string | null;
|
||||
status: string | null;
|
||||
backup_server_role_type: string | null;
|
||||
installation_uid: string | null;
|
||||
location_uid: string | null;
|
||||
management_agent_uid: string | null;
|
||||
synced_at: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface VeeamBackupJob {
|
||||
instance_uid: string;
|
||||
unique_uid: string | null;
|
||||
name: string;
|
||||
description: string | null;
|
||||
backup_server_uid: string | null;
|
||||
organization_uid: string | null;
|
||||
status: string | null;
|
||||
type: string | null;
|
||||
last_run: Date | null;
|
||||
last_end_time: Date | null;
|
||||
last_duration: number | null;
|
||||
processing_rate: number | null;
|
||||
avg_duration: number | null;
|
||||
transferred_data: number | null;
|
||||
backup_chain_size: number | null;
|
||||
bottleneck: string | null;
|
||||
is_enabled: boolean;
|
||||
schedule_type: string | null;
|
||||
failure_message: string | null;
|
||||
target_type: string | null;
|
||||
destination: string | null;
|
||||
retention_limit: number | null;
|
||||
retention_limit_type: string | null;
|
||||
is_gfs_option_enabled: boolean;
|
||||
synced_at: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface VeeamBackupAgentJob {
|
||||
instance_uid: string;
|
||||
original_uid: string | null;
|
||||
backup_agent_uid: string | null;
|
||||
organization_uid: string | null;
|
||||
name: string;
|
||||
description: string | null;
|
||||
config_uid: string | null;
|
||||
system_type: string | null;
|
||||
backup_policy_uid: string | null;
|
||||
backup_policy_name: string | null;
|
||||
backup_policy_assign_status: string | null;
|
||||
backup_policy_failure_message: string | null;
|
||||
status: string | null;
|
||||
operation_mode: string | null;
|
||||
destination: string | null;
|
||||
restore_points: number | null;
|
||||
last_run: Date | null;
|
||||
last_end_time: Date | null;
|
||||
last_duration: number | null;
|
||||
next_run: Date | null;
|
||||
avg_duration: number | null;
|
||||
backup_mode: string | null;
|
||||
target_type: string | null;
|
||||
is_enabled: boolean;
|
||||
schedule_type: string | null;
|
||||
failure_message: string | null;
|
||||
backed_up_size: number | null;
|
||||
free_space: number | null;
|
||||
synced_at: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface VeeamProtectedWorkload {
|
||||
instance_uid: string;
|
||||
name: string;
|
||||
backup_server_uid: string | null;
|
||||
organization_uid: string | null;
|
||||
job_uid: string | null;
|
||||
ip_addresses: string | null; // JSON string of IP array
|
||||
provisioned_source_size: number | null;
|
||||
used_source_size: number | null;
|
||||
total_restore_point_size: number | null;
|
||||
latest_restore_point_size: number | null;
|
||||
restore_points: number | null;
|
||||
latest_restore_point_date: Date | null;
|
||||
malware_state: string | null;
|
||||
immutable: boolean;
|
||||
synced_at: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface VeeamRepository {
|
||||
instance_uid: string;
|
||||
name: string;
|
||||
backup_server_uid: string | null;
|
||||
capacity_bytes: number | null;
|
||||
free_space_bytes: number | null;
|
||||
used_space_bytes: number | null;
|
||||
repository_type: string | null;
|
||||
synced_at: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
}
|
||||
|
||||
export interface VeeamComplianceResult {
|
||||
id: number;
|
||||
company_id: number | null;
|
||||
configuration_item_id: number | null;
|
||||
veeam_workload_uid: string | null;
|
||||
mismatch_type: 'contracted_not_backed_up' | 'backed_up_not_contracted';
|
||||
backup_type_udf: string | null;
|
||||
device_name: string;
|
||||
contract_name: string | null;
|
||||
veeam_workload_name: string | null;
|
||||
computed_at: Date;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// UI / Aggregation Types
|
||||
// ============================================================================
|
||||
|
||||
export interface VeeamBackupStatusSummary {
|
||||
totalProtectedWorkloads: number;
|
||||
unprotectedWorkloads: number;
|
||||
successRate24h: number; // percentage 0-100
|
||||
failedJobs24h: number;
|
||||
totalRepositoryCapacityBytes: number;
|
||||
totalRepositoryUsedBytes: number;
|
||||
repositoryUsagePercent: number;
|
||||
lastSyncAt: Date | null;
|
||||
totalBackupServerJobs: number;
|
||||
totalBackupAgentJobs: number;
|
||||
}
|
||||
|
||||
export interface VeeamCompanyBackupOverview {
|
||||
companyId: number;
|
||||
companyName: string;
|
||||
organizationUid: string;
|
||||
protectedWorkloadCount: number;
|
||||
unprotectedWorkloadCount: number;
|
||||
lastJobStatus: string | null; // 'Success' | 'Warning' | 'Failed'
|
||||
lastSuccessfulBackup: Date | null;
|
||||
oldestRestorePointAge: number | null; // hours
|
||||
backupServerJobCount: number;
|
||||
backupAgentJobCount: number;
|
||||
failedJobCount: number;
|
||||
warningJobCount: number;
|
||||
}
|
||||
|
||||
export interface VeeamComplianceSummary {
|
||||
totalContractedDevices: number;
|
||||
matchedDevices: number;
|
||||
contractedNotBackedUp: number;
|
||||
backedUpNotContracted: number;
|
||||
computedAt: Date | null;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue