Skip to content

Commit

Permalink
feat: Add the Azure client options parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
ZPascal committed Aug 6, 2024
1 parent d160276 commit 14aa8c6
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 66 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/99designs/keyring v1.2.2
github.com/Azure/azure-event-hubs-go/v3 v3.6.2
github.com/Azure/azure-kusto-go v0.15.3
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/monitor/armmonitor v0.11.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0
Expand Down Expand Up @@ -134,7 +135,7 @@ require (
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b
github.com/leodido/go-syslog/v4 v4.1.0
github.com/linkedin/goavro/v2 v2.13.0
github.com/logzio/azure-monitor-metrics-receiver v1.0.2
github.com/logzio/azure-monitor-metrics-receiver v1.1.0
github.com/lxc/incus/v6 v6.2.0
github.com/mdlayher/apcupsd v0.0.0-20220319200143-473c7b5f3c6a
github.com/mdlayher/vsock v1.2.1
Expand Down Expand Up @@ -247,8 +248,7 @@ require (
github.com/Azure/azure-amqp-common-go/v4 v4.2.0 // indirect
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 // indirect
github.com/Azure/go-amqp v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -646,12 +646,12 @@ github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVt
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 h1:GJHeeA2N7xrG3q30L2UXDyuWRzDM900/65j70wcM4Ww=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
Expand Down Expand Up @@ -1812,8 +1812,8 @@ github.com/linkedin/goavro/v2 v2.13.0 h1:L8eI8GcuciwUkt41Ej62joSZS4kKaYIUdze+6fo
github.com/linkedin/goavro/v2 v2.13.0/go.mod h1:KXx+erlq+RPlGSPmLF7xGo6SAbh8sCQ53x064+ioxhk=
github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU=
github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg=
github.com/logzio/azure-monitor-metrics-receiver v1.0.2 h1:1vNuag1MwjTm02BJ9U7w3hCStJug2CgPMmzI8VmEbFA=
github.com/logzio/azure-monitor-metrics-receiver v1.0.2/go.mod h1:yJGdECqN75b4r4SXLwNkeeZoN/rPVKcfJLfixQw1hZc=
github.com/logzio/azure-monitor-metrics-receiver v1.1.0 h1:L2LU/jWTOFibZeSKUeEDBdPY6iFL1gkSE3A/9mnk/Ms=
github.com/logzio/azure-monitor-metrics-receiver v1.1.0/go.mod h1:6J/ZJtFGAuv3XvLWOWTefbi1BBHvnawNjUTGcx2qUG4=
github.com/loov/hrtime v1.0.1/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd0p0=
github.com/loov/hrtime v1.0.3/go.mod h1:yDY3Pwv2izeY4sq7YcPX/dtLwzg5NU1AxWuWxKwd0p0=
github.com/loov/hrtime/hrplot v1.0.2/go.mod h1:9t65xYn4d42ntjv40Wt5lbU72/VC5S0zGDgjC8kD5BU=
Expand Down
7 changes: 7 additions & 0 deletions plugins/inputs/azure_monitor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ resource target `resource_id` can be found under
**Overview**->**Essentials**->**JSON View** (link) in the Azure
portal for your application/service.

`cloud_option` defines the optional value for the API endpoints in case you
are using the solution to get the metrics from the Azure Sovereign Cloud
shipment e.g. AzureChina, AzureGovernment or AzurePublic.
The default value is AzurePublic

## More Information

To see a table of resource types and their metrics, please use this link:
Expand Down Expand Up @@ -77,6 +82,8 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
client_secret = "<<CLIENT_SECRET>>"
# can be found under Azure Active Directory->Properties
tenant_id = "<<TENANT_ID>>"
# Define the optional Azure cloud option e.g. AzureChina, AzureGovernment or AzurePublic. The default is AzurePublic.
# cloud_option = "AzurePublic"

# resource target #1 to collect metrics from
[[inputs.azure_monitor.resource_target]]
Expand Down
30 changes: 24 additions & 6 deletions plugins/inputs/azure_monitor/azure_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package azure_monitor
import (
_ "embed"
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"sync"

Expand All @@ -17,6 +19,7 @@ type AzureMonitor struct {
ClientID string `toml:"client_id"`
ClientSecret string `toml:"client_secret"`
TenantID string `toml:"tenant_id"`
CloudOption string `toml:"cloud_option,omitempty"`
ResourceTargets []*ResourceTarget `toml:"resource_target"`
ResourceGroupTargets []*ResourceGroupTarget `toml:"resource_group_target"`
SubscriptionTargets []*Resource `toml:"subscription_target"`
Expand Down Expand Up @@ -47,7 +50,8 @@ type Resource struct {
type azureClientsManager struct{}

type azureClientsCreator interface {
createAzureClients(subscriptionID string, clientID string, clientSecret string, tenantID string) (*receiver.AzureClients, error)
createAzureClients(subscriptionID string, clientID string, clientSecret string, tenantID string,
clientOptions azcore.ClientOptions) (*receiver.AzureClients, error)
}

//go:embed sample.conf
Expand All @@ -59,8 +63,20 @@ func (am *AzureMonitor) SampleConfig() string {

// Init is for setup, and validating config.
func (am *AzureMonitor) Init() error {
var clientOptions azcore.ClientOptions
switch cloudOption := am.CloudOption; cloudOption {
case "AzureChina":
clientOptions = azcore.ClientOptions{Cloud: cloud.AzureChina}
case "AzureGovernment":
clientOptions = azcore.ClientOptions{Cloud: cloud.AzureGovernment}
case "", "AzurePublic":
clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic}
default:
return fmt.Errorf("unknown cloud option: %s", cloudOption)
}

var err error
am.azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID)
am.azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)
if err != nil {
return err
}
Expand Down Expand Up @@ -150,7 +166,7 @@ func (am *AzureMonitor) setReceiver() error {

targets := receiver.NewTargets(resourceTargets, resourceGroupTargets, subscriptionTargets)
var err error
am.receiver, err = receiver.NewAzureMonitorMetricsReceiver(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, targets, am.azureClients)
am.receiver, err = receiver.NewAzureMonitorMetricsReceiver(am.SubscriptionID, targets, am.azureClients)
return err
}

Expand All @@ -159,16 +175,18 @@ func (acm *azureClientsManager) createAzureClients(
clientID string,
clientSecret string,
tenantID string,
clientOptions azcore.ClientOptions,
) (*receiver.AzureClients, error) {
if clientSecret != "" {
return receiver.CreateAzureClients(subscriptionID, clientID, clientSecret, tenantID)
return receiver.CreateAzureClients(subscriptionID, clientID, clientSecret, tenantID, receiver.WithAzureClientOptions(&clientOptions))
}

token, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{TenantID: tenantID})
token, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{TenantID: tenantID,
ClientOptions: clientOptions})
if err != nil {
return nil, fmt.Errorf("error creating Azure token: %w", err)
}
return receiver.CreateAzureClientsWithCreds(subscriptionID, token)
return receiver.CreateAzureClientsWithCreds(subscriptionID, token, receiver.WithAzureClientOptions(&clientOptions))
}

func init() {
Expand Down
156 changes: 105 additions & 51 deletions plugins/inputs/azure_monitor/azure_monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"os"
"testing"

Expand All @@ -25,7 +27,7 @@ type mockAzureMetricDefinitionsClient struct{}

type mockAzureMetricsClient struct{}

func (mam *mockAzureClientsManager) createAzureClients(_ string, _ string, _ string, _ string) (*receiver.AzureClients, error) {
func (mam *mockAzureClientsManager) createAzureClients(_ string, _ string, _ string, _ string, _ azcore.ClientOptions) (*receiver.AzureClients, error) {
return &receiver.AzureClients{
Ctx: context.Background(),
ResourcesClient: &mockAzureResourcesClient{},
Expand Down Expand Up @@ -612,51 +614,6 @@ func TestInit_NoSubscriptionID(t *testing.T) {
require.Error(t, am.Init())
}

func TestInit_NoClientID(t *testing.T) {
file, err := os.ReadFile("testdata/toml/init_no_client_id.toml")
require.NoError(t, err)
require.NotNil(t, file)
require.NotEmpty(t, file)

var am *AzureMonitor
require.NoError(t, toml.Unmarshal(file, &am))

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

require.Error(t, am.Init())
}

func TestInit_NoClientSecret(t *testing.T) {
file, err := os.ReadFile("testdata/toml/init_no_client_secret.toml")
require.NoError(t, err)
require.NotNil(t, file)
require.NotEmpty(t, file)

var am *AzureMonitor
require.NoError(t, toml.Unmarshal(file, &am))

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

require.Error(t, am.Init())
}

func TestInit_NoTenantID(t *testing.T) {
file, err := os.ReadFile("testdata/toml/init_no_tenant_id.toml")
require.NoError(t, err)
require.NotNil(t, file)
require.NotEmpty(t, file)

var am *AzureMonitor
require.NoError(t, toml.Unmarshal(file, &am))

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

require.Error(t, am.Init())
}

func TestInit_NoTargets(t *testing.T) {
file, err := os.ReadFile("testdata/toml/init_no_targets.toml")
require.NoError(t, err)
Expand Down Expand Up @@ -952,22 +909,20 @@ func TestGather_Success(t *testing.T) {

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))
for _, target := range am.ResourceTargets {
resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))
}

var clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic}

var azureClients *receiver.AzureClients
azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID)
azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)
require.NoError(t, err)
require.NotNil(t, azureClients)

am.receiver, err = receiver.NewAzureMonitorMetricsReceiver(
am.SubscriptionID,
am.ClientID,
am.ClientSecret,
am.TenantID,
receiver.NewTargets(resourceTargets, []*receiver.ResourceGroupTarget{}, []*receiver.Resource{}),
azureClients,
)
Expand Down Expand Up @@ -1028,3 +983,102 @@ func TestGather_Success(t *testing.T) {
acc.AssertContainsTaggedFields(t, expectedResource2Metric1Name, expectedResource2Metric1MetricFields, expectedResource2MetricsTags)
acc.AssertContainsTaggedFields(t, expectedResource3Metric1Name, expectedResource3Metric1MetricFields, expectedResource3MetricsTags)
}

func TestGather_China_Success(t *testing.T) {
file, err := os.ReadFile("testdata/toml/gather_success_cloud_option_china.toml")
require.NoError(t, err)
require.NotNil(t, file)
require.NotEmpty(t, file)

var am *AzureMonitor
require.NoError(t, toml.Unmarshal(file, &am))

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))
for _, target := range am.ResourceTargets {
resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))
}

