1mod core;
117mod controller;
118pub mod scheduler;
119pub mod pool;
120pub mod discovery_scheduler;
121pub mod discovery;
122
123use std::sync::Arc;
124
125use serde::{Serialize, Deserialize};
126use tokio::sync::RwLock;
127use std::collections::HashMap;
128
129use crate::observability::{DMSCMetricsRegistry, DMSCMetric, DMSCMetricConfig, DMSCMetricType};
130
131#[cfg(feature = "pyo3")]
132use pyo3::prelude::*;
133
134
135pub use core::{DMSCDevice, DMSCDeviceType, DMSCDeviceStatus, DMSCDeviceCapabilities, DMSCDeviceControlConfig, DMSCDeviceConfig, DMSCNetworkDeviceInfo, DMSCDeviceHealthMetrics};
136pub use controller::DMSCDeviceController;
137pub use pool::{DMSCResourcePool, DMSCResourcePoolManager, DMSCConnectionPoolStatistics};
138pub use scheduler::DMSCDeviceScheduler;
139pub use discovery_scheduler::{DMSCDeviceDiscoveryEngine, DMSCResourceScheduler};
140
141pub use discovery::{
143 DMSCDeviceDiscovery,
144 DiscoveryConfig,
145 DiscoveryStats,
146 DiscoveryStrategy,
147 HardwareCategory,
148 PlatformInfo,
149 PlatformType,
150 Architecture,
151 PlatformCompatibility,
152 ProviderRegistry,
153 DMSCHardwareProvider,
154 PluginRegistry,
155 DMSCHardwareDiscoveryPlugin,
156 PluginMetadata,
157 PluginStatus,
158 PluginError,
159 AsyncDiscovery,
160};
161
162use crate::core::{DMSCResult, DMSCServiceContext};
163
164
165#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
170pub struct DMSCDeviceControlModule {
171 controller: Arc<RwLock<DMSCDeviceController>>,
173 scheduler: Arc<RwLock<DMSCDeviceScheduler>>,
175 discovery_engine: Arc<RwLock<DMSCResourceScheduler>>,
177 resource_pools: HashMap<String, Arc<DMSCResourcePool>>,
179 config: DMSCDeviceControlConfig,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
188#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
189pub struct DMSCDeviceSchedulingConfig {
190 pub discovery_enabled: bool,
192 pub discovery_interval_secs: u64,
194 pub auto_scheduling_enabled: bool,
196 pub max_concurrent_tasks: usize,
198 pub resource_allocation_timeout_secs: u64,
200}
201
202impl Default for DMSCDeviceSchedulingConfig {
203 fn default() -> Self {
204 Self {
205 discovery_enabled: true,
206 discovery_interval_secs: 30,
207 auto_scheduling_enabled: true,
208 max_concurrent_tasks: 100,
209 resource_allocation_timeout_secs: 60,
210 }
211 }
212}
213
214#[cfg(feature = "pyo3")]
215#[pymethods]
216impl DMSCDeviceSchedulingConfig {
217 #[new]
218 fn py_new() -> Self {
219 Self::default()
220 }
221
222 #[staticmethod]
223 fn default_config() -> Self {
224 Self::default()
225 }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
233#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
234pub struct DMSCDiscoveryResult {
235 pub discovered_devices: Vec<DMSCDevice>,
237 pub updated_devices: Vec<DMSCDevice>,
239 pub removed_devices: Vec<String>, pub total_devices: usize,
243}
244
245#[cfg(feature = "pyo3")]
246#[pymethods]
247impl DMSCDiscoveryResult {
248 #[new]
249 fn py_new() -> Self {
250 Self {
251 discovered_devices: Vec::new(),
252 updated_devices: Vec::new(),
253 removed_devices: Vec::new(),
254 total_devices: 0,
255 }
256 }
257
258 #[staticmethod]
259 fn default_result() -> Self {
260 Self::default()
261 }
262
263 fn discovered_devices_impl(&self) -> Vec<DMSCDevice> {
264 self.discovered_devices.clone()
265 }
266
267 fn updated_devices_impl(&self) -> Vec<DMSCDevice> {
268 self.updated_devices.clone()
269 }
270
271 fn removed_devices_impl(&self) -> Vec<String> {
272 self.removed_devices.clone()
273 }
274
275 fn total_devices_impl(&self) -> usize {
276 self.total_devices
277 }
278
279 fn __str__(&self) -> String {
280 format!("DMSCDiscoveryResult(discovered: {}, updated: {}, removed: {}, total: {})",
281 self.discovered_devices.len(), self.updated_devices.len(),
282 self.removed_devices.len(), self.total_devices)
283 }
284}
285
286impl Default for DMSCDiscoveryResult {
287 fn default() -> Self {
288 Self {
289 discovered_devices: Vec::new(),
290 updated_devices: Vec::new(),
291 removed_devices: Vec::new(),
292 total_devices: 0,
293 }
294 }
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
303#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
304pub struct DMSCResourceRequest {
305 pub request_id: String,
307 pub device_type: DMSCDeviceType,
309 pub required_capabilities: DMSCDeviceCapabilities,
311 pub priority: u8, pub timeout_secs: u64,
315 pub sla_class: Option<DMSCRequestSlaClass>,
317 pub resource_weights: Option<DMSCResourceWeights>,
319 pub affinity: Option<DMSCAffinityRules>,
321 pub anti_affinity: Option<DMSCAffinityRules>,
323}
324
325#[cfg(feature = "pyo3")]
326#[pymethods]
327impl DMSCResourceRequest {
328 #[new]
329 #[pyo3(signature = (request_id, device_type, required_capabilities, priority=5, timeout_secs=60))]
330 fn py_new(request_id: String, device_type: DMSCDeviceType, required_capabilities: DMSCDeviceCapabilities, priority: u8, timeout_secs: u64) -> Self {
331 Self {
332 request_id,
333 device_type,
334 required_capabilities,
335 priority,
336 timeout_secs,
337 sla_class: None,
338 resource_weights: None,
339 affinity: None,
340 anti_affinity: None,
341 }
342 }
343
344 #[pyo3(name = "request_id")]
345 fn request_id_impl(&self) -> String {
346 self.request_id.clone()
347 }
348
349 #[pyo3(name = "device_type")]
350 fn device_type_impl(&self) -> DMSCDeviceType {
351 self.device_type
352 }
353
354 #[pyo3(name = "required_capabilities")]
355 fn required_capabilities_impl(&self) -> DMSCDeviceCapabilities {
356 self.required_capabilities.clone()
357 }
358
359 #[pyo3(name = "priority")]
360 fn priority_impl(&self) -> u8 {
361 self.priority
362 }
363
364 #[pyo3(name = "timeout_secs")]
365 fn timeout_secs_impl(&self) -> u64 {
366 self.timeout_secs
367 }
368
369 #[pyo3(name = "sla_class")]
370 fn sla_class_impl(&self) -> Option<DMSCRequestSlaClass> {
371 self.sla_class
372 }
373
374 #[pyo3(name = "resource_weights")]
375 fn resource_weights_impl(&self) -> Option<DMSCResourceWeights> {
376 self.resource_weights.clone()
377 }
378
379 #[pyo3(name = "affinity")]
380 fn affinity_impl(&self) -> Option<DMSCAffinityRules> {
381 self.affinity.clone()
382 }
383
384 #[pyo3(name = "anti_affinity")]
385 fn anti_affinity_impl(&self) -> Option<DMSCAffinityRules> {
386 self.anti_affinity.clone()
387 }
388
389 #[pyo3(name = "set_priority")]
390 fn set_priority_impl(&mut self, priority: u8) {
391 self.priority = priority;
392 }
393
394 #[pyo3(name = "set_timeout_secs")]
395 fn set_timeout_secs_impl(&mut self, timeout_secs: u64) {
396 self.timeout_secs = timeout_secs;
397 }
398
399 #[pyo3(name = "set_sla_class")]
400 fn set_sla_class_impl(&mut self, sla_class: Option<DMSCRequestSlaClass>) {
401 self.sla_class = sla_class;
402 }
403
404 #[pyo3(name = "set_resource_weights")]
405 fn set_resource_weights_impl(&mut self, resource_weights: Option<DMSCResourceWeights>) {
406 self.resource_weights = resource_weights;
407 }
408
409 #[pyo3(name = "set_affinity")]
410 fn set_affinity_impl(&mut self, affinity: Option<DMSCAffinityRules>) {
411 self.affinity = affinity;
412 }
413
414 #[pyo3(name = "set_anti_affinity")]
415 fn set_anti_affinity_impl(&mut self, anti_affinity: Option<DMSCAffinityRules>) {
416 self.anti_affinity = anti_affinity;
417 }
418
419 fn __str__(&self) -> String {
420 format!("DMSCResourceRequest(id: {}, type: {:?}, priority: {}, timeout: {}s)",
421 self.request_id, self.device_type, self.priority, self.timeout_secs)
422 }
423}
424
425#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
430#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
431pub enum DMSCRequestSlaClass {
432 Critical,
434 High,
436 Medium,
438 Low,
440}
441
442#[cfg(feature = "pyo3")]
443#[pymethods]
444impl DMSCRequestSlaClass {
445 fn __str__(&self) -> String {
446 match self {
447 DMSCRequestSlaClass::Critical => "Critical".to_string(),
448 DMSCRequestSlaClass::High => "High".to_string(),
449 DMSCRequestSlaClass::Medium => "Medium".to_string(),
450 DMSCRequestSlaClass::Low => "Low".to_string(),
451 }
452 }
453}
454
455#[derive(Debug, Clone, Serialize, Deserialize)]
461#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
462pub struct DMSCResourceWeights {
463 pub compute_weight: f64,
465 pub memory_weight: f64,
467 pub storage_weight: f64,
469 pub bandwidth_weight: f64,
471}
472
473#[cfg(feature = "pyo3")]
474#[pymethods]
475impl DMSCResourceWeights {
476 #[new]
477 #[pyo3(signature = (compute_weight=1.0, memory_weight=1.0, storage_weight=1.0, bandwidth_weight=1.0))]
478 fn py_new(compute_weight: f64, memory_weight: f64, storage_weight: f64, bandwidth_weight: f64) -> Self {
479 Self {
480 compute_weight,
481 memory_weight,
482 storage_weight,
483 bandwidth_weight,
484 }
485 }
486
487 #[staticmethod]
488 fn default_weights() -> Self {
489 Self::default()
490 }
491
492 #[pyo3(name = "compute_weight")]
493 fn compute_weight_impl(&self) -> f64 { self.compute_weight }
494 #[pyo3(name = "memory_weight")]
495 fn memory_weight_impl(&self) -> f64 { self.memory_weight }
496 #[pyo3(name = "storage_weight")]
497 fn storage_weight_impl(&self) -> f64 { self.storage_weight }
498 #[pyo3(name = "bandwidth_weight")]
499 fn bandwidth_weight_impl(&self) -> f64 { self.bandwidth_weight }
500
501 #[pyo3(name = "set_compute_weight")]
502 fn set_compute_weight_impl(&mut self, weight: f64) { self.compute_weight = weight; }
503 #[pyo3(name = "set_memory_weight")]
504 fn set_memory_weight_impl(&mut self, weight: f64) { self.memory_weight = weight; }
505 #[pyo3(name = "set_storage_weight")]
506 fn set_storage_weight_impl(&mut self, weight: f64) { self.storage_weight = weight; }
507 #[pyo3(name = "set_bandwidth_weight")]
508 fn set_bandwidth_weight_impl(&mut self, weight: f64) { self.bandwidth_weight = weight; }
509
510 fn __str__(&self) -> String {
511 format!("DMSCResourceWeights(compute: {}, memory: {}, storage: {}, bandwidth: {})",
512 self.compute_weight, self.memory_weight, self.storage_weight, self.bandwidth_weight)
513 }
514}
515
516impl Default for DMSCResourceWeights {
517 fn default() -> Self {
518 Self {
519 compute_weight: 1.0,
520 memory_weight: 1.0,
521 storage_weight: 1.0,
522 bandwidth_weight: 1.0,
523 }
524 }
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
532#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
533pub struct DMSCAffinityRules {
534 pub required_labels: HashMap<String, String>,
536 pub preferred_labels: HashMap<String, String>,
538 pub forbidden_labels: HashMap<String, String>,
540}
541
542#[cfg(feature = "pyo3")]
543#[pymethods]
544impl DMSCAffinityRules {
545 #[new]
546 fn py_new() -> Self {
547 Self {
548 required_labels: HashMap::new(),
549 preferred_labels: HashMap::new(),
550 forbidden_labels: HashMap::new(),
551 }
552 }
553
554 #[staticmethod]
555 fn default_rules() -> Self {
556 Self::default()
557 }
558
559 #[pyo3(name = "required_labels")]
560 fn required_labels_impl(&self) -> HashMap<String, String> {
561 self.required_labels.clone()
562 }
563
564 #[pyo3(name = "preferred_labels")]
565 fn preferred_labels_impl(&self) -> HashMap<String, String> {
566 self.preferred_labels.clone()
567 }
568
569 #[pyo3(name = "forbidden_labels")]
570 fn forbidden_labels_impl(&self) -> HashMap<String, String> {
571 self.forbidden_labels.clone()
572 }
573
574 fn __str__(&self) -> String {
575 format!("DMSCAffinityRules(required: {}, preferred: {}, forbidden: {})",
576 self.required_labels.len(), self.preferred_labels.len(), self.forbidden_labels.len())
577 }
578}
579
580impl Default for DMSCAffinityRules {
581 fn default() -> Self {
582 Self {
583 required_labels: HashMap::new(),
584 preferred_labels: HashMap::new(),
585 forbidden_labels: HashMap::new(),
586 }
587 }
588}
589
590#[derive(Debug, Clone, Serialize, Deserialize)]
595#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
596pub struct DMSCResourceAllocation {
597 pub allocation_id: String,
599 pub device_id: String,
601 pub device_name: String,
603 pub allocated_at: chrono::DateTime<chrono::Utc>,
605 pub expires_at: chrono::DateTime<chrono::Utc>,
607 pub request: DMSCResourceRequest,
609}
610
611#[cfg(feature = "pyo3")]
612#[pymethods]
613impl DMSCResourceAllocation {
614 #[new]
615 fn py_new(allocation_id: String, device_id: String, device_name: String, request: DMSCResourceRequest) -> Self {
616 let now = chrono::Utc::now();
617 let expires_at = now + chrono::TimeDelta::seconds(request.timeout_secs as i64);
618
619 Self {
620 allocation_id,
621 device_id,
622 device_name,
623 allocated_at: now,
624 expires_at,
625 request,
626 }
627 }
628
629 #[pyo3(name = "allocation_id")]
630 fn allocation_id_impl(&self) -> String {
631 self.allocation_id.clone()
632 }
633
634 #[pyo3(name = "device_id")]
635 fn device_id_impl(&self) -> String {
636 self.device_id.clone()
637 }
638
639 #[pyo3(name = "device_name")]
640 fn device_name_impl(&self) -> String {
641 self.device_name.clone()
642 }
643
644 #[pyo3(name = "allocated_at")]
645 fn allocated_at_impl(&self) -> String {
646 self.allocated_at.to_rfc3339()
647 }
648
649 #[pyo3(name = "expires_at")]
650 fn expires_at_impl(&self) -> String {
651 self.expires_at.to_rfc3339()
652 }
653
654 #[pyo3(name = "request")]
655 fn request_impl(&self) -> DMSCResourceRequest {
656 self.request.clone()
657 }
658
659 #[pyo3(name = "is_expired")]
660 fn is_expired_impl(&self) -> bool {
661 chrono::Utc::now() > self.expires_at
662 }
663
664 #[pyo3(name = "remaining_time")]
665 fn remaining_time_impl(&self) -> i64 {
666 (self.expires_at - chrono::Utc::now()).num_seconds()
667 }
668
669 fn __str__(&self) -> String {
670 format!("DMSCResourceAllocation(id: {}, device: {} ({}), expires: {})",
671 self.allocation_id, self.device_name, self.device_id, self.expires_at)
672 }
673}
674
675impl Default for DMSCDeviceControlModule {
676 fn default() -> Self {
677 Self::new()
678 }
679}
680
681impl DMSCDeviceControlModule {
682 pub fn new() -> Self {
688 let controller = Arc::new(RwLock::new(DMSCDeviceController::new()));
689 let resource_pool_manager = Arc::new(RwLock::new(DMSCResourcePoolManager::new()));
690 let scheduler = Arc::new(RwLock::new(DMSCDeviceScheduler::new(resource_pool_manager)));
691 let discovery_engine = Arc::new(RwLock::new(DMSCResourceScheduler::new()));
692
693 Self {
694 controller,
695 scheduler,
696 discovery_engine,
697 resource_pools: HashMap::new(),
698 config: crate::device::core::DMSCDeviceControlConfig::default(),
699 }
700 }
701
702 pub fn with_config(mut self, config: crate::device::core::DMSCDeviceControlConfig) -> Self {
712 self.config = config;
713 self
714 }
715
716 pub async fn discover_devices(&self) -> DMSCResult<DMSCDiscoveryResult> {
725 if !self.config.enable_cpu_discovery && !self.config.enable_gpu_discovery &&
726 !self.config.enable_memory_discovery && !self.config.enable_storage_discovery &&
727 !self.config.enable_network_discovery {
728 return Ok(DMSCDiscoveryResult {
729 discovered_devices: vec![],
730 updated_devices: vec![],
731 removed_devices: vec![],
732 total_devices: 0,
733 });
734 }
735
736 let mut controller = self.controller.write().await;
737 controller.discover_devices().await
738 }
739
740 pub async fn allocate_resource(&self, request: DMSCResourceRequest) -> DMSCResult<Option<DMSCResourceAllocation>> {
754 let scheduling_enabled = match request.device_type {
756 DMSCDeviceType::CPU => self.config.enable_cpu_discovery,
757 DMSCDeviceType::GPU => self.config.enable_gpu_discovery,
758 DMSCDeviceType::Memory => self.config.enable_memory_discovery,
759 DMSCDeviceType::Storage => self.config.enable_storage_discovery,
760 DMSCDeviceType::Network => self.config.enable_network_discovery,
761 _ => true, };
763
764 if !scheduling_enabled {
765 return Ok(None);
766 }
767
768 let allocation_request = crate::device::scheduler::DMSCAllocationRequest {
769 device_type: request.device_type,
770 capabilities: request.required_capabilities,
771 priority: request.priority as u32,
772 timeout_secs: request.timeout_secs,
773 sla_class: request.sla_class,
774 resource_weights: request.resource_weights,
775 affinity: request.affinity,
776 anti_affinity: request.anti_affinity,
777 };
778
779 let scheduler = self.scheduler.write().await;
780 let device = scheduler.select_device(&allocation_request).await;
781
782 if let Some(device) = device {
783 let allocation = DMSCResourceAllocation {
784 allocation_id: uuid::Uuid::new_v4().to_string(),
785 device_id: device.id().to_string(),
786 device_name: device.name().to_string(),
787 allocated_at: chrono::Utc::now(),
788 expires_at: chrono::Utc::now() + chrono::Duration::seconds(allocation_request.timeout_secs as i64),
789 request: DMSCResourceRequest {
790 request_id: request.request_id,
791 device_type: allocation_request.device_type,
792 required_capabilities: allocation_request.capabilities,
793 priority: request.priority,
794 timeout_secs: allocation_request.timeout_secs,
795 sla_class: allocation_request.sla_class,
796 resource_weights: allocation_request.resource_weights,
797 affinity: allocation_request.affinity,
798 anti_affinity: allocation_request.anti_affinity,
799 },
800 };
801
802 let mut controller = self.controller.write().await;
804 controller.allocate_device(&allocation.device_id, &allocation.allocation_id).await?;
805
806 Ok(Some(allocation))
807 } else {
808 Ok(None)
809 }
810 }
811
812 pub async fn release_resource(&self, allocation_id: &str) -> DMSCResult<()> {
824 let mut controller = self.controller.write().await;
825 controller.release_device_by_allocation(allocation_id).await
826 }
827
828 pub async fn get_device_status(&self) -> DMSCResult<Vec<DMSCDevice>> {
836 let controller = self.controller.read().await;
837 Ok(controller.get_all_devices())
838 }
839
840 pub fn get_resource_pool_status(&self) -> HashMap<String, DMSCResourcePoolStatus> {
848 let mut status = HashMap::new();
849 for (pool_name, pool) in &self.resource_pools {
850 status.insert(pool_name.clone(), pool.get_status());
851 }
852 status
853 }
854
855 #[allow(dead_code)]
874 fn create_device_metrics(&self, registry: Arc<DMSCMetricsRegistry>) -> DMSCResult<()> {
875 let device_total_config = DMSCMetricConfig {
877 metric_type: DMSCMetricType::Gauge,
878 name: "dms_device_total".to_string(),
879 help: "Total number of devices by type and status".to_string(),
880 buckets: vec![],
881 quantiles: vec![],
882 max_age: std::time::Duration::from_secs(300),
883 age_buckets: 5,
884 };
885 let device_total_metric = Arc::new(DMSCMetric::new(device_total_config));
886 registry.register(device_total_metric)?;
887
888 let allocation_attempts_config = DMSCMetricConfig {
890 metric_type: DMSCMetricType::Counter,
891 name: "dms_device_allocation_attempts_total".to_string(),
892 help: "Total number of device allocation attempts".to_string(),
893 buckets: vec![],
894 quantiles: vec![],
895 max_age: std::time::Duration::from_secs(0),
896 age_buckets: 0,
897 };
898 let allocation_attempts_metric = Arc::new(DMSCMetric::new(allocation_attempts_config));
899 registry.register(allocation_attempts_metric)?;
900
901 let allocation_success_config = DMSCMetricConfig {
903 metric_type: DMSCMetricType::Counter,
904 name: "dms_device_allocation_success_total".to_string(),
905 help: "Total number of successful device allocations".to_string(),
906 buckets: vec![],
907 quantiles: vec![],
908 max_age: std::time::Duration::from_secs(0),
909 age_buckets: 0,
910 };
911 let allocation_success_metric = Arc::new(DMSCMetric::new(allocation_success_config));
912 registry.register(allocation_success_metric)?;
913
914 let allocation_failure_config = DMSCMetricConfig {
916 metric_type: DMSCMetricType::Counter,
917 name: "dms_device_allocation_failure_total".to_string(),
918 help: "Total number of failed device allocations".to_string(),
919 buckets: vec![],
920 quantiles: vec![],
921 max_age: std::time::Duration::from_secs(0),
922 age_buckets: 0,
923 };
924 let allocation_failure_metric = Arc::new(DMSCMetric::new(allocation_failure_config));
925 registry.register(allocation_failure_metric)?;
926
927 let discovery_attempts_config = DMSCMetricConfig {
929 metric_type: DMSCMetricType::Counter,
930 name: "dms_device_discovery_attempts_total".to_string(),
931 help: "Total number of device discovery attempts".to_string(),
932 buckets: vec![],
933 quantiles: vec![],
934 max_age: std::time::Duration::from_secs(0),
935 age_buckets: 0,
936 };
937 let discovery_attempts_metric = Arc::new(DMSCMetric::new(discovery_attempts_config));
938 registry.register(discovery_attempts_metric)?;
939
940 let discovery_success_config = DMSCMetricConfig {
942 metric_type: DMSCMetricType::Counter,
943 name: "dms_device_discovery_success_total".to_string(),
944 help: "Total number of successful device discoveries".to_string(),
945 buckets: vec![],
946 quantiles: vec![],
947 max_age: std::time::Duration::from_secs(0),
948 age_buckets: 0,
949 };
950 let discovery_success_metric = Arc::new(DMSCMetric::new(discovery_success_config));
951 registry.register(discovery_success_metric)?;
952
953 let resource_utilization_config = DMSCMetricConfig {
955 metric_type: DMSCMetricType::Gauge,
956 name: "dms_device_resource_utilization".to_string(),
957 help: "Resource utilization by device type".to_string(),
958 buckets: vec![],
959 quantiles: vec![],
960 max_age: std::time::Duration::from_secs(300),
961 age_buckets: 5,
962 };
963 let resource_utilization_metric = Arc::new(DMSCMetric::new(resource_utilization_config));
964 registry.register(resource_utilization_metric)?;
965
966 Ok(())
967 }
968}
969
970#[cfg(feature = "pyo3")]
971#[pyo3::prelude::pymethods]
972impl DMSCDeviceControlModule {
973 fn get_config(&self) -> String {
974 format!("{:?}", self.config)
975 }
976}
977
978#[derive(Debug, Clone, Serialize, Deserialize)]
983#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
984pub struct DMSCResourcePoolStatus {
985 pub total_capacity: usize,
987 pub available_capacity: usize,
989 pub allocated_capacity: usize,
991 pub pending_requests: usize,
993 pub utilization_rate: f64,
995}
996
997#[cfg(feature = "pyo3")]
998#[pyo3::prelude::pymethods]
999impl DMSCResourcePoolStatus {
1000 #[new]
1001 #[pyo3(signature = (total_capacity=0, available_capacity=0, allocated_capacity=0, pending_requests=0, utilization_rate=0.0))]
1002 fn py_new(total_capacity: usize, available_capacity: usize, allocated_capacity: usize, pending_requests: usize, utilization_rate: f64) -> Self {
1003 Self {
1004 total_capacity,
1005 available_capacity,
1006 allocated_capacity,
1007 pending_requests,
1008 utilization_rate,
1009 }
1010 }
1011
1012 #[staticmethod]
1013 fn default_status() -> Self {
1014 Self::default()
1015 }
1016
1017 #[pyo3(name = "total_capacity")]
1018 fn total_capacity_impl(&self) -> usize {
1019 self.total_capacity
1020 }
1021
1022 #[pyo3(name = "available_capacity")]
1023 fn available_capacity_impl(&self) -> usize {
1024 self.available_capacity
1025 }
1026
1027 #[pyo3(name = "allocated_capacity")]
1028 fn allocated_capacity_impl(&self) -> usize {
1029 self.allocated_capacity
1030 }
1031
1032 #[pyo3(name = "pending_requests")]
1033 fn pending_requests_impl(&self) -> usize {
1034 self.pending_requests
1035 }
1036
1037 #[pyo3(name = "utilization_rate")]
1038 fn utilization_rate_impl(&self) -> f64 {
1039 self.utilization_rate
1040 }
1041
1042 fn __str__(&self) -> String {
1043 format!("DMSCResourcePoolStatus(total: {}, available: {}, allocated: {}, utilization: {:.2}%)",
1044 self.total_capacity, self.available_capacity, self.allocated_capacity, self.utilization_rate)
1045 }
1046}
1047
1048impl Default for DMSCResourcePoolStatus {
1049 fn default() -> Self {
1050 Self {
1051 total_capacity: 0,
1052 available_capacity: 0,
1053 allocated_capacity: 0,
1054 pending_requests: 0,
1055 utilization_rate: 0.0,
1056 }
1057 }
1058}
1059
1060#[async_trait::async_trait]
1061impl crate::core::DMSCModule for DMSCDeviceControlModule {
1062 fn name(&self) -> &str {
1068 "DMSC.DeviceControl"
1069 }
1070
1071 fn is_critical(&self) -> bool {
1081 false }
1083
1084 async fn init(&mut self, ctx: &mut DMSCServiceContext) -> DMSCResult<()> {
1091 let binding = ctx.config();
1092 let cfg = binding.config();
1093 let device_config = parse_device_config(cfg.get("device"));
1094
1095 let mut controller = self.controller.write().await;
1096 controller.discover_system_devices(&device_config).await?;
1097 drop(controller);
1098
1099 let discovery_engine = DMSCResourceScheduler::new();
1100
1101 let mut discovery_guard = self.discovery_engine.write().await;
1102 *discovery_guard = discovery_engine;
1103
1104 if let Some(metrics_registry) = ctx.metrics_registry() {
1105 let mut controller = self.controller.write().await;
1106 controller.initialize_metrics(&metrics_registry)?;
1107 drop(controller);
1108 }
1109
1110 let logger = ctx.logger();
1111 logger.info("DMSC.DeviceControl", "Device control module initialized with real hardware discovery")?;
1112 Ok(())
1113 }
1114}
1115
1116impl crate::core::ServiceModule for DMSCDeviceControlModule {
1117 fn name(&self) -> &str {
1118 "DMSC.DeviceControl"
1119 }
1120
1121 fn is_critical(&self) -> bool {
1122 false
1123 }
1124
1125 fn priority(&self) -> i32 {
1126 25
1127 }
1128
1129 fn dependencies(&self) -> Vec<&str> {
1130 vec![]
1131 }
1132
1133 fn init(&mut self, _ctx: &mut crate::core::DMSCServiceContext) -> crate::core::DMSCResult<()> {
1134 Ok(())
1135 }
1136
1137 fn start(&mut self, _ctx: &mut crate::core::DMSCServiceContext) -> crate::core::DMSCResult<()> {
1138 Ok(())
1139 }
1140
1141 fn shutdown(&mut self, _ctx: &mut crate::core::DMSCServiceContext) -> crate::core::DMSCResult<()> {
1142 Ok(())
1143 }
1144}
1145
1146fn parse_device_config(config_str: Option<&String>) -> crate::device::core::DMSCDeviceControlConfig {
1147 match config_str {
1148 Some(config) => {
1149 let trimmed = config.trim();
1150 if trimmed.starts_with('{') {
1151 if let Ok(result) = serde_json::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed) {
1152 return result;
1153 }
1154 }
1155 if trimmed.starts_with("---") || trimmed.contains("discovery_enabled:") {
1156 if let Ok(result) = serde_yaml::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed) {
1157 return result;
1158 }
1159 }
1160 if trimmed.contains('[') || trimmed.contains("discovery_enabled") {
1161 if let Ok(result) = toml::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed) {
1162 return result;
1163 }
1164 }
1165 serde_json::from_str::<crate::device::core::DMSCDeviceControlConfig>(trimmed)
1166 .unwrap_or_default()
1167 }
1168 None => crate::device::core::DMSCDeviceControlConfig::default(),
1169 }
1170}