Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metric for multiple kymas per subaccount #1598

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/metricsv2/instances_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
// - kcp_keb_instances_total - total number of all instances
// - kcp_keb_global_account_id_instances_total - total number of all instances per global account
// - kcp_keb_ers_context_license_type_total - count of instances grouped by license types
// - kcp_keb_sub_account_id_instances_total - total number of instances per subaccount
type InstancesStatsGetter interface {
GetActiveInstanceStats() (internal.InstanceStats, error)
GetERSContextStats() (internal.ERSContextStats, error)
Expand All @@ -29,6 +30,7 @@ type InstancesCollector struct {

instancesDesc *prometheus.Desc
instancesPerGAIDDesc *prometheus.Desc
instancesPerSAIDDesc *prometheus.Desc
licenseTypeDesc *prometheus.Desc
logger *slog.Logger
}
Expand All @@ -47,6 +49,11 @@ func NewInstancesCollector(statsGetter InstancesStatsGetter, logger *slog.Logger
"The total number of instances by Global Account ID",
[]string{"global_account_id"},
nil),
instancesPerSAIDDesc: prometheus.NewDesc(
prometheus.BuildFQName(prometheusNamespacev2, prometheusSubsystemv2, "sub_account_id_instances_total"),
"The total number of instances by SubAccount ID",
[]string{"sub_account_id"},
nil),
licenseTypeDesc: prometheus.NewDesc(
prometheus.BuildFQName(prometheusNamespacev2, prometheusSubsystemv2, "ers_context_license_type_total"),
"count of instances grouped by license types",
Expand All @@ -58,6 +65,7 @@ func NewInstancesCollector(statsGetter InstancesStatsGetter, logger *slog.Logger
func (c *InstancesCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.instancesDesc
ch <- c.instancesPerGAIDDesc
ch <- c.instancesPerSAIDDesc
ch <- c.licenseTypeDesc
}

Expand All @@ -72,6 +80,10 @@ func (c *InstancesCollector) Collect(ch chan<- prometheus.Metric) {
for globalAccountID, num := range stats.PerGlobalAccountID {
collect(ch, c.instancesPerGAIDDesc, num, globalAccountID)
}

for subAccountID, num := range stats.PerSubAcocuntID {
collect(ch, c.instancesPerSAIDDesc, num, subAccountID)
}
}

stats2, err := c.statsGetter.GetERSContextStats()
Expand Down
1 change: 1 addition & 0 deletions internal/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ type OperationStatsV2 struct {
type InstanceStats struct {
TotalNumberOfInstances int
PerGlobalAccountID map[string]int
PerSubAcocuntID map[string]int
}

// ERSContextStats provides aggregated information regarding ERSContext
Expand Down
5 changes: 5 additions & 0 deletions internal/storage/dbmodel/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ type InstanceByGlobalAccountIDStatEntry struct {
Total int
}

type InstanceBySubAccountIDStatEntry struct {
SubAccountID string
Total int
}

type InstanceERSContextStatsEntry struct {
LicenseType sql.NullString
Total int
Expand Down
9 changes: 9 additions & 0 deletions internal/storage/driver/postsql/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,11 +545,20 @@ func (s *Instance) GetActiveInstanceStats() (internal.InstanceStats, error) {

result := internal.InstanceStats{
PerGlobalAccountID: make(map[string]int),
PerSubAcocuntID: make(map[string]int),
}
for _, e := range entries {
result.PerGlobalAccountID[e.GlobalAccountID] = e.Total
result.TotalNumberOfInstances = result.TotalNumberOfInstances + e.Total
}

subEntries, err := s.NewReadSession().GetSubaccountsInstanceStats()
if err != nil {
return internal.InstanceStats{}, err
}
for _, e := range subEntries {
result.PerSubAcocuntID[e.SubAccountID] = e.Total
}
return result, nil
}

Expand Down
9 changes: 5 additions & 4 deletions internal/storage/driver/postsql/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ func TestInstance(t *testing.T) {

// populate database with samples
fixInstances := []internal.Instance{
*fixInstance(instanceData{val: "A1", globalAccountID: "A"}),
*fixInstance(instanceData{val: "A2", globalAccountID: "A", deletedAt: time.Time{}}),
*fixInstance(instanceData{val: "A3", globalAccountID: "A"}),
*fixInstance(instanceData{val: "C1", globalAccountID: "C"}),
*fixInstance(instanceData{val: "A1", globalAccountID: "A", subAccountID: "sub-01"}),
*fixInstance(instanceData{val: "A2", globalAccountID: "A", subAccountID: "sub-02", deletedAt: time.Time{}}),
*fixInstance(instanceData{val: "A3", globalAccountID: "A", subAccountID: "sub-02"}),
*fixInstance(instanceData{val: "C1", globalAccountID: "C", subAccountID: "sub-01"}),
*fixInstance(instanceData{val: "C2", globalAccountID: "C", deletedAt: time.Now()}),
*fixInstance(instanceData{val: "B1", globalAccountID: "B", deletedAt: time.Now()}),
}
Expand Down Expand Up @@ -155,6 +155,7 @@ func TestInstance(t *testing.T) {
assert.Equal(t, internal.InstanceStats{
TotalNumberOfInstances: 3,
PerGlobalAccountID: map[string]int{"A": 2, "C": 1},
PerSubAcocuntID: map[string]int{"sub-01": 2},
}, stats)
assert.Equal(t, 3, numberOfInstancesA)
assert.Equal(t, 1, numberOfInstancesC)
Expand Down
1 change: 1 addition & 0 deletions internal/storage/postsql/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type ReadSession interface {
ListOperationsByType(operationType internal.OperationType) ([]dbmodel.OperationDTO, dberr.Error)
GetOperationStats() ([]dbmodel.OperationStatEntry, error)
GetActiveInstanceStats() ([]dbmodel.InstanceByGlobalAccountIDStatEntry, error)
GetSubaccountsInstanceStats() ([]dbmodel.InstanceBySubAccountIDStatEntry, error)
GetERSContextStats() ([]dbmodel.InstanceERSContextStatsEntry, error)
GetNumberOfInstancesForGlobalAccountID(globalAccountID string) (int, error)
GetRuntimeStateByOperationID(operationID string) (dbmodel.RuntimeStateDTO, dberr.Error)
Expand Down
24 changes: 24 additions & 0 deletions internal/storage/postsql/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,30 @@ func (r readSession) GetActiveInstanceStats() ([]dbmodel.InstanceByGlobalAccount
return rows, err
}

func (r readSession) GetSubaccountsInstanceStats() ([]dbmodel.InstanceBySubAccountIDStatEntry, error) {
var rows []dbmodel.InstanceBySubAccountIDStatEntry
var stmt *dbr.SelectStmt
filter := dbmodel.InstanceFilter{
States: []dbmodel.InstanceState{dbmodel.InstanceNotDeprovisioned},
}
// Find and join the last operation for each instance matching the state filter(s).
// Last operation is found with the greatest-n-per-group problem solved with OUTER JOIN, followed by a (INNER) JOIN to get instance columns.
stmt = r.session.
Select(fmt.Sprintf("%s.sub_account_id", InstancesTableName), "count(*) as total").
From(InstancesTableName).
Join(dbr.I(OperationTableName).As("o1"), fmt.Sprintf("%s.instance_id = o1.instance_id", InstancesTableName)).
LeftJoin(dbr.I(OperationTableName).As("o2"), fmt.Sprintf("%s.instance_id = o2.instance_id AND o1.created_at < o2.created_at AND o2.state NOT IN ('%s', '%s')", InstancesTableName, orchestration.Pending, orchestration.Canceled)).
Where("o2.created_at IS NULL").
Where("deleted_at = '0001-01-01T00:00:00.000Z'").
Where(fmt.Sprintf("o1.state NOT IN ('%s', '%s')", orchestration.Pending, orchestration.Canceled)).
Where(buildInstanceStateFilters("o1", filter)).
GroupBy(fmt.Sprintf("%s.sub_account_id", InstancesTableName)).
Having(fmt.Sprintf("count(*) > 1"))

_, err := stmt.Load(&rows)
return rows, err
}

func (r readSession) GetERSContextStats() ([]dbmodel.InstanceERSContextStatsEntry, error) {
var rows []dbmodel.InstanceERSContextStatsEntry
// group existing instances by license_Type from the last operation that is not pending or canceled
Expand Down
Loading