2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
package azure
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2022-07-27 16:02:33 -04:00
|
|
|
"fmt"
|
2022-08-30 09:15:51 -04:00
|
|
|
"strings"
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-08-30 09:15:51 -04:00
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
2022-07-27 16:02:33 -04:00
|
|
|
armcomputev2 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v2"
|
2022-03-22 11:03:15 -04:00
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
2022-10-24 10:58:21 -04:00
|
|
|
"github.com/edgelesssys/constellation/v2/internal/cloud"
|
2022-11-09 08:43:48 -05:00
|
|
|
"github.com/edgelesssys/constellation/v2/internal/cloud/azureshared"
|
2022-09-21 07:47:57 -04:00
|
|
|
"github.com/edgelesssys/constellation/v2/internal/cloud/metadata"
|
|
|
|
"github.com/edgelesssys/constellation/v2/internal/role"
|
2022-03-22 11:03:15 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// getScaleSetVM tries to get an azure vm belonging to a scale set.
|
2022-06-28 10:08:05 -04:00
|
|
|
func (m *Metadata) getScaleSetVM(ctx context.Context, providerID string) (metadata.InstanceMetadata, error) {
|
2022-06-10 07:18:30 -04:00
|
|
|
_, resourceGroup, scaleSet, instanceID, err := azureshared.ScaleSetInformationFromProviderID(providerID)
|
2022-03-22 11:03:15 -04:00
|
|
|
if err != nil {
|
2022-06-28 10:08:05 -04:00
|
|
|
return metadata.InstanceMetadata{}, err
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
vmResp, err := m.virtualMachineScaleSetVMsAPI.Get(ctx, resourceGroup, scaleSet, instanceID, nil)
|
|
|
|
if err != nil {
|
2022-06-28 10:08:05 -04:00
|
|
|
return metadata.InstanceMetadata{}, err
|
2022-05-24 04:04:42 -04:00
|
|
|
}
|
|
|
|
networkInterfaces, err := m.getScaleSetVMInterfaces(ctx, vmResp.VirtualMachineScaleSetVM, resourceGroup, scaleSet, instanceID)
|
|
|
|
if err != nil {
|
2022-06-28 10:08:05 -04:00
|
|
|
return metadata.InstanceMetadata{}, err
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
2022-11-09 08:43:48 -05:00
|
|
|
return convertScaleSetVMToCoreInstance(vmResp.VirtualMachineScaleSetVM, networkInterfaces)
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// listScaleSetVMs lists all scale set VMs in the current resource group.
|
2022-06-28 10:08:05 -04:00
|
|
|
func (m *Metadata) listScaleSetVMs(ctx context.Context, resourceGroup string) ([]metadata.InstanceMetadata, error) {
|
|
|
|
instances := []metadata.InstanceMetadata{}
|
2022-07-27 16:02:33 -04:00
|
|
|
scaleSetPager := m.scaleSetsAPI.NewListPager(resourceGroup, nil)
|
|
|
|
for scaleSetPager.More() {
|
|
|
|
page, err := scaleSetPager.NextPage(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("retrieving scale sets: %w", err)
|
|
|
|
}
|
|
|
|
for _, scaleSet := range page.Value {
|
2022-03-22 11:03:15 -04:00
|
|
|
if scaleSet == nil || scaleSet.Name == nil {
|
|
|
|
continue
|
|
|
|
}
|
2022-07-27 16:02:33 -04:00
|
|
|
vmPager := m.virtualMachineScaleSetVMsAPI.NewListPager(resourceGroup, *scaleSet.Name, nil)
|
|
|
|
for vmPager.More() {
|
|
|
|
vmPage, err := vmPager.NextPage(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("retrieving vms: %w", err)
|
|
|
|
}
|
|
|
|
for _, vm := range vmPage.Value {
|
2022-03-22 11:03:15 -04:00
|
|
|
if vm == nil || vm.InstanceID == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
interfaces, err := m.getScaleSetVMInterfaces(ctx, *vm, resourceGroup, *scaleSet.Name, *vm.InstanceID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-11-09 08:43:48 -05:00
|
|
|
instance, err := convertScaleSetVMToCoreInstance(*vm, interfaces)
|
2022-03-22 11:03:15 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
instances = append(instances, instance)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return instances, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// convertScaleSetVMToCoreInstance converts an azure scale set virtual machine with interface configurations into a core.Instance.
|
2022-10-06 06:14:41 -04:00
|
|
|
func convertScaleSetVMToCoreInstance(vm armcomputev2.VirtualMachineScaleSetVM, networkInterfaces []armnetwork.Interface,
|
|
|
|
) (metadata.InstanceMetadata, error) {
|
2022-03-22 11:03:15 -04:00
|
|
|
if vm.ID == nil {
|
2022-06-28 10:08:05 -04:00
|
|
|
return metadata.InstanceMetadata{}, errors.New("retrieving instance from armcompute API client returned no instance ID")
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
if vm.Properties == nil || vm.Properties.OSProfile == nil || vm.Properties.OSProfile.ComputerName == nil {
|
2022-06-28 10:08:05 -04:00
|
|
|
return metadata.InstanceMetadata{}, errors.New("retrieving instance from armcompute API client returned no computer name")
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
var sshKeys map[string][]string
|
|
|
|
if vm.Properties.OSProfile.LinuxConfiguration == nil || vm.Properties.OSProfile.LinuxConfiguration.SSH == nil {
|
|
|
|
sshKeys = map[string][]string{}
|
|
|
|
} else {
|
|
|
|
sshKeys = extractSSHKeys(*vm.Properties.OSProfile.LinuxConfiguration.SSH)
|
|
|
|
}
|
2022-10-06 06:14:41 -04:00
|
|
|
|
|
|
|
if vm.Tags == nil {
|
|
|
|
return metadata.InstanceMetadata{}, errors.New("retrieving instance from armcompute API client returned no tags")
|
|
|
|
}
|
|
|
|
|
2022-06-28 10:08:05 -04:00
|
|
|
return metadata.InstanceMetadata{
|
2022-03-22 11:03:15 -04:00
|
|
|
Name: *vm.Properties.OSProfile.ComputerName,
|
|
|
|
ProviderID: "azure://" + *vm.ID,
|
2022-10-06 06:14:41 -04:00
|
|
|
Role: extractScaleSetVMRole(vm.Tags),
|
2022-08-04 05:08:20 -04:00
|
|
|
VPCIP: extractVPCIP(networkInterfaces),
|
2022-03-22 11:03:15 -04:00
|
|
|
SSHKeys: sshKeys,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// extractScaleSetVMRole extracts the constellation role of a scale set using its name.
|
2022-10-06 06:14:41 -04:00
|
|
|
func extractScaleSetVMRole(tags map[string]*string) role.Role {
|
|
|
|
if tags == nil {
|
|
|
|
return role.Unknown
|
|
|
|
}
|
2022-10-24 10:58:21 -04:00
|
|
|
roleStr, ok := tags[cloud.TagRole]
|
2022-10-06 06:14:41 -04:00
|
|
|
if !ok {
|
|
|
|
return role.Unknown
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
2022-10-06 06:14:41 -04:00
|
|
|
if roleStr == nil {
|
|
|
|
return role.Unknown
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
2022-10-06 06:14:41 -04:00
|
|
|
return role.FromString(*roleStr)
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
2022-08-30 09:15:51 -04:00
|
|
|
|
|
|
|
// ImageReferenceFromImage sets the `ID` or `CommunityGalleryImageID` field
|
|
|
|
// of `ImageReference` depending on the provided `img`.
|
|
|
|
func ImageReferenceFromImage(img string) *armcomputev2.ImageReference {
|
|
|
|
ref := &armcomputev2.ImageReference{}
|
|
|
|
|
|
|
|
if strings.HasPrefix(img, "/CommunityGalleries") {
|
|
|
|
ref.CommunityGalleryImageID = to.Ptr(img)
|
|
|
|
} else {
|
|
|
|
ref.ID = to.Ptr(img)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ref
|
|
|
|
}
|