Skip to content

Commit

Permalink
Merge pull request #91 from qonto/fix-invalid-prometheus-label
Browse files Browse the repository at this point in the history
Replace unsupported characters by underscore in labels
  • Loading branch information
vmercierfr authored Dec 14, 2023
2 parents 82cb05d + a4df4a8 commit 1570e40
Show file tree
Hide file tree
Showing 14 changed files with 534 additions and 303 deletions.
21 changes: 21 additions & 0 deletions internal/app/cloudwatch/mock/cloudwatch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Package mocks contains mock for Cloudwatch client
package mocks

import (
"context"

aws_cloudwatch "github.com/aws/aws-sdk-go-v2/service/cloudwatch"
aws_cloudwatch_types "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
)

type CloudwatchClient struct {
Metrics []aws_cloudwatch_types.MetricDataResult
}

// GetMetricData returns custom metrics
func (m CloudwatchClient) GetMetricData(ctx context.Context, input *aws_cloudwatch.GetMetricDataInput, fn ...func(*aws_cloudwatch.Options)) (*aws_cloudwatch.GetMetricDataOutput, error) {
response := &aws_cloudwatch.GetMetricDataOutput{}
response.MetricDataResults = m.Metrics

return response, nil
}
10 changes: 6 additions & 4 deletions internal/app/cloudwatch/rds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
aws_cloudwatch_types "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/qonto/prometheus-rds-exporter/internal/app/cloudwatch"
cloudwatch_mock "github.com/qonto/prometheus-rds-exporter/internal/app/cloudwatch/mock"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -158,12 +160,12 @@ func TestGetDBInstanceTypeInformation(t *testing.T) {
i++
}

mock := mockCloudwatchClient{metrics: data}
client := cloudwatch.NewRDSFetcher(mock, slog.Logger{})
result, err := client.GetRDSInstanceMetrics(instancesName)
client := cloudwatch_mock.CloudwatchClient{Metrics: data}
fetcher := cloudwatch.NewRDSFetcher(client, slog.Logger{})
result, err := fetcher.GetRDSInstanceMetrics(instancesName)

require.NoError(t, err, "GetRDSInstanceMetrics must succeed")
assert.Equal(t, float64(1), client.GetStatistics().CloudWatchAPICall, "One call to Cloudwatch API")
assert.Equal(t, float64(1), fetcher.GetStatistics().CloudWatchAPICall, "One call to Cloudwatch API")

