Skip to content

Commit

Permalink
Refactor cluster_license, use the collector interface
Browse files Browse the repository at this point in the history
Signed-off-by: kekkokers <[email protected]>
  • Loading branch information
kekkker committed Dec 12, 2023
1 parent 728e447 commit b4149e1
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 120 deletions.
184 changes: 75 additions & 109 deletions collector/cluster_license.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package collector

import (
"context"
"encoding/json"
"fmt"
"io"
Expand All @@ -27,13 +28,6 @@ import (
"github.com/prometheus/client_golang/prometheus"
)

type clusterLicenseMetric struct {
Type prometheus.ValueType
Desc *prometheus.Desc
Value func(clusterLicenseStats clusterLicenseResponse) float64
Labels func(clusterLicenseStats clusterLicenseResponse) []string
}

type clusterLicenseResponse struct {
License struct {
Status string `json:"status"`
Expand All @@ -51,143 +45,115 @@ type clusterLicenseResponse struct {
}

var (
defaultClusterLicenseLabels = []string{"cluster_license_type"}
defaultClusterLicenseValues = func(clusterLicense clusterLicenseResponse) []string {
return []string{clusterLicense.License.Type}
defaultClusterLicenseLabels = []string{"issued_to", "issuer", "type", "status"}
defaultClusterLicenseLabelsValues = func(clusterLicense clusterLicenseResponse) []string {
return []string{clusterLicense.License.IssuedTo, clusterLicense.License.Issuer, clusterLicense.License.Type, clusterLicense.License.Status}
}
)

var (
licenseMaxNodes = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "max_nodes"),
"The max amount of nodes allowed by the license",
defaultClusterLicenseLabels, nil,
)
licenseIssueDate = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "issue_date_in_millis"),
"License issue date in milliseconds",
defaultClusterLicenseLabels, nil,
)
licenseExpiryDate = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "expiry_date_in_millis"),
"License expiry date in milliseconds",
defaultClusterLicenseLabels, nil,
)
licenseStartDate = prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "start_date_in_millis"),
"License start date in milliseconds",
defaultClusterLicenseLabels, nil,
)
)

func init() {
registerCollector("cluster_license", defaultDisabled, NewClusterLicense)
}

// License Information Struct
type ClusterLicense struct {
logger log.Logger
client *http.Client
url *url.URL

clusterLicenseMetrics []*clusterLicenseMetric
hc *http.Client
u *url.URL
}

// NewClusterLicense defines ClusterLicense Prometheus metrics
func NewClusterLicense(logger log.Logger, client *http.Client, url *url.URL) *ClusterLicense {
func NewClusterLicense(logger log.Logger, u *url.URL, hc *http.Client) (Collector, error) {
return &ClusterLicense{
logger: logger,
client: client,
url: url,

clusterLicenseMetrics: []*clusterLicenseMetric{
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "max_nodes"),
"The max amount of nodes allowed by the license",
defaultClusterLicenseLabels, nil,
),
Value: func(clusterLicenseStats clusterLicenseResponse) float64 {
return float64(clusterLicenseStats.License.MaxNodes)
},
Labels: defaultClusterLicenseValues,
},
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "issue_date_in_millis"),
"License issue date in milliseconds",
defaultClusterLicenseLabels, nil,
),
Value: func(clusterLicenseStats clusterLicenseResponse) float64 {
return float64(clusterLicenseStats.License.IssueDateInMillis)
},
Labels: defaultClusterLicenseValues,
},
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "expiry_date_in_millis"),
"License expiry date in milliseconds",
defaultClusterLicenseLabels, nil,
),
Value: func(clusterLicenseStats clusterLicenseResponse) float64 {
return float64(clusterLicenseStats.License.ExpiryDateInMillis)
},
Labels: defaultClusterLicenseValues,
},
{
Type: prometheus.GaugeValue,
Desc: prometheus.NewDesc(
prometheus.BuildFQName(namespace, "cluster_license", "start_date_in_millis"),
"License start date in milliseconds",
defaultClusterLicenseLabels, nil,
),
Value: func(clusterLicenseStats clusterLicenseResponse) float64 {
return float64(clusterLicenseStats.License.StartDateInMillis)
},
Labels: defaultClusterLicenseValues,
},
},
}
}

