2016-04-06 20:47:02 -07:00
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2016-11-21 06:51:36 -08:00
package azure
2016-04-06 20:47:02 -07:00
import (
2017-10-24 21:21:42 -07:00
"context"
2022-06-03 04:47:14 -07:00
"errors"
2016-04-06 20:47:02 -07:00
"fmt"
2023-11-21 03:59:17 -08:00
"math/rand"
2016-09-05 05:40:28 -07:00
"net"
2018-08-01 04:52:21 -07:00
"net/http"
2016-04-06 20:47:02 -07:00
"strings"
2019-01-18 00:55:47 -08:00
"sync"
2016-04-06 20:47:02 -07:00
"time"
2023-01-17 23:58:48 -08:00
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
2023-12-07 03:42:14 -08:00
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
2023-01-17 23:58:48 -08:00
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
2023-12-15 02:21:18 -08:00
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4"
2023-11-21 03:59:17 -08:00
cache "github.com/Code-Hex/go-generics-cache"
"github.com/Code-Hex/go-generics-cache/policy/lru"
2021-06-11 09:17:59 -07:00
"github.com/go-kit/log"
"github.com/go-kit/log/level"
2022-03-31 05:50:17 -07:00
"github.com/prometheus/client_golang/prometheus"
2018-01-11 07:10:25 -08:00
config_util "github.com/prometheus/common/config"
2023-11-21 03:59:17 -08:00
2016-04-06 20:47:02 -07:00
"github.com/prometheus/common/model"
2022-01-28 04:36:04 -08:00
"github.com/prometheus/common/version"
2019-03-25 03:54:22 -07:00
2020-08-20 05:48:26 -07:00
"github.com/prometheus/prometheus/discovery"
2019-03-25 03:54:22 -07:00
"github.com/prometheus/prometheus/discovery/refresh"
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
"github.com/prometheus/prometheus/discovery/targetgroup"
2016-04-06 20:47:02 -07:00
"github.com/prometheus/prometheus/util/strutil"
)
const (
azureLabel = model . MetaLabelPrefix + "azure_"
2018-12-07 01:40:45 -08:00
azureLabelSubscriptionID = azureLabel + "subscription_id"
azureLabelTenantID = azureLabel + "tenant_id"
2016-04-06 20:47:02 -07:00
azureLabelMachineID = azureLabel + "machine_id"
azureLabelMachineResourceGroup = azureLabel + "machine_resource_group"
azureLabelMachineName = azureLabel + "machine_name"
2021-07-25 09:34:32 -07:00
azureLabelMachineComputerName = azureLabel + "machine_computer_name"
2018-02-19 07:40:57 -08:00
azureLabelMachineOSType = azureLabel + "machine_os_type"
2016-04-06 20:47:02 -07:00
azureLabelMachineLocation = azureLabel + "machine_location"
azureLabelMachinePrivateIP = azureLabel + "machine_private_ip"
2019-04-17 08:05:44 -07:00
azureLabelMachinePublicIP = azureLabel + "machine_public_ip"
2016-04-06 20:47:02 -07:00
azureLabelMachineTag = azureLabel + "machine_tag_"
2018-08-01 04:52:21 -07:00
azureLabelMachineScaleSet = azureLabel + "machine_scale_set"
2022-12-16 10:14:35 -08:00
azureLabelMachineSize = azureLabel + "machine_size"
2018-12-19 02:03:33 -08:00
authMethodOAuth = "OAuth"
2024-03-16 04:06:57 -07:00
authMethodSDK = "SDK"
2018-12-19 02:03:33 -08:00
authMethodManagedIdentity = "ManagedIdentity"
2016-04-06 20:47:02 -07:00
)
2022-01-28 04:36:04 -08:00
var (
userAgent = fmt . Sprintf ( "Prometheus/%s" , version . Version )
// DefaultSDConfig is the default Azure SD configuration.
DefaultSDConfig = SDConfig {
Port : 80 ,
RefreshInterval : model . Duration ( 5 * time . Minute ) ,
2023-01-17 23:58:48 -08:00
Environment : "AzurePublicCloud" ,
2022-01-28 04:36:04 -08:00
AuthenticationMethod : authMethodOAuth ,
HTTPClientConfig : config_util . DefaultHTTPClientConfig ,
}
)
2016-10-20 00:23:50 -07:00
2023-01-17 23:58:48 -08:00
var environments = map [ string ] cloud . Configuration {
"AZURECHINACLOUD" : cloud . AzureChina ,
"AZURECLOUD" : cloud . AzurePublic ,
"AZUREGERMANCLOUD" : cloud . AzurePublic ,
"AZUREPUBLICCLOUD" : cloud . AzurePublic ,
"AZUREUSGOVERNMENT" : cloud . AzureGovernment ,
"AZUREUSGOVERNMENTCLOUD" : cloud . AzureGovernment ,
}
// CloudConfigurationFromName returns cloud configuration based on the common name specified.
func CloudConfigurationFromName ( name string ) ( cloud . Configuration , error ) {
name = strings . ToUpper ( name )
env , ok := environments [ name ]
if ! ok {
2023-12-13 04:38:16 -08:00
return env , fmt . Errorf ( "there is no cloud configuration matching the name %q" , name )
2023-01-17 23:58:48 -08:00
}
return env , nil
}
2020-08-20 05:48:26 -07:00
func init ( ) {
discovery . RegisterConfig ( & SDConfig { } )
}
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
// SDConfig is the configuration for Azure based service discovery.
type SDConfig struct {
2018-12-19 02:03:33 -08:00
Environment string ` yaml:"environment,omitempty" `
Port int ` yaml:"port" `
SubscriptionID string ` yaml:"subscription_id" `
TenantID string ` yaml:"tenant_id,omitempty" `
ClientID string ` yaml:"client_id,omitempty" `
ClientSecret config_util . Secret ` yaml:"client_secret,omitempty" `
RefreshInterval model . Duration ` yaml:"refresh_interval,omitempty" `
AuthenticationMethod string ` yaml:"authentication_method,omitempty" `
2022-03-28 16:21:23 -07:00
ResourceGroup string ` yaml:"resource_group,omitempty" `
2021-10-20 14:09:58 -07:00
HTTPClientConfig config_util . HTTPClientConfig ` yaml:",inline" `
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
}
2024-01-23 07:53:55 -08:00
// NewDiscovererMetrics implements discovery.Config.
func ( * SDConfig ) NewDiscovererMetrics ( reg prometheus . Registerer , rmi discovery . RefreshMetricsInstantiator ) discovery . DiscovererMetrics {
return newDiscovererMetrics ( reg , rmi )
}
2020-08-20 05:48:26 -07:00
// Name returns the name of the Config.
func ( * SDConfig ) Name ( ) string { return "azure" }
// NewDiscoverer returns a Discoverer for the Config.
func ( c * SDConfig ) NewDiscoverer ( opts discovery . DiscovererOptions ) ( discovery . Discoverer , error ) {
2024-01-23 07:53:55 -08:00
return NewDiscovery ( c , opts . Logger , opts . Metrics )
2020-08-20 05:48:26 -07:00
}
2018-11-29 07:47:59 -08:00
func validateAuthParam ( param , name string ) error {
if len ( param ) == 0 {
2022-06-03 04:47:14 -07:00
return fmt . Errorf ( "azure SD configuration requires a %s" , name )
2018-11-29 07:47:59 -08:00
}
return nil
}
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func ( c * SDConfig ) UnmarshalYAML ( unmarshal func ( interface { } ) error ) error {
* c = DefaultSDConfig
type plain SDConfig
err := unmarshal ( ( * plain ) ( c ) )
if err != nil {
return err
}
2018-11-29 07:47:59 -08:00
if err = validateAuthParam ( c . SubscriptionID , "subscription_id" ) ; err != nil {
return err
}
2018-12-19 02:03:33 -08:00
if c . AuthenticationMethod == authMethodOAuth {
if err = validateAuthParam ( c . TenantID , "tenant_id" ) ; err != nil {
return err
}
if err = validateAuthParam ( c . ClientID , "client_id" ) ; err != nil {
return err
}
if err = validateAuthParam ( string ( c . ClientSecret ) , "client_secret" ) ; err != nil {
return err
}
2018-11-29 07:47:59 -08:00
}
2018-12-19 02:03:33 -08:00
2024-03-16 04:06:57 -07:00
if c . AuthenticationMethod != authMethodOAuth && c . AuthenticationMethod != authMethodManagedIdentity && c . AuthenticationMethod != authMethodSDK {
return fmt . Errorf ( "unknown authentication_type %q. Supported types are %q, %q or %q" , c . AuthenticationMethod , authMethodOAuth , authMethodManagedIdentity , authMethodSDK )
2018-03-05 11:27:54 -08:00
}
2018-12-19 02:03:33 -08:00
2023-09-07 23:30:18 -07:00
return c . HTTPClientConfig . Validate ( )
Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
2017-12-29 12:01:34 -08:00
}
2017-03-16 16:29:47 -07:00
type Discovery struct {
2019-03-25 03:54:22 -07:00
* refresh . Discovery
2024-01-23 07:53:55 -08:00
logger log . Logger
cfg * SDConfig
port int
cache * cache . Cache [ string , * armnetwork . Interface ]
metrics * azureMetrics
2016-04-06 20:47:02 -07:00
}
2016-11-21 06:51:36 -08:00
// NewDiscovery returns a new AzureDiscovery which periodically refreshes its targets.
2024-01-23 07:53:55 -08:00
func NewDiscovery ( cfg * SDConfig , logger log . Logger , metrics discovery . DiscovererMetrics ) ( * Discovery , error ) {
m , ok := metrics . ( * azureMetrics )
if ! ok {
return nil , fmt . Errorf ( "invalid discovery metrics type" )
}
2017-08-11 11:45:52 -07:00
if logger == nil {
logger = log . NewNopLogger ( )
}
2023-11-21 03:59:17 -08:00
l := cache . New ( cache . AsLRU [ string , * armnetwork . Interface ] ( lru . WithCapacity ( 5000 ) ) )
2019-03-25 03:54:22 -07:00
d := & Discovery {
2024-01-23 07:53:55 -08:00
cfg : cfg ,
port : cfg . Port ,
logger : logger ,
cache : l ,
metrics : m ,
2016-04-06 20:47:02 -07:00
}
2023-11-21 03:59:17 -08:00
2019-03-25 03:54:22 -07:00
d . Discovery = refresh . NewDiscovery (
2023-10-23 06:55:36 -07:00
refresh . Options {
2024-01-23 07:53:55 -08:00
Logger : logger ,
Mech : "azure" ,
Interval : time . Duration ( cfg . RefreshInterval ) ,
RefreshF : d . refresh ,
MetricsInstantiator : m . refreshMetrics ,
2023-10-23 06:55:36 -07:00
} ,
2019-03-25 03:54:22 -07:00
)
2023-11-21 03:59:17 -08:00
2023-10-23 06:55:36 -07:00
return d , nil
2016-04-06 20:47:02 -07:00
}
2024-03-08 06:41:26 -08:00
type client interface {
getVMs ( ctx context . Context , resourceGroup string ) ( [ ] virtualMachine , error )
getScaleSets ( ctx context . Context , resourceGroup string ) ( [ ] armcompute . VirtualMachineScaleSet , error )
getScaleSetVMs ( ctx context . Context , scaleSet armcompute . VirtualMachineScaleSet ) ( [ ] virtualMachine , error )
getVMNetworkInterfaceByID ( ctx context . Context , networkInterfaceID string ) ( * armnetwork . Interface , error )
getVMScaleSetVMNetworkInterfaceByID ( ctx context . Context , networkInterfaceID , scaleSetName , instanceID string ) ( * armnetwork . Interface , error )
}
2016-04-06 20:47:02 -07:00
// azureClient represents multiple Azure Resource Manager providers.
type azureClient struct {
2023-01-17 23:58:48 -08:00
nic * armnetwork . InterfacesClient
vm * armcompute . VirtualMachinesClient
vmss * armcompute . VirtualMachineScaleSetsClient
vmssvm * armcompute . VirtualMachineScaleSetVMsClient
logger log . Logger
2016-04-06 20:47:02 -07:00
}
2024-03-08 06:41:26 -08:00
var _ client = & azureClient { }
2016-04-06 20:47:02 -07:00
// createAzureClient is a helper function for creating an Azure compute client to ARM.
2024-03-08 06:41:26 -08:00
func createAzureClient ( cfg SDConfig , logger log . Logger ) ( client , error ) {
2023-01-17 23:58:48 -08:00
cloudConfiguration , err := CloudConfigurationFromName ( cfg . Environment )
2018-09-04 08:55:40 -07:00
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2018-09-04 08:55:40 -07:00
}
2016-04-06 20:47:02 -07:00
var c azureClient
2024-03-08 06:41:26 -08:00
c . logger = logger
2018-12-19 02:03:33 -08:00
2023-01-17 23:58:48 -08:00
telemetry := policy . TelemetryOptions {
ApplicationID : userAgent ,
}
2018-12-19 02:03:33 -08:00
2023-01-17 23:58:48 -08:00
credential , err := newCredential ( cfg , policy . ClientOptions {
Cloud : cloudConfiguration ,
Telemetry : telemetry ,
} )
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2016-04-06 20:47:02 -07:00
}
2021-10-20 14:09:58 -07:00
client , err := config_util . NewClientFromConfig ( cfg . HTTPClientConfig , "azure_sd" )
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2021-10-20 14:09:58 -07:00
}
2023-01-17 23:58:48 -08:00
options := & arm . ClientOptions {
ClientOptions : policy . ClientOptions {
Transport : client ,
Cloud : cloudConfiguration ,
Telemetry : telemetry ,
} ,
}
2018-09-04 08:55:40 -07:00
2023-01-17 23:58:48 -08:00
c . vm , err = armcompute . NewVirtualMachinesClient ( cfg . SubscriptionID , credential , options )
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2023-01-17 23:58:48 -08:00
}
2016-04-06 20:47:02 -07:00
2023-01-17 23:58:48 -08:00
c . nic , err = armnetwork . NewInterfacesClient ( cfg . SubscriptionID , credential , options )
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2023-01-17 23:58:48 -08:00
}
2016-04-06 20:47:02 -07:00
2023-01-17 23:58:48 -08:00
c . vmss , err = armcompute . NewVirtualMachineScaleSetsClient ( cfg . SubscriptionID , credential , options )
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2023-01-17 23:58:48 -08:00
}
2018-08-01 04:52:21 -07:00
2023-01-17 23:58:48 -08:00
c . vmssvm , err = armcompute . NewVirtualMachineScaleSetVMsClient ( cfg . SubscriptionID , credential , options )
if err != nil {
2024-03-08 06:41:26 -08:00
return & azureClient { } , err
2023-01-17 23:58:48 -08:00
}
2018-08-01 04:52:21 -07:00
2024-03-08 06:41:26 -08:00
return & c , nil
2016-04-06 20:47:02 -07:00
}
2023-01-17 23:58:48 -08:00
func newCredential ( cfg SDConfig , policyClientOptions policy . ClientOptions ) ( azcore . TokenCredential , error ) {
var credential azcore . TokenCredential
switch cfg . AuthenticationMethod {
case authMethodManagedIdentity :
options := & azidentity . ManagedIdentityCredentialOptions { ClientOptions : policyClientOptions , ID : azidentity . ClientID ( cfg . ClientID ) }
managedIdentityCredential , err := azidentity . NewManagedIdentityCredential ( options )
if err != nil {
return nil , err
}
credential = azcore . TokenCredential ( managedIdentityCredential )
case authMethodOAuth :
options := & azidentity . ClientSecretCredentialOptions { ClientOptions : policyClientOptions }
secretCredential , err := azidentity . NewClientSecretCredential ( cfg . TenantID , cfg . ClientID , string ( cfg . ClientSecret ) , options )
if err != nil {
return nil , err
}
credential = azcore . TokenCredential ( secretCredential )
2024-03-16 04:06:57 -07:00
case authMethodSDK :
options := & azidentity . DefaultAzureCredentialOptions { ClientOptions : policyClientOptions }
if len ( cfg . TenantID ) != 0 {
options . TenantID = cfg . TenantID
}
sdkCredential , err := azidentity . NewDefaultAzureCredential ( options )
if err != nil {
return nil , err
}
credential = azcore . TokenCredential ( sdkCredential )
2023-01-17 23:58:48 -08:00
}
return credential , nil
2016-04-06 20:47:02 -07:00
}
2023-10-03 13:09:25 -07:00
// virtualMachine represents an Azure virtual machine (which can also be created by a VMSS).
2018-08-01 04:52:21 -07:00
type virtualMachine struct {
2019-03-15 09:18:37 -07:00
ID string
Name string
2021-07-25 09:34:32 -07:00
ComputerName string
2019-03-15 09:18:37 -07:00
Type string
Location string
OsType string
ScaleSet string
2023-12-13 04:38:16 -08:00
InstanceID string
2019-03-15 09:18:37 -07:00
Tags map [ string ] * string
NetworkInterfaces [ ] string
2022-12-16 10:14:35 -08:00
Size string
2018-08-01 04:52:21 -07:00
}
2016-04-06 20:47:02 -07:00
// Create a new azureResource object from an ID string.
2023-01-17 23:58:48 -08:00
func newAzureResourceFromID ( id string , logger log . Logger ) ( * arm . ResourceID , error ) {
if logger == nil {
logger = log . NewNopLogger ( )
}
resourceID , err := arm . ParseResourceID ( id )
if err != nil {
err := fmt . Errorf ( "invalid ID '%s': %w" , id , err )
2017-08-11 11:45:52 -07:00
level . Error ( logger ) . Log ( "err" , err )
2023-01-17 23:58:48 -08:00
return & arm . ResourceID { } , err
2016-04-06 20:47:02 -07:00
}
2023-01-17 23:58:48 -08:00
return resourceID , nil
2016-04-06 20:47:02 -07:00
}
2019-03-25 03:54:22 -07:00
func ( d * Discovery ) refresh ( ctx context . Context ) ( [ ] * targetgroup . Group , error ) {
2017-08-11 11:45:52 -07:00
defer level . Debug ( d . logger ) . Log ( "msg" , "Azure discovery completed" )
2024-03-08 06:41:26 -08:00
client , err := createAzureClient ( * d . cfg , d . logger )
2016-04-06 20:47:02 -07:00
if err != nil {
2024-01-23 07:53:55 -08:00
d . metrics . failuresCount . Inc ( )
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "could not create Azure client: %w" , err )
2016-04-06 20:47:02 -07:00
}
2022-03-28 16:21:23 -07:00
machines , err := client . getVMs ( ctx , d . cfg . ResourceGroup )
2016-04-06 20:47:02 -07:00
if err != nil {
2024-01-23 07:53:55 -08:00
d . metrics . failuresCount . Inc ( )
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "could not get virtual machines: %w" , err )
2016-04-06 20:47:02 -07:00
}
2018-08-01 04:52:21 -07:00
level . Debug ( d . logger ) . Log ( "msg" , "Found virtual machines during Azure discovery." , "count" , len ( machines ) )
// Load the vms managed by scale sets.
2022-03-28 16:21:23 -07:00
scaleSets , err := client . getScaleSets ( ctx , d . cfg . ResourceGroup )
2018-08-01 04:52:21 -07:00
if err != nil {
2024-01-23 07:53:55 -08:00
d . metrics . failuresCount . Inc ( )
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "could not get virtual machine scale sets: %w" , err )
2018-08-01 04:52:21 -07:00
}
for _ , scaleSet := range scaleSets {
2019-01-28 10:30:29 -08:00
scaleSetVms , err := client . getScaleSetVMs ( ctx , scaleSet )
2016-04-06 20:47:02 -07:00
if err != nil {
2024-01-23 07:53:55 -08:00
d . metrics . failuresCount . Inc ( )
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "could not get virtual machine scale set vms: %w" , err )
2016-04-06 20:47:02 -07:00
}
2018-08-01 04:52:21 -07:00
machines = append ( machines , scaleSetVms ... )
2016-04-06 20:47:02 -07:00
}
// We have the slice of machines. Now turn them into targets.
// Doing them in go routines because the network interface calls are slow.
type target struct {
labelSet model . LabelSet
err error
}
2019-01-18 00:55:47 -08:00
var wg sync . WaitGroup
wg . Add ( len ( machines ) )
2016-04-06 20:47:02 -07:00
ch := make ( chan target , len ( machines ) )
2022-03-31 05:50:17 -07:00
for _ , vm := range machines {
go func ( vm virtualMachine ) {
2019-01-18 00:55:47 -08:00
defer wg . Done ( )
2024-03-08 06:07:57 -08:00
labelSet , err := d . vmToLabelSet ( ctx , client , vm )
ch <- target { labelSet : labelSet , err : err }
2022-03-31 05:50:17 -07:00
} ( vm )
2016-04-06 20:47:02 -07:00
}
2019-01-18 00:55:47 -08:00
wg . Wait ( )
close ( ch )
2019-03-25 03:54:22 -07:00
var tg targetgroup . Group
2019-01-18 00:55:47 -08:00
for tgt := range ch {
2016-04-06 20:47:02 -07:00
if tgt . err != nil {
2024-01-23 07:53:55 -08:00
d . metrics . failuresCount . Inc ( )
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "unable to complete Azure service discovery: %w" , tgt . err )
2016-04-06 20:47:02 -07:00
}
if tgt . labelSet != nil {
tg . Targets = append ( tg . Targets , tgt . labelSet )
}
}
2019-03-25 03:54:22 -07:00
return [ ] * targetgroup . Group { & tg } , nil
2016-04-06 20:47:02 -07:00
}
2018-08-01 04:52:21 -07:00
2024-03-08 06:41:26 -08:00
func ( d * Discovery ) vmToLabelSet ( ctx context . Context , client client , vm virtualMachine ) ( model . LabelSet , error ) {
2024-03-08 06:07:57 -08:00
r , err := newAzureResourceFromID ( vm . ID , d . logger )
if err != nil {
return nil , err
}
labels := model . LabelSet {
azureLabelSubscriptionID : model . LabelValue ( d . cfg . SubscriptionID ) ,
azureLabelTenantID : model . LabelValue ( d . cfg . TenantID ) ,
azureLabelMachineID : model . LabelValue ( vm . ID ) ,
azureLabelMachineName : model . LabelValue ( vm . Name ) ,
azureLabelMachineComputerName : model . LabelValue ( vm . ComputerName ) ,
azureLabelMachineOSType : model . LabelValue ( vm . OsType ) ,
azureLabelMachineLocation : model . LabelValue ( vm . Location ) ,
azureLabelMachineResourceGroup : model . LabelValue ( r . ResourceGroupName ) ,
azureLabelMachineSize : model . LabelValue ( vm . Size ) ,
}
if vm . ScaleSet != "" {
labels [ azureLabelMachineScaleSet ] = model . LabelValue ( vm . ScaleSet )
}
for k , v := range vm . Tags {
name := strutil . SanitizeLabelName ( k )
labels [ azureLabelMachineTag + model . LabelName ( name ) ] = model . LabelValue ( * v )
}
// Get the IP address information via separate call to the network provider.
for _ , nicID := range vm . NetworkInterfaces {
var networkInterface * armnetwork . Interface
if v , ok := d . getFromCache ( nicID ) ; ok {
networkInterface = v
d . metrics . cacheHitCount . Add ( 1 )
} else {
if vm . ScaleSet == "" {
networkInterface , err = client . getVMNetworkInterfaceByID ( ctx , nicID )
} else {
networkInterface , err = client . getVMScaleSetVMNetworkInterfaceByID ( ctx , nicID , vm . ScaleSet , vm . InstanceID )
}
if err != nil {
if errors . Is ( err , errorNotFound ) {
level . Warn ( d . logger ) . Log ( "msg" , "Network interface does not exist" , "name" , nicID , "err" , err )
} else {
return nil , err
}
// Get out of this routine because we cannot continue without a network interface.
return nil , nil
}
// Continue processing with the network interface
d . addToCache ( nicID , networkInterface )
}
if networkInterface . Properties == nil {
continue
}
// Unfortunately Azure does not return information on whether a VM is deallocated.
// This information is available via another API call however the Go SDK does not
// yet support this. On deallocated machines, this value happens to be nil so it
// is a cheap and easy way to determine if a machine is allocated or not.
if networkInterface . Properties . Primary == nil {
level . Debug ( d . logger ) . Log ( "msg" , "Skipping deallocated virtual machine" , "machine" , vm . Name )
return nil , nil
}
if * networkInterface . Properties . Primary {
for _ , ip := range networkInterface . Properties . IPConfigurations {
// IPAddress is a field defined in PublicIPAddressPropertiesFormat,
// therefore we need to validate that both are not nil.
if ip . Properties != nil && ip . Properties . PublicIPAddress != nil && ip . Properties . PublicIPAddress . Properties != nil && ip . Properties . PublicIPAddress . Properties . IPAddress != nil {
labels [ azureLabelMachinePublicIP ] = model . LabelValue ( * ip . Properties . PublicIPAddress . Properties . IPAddress )
}
if ip . Properties != nil && ip . Properties . PrivateIPAddress != nil {
labels [ azureLabelMachinePrivateIP ] = model . LabelValue ( * ip . Properties . PrivateIPAddress )
address := net . JoinHostPort ( * ip . Properties . PrivateIPAddress , fmt . Sprintf ( "%d" , d . port ) )
labels [ model . AddressLabel ] = model . LabelValue ( address )
return labels , nil
}
// If we made it here, we don't have a private IP which should be impossible.
// Return an empty target and error to ensure an all or nothing situation.
return nil , fmt . Errorf ( "unable to find a private IP for VM %s" , vm . Name )
}
}
}
// TODO: Should we say something at this point?
return nil , nil
}
2022-03-28 16:21:23 -07:00
func ( client * azureClient ) getVMs ( ctx context . Context , resourceGroup string ) ( [ ] virtualMachine , error ) {
2018-09-04 08:55:40 -07:00
var vms [ ] virtualMachine
2022-03-28 16:21:23 -07:00
if len ( resourceGroup ) == 0 {
2023-01-17 23:58:48 -08:00
pager := client . vm . NewListAllPager ( nil )
for pager . More ( ) {
nextResult , err := pager . NextPage ( ctx )
if err != nil {
return nil , fmt . Errorf ( "could not list virtual machines: %w" , err )
}
for _ , vm := range nextResult . Value {
vms = append ( vms , mapFromVM ( * vm ) )
}
2018-08-01 04:52:21 -07:00
}
2023-01-17 23:58:48 -08:00
} else {
pager := client . vm . NewListPager ( resourceGroup , nil )
for pager . More ( ) {
nextResult , err := pager . NextPage ( ctx )
if err != nil {
return nil , fmt . Errorf ( "could not list virtual machines: %w" , err )
}
for _ , vm := range nextResult . Value {
vms = append ( vms , mapFromVM ( * vm ) )
}
2019-03-20 02:03:47 -07:00
}
2018-08-01 04:52:21 -07:00
}
return vms , nil
}
2023-01-17 23:58:48 -08:00
func ( client * azureClient ) getScaleSets ( ctx context . Context , resourceGroup string ) ( [ ] armcompute . VirtualMachineScaleSet , error ) {
var scaleSets [ ] armcompute . VirtualMachineScaleSet
2022-03-28 16:21:23 -07:00
if len ( resourceGroup ) == 0 {
2023-01-17 23:58:48 -08:00
pager := client . vmss . NewListAllPager ( nil )
for pager . More ( ) {
nextResult , err := pager . NextPage ( ctx )
if err != nil {
return nil , fmt . Errorf ( "could not list virtual machine scale sets: %w" , err )
}
for _ , vmss := range nextResult . Value {
scaleSets = append ( scaleSets , * vmss )
}
2022-03-28 16:21:23 -07:00
}
} else {
2023-01-17 23:58:48 -08:00
pager := client . vmss . NewListPager ( resourceGroup , nil )
for pager . More ( ) {
nextResult , err := pager . NextPage ( ctx )
if err != nil {
return nil , fmt . Errorf ( "could not list virtual machine scale sets: %w" , err )
}
for _ , vmss := range nextResult . Value {
scaleSets = append ( scaleSets , * vmss )
}
2018-08-01 04:52:21 -07:00
}
}
return scaleSets , nil
}
2023-01-17 23:58:48 -08:00
func ( client * azureClient ) getScaleSetVMs ( ctx context . Context , scaleSet armcompute . VirtualMachineScaleSet ) ( [ ] virtualMachine , error ) {
2018-09-04 08:55:40 -07:00
var vms [ ] virtualMachine
2021-10-22 01:06:44 -07:00
// TODO do we really need to fetch the resourcegroup this way?
2023-01-17 23:58:48 -08:00
r , err := newAzureResourceFromID ( * scaleSet . ID , client . logger )
2018-08-01 04:52:21 -07:00
if err != nil {
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "could not parse scale set ID: %w" , err )
2018-08-01 04:52:21 -07:00
}
2023-01-17 23:58:48 -08:00
pager := client . vmssvm . NewListPager ( r . ResourceGroupName , * ( scaleSet . Name ) , nil )
for pager . More ( ) {
nextResult , err := pager . NextPage ( ctx )
2019-03-20 02:03:47 -07:00
if err != nil {
2022-06-03 04:47:14 -07:00
return nil , fmt . Errorf ( "could not list virtual machine scale set vms: %w" , err )
2019-03-20 02:03:47 -07:00
}
2023-01-17 23:58:48 -08:00
for _ , vmssvm := range nextResult . Value {
vms = append ( vms , mapFromVMScaleSetVM ( * vmssvm , * scaleSet . Name ) )
}
2018-08-01 04:52:21 -07:00
}
return vms , nil
}
2023-01-17 23:58:48 -08:00
func mapFromVM ( vm armcompute . VirtualMachine ) virtualMachine {
2024-02-14 08:59:01 -08:00
var osType string
2018-08-02 02:10:17 -07:00
tags := map [ string ] * string { }
2019-03-15 09:18:37 -07:00
networkInterfaces := [ ] string { }
2021-07-28 06:53:17 -07:00
var computerName string
2022-12-16 10:14:35 -08:00
var size string
2018-08-02 02:10:17 -07:00
if vm . Tags != nil {
2019-01-28 10:30:29 -08:00
tags = vm . Tags
2018-08-02 02:10:17 -07:00
}
2018-08-01 04:52:21 -07:00
2023-01-17 23:58:48 -08:00
if vm . Properties != nil {
2024-02-14 08:59:01 -08:00
if vm . Properties . StorageProfile != nil &&
vm . Properties . StorageProfile . OSDisk != nil &&
vm . Properties . StorageProfile . OSDisk . OSType != nil {
osType = string ( * vm . Properties . StorageProfile . OSDisk . OSType )
}
2023-01-17 23:58:48 -08:00
if vm . Properties . NetworkProfile != nil {
for _ , vmNIC := range vm . Properties . NetworkProfile . NetworkInterfaces {
networkInterfaces = append ( networkInterfaces , * vmNIC . ID )
}
2019-03-15 09:18:37 -07:00
}
2023-01-17 23:58:48 -08:00
if vm . Properties . OSProfile != nil && vm . Properties . OSProfile . ComputerName != nil {
computerName = * ( vm . Properties . OSProfile . ComputerName )
2022-12-16 10:14:35 -08:00
}
2023-01-17 23:58:48 -08:00
if vm . Properties . HardwareProfile != nil {
size = string ( * vm . Properties . HardwareProfile . VMSize )
2022-12-16 10:14:35 -08:00
}
2021-07-28 06:53:17 -07:00
}
2018-08-01 04:52:21 -07:00
return virtualMachine {
2019-03-15 09:18:37 -07:00
ID : * ( vm . ID ) ,
Name : * ( vm . Name ) ,
2021-07-28 06:53:17 -07:00
ComputerName : computerName ,
2019-03-15 09:18:37 -07:00
Type : * ( vm . Type ) ,
Location : * ( vm . Location ) ,
OsType : osType ,
ScaleSet : "" ,
Tags : tags ,
NetworkInterfaces : networkInterfaces ,
2022-12-16 10:14:35 -08:00
Size : size ,
2018-08-01 04:52:21 -07:00
}
}
2023-01-17 23:58:48 -08:00
func mapFromVMScaleSetVM ( vm armcompute . VirtualMachineScaleSetVM , scaleSetName string ) virtualMachine {
2024-02-14 08:59:01 -08:00
var osType string
2018-08-02 02:10:17 -07:00
tags := map [ string ] * string { }
2019-03-15 09:18:37 -07:00
networkInterfaces := [ ] string { }
2021-07-28 06:53:17 -07:00
var computerName string
2022-12-16 10:14:35 -08:00
var size string
2018-08-02 02:10:17 -07:00
if vm . Tags != nil {
2019-01-28 10:30:29 -08:00
tags = vm . Tags
2018-08-02 02:10:17 -07:00
}
2018-08-01 04:52:21 -07:00
2023-01-17 23:58:48 -08:00
if vm . Properties != nil {
2024-02-14 08:59:01 -08:00
if vm . Properties . StorageProfile != nil &&
vm . Properties . StorageProfile . OSDisk != nil &&
vm . Properties . StorageProfile . OSDisk . OSType != nil {
osType = string ( * vm . Properties . StorageProfile . OSDisk . OSType )
}
2023-01-17 23:58:48 -08:00
if vm . Properties . NetworkProfile != nil {
for _ , vmNIC := range vm . Properties . NetworkProfile . NetworkInterfaces {
networkInterfaces = append ( networkInterfaces , * vmNIC . ID )
}
2019-03-15 09:18:37 -07:00
}
2023-01-17 23:58:48 -08:00
if vm . Properties . OSProfile != nil && vm . Properties . OSProfile . ComputerName != nil {
computerName = * ( vm . Properties . OSProfile . ComputerName )
2022-12-16 10:14:35 -08:00
}
2023-01-17 23:58:48 -08:00
if vm . Properties . HardwareProfile != nil {
size = string ( * vm . Properties . HardwareProfile . VMSize )
2022-12-16 10:14:35 -08:00
}
2021-07-28 06:53:17 -07:00
}
2018-08-01 04:52:21 -07:00
return virtualMachine {
2019-03-15 09:18:37 -07:00
ID : * ( vm . ID ) ,
Name : * ( vm . Name ) ,
2021-07-28 06:53:17 -07:00
ComputerName : computerName ,
2019-03-15 09:18:37 -07:00
Type : * ( vm . Type ) ,
Location : * ( vm . Location ) ,
OsType : osType ,
ScaleSet : scaleSetName ,
2023-12-13 04:38:16 -08:00
InstanceID : * ( vm . InstanceID ) ,
2019-03-15 09:18:37 -07:00
Tags : tags ,
NetworkInterfaces : networkInterfaces ,
2022-12-16 10:14:35 -08:00
Size : size ,
2018-08-01 04:52:21 -07:00
}
}
2022-03-31 05:50:17 -07:00
var errorNotFound = errors . New ( "network interface does not exist" )
2023-12-13 04:38:16 -08:00
// getVMNetworkInterfaceByID gets the network interface.
2022-03-31 05:50:17 -07:00
// If a 404 is returned from the Azure API, `errorNotFound` is returned.
2023-12-13 04:38:16 -08:00
func ( client * azureClient ) getVMNetworkInterfaceByID ( ctx context . Context , networkInterfaceID string ) ( * armnetwork . Interface , error ) {
2023-01-17 23:58:48 -08:00
r , err := newAzureResourceFromID ( networkInterfaceID , client . logger )
2018-08-01 04:52:21 -07:00
if err != nil {
2023-01-17 23:58:48 -08:00
return nil , fmt . Errorf ( "could not parse network interface ID: %w" , err )
2018-08-01 04:52:21 -07:00
}
2023-12-07 03:42:14 -08:00
resp , err := client . nic . Get ( ctx , r . ResourceGroupName , r . Name , & armnetwork . InterfacesClientGetOptions { Expand : to . Ptr ( "IPConfigurations/PublicIPAddress" ) } )
2018-08-01 04:52:21 -07:00
if err != nil {
2023-01-17 23:58:48 -08:00
var responseError * azcore . ResponseError
if errors . As ( err , & responseError ) && responseError . StatusCode == http . StatusNotFound {
2022-03-31 05:50:17 -07:00
return nil , errorNotFound
}
2023-12-13 04:38:16 -08:00
return nil , fmt . Errorf ( "failed to retrieve Interface %v with error: %w" , networkInterfaceID , err )
}
return & resp . Interface , nil
}
// getVMScaleSetVMNetworkInterfaceByID gets the network interface.
// If a 404 is returned from the Azure API, `errorNotFound` is returned.
func ( client * azureClient ) getVMScaleSetVMNetworkInterfaceByID ( ctx context . Context , networkInterfaceID , scaleSetName , instanceID string ) ( * armnetwork . Interface , error ) {
r , err := newAzureResourceFromID ( networkInterfaceID , client . logger )
if err != nil {
return nil , fmt . Errorf ( "could not parse network interface ID: %w" , err )
}
resp , err := client . nic . GetVirtualMachineScaleSetNetworkInterface ( ctx , r . ResourceGroupName , scaleSetName , instanceID , r . Name , & armnetwork . InterfacesClientGetVirtualMachineScaleSetNetworkInterfaceOptions { Expand : to . Ptr ( "IPConfigurations/PublicIPAddress" ) } )
if err != nil {
var responseError * azcore . ResponseError
if errors . As ( err , & responseError ) && responseError . StatusCode == http . StatusNotFound {
return nil , errorNotFound
}
return nil , fmt . Errorf ( "failed to retrieve Interface %v with error: %w" , networkInterfaceID , err )
2018-08-01 04:52:21 -07:00
}
2023-01-17 23:58:48 -08:00
return & resp . Interface , nil
2018-08-01 04:52:21 -07:00
}
2023-11-21 03:59:17 -08:00
2023-11-23 01:07:23 -08:00
// addToCache will add the network interface information for the specified nicID.
2023-11-21 03:59:17 -08:00
func ( d * Discovery ) addToCache ( nicID string , netInt * armnetwork . Interface ) {
random := rand . Int63n ( int64 ( time . Duration ( d . cfg . RefreshInterval * 3 ) . Seconds ( ) ) )
rs := time . Duration ( random ) * time . Second
exptime := time . Duration ( d . cfg . RefreshInterval * 10 ) + rs
d . cache . Set ( nicID , netInt , cache . WithExpiration ( exptime ) )
level . Debug ( d . logger ) . Log ( "msg" , "Adding nic" , "nic" , nicID , "time" , exptime . Seconds ( ) )
}
// getFromCache will get the network Interface for the specified nicID
2023-11-23 01:07:23 -08:00
// If the cache is disabled nothing will happen.
2023-11-21 03:59:17 -08:00
func ( d * Discovery ) getFromCache ( nicID string ) ( * armnetwork . Interface , bool ) {
net , found := d . cache . Get ( nicID )
return net , found
}