Skip to content

Commit b7fbbe5

Browse files
committed
add vminitd api for freeze and thaw filesystem operations
1 parent 72043f9 commit b7fbbe5

9 files changed

Lines changed: 679 additions & 0 deletions

File tree

Sources/Containerization/LinuxContainer.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,20 @@ extension LinuxContainer {
10431043
}
10441044
}
10451045

1046+
// Perform filesystem operations in the container.
1047+
public func filesystemOperation(operation: FilesystemOperation, path: String) async throws {
1048+
try await self.state.withLock {
1049+
let state = try $0.startedState("filesystemOperation")
1050+
try await state.vm.withAgent { agent in
1051+
guard let vminitd = agent as? Vminitd else {
1052+
throw ContainerizationError(.unsupported, message: "filesystemOperation requires Vminitd agent")
1053+
}
1054+
let guestPath = URL(filePath: Self.guestRootfsPath(self.id)).appending(path: path).path
1055+
try await vminitd.filesystemOperation(operation: operation, path: guestPath)
1056+
}
1057+
}
1058+
}
1059+
10461060
private func relayUnixSocket(
10471061
socket: UnixSocketConfiguration,
10481062
relayManager: UnixSocketRelayManager,

Sources/Containerization/SandboxContext/SandboxContext.grpc.swift

Lines changed: 222 additions & 0 deletions
Large diffs are not rendered by default.

Sources/Containerization/SandboxContext/SandboxContext.pb.swift

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,72 @@ public struct Com_Apple_Containerization_Sandbox_V3_StatResponse: @unchecked Sen
10541054
fileprivate var _storage = _StorageClass.defaultInstance
10551055
}
10561056

1057+
public struct Com_Apple_Containerization_Sandbox_V3_FiFreezeParams: Sendable {
1058+
// SwiftProtobuf.Message conformance is added in an extension below. See the
1059+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
1060+
// methods supported on all messages.
1061+
1062+
public var unknownFields = SwiftProtobuf.UnknownStorage()
1063+
1064+
public init() {}
1065+
}
1066+
1067+
public struct Com_Apple_Containerization_Sandbox_V3_FiThawParams: Sendable {
1068+
// SwiftProtobuf.Message conformance is added in an extension below. See the
1069+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
1070+
// methods supported on all messages.
1071+
1072+
public var unknownFields = SwiftProtobuf.UnknownStorage()
1073+
1074+
public init() {}
1075+
}
1076+
1077+
public struct Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest: Sendable {
1078+
// SwiftProtobuf.Message conformance is added in an extension below. See the
1079+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
1080+
// methods supported on all messages.
1081+
1082+
public var path: String = String()
1083+
1084+
public var operation: Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest.OneOf_Operation? = nil
1085+
1086+
public var freeze: Com_Apple_Containerization_Sandbox_V3_FiFreezeParams {
1087+
get {
1088+
if case .freeze(let v)? = operation {return v}
1089+
return Com_Apple_Containerization_Sandbox_V3_FiFreezeParams()
1090+
}
1091+
set {operation = .freeze(newValue)}
1092+
}
1093+
1094+
public var thaw: Com_Apple_Containerization_Sandbox_V3_FiThawParams {
1095+
get {
1096+
if case .thaw(let v)? = operation {return v}
1097+
return Com_Apple_Containerization_Sandbox_V3_FiThawParams()
1098+
}
1099+
set {operation = .thaw(newValue)}
1100+
}
1101+
1102+
public var unknownFields = SwiftProtobuf.UnknownStorage()
1103+
1104+
public enum OneOf_Operation: Equatable, Sendable {
1105+
case freeze(Com_Apple_Containerization_Sandbox_V3_FiFreezeParams)
1106+
case thaw(Com_Apple_Containerization_Sandbox_V3_FiThawParams)
1107+
1108+
}
1109+
1110+
public init() {}
1111+
}
1112+
1113+
public struct Com_Apple_Containerization_Sandbox_V3_FilesystemOperationResponse: Sendable {
1114+
// SwiftProtobuf.Message conformance is added in an extension below. See the
1115+
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
1116+
// methods supported on all messages.
1117+
1118+
public var unknownFields = SwiftProtobuf.UnknownStorage()
1119+
1120+
public init() {}
1121+
}
1122+
10571123
public struct Com_Apple_Containerization_Sandbox_V3_IpLinkSetRequest: Sendable {
10581124
// SwiftProtobuf.Message conformance is added in an extension below. See the
10591125
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@@ -3138,6 +3204,135 @@ extension Com_Apple_Containerization_Sandbox_V3_StatResponse: SwiftProtobuf.Mess
31383204
}
31393205
}
31403206

