Skip to content

Commit

Permalink
Metric for multiple kymas per subaccount (#1598)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrmiskiewicz authored Jan 2, 2025
1 parent beee909 commit f9ef251
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 4 deletions.
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

0 comments on commit f9ef251

Please sign in to comment.