// Describe adds License metrics descriptions
func (cl *ClusterLicense) Describe(ch chan<- *prometheus.Desc) {
for _, metric := range cl.clusterLicenseMetrics {
ch <- metric.Desc
}
u: u,
hc: hc,
}, nil
}

func (cl *ClusterLicense) fetchAndDecodeClusterLicense() (clusterLicenseResponse, error) {
func (c *ClusterLicense) Update(ctx context.Context, ch chan<- prometheus.Metric) error {
var clr clusterLicenseResponse

u := *cl.url
u := *c.u
u.Path = path.Join(u.Path, "/_license")
res, err := cl.client.Get(u.String())
res, err := c.hc.Get(u.String())

if err != nil {
return clr, fmt.Errorf("failed to get license stats from %s://%s:%s%s: %s",
u.Scheme, u.Hostname(), u.Port(), u.Path, err)
return err
}

defer func() {
err = res.Body.Close()
if err != nil {
level.Warn(cl.logger).Log(
level.Warn(c.logger).Log(
"msg", "failed to close http.Client",
"err", err,
)
}
}()

if res.StatusCode != http.StatusOK {
return clr, fmt.Errorf("HTTP Request failed with code %d", res.StatusCode)
return fmt.Errorf("HTTP Request failed with code %d", res.StatusCode)
}

bts, err := io.ReadAll(res.Body)
if err != nil {
return clr, err
return err
}

if err := json.Unmarshal(bts, &clr); err != nil {
return clr, err
}

return clr, nil
}

// Collect gets ClusterLicense metric values
func (cl *ClusterLicense) Collect(ch chan<- prometheus.Metric) {

clusterLicenseResp, err := cl.fetchAndDecodeClusterLicense()
if err != nil {
level.Warn(cl.logger).Log(
"msg", "failed to fetch and decode license stats",
"err", err,
)
return
return err
}

for _, metric := range cl.clusterLicenseMetrics {
ch <- prometheus.MustNewConstMetric(
metric.Desc,
metric.Type,
metric.Value(clusterLicenseResp),
metric.Labels(clusterLicenseResp)...,
)
}
ch <- prometheus.MustNewConstMetric(
licenseMaxNodes,
prometheus.GaugeValue,
float64(clr.License.MaxNodes),
defaultClusterLicenseLabelsValues(clr)...,
)

ch <- prometheus.MustNewConstMetric(
licenseIssueDate,
prometheus.GaugeValue,
float64(clr.License.IssueDateInMillis),
defaultClusterLicenseLabelsValues(clr)...,
)

ch <- prometheus.MustNewConstMetric(
licenseExpiryDate,
prometheus.GaugeValue,
float64(clr.License.ExpiryDateInMillis),
defaultClusterLicenseLabelsValues(clr)...,
)

ch <- prometheus.MustNewConstMetric(
licenseStartDate,
prometheus.GaugeValue,
float64(clr.License.StartDateInMillis),
defaultClusterLicenseLabelsValues(clr)...,
)

return nil
}
26 changes: 15 additions & 11 deletions collector/cluster_license_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil"
)

func TestIndicesHealth(t *testing.T) {
func TestClusterLicense(t *testing.T) {
// Testcases created using:
// docker run -d -p 9200:9200 elasticsearch:VERSION
// curl http://localhost:9200/_license
Expand All @@ -41,16 +41,16 @@ func TestIndicesHealth(t *testing.T) {
want: `
# HELP elasticsearch_cluster_license_expiry_date_in_millis License expiry date in milliseconds
# TYPE elasticsearch_cluster_license_expiry_date_in_millis gauge
elasticsearch_cluster_license_expiry_date_in_millis{cluster_license_type="basic"} 0
elasticsearch_cluster_license_expiry_date_in_millis{issued_to="redacted",issuer="elasticsearch",status="active",type="basic"} 0
# HELP elasticsearch_cluster_license_issue_date_in_millis License issue date in milliseconds
# TYPE elasticsearch_cluster_license_issue_date_in_millis gauge
elasticsearch_cluster_license_issue_date_in_millis{cluster_license_type="basic"} 1.702196247064e+12
elasticsearch_cluster_license_issue_date_in_millis{issued_to="redacted",issuer="elasticsearch",status="active",type="basic"} 1.702196247064e+12
# HELP elasticsearch_cluster_license_max_nodes The max amount of nodes allowed by the license
# TYPE elasticsearch_cluster_license_max_nodes gauge
elasticsearch_cluster_license_max_nodes{cluster_license_type="basic"} 1000
elasticsearch_cluster_license_max_nodes{issued_to="redacted",issuer="elasticsearch",status="active",type="basic"} 1000
# HELP elasticsearch_cluster_license_start_date_in_millis License start date in milliseconds
# TYPE elasticsearch_cluster_license_start_date_in_millis gauge
elasticsearch_cluster_license_start_date_in_millis{cluster_license_type="basic"} -1
elasticsearch_cluster_license_start_date_in_millis{issued_to="redacted",issuer="elasticsearch",status="active",type="basic"} -1
`,
},
{
Expand All @@ -59,16 +59,16 @@ func TestIndicesHealth(t *testing.T) {
want: `
# HELP elasticsearch_cluster_license_expiry_date_in_millis License expiry date in milliseconds
# TYPE elasticsearch_cluster_license_expiry_date_in_millis gauge
elasticsearch_cluster_license_expiry_date_in_millis{cluster_license_type="platinum"} 1.714521599999e+12
elasticsearch_cluster_license_expiry_date_in_millis{issued_to="redacted",issuer="API",status="active",type="platinum"} 1.714521599999e+12
# HELP elasticsearch_cluster_license_issue_date_in_millis License issue date in milliseconds
# TYPE elasticsearch_cluster_license_issue_date_in_millis gauge
elasticsearch_cluster_license_issue_date_in_millis{cluster_license_type="platinum"} 1.6192224e+12
elasticsearch_cluster_license_issue_date_in_millis{issued_to="redacted",issuer="API",status="active",type="platinum"} 1.6192224e+12
# HELP elasticsearch_cluster_license_max_nodes The max amount of nodes allowed by the license
# TYPE elasticsearch_cluster_license_max_nodes gauge
elasticsearch_cluster_license_max_nodes{cluster_license_type="platinum"} 10
elasticsearch_cluster_license_max_nodes{issued_to="redacted",issuer="API",status="active",type="platinum"} 10
# HELP elasticsearch_cluster_license_start_date_in_millis License start date in milliseconds
# TYPE elasticsearch_cluster_license_start_date_in_millis gauge
elasticsearch_cluster_license_start_date_in_millis{cluster_license_type="platinum"} 1.6192224e+12
elasticsearch_cluster_license_start_date_in_millis{issued_to="redacted",issuer="API",status="active",type="platinum"} 1.6192224e+12
`,
},
}
Expand All @@ -92,9 +92,13 @@ func TestIndicesHealth(t *testing.T) {
t.Fatal(err)
}

c := NewClusterLicense(log.NewNopLogger(), http.DefaultClient, u)
c, err := NewClusterLicense(log.NewNopLogger(), u, http.DefaultClient)

if err := testutil.CollectAndCompare(c, strings.NewReader(tt.want)); err != nil {
if err != nil {
t.Fatal(err)
}

if err := testutil.CollectAndCompare(wrapCollector{c}, strings.NewReader(tt.want)); err != nil {
t.Fatal(err)
}
})
Expand Down

0 comments on commit b4149e1

Please sign in to comment.