|
|
|
|
@ -23,11 +23,13 @@ import ( |
|
|
|
|
"sync" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-10-01/compute" |
|
|
|
|
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-10-01/network" |
|
|
|
|
"github.com/Azure/go-autorest/autorest" |
|
|
|
|
"github.com/Azure/go-autorest/autorest/adal" |
|
|
|
|
"github.com/Azure/go-autorest/autorest/azure" |
|
|
|
|
"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" |
|
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/azidentity" |
|
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4" |
|
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2" |
|
|
|
|
"github.com/go-kit/log" |
|
|
|
|
"github.com/go-kit/log/level" |
|
|
|
|
"github.com/prometheus/client_golang/prometheus" |
|
|
|
|
@ -68,7 +70,7 @@ var ( |
|
|
|
|
DefaultSDConfig = SDConfig{ |
|
|
|
|
Port: 80, |
|
|
|
|
RefreshInterval: model.Duration(5 * time.Minute), |
|
|
|
|
Environment: azure.PublicCloud.Name, |
|
|
|
|
Environment: "AzurePublicCloud", |
|
|
|
|
AuthenticationMethod: authMethodOAuth, |
|
|
|
|
HTTPClientConfig: config_util.DefaultHTTPClientConfig, |
|
|
|
|
} |
|
|
|
|
@ -80,6 +82,26 @@ var ( |
|
|
|
|
}) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
return env, fmt.Errorf("There is no cloud configuration matching the name %q", name) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return env, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func init() { |
|
|
|
|
discovery.RegisterConfig(&SDConfig{}) |
|
|
|
|
prometheus.MustRegister(failuresCount) |
|
|
|
|
@ -175,80 +197,88 @@ func NewDiscovery(cfg *SDConfig, logger log.Logger) *Discovery { |
|
|
|
|
|
|
|
|
|
// azureClient represents multiple Azure Resource Manager providers.
|
|
|
|
|
type azureClient struct { |
|
|
|
|
nic network.InterfacesClient |
|
|
|
|
vm compute.VirtualMachinesClient |
|
|
|
|
vmss compute.VirtualMachineScaleSetsClient |
|
|
|
|
vmssvm compute.VirtualMachineScaleSetVMsClient |
|
|
|
|
nic *armnetwork.InterfacesClient |
|
|
|
|
vm *armcompute.VirtualMachinesClient |
|
|
|
|
vmss *armcompute.VirtualMachineScaleSetsClient |
|
|
|
|
vmssvm *armcompute.VirtualMachineScaleSetVMsClient |
|
|
|
|
logger log.Logger |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// createAzureClient is a helper function for creating an Azure compute client to ARM.
|
|
|
|
|
func createAzureClient(cfg SDConfig) (azureClient, error) { |
|
|
|
|
env, err := azure.EnvironmentFromName(cfg.Environment) |
|
|
|
|
cloudConfiguration, err := CloudConfigurationFromName(cfg.Environment) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
activeDirectoryEndpoint := env.ActiveDirectoryEndpoint |
|
|
|
|
resourceManagerEndpoint := env.ResourceManagerEndpoint |
|
|
|
|
|
|
|
|
|
var c azureClient |
|
|
|
|
|
|
|
|
|
var spt *adal.ServicePrincipalToken |
|
|
|
|
|
|
|
|
|
switch cfg.AuthenticationMethod { |
|
|
|
|
case authMethodManagedIdentity: |
|
|
|
|
spt, err = adal.NewServicePrincipalTokenFromManagedIdentity(resourceManagerEndpoint, &adal.ManagedIdentityOptions{ClientID: cfg.ClientID}) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
case authMethodOAuth: |
|
|
|
|
oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, cfg.TenantID) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
telemetry := policy.TelemetryOptions{ |
|
|
|
|
ApplicationID: userAgent, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
spt, err = adal.NewServicePrincipalToken(*oauthConfig, cfg.ClientID, string(cfg.ClientSecret), resourceManagerEndpoint) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
credential, err := newCredential(cfg, policy.ClientOptions{ |
|
|
|
|
Cloud: cloudConfiguration, |
|
|
|
|
Telemetry: telemetry, |
|
|
|
|
}) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
client, err := config_util.NewClientFromConfig(cfg.HTTPClientConfig, "azure_sd") |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
sender := autorest.DecorateSender(client) |
|
|
|
|
preparer := autorest.WithUserAgent(userAgent) |
|
|
|
|
|
|
|
|
|
bearerAuthorizer := autorest.NewBearerAuthorizer(spt) |
|
|
|
|
options := &arm.ClientOptions{ |
|
|
|
|
ClientOptions: policy.ClientOptions{ |
|
|
|
|
Transport: client, |
|
|
|
|
Cloud: cloudConfiguration, |
|
|
|
|
Telemetry: telemetry, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.vm = compute.NewVirtualMachinesClientWithBaseURI(resourceManagerEndpoint, cfg.SubscriptionID) |
|
|
|
|
c.vm.Authorizer = bearerAuthorizer |
|
|
|
|
c.vm.Sender = sender |
|
|
|
|
c.vm.RequestInspector = preparer |
|
|
|
|
c.vm, err = armcompute.NewVirtualMachinesClient(cfg.SubscriptionID, credential, options) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.nic = network.NewInterfacesClientWithBaseURI(resourceManagerEndpoint, cfg.SubscriptionID) |
|
|
|
|
c.nic.Authorizer = bearerAuthorizer |
|
|
|
|
c.nic.Sender = sender |
|
|
|
|
c.nic.RequestInspector = preparer |
|
|
|
|
c.nic, err = armnetwork.NewInterfacesClient(cfg.SubscriptionID, credential, options) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.vmss = compute.NewVirtualMachineScaleSetsClientWithBaseURI(resourceManagerEndpoint, cfg.SubscriptionID) |
|
|
|
|
c.vmss.Authorizer = bearerAuthorizer |
|
|
|
|
c.vmss.Sender = sender |
|
|
|
|
c.vmss.RequestInspector = preparer |
|
|
|
|
c.vmss, err = armcompute.NewVirtualMachineScaleSetsClient(cfg.SubscriptionID, credential, options) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c.vmssvm = compute.NewVirtualMachineScaleSetVMsClientWithBaseURI(resourceManagerEndpoint, cfg.SubscriptionID) |
|
|
|
|
c.vmssvm.Authorizer = bearerAuthorizer |
|
|
|
|
c.vmssvm.Sender = sender |
|
|
|
|
c.vmssvm.RequestInspector = preparer |
|
|
|
|
c.vmssvm, err = armcompute.NewVirtualMachineScaleSetVMsClient(cfg.SubscriptionID, credential, options) |
|
|
|
|
if err != nil { |
|
|
|
|
return azureClient{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return c, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// azureResource represents a resource identifier in Azure.
|
|
|
|
|
type azureResource struct { |
|
|
|
|
Name string |
|
|
|
|
ResourceGroup string |
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
return credential, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// virtualMachine represents an Azure virtual machine (which can also be created by a VMSS)
|
|
|
|
|
@ -266,22 +296,17 @@ type virtualMachine struct { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create a new azureResource object from an ID string.
|
|
|
|
|
func newAzureResourceFromID(id string, logger log.Logger) (azureResource, error) { |
|
|
|
|
// Resource IDs have the following format.
|
|
|
|
|
// /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/PROVIDER/TYPE/NAME
|
|
|
|
|
// or if embedded resource then
|
|
|
|
|
// /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/PROVIDER/TYPE/NAME/TYPE/NAME
|
|
|
|
|
s := strings.Split(id, "/") |
|
|
|
|
if len(s) != 9 && len(s) != 11 { |
|
|
|
|
err := fmt.Errorf("invalid ID '%s'. Refusing to create azureResource", id) |
|
|
|
|
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) |
|
|
|
|
level.Error(logger).Log("err", err) |
|
|
|
|
return azureResource{}, err |
|
|
|
|
return &arm.ResourceID{}, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return azureResource{ |
|
|
|
|
Name: strings.ToLower(s[8]), |
|
|
|
|
ResourceGroup: strings.ToLower(s[4]), |
|
|
|
|
}, nil |
|
|
|
|
return resourceID, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { |
|
|
|
|
@ -292,6 +317,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { |
|
|
|
|
failuresCount.Inc() |
|
|
|
|
return nil, fmt.Errorf("could not create Azure client: %w", err) |
|
|
|
|
} |
|
|
|
|
client.logger = d.logger |
|
|
|
|
|
|
|
|
|
machines, err := client.getVMs(ctx, d.cfg.ResourceGroup) |
|
|
|
|
if err != nil { |
|
|
|
|
@ -344,7 +370,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { |
|
|
|
|
azureLabelMachineComputerName: model.LabelValue(vm.ComputerName), |
|
|
|
|
azureLabelMachineOSType: model.LabelValue(vm.OsType), |
|
|
|
|
azureLabelMachineLocation: model.LabelValue(vm.Location), |
|
|
|
|
azureLabelMachineResourceGroup: model.LabelValue(r.ResourceGroup), |
|
|
|
|
azureLabelMachineResourceGroup: model.LabelValue(r.ResourceGroupName), |
|
|
|
|
azureLabelMachineSize: model.LabelValue(vm.Size), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -370,7 +396,7 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if networkInterface.InterfacePropertiesFormat == nil { |
|
|
|
|
if networkInterface.Properties == nil { |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -378,21 +404,21 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { |
|
|
|
|
// 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.Primary == nil { |
|
|
|
|
if networkInterface.Properties.Primary == nil { |
|
|
|
|
level.Debug(d.logger).Log("msg", "Skipping deallocated virtual machine", "machine", vm.Name) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if *networkInterface.Primary { |
|
|
|
|
for _, ip := range *networkInterface.IPConfigurations { |
|
|
|
|
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.PublicIPAddress != nil && ip.PublicIPAddress.PublicIPAddressPropertiesFormat != nil && ip.PublicIPAddress.IPAddress != nil { |
|
|
|
|
labels[azureLabelMachinePublicIP] = model.LabelValue(*ip.PublicIPAddress.IPAddress) |
|
|
|
|
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.PrivateIPAddress != nil { |
|
|
|
|
labels[azureLabelMachinePrivateIP] = model.LabelValue(*ip.PrivateIPAddress) |
|
|
|
|
address := net.JoinHostPort(*ip.PrivateIPAddress, fmt.Sprintf("%d", d.port)) |
|
|
|
|
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) |
|
|
|
|
ch <- target{labelSet: labels, err: nil} |
|
|
|
|
return |
|
|
|
|
@ -427,93 +453,84 @@ func (d *Discovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { |
|
|
|
|
|
|
|
|
|
func (client *azureClient) getVMs(ctx context.Context, resourceGroup string) ([]virtualMachine, error) { |
|
|
|
|
var vms []virtualMachine |
|
|
|
|
var result compute.VirtualMachineListResultPage |
|
|
|
|
var err error |
|
|
|
|
if len(resourceGroup) == 0 { |
|
|
|
|
result, err = client.vm.ListAll(ctx) |
|
|
|
|
} else { |
|
|
|
|
result, err = client.vm.List(ctx, resourceGroup) |
|
|
|
|
} |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machines: %w", err) |
|
|
|
|
} |
|
|
|
|
for result.NotDone() { |
|
|
|
|
for _, vm := range result.Values() { |
|
|
|
|
vms = append(vms, mapFromVM(vm)) |
|
|
|
|
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)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
err = result.NextWithContext(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machines: %w", err) |
|
|
|
|
} 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)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return vms, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type VmssListResultPage interface { |
|
|
|
|
NextWithContext(ctx context.Context) (err error) |
|
|
|
|
NotDone() bool |
|
|
|
|
Values() []compute.VirtualMachineScaleSet |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (client *azureClient) getScaleSets(ctx context.Context, resourceGroup string) ([]compute.VirtualMachineScaleSet, error) { |
|
|
|
|
var scaleSets []compute.VirtualMachineScaleSet |
|
|
|
|
var result VmssListResultPage |
|
|
|
|
var err error |
|
|
|
|
func (client *azureClient) getScaleSets(ctx context.Context, resourceGroup string) ([]armcompute.VirtualMachineScaleSet, error) { |
|
|
|
|
var scaleSets []armcompute.VirtualMachineScaleSet |
|
|
|
|
if len(resourceGroup) == 0 { |
|
|
|
|
var rtn compute.VirtualMachineScaleSetListWithLinkResultPage |
|
|
|
|
rtn, err = client.vmss.ListAll(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machine scale sets: %w", err) |
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
result = &rtn |
|
|
|
|
} else { |
|
|
|
|
var rtn compute.VirtualMachineScaleSetListResultPage |
|
|
|
|
rtn, err = client.vmss.List(ctx, resourceGroup) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machine scale sets: %w", err) |
|
|
|
|
} |
|
|
|
|
result = &rtn |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for result.NotDone() { |
|
|
|
|
scaleSets = append(scaleSets, result.Values()...) |
|
|
|
|
err = result.NextWithContext(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machine scale sets: %w", err) |
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return scaleSets, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (client *azureClient) getScaleSetVMs(ctx context.Context, scaleSet compute.VirtualMachineScaleSet) ([]virtualMachine, error) { |
|
|
|
|
func (client *azureClient) getScaleSetVMs(ctx context.Context, scaleSet armcompute.VirtualMachineScaleSet) ([]virtualMachine, error) { |
|
|
|
|
var vms []virtualMachine |
|
|
|
|
// TODO do we really need to fetch the resourcegroup this way?
|
|
|
|
|
r, err := newAzureResourceFromID(*scaleSet.ID, nil) |
|
|
|
|
r, err := newAzureResourceFromID(*scaleSet.ID, client.logger) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not parse scale set ID: %w", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result, err := client.vmssvm.List(ctx, r.ResourceGroup, *(scaleSet.Name), "", "", "") |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machine scale set vms: %w", err) |
|
|
|
|
} |
|
|
|
|
for result.NotDone() { |
|
|
|
|
for _, vm := range result.Values() { |
|
|
|
|
vms = append(vms, mapFromVMScaleSetVM(vm, *scaleSet.Name)) |
|
|
|
|
} |
|
|
|
|
err = result.NextWithContext(ctx) |
|
|
|
|
pager := client.vmssvm.NewListPager(r.ResourceGroupName, *(scaleSet.Name), nil) |
|
|
|
|
for pager.More() { |
|
|
|
|
nextResult, err := pager.NextPage(ctx) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, fmt.Errorf("could not list virtual machine scale set vms: %w", err) |
|
|
|
|
} |
|
|
|
|
for _, vmssvm := range nextResult.Value { |
|
|
|
|
vms = append(vms, mapFromVMScaleSetVM(*vmssvm, *scaleSet.Name)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return vms, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func mapFromVM(vm compute.VirtualMachine) virtualMachine { |
|
|
|
|
osType := string(vm.StorageProfile.OsDisk.OsType) |
|
|
|
|
func mapFromVM(vm armcompute.VirtualMachine) virtualMachine { |
|
|
|
|
osType := string(*vm.Properties.StorageProfile.OSDisk.OSType) |
|
|
|
|
tags := map[string]*string{} |
|
|
|
|
networkInterfaces := []string{} |
|
|
|
|
var computerName string |
|
|
|
|
@ -523,18 +540,17 @@ func mapFromVM(vm compute.VirtualMachine) virtualMachine { |
|
|
|
|
tags = vm.Tags |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if vm.NetworkProfile != nil { |
|
|
|
|
for _, vmNIC := range *(vm.NetworkProfile.NetworkInterfaces) { |
|
|
|
|
networkInterfaces = append(networkInterfaces, *vmNIC.ID) |
|
|
|
|
if vm.Properties != nil { |
|
|
|
|
if vm.Properties.NetworkProfile != nil { |
|
|
|
|
for _, vmNIC := range vm.Properties.NetworkProfile.NetworkInterfaces { |
|
|
|
|
networkInterfaces = append(networkInterfaces, *vmNIC.ID) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if vm.VirtualMachineProperties != nil { |
|
|
|
|
if vm.VirtualMachineProperties.OsProfile != nil && vm.VirtualMachineProperties.OsProfile.ComputerName != nil { |
|
|
|
|
computerName = *(vm.VirtualMachineProperties.OsProfile.ComputerName) |
|
|
|
|
if vm.Properties.OSProfile != nil && vm.Properties.OSProfile.ComputerName != nil { |
|
|
|
|
computerName = *(vm.Properties.OSProfile.ComputerName) |
|
|
|
|
} |
|
|
|
|
if vm.VirtualMachineProperties.HardwareProfile != nil { |
|
|
|
|
size = string(vm.VirtualMachineProperties.HardwareProfile.VMSize) |
|
|
|
|
if vm.Properties.HardwareProfile != nil { |
|
|
|
|
size = string(*vm.Properties.HardwareProfile.VMSize) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -552,8 +568,8 @@ func mapFromVM(vm compute.VirtualMachine) virtualMachine { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func mapFromVMScaleSetVM(vm compute.VirtualMachineScaleSetVM, scaleSetName string) virtualMachine { |
|
|
|
|
osType := string(vm.StorageProfile.OsDisk.OsType) |
|
|
|
|
func mapFromVMScaleSetVM(vm armcompute.VirtualMachineScaleSetVM, scaleSetName string) virtualMachine { |
|
|
|
|
osType := string(*vm.Properties.StorageProfile.OSDisk.OSType) |
|
|
|
|
tags := map[string]*string{} |
|
|
|
|
networkInterfaces := []string{} |
|
|
|
|
var computerName string |
|
|
|
|
@ -563,18 +579,17 @@ func mapFromVMScaleSetVM(vm compute.VirtualMachineScaleSetVM, scaleSetName strin |
|
|
|
|
tags = vm.Tags |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if vm.NetworkProfile != nil { |
|
|
|
|
for _, vmNIC := range *(vm.NetworkProfile.NetworkInterfaces) { |
|
|
|
|
networkInterfaces = append(networkInterfaces, *vmNIC.ID) |
|
|
|
|
if vm.Properties != nil { |
|
|
|
|
if vm.Properties.NetworkProfile != nil { |
|
|
|
|
for _, vmNIC := range vm.Properties.NetworkProfile.NetworkInterfaces { |
|
|
|
|
networkInterfaces = append(networkInterfaces, *vmNIC.ID) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if vm.VirtualMachineScaleSetVMProperties != nil { |
|
|
|
|
if vm.VirtualMachineScaleSetVMProperties.OsProfile != nil && vm.VirtualMachineScaleSetVMProperties.OsProfile.ComputerName != nil { |
|
|
|
|
computerName = *(vm.VirtualMachineScaleSetVMProperties.OsProfile.ComputerName) |
|
|
|
|
if vm.Properties.OSProfile != nil && vm.Properties.OSProfile.ComputerName != nil { |
|
|
|
|
computerName = *(vm.Properties.OSProfile.ComputerName) |
|
|
|
|
} |
|
|
|
|
if vm.VirtualMachineScaleSetVMProperties.HardwareProfile != nil { |
|
|
|
|
size = string(vm.VirtualMachineScaleSetVMProperties.HardwareProfile.VMSize) |
|
|
|
|
if vm.Properties.HardwareProfile != nil { |
|
|
|
|
size = string(*vm.Properties.HardwareProfile.VMSize) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -596,36 +611,20 @@ var errorNotFound = errors.New("network interface does not exist") |
|
|
|
|
|
|
|
|
|
// getNetworkInterfaceByID gets the network interface.
|
|
|
|
|
// If a 404 is returned from the Azure API, `errorNotFound` is returned.
|
|
|
|
|
// On all other errors, an autorest.DetailedError is returned.
|
|
|
|
|
func (client *azureClient) getNetworkInterfaceByID(ctx context.Context, networkInterfaceID string) (*network.Interface, error) { |
|
|
|
|
result := network.Interface{} |
|
|
|
|
queryParameters := map[string]interface{}{ |
|
|
|
|
"api-version": "2018-10-01", |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
preparer := autorest.CreatePreparer( |
|
|
|
|
autorest.AsGet(), |
|
|
|
|
autorest.WithBaseURL(client.nic.BaseURI), |
|
|
|
|
autorest.WithPath(networkInterfaceID), |
|
|
|
|
autorest.WithQueryParameters(queryParameters), |
|
|
|
|
autorest.WithUserAgent(userAgent)) |
|
|
|
|
req, err := preparer.Prepare((&http.Request{}).WithContext(ctx)) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, autorest.NewErrorWithError(err, "network.InterfacesClient", "Get", nil, "Failure preparing request") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
resp, err := client.nic.GetSender(req) |
|
|
|
|
func (client *azureClient) getNetworkInterfaceByID(ctx context.Context, networkInterfaceID string) (*armnetwork.Interface, error) { |
|
|
|
|
r, err := newAzureResourceFromID(networkInterfaceID, client.logger) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, autorest.NewErrorWithError(err, "network.InterfacesClient", "Get", resp, "Failure sending request") |
|
|
|
|
return nil, fmt.Errorf("could not parse network interface ID: %w", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result, err = client.nic.GetResponder(resp) |
|
|
|
|
resp, err := client.nic.Get(ctx, r.ResourceGroupName, r.Name, nil) |
|
|
|
|
if err != nil { |
|
|
|
|
if resp.StatusCode == http.StatusNotFound { |
|
|
|
|
var responseError *azcore.ResponseError |
|
|
|
|
if errors.As(err, &responseError) && responseError.StatusCode == http.StatusNotFound { |
|
|
|
|
return nil, errorNotFound |
|
|
|
|
} |
|
|
|
|
return nil, autorest.NewErrorWithError(err, "network.InterfacesClient", "Get", resp, "Failure responding to request") |
|
|
|
|
return nil, fmt.Errorf("Failed to retrieve Interface %v with error: %w", networkInterfaceID, err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return &result, nil |
|
|
|
|
return &resp.Interface, nil |
|
|
|
|
} |
|
|
|
|
|