Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [unreleased]

### Bug Fixes

1. [#6145](https://github.com/influxdata/chronograf/pull/6145): Show missing retention policies on the Databases page

## v1.10.7 [2025-04-15]

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion influx/databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func (c *Client) showRetentionPolicies(ctx context.Context, db string) ([]chrono
return nil, err
}

return results.RetentionPolicies(), nil
return results.RetentionPolicies(c.Logger), nil
}

func (c *Client) showMeasurements(ctx context.Context, db string, limit, offset int) ([]chronograf.Measurement, error) {
Expand Down
77 changes: 56 additions & 21 deletions influx/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (c *Client) Permissions(context.Context) chronograf.Permissions {
// showResults is used to deserialize InfluxQL SHOW commands
type showResults []struct {
Series []struct {
Values [][]interface{} `json:"values"`
Values []value `json:"values"`
} `json:"series"`
}

Expand Down Expand Up @@ -93,37 +93,72 @@ func (r *showResults) Databases() []chronograf.Database {
return res
}

func (r *showResults) RetentionPolicies() []chronograf.RetentionPolicy {
res := []chronograf.RetentionPolicy{}
func (r *showResults) RetentionPolicies(logger chronograf.Logger) []chronograf.RetentionPolicy {
var res []chronograf.RetentionPolicy
for _, u := range *r {
for _, s := range u.Series {
for _, v := range s.Values {
if name, ok := v[0].(string); !ok {
continue
} else if duration, ok := v[1].(string); !ok {
continue
} else if sduration, ok := v[2].(string); !ok {
continue
} else if replication, ok := v[3].(float64); !ok {
continue
} else if def, ok := v[4].(bool); !ok {
continue
} else {
d := chronograf.RetentionPolicy{
Name: name,
Duration: duration,
ShardDuration: sduration,
Replication: int32(replication),
Default: def,
rp, err := parseRetentionPolicy(v)
if err != nil {
if logger != nil {
types := make([]string, len(v))
for i, val := range v {
types[i] = fmt.Sprintf("%T", val)
}
logger.
WithField("values", fmt.Sprintf("%v", v)).
WithField("types", fmt.Sprintf("%v", types)).
WithField("error", err.Error()).
Error("Unsupported retention policy format")
}
res = append(res, d)
continue
}
res = append(res, rp)
}
}
}
return res
}

// parseRetentionPolicy validates and parses a retention policy row
func parseRetentionPolicy(v []interface{}) (chronograf.RetentionPolicy, error) {
columns := len(v)
if columns < 5 {
return chronograf.RetentionPolicy{}, fmt.Errorf("insufficient columns: expected at least 5, got %d", columns)
} else if name, ok := v[0].(string); !ok {
return chronograf.RetentionPolicy{}, fmt.Errorf("column 0 (name) is not a string")
} else if duration, ok := v[1].(string); !ok {
return chronograf.RetentionPolicy{}, fmt.Errorf("column 1 (duration) is not a string")
} else if sduration, ok := v[2].(string); !ok {
return chronograf.RetentionPolicy{}, fmt.Errorf("column 2 (shardDuration) is not a string")
} else if replication, ok := v[3].(float64); !ok {
return chronograf.RetentionPolicy{}, fmt.Errorf("column 3 (replication) is not a float64")
} else {
var def bool
if columns == 5 {
// 5-column format: [name, duration, shardGroupDuration, replicaN, default]
if def, ok = v[4].(bool); !ok {
return chronograf.RetentionPolicy{}, fmt.Errorf("column 4 (default) is not a bool")
}
} else if columns == 7 {
// 7-column format: [name, duration, shardGroupDuration, replicaN, futureWriteLimit, pastWriteLimit, default]
if def, ok = v[6].(bool); !ok {
return chronograf.RetentionPolicy{}, fmt.Errorf("column 6 (default) is not a bool")
}
} else {
return chronograf.RetentionPolicy{}, fmt.Errorf("unexpected number of columns: %d", columns)
}

return chronograf.RetentionPolicy{
Name: name,
Duration: duration,
ShardDuration: sduration,
Replication: int32(replication),
Default: def,
}, nil
}
}

// Measurements converts SHOW MEASUREMENTS to chronograf Measurement
func (r *showResults) Measurements() []chronograf.Measurement {
res := []chronograf.Measurement{}
Expand Down
Loading
Loading