361 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			361 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| fn main() {
 | |
|     // Create topologies
 | |
|     let okd_topology = OKDHaClusterTopology::new();
 | |
|     let k3d_topology = K3DTopology::new();
 | |
|     let linux_topology = LinuxTopology::new();
 | |
| 
 | |
|     // Create scores - boxing them as trait objects for dynamic dispatch
 | |
|     let scores: Vec<Box<dyn Score>> = vec![
 | |
|         Box::new(LAMPScore::new("MySQL 8.0", "PHP 8.1", "Apache 2.4")),
 | |
|         Box::new(BinaryScore::new("https://example.com/binary", vec!["--arg1", "--arg2"])),
 | |
|         Box::new(LoadBalancerScore::new(vec!["service1", "service2"], 80)),
 | |
|     ];
 | |
| 
 | |
|     // Running scores on OKD topology (which has all capabilities)
 | |
|     println!("\n=== Running all scores on OKD HA Cluster ===");
 | |
|     for score in &scores {
 | |
|         match score.execute(&okd_topology) {
 | |
|             Ok(result) => println!("Score executed successfully: {}", result),
 | |
|             Err(e) => println!("Failed to execute score: {}", e),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Running scores on K3D topology (only has K8s capability)
 | |
|     println!("\n=== Running scores on K3D Cluster ===");
 | |
|     for score in &scores {
 | |
|         match score.execute(&k3d_topology) {
 | |
|             Ok(result) => println!("Score executed successfully: {}", result),
 | |
|             Err(e) => println!("Failed to execute score: {}", e),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Running scores on Linux topology (only has Linux capability)
 | |
|     println!("\n=== Running scores on Linux Host ===");
 | |
|     for score in &scores {
 | |
|         match score.execute(&linux_topology) {
 | |
|             Ok(result) => println!("Score executed successfully: {}", result),
 | |
|             Err(e) => println!("Failed to execute score: {}", e),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Base Topology trait
 | |
| trait Topology: Any {
 | |
|     fn name(&self) -> &str;
 | |
|     
 | |
|     // This method allows us to get type information at runtime
 | |
|     fn as_any(&self) -> &dyn Any;
 | |
| }
 | |
| 
 | |
| // Use Any trait for runtime type checking
 | |
| use std::any::Any;
 | |
| 
 | |
| // Define capabilities
 | |
| trait K8sCapability {
 | |
|     fn deploy_k8s_resource(&self, resource_yaml: &str);
 | |
|     fn execute_kubectl(&self, command: &str) -> String;
 | |
| }
 | |
| 
 | |
| trait OKDCapability: K8sCapability {
 | |
|     fn execute_oc(&self, command: &str) -> String;
 | |
| }
 | |
| 
 | |
| trait LinuxCapability {
 | |
|     fn execute_command(&self, command: &str, args: &[&str]);
 | |
|     fn download_file(&self, url: &str, destination: &str) -> Result<(), String>;
 | |
| }
 | |
| 
 | |
| trait LoadBalancerCapability {
 | |
|     fn configure_load_balancer(&self, services: &[&str], port: u16);
 | |
|     fn get_load_balancer_status(&self) -> String;
 | |
| }
 | |
| 
 | |
| // Base Score trait with dynamic dispatch
 | |
| trait Score {
 | |
|     // Generic execute method that takes any topology
 | |
|     fn execute(&self, topology: &dyn Topology) -> Result<String, String>;
 | |
|     
 | |
|     // Optional method to get score type for better error messages
 | |
|     fn score_type(&self) -> &str;
 | |
| }
 | |
| 
 | |
| // Topology implementations
 | |
| struct OKDHaClusterTopology {
 | |
|     cluster_name: String,
 | |
| }
 | |
| 
 | |
| impl OKDHaClusterTopology {
 | |
|     fn new() -> Self {
 | |
|         Self { cluster_name: "okd-ha-cluster".to_string() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Topology for OKDHaClusterTopology {
 | |
|     fn name(&self) -> &str {
 | |
|         &self.cluster_name
 | |
|     }
 | |
|     
 | |
|     fn as_any(&self) -> &dyn Any {
 | |
|         self
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl K8sCapability for OKDHaClusterTopology {
 | |
|     fn deploy_k8s_resource(&self, resource_yaml: &str) {
 | |
|         println!("Deploying K8s resource on OKD cluster: {}", resource_yaml);
 | |
|     }
 | |
|     
 | |
|     fn execute_kubectl(&self, command: &str) -> String {
 | |
|         println!("Executing kubectl command on OKD cluster: {}", command);
 | |
|         "kubectl command output".to_string()
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl OKDCapability for OKDHaClusterTopology {
 | |
|     fn execute_oc(&self, command: &str) -> String {
 | |
|         println!("Executing oc command on OKD cluster: {}", command);
 | |
|         "oc command output".to_string()
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl LinuxCapability for OKDHaClusterTopology {
 | |
|     fn execute_command(&self, command: &str, args: &[&str]) {
 | |
|         println!("Executing command '{}' with args {:?} on OKD node", command, args);
 | |
|     }
 | |
|     
 | |
|     fn download_file(&self, url: &str, destination: &str) -> Result<(), String> {
 | |
|         println!("Downloading file from {} to {} on OKD node", url, destination);
 | |
|         Ok(())
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl LoadBalancerCapability for OKDHaClusterTopology {
 | |
|     fn configure_load_balancer(&self, services: &[&str], port: u16) {
 | |
|         println!("Configuring load balancer for services {:?} on port {} in OKD", services, port);
 | |
|     }
 | |
|     
 | |
|     fn get_load_balancer_status(&self) -> String {
 | |
|         "OKD Load Balancer: HEALTHY".to_string()
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct K3DTopology {
 | |
|     cluster_name: String,
 | |
| }
 | |
| 
 | |
| impl K3DTopology {
 | |
|     fn new() -> Self {
 | |
|         Self { cluster_name: "k3d-local".to_string() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Topology for K3DTopology {
 | |
|     fn name(&self) -> &str {
 | |
|         &self.cluster_name
 | |
|     }
 | |
|     
 | |
|     fn as_any(&self) -> &dyn Any {
 | |
|         self
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl K8sCapability for K3DTopology {
 | |
|     fn deploy_k8s_resource(&self, resource_yaml: &str) {
 | |
|         println!("Deploying K8s resource on K3D cluster: {}", resource_yaml);
 | |
|     }
 | |
|     
 | |
|     fn execute_kubectl(&self, command: &str) -> String {
 | |
|         println!("Executing kubectl command on K3D cluster: {}", command);
 | |
|         "kubectl command output from K3D".to_string()
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct LinuxTopology {
 | |
|     hostname: String,
 | |
| }
 | |
| 
 | |
| impl LinuxTopology {
 | |
|     fn new() -> Self {
 | |
|         Self { hostname: "linux-host".to_string() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Topology for LinuxTopology {
 | |
|     fn name(&self) -> &str {
 | |
|         &self.hostname
 | |
|     }
 | |
|     
 | |
|     fn as_any(&self) -> &dyn Any {
 | |
|         self
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl LinuxCapability for LinuxTopology {
 | |
|     fn execute_command(&self, command: &str, args: &[&str]) {
 | |
|         println!("Executing command '{}' with args {:?} on Linux host", command, args);
 | |
|     }
 | |
|     
 | |
|     fn download_file(&self, url: &str, destination: &str) -> Result<(), String> {
 | |
|         println!("Downloading file from {} to {} on Linux host", url, destination);
 | |
|         Ok(())
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Score implementations using dynamic capability checks
 | |
| struct LAMPScore {
 | |
|     mysql_version: String,
 | |
|     php_version: String,
 | |
|     apache_version: String,
 | |
| }
 | |
| 
 | |
| impl LAMPScore {
 | |
|     fn new(mysql_version: &str, php_version: &str, apache_version: &str) -> Self {
 | |
|         Self {
 | |
|             mysql_version: mysql_version.to_string(),
 | |
|             php_version: php_version.to_string(),
 | |
|             apache_version: apache_version.to_string(),
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     // Helper method for typesafe execution
 | |
|     fn execute_with_k8s(&self, topology: &dyn K8sCapability) -> String {
 | |
|         println!("Deploying LAMP stack with MySQL {}, PHP {}, Apache {}",
 | |
|                  self.mysql_version, self.php_version, self.apache_version);
 | |
|         
 | |
|         // Deploy MySQL
 | |
|         topology.deploy_k8s_resource("mysql-deployment.yaml");
 | |
|         
 | |
|         // Deploy PHP
 | |
|         topology.deploy_k8s_resource("php-deployment.yaml");
 | |
|         
 | |
|         // Deploy Apache
 | |
|         topology.deploy_k8s_resource("apache-deployment.yaml");
 | |
|         
 | |
|         // Create service
 | |
|         topology.deploy_k8s_resource("lamp-service.yaml");
 | |
|         
 | |
|         // Check deployment
 | |
|         let status = topology.execute_kubectl("get pods -l app=lamp");
 | |
|         format!("LAMP deployment status: {}", status)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Score for LAMPScore {
 | |
|     fn execute(&self, topology: &dyn Topology) -> Result<String, String> {
 | |
|         // Try to downcast to K8sCapability
 | |
|         if let Some(k8s_topology) = topology.as_any().downcast_ref::<OKDHaClusterTopology>() {
 | |
|             Ok(self.execute_with_k8s(k8s_topology))
 | |
|         } else if let Some(k8s_topology) = topology.as_any().downcast_ref::<K3DTopology>() {
 | |
|             Ok(self.execute_with_k8s(k8s_topology))
 | |
|         } else {
 | |
|             Err(format!("LAMPScore requires K8sCapability but topology {} doesn't provide it", 
 | |
|                         topology.name()))
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     fn score_type(&self) -> &str {
 | |
|         "LAMP"
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct BinaryScore {
 | |
|     url: String,
 | |
|     args: Vec<String>,
 | |
| }
 | |
| 
 | |
| impl BinaryScore {
 | |
|     fn new(url: &str, args: Vec<&str>) -> Self {
 | |
|         Self {
 | |
|             url: url.to_string(),
 | |
|             args: args.iter().map(|s| s.to_string()).collect(),
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     // Helper method for typesafe execution
 | |
|     fn execute_with_linux(&self, topology: &dyn LinuxCapability) -> Result<String, String> {
 | |
|         let destination = "/tmp/binary";
 | |
|         
 | |
|         // Download the binary
 | |
|         println!("Preparing to run binary from {}", self.url);
 | |
|         
 | |
|         match topology.download_file(&self.url, destination) {
 | |
|             Ok(_) => {
 | |
|                 println!("Binary downloaded successfully");
 | |
|                 
 | |
|                 // Convert args to slice of &str
 | |
|                 let args: Vec<&str> = self.args.iter().map(|s| s.as_str()).collect();
 | |
|                 
 | |
|                 // Execute the binary
 | |
|                 topology.execute_command(destination, &args);
 | |
|                 Ok("Binary execution completed successfully".to_string())
 | |
|             },
 | |
|             Err(e) => {
 | |
|                 Err(format!("Failed to download binary: {}", e))
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Score for BinaryScore {
 | |
|     fn execute(&self, topology: &dyn Topology) -> Result<String, String> {
 | |
|         // Try to downcast to LinuxCapability
 | |
|         if let Some(linux_topology) = topology.as_any().downcast_ref::<OKDHaClusterTopology>() {
 | |
|             self.execute_with_linux(linux_topology)
 | |
|         } else if let Some(linux_topology) = topology.as_any().downcast_ref::<LinuxTopology>() {
 | |
|             self.execute_with_linux(linux_topology)
 | |
|         } else {
 | |
|             Err(format!("BinaryScore requires LinuxCapability but topology {} doesn't provide it", 
 | |
|                         topology.name()))
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     fn score_type(&self) -> &str {
 | |
|         "Binary"
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct LoadBalancerScore {
 | |
|     services: Vec<String>,
 | |
|     port: u16,
 | |
| }
 | |
| 
 | |
| impl LoadBalancerScore {
 | |
|     fn new(services: Vec<&str>, port: u16) -> Self {
 | |
|         Self {
 | |
|             services: services.iter().map(|s| s.to_string()).collect(),
 | |
|             port,
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     // Helper method for typesafe execution
 | |
|     fn execute_with_lb(&self, topology: &dyn LoadBalancerCapability) -> String {
 | |
|         println!("Configuring load balancer for services");
 | |
|         
 | |
|         // Convert services to slice of &str
 | |
|         let services: Vec<&str> = self.services.iter().map(|s| s.as_str()).collect();
 | |
|         
 | |
|         // Configure load balancer
 | |
|         topology.configure_load_balancer(&services, self.port);
 | |
|         
 | |
|         // Check status
 | |
|         let status = topology.get_load_balancer_status();
 | |
|         format!("Load balancer configured successfully. Status: {}", status)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Score for LoadBalancerScore {
 | |
|     fn execute(&self, topology: &dyn Topology) -> Result<String, String> {
 | |
|         // Only OKDHaClusterTopology implements LoadBalancerCapability
 | |
|         if let Some(lb_topology) = topology.as_any().downcast_ref::<OKDHaClusterTopology>() {
 | |
|             Ok(self.execute_with_lb(lb_topology))
 | |
|         } else {
 | |
|             Err(format!("LoadBalancerScore requires LoadBalancerCapability but topology {} doesn't provide it", 
 | |
|                         topology.name()))
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     fn score_type(&self) -> &str {
 | |
|         "LoadBalancer"
 | |
|     }
 | |
| }
 |