overgrowth / agent /hardware_pricing.py
Graham Paasch
Improve monitoring UX and deterministic offline outputs
1209812
Raw
History Blame
6.02 kB
"""
Hardware pricing database for BOM generation
Prices are approximate retail as of 2025
"""
# Basic procurement links for common gear we surface in mock/default designs
PROCUREMENT_LINKS = {
"Cisco Catalyst 9300": "https://www.cisco.com/c/en/us/products/switches/catalyst-9300-series-switches/",
"Cisco ISR 4331": "https://www.cisco.com/c/en/us/products/routers/4000-series-integrated-services-routers-isr/index.html",
"Cisco ISR 1100": "https://www.cisco.com/c/en/us/products/routers/1100-series-integrated-services-routers-isr/index.html",
"Arista 7050": "https://www.arista.com/en/products/7050x3-series",
"Fortinet FortiGate 60F": "https://www.fortinet.com/products/next-generation-firewall/fortigate-60f",
"Palo Alto PA-220": "https://www.paloaltonetworks.com/products/secure-the-network/next-generation-firewall/pa-220",
"Ubiquiti U6-Pro": "https://store.ui.com/us/en/pro/category/all-wifi/products/u6-pro",
"Ubiquiti U6-Enterprise": "https://store.ui.com/us/en/pro/category/all-wifi/products/u6-enterprise",
"Ubiquiti USW-Pro-24-PoE": "https://store.ui.com/us/en/pro/category/switching/products/usw-pro-24-poe",
"Ubiquiti USW-Enterprise-48-PoE": "https://store.ui.com/us/en/pro/category/switching/products/usw-enterprise-48-poe",
"pfSense Netgate 6100": "https://shop.netgate.com/products/6100-base",
"Dell PowerEdge R650": "https://www.dell.com/en-us/shop/povw/poweredge-r650",
}
HARDWARE_PRICING = {
# Switches
"Cisco Catalyst 9300": {"price": 8500, "category": "switch", "vendor": "Cisco"},
"Cisco Catalyst 2960": {"price": 2500, "category": "switch", "vendor": "Cisco"},
"Arista 7050": {"price": 12000, "category": "switch", "vendor": "Arista"},
"Ubiquiti USW-Enterprise-48-PoE": {"price": 1799, "category": "switch", "vendor": "Ubiquiti"},
"Ubiquiti USW-Pro-24-PoE": {"price": 499, "category": "switch", "vendor": "Ubiquiti"},
"Juniper EX4300": {"price": 6500, "category": "switch", "vendor": "Juniper"},
# Routers
"Cisco ISR 4331": {"price": 4500, "category": "router", "vendor": "Cisco"},
"Cisco ISR 1100": {"price": 1200, "category": "router", "vendor": "Cisco"},
"Ubiquiti Dream Machine Pro": {"price": 379, "category": "router", "vendor": "Ubiquiti"},
"MikroTik CCR2004": {"price": 899, "category": "router", "vendor": "MikroTik"},
# Access Points
"Ubiquiti U6-Enterprise": {"price": 379, "category": "access_point", "vendor": "Ubiquiti"},
"Ubiquiti U6-Pro": {"price": 179, "category": "access_point", "vendor": "Ubiquiti"},
"Cisco Catalyst 9130": {"price": 1500, "category": "access_point", "vendor": "Cisco"},
"Aruba AP-535": {"price": 1200, "category": "access_point", "vendor": "Aruba"},
# Firewalls
"Palo Alto PA-220": {"price": 3500, "category": "firewall", "vendor": "Palo Alto"},
"Fortinet FortiGate 60F": {"price": 800, "category": "firewall", "vendor": "Fortinet"},
"pfSense Netgate 6100": {"price": 899, "category": "firewall", "vendor": "Netgate"},
# Servers
"Dell PowerEdge R650": {"price": 5000, "category": "server", "vendor": "Dell"},
"HP ProLiant DL360": {"price": 4500, "category": "server", "vendor": "HP"},
# Generic fallbacks
"Generic Switch 48-port": {"price": 800, "category": "switch", "vendor": "Generic"},
"Generic Router": {"price": 500, "category": "router", "vendor": "Generic"},
"Generic Access Point": {"price": 150, "category": "access_point", "vendor": "Generic"},
}
CABLE_PRICING = {
"Cat6 Ethernet": {"price_per_foot": 0.50, "typical_length_ft": 3},
"Cat6a Ethernet": {"price_per_foot": 0.75, "typical_length_ft": 3},
"Fiber LC-LC": {"price_per_meter": 15.00, "typical_length_m": 10},
"Fiber SC-SC": {"price_per_meter": 12.00, "typical_length_m": 10},
}
ACCESSORY_PRICING = {
"42U Server Rack": 800,
"Console Cable Kit": 45,
"Rack PDU 20A": 250,
"Cable Management": 100,
"UPS 1500VA": 350,
"Network Tools Kit": 150,
}
def estimate_device_cost(model: str, vendor: str = None) -> float:
"""
Estimate cost for a network device
Returns price in USD
"""
# Try exact match first
if model in HARDWARE_PRICING:
return HARDWARE_PRICING[model]["price"]
# Try fuzzy match on vendor
if vendor:
for key, data in HARDWARE_PRICING.items():
if vendor.lower() in key.lower() or vendor.lower() in data["vendor"].lower():
return data["price"]
# Fallback based on role keywords
model_lower = model.lower()
if "switch" in model_lower:
return HARDWARE_PRICING["Generic Switch 48-port"]["price"]
elif "router" in model_lower or "gateway" in model_lower:
return HARDWARE_PRICING["Generic Router"]["price"]
elif "access point" in model_lower or "ap" in model_lower:
return HARDWARE_PRICING["Generic Access Point"]["price"]
# Default fallback
return 1000
def estimate_cable_cost(cable_type: str, quantity: int, length: str = None) -> float:
"""
Estimate cable costs
"""
if cable_type in CABLE_PRICING:
pricing = CABLE_PRICING[cable_type]
if "price_per_foot" in pricing:
feet = pricing["typical_length_ft"]
if length and "ft" in length:
feet = int(length.replace("ft", "").strip())
return pricing["price_per_foot"] * feet * quantity
elif "price_per_meter" in pricing:
meters = pricing["typical_length_m"]
if length and "m" in length:
meters = int(length.replace("m", "").strip())
return pricing["price_per_meter"] * meters * quantity
return 10 * quantity # Default $10 per cable
def estimate_accessory_cost(accessory_name: str) -> float:
"""
Estimate accessory costs
"""
for key, price in ACCESSORY_PRICING.items():
if key.lower() in accessory_name.lower():
return price
return 50 # Default $50 for unknown accessories