use crate::core::client::VimClientHandle;
use crate::core::error::{Error, Result};
use crate::core::pc_helpers::{obj_spec_for_view, BoxableError, Queriable};
use crate::mo::{PropertyCollector, ViewManager};
use crate::types::structs::{ManagedObjectReference, ObjectContent, ObjectSpec};
use log::error;
pub trait Retrievable: Queriable + TryFrom<ObjectContent>
where
Self::Error: BoxableError,
{
}
impl<T: Queriable + TryFrom<ObjectContent, Error = E>, E: BoxableError> Retrievable for T {}
pub struct ObjectRetriever {
client: VimClientHandle,
property_collector: PropertyCollector,
view_manager: ViewManager,
}
impl ObjectRetriever {
pub fn new(client: VimClientHandle) -> Result<Self> {
let pc_mo_id = &client.service_content().property_collector.value;
let property_collector = PropertyCollector::new(client.clone(), pc_mo_id);
let Some(view_manager_moref) = &client.service_content().view_manager else {
return Err(Error::internal("cannot find view_manager".to_string()));
};
let view_manager = ViewManager::new(client.clone(), &view_manager_moref.value);
Ok(Self {
client,
property_collector,
view_manager,
})
}
pub async fn retrieve_objects_from_container<T: Retrievable>(&self, container: &ManagedObjectReference) -> Result<Vec<T>>
where
<T as TryFrom<crate::types::structs::ObjectContent>>::Error: BoxableError,
{
let view_moref = self
.view_manager
.create_container_view(container, Some(&[T::prop_spec().r#type]), true)
.await?;
self.retrieve_objects_from_view(&view_moref).await
}
pub async fn retrieve_objects_from_list<T: Retrievable>(&self, objs: &[ManagedObjectReference]) -> Result<Vec<T>>
where
<T as TryFrom<crate::types::structs::ObjectContent>>::Error: BoxableError,
{
let view_moref = self.view_manager.create_list_view(Some(objs)).await?;
self.retrieve_objects_from_view(&view_moref).await
}
async fn retrieve_objects_from_view<T: Retrievable>(&self, view_moref: &ManagedObjectReference)-> Result<Vec<T>>
where
<T as TryFrom<crate::types::structs::ObjectContent>>::Error: BoxableError,
{
let object_set = obj_spec_for_view(view_moref.clone());
let res = self.retrieve_objects(object_set).await;
if let Err(e) = self.client
.invoke_void("", view_moref.r#type.as_str(), &view_moref.value, "DestroyView", None)
.await {
error!("Error destroying view {}:{}: {:?}", view_moref.r#type.as_str(), view_moref.value, e);
};
res
}
pub async fn retrieve_object<T: Retrievable>(&self, obj: &ManagedObjectReference) -> Result<Option<T>>
where
<T as TryFrom<crate::types::structs::ObjectContent>>::Error: BoxableError,
{
let object_spec = ObjectSpec {
obj: obj.clone(),
skip: Some(false),
select_set: None,
};
let object_set = vec![object_spec];
let res = self.retrieve_objects(object_set).await?;
Ok(res.into_iter().next())
}
pub async fn retrieve_objects<T: Retrievable>(&self, object_set: Vec<ObjectSpec>) -> Result<Vec<T>>
where
<T as TryFrom<crate::types::structs::ObjectContent>>::Error: BoxableError,
{
let spec_set = vec![crate::types::structs::PropertyFilterSpec {
object_set,
prop_set: vec![T::prop_spec()],
report_missing_objects_in_results: Some(true),
}];
let options = crate::types::structs::RetrieveOptions {
max_objects: Some(100),
};
let mut vms: Vec<T> = Vec::new();
let retrieve_result = self
.property_collector
.retrieve_properties_ex(&spec_set, &options)
.await?;
let Some(mut res) = retrieve_result else {
return Ok(Vec::new());
};
loop {
for obj in res.objects {
vms.push(obj.try_into().map_err(|e| -> Error { Error::from(Box::new(e) as Box<dyn std::error::Error + Send + Sync>) })?);
};
let Some(token) = res.token else {
break;
};
res = self
.property_collector
.continue_retrieve_properties_ex(&token)
.await?;
}
Ok(vms)
}
}