mirror of
https://github.com/apple/container.git
synced 2026-07-13 21:17:05 +00:00
88ab3192f9
- Part of #1833. - Distributes fixture extensions for images and containers added as part of previous builder PR to more sensible locations.
88 lines
3.5 KiB
Swift
88 lines
3.5 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2026 Apple Inc. and the container project authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
|
|
// MARK: - Volume lifecycle helpers
|
|
|
|
extension ContainerFixture {
|
|
|
|
/// Creates a named volume, optionally with extra `--opt` arguments.
|
|
func doVolumeCreate(_ name: String, opts: [String] = []) throws {
|
|
var args = ["volume", "create"]
|
|
for opt in opts { args += ["--opt", opt] }
|
|
args.append(name)
|
|
try run(args).check()
|
|
}
|
|
|
|
/// Deletes a volume, throwing on failure.
|
|
func doVolumeDelete(_ name: String) throws {
|
|
try run(["volume", "rm", name]).check()
|
|
}
|
|
|
|
/// Deletes a volume, silently ignoring errors.
|
|
func doVolumeDeleteIfExists(_ name: String) {
|
|
_ = try? run(["volume", "rm", name])
|
|
}
|
|
|
|
/// Returns `true` if `volume rm` exits non-zero (i.e. the delete was blocked).
|
|
func doesVolumeDeleteFail(_ name: String) throws -> Bool {
|
|
try run(["volume", "rm", name]).status != 0
|
|
}
|
|
|
|
/// Returns the names of all volume attachments on a container
|
|
/// (the UUID name for anonymous volumes, the explicit name for named volumes).
|
|
func getContainerMountedVolumeNames(_ containerName: String) throws -> [String] {
|
|
let inspect = try inspectContainer(containerName)
|
|
return inspect.configuration.mounts.compactMap { mount in
|
|
if case .volume(let name, _, _, _) = mount.type { return name }
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// Returns the names of all anonymous volumes (UUID-format names) in the local store.
|
|
func getAnonymousVolumeNames() throws -> [String] {
|
|
let result = try run(["volume", "list", "--quiet"]).check()
|
|
return result.output
|
|
.components(separatedBy: .newlines)
|
|
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
|
.filter { !$0.isEmpty && isAnonymousVolumeName($0) }
|
|
}
|
|
|
|
/// Deletes all currently known anonymous volumes. Useful before count-based assertions.
|
|
func doCleanupAnonymousVolumes() {
|
|
for vol in (try? getAnonymousVolumeNames()) ?? [] {
|
|
doVolumeDeleteIfExists(vol)
|
|
}
|
|
}
|
|
|
|
/// Returns `true` if a volume with the given name appears in `volume list`.
|
|
func volumeExists(_ name: String) throws -> Bool {
|
|
let result = try run(["volume", "list", "--quiet"]).check()
|
|
return result.output
|
|
.components(separatedBy: .newlines)
|
|
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
|
.contains(name)
|
|
}
|
|
|
|
/// Returns `true` if `name` has the UUID format used for anonymous volumes.
|
|
private func isAnonymousVolumeName(_ name: String) -> Bool {
|
|
let pattern = #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"#
|
|
guard let regex = try? Regex(pattern) else { return false }
|
|
return (try? regex.firstMatch(in: name)) != nil
|
|
}
|
|
}
|