3207+
extension Com_Apple_Containerization_Sandbox_V3_FiFreezeParams: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
3208+
public static let protoMessageName: String = _protobuf_package + ".FiFreezeParams"
3209+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
3210+
3211+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
3212+
// Load everything into unknown fields
3213+
while try decoder.nextFieldNumber() != nil {}
3214+
}
3215+
3216+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
3217+
try unknownFields.traverse(visitor: &visitor)
3218+
}
3219+
3220+
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_FiFreezeParams, rhs: Com_Apple_Containerization_Sandbox_V3_FiFreezeParams) -> Bool {
3221+
if lhs.unknownFields != rhs.unknownFields {return false}
3222+
return true
3223+
}
3224+
}
3225+
3226+
extension Com_Apple_Containerization_Sandbox_V3_FiThawParams: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
3227+
public static let protoMessageName: String = _protobuf_package + ".FiThawParams"
3228+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
3229+
3230+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
3231+
// Load everything into unknown fields
3232+
while try decoder.nextFieldNumber() != nil {}
3233+
}
3234+
3235+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
3236+
try unknownFields.traverse(visitor: &visitor)
3237+
}
3238+
3239+
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_FiThawParams, rhs: Com_Apple_Containerization_Sandbox_V3_FiThawParams) -> Bool {
3240+
if lhs.unknownFields != rhs.unknownFields {return false}
3241+
return true
3242+
}
3243+
}
3244+
3245+
extension Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
3246+
public static let protoMessageName: String = _protobuf_package + ".FilesystemOperationRequest"
3247+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}path\0\u{1}freeze\0\u{1}thaw\0")
3248+
3249+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
3250+
while let fieldNumber = try decoder.nextFieldNumber() {
3251+
// The use of inline closures is to circumvent an issue where the compiler
3252+
// allocates stack space for every case branch when no optimizations are
3253+
// enabled. https://github.com/apple/swift-protobuf/issues/1034
3254+
switch fieldNumber {
3255+
case 1: try { try decoder.decodeSingularStringField(value: &self.path) }()
3256+
case 2: try {
3257+
var v: Com_Apple_Containerization_Sandbox_V3_FiFreezeParams?
3258+
var hadOneofValue = false
3259+
if let current = self.operation {
3260+
hadOneofValue = true
3261+
if case .freeze(let m) = current {v = m}
3262+
}
3263+
try decoder.decodeSingularMessageField(value: &v)
3264+
if let v = v {
3265+
if hadOneofValue {try decoder.handleConflictingOneOf()}
3266+
self.operation = .freeze(v)
3267+
}
3268+
}()
3269+
case 3: try {
3270+
var v: Com_Apple_Containerization_Sandbox_V3_FiThawParams?
3271+
var hadOneofValue = false
3272+
if let current = self.operation {
3273+
hadOneofValue = true
3274+
if case .thaw(let m) = current {v = m}
3275+
}
3276+
try decoder.decodeSingularMessageField(value: &v)
3277+
if let v = v {
3278+
if hadOneofValue {try decoder.handleConflictingOneOf()}
3279+
self.operation = .thaw(v)
3280+
}
3281+
}()
3282+
default: break
3283+
}
3284+
}
3285+
}
3286+
3287+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
3288+
// The use of inline closures is to circumvent an issue where the compiler
3289+
// allocates stack space for every if/case branch local when no optimizations
3290+
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
3291+
// https://github.com/apple/swift-protobuf/issues/1182
3292+
if !self.path.isEmpty {
3293+
try visitor.visitSingularStringField(value: self.path, fieldNumber: 1)
3294+
}
3295+
switch self.operation {
3296+
case .freeze?: try {
3297+
guard case .freeze(let v)? = self.operation else { preconditionFailure() }
3298+
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
3299+
}()
3300+
case .thaw?: try {
3301+
guard case .thaw(let v)? = self.operation else { preconditionFailure() }
3302+
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
3303+
}()
3304+
case nil: break
3305+
}
3306+
try unknownFields.traverse(visitor: &visitor)
3307+
}
3308+
3309+
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest, rhs: Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest) -> Bool {
3310+
if lhs.path != rhs.path {return false}
3311+
if lhs.operation != rhs.operation {return false}
3312+
if lhs.unknownFields != rhs.unknownFields {return false}
3313+
return true
3314+
}
3315+
}
3316+
3317+
extension Com_Apple_Containerization_Sandbox_V3_FilesystemOperationResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
3318+
public static let protoMessageName: String = _protobuf_package + ".FilesystemOperationResponse"
3319+
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
3320+
3321+
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
3322+
// Load everything into unknown fields
3323+
while try decoder.nextFieldNumber() != nil {}
3324+
}
3325+
3326+
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
3327+
try unknownFields.traverse(visitor: &visitor)
3328+
}
3329+
3330+
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_FilesystemOperationResponse, rhs: Com_Apple_Containerization_Sandbox_V3_FilesystemOperationResponse) -> Bool {
3331+
if lhs.unknownFields != rhs.unknownFields {return false}
3332+
return true
3333+
}
3334+
}
3335+
31413336
extension Com_Apple_Containerization_Sandbox_V3_IpLinkSetRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
31423337
public static let protoMessageName: String = _protobuf_package + ".IpLinkSetRequest"
31433338
public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}interface\0\u{1}up\0\u{1}mtu\0")