var clientOptions = azcore.ClientOptions{Cloud: cloud.AzureChina}

var azureClients *receiver.AzureClients
azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)
require.NoError(t, err)
require.NotNil(t, azureClients)

am.receiver, err = receiver.NewAzureMonitorMetricsReceiver(
am.SubscriptionID,
receiver.NewTargets(resourceTargets, []*receiver.ResourceGroupTarget{}, []*receiver.Resource{}),
azureClients,
)
require.NoError(t, err)
require.NotNil(t, am.receiver)
}

func TestGather_Government_Success(t *testing.T) {
file, err := os.ReadFile("testdata/toml/gather_success_cloud_option_government.toml")
require.NoError(t, err)
require.NotNil(t, file)
require.NotEmpty(t, file)

var am *AzureMonitor
require.NoError(t, toml.Unmarshal(file, &am))

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))
for _, target := range am.ResourceTargets {
resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))
}

var clientOptions = azcore.ClientOptions{Cloud: cloud.AzureGovernment}

var azureClients *receiver.AzureClients
azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)
require.NoError(t, err)
require.NotNil(t, azureClients)

am.receiver, err = receiver.NewAzureMonitorMetricsReceiver(
am.SubscriptionID,
receiver.NewTargets(resourceTargets, []*receiver.ResourceGroupTarget{}, []*receiver.Resource{}),
azureClients,
)
require.NoError(t, err)
require.NotNil(t, am.receiver)
}

