new features

This commit is contained in:
Mark Gregory
2026-11-09 08:20:57 +00:00
parent ecfa74a35f
commit 965ae923c2
27 changed files with 1474 additions and 168 deletions
+35
View File
@@ -0,0 +1,35 @@
import Foundation
public enum VolumeInventory {
/// Managed volumes are enriched with configured references. Persistent host
/// mounts are displayed separately and can never be deleted as volumes.
public static func combine(volumes: [Resource], containers: [Resource], includeHostMounts: Bool = true) -> [Resource] {
var result = volumes
var uses: [String: Set<String>] = [:]
var host: [String: Resource] = [:]
for container in containers {
guard let data = container.raw.data(using: .utf8), let row = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let cfg = row["configuration"] as? [String: Any], let mounts = cfg["mounts"] as? [[String: Any]] else { continue }
for mount in mounts {
let type = mount["type"] as? [String: Any] ?? [:]
let source = mount["source"] as? String ?? ""
let destination = mount["destination"] as? String ?? ""
let reference = "\(container.name):\(destination)"
if let volume = type["volume"] as? [String: Any], let name = volume["name"] as? String { uses[name, default: []].insert(reference); continue }
if let volume = volumes.first(where: { $0.source == source && !source.isEmpty }) { uses[volume.id, default: []].insert(reference); continue }
guard includeHostMounts, !source.isEmpty, type["virtiofs"] != nil || type["block"] != nil else { continue }
let id = "host:" + source
var item = host[id] ?? Resource(id: id, name: URL(fileURLWithPath: source).lastPathComponent, state: "Referenced", image: "—", project: "", service: "", ports: "—", raw: ContainerService.pretty(mount))
item.source = source; item.storageKind = type["block"] == nil ? "Bind mount" : "Disk mount"; item.readOnlyStorage = true
item.driver = type["block"] == nil ? "virtiofs" : "block"; item.format = "host"; item.usedBy = ""
host[id] = item; uses[id, default: []].insert(reference)
}
}
result += host.values
for index in result.indices {
let references = uses[result[index].id] ?? []
result[index].usedBy = references.isEmpty ? "No container references" : references.sorted().joined(separator: ", ")
result[index].state = references.isEmpty ? "Unreferenced" : "Referenced"
}
return result.sorted { ($0.readOnlyStorage ? 1 : 0, $0.name) < ($1.readOnlyStorage ? 1 : 0, $1.name) }
}
}