source.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package heartbeat
  2. import (
  3. "time"
  4. "github.com/google/uuid"
  5. "github.com/opencost/opencost/core/pkg/clusters"
  6. "github.com/opencost/opencost/core/pkg/log"
  7. "github.com/opencost/opencost/core/pkg/version"
  8. )
  9. // HeartbeatMetadataProvider is an interface that provides metadata for heartbeat instances. It can be used to inject
  10. // custom metadata into a generic `Heartbeat` payload.
  11. type HeartbeatMetadataProvider interface {
  12. // GetMetadata returns the metadata for new heartbeat instances.
  13. GetMetadata() map[string]any
  14. }
  15. // ClusterInfoMetadataProvider is a `HeartbeatMetadataProvider` implementation that provides metadata about the cluster
  16. // leveraging a `ClusterInfoProvider` implementation.
  17. type ClusterInfoMetadataProvider struct {
  18. clusterInfoProvider clusters.ClusterInfoProvider
  19. }
  20. // NewClusterInfoMetadataProvider creates a new `ClusterInfoMetadataProvider` instance. The `provider` parameter is used to
  21. // inject custom metadata, but can be set to `nil` if no metadata is needed.
  22. func NewClusterInfoMetadataProvider(provider clusters.ClusterInfoProvider) *ClusterInfoMetadataProvider {
  23. return &ClusterInfoMetadataProvider{
  24. clusterInfoProvider: provider,
  25. }
  26. }
  27. // GetMetadata returns the metadata for new heartbeat instances. It uses the `ClusterInfoProvider` to get the cluster
  28. // information and injects it into the metadata map.
  29. func (c *ClusterInfoMetadataProvider) GetMetadata() map[string]any {
  30. m := c.clusterInfoProvider.GetClusterInfo()
  31. metadata := make(map[string]any, len(m))
  32. for k, v := range m {
  33. metadata[k] = v
  34. }
  35. return metadata
  36. }
  37. // HeartbeatSource is an `export.ExportSource` implementation that provides the basic data for a `Heartbeat` payload, and
  38. // leverages a `HeartbeatMetadataProvider` to inject custom metadata.
  39. type HeartbeatSource struct {
  40. startTime time.Time
  41. metadataProvider HeartbeatMetadataProvider
  42. }
  43. // NewHeartbeatSource creates a new `HeartbeatSource` instance. The `provider` parameter is used to inject custom metadata,
  44. // but can be set to `nil` if no metadata is needed.
  45. func NewHeartbeatSource(provider HeartbeatMetadataProvider) *HeartbeatSource {
  46. return &HeartbeatSource{
  47. startTime: time.Now().UTC(),
  48. metadataProvider: provider,
  49. }
  50. }
  51. // Make creates a new `Heartbeat` instance with the provided current time.
  52. func (h *HeartbeatSource) Make(t time.Time) *Heartbeat {
  53. uid, err := uuid.NewV7()
  54. if err != nil {
  55. log.Warnf("failed to generate v7 UUID, replacing with UUID v4: %s", err)
  56. uid = uuid.New()
  57. }
  58. id := uid.String()
  59. uptime := uint64(t.Sub(h.startTime).Minutes())
  60. v := version.FriendlyVersion()
  61. var metadata map[string]any
  62. if h.metadataProvider != nil {
  63. metadata = h.metadataProvider.GetMetadata()
  64. }
  65. return NewHeartbeat(id, t, uptime, v, metadata)
  66. }
  67. func (h *HeartbeatSource) Name() string {
  68. return HeartbeatEventName + "-source"
  69. }