func TestGather_Public_Success(t *testing.T) {
file, err := os.ReadFile("testdata/toml/gather_success_cloud_option_public.toml")
require.NoError(t, err)
require.NotNil(t, file)
require.NotEmpty(t, file)

var am *AzureMonitor
require.NoError(t, toml.Unmarshal(file, &am))

am.Log = testutil.Logger{}
am.azureManager = &mockAzureClientsManager{}

resourceTargets := make([]*receiver.ResourceTarget, 0, len(am.ResourceTargets))
for _, target := range am.ResourceTargets {
resourceTargets = append(resourceTargets, receiver.NewResourceTarget(target.ResourceID, target.Metrics, target.Aggregations))
}

var clientOptions = azcore.ClientOptions{Cloud: cloud.AzurePublic}

var azureClients *receiver.AzureClients
azureClients, err = am.azureManager.createAzureClients(am.SubscriptionID, am.ClientID, am.ClientSecret, am.TenantID, clientOptions)
require.NoError(t, err)
require.NotNil(t, azureClients)

am.receiver, err = receiver.NewAzureMonitorMetricsReceiver(
am.SubscriptionID,
receiver.NewTargets(resourceTargets, []*receiver.ResourceGroupTarget{}, []*receiver.Resource{}),
azureClients,
)
require.NoError(t, err)
require.NotNil(t, am.receiver)
}
2 changes: 2 additions & 0 deletions plugins/inputs/azure_monitor/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
client_secret = "<<CLIENT_SECRET>>"
# can be found under Azure Active Directory->Properties
tenant_id = "<<TENANT_ID>>"
# Define the optional Azure cloud option e.g. AzureChina, AzureGovernment or AzurePublic. The default is AzurePublic.
# cloud_option = "AzurePublic"

# resource target #1 to collect metrics from
[[inputs.azure_monitor.resource_target]]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
subscription_id = "subscriptionID"
client_id = "clientID"
client_secret = "clientSecret"
tenant_id = "tenantID"
cloud_option = "AzureChina"

[[resource_target]]
resource_id = "resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1"
metrics = ["metric1", "metric2"]
aggregations = ["Total", "Maximum"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
subscription_id = "subscriptionID"
client_id = "clientID"
client_secret = "clientSecret"
tenant_id = "tenantID"
cloud_option = "AzureGovernment"

[[resource_target]]
resource_id = "resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1"
metrics = ["metric1", "metric2"]
aggregations = ["Total", "Maximum"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
subscription_id = "subscriptionID"
client_id = "clientID"
client_secret = "clientSecret"
tenant_id = "tenantID"
cloud_option = "AzurePublic"

[[resource_target]]
resource_id = "resourceGroups/resourceGroup1/providers/Microsoft.Test/type1/resource1"
metrics = ["metric1", "metric2"]
aggregations = ["Total", "Maximum"]

0 comments on commit 14aa8c6

Please sign in to comment.