mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-23 11:46:28 +00:00
13371a6b6c
Host agents key their identity on the machine-derived agent ID, so MSP template deployments that clone /etc/machine-id fold two physical machines at different sites into one host row whose reports overwrite each other (hostname, report IP, and interfaces flapping between sites), silently poisoning node-agent linking. Mirror the Docker host identity-collapse doctrine (#1584) for host report ingest: track hostname and report-IP revisits per resolved agent identity inside the monitoring-owned flap window, publish an active conflict as models.Host.IdentityConflict through unified resources, and warn on the Machines page. The report IP is tracked alongside the hostname because template fleets often reuse hostnames across sites (pve01 at two customers), leaving the address as the only field that betrays the clone. A one-time hostname rename never revisits and is not flagged; the conflict clears on its own once only one machine keeps reporting for the window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1419 lines
38 KiB
Go
1419 lines
38 KiB
Go
package models
|
|
|
|
import (
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/pkg/diskinventory"
|
|
)
|
|
|
|
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 clonePVETagStyles(src map[string]PVETagStyle) map[string]PVETagStyle {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make(map[string]PVETagStyle, len(src))
|
|
for instance, style := range src {
|
|
colors := cloneStringMap(style.Colors)
|
|
if colors == nil {
|
|
colors = map[string]string{}
|
|
}
|
|
dest[instance] = PVETagStyle{
|
|
Colors: colors,
|
|
CaseSensitive: style.CaseSensitive,
|
|
}
|
|
}
|
|
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 cloneStringIntMap(src map[string]int) map[string]int {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make(map[string]int, 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.NativeNameAliases = append([]string(nil), src.NativeNameAliases...)
|
|
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)
|
|
diskCopy.Collection = diskinventory.CloneStatus(disk.Collection)
|
|
if disk.IO != nil {
|
|
ioCopy := *disk.IO
|
|
diskCopy.IO = &ioCopy
|
|
}
|
|
dest[i] = diskCopy
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneHostSensorSummary(src HostSensorSummary) HostSensorSummary {
|
|
return HostSensorSummary{
|
|
TemperatureCelsius: cloneStringFloat64Map(src.TemperatureCelsius),
|
|
FanRPM: cloneStringFloat64Map(src.FanRPM),
|
|
PowerWatts: cloneStringFloat64Map(src.PowerWatts),
|
|
Additional: cloneStringFloat64Map(src.Additional),
|
|
GPU: cloneHostGPUSensors(src.GPU),
|
|
ThermalState: cloneHostThermalState(src.ThermalState),
|
|
SMART: cloneHostDiskSMART(src.SMART),
|
|
}.NormalizeCollections()
|
|
}
|
|
|
|
func cloneHostGPUSensors(src []HostGPUSensor) []HostGPUSensor {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]HostGPUSensor, len(src))
|
|
for i, gpu := range src {
|
|
dest[i] = HostGPUSensor{
|
|
ID: gpu.ID,
|
|
Name: gpu.Name,
|
|
TemperatureCelsius: cloneFloat64Ptr(gpu.TemperatureCelsius),
|
|
UtilizationPercent: cloneFloat64Ptr(gpu.UtilizationPercent),
|
|
MemoryUsedBytes: cloneInt64Ptr(gpu.MemoryUsedBytes),
|
|
MemoryTotalBytes: cloneInt64Ptr(gpu.MemoryTotalBytes),
|
|
}
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneHostThermalState(src *HostThermalState) *HostThermalState {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
dest.ThermalWarningLevel = cloneIntPtr(src.ThermalWarningLevel)
|
|
dest.PerformanceWarningLevel = cloneIntPtr(src.PerformanceWarningLevel)
|
|
dest.CPUPowerStatus = cloneIntPtr(src.CPUPowerStatus)
|
|
dest.LimitsPercent = cloneStringIntMap(src.LimitsPercent)
|
|
return &dest
|
|
}
|
|
|
|
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 cloneHostPackageUpdateStatus(src *HostPackageUpdateStatus) *HostPackageUpdateStatus {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
dest.Packages = append([]HostPackageUpdate(nil), src.Packages...)
|
|
return &dest
|
|
}
|
|
|
|
func cloneHostStorageCleanupStatus(src *HostStorageCleanupStatus) *HostStorageCleanupStatus {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
return &dest
|
|
}
|
|
|
|
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.PackageUpdates = cloneHostPackageUpdateStatus(src.PackageUpdates)
|
|
dest.StorageCleanup = cloneHostStorageCleanupStatus(src.StorageCleanup)
|
|
dest.TokenLastUsedAt = cloneTimePtr(src.TokenLastUsedAt)
|
|
dest.Tags = append([]string(nil), src.Tags...)
|
|
dest.DiskExclude = append([]string(nil), src.DiskExclude...)
|
|
dest.IdentityConflict = cloneHostIdentityConflict(src.IdentityConflict)
|
|
return dest.NormalizeCollections()
|
|
}
|
|
|
|
func cloneHostIdentityConflict(src *HostIdentityConflict) *HostIdentityConflict {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
dest.Hostnames = append([]string(nil), src.Hostnames...)
|
|
dest.ReportIPs = append([]string(nil), src.ReportIPs...)
|
|
return &dest
|
|
}
|
|
|
|
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.OOMKilled = cloneBoolPtr(src.OOMKilled)
|
|
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 cloneDockerImages(src []DockerImage) []DockerImage {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]DockerImage, len(src))
|
|
for i, image := range src {
|
|
imageCopy := image
|
|
imageCopy.RepoTags = append([]string(nil), image.RepoTags...)
|
|
imageCopy.RepoDigests = append([]string(nil), image.RepoDigests...)
|
|
imageCopy.Labels = cloneStringMap(image.Labels)
|
|
dest[i] = imageCopy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneDockerVolumes(src []DockerVolume) []DockerVolume {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]DockerVolume, len(src))
|
|
for i, volume := range src {
|
|
volumeCopy := volume
|
|
volumeCopy.Labels = cloneStringMap(volume.Labels)
|
|
volumeCopy.Options = cloneStringMap(volume.Options)
|
|
dest[i] = volumeCopy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneDockerNetworks(src []DockerNetwork) []DockerNetwork {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]DockerNetwork, len(src))
|
|
for i, network := range src {
|
|
networkCopy := network
|
|
networkCopy.Subnets = append([]DockerNetworkSubnet(nil), network.Subnets...)
|
|
networkCopy.Labels = cloneStringMap(network.Labels)
|
|
networkCopy.Options = cloneStringMap(network.Options)
|
|
dest[i] = networkCopy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneDockerStorageUsage(src *DockerStorageUsage) *DockerStorageUsage {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
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 cloneDockerNodes(src []DockerNode) []DockerNode {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]DockerNode, len(src))
|
|
for i, node := range src {
|
|
nodeCopy := node
|
|
nodeCopy.Labels = cloneStringMap(node.Labels)
|
|
nodeCopy.EngineLabels = cloneStringMap(node.EngineLabels)
|
|
nodeCopy.UpdatedAt = cloneTimePtr(node.UpdatedAt)
|
|
dest[i] = nodeCopy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneDockerSecrets(src []DockerSecret) []DockerSecret {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]DockerSecret, len(src))
|
|
for i, secret := range src {
|
|
secretCopy := secret
|
|
secretCopy.Labels = cloneStringMap(secret.Labels)
|
|
secretCopy.UpdatedAt = cloneTimePtr(secret.UpdatedAt)
|
|
dest[i] = secretCopy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneDockerConfigs(src []DockerConfig) []DockerConfig {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]DockerConfig, len(src))
|
|
for i, config := range src {
|
|
configCopy := config
|
|
configCopy.Labels = cloneStringMap(config.Labels)
|
|
configCopy.UpdatedAt = cloneTimePtr(config.UpdatedAt)
|
|
dest[i] = configCopy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneDockerSwarmInfo(src *DockerSwarmInfo) *DockerSwarmInfo {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
return &dest
|
|
}
|
|
|
|
func cloneDockerHostSecurity(src *DockerHostSecurity) *DockerHostSecurity {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
dest.AuthorizationPlugins = append([]string(nil), src.AuthorizationPlugins...)
|
|
return &dest
|
|
}
|
|
|
|
func cloneDockerHostIdentityConflict(src *DockerHostIdentityConflict) *DockerHostIdentityConflict {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dest := *src
|
|
dest.Hostnames = append([]string(nil), src.Hostnames...)
|
|
dest.MachineIDs = append([]string(nil), src.MachineIDs...)
|
|
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.Images = cloneDockerImages(src.Images)
|
|
dest.Volumes = cloneDockerVolumes(src.Volumes)
|
|
dest.Networks = cloneDockerNetworks(src.Networks)
|
|
dest.Services = cloneDockerServices(src.Services)
|
|
dest.Tasks = cloneDockerTasks(src.Tasks)
|
|
dest.Nodes = cloneDockerNodes(src.Nodes)
|
|
dest.Secrets = cloneDockerSecrets(src.Secrets)
|
|
dest.Configs = cloneDockerConfigs(src.Configs)
|
|
dest.StorageUsage = cloneDockerStorageUsage(src.StorageUsage)
|
|
dest.Swarm = cloneDockerSwarmInfo(src.Swarm)
|
|
dest.Security = cloneDockerHostSecurity(src.Security)
|
|
dest.Temperature = cloneFloat64Ptr(src.Temperature)
|
|
dest.TokenLastUsedAt = cloneTimePtr(src.TokenLastUsedAt)
|
|
dest.Command = cloneDockerHostCommandStatus(src.Command)
|
|
dest.IdentityConflict = cloneDockerHostIdentityConflict(src.IdentityConflict)
|
|
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 cloneKubernetesNamespaces(src []KubernetesNamespace) []KubernetesNamespace {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesNamespace, len(src))
|
|
for i, namespace := range src {
|
|
namespaceCopy := namespace
|
|
namespaceCopy.Labels = cloneStringMap(namespace.Labels)
|
|
dest[i] = namespaceCopy.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 cloneKubernetesReplicaSets(src []KubernetesReplicaSet) []KubernetesReplicaSet {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesReplicaSet, len(src))
|
|
for i, replicaSet := range src {
|
|
copy := replicaSet
|
|
copy.Labels = cloneStringMap(replicaSet.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesStatefulSets(src []KubernetesStatefulSet) []KubernetesStatefulSet {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesStatefulSet, len(src))
|
|
for i, statefulSet := range src {
|
|
copy := statefulSet
|
|
copy.Labels = cloneStringMap(statefulSet.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesDaemonSets(src []KubernetesDaemonSet) []KubernetesDaemonSet {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesDaemonSet, len(src))
|
|
for i, daemonSet := range src {
|
|
copy := daemonSet
|
|
copy.Labels = cloneStringMap(daemonSet.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesServices(src []KubernetesService) []KubernetesService {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesService, len(src))
|
|
for i, service := range src {
|
|
copy := service
|
|
copy.ExternalIPs = append([]string(nil), service.ExternalIPs...)
|
|
copy.Ports = append([]KubernetesServicePort(nil), service.Ports...)
|
|
copy.Selector = cloneStringMap(service.Selector)
|
|
copy.Labels = cloneStringMap(service.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesJobs(src []KubernetesJob) []KubernetesJob {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesJob, len(src))
|
|
for i, job := range src {
|
|
copy := job
|
|
copy.StartTime = cloneTimePtr(job.StartTime)
|
|
copy.CompletionTime = cloneTimePtr(job.CompletionTime)
|
|
copy.Labels = cloneStringMap(job.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesCronJobs(src []KubernetesCronJob) []KubernetesCronJob {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesCronJob, len(src))
|
|
for i, cronJob := range src {
|
|
copy := cronJob
|
|
copy.LastScheduleTime = cloneTimePtr(cronJob.LastScheduleTime)
|
|
copy.LastSuccessfulTime = cloneTimePtr(cronJob.LastSuccessfulTime)
|
|
copy.Labels = cloneStringMap(cronJob.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesIngresses(src []KubernetesIngress) []KubernetesIngress {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesIngress, len(src))
|
|
for i, ingress := range src {
|
|
copy := ingress
|
|
copy.Hosts = append([]string(nil), ingress.Hosts...)
|
|
copy.Addresses = append([]string(nil), ingress.Addresses...)
|
|
copy.Labels = cloneStringMap(ingress.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesEndpointSlices(src []KubernetesEndpointSlice) []KubernetesEndpointSlice {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesEndpointSlice, len(src))
|
|
for i, endpointSlice := range src {
|
|
copy := endpointSlice
|
|
copy.Ports = append([]KubernetesEndpointPort(nil), endpointSlice.Ports...)
|
|
copy.Labels = cloneStringMap(endpointSlice.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesNetworkPolicies(src []KubernetesNetworkPolicy) []KubernetesNetworkPolicy {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesNetworkPolicy, len(src))
|
|
for i, policy := range src {
|
|
copy := policy
|
|
copy.PolicyTypes = append([]string(nil), policy.PolicyTypes...)
|
|
copy.Labels = cloneStringMap(policy.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesPersistentVolumes(src []KubernetesPersistentVolume) []KubernetesPersistentVolume {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesPersistentVolume, len(src))
|
|
for i, volume := range src {
|
|
copy := volume
|
|
copy.AccessModes = append([]string(nil), volume.AccessModes...)
|
|
copy.Labels = cloneStringMap(volume.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesPersistentVolumeClaims(src []KubernetesPersistentVolumeClaim) []KubernetesPersistentVolumeClaim {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesPersistentVolumeClaim, len(src))
|
|
for i, claim := range src {
|
|
copy := claim
|
|
copy.AccessModes = append([]string(nil), claim.AccessModes...)
|
|
copy.Labels = cloneStringMap(claim.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesStorageClasses(src []KubernetesStorageClass) []KubernetesStorageClass {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesStorageClass, len(src))
|
|
for i, class := range src {
|
|
copy := class
|
|
copy.AllowVolumeExpansion = cloneBoolPtr(class.AllowVolumeExpansion)
|
|
copy.ParameterKeys = append([]string(nil), class.ParameterKeys...)
|
|
copy.Labels = cloneStringMap(class.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesConfigMaps(src []KubernetesConfigMap) []KubernetesConfigMap {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesConfigMap, len(src))
|
|
for i, configMap := range src {
|
|
copy := configMap
|
|
copy.DataKeys = append([]string(nil), configMap.DataKeys...)
|
|
copy.BinaryDataKeys = append([]string(nil), configMap.BinaryDataKeys...)
|
|
copy.Labels = cloneStringMap(configMap.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesSecrets(src []KubernetesSecret) []KubernetesSecret {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesSecret, len(src))
|
|
for i, secret := range src {
|
|
copy := secret
|
|
copy.DataKeys = append([]string(nil), secret.DataKeys...)
|
|
copy.Labels = cloneStringMap(secret.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesServiceAccounts(src []KubernetesServiceAccount) []KubernetesServiceAccount {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesServiceAccount, len(src))
|
|
for i, account := range src {
|
|
copy := account
|
|
copy.AutomountServiceAccountToken = cloneBoolPtr(account.AutomountServiceAccountToken)
|
|
copy.ImagePullSecrets = append([]string(nil), account.ImagePullSecrets...)
|
|
copy.Labels = cloneStringMap(account.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesResourceQuotas(src []KubernetesResourceQuota) []KubernetesResourceQuota {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesResourceQuota, len(src))
|
|
for i, quota := range src {
|
|
copy := quota
|
|
copy.Hard = cloneStringMap(quota.Hard)
|
|
copy.Used = cloneStringMap(quota.Used)
|
|
copy.Labels = cloneStringMap(quota.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesLimitRanges(src []KubernetesLimitRange) []KubernetesLimitRange {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesLimitRange, len(src))
|
|
for i, limitRange := range src {
|
|
copy := limitRange
|
|
copy.LimitTypes = append([]string(nil), limitRange.LimitTypes...)
|
|
copy.Labels = cloneStringMap(limitRange.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesPodDisruptionBudgets(src []KubernetesPodDisruptionBudget) []KubernetesPodDisruptionBudget {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesPodDisruptionBudget, len(src))
|
|
for i, budget := range src {
|
|
copy := budget
|
|
copy.Labels = cloneStringMap(budget.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesHorizontalPodAutoscalers(src []KubernetesHorizontalPodAutoscaler) []KubernetesHorizontalPodAutoscaler {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesHorizontalPodAutoscaler, len(src))
|
|
for i, autoscaler := range src {
|
|
copy := autoscaler
|
|
copy.MetricTypes = append([]string(nil), autoscaler.MetricTypes...)
|
|
copy.Labels = cloneStringMap(autoscaler.Labels)
|
|
dest[i] = copy.NormalizeCollections()
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesEvents(src []KubernetesEvent) []KubernetesEvent {
|
|
if len(src) == 0 {
|
|
return nil
|
|
}
|
|
dest := make([]KubernetesEvent, len(src))
|
|
for i, event := range src {
|
|
copy := event
|
|
copy.FirstSeen = cloneTimePtr(event.FirstSeen)
|
|
copy.LastSeen = cloneTimePtr(event.LastSeen)
|
|
copy.EventTime = cloneTimePtr(event.EventTime)
|
|
dest[i] = copy
|
|
}
|
|
return dest
|
|
}
|
|
|
|
func cloneKubernetesCluster(src KubernetesCluster) KubernetesCluster {
|
|
dest := src
|
|
dest.Nodes = cloneKubernetesNodes(src.Nodes)
|
|
dest.Namespaces = cloneKubernetesNamespaces(src.Namespaces)
|
|
dest.Pods = cloneKubernetesPods(src.Pods)
|
|
dest.Deployments = cloneKubernetesDeployments(src.Deployments)
|
|
dest.ReplicaSets = cloneKubernetesReplicaSets(src.ReplicaSets)
|
|
dest.StatefulSets = cloneKubernetesStatefulSets(src.StatefulSets)
|
|
dest.DaemonSets = cloneKubernetesDaemonSets(src.DaemonSets)
|
|
dest.Services = cloneKubernetesServices(src.Services)
|
|
dest.Jobs = cloneKubernetesJobs(src.Jobs)
|
|
dest.CronJobs = cloneKubernetesCronJobs(src.CronJobs)
|
|
dest.Ingresses = cloneKubernetesIngresses(src.Ingresses)
|
|
dest.EndpointSlices = cloneKubernetesEndpointSlices(src.EndpointSlices)
|
|
dest.NetworkPolicies = cloneKubernetesNetworkPolicies(src.NetworkPolicies)
|
|
dest.PersistentVolumes = cloneKubernetesPersistentVolumes(src.PersistentVolumes)
|
|
dest.PersistentVolumeClaims = cloneKubernetesPersistentVolumeClaims(src.PersistentVolumeClaims)
|
|
dest.StorageClasses = cloneKubernetesStorageClasses(src.StorageClasses)
|
|
dest.ConfigMaps = cloneKubernetesConfigMaps(src.ConfigMaps)
|
|
dest.Secrets = cloneKubernetesSecrets(src.Secrets)
|
|
dest.ServiceAccounts = cloneKubernetesServiceAccounts(src.ServiceAccounts)
|
|
dest.ResourceQuotas = cloneKubernetesResourceQuotas(src.ResourceQuotas)
|
|
dest.LimitRanges = cloneKubernetesLimitRanges(src.LimitRanges)
|
|
dest.PodDisruptionBudgets = cloneKubernetesPodDisruptionBudgets(src.PodDisruptionBudgets)
|
|
dest.HorizontalPodAutoscalers = cloneKubernetesHorizontalPodAutoscalers(src.HorizontalPodAutoscalers)
|
|
dest.Events = cloneKubernetesEvents(src.Events)
|
|
// RBAC slices: NormalizeCollections() mutates these via index
|
|
// assignment (c.Roles[i] = c.Roles[i].NormalizeCollections()), so they
|
|
// must not be aliased to the source slice or concurrent clones will
|
|
// race on the shared underlying array.
|
|
dest.Roles = append([]KubernetesRole(nil), src.Roles...)
|
|
dest.ClusterRoles = append([]KubernetesClusterRole(nil), src.ClusterRoles...)
|
|
dest.RoleBindings = append([]KubernetesRoleBinding(nil), src.RoleBindings...)
|
|
dest.ClusterRoleBindings = append([]KubernetesClusterRoleBinding(nil), src.ClusterRoleBindings...)
|
|
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.AliasIDs = append([]string(nil), src.AliasIDs...)
|
|
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.InstanceAliases = append([]string(nil), src.InstanceAliases...)
|
|
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)
|
|
dest.Collection = diskinventory.CloneStatus(src.Collection)
|
|
if src.IO != nil {
|
|
ioCopy := *src.IO
|
|
dest.IO = &ioCopy
|
|
}
|
|
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...)
|
|
dest.JobHealthEvidence = append([]PBSJobHealthEvidence(nil), src.JobHealthEvidence...)
|
|
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 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)
|
|
if src.Metadata != nil {
|
|
dest.Metadata = make(map[string]interface{}, len(src.Metadata))
|
|
for k, v := range src.Metadata {
|
|
dest.Metadata[k] = v
|
|
}
|
|
}
|
|
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
|
|
}
|