Sources/Containerization/SandboxContext/SandboxContext.proto

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ service SandboxContext {
3030
rpc Copy(CopyRequest) returns (stream CopyResponse);
3131
// Stat a path in the guest filesystem.
3232
rpc Stat(StatRequest) returns (StatResponse);
33+
// Perform a filesystem operation on a mounted filesystem.
34+
rpc FilesystemOperation(FilesystemOperationRequest) returns (FilesystemOperationResponse);
3335

3436
// Create a new process inside the container.
3537
rpc CreateProcess(CreateProcessRequest) returns (CreateProcessResponse);
@@ -292,6 +294,19 @@ message StatResponse {
292294
string error = 2; // Non-empty if stat failed.
293295
}
294296

297+
message FiFreezeParams {}
298+
message FiThawParams {}
299+
300+
message FilesystemOperationRequest {
301+
string path = 1;
302+
oneof operation {
303+
FiFreezeParams freeze = 2;
304+
FiThawParams thaw = 3;
305+
}
306+
}
307+
308+
message FilesystemOperationResponse {}
309+
295310
message IpLinkSetRequest {
296311
string interface = 1;
297312
bool up = 2;

Sources/Containerization/VirtualMachineAgent.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ public struct WriteFileFlags {
2525
public var create = false
2626
}
2727

28+
public enum FilesystemOperation: Sendable {
29+
case freeze
30+
case thaw
31+
}
32+
2833
/// A protocol for the agent running inside a virtual machine. If an operation isn't
2934
/// supported the implementation MUST return a ContainerizationError with a code of
3035
/// `.unsupported`.
@@ -34,6 +39,8 @@ public protocol VirtualMachineAgent: Sendable {
3439
func standardSetup() async throws
3540
/// Close any resources held by the agent.
3641
func close() async throws
42+
// Perform a filesystem operation on the given path.
43+
func filesystemOperation(operation: FilesystemOperation, path: String) async throws
3744

3845
// POSIX-y
3946
func getenv(key: String) async throws -> String

Sources/Containerization/Vminitd.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,15 @@ extension Vminitd: VirtualMachineAgent {
207207
})
208208
}
209209

210+
/// Perform a filesystem operation on a path inside the sandbox's environment.
211+
public func filesystemOperation(operation: FilesystemOperation, path: String) async throws {
212+
_ = try await client.filesystemOperation(
213+
.with {
214+
$0.operation = operation.toProtoOperation()
215+
$0.path = path
216+
})
217+
}
218+
210219
public func createProcess(
211220
id: String,
212221
containerID: String?,
@@ -596,3 +605,15 @@ extension StatCategory {
596605
return categories
597606
}
598607
}
608+
609+
extension FilesystemOperation {
610+
/// Convert FilesystemOperation to proto oneof value.
611+
func toProtoOperation() -> Com_Apple_Containerization_Sandbox_V3_FilesystemOperationRequest.OneOf_Operation {
612+
switch self {
613+
case .freeze:
614+
return .freeze(.init())
615+
case .thaw:
616+
return .thaw(.init())
617+
}
618+
}
619+
}

0 commit comments

Comments
 (0)