service.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package kubemodel
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. )
  7. // @bingen:generate:ServiceType
  8. type ServiceType string
  9. const (
  10. ServiceTypeClusterIP ServiceType = "ClusterIP"
  11. ServiceTypeNodePort ServiceType = "NodePort"
  12. ServiceTypeLoadBalancer ServiceType = "LoadBalancer"
  13. ServiceTypeExternalName ServiceType = "ExternalName"
  14. )
  15. // ParseServiceType converts a string to a ServiceType, performing case-insensitive matching.
  16. // Returns ServiceTypeClusterIP (the default) if the service type string is not recognized.
  17. func ParseServiceType(serviceType string) ServiceType {
  18. switch strings.ToLower(serviceType) {
  19. case "clusterip":
  20. return ServiceTypeClusterIP
  21. case "nodeport":
  22. return ServiceTypeNodePort
  23. case "loadbalancer", "lb":
  24. return ServiceTypeLoadBalancer
  25. case "externalname":
  26. return ServiceTypeExternalName
  27. default:
  28. return ServiceTypeClusterIP
  29. }
  30. }
  31. // @bingen:generate:Service
  32. // Service represents a Kubernetes Service with network traffic tracking for cost allocation.
  33. //
  34. // Network Cost Allocation Strategy:
  35. // Services expose applications and route traffic, incurring costs for:
  36. // 1. Load Balancers (LoadBalancer type) - Cloud provider LB hourly cost + data transfer
  37. // 2. Data Transfer - Egress charges based on NetworkTransferBytes
  38. // 3. Public IPs (for LoadBalancer/NodePort with external IPs)
  39. //
  40. // Cost Attribution Flow:
  41. // - LoadBalancer Services: Direct cloud resource cost (e.g., AWS ELB, GCP LB) allocated to service
  42. // - Data Transfer: NetworkTransferBytes × cloud provider egress rate (varies by region/destination)
  43. // - NetworkReceiveBytes: Typically free (ingress), tracked for visibility
  44. // - Use Selector to map service costs to backing pods/containers proportionally
  45. //
  46. // Example: AWS Application Load Balancer
  47. // - Fixed hourly cost: $0.0225/hour
  48. // - LCU cost: $0.008/hour per LCU (based on connections, requests, bandwidth)
  49. // - Data transfer: $0.09/GB for internet egress
  50. // Total Service Cost = (LB hours × hourly rate) + (LCU hours × LCU rate) + (NetworkTransferBytes × transfer rate)
  51. type Service struct {
  52. UID string `json:"uid"`
  53. NamespaceUID string `json:"namespaceUid"`
  54. Name string `json:"name"`
  55. Type ServiceType `json:"type"`
  56. Start time.Time `json:"start"`
  57. End time.Time `json:"end"`
  58. // Label selector to identify pods/containers targeted by this service
  59. // Maps label keys to values (e.g., {"app": "nginx", "tier": "frontend"})
  60. // Pods with matching labels will receive traffic from this service
  61. Selector map[string]string `json:"selector,omitempty"`
  62. LBIngressAddress string `json:"lbIngressAddress,omitempty"`
  63. }
  64. func (s *Service) ValidateService(window Window) error {
  65. if s.UID == "" {
  66. return fmt.Errorf("UID is missing for Service with name '%s'", s.Name)
  67. }
  68. if s.Name == "" {
  69. return fmt.Errorf("Name is missing for Service '%s'", s.UID)
  70. }
  71. if s.NamespaceUID == "" {
  72. return fmt.Errorf("NamespaceUID is missing for Service '%s'", s.UID)
  73. }
  74. if err := checkWindow(window, s.Start, s.End); err != nil {
  75. return err
  76. }
  77. return nil
  78. }
  79. func (kms *KubeModelSet) RegisterService(service *Service) error {
  80. if err := service.ValidateService(kms.Window); err != nil {
  81. err = fmt.Errorf("RegisterService: invalid service: %w", err)
  82. kms.Error(err)
  83. return err
  84. }
  85. if _, ok := kms.Services[service.UID]; !ok {
  86. kms.Services[service.UID] = service
  87. kms.Metadata.ObjectCount++
  88. }
  89. return nil
  90. }