feat: add slice calculator integration and marketplace SLA for grid nodes
This commit is contained in:
@@ -1301,25 +1301,83 @@ impl ResourceProviderService {
|
|||||||
// Fetch node data from grid
|
// Fetch node data from grid
|
||||||
let grid_data = self.grid_service.fetch_node_data(grid_node_id).await?;
|
let grid_data = self.grid_service.fetch_node_data(grid_node_id).await?;
|
||||||
|
|
||||||
// Create FarmNode from grid data
|
// FIX: Calculate slice data using the slice calculator
|
||||||
let node = FarmNodeBuilder::new()
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&grid_data.total_resources);
|
||||||
.id(format!("grid_node_{}", grid_node_id))
|
|
||||||
.name(format!("Grid Node {}", grid_node_id))
|
// Generate unique node ID for SLA
|
||||||
.location(format!("{}, {}",
|
let node_id = format!("grid_node_{}", grid_node_id);
|
||||||
if grid_data.city.is_empty() { "Unknown City" } else { &grid_data.city },
|
let node_id_for_sla = node_id.clone();
|
||||||
if grid_data.country.is_empty() { "Unknown Country" } else { &grid_data.country }
|
|
||||||
))
|
// Create FarmNode from grid data with proper slice calculations
|
||||||
.status(NodeStatus::Online)
|
let mut node = FarmNode {
|
||||||
.capacity(grid_data.total_resources.clone())
|
id: node_id,
|
||||||
.used_capacity(grid_data.used_resources.clone())
|
name: if grid_data.farm_name.is_empty() { format!("Grid Node {}", grid_node_id) } else { grid_data.farm_name.clone() },
|
||||||
.uptime_percentage(99.0) // Default uptime
|
location: {
|
||||||
.earnings_today_usd(Decimal::ZERO)
|
let city = if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city };
|
||||||
.health_score(100.0)
|
let country = if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country };
|
||||||
.region(if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() })
|
if city == "Unknown" {
|
||||||
.node_type("MyceliumNode".to_string())
|
country.to_string()
|
||||||
.grid_node_id(grid_node_id)
|
} else {
|
||||||
.grid_data(grid_data)
|
format!("{}, {}", city, country)
|
||||||
.build()?;
|
}
|
||||||
|
},
|
||||||
|
status: NodeStatus::Online, // Assume online if we can fetch from grid
|
||||||
|
capacity: grid_data.total_resources.clone(),
|
||||||
|
used_capacity: grid_data.used_resources.clone(),
|
||||||
|
uptime_percentage: 99.8, // Clean uptime value for grid nodes
|
||||||
|
farming_start_date: Utc::now() - chrono::Duration::days(30), // Default farming start
|
||||||
|
last_updated: grid_data.last_updated,
|
||||||
|
last_seen: Some(Utc::now()),
|
||||||
|
health_score: 98.5,
|
||||||
|
utilization_7_day_avg: 65.0, // Default utilization
|
||||||
|
slice_formats_supported: vec!["1x1".to_string(), "2x2".to_string(), "4x4".to_string()],
|
||||||
|
rental_options: None,
|
||||||
|
earnings_today_usd: Decimal::ZERO,
|
||||||
|
region: if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() },
|
||||||
|
node_type: "MyceliumNode".to_string(),
|
||||||
|
slice_formats: None, // Not used in new slice system
|
||||||
|
staking_options: None,
|
||||||
|
availability_status: crate::models::user::NodeAvailabilityStatus::Available,
|
||||||
|
grid_node_id: Some(grid_node_id.to_string()),
|
||||||
|
grid_data: Some(serde_json::to_value(&grid_data).unwrap_or_default()),
|
||||||
|
node_group_id: None,
|
||||||
|
group_assignment_date: None,
|
||||||
|
group_slice_format: None,
|
||||||
|
group_slice_price: None,
|
||||||
|
|
||||||
|
// FIX: Marketplace SLA field with clean uptime value
|
||||||
|
marketplace_sla: Some(MarketplaceSLA {
|
||||||
|
id: format!("sla-{}", node_id_for_sla),
|
||||||
|
name: "Standard Marketplace SLA".to_string(),
|
||||||
|
uptime_guarantee: 99.8,
|
||||||
|
response_time_hours: 24,
|
||||||
|
resolution_time_hours: 48,
|
||||||
|
penalty_rate: 0.01,
|
||||||
|
uptime_guarantee_percentage: 99.8,
|
||||||
|
bandwidth_guarantee_mbps: grid_data.total_resources.bandwidth_mbps as f32,
|
||||||
|
base_slice_price: SlicePricing::default().base_price_per_hour,
|
||||||
|
last_updated: Utc::now(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// FIX: Automatic slice management fields
|
||||||
|
total_base_slices: total_base_slices as i32,
|
||||||
|
allocated_base_slices: 0,
|
||||||
|
slice_allocations: Vec::new(),
|
||||||
|
available_combinations: Vec::new(), // Will be calculated below
|
||||||
|
slice_pricing: Some(serde_json::to_value(&SlicePricing::default()).unwrap_or_default()),
|
||||||
|
slice_last_calculated: Some(Utc::now()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIX: Generate initial slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
node.total_base_slices as u32,
|
||||||
|
node.allocated_base_slices as u32,
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Save to persistent storage
|
// Save to persistent storage
|
||||||
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||||
@@ -1356,26 +1414,82 @@ impl ResourceProviderService {
|
|||||||
}
|
}
|
||||||
let grid_data = self.grid_service.fetch_node_data(grid_node_id).await.map_err(|e| e.to_string())?;
|
let grid_data = self.grid_service.fetch_node_data(grid_node_id).await.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Build node
|
// FIX: Calculate slice data using the slice calculator (same as add_node_from_grid)
|
||||||
let node = FarmNodeBuilder::new()
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&grid_data.total_resources);
|
||||||
.id(node_id)
|
|
||||||
.name(format!("Grid Node {}", grid_node_id))
|
// Generate unique node ID for SLA
|
||||||
.location(format!("{}, {}",
|
let node_id_for_sla = node_id.clone();
|
||||||
if grid_data.city.is_empty() { "Unknown City" } else { &grid_data.city },
|
|
||||||
if grid_data.country.is_empty() { "Unknown Country" } else { &grid_data.country }
|
// Build node with proper slice calculations
|
||||||
))
|
let mut node = FarmNode {
|
||||||
.status(NodeStatus::Online)
|
id: node_id,
|
||||||
.capacity(grid_data.total_resources.clone())
|
name: if grid_data.farm_name.is_empty() { format!("Grid Node {}", grid_node_id) } else { grid_data.farm_name.clone() },
|
||||||
.used_capacity(grid_data.used_resources.clone())
|
location: {
|
||||||
.uptime_percentage(99.0)
|
let city = if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city };
|
||||||
.earnings_today_usd(Decimal::ZERO)
|
let country = if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country };
|
||||||
.health_score(100.0)
|
if city == "Unknown" {
|
||||||
.region(if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() })
|
country.to_string()
|
||||||
.node_type("MyceliumNode".to_string())
|
} else {
|
||||||
.grid_node_id(grid_node_id)
|
format!("{}, {}", city, country)
|
||||||
.grid_data(grid_data)
|
}
|
||||||
.build()
|
},
|
||||||
.map_err(|e| e.to_string())?;
|
status: NodeStatus::Online, // Assume online if we can fetch from grid
|
||||||
|
capacity: grid_data.total_resources.clone(),
|
||||||
|
used_capacity: grid_data.used_resources.clone(),
|
||||||
|
uptime_percentage: 99.8, // Clean uptime value for grid nodes
|
||||||
|
farming_start_date: Utc::now() - chrono::Duration::days(30), // Default farming start
|
||||||
|
last_updated: grid_data.last_updated,
|
||||||
|
last_seen: Some(Utc::now()),
|
||||||
|
health_score: 98.5,
|
||||||
|
utilization_7_day_avg: 65.0, // Default utilization
|
||||||
|
slice_formats_supported: vec!["1x1".to_string(), "2x2".to_string(), "4x4".to_string()],
|
||||||
|
rental_options: None,
|
||||||
|
earnings_today_usd: Decimal::ZERO,
|
||||||
|
region: if grid_data.country.is_empty() { "Unknown".to_string() } else { grid_data.country.clone() },
|
||||||
|
node_type: "MyceliumNode".to_string(),
|
||||||
|
slice_formats: None, // Not used in new slice system
|
||||||
|
staking_options: None,
|
||||||
|
availability_status: crate::models::user::NodeAvailabilityStatus::Available,
|
||||||
|
grid_node_id: Some(grid_node_id.to_string()),
|
||||||
|
grid_data: Some(serde_json::to_value(&grid_data).unwrap_or_default()),
|
||||||
|
node_group_id: None,
|
||||||
|
group_assignment_date: None,
|
||||||
|
group_slice_format: None,
|
||||||
|
group_slice_price: None,
|
||||||
|
|
||||||
|
// FIX: Marketplace SLA field with clean uptime value
|
||||||
|
marketplace_sla: Some(MarketplaceSLA {
|
||||||
|
id: format!("sla-{}", node_id_for_sla),
|
||||||
|
name: "Standard Marketplace SLA".to_string(),
|
||||||
|
uptime_guarantee: 99.8,
|
||||||
|
response_time_hours: 24,
|
||||||
|
resolution_time_hours: 48,
|
||||||
|
penalty_rate: 0.01,
|
||||||
|
uptime_guarantee_percentage: 99.8,
|
||||||
|
bandwidth_guarantee_mbps: grid_data.total_resources.bandwidth_mbps as f32,
|
||||||
|
base_slice_price: SlicePricing::default().base_price_per_hour,
|
||||||
|
last_updated: Utc::now(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// FIX: Automatic slice management fields
|
||||||
|
total_base_slices: total_base_slices as i32,
|
||||||
|
allocated_base_slices: 0,
|
||||||
|
slice_allocations: Vec::new(),
|
||||||
|
available_combinations: Vec::new(), // Will be calculated below
|
||||||
|
slice_pricing: Some(serde_json::to_value(&SlicePricing::default()).unwrap_or_default()),
|
||||||
|
slice_last_calculated: Some(Utc::now()),
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIX: Generate initial slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
node.total_base_slices as u32,
|
||||||
|
node.allocated_base_slices as u32,
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
|
||||||
persistent_data.nodes.push(node.clone());
|
persistent_data.nodes.push(node.clone());
|
||||||
added_nodes.push(node);
|
added_nodes.push(node);
|
||||||
@@ -1472,6 +1586,50 @@ impl ResourceProviderService {
|
|||||||
// Apply slice formats if provided
|
// Apply slice formats if provided
|
||||||
if !slice_formats.is_empty() { node.slice_formats = Some(slice_formats.clone()); }
|
if !slice_formats.is_empty() { node.slice_formats = Some(slice_formats.clone()); }
|
||||||
|
|
||||||
|
// FIX: Calculate and set slice data
|
||||||
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity);
|
||||||
|
node.total_base_slices = total_base_slices as i32;
|
||||||
|
node.allocated_base_slices = 0;
|
||||||
|
node.slice_allocations = Vec::new();
|
||||||
|
|
||||||
|
// Generate slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
total_base_slices,
|
||||||
|
0, // No allocated slices yet
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
node.slice_last_calculated = Some(Utc::now());
|
||||||
|
|
||||||
|
// Set marketplace SLA if not already set
|
||||||
|
if node.marketplace_sla.is_none() {
|
||||||
|
node.marketplace_sla = Some(MarketplaceSLA {
|
||||||
|
id: format!("sla-{}", node.id),
|
||||||
|
name: "Standard Marketplace SLA".to_string(),
|
||||||
|
uptime_guarantee: 99.8,
|
||||||
|
response_time_hours: 24,
|
||||||
|
resolution_time_hours: 48,
|
||||||
|
penalty_rate: 0.01,
|
||||||
|
uptime_guarantee_percentage: 99.8,
|
||||||
|
bandwidth_guarantee_mbps: node.capacity.bandwidth_mbps as f32,
|
||||||
|
base_slice_price: SlicePricing::default().base_price_per_hour,
|
||||||
|
last_updated: Utc::now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default slice pricing if not already set
|
||||||
|
if node.slice_pricing.is_none() {
|
||||||
|
let default_pricing = SlicePricing {
|
||||||
|
base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(),
|
||||||
|
currency: "USD".to_string(),
|
||||||
|
pricing_multiplier: rust_decimal::Decimal::from(1),
|
||||||
|
};
|
||||||
|
node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default());
|
||||||
|
}
|
||||||
|
|
||||||
persistent_data.nodes.push(node.clone());
|
persistent_data.nodes.push(node.clone());
|
||||||
added_nodes.push(node);
|
added_nodes.push(node);
|
||||||
}
|
}
|
||||||
@@ -1554,6 +1712,34 @@ impl ResourceProviderService {
|
|||||||
node.slice_formats = Some(slice_formats.clone());
|
node.slice_formats = Some(slice_formats.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SLICE CALCULATION FIX: Calculate and set slice data
|
||||||
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity);
|
||||||
|
node.total_base_slices = total_base_slices as i32;
|
||||||
|
node.allocated_base_slices = 0;
|
||||||
|
node.slice_allocations = Vec::new();
|
||||||
|
|
||||||
|
// Generate slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
total_base_slices,
|
||||||
|
0, // No allocated slices yet
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
node.slice_last_calculated = Some(Utc::now());
|
||||||
|
|
||||||
|
// Set default slice pricing if not already set
|
||||||
|
if node.slice_pricing.is_none() {
|
||||||
|
let default_pricing = crate::services::slice_calculator::SlicePricing {
|
||||||
|
base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(),
|
||||||
|
currency: "USD".to_string(),
|
||||||
|
pricing_multiplier: rust_decimal::Decimal::from(1),
|
||||||
|
};
|
||||||
|
node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default());
|
||||||
|
}
|
||||||
|
|
||||||
// Push to in-memory and batch list
|
// Push to in-memory and batch list
|
||||||
persistent_data.nodes.push(node.clone());
|
persistent_data.nodes.push(node.clone());
|
||||||
added_nodes.push(node);
|
added_nodes.push(node);
|
||||||
@@ -1654,6 +1840,34 @@ impl ResourceProviderService {
|
|||||||
node.slice_formats = Some(slice_formats.clone());
|
node.slice_formats = Some(slice_formats.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SLICE CALCULATION FIX: Calculate and set slice data for individual pricing method
|
||||||
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity);
|
||||||
|
node.total_base_slices = total_base_slices as i32;
|
||||||
|
node.allocated_base_slices = 0;
|
||||||
|
node.slice_allocations = Vec::new();
|
||||||
|
|
||||||
|
// Generate slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
total_base_slices,
|
||||||
|
0, // No allocated slices yet
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
node.slice_last_calculated = Some(Utc::now());
|
||||||
|
|
||||||
|
// Set default slice pricing if not already set
|
||||||
|
if node.slice_pricing.is_none() {
|
||||||
|
let default_pricing = crate::services::slice_calculator::SlicePricing {
|
||||||
|
base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(),
|
||||||
|
currency: "USD".to_string(),
|
||||||
|
pricing_multiplier: rust_decimal::Decimal::from(1),
|
||||||
|
};
|
||||||
|
node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default());
|
||||||
|
}
|
||||||
|
|
||||||
persistent_data.nodes.push(node.clone());
|
persistent_data.nodes.push(node.clone());
|
||||||
added_nodes.push(node);
|
added_nodes.push(node);
|
||||||
}
|
}
|
||||||
@@ -1721,6 +1935,50 @@ impl ResourceProviderService {
|
|||||||
node.slice_formats = Some(slice_formats);
|
node.slice_formats = Some(slice_formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIX: Calculate and set slice data
|
||||||
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node.capacity);
|
||||||
|
node.total_base_slices = total_base_slices as i32;
|
||||||
|
node.allocated_base_slices = 0;
|
||||||
|
node.slice_allocations = Vec::new();
|
||||||
|
|
||||||
|
// Generate slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
total_base_slices,
|
||||||
|
0, // No allocated slices yet
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
node.slice_last_calculated = Some(Utc::now());
|
||||||
|
|
||||||
|
// Set marketplace SLA if not already set
|
||||||
|
if node.marketplace_sla.is_none() {
|
||||||
|
node.marketplace_sla = Some(MarketplaceSLA {
|
||||||
|
id: format!("sla-{}", node.id),
|
||||||
|
name: "Standard Marketplace SLA".to_string(),
|
||||||
|
uptime_guarantee: 99.8,
|
||||||
|
response_time_hours: 24,
|
||||||
|
resolution_time_hours: 48,
|
||||||
|
penalty_rate: 0.01,
|
||||||
|
uptime_guarantee_percentage: 99.8,
|
||||||
|
bandwidth_guarantee_mbps: node.capacity.bandwidth_mbps as f32,
|
||||||
|
base_slice_price: SlicePricing::default().base_price_per_hour,
|
||||||
|
last_updated: Utc::now(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default slice pricing if not already set
|
||||||
|
if node.slice_pricing.is_none() {
|
||||||
|
let default_pricing = SlicePricing {
|
||||||
|
base_price_per_hour: rust_decimal::Decimal::try_from(0.50).unwrap_or_default(),
|
||||||
|
currency: "USD".to_string(),
|
||||||
|
pricing_multiplier: rust_decimal::Decimal::from(1),
|
||||||
|
};
|
||||||
|
node.slice_pricing = Some(serde_json::to_value(&default_pricing).unwrap_or_default());
|
||||||
|
}
|
||||||
|
|
||||||
// Add node to user's data
|
// Add node to user's data
|
||||||
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||||
|
|
||||||
@@ -1767,41 +2025,53 @@ impl ResourceProviderService {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the node
|
// FIX: Calculate slice data using the slice calculator
|
||||||
let node = FarmNode {
|
let node_capacity = crate::models::user::NodeCapacity {
|
||||||
id: format!("grid_node_{}", grid_node_id),
|
cpu_cores: grid_data.total_resources.cpu_cores,
|
||||||
name: format!("Grid Node {}", grid_node_id),
|
memory_gb: grid_data.total_resources.memory_gb,
|
||||||
location: format!("{}, {}",
|
storage_gb: grid_data.total_resources.storage_gb,
|
||||||
if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city },
|
bandwidth_mbps: grid_data.total_resources.bandwidth_mbps,
|
||||||
if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }
|
ssd_storage_gb: grid_data.total_resources.ssd_storage_gb,
|
||||||
),
|
hdd_storage_gb: grid_data.total_resources.hdd_storage_gb,
|
||||||
|
ram_gb: grid_data.total_resources.ram_gb,
|
||||||
|
};
|
||||||
|
|
||||||
|
let total_base_slices = self.slice_calculator.calculate_max_base_slices(&node_capacity);
|
||||||
|
let node_id = format!("grid_node_{}", grid_node_id);
|
||||||
|
let bandwidth_mbps = node_capacity.bandwidth_mbps; // Store before move
|
||||||
|
|
||||||
|
// Create the node with proper slice calculations
|
||||||
|
let mut node = FarmNode {
|
||||||
|
id: node_id.clone(),
|
||||||
|
name: if grid_data.farm_name.is_empty() { format!("Grid Node {}", grid_node_id) } else { grid_data.farm_name.clone() },
|
||||||
|
location: {
|
||||||
|
let city = if grid_data.city.is_empty() { "Unknown" } else { &grid_data.city };
|
||||||
|
let country = if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country };
|
||||||
|
if city == "Unknown" {
|
||||||
|
country.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}, {}", city, country)
|
||||||
|
}
|
||||||
|
},
|
||||||
status: crate::models::user::NodeStatus::Online,
|
status: crate::models::user::NodeStatus::Online,
|
||||||
capacity: crate::models::user::NodeCapacity {
|
capacity: node_capacity,
|
||||||
cpu_cores: grid_data.total_resources.cpu_cores,
|
|
||||||
memory_gb: grid_data.total_resources.memory_gb,
|
|
||||||
storage_gb: grid_data.total_resources.storage_gb,
|
|
||||||
bandwidth_mbps: grid_data.total_resources.bandwidth_mbps,
|
|
||||||
ssd_storage_gb: grid_data.total_resources.ssd_storage_gb,
|
|
||||||
hdd_storage_gb: grid_data.total_resources.hdd_storage_gb,
|
|
||||||
ram_gb: grid_data.total_resources.ram_gb,
|
|
||||||
},
|
|
||||||
used_capacity: crate::models::user::NodeCapacity {
|
used_capacity: crate::models::user::NodeCapacity {
|
||||||
cpu_cores: 0,
|
cpu_cores: grid_data.used_resources.cpu_cores,
|
||||||
memory_gb: 0,
|
memory_gb: grid_data.used_resources.memory_gb,
|
||||||
storage_gb: 0,
|
storage_gb: grid_data.used_resources.storage_gb,
|
||||||
bandwidth_mbps: 0,
|
bandwidth_mbps: grid_data.used_resources.bandwidth_mbps,
|
||||||
ssd_storage_gb: 0,
|
ssd_storage_gb: grid_data.used_resources.ssd_storage_gb,
|
||||||
hdd_storage_gb: 0,
|
hdd_storage_gb: grid_data.used_resources.hdd_storage_gb,
|
||||||
ram_gb: 0,
|
ram_gb: grid_data.used_resources.ram_gb,
|
||||||
},
|
},
|
||||||
uptime_percentage: 99.0,
|
uptime_percentage: 99.8, // Clean uptime value for grid nodes
|
||||||
farming_start_date: grid_data.last_updated,
|
farming_start_date: grid_data.last_updated,
|
||||||
last_updated: grid_data.last_updated,
|
last_updated: grid_data.last_updated,
|
||||||
utilization_7_day_avg: 0.0,
|
utilization_7_day_avg: 65.0, // Default utilization
|
||||||
slice_formats_supported: if slice_formats.is_empty() { Vec::new() } else { slice_formats.clone() },
|
slice_formats_supported: if slice_formats.is_empty() { vec!["1x1".to_string(), "2x2".to_string(), "4x4".to_string()] } else { slice_formats.clone() },
|
||||||
earnings_today_usd: Decimal::ZERO,
|
earnings_today_usd: Decimal::ZERO,
|
||||||
last_seen: Some(Utc::now()),
|
last_seen: Some(Utc::now()),
|
||||||
health_score: 100.0,
|
health_score: 98.5,
|
||||||
region: if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }.to_string(),
|
region: if grid_data.country.is_empty() { "Unknown" } else { &grid_data.country }.to_string(),
|
||||||
node_type: "MyceliumNode".to_string(),
|
node_type: "MyceliumNode".to_string(),
|
||||||
slice_formats: if slice_formats.is_empty() { None } else { Some(slice_formats.clone()) },
|
slice_formats: if slice_formats.is_empty() { None } else { Some(slice_formats.clone()) },
|
||||||
@@ -1815,17 +2085,40 @@ impl ResourceProviderService {
|
|||||||
group_slice_format: None,
|
group_slice_format: None,
|
||||||
group_slice_price: None,
|
group_slice_price: None,
|
||||||
|
|
||||||
// NEW: Marketplace SLA field (None for basic grid nodes)
|
// FIX: Marketplace SLA field with proper data
|
||||||
marketplace_sla: None,
|
marketplace_sla: Some(MarketplaceSLA {
|
||||||
|
id: format!("sla-{}", node_id),
|
||||||
|
name: "Standard Marketplace SLA".to_string(),
|
||||||
|
uptime_guarantee: 99.8,
|
||||||
|
response_time_hours: 24,
|
||||||
|
resolution_time_hours: 48,
|
||||||
|
penalty_rate: 0.01,
|
||||||
|
uptime_guarantee_percentage: 99.8,
|
||||||
|
bandwidth_guarantee_mbps: bandwidth_mbps as f32,
|
||||||
|
base_slice_price: SlicePricing::default().base_price_per_hour,
|
||||||
|
last_updated: Utc::now(),
|
||||||
|
}),
|
||||||
|
|
||||||
total_base_slices: 0,
|
// FIX: Automatic slice management fields with proper calculations
|
||||||
|
total_base_slices: total_base_slices as i32,
|
||||||
allocated_base_slices: 0,
|
allocated_base_slices: 0,
|
||||||
slice_allocations: Vec::new(),
|
slice_allocations: Vec::new(),
|
||||||
available_combinations: Vec::new(),
|
available_combinations: Vec::new(), // Will be calculated below
|
||||||
slice_pricing: Some(serde_json::to_value(&crate::services::slice_calculator::SlicePricing::default()).unwrap_or_default()),
|
slice_pricing: Some(serde_json::to_value(&SlicePricing::default()).unwrap_or_default()),
|
||||||
slice_last_calculated: None,
|
slice_last_calculated: Some(Utc::now()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIX: Generate initial slice combinations
|
||||||
|
let combinations = self.slice_calculator.generate_slice_combinations(
|
||||||
|
node.total_base_slices as u32,
|
||||||
|
node.allocated_base_slices as u32,
|
||||||
|
&node,
|
||||||
|
user_email
|
||||||
|
);
|
||||||
|
node.available_combinations = combinations.iter()
|
||||||
|
.map(|c| serde_json::to_value(c).unwrap_or_default())
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Save to persistent storage
|
// Save to persistent storage
|
||||||
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
let mut persistent_data = crate::models::builders::SessionDataBuilder::load_or_create(user_email);
|
||||||
|
|
||||||
|
50
src/static/js/dashboard-layout-init.js
Normal file
50
src/static/js/dashboard-layout-init.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Dashboard Layout Initialization - CSP-compliant external script
|
||||||
|
* Handles messaging system initialization and other dashboard-wide functionality
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize messaging system with proper error handling
|
||||||
|
*/
|
||||||
|
function initializeMessagingSystem() {
|
||||||
|
try {
|
||||||
|
// Check if MessagingSystem is available
|
||||||
|
if (typeof MessagingSystem !== 'undefined') {
|
||||||
|
// Create global messaging system instance if it doesn't exist
|
||||||
|
if (!window.messagingSystem) {
|
||||||
|
console.log('🔧 Creating MessagingSystem instance for dashboard');
|
||||||
|
window.messagingSystem = new MessagingSystem();
|
||||||
|
} else {
|
||||||
|
console.log('✅ MessagingSystem already initialized');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ MessagingSystem class not available - messaging features may not work');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Failed to initialize messaging system:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize dashboard layout components
|
||||||
|
*/
|
||||||
|
function initializeDashboard() {
|
||||||
|
// Initialize messaging system
|
||||||
|
initializeMessagingSystem();
|
||||||
|
|
||||||
|
// Add any other dashboard-wide initialization here
|
||||||
|
console.log('✅ Dashboard layout initialized');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize when DOM is ready
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', initializeDashboard);
|
||||||
|
} else {
|
||||||
|
// DOM is already ready
|
||||||
|
initializeDashboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
@@ -224,15 +224,5 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="/static/js/dashboard_layout.js"></script>
|
<script src="/static/js/dashboard_layout.js"></script>
|
||||||
<script src="/static/js/messaging-system.js"></script>
|
<script src="/static/js/messaging-system.js"></script>
|
||||||
<script>
|
<script src="/static/js/dashboard-layout-init.js"></script>
|
||||||
// Dynamic user detection for messaging system
|
|
||||||
try {
|
|
||||||
// Initialize messaging system with dynamic user detection
|
|
||||||
if (window.MessagingSystem) {
|
|
||||||
window.MessagingSystem.initializeWithDynamicUser();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to initialize messaging system:', error);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@@ -303,9 +303,12 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm">
|
||||||
<button class="btn btn-outline-primary" data-action="node.view" data-node-id="{{ node.id }}">
|
<button class="btn btn-outline-primary" onclick="viewNodeDetails('{{ node.id }}')" title="View Details">
|
||||||
<i class="bi bi-eye"></i>
|
<i class="bi bi-eye"></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-outline-danger" onclick="deleteNodeConfiguration('{{ node.id }}')" title="Delete">
|
||||||
|
<i class="bi bi-trash"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@@ -150,6 +150,232 @@
|
|||||||
"group_slice_price": null,
|
"group_slice_price": null,
|
||||||
"last_seen": "2025-09-09T03:03:44.241206636Z",
|
"last_seen": "2025-09-09T03:03:44.241206636Z",
|
||||||
"health_score": 100.0
|
"health_score": 100.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "grid_node_10",
|
||||||
|
"location": "Unknown, Belgium",
|
||||||
|
"status": "Online",
|
||||||
|
"capacity": {
|
||||||
|
"cpu_cores": 8,
|
||||||
|
"memory_gb": 15,
|
||||||
|
"storage_gb": 402559,
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"ssd_storage_gb": 223,
|
||||||
|
"hdd_storage_gb": 402336,
|
||||||
|
"ram_gb": 15
|
||||||
|
},
|
||||||
|
"used_capacity": {
|
||||||
|
"cpu_cores": 4,
|
||||||
|
"memory_gb": 10,
|
||||||
|
"storage_gb": 137,
|
||||||
|
"bandwidth_mbps": 0,
|
||||||
|
"ssd_storage_gb": 137,
|
||||||
|
"hdd_storage_gb": 0,
|
||||||
|
"ram_gb": 10
|
||||||
|
},
|
||||||
|
"uptime_percentage": 99.0,
|
||||||
|
"farming_start_date": "2025-08-10T03:10:19.936729614Z",
|
||||||
|
"last_updated": "2025-09-09T03:10:19.936733378Z",
|
||||||
|
"utilization_7_day_avg": 65.0,
|
||||||
|
"slice_formats_supported": [
|
||||||
|
"1x1",
|
||||||
|
"2x2",
|
||||||
|
"4x4"
|
||||||
|
],
|
||||||
|
"rental_options": null,
|
||||||
|
"total_base_slices": 0,
|
||||||
|
"allocated_base_slices": 0,
|
||||||
|
"earnings_today_usd": 0.0,
|
||||||
|
"grid_node_id": "10",
|
||||||
|
"available_combinations": [],
|
||||||
|
"slice_allocations": [],
|
||||||
|
"slice_last_calculated": null,
|
||||||
|
"marketplace_sla": {
|
||||||
|
"id": "sla-repair-e3b05c2c-5eb6-4304-93c0-7a9c7348636a",
|
||||||
|
"name": "Repaired Node SLA",
|
||||||
|
"uptime_guarantee": 99.8,
|
||||||
|
"response_time_hours": 24,
|
||||||
|
"resolution_time_hours": 48,
|
||||||
|
"penalty_rate": 0.01,
|
||||||
|
"uptime_guarantee_percentage": 99.8,
|
||||||
|
"base_slice_price": 0.5,
|
||||||
|
"bandwidth_guarantee_mbps": 100.0,
|
||||||
|
"last_updated": "2025-09-09T03:13:53.570999450Z"
|
||||||
|
},
|
||||||
|
"slice_pricing": {
|
||||||
|
"base_price_per_hour": 1.0,
|
||||||
|
"currency": "USD",
|
||||||
|
"pricing_multiplier": 1.0
|
||||||
|
},
|
||||||
|
"grid_data": {
|
||||||
|
"capacity": {
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"cpu_cores": 8,
|
||||||
|
"hdd_storage_gb": 402336,
|
||||||
|
"memory_gb": 15,
|
||||||
|
"ram_gb": 15,
|
||||||
|
"ssd_storage_gb": 223,
|
||||||
|
"storage_gb": 402559
|
||||||
|
},
|
||||||
|
"certification_type": "Diy",
|
||||||
|
"city": "Unknown",
|
||||||
|
"country": "Belgium",
|
||||||
|
"farm_id": 1,
|
||||||
|
"farm_name": "Freefarm",
|
||||||
|
"farming_policy_id": 1,
|
||||||
|
"grid_node_id": 10,
|
||||||
|
"last_updated": "2025-09-09T03:10:19.936676347Z",
|
||||||
|
"location": "Unknown, Belgium",
|
||||||
|
"node_id": 10,
|
||||||
|
"public_ips": [
|
||||||
|
"192.168.1.100"
|
||||||
|
],
|
||||||
|
"status": "Online",
|
||||||
|
"total_resources": {
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"cpu_cores": 8,
|
||||||
|
"hdd_storage_gb": 402336,
|
||||||
|
"memory_gb": 15,
|
||||||
|
"ram_gb": 15,
|
||||||
|
"ssd_storage_gb": 223,
|
||||||
|
"storage_gb": 402559
|
||||||
|
},
|
||||||
|
"uptime": 99.5,
|
||||||
|
"used_resources": {
|
||||||
|
"bandwidth_mbps": 0,
|
||||||
|
"cpu_cores": 4,
|
||||||
|
"hdd_storage_gb": 0,
|
||||||
|
"memory_gb": 10,
|
||||||
|
"ram_gb": 10,
|
||||||
|
"ssd_storage_gb": 137,
|
||||||
|
"storage_gb": 137
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slice_formats": null,
|
||||||
|
"name": "Grid Node 10",
|
||||||
|
"region": "Belgium",
|
||||||
|
"node_type": "MyceliumNode",
|
||||||
|
"staking_options": null,
|
||||||
|
"availability_status": "Available",
|
||||||
|
"node_group_id": null,
|
||||||
|
"group_assignment_date": null,
|
||||||
|
"group_slice_format": null,
|
||||||
|
"group_slice_price": null,
|
||||||
|
"last_seen": "2025-09-09T03:10:19.936736220Z",
|
||||||
|
"health_score": 100.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "grid_node_12",
|
||||||
|
"location": "Unknown, Belgium",
|
||||||
|
"status": "Online",
|
||||||
|
"capacity": {
|
||||||
|
"cpu_cores": 8,
|
||||||
|
"memory_gb": 15,
|
||||||
|
"storage_gb": 402559,
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"ssd_storage_gb": 223,
|
||||||
|
"hdd_storage_gb": 402336,
|
||||||
|
"ram_gb": 15
|
||||||
|
},
|
||||||
|
"used_capacity": {
|
||||||
|
"cpu_cores": 5,
|
||||||
|
"memory_gb": 12,
|
||||||
|
"storage_gb": 165,
|
||||||
|
"bandwidth_mbps": 0,
|
||||||
|
"ssd_storage_gb": 165,
|
||||||
|
"hdd_storage_gb": 0,
|
||||||
|
"ram_gb": 12
|
||||||
|
},
|
||||||
|
"uptime_percentage": 99.0,
|
||||||
|
"farming_start_date": "2025-08-10T03:30:24.732131670Z",
|
||||||
|
"last_updated": "2025-09-09T03:30:24.732143334Z",
|
||||||
|
"utilization_7_day_avg": 65.0,
|
||||||
|
"slice_formats_supported": [
|
||||||
|
"1x1",
|
||||||
|
"2x2",
|
||||||
|
"4x4"
|
||||||
|
],
|
||||||
|
"rental_options": null,
|
||||||
|
"total_base_slices": 0,
|
||||||
|
"allocated_base_slices": 0,
|
||||||
|
"earnings_today_usd": 0.0,
|
||||||
|
"grid_node_id": "12",
|
||||||
|
"available_combinations": [],
|
||||||
|
"slice_allocations": [],
|
||||||
|
"slice_last_calculated": null,
|
||||||
|
"marketplace_sla": {
|
||||||
|
"id": "sla-repair-25c05a40-790f-4a80-8ef8-fa12a726c0ff",
|
||||||
|
"name": "Repaired Node SLA",
|
||||||
|
"uptime_guarantee": 99.8,
|
||||||
|
"response_time_hours": 24,
|
||||||
|
"resolution_time_hours": 48,
|
||||||
|
"penalty_rate": 0.01,
|
||||||
|
"uptime_guarantee_percentage": 99.8,
|
||||||
|
"base_slice_price": 0.5,
|
||||||
|
"bandwidth_guarantee_mbps": 100.0,
|
||||||
|
"last_updated": "2025-09-09T03:30:27.416132016Z"
|
||||||
|
},
|
||||||
|
"slice_pricing": {
|
||||||
|
"base_price_per_hour": 1.0,
|
||||||
|
"currency": "USD",
|
||||||
|
"pricing_multiplier": 1.0
|
||||||
|
},
|
||||||
|
"grid_data": {
|
||||||
|
"capacity": {
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"cpu_cores": 8,
|
||||||
|
"hdd_storage_gb": 402336,
|
||||||
|
"memory_gb": 15,
|
||||||
|
"ram_gb": 15,
|
||||||
|
"ssd_storage_gb": 223,
|
||||||
|
"storage_gb": 402559
|
||||||
|
},
|
||||||
|
"certification_type": "Diy",
|
||||||
|
"city": "Unknown",
|
||||||
|
"country": "Belgium",
|
||||||
|
"farm_id": 1,
|
||||||
|
"farm_name": "Freefarm",
|
||||||
|
"farming_policy_id": 1,
|
||||||
|
"grid_node_id": 12,
|
||||||
|
"last_updated": "2025-09-09T03:30:24.731928799Z",
|
||||||
|
"location": "Unknown, Belgium",
|
||||||
|
"node_id": 12,
|
||||||
|
"public_ips": [
|
||||||
|
"192.168.1.100"
|
||||||
|
],
|
||||||
|
"status": "Online",
|
||||||
|
"total_resources": {
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"cpu_cores": 8,
|
||||||
|
"hdd_storage_gb": 402336,
|
||||||
|
"memory_gb": 15,
|
||||||
|
"ram_gb": 15,
|
||||||
|
"ssd_storage_gb": 223,
|
||||||
|
"storage_gb": 402559
|
||||||
|
},
|
||||||
|
"uptime": 99.5,
|
||||||
|
"used_resources": {
|
||||||
|
"bandwidth_mbps": 0,
|
||||||
|
"cpu_cores": 5,
|
||||||
|
"hdd_storage_gb": 0,
|
||||||
|
"memory_gb": 12,
|
||||||
|
"ram_gb": 12,
|
||||||
|
"ssd_storage_gb": 165,
|
||||||
|
"storage_gb": 165
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slice_formats": null,
|
||||||
|
"name": "Grid Node 12",
|
||||||
|
"region": "Belgium",
|
||||||
|
"node_type": "MyceliumNode",
|
||||||
|
"staking_options": null,
|
||||||
|
"availability_status": "Available",
|
||||||
|
"node_group_id": null,
|
||||||
|
"group_assignment_date": null,
|
||||||
|
"group_slice_format": null,
|
||||||
|
"group_slice_price": null,
|
||||||
|
"last_seen": "2025-09-09T03:30:24.732150580Z",
|
||||||
|
"health_score": 100.0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"resource_provider_earnings": [],
|
"resource_provider_earnings": [],
|
||||||
|
15
user_data/user123_at_example_com_cart.json
Normal file
15
user_data/user123_at_example_com_cart.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"user_id": "user123@example.com",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"product_id": "user_user0_example_com_fa373486",
|
||||||
|
"quantity": 1,
|
||||||
|
"selected_specifications": {},
|
||||||
|
"added_at": "2025-09-09T03:32:30.573242755Z",
|
||||||
|
"updated_at": "2025-09-09T03:32:30.573242755Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"session_id": null,
|
||||||
|
"created_at": "2025-09-09T03:32:30.573133861Z",
|
||||||
|
"updated_at": "2025-09-09T03:32:30.573271484Z"
|
||||||
|
}
|
@@ -18,7 +18,121 @@
|
|||||||
"deleted": null,
|
"deleted": null,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"deletion_reason": null,
|
"deletion_reason": null,
|
||||||
"nodes": [],
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "grid_node_2007",
|
||||||
|
"location": "Unknown, Belgium",
|
||||||
|
"status": "Online",
|
||||||
|
"capacity": {
|
||||||
|
"cpu_cores": 24,
|
||||||
|
"memory_gb": 188,
|
||||||
|
"storage_gb": 8859,
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"ssd_storage_gb": 476,
|
||||||
|
"hdd_storage_gb": 8383,
|
||||||
|
"ram_gb": 188
|
||||||
|
},
|
||||||
|
"used_capacity": {
|
||||||
|
"cpu_cores": 9,
|
||||||
|
"memory_gb": 55,
|
||||||
|
"storage_gb": 343,
|
||||||
|
"bandwidth_mbps": 0,
|
||||||
|
"ssd_storage_gb": 343,
|
||||||
|
"hdd_storage_gb": 0,
|
||||||
|
"ram_gb": 55
|
||||||
|
},
|
||||||
|
"uptime_percentage": 99.0,
|
||||||
|
"farming_start_date": "2025-08-10T03:27:08.942256607Z",
|
||||||
|
"last_updated": "2025-09-09T03:27:08.942268123Z",
|
||||||
|
"utilization_7_day_avg": 65.0,
|
||||||
|
"slice_formats_supported": [
|
||||||
|
"1x1",
|
||||||
|
"2x2",
|
||||||
|
"4x4"
|
||||||
|
],
|
||||||
|
"rental_options": null,
|
||||||
|
"total_base_slices": 0,
|
||||||
|
"allocated_base_slices": 0,
|
||||||
|
"earnings_today_usd": 0.0,
|
||||||
|
"grid_node_id": "2007",
|
||||||
|
"available_combinations": [],
|
||||||
|
"slice_allocations": [],
|
||||||
|
"slice_last_calculated": null,
|
||||||
|
"marketplace_sla": {
|
||||||
|
"id": "sla-repair-8fa25e61-493a-46cc-b942-ce8cef923ae6",
|
||||||
|
"name": "Repaired Node SLA",
|
||||||
|
"uptime_guarantee": 99.8,
|
||||||
|
"response_time_hours": 24,
|
||||||
|
"resolution_time_hours": 48,
|
||||||
|
"penalty_rate": 0.01,
|
||||||
|
"uptime_guarantee_percentage": 99.8,
|
||||||
|
"base_slice_price": 0.5,
|
||||||
|
"bandwidth_guarantee_mbps": 100.0,
|
||||||
|
"last_updated": "2025-09-09T03:27:12.489433171Z"
|
||||||
|
},
|
||||||
|
"slice_pricing": {
|
||||||
|
"base_price_per_hour": 1.0,
|
||||||
|
"currency": "USD",
|
||||||
|
"pricing_multiplier": 1.0
|
||||||
|
},
|
||||||
|
"grid_data": {
|
||||||
|
"capacity": {
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"cpu_cores": 24,
|
||||||
|
"hdd_storage_gb": 8383,
|
||||||
|
"memory_gb": 188,
|
||||||
|
"ram_gb": 188,
|
||||||
|
"ssd_storage_gb": 476,
|
||||||
|
"storage_gb": 8859
|
||||||
|
},
|
||||||
|
"certification_type": "Diy",
|
||||||
|
"city": "Unknown",
|
||||||
|
"country": "Belgium",
|
||||||
|
"farm_id": 1,
|
||||||
|
"farm_name": "Freefarm",
|
||||||
|
"farming_policy_id": 1,
|
||||||
|
"grid_node_id": 2007,
|
||||||
|
"last_updated": "2025-09-09T03:27:08.942100965Z",
|
||||||
|
"location": "Unknown, Belgium",
|
||||||
|
"node_id": 2007,
|
||||||
|
"public_ips": [
|
||||||
|
"192.168.1.100"
|
||||||
|
],
|
||||||
|
"status": "Online",
|
||||||
|
"total_resources": {
|
||||||
|
"bandwidth_mbps": 1000,
|
||||||
|
"cpu_cores": 24,
|
||||||
|
"hdd_storage_gb": 8383,
|
||||||
|
"memory_gb": 188,
|
||||||
|
"ram_gb": 188,
|
||||||
|
"ssd_storage_gb": 476,
|
||||||
|
"storage_gb": 8859
|
||||||
|
},
|
||||||
|
"uptime": 99.5,
|
||||||
|
"used_resources": {
|
||||||
|
"bandwidth_mbps": 0,
|
||||||
|
"cpu_cores": 9,
|
||||||
|
"hdd_storage_gb": 0,
|
||||||
|
"memory_gb": 55,
|
||||||
|
"ram_gb": 55,
|
||||||
|
"ssd_storage_gb": 343,
|
||||||
|
"storage_gb": 343
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"slice_formats": null,
|
||||||
|
"name": "Grid Node 2007",
|
||||||
|
"region": "Belgium",
|
||||||
|
"node_type": "MyceliumNode",
|
||||||
|
"staking_options": null,
|
||||||
|
"availability_status": "Available",
|
||||||
|
"node_group_id": null,
|
||||||
|
"group_assignment_date": null,
|
||||||
|
"group_slice_format": null,
|
||||||
|
"group_slice_price": null,
|
||||||
|
"last_seen": "2025-09-09T03:27:08.942273898Z",
|
||||||
|
"health_score": 100.0
|
||||||
|
}
|
||||||
|
],
|
||||||
"resource_provider_earnings": [],
|
"resource_provider_earnings": [],
|
||||||
"resource_provider_settings": null,
|
"resource_provider_settings": null,
|
||||||
"slice_products": [],
|
"slice_products": [],
|
||||||
@@ -29,7 +143,91 @@
|
|||||||
"active_product_rentals": [],
|
"active_product_rentals": [],
|
||||||
"resource_provider_rental_earnings": [],
|
"resource_provider_rental_earnings": [],
|
||||||
"node_rentals": [],
|
"node_rentals": [],
|
||||||
"node_groups": [],
|
"node_groups": [
|
||||||
|
{
|
||||||
|
"id": "compute",
|
||||||
|
"name": "Compute",
|
||||||
|
"description": "General compute workloads",
|
||||||
|
"node_ids": [],
|
||||||
|
"group_type": {
|
||||||
|
"Default": "compute"
|
||||||
|
},
|
||||||
|
"updated_at": "2025-09-09T03:26:57.639840151Z",
|
||||||
|
"created_at": "2025-09-09T03:26:57.639836172Z",
|
||||||
|
"group_config": {
|
||||||
|
"group_name": "Compute Nodes",
|
||||||
|
"max_nodes": 100,
|
||||||
|
"allocation_strategy": "balanced",
|
||||||
|
"auto_scaling": true,
|
||||||
|
"preferred_slice_formats": [
|
||||||
|
"1x1",
|
||||||
|
"2x2"
|
||||||
|
],
|
||||||
|
"default_pricing": 50.0,
|
||||||
|
"resource_optimization": {
|
||||||
|
"cpu_optimization": 0.5,
|
||||||
|
"memory_optimization": 0.5,
|
||||||
|
"storage_optimization": 0.5,
|
||||||
|
"network_optimization": 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "storage",
|
||||||
|
"name": "Storage",
|
||||||
|
"description": "Storage and data workloads",
|
||||||
|
"node_ids": [],
|
||||||
|
"group_type": {
|
||||||
|
"Default": "storage"
|
||||||
|
},
|
||||||
|
"updated_at": "2025-09-09T03:26:57.639846621Z",
|
||||||
|
"created_at": "2025-09-09T03:26:57.639846284Z",
|
||||||
|
"group_config": {
|
||||||
|
"group_name": "Storage Nodes",
|
||||||
|
"max_nodes": 50,
|
||||||
|
"allocation_strategy": "storage_optimized",
|
||||||
|
"auto_scaling": false,
|
||||||
|
"preferred_slice_formats": [
|
||||||
|
"1x1"
|
||||||
|
],
|
||||||
|
"default_pricing": 30.0,
|
||||||
|
"resource_optimization": {
|
||||||
|
"cpu_optimization": 0.3,
|
||||||
|
"memory_optimization": 0.3,
|
||||||
|
"storage_optimization": 0.8,
|
||||||
|
"network_optimization": 0.6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ai-gpu",
|
||||||
|
"name": "AI/GPU",
|
||||||
|
"description": "AI and GPU-intensive workloads",
|
||||||
|
"node_ids": [],
|
||||||
|
"group_type": {
|
||||||
|
"Default": "ai-gpu"
|
||||||
|
},
|
||||||
|
"updated_at": "2025-09-09T03:26:57.639850994Z",
|
||||||
|
"created_at": "2025-09-09T03:26:57.639850646Z",
|
||||||
|
"group_config": {
|
||||||
|
"group_name": "AI/GPU Nodes",
|
||||||
|
"max_nodes": 20,
|
||||||
|
"allocation_strategy": "gpu_optimized",
|
||||||
|
"auto_scaling": true,
|
||||||
|
"preferred_slice_formats": [
|
||||||
|
"4x4",
|
||||||
|
"8x8"
|
||||||
|
],
|
||||||
|
"default_pricing": 200.0,
|
||||||
|
"resource_optimization": {
|
||||||
|
"cpu_optimization": 0.8,
|
||||||
|
"memory_optimization": 0.7,
|
||||||
|
"storage_optimization": 0.4,
|
||||||
|
"network_optimization": 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"slice_rentals": [],
|
"slice_rentals": [],
|
||||||
"slice_assignments": [],
|
"slice_assignments": [],
|
||||||
"display_currency": "MC",
|
"display_currency": "MC",
|
||||||
|
Reference in New Issue
Block a user