From a67f9d4041a535c8e301f6d24b64b187d35b9b04 Mon Sep 17 00:00:00 2001 From: Ash-exp Date: Fri, 12 Sep 2025 16:57:18 +0530 Subject: [PATCH 1/3] fix: update validation tags for TimeBoundariesRequest fields --- common-lib/utils/TimeUtils.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common-lib/utils/TimeUtils.go b/common-lib/utils/TimeUtils.go index cebe36da4..9e8e3d6c0 100644 --- a/common-lib/utils/TimeUtils.go +++ b/common-lib/utils/TimeUtils.go @@ -110,9 +110,9 @@ func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeReques // TimeBoundariesRequest represents the request for time boundary frames type TimeBoundariesRequest struct { - TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty, min=1"` - TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty, oneof=week month quarter year"` // week, month, quarter, year - Iterations int `json:"iterations" schema:"iterations" validate:"omitempty, min=1"` + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` } // TimeWindowBoundaries represents the start and end times for a time window From be63a991fb0f593daeb9c3bd6af405d3462ae455 Mon Sep 17 00:00:00 2001 From: Shivam Nagar <124123645+Shivam-nagar23@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:47:03 +0530 Subject: [PATCH 2/3] Feat/finops config (#337) * feat: add cost module installation topics and configurations * feat: add cost module installation topics and time range utilities --- chart-sync/go.mod | 2 +- chart-sync/go.sum | 4 +- .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- chart-sync/vendor/modules.txt | 4 +- ci-runner/go.mod | 2 +- ci-runner/go.sum | 4 +- .../common-lib/pubsub-lib/JetStreamUtil.go | 5 + .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- ci-runner/vendor/modules.txt | 4 +- common-lib/pubsub-lib/JetStreamUtil.go | 5 + git-sensor/go.mod | 2 +- git-sensor/go.sum | 4 +- .../common-lib/pubsub-lib/JetStreamUtil.go | 5 + .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- git-sensor/vendor/modules.txt | 4 +- image-scanner/go.mod | 2 +- image-scanner/go.sum | 4 +- .../common-lib/pubsub-lib/JetStreamUtil.go | 5 + .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- image-scanner/vendor/modules.txt | 4 +- kubelink/go.mod | 2 +- kubelink/go.sum | 4 +- .../common-lib/pubsub-lib/JetStreamUtil.go | 5 + .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- kubelink/vendor/modules.txt | 4 +- kubewatch/go.mod | 2 +- kubewatch/go.sum | 4 +- .../common-lib/pubsub-lib/JetStreamUtil.go | 5 + .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- kubewatch/vendor/modules.txt | 4 +- lens/go.mod | 2 +- lens/go.sum | 4 +- .../common-lib/pubsub-lib/JetStreamUtil.go | 5 + .../common-lib/utils/TimeUtils.go | 275 ++++++++++++++++++ .../common-lib/utils/bean/bean.go | 4 +- lens/vendor/modules.txt | 4 +- 42 files changed, 2016 insertions(+), 42 deletions(-) create mode 100644 chart-sync/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go create mode 100644 ci-runner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go create mode 100644 git-sensor/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go create mode 100644 image-scanner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go create mode 100644 kubelink/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go create mode 100644 kubewatch/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go create mode 100644 lens/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go diff --git a/chart-sync/go.mod b/chart-sync/go.mod index 3f70584cf..683a390a7 100644 --- a/chart-sync/go.mod +++ b/chart-sync/go.mod @@ -4,7 +4,7 @@ go 1.24.0 toolchain go1.24.3 -replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b require ( github.com/caarlos0/env v3.5.0+incompatible diff --git a/chart-sync/go.sum b/chart-sync/go.sum index 50f0fe981..9b1611e39 100644 --- a/chart-sync/go.sum +++ b/chart-sync/go.sum @@ -43,8 +43,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM= diff --git a/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/chart-sync/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/chart-sync/vendor/modules.txt b/chart-sync/vendor/modules.txt index a41fd5861..912774854 100644 --- a/chart-sync/vendor/modules.txt +++ b/chart-sync/vendor/modules.txt @@ -95,7 +95,7 @@ github.com/containerd/platforms # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/constants github.com/devtron-labs/common-lib/fetchAllEnv @@ -967,4 +967,4 @@ sigs.k8s.io/structured-merge-diff/v4/value sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 sigs.k8s.io/yaml/goyaml.v3 -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/ci-runner/go.mod b/ci-runner/go.mod index a47038b06..fb5b91fc0 100644 --- a/ci-runner/go.mod +++ b/ci-runner/go.mod @@ -4,7 +4,7 @@ go 1.24.0 toolchain go1.24.3 -replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b require ( github.com/Knetic/govaluate v3.0.0+incompatible diff --git a/ci-runner/go.sum b/ci-runner/go.sum index 989602349..03c9fe234 100644 --- a/ci-runner/go.sum +++ b/ci-runner/go.sum @@ -114,8 +114,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k= diff --git a/ci-runner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/ci-runner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/ci-runner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go +++ b/ci-runner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/ci-runner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/ci-runner/vendor/modules.txt b/ci-runner/vendor/modules.txt index adcc96a6d..345a48f63 100644 --- a/ci-runner/vendor/modules.txt +++ b/ci-runner/vendor/modules.txt @@ -298,7 +298,7 @@ github.com/cncf/xds/go/xds/type/v3 # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/blob-storage github.com/devtron-labs/common-lib/constants @@ -1198,4 +1198,4 @@ sigs.k8s.io/structured-merge-diff/v4/value ## explicit; go 1.12 sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/common-lib/pubsub-lib/JetStreamUtil.go b/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/common-lib/pubsub-lib/JetStreamUtil.go +++ b/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/git-sensor/go.mod b/git-sensor/go.mod index d77b1cbc7..8e9cd5b47 100644 --- a/git-sensor/go.mod +++ b/git-sensor/go.mod @@ -4,7 +4,7 @@ go 1.24.0 toolchain go1.24.3 -replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b require ( github.com/caarlos0/env v3.5.0+incompatible diff --git a/git-sensor/go.sum b/git-sensor/go.sum index 163eedaf1..ef90a99ab 100644 --- a/git-sensor/go.sum +++ b/git-sensor/go.sum @@ -26,8 +26,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/devtron-labs/protos v0.0.3-0.20250323220609-ecf8a0f7305e h1:U6UdYbW8a7xn5IzFPd8cywjVVPfutGJCudjePAfL/Hs= github.com/devtron-labs/protos v0.0.3-0.20250323220609-ecf8a0f7305e/go.mod h1:1TqULGlTey+VNhAu/ag7NJuUvByJemkqodsc9L5PHJk= github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k= diff --git a/git-sensor/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/git-sensor/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/git-sensor/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go +++ b/git-sensor/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/git-sensor/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/git-sensor/vendor/modules.txt b/git-sensor/vendor/modules.txt index 64366ab2b..9c2eb4ebc 100644 --- a/git-sensor/vendor/modules.txt +++ b/git-sensor/vendor/modules.txt @@ -66,7 +66,7 @@ github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/constants github.com/devtron-labs/common-lib/fetchAllEnv @@ -472,4 +472,4 @@ gopkg.in/yaml.v3 # mellium.im/sasl v0.3.2 ## explicit; go 1.20 mellium.im/sasl -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/image-scanner/go.mod b/image-scanner/go.mod index ca39474ec..447c23fdb 100644 --- a/image-scanner/go.mod +++ b/image-scanner/go.mod @@ -70,4 +70,4 @@ require ( mellium.im/sasl v0.3.2 // indirect ) -replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/image-scanner/go.sum b/image-scanner/go.sum index 77eb02326..3af182a6e 100644 --- a/image-scanner/go.sum +++ b/image-scanner/go.sum @@ -279,8 +279,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= diff --git a/image-scanner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/image-scanner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/image-scanner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go +++ b/image-scanner/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/image-scanner/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/image-scanner/vendor/modules.txt b/image-scanner/vendor/modules.txt index db18a5bc9..7b4322f99 100644 --- a/image-scanner/vendor/modules.txt +++ b/image-scanner/vendor/modules.txt @@ -74,7 +74,7 @@ github.com/cespare/xxhash/v2 github.com/coreos/clair/api/v3/clairpb github.com/coreos/clair/database github.com/coreos/clair/ext/versionfmt -# github.com/devtron-labs/common-lib v0.19.0 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.19.0 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/async github.com/devtron-labs/common-lib/constants @@ -456,4 +456,4 @@ google.golang.org/protobuf/types/known/wrapperspb # mellium.im/sasl v0.3.2 ## explicit; go 1.20 mellium.im/sasl -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/kubelink/go.mod b/kubelink/go.mod index 02cdc4b8c..59051d05f 100644 --- a/kubelink/go.mod +++ b/kubelink/go.mod @@ -168,4 +168,4 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect ) -replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +replace github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/kubelink/go.sum b/kubelink/go.sum index 56493c2f1..823496ea9 100644 --- a/kubelink/go.sum +++ b/kubelink/go.sum @@ -65,8 +65,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM= diff --git a/kubelink/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/kubelink/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/kubelink/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go +++ b/kubelink/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/kubelink/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/kubelink/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/kubelink/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/kubelink/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/kubelink/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/kubelink/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/kubelink/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/kubelink/vendor/modules.txt b/kubelink/vendor/modules.txt index 31223746e..722ef5368 100644 --- a/kubelink/vendor/modules.txt +++ b/kubelink/vendor/modules.txt @@ -125,7 +125,7 @@ github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/devtron-labs/common-lib v0.0.0 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.0.0 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/async github.com/devtron-labs/common-lib/constants @@ -1388,4 +1388,4 @@ sigs.k8s.io/structured-merge-diff/v4/value sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 sigs.k8s.io/yaml/goyaml.v3 -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/kubewatch/go.mod b/kubewatch/go.mod index 4bf7c2b80..3c3e6bd4d 100644 --- a/kubewatch/go.mod +++ b/kubewatch/go.mod @@ -238,5 +238,5 @@ require ( replace ( github.com/cyphar/filepath-securejoin v0.4.1 => github.com/cyphar/filepath-securejoin v0.3.6 // indirect - github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 + github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ) diff --git a/kubewatch/go.sum b/kubewatch/go.sum index d75a94a99..7f05fdf6b 100644 --- a/kubewatch/go.sum +++ b/kubewatch/go.sum @@ -129,8 +129,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= diff --git a/kubewatch/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/kubewatch/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/kubewatch/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go +++ b/kubewatch/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/kubewatch/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/kubewatch/vendor/modules.txt b/kubewatch/vendor/modules.txt index 89d6333c4..ae3d16409 100644 --- a/kubewatch/vendor/modules.txt +++ b/kubewatch/vendor/modules.txt @@ -251,7 +251,7 @@ github.com/cyphar/filepath-securejoin # github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc ## explicit github.com/davecgh/go-spew/spew -# github.com/devtron-labs/common-lib v0.0.0 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.0.0 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/async github.com/devtron-labs/common-lib/constants @@ -1981,4 +1981,4 @@ sigs.k8s.io/structured-merge-diff/v4/value sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 sigs.k8s.io/yaml/goyaml.v3 -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b diff --git a/lens/go.mod b/lens/go.mod index 0a77043cf..56f804485 100644 --- a/lens/go.mod +++ b/lens/go.mod @@ -59,6 +59,6 @@ require ( ) replace ( - github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 + github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 ) diff --git a/lens/go.sum b/lens/go.sum index 28237eac8..f6d2f4d03 100644 --- a/lens/go.sum +++ b/lens/go.sum @@ -17,8 +17,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 h1:jCxpB8+6KD29jenB4SLTimCYzsmazBAPKv6637xRT5M= -github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b h1:isxMjLS0o56qRQxEs64JiNBaoba/t0k3D8jXWR7P8Ck= +github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b/go.mod h1:/Ciy9tD9OxZOWBDPIasM448H7uvSo4+ZJiExpfwBZpA= github.com/devtron-labs/protos v0.0.3-0.20240912111807-605886d90b8d h1:IV6FWU6eWSfKq67Fs2DBx3LjkX/wtjMj9QB3ufZgga4= github.com/devtron-labs/protos v0.0.3-0.20240912111807-605886d90b8d/go.mod h1:1TqULGlTey+VNhAu/ag7NJuUvByJemkqodsc9L5PHJk= github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k= diff --git a/lens/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go b/lens/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go index b7434bb27..aaa6d129b 100644 --- a/lens/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go +++ b/lens/vendor/github.com/devtron-labs/common-lib/pubsub-lib/JetStreamUtil.go @@ -124,6 +124,9 @@ const ( INFRA_HELM_RELEASE_ACTION_TOPIC string = "INFRA_HELM_RELEASE_ACTION_TOPIC" INFRA_HELM_RELEASE_ACTION_GROUP string = "INFRA_HELM_RELEASE_ACTION_GROUP" INFRA_HELM_RELEASE_ACTION_DURABLE string = "INFRA_HELM_RELEASE_ACTION_DURABLE" + COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" + COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" + COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -179,6 +182,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, + COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{ @@ -221,6 +225,7 @@ var NatsConsumerWiseConfigMapping = map[string]NatsConsumerConfig{ INFRASTRACTURE_INSTALLATION_SUCCESS_DURABLE: {}, INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE: {}, INFRA_HELM_RELEASE_ACTION_DURABLE: {}, + COST_MODULE_INSTALLATION_DURABLE: {}, } // getConsumerConfigMap will fetch the consumer wise config from the json string diff --git a/lens/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go b/lens/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go new file mode 100644 index 000000000..9e8e3d6c0 --- /dev/null +++ b/lens/vendor/github.com/devtron-labs/common-lib/utils/TimeUtils.go @@ -0,0 +1,275 @@ +package utils + +import ( + "fmt" + "strings" + "time" +) + +type TimeRangeRequest struct { + From *time.Time `json:"from" schema:"from"` + To *time.Time `json:"to" schema:"to"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=today yesterday week month quarter lastWeek lastMonth"` +} + +func NewTimeRangeRequest(from *time.Time, to *time.Time) *TimeRangeRequest { + return &TimeRangeRequest{ + From: from, + To: to, + } +} + +func NewTimeWindowRequest(timeWindow TimeWindows) *TimeRangeRequest { + return &TimeRangeRequest{ + TimeWindow: &timeWindow, + } +} + +// TimeWindows is a string type that represents different time windows +type TimeWindows string + +func (timeRange TimeWindows) String() string { + return string(timeRange) +} + +// Define constants for different time windows +const ( + Today TimeWindows = "today" + Yesterday TimeWindows = "yesterday" + Week TimeWindows = "week" + Month TimeWindows = "month" + Quarter TimeWindows = "quarter" + LastWeek TimeWindows = "lastWeek" + LastMonth TimeWindows = "lastMonth" + Year TimeWindows = "year" +) + +func (timeRange *TimeRangeRequest) ParseAndValidateTimeRange() (*TimeRangeRequest, error) { + if timeRange == nil { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("invalid time range request. either from/to or timeWindow must be provided") + } + now := time.Now() + // If timeWindow is provided, it takes preference over from/to + if timeRange.TimeWindow != nil { + switch *timeRange.TimeWindow { + case Today: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Yesterday: + start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour) + end := start.Add(24 * time.Hour) + return NewTimeRangeRequest(&start, &end), nil + case Week: + // Current week (Monday to Sunday) + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + start := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + return NewTimeRangeRequest(&start, &now), nil + case Month: + start := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case Quarter: + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterStart := time.Month((quarter-1)*3 + 1) + start := time.Date(now.Year(), quarterStart, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + case LastWeek: + weekday := int(now.Weekday()) + if weekday == 0 { // Sunday + weekday = 7 + } + thisWeekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour) + lastWeekStart := thisWeekStart.AddDate(0, 0, -7) + lastWeekEnd := thisWeekStart.Add(-time.Second) + return NewTimeRangeRequest(&lastWeekStart, &lastWeekEnd), nil + case LastMonth: + thisMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + lastMonthStart := thisMonthStart.AddDate(0, -1, 0) + lastMonthEnd := thisMonthStart.Add(-time.Second) + return NewTimeRangeRequest(&lastMonthStart, &lastMonthEnd), nil + case Year: + start := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + return NewTimeRangeRequest(&start, &now), nil + default: + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("unsupported time window: %q", *timeRange.TimeWindow) + } + } + + // Use from/to dates if provided + if timeRange.From != nil && timeRange.To != nil { + if timeRange.From.After(*timeRange.To) { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from date cannot be after to date") + } + return NewTimeRangeRequest(timeRange.From, timeRange.To), nil + } else { + return NewTimeRangeRequest(&time.Time{}, &time.Time{}), fmt.Errorf("from and to dates are required if time window is not provided") + } +} + +// TimeBoundariesRequest represents the request for time boundary frames +type TimeBoundariesRequest struct { + TimeWindowBoundaries []string `json:"timeWindowBoundaries" schema:"timeWindowBoundaries" validate:"omitempty,min=1"` + TimeWindow *TimeWindows `json:"timeWindow" schema:"timeWindow" validate:"omitempty,oneof=week month quarter year"` // week, month, quarter, year + Iterations int `json:"iterations" schema:"iterations" validate:"omitempty,min=1"` +} + +// TimeWindowBoundaries represents the start and end times for a time window +type TimeWindowBoundaries struct { + StartTime time.Time + EndTime time.Time +} + +func (timeBoundaries *TimeBoundariesRequest) ParseAndValidateTimeBoundaries() ([]TimeWindowBoundaries, error) { + if timeBoundaries == nil { + return []TimeWindowBoundaries{}, fmt.Errorf("invalid time boundaries request") + } + // If timeWindow is provided, it takes preference over timeWindowBoundaries + if timeBoundaries.TimeWindow != nil { + switch *timeBoundaries.TimeWindow { + case Week: + return GetWeeklyTimeBoundaries(timeBoundaries.Iterations), nil + case Month: + return GetMonthlyTimeBoundaries(timeBoundaries.Iterations), nil + case Quarter: + return GetQuarterlyTimeBoundaries(timeBoundaries.Iterations), nil + case Year: + return GetYearlyTimeBoundaries(timeBoundaries.Iterations), nil + default: + return []TimeWindowBoundaries{}, fmt.Errorf("unsupported time window: %q", *timeBoundaries.TimeWindow) + } + } else if len(timeBoundaries.TimeWindowBoundaries) != 0 { + // Validate time window + return DecodeAndValidateTimeWindowBoundaries(timeBoundaries.TimeWindowBoundaries) + } else { + return []TimeWindowBoundaries{}, fmt.Errorf("time window boundaries are required if time window is not provided") + } +} + +func GetWeeklyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + weekday := int(now.Weekday()) + if weekday == 0 { + weekday = 7 + } + // Get start of this week (Monday) + weekStart := now.AddDate(0, 0, -(weekday - 1)) + // Set time to midnight + weekStart = time.Date(weekStart.Year(), weekStart.Month(), weekStart.Day(), 0, 0, 0, 0, weekStart.Location()) + + for i := 0; i < iterations; i++ { + start := weekStart.AddDate(0, 0, -7*i) + end := start.AddDate(0, 0, 7) + // For the current week, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetMonthlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this month (1st) + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := monthStart.AddDate(0, -i, 0) + end := start.AddDate(0, 1, 0) + // For the current month, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetQuarterlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + quarter := ((int(now.Month()) - 1) / 3) + 1 + quarterMonth := time.Month((quarter-1)*3 + 1) + // Get start of this quarter (1st of the month) + quarterStart := time.Date(now.Year(), quarterMonth, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := quarterStart.AddDate(0, -3*i, 0) + end := start.AddDate(0, 3, 0) + // For the current quarter, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func GetYearlyTimeBoundaries(iterations int) []TimeWindowBoundaries { + if iterations <= 0 { + return []TimeWindowBoundaries{} + } + boundaries := make([]TimeWindowBoundaries, iterations) + now := time.Now() + // Get start of this year (1st of January) + yearStart := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, now.Location()) + for i := 0; i < iterations; i++ { + start := yearStart.AddDate(-i, 0, 0) + end := start.AddDate(1, 0, 0) + // For the current year, if now < end, set end = now + if i == 0 && now.Before(end) { + end = now + } + boundaries[i] = TimeWindowBoundaries{ + StartTime: start, + EndTime: end, + } + } + return boundaries +} + +func DecodeAndValidateTimeWindowBoundaries(timeWindowBoundaries []string) ([]TimeWindowBoundaries, error) { + boundaries := make([]TimeWindowBoundaries, 0, len(timeWindowBoundaries)) + for _, boundary := range timeWindowBoundaries { + parts := strings.Split(boundary, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid time window boundary format: %q", boundary) + } + startTime, err := time.Parse(time.RFC3339, parts[0]) + if err != nil { + return nil, fmt.Errorf("invalid start time format: %q. expected format: %q", parts[0], time.RFC3339) + } + endTime, err := time.Parse(time.RFC3339, parts[1]) + if err != nil { + return nil, fmt.Errorf("invalid end time format: %q. expected format: %q", parts[1], time.RFC3339) + } + if startTime.After(endTime) { + return nil, fmt.Errorf("start time cannot be after end time: %q", boundary) + } + boundaries = append(boundaries, TimeWindowBoundaries{ + StartTime: startTime, + EndTime: endTime, + }) + } + return boundaries, nil +} diff --git a/lens/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go b/lens/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go index ea16a2f72..2bbfa1dc1 100644 --- a/lens/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go +++ b/lens/vendor/github.com/devtron-labs/common-lib/utils/bean/bean.go @@ -74,7 +74,9 @@ type PgQueryMonitoringConfig struct { } func GetPgQueryMonitoringConfig(serviceName string) (PgQueryMonitoringConfig, error) { - cfg := &PgQueryMonitoringConfig{} + cfg := &PgQueryMonitoringConfig{ + ServiceName: serviceName, + } err := env.Parse(cfg) return *cfg, err } diff --git a/lens/vendor/modules.txt b/lens/vendor/modules.txt index 72b9142be..2795f81a0 100644 --- a/lens/vendor/modules.txt +++ b/lens/vendor/modules.txt @@ -7,7 +7,7 @@ github.com/caarlos0/env # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 -# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib v0.19.1 => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b ## explicit; go 1.24.0 github.com/devtron-labs/common-lib/constants github.com/devtron-labs/common-lib/fetchAllEnv @@ -302,4 +302,4 @@ google.golang.org/protobuf/types/known/timestamppb # mellium.im/sasl v0.3.2 ## explicit; go 1.20 mellium.im/sasl -# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250901093002-1be330be4db3 +# github.com/devtron-labs/common-lib => github.com/devtron-labs/devtron-services/common-lib v0.0.0-20250929110950-82972ae5dc6b From 67f1cdde76f72c7b642339a898f8c4f598797d8e Mon Sep 17 00:00:00 2001 From: ayushmaheshwari Date: Sun, 12 Oct 2025 12:20:12 +0530 Subject: [PATCH 3/3] adding new topic for gpu installation --- common-lib/pubsub-lib/JetStreamUtil.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common-lib/pubsub-lib/JetStreamUtil.go b/common-lib/pubsub-lib/JetStreamUtil.go index aaa6d129b..50c006de4 100644 --- a/common-lib/pubsub-lib/JetStreamUtil.go +++ b/common-lib/pubsub-lib/JetStreamUtil.go @@ -127,6 +127,9 @@ const ( COST_MODULE_INSTALLATION_TOPIC string = "COST_MODULE_INSTALLATION_TOPIC" COST_MODULE_INSTALLATION_GROUP string = "COST_MODULE_INSTALLATION_GROUP" COST_MODULE_INSTALLATION_DURABLE string = "COST_MODULE_INSTALLATION_DURABLE" + COST_MODULE_GPU_INSTALLATION_TOPIC string = "COST_MODULE_GPU_INSTALLATION_TOPIC" + COST_MODULE_GPU_INSTALLATION_GROUP string = "COST_MODULE_GPU_INSTALLATION_GROUP" + COST_MODULE_GPU_INSTALLATION_DURABLE string = "COST_MODULE_GPU_INSTALLATION_DURABLE" ) type NatsTopic struct { @@ -183,6 +186,7 @@ var natsTopicMapping = map[string]NatsTopic{ INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC: {topicName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_GROUP, consumerName: INFRASTRACTURE_INSTALLATION_DELETE_SUCCESS_DURABLE}, INFRA_HELM_RELEASE_ACTION_TOPIC: {topicName: INFRA_HELM_RELEASE_ACTION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: INFRA_HELM_RELEASE_ACTION_GROUP, consumerName: INFRA_HELM_RELEASE_ACTION_DURABLE}, COST_MODULE_INSTALLATION_TOPIC: {topicName: COST_MODULE_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_INSTALLATION_GROUP, consumerName: COST_MODULE_INSTALLATION_DURABLE}, + COST_MODULE_GPU_INSTALLATION_TOPIC: {topicName: COST_MODULE_GPU_INSTALLATION_TOPIC, streamName: ORCHESTRATOR_STREAM, queueName: COST_MODULE_GPU_INSTALLATION_GROUP, consumerName: COST_MODULE_GPU_INSTALLATION_DURABLE}, } var NatsStreamWiseConfigMapping = map[string]NatsStreamConfig{