mirror of
https://github.com/apple/container.git
synced 2026-11-14 18:00:32 +00:00
Agent: Add and implement writeFile (#259)
This change adds in a new rpc that we probably should swap to for the underlying implementation of a couple rpcs we currently have. This new rpc simply writes to an existing or new file some data. This is useful for guest (and container) setup for things like /etc/hosts, /etc/resolv.conf, writing to one-off cgroup files and so on. Currently I've just implemented subtree_control toggling for the root cg in standardSetup with this new change, but in the future I'd like to swap the implementations of our /etc/hosts and /etc/resolv.conf logic with this.
This commit is contained in:
1 parent
7b00f39140
commit
87541cbe65
6 files changed
+380
-1
No files matched your search
@@ -64,6 +64,29 @@ extension Vminitd: VirtualMachineAgent {
|
||||
for mount in mounts {
|
||||
try await self.mount(mount)
|
||||
}
|
||||
|
||||
// Setup root cg subtree_control.
|
||||
let data = "+memory +pids +io +cpu +cpuset".data(using: .utf8)!
|
||||
try await writeFile(
|
||||
path: "/sys/fs/cgroup/cgroup.subtree_control",
|
||||
data: data,
|
||||
flags: .init(),
|
||||
mode: 0
|
||||
)
|
||||
}
|
||||
|
||||
public func writeFile(path: String, data: Data, flags: WriteFileFlags, mode: UInt32) async throws {
|
||||
_ = try await client.writeFile(
|
||||
.with {
|
||||
$0.path = path
|
||||
$0.mode = mode
|
||||
$0.data = data
|
||||
$0.flags = .with {
|
||||
$0.append = flags.append
|
||||
$0.createIfMissing = flags.create
|
||||
$0.createParentDirs = flags.createParentDirectories
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Mount a filesystem in the sandbox's environment.
|
||||
|
||||
@@ -74,6 +74,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtoc
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<Com_Apple_Containerization_Sandbox_V3_SetupEmulatorRequest, Com_Apple_Containerization_Sandbox_V3_SetupEmulatorResponse>
|
||||
|
||||
func writeFile(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest,
|
||||
callOptions: CallOptions?
|
||||
) -> UnaryCall<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>
|
||||
|
||||
func createProcess(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest,
|
||||
callOptions: CallOptions?
|
||||
@@ -309,6 +314,24 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextClientProtocol {
|
||||
)
|
||||
}
|
||||
|
||||
/// Write data to an existing or new file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - request: Request to send to WriteFile.
|
||||
/// - callOptions: Call options.
|
||||
/// - Returns: A `UnaryCall` with futures for the metadata, status and response.
|
||||
public func writeFile(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> UnaryCall<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, Com_Apple_Containerization_Sandbox_V3_WriteFileResponse> {
|
||||
return self.makeUnaryCall(
|
||||
path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.writeFile.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeWriteFileInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new process inside the container.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -720,6 +743,11 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientP
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<Com_Apple_Containerization_Sandbox_V3_SetupEmulatorRequest, Com_Apple_Containerization_Sandbox_V3_SetupEmulatorResponse>
|
||||
|
||||
func makeWriteFileCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest,
|
||||
callOptions: CallOptions?
|
||||
) -> GRPCAsyncUnaryCall<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>
|
||||
|
||||
func makeCreateProcessCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest,
|
||||
callOptions: CallOptions?
|
||||
@@ -912,6 +940,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco
|
||||
)
|
||||
}
|
||||
|
||||
public func makeWriteFileCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
) -> GRPCAsyncUnaryCall<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, Com_Apple_Containerization_Sandbox_V3_WriteFileResponse> {
|
||||
return self.makeAsyncUnaryCall(
|
||||
path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.writeFile.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeWriteFileInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
public func makeCreateProcessCall(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
@@ -1215,6 +1255,18 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncClientProtoco
|
||||
)
|
||||
}
|
||||
|
||||
public func writeFile(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_WriteFileResponse {
|
||||
return try await self.performAsyncUnaryCall(
|
||||
path: Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.writeFile.path,
|
||||
request: request,
|
||||
callOptions: callOptions ?? self.defaultCallOptions,
|
||||
interceptors: self.interceptors?.makeWriteFileInterceptors() ?? []
|
||||
)
|
||||
}
|
||||
|
||||
public func createProcess(
|
||||
_ request: Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest,
|
||||
callOptions: CallOptions? = nil
|
||||
@@ -1463,6 +1515,9 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextClientInterc
|
||||
/// - Returns: Interceptors to use when invoking 'setupEmulator'.
|
||||
func makeSetupEmulatorInterceptors() -> [ClientInterceptor<Com_Apple_Containerization_Sandbox_V3_SetupEmulatorRequest, Com_Apple_Containerization_Sandbox_V3_SetupEmulatorResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'writeFile'.
|
||||
func makeWriteFileInterceptors() -> [ClientInterceptor<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when invoking 'createProcess'.
|
||||
func makeCreateProcessInterceptors() -> [ClientInterceptor<Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest, Com_Apple_Containerization_Sandbox_V3_CreateProcessResponse>]
|
||||
|
||||
@@ -1528,6 +1583,7 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata {
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.sysctl,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.setTime,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.setupEmulator,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.writeFile,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.createProcess,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.deleteProcess,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata.Methods.startProcess,
|
||||
@@ -1597,6 +1653,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextClientMetadata {
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let writeFile = GRPCMethodDescriptor(
|
||||
name: "WriteFile",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/WriteFile",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let createProcess = GRPCMethodDescriptor(
|
||||
name: "CreateProcess",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/CreateProcess",
|
||||
@@ -1731,6 +1793,9 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider: Ca
|
||||
/// Set up an emulator in the guest for a specific binary format.
|
||||
func setupEmulator(request: Com_Apple_Containerization_Sandbox_V3_SetupEmulatorRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Com_Apple_Containerization_Sandbox_V3_SetupEmulatorResponse>
|
||||
|
||||
/// Write data to an existing or new file.
|
||||
func writeFile(request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>
|
||||
|
||||
/// Create a new process inside the container.
|
||||
func createProcess(request: Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest, context: StatusOnlyCallContext) -> EventLoopFuture<Com_Apple_Containerization_Sandbox_V3_CreateProcessResponse>
|
||||
|
||||
@@ -1868,6 +1933,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextProvider {
|
||||
userFunction: self.setupEmulator(request:context:)
|
||||
)
|
||||
|
||||
case "WriteFile":
|
||||
return UnaryServerHandler(
|
||||
context: context,
|
||||
requestDeserializer: ProtobufDeserializer<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest>(),
|
||||
responseSerializer: ProtobufSerializer<Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>(),
|
||||
interceptors: self.interceptors?.makeWriteFileInterceptors() ?? [],
|
||||
userFunction: self.writeFile(request:context:)
|
||||
)
|
||||
|
||||
case "CreateProcess":
|
||||
return UnaryServerHandler(
|
||||
context: context,
|
||||
@@ -2083,6 +2157,12 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvide
|
||||
context: GRPCAsyncServerCallContext
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_SetupEmulatorResponse
|
||||
|
||||
/// Write data to an existing or new file.
|
||||
func writeFile(
|
||||
request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest,
|
||||
context: GRPCAsyncServerCallContext
|
||||
) async throws -> Com_Apple_Containerization_Sandbox_V3_WriteFileResponse
|
||||
|
||||
/// Create a new process inside the container.
|
||||
func createProcess(
|
||||
request: Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest,
|
||||
@@ -2278,6 +2358,15 @@ extension Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvider {
|
||||
wrapping: { try await self.setupEmulator(request: $0, context: $1) }
|
||||
)
|
||||
|
||||
case "WriteFile":
|
||||
return GRPCAsyncServerHandler(
|
||||
context: context,
|
||||
requestDeserializer: ProtobufDeserializer<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest>(),
|
||||
responseSerializer: ProtobufSerializer<Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>(),
|
||||
interceptors: self.interceptors?.makeWriteFileInterceptors() ?? [],
|
||||
wrapping: { try await self.writeFile(request: $0, context: $1) }
|
||||
)
|
||||
|
||||
case "CreateProcess":
|
||||
return GRPCAsyncServerHandler(
|
||||
context: context,
|
||||
@@ -2471,6 +2560,10 @@ public protocol Com_Apple_Containerization_Sandbox_V3_SandboxContextServerInterc
|
||||
/// Defaults to calling `self.makeInterceptors()`.
|
||||
func makeSetupEmulatorInterceptors() -> [ServerInterceptor<Com_Apple_Containerization_Sandbox_V3_SetupEmulatorRequest, Com_Apple_Containerization_Sandbox_V3_SetupEmulatorResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when handling 'writeFile'.
|
||||
/// Defaults to calling `self.makeInterceptors()`.
|
||||
func makeWriteFileInterceptors() -> [ServerInterceptor<Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, Com_Apple_Containerization_Sandbox_V3_WriteFileResponse>]
|
||||
|
||||
/// - Returns: Interceptors to use when handling 'createProcess'.
|
||||
/// Defaults to calling `self.makeInterceptors()`.
|
||||
func makeCreateProcessInterceptors() -> [ServerInterceptor<Com_Apple_Containerization_Sandbox_V3_CreateProcessRequest, Com_Apple_Containerization_Sandbox_V3_CreateProcessResponse>]
|
||||
@@ -2553,6 +2646,7 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata {
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.sysctl,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.setTime,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.setupEmulator,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.writeFile,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.createProcess,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.deleteProcess,
|
||||
Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata.Methods.startProcess,
|
||||
@@ -2622,6 +2716,12 @@ public enum Com_Apple_Containerization_Sandbox_V3_SandboxContextServerMetadata {
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let writeFile = GRPCMethodDescriptor(
|
||||
name: "WriteFile",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/WriteFile",
|
||||
type: GRPCCallType.unary
|
||||
)
|
||||
|
||||
public static let createProcess = GRPCMethodDescriptor(
|
||||
name: "CreateProcess",
|
||||
path: "/com.apple.containerization.sandbox.v3.SandboxContext/CreateProcess",
|
||||
|
||||
@@ -682,6 +682,59 @@ public struct Com_Apple_Containerization_Sandbox_V3_MkdirResponse: Sendable {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_WriteFileRequest: @unchecked Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
public var path: String = String()
|
||||
|
||||
public var data: Data = Data()
|
||||
|
||||
public var mode: UInt32 = 0
|
||||
|
||||
public var flags: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.WriteFileFlags {
|
||||
get {return _flags ?? Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.WriteFileFlags()}
|
||||
set {_flags = newValue}
|
||||
}
|
||||
/// Returns true if `flags` has been explicitly set.
|
||||
public var hasFlags: Bool {return self._flags != nil}
|
||||
/// Clears the value of `flags`. Subsequent reads from it will return its default value.
|
||||
public mutating func clearFlags() {self._flags = nil}
|
||||
|
||||
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
public struct WriteFileFlags: Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
public var createParentDirs: Bool = false
|
||||
|
||||
public var append: Bool = false
|
||||
|
||||
public var createIfMissing: Bool = false
|
||||
|
||||
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public init() {}
|
||||
|
||||
fileprivate var _flags: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.WriteFileFlags? = nil
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_WriteFileResponse: Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
public var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public struct Com_Apple_Containerization_Sandbox_V3_IpLinkSetRequest: Sendable {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
@@ -2152,6 +2205,123 @@ extension Com_Apple_Containerization_Sandbox_V3_MkdirResponse: SwiftProtobuf.Mes
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_WriteFileRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = _protobuf_package + ".WriteFileRequest"
|
||||
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "path"),
|
||||
2: .same(proto: "data"),
|
||||
3: .same(proto: "mode"),
|
||||
4: .same(proto: "flags"),
|
||||
]
|
||||
|
||||
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.path) }()
|
||||
case 2: try { try decoder.decodeSingularBytesField(value: &self.data) }()
|
||||
case 3: try { try decoder.decodeSingularUInt32Field(value: &self.mode) }()
|
||||
case 4: try { try decoder.decodeSingularMessageField(value: &self._flags) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
if !self.path.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.path, fieldNumber: 1)
|
||||
}
|
||||
if !self.data.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: self.data, fieldNumber: 2)
|
||||
}
|
||||
if self.mode != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.mode, fieldNumber: 3)
|
||||
}
|
||||
try { if let v = self._flags {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, rhs: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest) -> Bool {
|
||||
if lhs.path != rhs.path {return false}
|
||||
if lhs.data != rhs.data {return false}
|
||||
if lhs.mode != rhs.mode {return false}
|
||||
if lhs._flags != rhs._flags {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.WriteFileFlags: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.protoMessageName + ".WriteFileFlags"
|
||||
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .standard(proto: "create_parent_dirs"),
|
||||
2: .same(proto: "append"),
|
||||
3: .standard(proto: "create_if_missing"),
|
||||
]
|
||||
|
||||
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularBoolField(value: &self.createParentDirs) }()
|
||||
case 2: try { try decoder.decodeSingularBoolField(value: &self.append) }()
|
||||
case 3: try { try decoder.decodeSingularBoolField(value: &self.createIfMissing) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.createParentDirs != false {
|
||||
try visitor.visitSingularBoolField(value: self.createParentDirs, fieldNumber: 1)
|
||||
}
|
||||
if self.append != false {
|
||||
try visitor.visitSingularBoolField(value: self.append, fieldNumber: 2)
|
||||
}
|
||||
if self.createIfMissing != false {
|
||||
try visitor.visitSingularBoolField(value: self.createIfMissing, fieldNumber: 3)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.WriteFileFlags, rhs: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest.WriteFileFlags) -> Bool {
|
||||
if lhs.createParentDirs != rhs.createParentDirs {return false}
|
||||
if lhs.append != rhs.append {return false}
|
||||
if lhs.createIfMissing != rhs.createIfMissing {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_WriteFileResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = _protobuf_package + ".WriteFileResponse"
|
||||
public static let _protobuf_nameMap = SwiftProtobuf._NameMap()
|
||||
|
||||
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
// Load everything into unknown fields
|
||||
while try decoder.nextFieldNumber() != nil {}
|
||||
}
|
||||
|
||||
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Com_Apple_Containerization_Sandbox_V3_WriteFileResponse, rhs: Com_Apple_Containerization_Sandbox_V3_WriteFileResponse) -> Bool {
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Com_Apple_Containerization_Sandbox_V3_IpLinkSetRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
public static let protoMessageName: String = _protobuf_package + ".IpLinkSetRequest"
|
||||
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
|
||||
@@ -20,6 +20,8 @@ service SandboxContext {
|
||||
rpc SetTime(SetTimeRequest) returns (SetTimeResponse);
|
||||
// Set up an emulator in the guest for a specific binary format.
|
||||
rpc SetupEmulator(SetupEmulatorRequest) returns (SetupEmulatorResponse);
|
||||
// Write data to an existing or new file.
|
||||
rpc WriteFile(WriteFileRequest) returns (WriteFileResponse);
|
||||
|
||||
// Create a new process inside the container.
|
||||
rpc CreateProcess(CreateProcessRequest) returns (CreateProcessResponse);
|
||||
@@ -201,6 +203,20 @@ message MkdirRequest {
|
||||
|
||||
message MkdirResponse {}
|
||||
|
||||
message WriteFileRequest {
|
||||
message WriteFileFlags {
|
||||
bool create_parent_dirs = 1;
|
||||
bool append = 2;
|
||||
bool create_if_missing = 3;
|
||||
}
|
||||
string path = 1;
|
||||
bytes data = 2;
|
||||
uint32 mode = 3;
|
||||
WriteFileFlags flags = 4;
|
||||
}
|
||||
|
||||
message WriteFileResponse {}
|
||||
|
||||
message IpLinkSetRequest {
|
||||
string interface = 1;
|
||||
bool up = 2;
|
||||
|
||||
@@ -18,6 +18,12 @@ import ContainerizationError
|
||||
import ContainerizationOCI
|
||||
import Foundation
|
||||
|
||||
public struct WriteFileFlags {
|
||||
public var createParentDirectories = false
|
||||
public var append = false
|
||||
public var create = false
|
||||
}
|
||||
|
||||
/// A protocol for the agent running inside a virtual machine. If an operation isn't
|
||||
/// supported the implementation MUST return a ContainerizationError with a code of
|
||||
/// `.unsupported`.
|
||||
@@ -28,7 +34,7 @@ public protocol VirtualMachineAgent: Sendable {
|
||||
/// Close any resources held by the agent.
|
||||
func close() async throws
|
||||
|
||||
// POSIX
|
||||
// POSIX-y
|
||||
func getenv(key: String) async throws -> String
|
||||
func setenv(key: String, value: String) async throws
|
||||
func mount(_ mount: ContainerizationOCI.Mount) async throws
|
||||
@@ -36,6 +42,7 @@ public protocol VirtualMachineAgent: Sendable {
|
||||
func mkdir(path: String, all: Bool, perms: UInt32) async throws
|
||||
@discardableResult
|
||||
func kill(pid: Int32, signal: Int32) async throws -> Int32
|
||||
func writeFile(path: String, data: Data, flags: WriteFileFlags, mode: UInt32) async throws
|
||||
|
||||
// Process lifecycle
|
||||
func createProcess(
|
||||
@@ -71,4 +78,8 @@ extension VirtualMachineAgent {
|
||||
public func configureHosts(config: Hosts, location: String) async throws {
|
||||
throw ContainerizationError(.unsupported, message: "configureHosts")
|
||||
}
|
||||
|
||||
public func writeFile(path: String, data: Data, flags: WriteFileFlags, mode: UInt32) async throws {
|
||||
throw ContainerizationError(.unsupported, message: "writeFile")
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,65 @@ extension Initd: Com_Apple_Containerization_Sandbox_V3_SandboxContextAsyncProvid
|
||||
return .init()
|
||||
}
|
||||
|
||||
func writeFile(request: Com_Apple_Containerization_Sandbox_V3_WriteFileRequest, context: GRPC.GRPCAsyncServerCallContext)
|
||||
async throws -> Com_Apple_Containerization_Sandbox_V3_WriteFileResponse
|
||||
{
|
||||
log.debug(
|
||||
"writeFile",
|
||||
metadata: [
|
||||
"path": "\(request.path)",
|
||||
"mode": "\(request.mode)",
|
||||
"dataSize": "\(request.data.count)",
|
||||
])
|
||||
|
||||
do {
|
||||
if request.flags.createParentDirs {
|
||||
let fileURL = URL(fileURLWithPath: request.path)
|
||||
let parentDir = fileURL.deletingLastPathComponent()
|
||||
try FileManager.default.createDirectory(
|
||||
at: parentDir,
|
||||
withIntermediateDirectories: true
|
||||
)
|
||||
}
|
||||
|
||||
var flags = O_WRONLY
|
||||
if request.flags.createIfMissing {
|
||||
flags |= O_CREAT
|
||||
}
|
||||
if request.flags.append {
|
||||
flags |= O_APPEND
|
||||
}
|
||||
|
||||
let mode = request.mode > 0 ? mode_t(request.mode) : mode_t(0644)
|
||||
let fd = open(request.path, flags, mode)
|
||||
guard fd != -1 else {
|
||||
let error = swiftErrno("open")
|
||||
throw GRPCStatus(
|
||||
code: .internalError,
|
||||
message: "writeFile: failed to open file: \(error)"
|
||||
)
|
||||
}
|
||||
|
||||
let fh = FileHandle(fileDescriptor: fd, closeOnDealloc: true)
|
||||
try fh.write(contentsOf: request.data)
|
||||
} catch {
|
||||
log.error(
|
||||
"writeFile",
|
||||
metadata: [
|
||||
"error": "\(error)"
|
||||
])
|
||||
if error is GRPCStatus {
|
||||
throw error
|
||||
}
|
||||
throw GRPCStatus(
|
||||
code: .internalError,
|
||||
message: "writeFile: \(error)"
|
||||
)
|
||||
}
|
||||
|
||||
return .init()
|
||||
}
|
||||
|
||||
func mount(request: Com_Apple_Containerization_Sandbox_V3_MountRequest, context: GRPC.GRPCAsyncServerCallContext)
|
||||
async throws -> Com_Apple_Containerization_Sandbox_V3_MountResponse
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user