for id, value := range instances {
assert.Equal(t, value.DatabaseConnections, result.Instances[id].DatabaseConnections, "DatabaseConnections mismatch")
Expand Down
20 changes: 0 additions & 20 deletions internal/app/cloudwatch/type_test.go

This file was deleted.

11 changes: 6 additions & 5 deletions internal/app/cloudwatch/usage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
aws_cloudwatch_types "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/qonto/prometheus-rds-exporter/internal/app/cloudwatch"
cloudwatch_mock "github.com/qonto/prometheus-rds-exporter/internal/app/cloudwatch/mock"
converter "github.com/qonto/prometheus-rds-exporter/internal/app/unit"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -20,8 +21,8 @@ func TestGetUsageMetrics(t *testing.T) {
ReservedDBInstances: 3,
}

mock := mockCloudwatchClient{
metrics: []aws_cloudwatch_types.MetricDataResult{
client := cloudwatch_mock.CloudwatchClient{
Metrics: []aws_cloudwatch_types.MetricDataResult{
{
Label: aws.String("AllocatedStorage"),
Values: []float64{expected.AllocatedStorage},
Expand All @@ -41,14 +42,14 @@ func TestGetUsageMetrics(t *testing.T) {
},
}

client := cloudwatch.NewUsageFetcher(mock, slog.Logger{})
result, err := client.GetUsageMetrics()
fetcher := cloudwatch.NewUsageFetcher(client, slog.Logger{})
result, err := fetcher.GetUsageMetrics()

require.NoError(t, err, "GetUsageMetrics must succeed")
assert.Equal(t, converter.GigaBytesToBytes(expected.AllocatedStorage), result.AllocatedStorage, "Allocated storage mismatch")
assert.Equal(t, expected.DBInstances, result.DBInstances, "DB instances count mismatch")
assert.Equal(t, expected.ManualSnapshots, result.ManualSnapshots, "Manual snapshots mismatch")
assert.Equal(t, expected.ReservedDBInstances, result.ReservedDBInstances, "Reserved DB instances mismatch")

assert.Equal(t, float64(1), client.GetStatistics().CloudWatchAPICall, "One call to Cloudwatch API")
assert.Equal(t, float64(1), fetcher.GetStatistics().CloudWatchAPICall, "One call to Cloudwatch API")
}
72 changes: 11 additions & 61 deletions internal/app/ec2/ec2_test.go
Original file line number Diff line number Diff line change
@@ -1,80 +1,30 @@
package ec2_test

import (
"context"
"testing"

aws_ec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
aws_ec2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/qonto/prometheus-rds-exporter/internal/app/ec2"
mock "github.com/qonto/prometheus-rds-exporter/internal/app/ec2/mock"
converter "github.com/qonto/prometheus-rds-exporter/internal/app/unit"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var t3Large = ec2.EC2InstanceMetrics{
MaximumIops: 15700,
MaximumThroughput: 347.5,
Memory: 8,
Vcpu: 2,
}

var t3Small = ec2.EC2InstanceMetrics{
MaximumIops: 11800,
MaximumThroughput: 260.62,
Memory: 2,
Vcpu: 2,
}

type mockEC2Client struct{}

func (m mockEC2Client) DescribeInstanceTypes(ctx context.Context, input *aws_ec2.DescribeInstanceTypesInput, optFns ...func(*aws_ec2.Options)) (*aws_ec2.DescribeInstanceTypesOutput, error) {
var instances []aws_ec2_types.InstanceTypeInfo

for _, instanceType := range input.InstanceTypes {
//nolint // Hide "missing cases in switch" alert because instanceType has many values. Mock with return empty result for unknown instances
switch instanceType {
case "t3.large":
instances = append(instances, aws_ec2_types.InstanceTypeInfo{
InstanceType: instanceType,
VCpuInfo: &aws_ec2_types.VCpuInfo{DefaultVCpus: &t3Large.Vcpu},
MemoryInfo: &aws_ec2_types.MemoryInfo{SizeInMiB: &t3Large.Memory},
EbsInfo: &aws_ec2_types.EbsInfo{EbsOptimizedInfo: &aws_ec2_types.EbsOptimizedInfo{
MaximumIops: &t3Large.MaximumIops,
MaximumThroughputInMBps: &t3Large.MaximumThroughput,
}},
})
case "t3.small":
instances = append(instances, aws_ec2_types.InstanceTypeInfo{
InstanceType: instanceType,
VCpuInfo: &aws_ec2_types.VCpuInfo{DefaultVCpus: &t3Small.Vcpu},
MemoryInfo: &aws_ec2_types.MemoryInfo{SizeInMiB: &t3Small.Memory},
EbsInfo: &aws_ec2_types.EbsInfo{EbsOptimizedInfo: &aws_ec2_types.EbsOptimizedInfo{
MaximumIops: &t3Small.MaximumIops,
MaximumThroughputInMBps: &t3Small.MaximumThroughput,
}},
})
}
}

return &aws_ec2.DescribeInstanceTypesOutput{InstanceTypes: instances}, nil
}

func TestGetDBInstanceTypeInformation(t *testing.T) {
mock := mockEC2Client{}
client := mock.EC2Client{}

instanceTypes := []string{"db.t3.large", "db.t3.small"}
client := ec2.NewFetcher(mock)
result, err := client.GetDBInstanceTypeInformation(instanceTypes)
fetcher := ec2.NewFetcher(client)
result, err := fetcher.GetDBInstanceTypeInformation(instanceTypes)

require.NoError(t, err, "GetDBInstanceTypeInformation must succeed")
assert.Equal(t, t3Large.Vcpu, result.Instances["db.t3.large"].Vcpu, "vCPU don't match")
assert.Equal(t, converter.MegaBytesToBytes(t3Large.Memory), result.Instances["db.t3.large"].Memory, "Memory don't match")
assert.Equal(t, t3Large.MaximumIops, result.Instances["db.t3.large"].MaximumIops, "MaximumThroughput don't match")
assert.Equal(t, converter.MegaBytesToBytes(t3Large.MaximumThroughput), result.Instances["db.t3.large"].MaximumThroughput, "MaximumThroughput don't match")
assert.Equal(t, mock.InstanceT3Large.Vcpu, result.Instances["db.t3.large"].Vcpu, "vCPU don't match")
assert.Equal(t, converter.MegaBytesToBytes(mock.InstanceT3Large.Memory), result.Instances["db.t3.large"].Memory, "Memory don't match")
assert.Equal(t, mock.InstanceT3Large.MaximumIops, result.Instances["db.t3.large"].MaximumIops, "MaximumThroughput don't match")
assert.Equal(t, converter.MegaBytesToBytes(mock.InstanceT3Large.MaximumThroughput), result.Instances["db.t3.large"].MaximumThroughput, "MaximumThroughput don't match")

assert.Equal(t, t3Small.Vcpu, result.Instances["db.t3.small"].Vcpu, "vCPU don't match")
assert.Equal(t, converter.MegaBytesToBytes(t3Small.Memory), result.Instances["db.t3.small"].Memory, "Memory don't match")
assert.Equal(t, mock.InstanceT3Small.Vcpu, result.Instances["db.t3.small"].Vcpu, "vCPU don't match")
assert.Equal(t, converter.MegaBytesToBytes(mock.InstanceT3Small.Memory), result.Instances["db.t3.small"].Memory, "Memory don't match")

assert.Equal(t, float64(1), client.GetStatistics().EC2ApiCall, "EC2 API call don't match")
assert.Equal(t, float64(1), fetcher.GetStatistics().EC2ApiCall, "EC2 API call don't match")
}
60 changes: 60 additions & 0 deletions internal/app/ec2/mock/ec2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Package mocks contains mock for EC2 client
package mocks

import (
"context"

aws_ec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
aws_ec2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/qonto/prometheus-rds-exporter/internal/app/ec2"
)

//nolint:golint,gomnd
var InstanceT3Large = ec2.EC2InstanceMetrics{
MaximumIops: 15700,
MaximumThroughput: 347.5,
Memory: 8,
Vcpu: 2,
}

//nolint:golint,gomnd
var InstanceT3Small = ec2.EC2InstanceMetrics{
MaximumIops: 11800,
MaximumThroughput: 260.62,
Memory: 2,
Vcpu: 2,
}

type EC2Client struct{}

func (m EC2Client) DescribeInstanceTypes(ctx context.Context, input *aws_ec2.DescribeInstanceTypesInput, optFns ...func(*aws_ec2.Options)) (*aws_ec2.DescribeInstanceTypesOutput, error) {
var instances []aws_ec2_types.InstanceTypeInfo

for _, instanceType := range input.InstanceTypes {
//nolint // Hide "missing cases in switch" alert because instanceType has many values. Mock with return empty result for unknown instances
switch instanceType {
case "t3.large":
instances = append(instances, aws_ec2_types.InstanceTypeInfo{
InstanceType: instanceType,
VCpuInfo: &aws_ec2_types.VCpuInfo{DefaultVCpus: &InstanceT3Large.Vcpu},
MemoryInfo: &aws_ec2_types.MemoryInfo{SizeInMiB: &InstanceT3Large.Memory},
EbsInfo: &aws_ec2_types.EbsInfo{EbsOptimizedInfo: &aws_ec2_types.EbsOptimizedInfo{
MaximumIops: &InstanceT3Large.MaximumIops,
MaximumThroughputInMBps: &InstanceT3Large.MaximumThroughput,
}},
})
case "t3.small":
instances = append(instances, aws_ec2_types.InstanceTypeInfo{
InstanceType: instanceType,
VCpuInfo: &aws_ec2_types.VCpuInfo{DefaultVCpus: &InstanceT3Small.Vcpu},
MemoryInfo: &aws_ec2_types.MemoryInfo{SizeInMiB: &InstanceT3Small.Memory},
EbsInfo: &aws_ec2_types.EbsInfo{EbsOptimizedInfo: &aws_ec2_types.EbsOptimizedInfo{
MaximumIops: &InstanceT3Small.MaximumIops,
MaximumThroughputInMBps: &InstanceT3Small.MaximumThroughput,
}},
})
}
}

return &aws_ec2.DescribeInstanceTypesOutput{InstanceTypes: instances}, nil
}
Loading

0 comments on commit 1570e40

Please sign in to comment.