package models import ( "reflect" "time" ) func cloneBoolPtr(src *bool) *bool { if src == nil { return nil } v := *src return &v } func cloneFloat64Ptr(src *float64) *float64 { if src == nil { return nil } v := *src return &v } func cloneIntPtr(src *int) *int { if src == nil { return nil } v := *src return &v } func cloneInt64Ptr(src *int64) *int64 { if src == nil { return nil } v := *src return &v } func cloneTimePtr(src *time.Time) *time.Time { if src == nil { return nil } v := *src return &v } func cloneStringMap(src map[string]string) map[string]string { if len(src) == 0 { return nil } dest := make(map[string]string, len(src)) for k, v := range src { dest[k] = v } return dest } func cloneStringFloat64Map(src map[string]float64) map[string]float64 { if len(src) == 0 { return nil } dest := make(map[string]float64, len(src)) for k, v := range src { dest[k] = v } return dest } func cloneCoreTemps(src []CoreTemp) []CoreTemp { return append([]CoreTemp(nil), src...) } func cloneGPUTemps(src []GPUTemp) []GPUTemp { return append([]GPUTemp(nil), src...) } func cloneNVMeTemps(src []NVMeTemp) []NVMeTemp { return append([]NVMeTemp(nil), src...) } func cloneDiskTemps(src []DiskTemp) []DiskTemp { return append([]DiskTemp(nil), src...) } func cloneTemperature(src *Temperature) *Temperature { if src == nil { return nil } dest := *src dest.Cores = cloneCoreTemps(src.Cores) dest.GPU = cloneGPUTemps(src.GPU) dest.NVMe = cloneNVMeTemps(src.NVMe) dest.SMART = cloneDiskTemps(src.SMART) normalized := dest.NormalizeCollections() return &normalized } func cloneGuestNetworkInterfaces(src []GuestNetworkInterface) []GuestNetworkInterface { if len(src) == 0 { return nil } dest := make([]GuestNetworkInterface, len(src)) for i, nic := range src { nicCopy := nic nicCopy.Addresses = append([]string(nil), nic.Addresses...) dest[i] = nicCopy.NormalizeCollections() } return dest } func cloneNode(src Node) Node { dest := src dest.LoadAverage = append([]float64(nil), src.LoadAverage...) dest.Temperature = cloneTemperature(src.Temperature) dest.TemperatureMonitoringEnabled = cloneBoolPtr(src.TemperatureMonitoringEnabled) return dest.NormalizeCollections() } func cloneNodes(src []Node) []Node { if len(src) == 0 { return nil } dest := make([]Node, len(src)) for i, node := range src { dest[i] = cloneNode(node) } return dest } func cloneVM(src VM) VM { dest := src dest.Disks = append([]Disk(nil), src.Disks...) dest.IPAddresses = append([]string(nil), src.IPAddresses...) dest.Tags = append([]string(nil), src.Tags...) dest.NetworkInterfaces = cloneGuestNetworkInterfaces(src.NetworkInterfaces) return dest.NormalizeCollections() } func cloneVMs(src []VM) []VM { if len(src) == 0 { return nil } dest := make([]VM, len(src)) for i, vm := range src { dest[i] = cloneVM(vm) } return dest } func cloneContainer(src Container) Container { dest := src dest.Disks = append([]Disk(nil), src.Disks...) dest.IPAddresses = append([]string(nil), src.IPAddresses...) dest.Tags = append([]string(nil), src.Tags...) dest.NetworkInterfaces = cloneGuestNetworkInterfaces(src.NetworkInterfaces) return dest.NormalizeCollections() } func cloneContainers(src []Container) []Container { if len(src) == 0 { return nil } dest := make([]Container, len(src)) for i, container := range src { dest[i] = cloneContainer(container) } return dest } func cloneHostNetworkInterfaces(src []HostNetworkInterface) []HostNetworkInterface { if len(src) == 0 { return nil } dest := make([]HostNetworkInterface, len(src)) for i, nic := range src { nicCopy := nic nicCopy.Addresses = append([]string(nil), nic.Addresses...) nicCopy.SpeedMbps = cloneInt64Ptr(nic.SpeedMbps) dest[i] = nicCopy.NormalizeCollections() } return dest } func cloneSMARTAttributes(src *SMARTAttributes) *SMARTAttributes { if src == nil { return nil } dest := *src dest.PowerOnHours = cloneInt64Ptr(src.PowerOnHours) dest.PowerCycles = cloneInt64Ptr(src.PowerCycles) dest.ReallocatedSectors = cloneInt64Ptr(src.ReallocatedSectors) dest.PendingSectors = cloneInt64Ptr(src.PendingSectors) dest.OfflineUncorrectable = cloneInt64Ptr(src.OfflineUncorrectable) dest.UDMACRCErrors = cloneInt64Ptr(src.UDMACRCErrors) dest.PercentageUsed = cloneIntPtr(src.PercentageUsed) dest.AvailableSpare = cloneIntPtr(src.AvailableSpare) dest.MediaErrors = cloneInt64Ptr(src.MediaErrors) dest.UnsafeShutdowns = cloneInt64Ptr(src.UnsafeShutdowns) return &dest } func cloneHostDiskSMART(src []HostDiskSMART) []HostDiskSMART { if len(src) == 0 { return nil } dest := make([]HostDiskSMART, len(src)) for i, disk := range src { diskCopy := disk diskCopy.Attributes = cloneSMARTAttributes(disk.Attributes) dest[i] = diskCopy } return dest } func cloneHostSensorSummary(src HostSensorSummary) HostSensorSummary { return HostSensorSummary{ TemperatureCelsius: cloneStringFloat64Map(src.TemperatureCelsius), FanRPM: cloneStringFloat64Map(src.FanRPM), Additional: cloneStringFloat64Map(src.Additional), SMART: cloneHostDiskSMART(src.SMART), }.NormalizeCollections() } func cloneHostRAIDArrays(src []HostRAIDArray) []HostRAIDArray { if len(src) == 0 { return nil } dest := make([]HostRAIDArray, len(src)) for i, arr := range src { arrCopy := arr arrCopy.Devices = append([]HostRAIDDevice(nil), arr.Devices...) dest[i] = arrCopy.NormalizeCollections() } return dest } func cloneHostUnraidStorage(src *HostUnraidStorage) *HostUnraidStorage { if src == nil { return nil } dest := *src if len(src.Disks) > 0 { dest.Disks = make([]HostUnraidDisk, len(src.Disks)) copy(dest.Disks, src.Disks) } normalized := dest.NormalizeCollections() return &normalized } func cloneHostCephHealth(src HostCephHealth) HostCephHealth { dest := HostCephHealth{ Status: src.Status, Checks: make(map[string]HostCephCheck, len(src.Checks)), Summary: append([]HostCephHealthSummary(nil), src.Summary...), } for key, check := range src.Checks { checkCopy := check checkCopy.Detail = append([]string(nil), check.Detail...) dest.Checks[key] = checkCopy } if len(src.Checks) == 0 { dest.Checks = nil } return dest.NormalizeCollections() } func cloneHostCephCluster(src *HostCephCluster) *HostCephCluster { if src == nil { return nil } dest := *src dest.Health = cloneHostCephHealth(src.Health) dest.MonMap.Monitors = append([]HostCephMonitor(nil), src.MonMap.Monitors...) dest.Pools = append([]HostCephPool(nil), src.Pools...) dest.Services = make([]HostCephService, len(src.Services)) for i, service := range src.Services { serviceCopy := service serviceCopy.Daemons = append([]string(nil), service.Daemons...) dest.Services[i] = serviceCopy.NormalizeCollections() } if len(src.Services) == 0 { dest.Services = nil } normalized := dest.NormalizeCollections() return &normalized } func cloneHost(src Host) Host { dest := src dest.LoadAverage = append([]float64(nil), src.LoadAverage...) dest.Disks = append([]Disk(nil), src.Disks...) dest.DiskIO = append([]DiskIO(nil), src.DiskIO...) dest.NetworkInterfaces = cloneHostNetworkInterfaces(src.NetworkInterfaces) dest.Sensors = cloneHostSensorSummary(src.Sensors) dest.RAID = cloneHostRAIDArrays(src.RAID) dest.Unraid = cloneHostUnraidStorage(src.Unraid) dest.Ceph = cloneHostCephCluster(src.Ceph) dest.TokenLastUsedAt = cloneTimePtr(src.TokenLastUsedAt) dest.Tags = append([]string(nil), src.Tags...) dest.DiskExclude = append([]string(nil), src.DiskExclude...) return dest.NormalizeCollections() } func cloneHosts(src []Host) []Host { if len(src) == 0 { return nil } dest := make([]Host, len(src)) for i, host := range src { dest[i] = cloneHost(host) } return dest } func cloneDockerContainerBlockIO(src *DockerContainerBlockIO) *DockerContainerBlockIO { if src == nil { return nil } dest := *src dest.ReadRateBytesPerSecond = cloneFloat64Ptr(src.ReadRateBytesPerSecond) dest.WriteRateBytesPerSecond = cloneFloat64Ptr(src.WriteRateBytesPerSecond) return &dest } func cloneDockerPodmanContainer(src *DockerPodmanContainer) *DockerPodmanContainer { if src == nil { return nil } dest := *src return &dest } func cloneDockerContainerUpdateStatus(src *DockerContainerUpdateStatus) *DockerContainerUpdateStatus { if src == nil { return nil } dest := *src return &dest } func cloneDockerContainer(src DockerContainer) DockerContainer { dest := src dest.StartedAt = cloneTimePtr(src.StartedAt) dest.FinishedAt = cloneTimePtr(src.FinishedAt) dest.Ports = append([]DockerContainerPort(nil), src.Ports...) dest.Labels = cloneStringMap(src.Labels) dest.Networks = append([]DockerContainerNetworkLink(nil), src.Networks...) dest.BlockIO = cloneDockerContainerBlockIO(src.BlockIO) dest.Mounts = append([]DockerContainerMount(nil), src.Mounts...) dest.Podman = cloneDockerPodmanContainer(src.Podman) dest.UpdateStatus = cloneDockerContainerUpdateStatus(src.UpdateStatus) return dest.NormalizeCollections() } func cloneDockerContainers(src []DockerContainer) []DockerContainer { if len(src) == 0 { return nil } dest := make([]DockerContainer, len(src)) for i, container := range src { dest[i] = cloneDockerContainer(container) } return dest } func cloneDockerServiceUpdate(src *DockerServiceUpdate) *DockerServiceUpdate { if src == nil { return nil } dest := *src dest.CompletedAt = cloneTimePtr(src.CompletedAt) return &dest } func cloneDockerServices(src []DockerService) []DockerService { if len(src) == 0 { return nil } dest := make([]DockerService, len(src)) for i, service := range src { serviceCopy := service serviceCopy.UpdateStatus = cloneDockerServiceUpdate(service.UpdateStatus) serviceCopy.Labels = cloneStringMap(service.Labels) serviceCopy.EndpointPorts = append([]DockerServicePort(nil), service.EndpointPorts...) serviceCopy.CreatedAt = cloneTimePtr(service.CreatedAt) serviceCopy.UpdatedAt = cloneTimePtr(service.UpdatedAt) dest[i] = serviceCopy.NormalizeCollections() } return dest } func cloneDockerTasks(src []DockerTask) []DockerTask { if len(src) == 0 { return nil } dest := make([]DockerTask, len(src)) for i, task := range src { taskCopy := task taskCopy.UpdatedAt = cloneTimePtr(task.UpdatedAt) taskCopy.StartedAt = cloneTimePtr(task.StartedAt) taskCopy.CompletedAt = cloneTimePtr(task.CompletedAt) dest[i] = taskCopy } return dest } func cloneDockerSwarmInfo(src *DockerSwarmInfo) *DockerSwarmInfo { if src == nil { return nil } dest := *src return &dest } func cloneDockerHostCommandStatus(src *DockerHostCommandStatus) *DockerHostCommandStatus { if src == nil { return nil } dest := *src dest.DispatchedAt = cloneTimePtr(src.DispatchedAt) dest.AcknowledgedAt = cloneTimePtr(src.AcknowledgedAt) dest.CompletedAt = cloneTimePtr(src.CompletedAt) dest.FailedAt = cloneTimePtr(src.FailedAt) dest.ExpiresAt = cloneTimePtr(src.ExpiresAt) return &dest } func cloneDockerHost(src DockerHost) DockerHost { dest := src dest.LoadAverage = append([]float64(nil), src.LoadAverage...) dest.Disks = append([]Disk(nil), src.Disks...) dest.NetworkInterfaces = cloneHostNetworkInterfaces(src.NetworkInterfaces) dest.Containers = cloneDockerContainers(src.Containers) dest.Services = cloneDockerServices(src.Services) dest.Tasks = cloneDockerTasks(src.Tasks) dest.Swarm = cloneDockerSwarmInfo(src.Swarm) dest.Temperature = cloneFloat64Ptr(src.Temperature) dest.TokenLastUsedAt = cloneTimePtr(src.TokenLastUsedAt) dest.Command = cloneDockerHostCommandStatus(src.Command) return dest.NormalizeCollections() } func cloneDockerHosts(src []DockerHost) []DockerHost { if len(src) == 0 { return nil } dest := make([]DockerHost, len(src)) for i, host := range src { dest[i] = cloneDockerHost(host) } return dest } func cloneKubernetesNodes(src []KubernetesNode) []KubernetesNode { if len(src) == 0 { return nil } dest := make([]KubernetesNode, len(src)) for i, node := range src { nodeCopy := node nodeCopy.Roles = append([]string(nil), node.Roles...) dest[i] = nodeCopy.NormalizeCollections() } return dest } func cloneKubernetesPodContainers(src []KubernetesPodContainer) []KubernetesPodContainer { return append([]KubernetesPodContainer(nil), src...) } func cloneKubernetesPods(src []KubernetesPod) []KubernetesPod { if len(src) == 0 { return nil } dest := make([]KubernetesPod, len(src)) for i, pod := range src { podCopy := pod podCopy.StartTime = cloneTimePtr(pod.StartTime) podCopy.Labels = cloneStringMap(pod.Labels) podCopy.Containers = cloneKubernetesPodContainers(pod.Containers) dest[i] = podCopy.NormalizeCollections() } return dest } func cloneKubernetesDeployments(src []KubernetesDeployment) []KubernetesDeployment { if len(src) == 0 { return nil } dest := make([]KubernetesDeployment, len(src)) for i, deployment := range src { deploymentCopy := deployment deploymentCopy.Labels = cloneStringMap(deployment.Labels) dest[i] = deploymentCopy.NormalizeCollections() } return dest } func cloneKubernetesCluster(src KubernetesCluster) KubernetesCluster { dest := src dest.Nodes = cloneKubernetesNodes(src.Nodes) dest.Pods = cloneKubernetesPods(src.Pods) dest.Deployments = cloneKubernetesDeployments(src.Deployments) dest.TokenLastUsedAt = cloneTimePtr(src.TokenLastUsedAt) return dest.NormalizeCollections() } func cloneKubernetesClusters(src []KubernetesCluster) []KubernetesCluster { if len(src) == 0 { return nil } dest := make([]KubernetesCluster, len(src)) for i, cluster := range src { dest[i] = cloneKubernetesCluster(cluster) } return dest } func cloneStorage(src Storage) Storage { dest := src dest.Nodes = append([]string(nil), src.Nodes...) dest.NodeIDs = append([]string(nil), src.NodeIDs...) dest.ZFSPool = cloneZFSPool(src.ZFSPool) return dest.NormalizeCollections() } func cloneZFSPool(src *ZFSPool) *ZFSPool { if src == nil { return nil } dest := *src dest.Devices = append([]ZFSDevice(nil), src.Devices...) normalized := dest.NormalizeCollections() return &normalized } func cloneStorages(src []Storage) []Storage { if len(src) == 0 { return nil } dest := make([]Storage, len(src)) for i, storage := range src { dest[i] = cloneStorage(storage) } return dest } func cloneCephCluster(src CephCluster) CephCluster { dest := src dest.Pools = append([]CephPool(nil), src.Pools...) dest.Services = append([]CephServiceStatus(nil), src.Services...) return dest.NormalizeCollections() } func cloneCephClusters(src []CephCluster) []CephCluster { if len(src) == 0 { return nil } dest := make([]CephCluster, len(src)) for i, cluster := range src { dest[i] = cloneCephCluster(cluster) } return dest } func clonePhysicalDisk(src PhysicalDisk) PhysicalDisk { dest := src dest.SmartAttributes = cloneSMARTAttributes(src.SmartAttributes) return dest } func clonePhysicalDisks(src []PhysicalDisk) []PhysicalDisk { if len(src) == 0 { return nil } dest := make([]PhysicalDisk, len(src)) for i, disk := range src { dest[i] = clonePhysicalDisk(disk) } return dest } func clonePBSDatastores(src []PBSDatastore) []PBSDatastore { if len(src) == 0 { return nil } dest := make([]PBSDatastore, len(src)) for i, datastore := range src { datastoreCopy := datastore datastoreCopy.Namespaces = append([]PBSNamespace(nil), datastore.Namespaces...) dest[i] = datastoreCopy.NormalizeCollections() } return dest } func clonePBSInstance(src PBSInstance) PBSInstance { dest := src dest.Datastores = clonePBSDatastores(src.Datastores) dest.BackupJobs = append([]PBSBackupJob(nil), src.BackupJobs...) dest.SyncJobs = append([]PBSSyncJob(nil), src.SyncJobs...) dest.VerifyJobs = append([]PBSVerifyJob(nil), src.VerifyJobs...) dest.PruneJobs = append([]PBSPruneJob(nil), src.PruneJobs...) dest.GarbageJobs = append([]PBSGarbageJob(nil), src.GarbageJobs...) return dest.NormalizeCollections() } func clonePBSInstances(src []PBSInstance) []PBSInstance { if len(src) == 0 { return nil } dest := make([]PBSInstance, len(src)) for i, instance := range src { dest[i] = clonePBSInstance(instance) } return dest } func clonePMGNodeStatus(src []PMGNodeStatus) []PMGNodeStatus { if len(src) == 0 { return nil } dest := make([]PMGNodeStatus, len(src)) for i, node := range src { nodeCopy := node if node.QueueStatus != nil { queueCopy := *node.QueueStatus nodeCopy.QueueStatus = &queueCopy } dest[i] = nodeCopy } return dest } func clonePMGMailStats(src *PMGMailStats) *PMGMailStats { if src == nil { return nil } dest := *src return &dest } func clonePMGQuarantine(src *PMGQuarantineTotals) *PMGQuarantineTotals { if src == nil { return nil } dest := *src return &dest } func clonePMGInstance(src PMGInstance) PMGInstance { dest := src dest.Nodes = clonePMGNodeStatus(src.Nodes) dest.MailStats = clonePMGMailStats(src.MailStats) dest.MailCount = append([]PMGMailCountPoint(nil), src.MailCount...) dest.SpamDistribution = append([]PMGSpamBucket(nil), src.SpamDistribution...) dest.Quarantine = clonePMGQuarantine(src.Quarantine) dest.RelayDomains = append([]PMGRelayDomain(nil), src.RelayDomains...) dest.DomainStats = append([]PMGDomainStat(nil), src.DomainStats...) return dest.NormalizeCollections() } func clonePMGInstances(src []PMGInstance) []PMGInstance { if len(src) == 0 { return nil } dest := make([]PMGInstance, len(src)) for i, instance := range src { dest[i] = clonePMGInstance(instance) } return dest } func clonePBSBackup(src PBSBackup) PBSBackup { dest := src dest.Files = append([]string(nil), src.Files...) // Deep-copy VerificationRaw to avoid shared map references if m, ok := src.VerificationRaw.(map[string]interface{}); ok { cp := make(map[string]interface{}, len(m)) for k, v := range m { cp[k] = v } dest.VerificationRaw = cp } // string and nil cases are immutable - shallow copy is fine return dest.NormalizeCollections() } func clonePBSBackups(src []PBSBackup) []PBSBackup { if len(src) == 0 { return nil } dest := make([]PBSBackup, len(src)) for i, backup := range src { dest[i] = clonePBSBackup(backup) } return dest } func clonePMGBackup(src PMGBackup) PMGBackup { return src } func clonePMGBackups(src []PMGBackup) []PMGBackup { return append([]PMGBackup(nil), src...) } func clonePVEBackups(src PVEBackups) PVEBackups { return PVEBackups{ BackupTasks: append([]BackupTask(nil), src.BackupTasks...), StorageBackups: append([]StorageBackup(nil), src.StorageBackups...), GuestSnapshots: append([]GuestSnapshot(nil), src.GuestSnapshots...), }.NormalizeCollections() } func clonePerformance(src Performance) Performance { return Performance{ APICallDuration: cloneStringFloat64Map(src.APICallDuration), LastPollDuration: src.LastPollDuration, PollingStartTime: src.PollingStartTime, TotalAPICalls: src.TotalAPICalls, FailedAPICalls: src.FailedAPICalls, }.NormalizeCollections() } func cloneAlert(src Alert) Alert { dest := src dest.AckTime = cloneTimePtr(src.AckTime) return dest } func cloneAlerts(src []Alert) []Alert { if len(src) == 0 { return nil } dest := make([]Alert, len(src)) for i, alert := range src { dest[i] = cloneAlert(alert) } return dest } func cloneResolvedAlerts(src []ResolvedAlert) []ResolvedAlert { if len(src) == 0 { return nil } dest := make([]ResolvedAlert, len(src)) for i, alert := range src { alertCopy := alert alertCopy.Alert = cloneAlert(alert.Alert) dest[i] = alertCopy } return dest } func cloneReplicationJob(src ReplicationJob) ReplicationJob { dest := src dest.LastSyncTime = cloneTimePtr(src.LastSyncTime) dest.NextSyncTime = cloneTimePtr(src.NextSyncTime) dest.RateLimitMbps = cloneFloat64Ptr(src.RateLimitMbps) return dest } func cloneReplicationJobs(src []ReplicationJob) []ReplicationJob { if len(src) == 0 { return nil } dest := make([]ReplicationJob, len(src)) for i, job := range src { dest[i] = cloneReplicationJob(job) } return dest } func cloneMetricValues(src map[string]interface{}) map[string]interface{} { if len(src) == 0 { return nil } dest := make(map[string]interface{}, len(src)) for key, value := range src { dest[key] = cloneDynamicValue(value) } return dest } func cloneDynamicValue(value interface{}) interface{} { if value == nil { return nil } v := reflect.ValueOf(value) switch v.Kind() { case reflect.Map: if v.IsNil() { return value } cloned := reflect.MakeMapWithSize(v.Type(), v.Len()) iter := v.MapRange() for iter.Next() { clonedValue := cloneDynamicValue(iter.Value().Interface()) cloned.SetMapIndex(iter.Key(), valueForType(v.Type().Elem(), clonedValue)) } return cloned.Interface() case reflect.Slice: if v.IsNil() { return value } cloned := reflect.MakeSlice(v.Type(), v.Len(), v.Len()) for i := 0; i < v.Len(); i++ { clonedValue := cloneDynamicValue(v.Index(i).Interface()) cloned.Index(i).Set(valueForType(v.Type().Elem(), clonedValue)) } return cloned.Interface() case reflect.Pointer: if v.IsNil() { return value } clonedElem := cloneDynamicValue(v.Elem().Interface()) ptr := reflect.New(v.Type().Elem()) ptr.Elem().Set(valueForType(v.Type().Elem(), clonedElem)) return ptr.Interface() default: return value } } func valueForType(targetType reflect.Type, value interface{}) reflect.Value { if value == nil { return reflect.Zero(targetType) } result := reflect.ValueOf(value) if result.Type().AssignableTo(targetType) { return result } if result.Type().ConvertibleTo(targetType) { return result.Convert(targetType) } return reflect.Zero(targetType) } func cloneMetric(src Metric) Metric { dest := src dest.Values = cloneMetricValues(src.Values) return dest.NormalizeCollections() } func cloneMetrics(src []Metric) []Metric { if len(src) == 0 { return nil } dest := make([]Metric, len(src)) for i, metric := range src { dest[i] = cloneMetric(metric) } return dest }