-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathmod.rs
More file actions
135 lines (114 loc) · 4.55 KB
/
mod.rs
File metadata and controls
135 lines (114 loc) · 4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: Apache-2.0
use crate::VmEventWrapper;
use feos_proto::vm_service::{
AttachDiskRequest, AttachDiskResponse, AttachNicRequest, AttachNicResponse, CreateVmRequest,
DeleteVmRequest, DeleteVmResponse, DetachDiskRequest, DetachDiskResponse, DetachNicRequest,
DetachNicResponse, GetVmRequest, PauseVmRequest, PauseVmResponse, PingVmRequest,
PingVmResponse, ResumeVmRequest, ResumeVmResponse, ShutdownVmRequest, ShutdownVmResponse,
StartVmRequest, StartVmResponse, VmEvent, VmInfo, VmStateChangedEvent,
};
use prost::Message;
use prost_types::Any;
use std::path::{Path, PathBuf};
use tokio::sync::{broadcast, mpsc};
use tonic::Status;
use uuid::Uuid;
pub mod ch_adapter;
#[derive(Debug, thiserror::Error)]
pub enum VmmError {
#[error("Hypervisor process failed to start: {0}")]
ProcessSpawnFailed(String),
#[error("The provided configuration is invalid for this hypervisor: {0}")]
InvalidConfig(String),
#[error("Could not connect to the hypervisor's API socket: {0}")]
ApiConnectionFailed(String),
#[error("The hypervisor's API returned an error: {0}")]
ApiOperationFailed(String),
#[error("The requested VM (id: {0}) could not be found")]
VmNotFound(String),
#[error("The image service returned an error: {0}")]
ImageServiceFailed(String),
#[error("An internal or unexpected error occurred: {0}")]
Internal(String),
}
impl From<VmmError> for Status {
fn from(err: VmmError) -> Self {
match err {
VmmError::VmNotFound(id) => Status::not_found(id),
VmmError::InvalidConfig(msg) => Status::invalid_argument(msg),
VmmError::ApiConnectionFailed(msg) | VmmError::ImageServiceFailed(msg) => {
Status::unavailable(msg)
}
VmmError::ProcessSpawnFailed(msg)
| VmmError::ApiOperationFailed(msg)
| VmmError::Internal(msg) => Status::internal(msg),
}
}
}
#[tonic::async_trait]
pub trait Hypervisor: Send + Sync {
async fn create_vm(
&self,
vm_id: &str,
req: CreateVmRequest,
image_uuid: String,
) -> Result<Option<i64>, VmmError>;
async fn start_vm(&self, req: StartVmRequest) -> Result<StartVmResponse, VmmError>;
async fn healthcheck_vm(
&self,
vm_id: String,
broadcast_tx: mpsc::Sender<VmEventWrapper>,
cancel_bus: broadcast::Receiver<Uuid>,
);
async fn get_vm(&self, req: GetVmRequest) -> Result<VmInfo, VmmError>;
async fn delete_vm(
&self,
req: DeleteVmRequest,
process_id: Option<i64>,
) -> Result<DeleteVmResponse, VmmError>;
async fn get_console_socket_path(&self, vm_id: &str) -> Result<PathBuf, VmmError>;
async fn ping_vm(&self, req: PingVmRequest) -> Result<PingVmResponse, VmmError>;
async fn shutdown_vm(&self, req: ShutdownVmRequest) -> Result<ShutdownVmResponse, VmmError>;
async fn pause_vm(&self, req: PauseVmRequest) -> Result<PauseVmResponse, VmmError>;
async fn resume_vm(&self, req: ResumeVmRequest) -> Result<ResumeVmResponse, VmmError>;
async fn attach_disk(&self, req: AttachDiskRequest) -> Result<AttachDiskResponse, VmmError>;
async fn detach_disk(&self, req: DetachDiskRequest) -> Result<DetachDiskResponse, VmmError>;
async fn attach_nic(&self, req: AttachNicRequest) -> Result<AttachNicResponse, VmmError>;
async fn detach_nic(&self, req: DetachNicRequest) -> Result<DetachNicResponse, VmmError>;
}
pub async fn broadcast_state_change_event(
broadcast_tx: &mpsc::Sender<VmEventWrapper>,
vm_id: &str,
component: &str,
data: VmStateChangedEvent,
process_id: Option<i64>,
) {
let event = VmEvent {
vm_id: vm_id.to_string(),
id: Uuid::new_v4().to_string(),
component_id: component.to_string(),
data: Some(Any {
type_url: "type.googleapis.com/feos.vm.vmm.api.v1.VmStateChangedEvent".to_string(),
value: data.encode_to_vec(),
}),
};
if broadcast_tx
.send(VmEventWrapper { event, process_id })
.await
.is_err()
{
log::warn!("Failed to broadcast event for VM '{vm_id}': channel closed.");
}
}
pub enum VmmType {
CloudHypervisor,
}
pub fn factory(vmm_type: VmmType) -> Box<dyn Hypervisor> {
match vmm_type {
VmmType::CloudHypervisor => {
let ch_binary_path = Path::new(super::VM_CH_BIN).to_path_buf();
Box::new(ch_adapter::CloudHypervisorAdapter::new(ch_binary_path))
}
}
}