mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
AB#2104 Feat/azure logging (#198)
implementation for azure early boot logging
This commit is contained in:
parent
963c6f98e5
commit
84552ca8f7
@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Early boot logging for Cloud Provider: GCP & Azure
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/profiles/latest/authorization/mgmt/authorization"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||
@ -139,3 +140,8 @@ type virtualMachinesAPI interface {
|
||||
BeginCreateOrUpdate(ctx context.Context, resourceGroupName string, vmName string, parameters armcompute.VirtualMachine,
|
||||
options *armcompute.VirtualMachinesClientBeginCreateOrUpdateOptions) (virtualMachinesClientCreateOrUpdatePollerResponse, error)
|
||||
}
|
||||
|
||||
type applicationInsightsAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, resourceName string, insightProperties armapplicationinsights.Component,
|
||||
options *armapplicationinsights.ComponentsClientCreateOrUpdateOptions) (armapplicationinsights.ComponentsClientCreateOrUpdateResponse, error)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/profiles/latest/authorization/mgmt/authorization"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||
@ -402,3 +403,12 @@ func (a *stubRoleAssignmentsAPI) Create(ctx context.Context, scope string, roleA
|
||||
}
|
||||
return authorization.RoleAssignment{}, a.createErrors[(a.createCounter-1)%len(a.createErrors)]
|
||||
}
|
||||
|
||||
type stubApplicationInsightsAPI struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (a *stubApplicationInsightsAPI) CreateOrUpdate(ctx context.Context, resourceGroupName string, resourceName string, insightProperties armapplicationinsights.Component, options *armapplicationinsights.ComponentsClientCreateOrUpdateOptions) (armapplicationinsights.ComponentsClientCreateOrUpdateResponse, error) {
|
||||
resp := armapplicationinsights.ComponentsClientCreateOrUpdateResponse{}
|
||||
return resp, a.err
|
||||
}
|
||||
|
26
cli/internal/azure/client/applicationinsight.go
Normal file
26
cli/internal/azure/client/applicationinsight.go
Normal file
@ -0,0 +1,26 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (c *Client) CreateApplicationInsight(ctx context.Context) error {
|
||||
properties := armapplicationinsights.Component{
|
||||
Kind: to.StringPtr("web"),
|
||||
Location: to.StringPtr(c.location),
|
||||
Properties: &armapplicationinsights.ComponentProperties{
|
||||
ApplicationType: armapplicationinsights.ApplicationTypeWeb.ToPtr(),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := c.applicationInsightsAPI.CreateOrUpdate(
|
||||
ctx,
|
||||
c.resourceGroup,
|
||||
"constellation-insights-"+c.uid,
|
||||
properties,
|
||||
nil,
|
||||
)
|
||||
return err
|
||||
}
|
46
cli/internal/azure/client/applicationinsight_test.go
Normal file
46
cli/internal/azure/client/applicationinsight_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCreateApplicationInsight(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
applicationInsightsAPI applicationInsightsAPI
|
||||
wantErr bool
|
||||
}{
|
||||
"successful create": {
|
||||
applicationInsightsAPI: &stubApplicationInsightsAPI{
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
"failed create": {
|
||||
applicationInsightsAPI: &stubApplicationInsightsAPI{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
client := Client{
|
||||
applicationInsightsAPI: tc.applicationInsightsAPI,
|
||||
}
|
||||
|
||||
err := client.CreateApplicationInsight(context.Background())
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
})
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/profiles/latest/authorization/mgmt/authorization"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||
@ -38,6 +39,7 @@ type Client struct {
|
||||
applicationsAPI
|
||||
servicePrincipalsAPI
|
||||
roleAssignmentsAPI
|
||||
applicationInsightsAPI
|
||||
|
||||
adReplicationLagCheckInterval time.Duration
|
||||
adReplicationLagCheckMaxRetries int
|
||||
@ -82,6 +84,7 @@ func NewFromDefault(subscriptionID, tenantID string) (*Client, error) {
|
||||
networkInterfacesAPI := armnetwork.NewInterfacesClient(subscriptionID, cred, nil)
|
||||
loadBalancersAPI := armnetwork.NewLoadBalancersClient(subscriptionID, cred, nil)
|
||||
virtualMachinesAPI := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
|
||||
applicationInsightsAPI := armapplicationinsights.NewComponentsClient(subscriptionID, cred, nil)
|
||||
applicationsAPI := graphrbac.NewApplicationsClient(tenantID)
|
||||
applicationsAPI.Authorizer = graphAuthorizer
|
||||
servicePrincipalsAPI := graphrbac.NewServicePrincipalsClient(tenantID)
|
||||
@ -101,6 +104,7 @@ func NewFromDefault(subscriptionID, tenantID string) (*Client, error) {
|
||||
servicePrincipalsAPI: &servicePrincipalsClient{&servicePrincipalsAPI},
|
||||
roleAssignmentsAPI: &roleAssignmentsClient{&roleAssignmentsAPI},
|
||||
virtualMachinesAPI: &virtualMachinesClient{virtualMachinesAPI},
|
||||
applicationInsightsAPI: applicationInsightsAPI,
|
||||
subscriptionID: subscriptionID,
|
||||
tenantID: tenantID,
|
||||
nodes: cloudtypes.Instances{},
|
||||
|
@ -25,6 +25,7 @@ type gcpclient interface {
|
||||
type azureclient interface {
|
||||
GetState() (state.ConstellationState, error)
|
||||
SetState(state.ConstellationState) error
|
||||
CreateApplicationInsight(ctx context.Context) error
|
||||
CreateResourceGroup(ctx context.Context) error
|
||||
CreateExternalLoadBalancer(ctx context.Context) error
|
||||
CreateVirtualNetwork(ctx context.Context) error
|
||||
|
@ -69,6 +69,10 @@ func (c *fakeAzureClient) SetState(stat state.ConstellationState) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeAzureClient) CreateApplicationInsight(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeAzureClient) CreateResourceGroup(ctx context.Context) error {
|
||||
c.resourceGroup = "resource-group"
|
||||
return nil
|
||||
@ -156,6 +160,7 @@ type stubAzureClient struct {
|
||||
|
||||
getStateErr error
|
||||
setStateErr error
|
||||
createApplicationInsightErr error
|
||||
createResourceGroupErr error
|
||||
createVirtualNetworkErr error
|
||||
createSecurityGroupErr error
|
||||
@ -178,6 +183,10 @@ func (c *stubAzureClient) CreateExternalLoadBalancer(ctx context.Context) error
|
||||
return c.createLoadBalancerErr
|
||||
}
|
||||
|
||||
func (c *stubAzureClient) CreateApplicationInsight(ctx context.Context) error {
|
||||
return c.createApplicationInsightErr
|
||||
}
|
||||
|
||||
func (c *stubAzureClient) CreateResourceGroup(ctx context.Context) error {
|
||||
return c.createResourceGroupErr
|
||||
}
|
||||
|
@ -166,6 +166,9 @@ func (c *Creator) createAzure(ctx context.Context, cl azureclient, config *confi
|
||||
if err := cl.CreateInstances(ctx, createInput); err != nil {
|
||||
return state.ConstellationState{}, err
|
||||
}
|
||||
if err := cl.CreateApplicationInsight(ctx); err != nil {
|
||||
return state.ConstellationState{}, err
|
||||
}
|
||||
|
||||
return cl.GetState()
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package azure
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||
@ -91,3 +92,7 @@ type tagsAPI interface {
|
||||
CreateOrUpdateAtScope(ctx context.Context, scope string, parameters armresources.TagsResource, options *armresources.TagsClientCreateOrUpdateAtScopeOptions) (armresources.TagsClientCreateOrUpdateAtScopeResponse, error)
|
||||
UpdateAtScope(ctx context.Context, scope string, parameters armresources.TagsPatchResource, options *armresources.TagsClientUpdateAtScopeOptions) (armresources.TagsClientUpdateAtScopeResponse, error)
|
||||
}
|
||||
|
||||
type applicationInsightsAPI interface {
|
||||
Get(ctx context.Context, resourceGroupName string, resourceName string, options *armapplicationinsights.ComponentsClientGetOptions) (armapplicationinsights.ComponentsClientGetResponse, error)
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func (a *Autoscaler) Name() string {
|
||||
|
||||
// Secrets returns a list of secrets to deploy together with the k8s cluster-autoscaler.
|
||||
func (a *Autoscaler) Secrets(instance cloudtypes.Instance, cloudServiceAccountURI string) (resources.Secrets, error) {
|
||||
subscriptionID, resourceGroup, err := extractBasicsFromProviderID(instance.ProviderID)
|
||||
subscriptionID, resourceGroup, err := azureshared.BasicsFromProviderID(instance.ProviderID)
|
||||
if err != nil {
|
||||
return resources.Secrets{}, err
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ func (c *CloudControllerManager) Secrets(ctx context.Context, instance cloudtype
|
||||
// Azure CCM expects cloud provider config to contain cluster configuration and service principal client secrets
|
||||
// reference: https://kubernetes-sigs.github.io/cloud-provider-azure/install/configs/
|
||||
|
||||
subscriptionID, resourceGroup, err := extractBasicsFromProviderID(instance.ProviderID)
|
||||
subscriptionID, resourceGroup, err := azureshared.BasicsFromProviderID(instance.ProviderID)
|
||||
if err != nil {
|
||||
return resources.Secrets{}, err
|
||||
}
|
||||
@ -75,7 +75,7 @@ func (c *CloudControllerManager) Secrets(ctx context.Context, instance cloudtype
|
||||
}
|
||||
|
||||
vmType := "standard"
|
||||
if _, _, _, _, err := splitScaleSetProviderID(instance.ProviderID); err == nil {
|
||||
if _, _, _, _, err := azureshared.ScaleSetInformationFromProviderID(instance.ProviderID); err == nil {
|
||||
vmType = "vmss"
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
package azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/edgelesssys/constellation/internal/azureshared"
|
||||
"github.com/microsoft/ApplicationInsights-Go/appinsights"
|
||||
)
|
||||
|
||||
@ -10,10 +15,34 @@ type Logger struct {
|
||||
|
||||
// NewLogger creates a new client to store information in Azure Application Insights
|
||||
// https://github.com/Microsoft/ApplicationInsights-go
|
||||
func NewLogger(instrumentationKey string) *Logger {
|
||||
return &Logger{
|
||||
client: appinsights.NewTelemetryClient(instrumentationKey),
|
||||
func NewLogger(ctx context.Context, metadata *Metadata) (*Logger, error) {
|
||||
providerID, err := metadata.providerID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uid, err := azureshared.UIDFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceName := "constellation-insights-" + uid
|
||||
resp, err := metadata.applicationInsightsAPI.Get(ctx, resourceGroup, resourceName, &armapplicationinsights.ComponentsClientGetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Properties == nil || resp.Properties.InstrumentationKey == nil {
|
||||
return nil, errors.New("unable to get instrumentation key")
|
||||
}
|
||||
|
||||
return &Logger{
|
||||
client: appinsights.NewTelemetryClient(*resp.Properties.InstrumentationKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Disclose stores log information in Azure Application Insights!
|
||||
|
@ -7,12 +7,14 @@ import (
|
||||
"regexp"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/internal/azureshared"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -32,6 +34,7 @@ type Metadata struct {
|
||||
virtualMachinesAPI
|
||||
virtualMachineScaleSetVMsAPI
|
||||
tagsAPI
|
||||
applicationInsightsAPI
|
||||
}
|
||||
|
||||
// NewMetadata creates a new Metadata.
|
||||
@ -50,7 +53,7 @@ func NewMetadata(ctx context.Context) (*Metadata, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subscriptionID, _, err := extractBasicsFromProviderID("azure://" + instanceMetadata.Compute.ResourceID)
|
||||
subscriptionID, _, err := azureshared.BasicsFromProviderID("azure://" + instanceMetadata.Compute.ResourceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -63,6 +66,7 @@ func NewMetadata(ctx context.Context) (*Metadata, error) {
|
||||
virtualMachinesAPI := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
|
||||
virtualMachineScaleSetVMsAPI := armcompute.NewVirtualMachineScaleSetVMsClient(subscriptionID, cred, nil)
|
||||
tagsAPI := armresources.NewTagsClient(subscriptionID, cred, nil)
|
||||
applicationInsightsAPI := armapplicationinsights.NewComponentsClient(subscriptionID, cred, nil)
|
||||
|
||||
return &Metadata{
|
||||
imdsAPI: &imdsAPI,
|
||||
@ -75,6 +79,7 @@ func NewMetadata(ctx context.Context) (*Metadata, error) {
|
||||
virtualMachinesAPI: &virtualMachinesClient{virtualMachinesAPI},
|
||||
virtualMachineScaleSetVMsAPI: &virtualMachineScaleSetVMsClient{virtualMachineScaleSetVMsAPI},
|
||||
tagsAPI: &tagsClient{tagsAPI},
|
||||
applicationInsightsAPI: &applicationInsightsClient{applicationInsightsAPI},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -84,7 +89,7 @@ func (m *Metadata) List(ctx context.Context) ([]cloudtypes.Instance, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
||||
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -131,7 +136,7 @@ func (m *Metadata) SignalRole(ctx context.Context, role role.Role) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, _, _, _, err := splitScaleSetProviderID(providerID); err == nil {
|
||||
if _, _, _, _, err := azureshared.ScaleSetInformationFromProviderID(providerID); err == nil {
|
||||
// scale set instances cannot store tags and role can be inferred from scale set name.
|
||||
return nil
|
||||
}
|
||||
@ -144,7 +149,7 @@ func (m *Metadata) GetNetworkSecurityGroupName(ctx context.Context) (string, err
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
||||
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -165,7 +170,7 @@ func (m *Metadata) GetSubnetworkCIDR(ctx context.Context) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
||||
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -187,7 +192,7 @@ func (m *Metadata) getLoadBalancer(ctx context.Context) (*armnetwork.LoadBalance
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
||||
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -253,7 +258,7 @@ func (m *Metadata) GetLoadBalancerIP(ctx context.Context) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
||||
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -286,19 +291,6 @@ func (m *Metadata) providerID(ctx context.Context) (string, error) {
|
||||
return "azure://" + instanceMetadata.Compute.ResourceID, nil
|
||||
}
|
||||
|
||||
// extractBasicsFromProviderID extracts subscriptionID and resourceGroup from both types of valid azure providerID.
|
||||
func extractBasicsFromProviderID(providerID string) (subscriptionID, resourceGroup string, err error) {
|
||||
subscriptionID, resourceGroup, _, err = splitVMProviderID(providerID)
|
||||
if err == nil {
|
||||
return subscriptionID, resourceGroup, nil
|
||||
}
|
||||
subscriptionID, resourceGroup, _, _, err = splitScaleSetProviderID(providerID)
|
||||
if err == nil {
|
||||
return subscriptionID, resourceGroup, nil
|
||||
}
|
||||
return "", "", fmt.Errorf("providerID %v is malformatted", providerID)
|
||||
}
|
||||
|
||||
// extractInstanceTags converts azure tags into metadata key-value pairs.
|
||||
func extractInstanceTags(tags map[string]*string) map[string]string {
|
||||
metadataMap := map[string]string{}
|
||||
|
@ -605,47 +605,6 @@ func TestProviderID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractBasicsFromProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantErr bool
|
||||
wantSubscriptionID string
|
||||
wantResourceGroup string
|
||||
}{
|
||||
"providerID for individual instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
},
|
||||
"providerID for scale set instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name/virtualMachines/instance-id",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
subscriptionID, resourceGroup, err := extractBasicsFromProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||
assert.Equal(tc.wantResourceGroup, resourceGroup)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractInstanceTags(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
in map[string]*string
|
||||
|
@ -9,17 +9,17 @@ import (
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/internal/azureshared"
|
||||
)
|
||||
|
||||
var (
|
||||
azureVMSSProviderIDRegexp = regexp.MustCompile(`^azure:///subscriptions/([^/]+)/resourceGroups/([^/]+)/providers/Microsoft.Compute/virtualMachineScaleSets/([^/]+)/virtualMachines/([^/]+)$`)
|
||||
coordinatorScaleSetRegexp = regexp.MustCompile(`constellation-scale-set-coordinators-[0-9a-zA-Z]+$`)
|
||||
nodeScaleSetRegexp = regexp.MustCompile(`constellation-scale-set-nodes-[0-9a-zA-Z]+$`)
|
||||
)
|
||||
|
||||
// getScaleSetVM tries to get an azure vm belonging to a scale set.
|
||||
func (m *Metadata) getScaleSetVM(ctx context.Context, providerID string) (cloudtypes.Instance, error) {
|
||||
_, resourceGroup, scaleSet, instanceID, err := splitScaleSetProviderID(providerID)
|
||||
_, resourceGroup, scaleSet, instanceID, err := azureshared.ScaleSetInformationFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return cloudtypes.Instance{}, err
|
||||
}
|
||||
@ -70,17 +70,6 @@ func (m *Metadata) listScaleSetVMs(ctx context.Context, resourceGroup string) ([
|
||||
return instances, nil
|
||||
}
|
||||
|
||||
// splitScaleSetProviderID splits a provider's id belonging to an azure scaleset into core components.
|
||||
// A providerID for scale set VMs is build after the following schema:
|
||||
// - 'azure:///subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Compute/virtualMachineScaleSets/<scale-set-name>/virtualMachines/<instance-id>'
|
||||
func splitScaleSetProviderID(providerID string) (subscriptionID, resourceGroup, scaleSet, instanceID string, err error) {
|
||||
matches := azureVMSSProviderIDRegexp.FindStringSubmatch(providerID)
|
||||
if len(matches) != 5 {
|
||||
return "", "", "", "", errors.New("error splitting providerID")
|
||||
}
|
||||
return matches[1], matches[2], matches[3], matches[4], nil
|
||||
}
|
||||
|
||||
// convertScaleSetVMToCoreInstance converts an azure scale set virtual machine with interface configurations into a core.Instance.
|
||||
func convertScaleSetVMToCoreInstance(scaleSet string, vm armcompute.VirtualMachineScaleSetVM, networkInterfaces []armnetwork.Interface, publicIPAddresses []string) (cloudtypes.Instance, error) {
|
||||
if vm.ID == nil {
|
||||
|
@ -162,52 +162,6 @@ func TestListScaleSetVMs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitScaleSetProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantErr bool
|
||||
wantSubscriptionID string
|
||||
wantResourceGroup string
|
||||
wantScaleSet string
|
||||
wantInstanceID string
|
||||
}{
|
||||
"providerID for scale set instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name/virtualMachines/instance-id",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
wantScaleSet: "scale-set-name",
|
||||
wantInstanceID: "instance-id",
|
||||
},
|
||||
"providerID for individual instance must fail": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name",
|
||||
wantErr: true,
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
subscriptionID, resourceGroup, scaleSet, instanceID, err := splitScaleSetProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||
assert.Equal(tc.wantResourceGroup, resourceGroup)
|
||||
assert.Equal(tc.wantScaleSet, scaleSet)
|
||||
assert.Equal(tc.wantInstanceID, instanceID)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertScaleSetVMToCoreInstance(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
inVM armcompute.VirtualMachineScaleSetVM
|
||||
|
@ -2,9 +2,7 @@ package azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
@ -12,13 +10,11 @@ import (
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/internal/azureshared"
|
||||
)
|
||||
|
||||
var azureVMProviderIDRegexp = regexp.MustCompile(`^azure:///subscriptions/([^/]+)/resourceGroups/([^/]+)/providers/Microsoft.Compute/virtualMachines/([^/]+)$`)
|
||||
|
||||
// getVM tries to get a single azure vm.
|
||||
func (m *Metadata) getVM(ctx context.Context, providerID string) (cloudtypes.Instance, error) {
|
||||
_, resourceGroup, instanceName, err := splitVMProviderID(providerID)
|
||||
_, resourceGroup, instanceName, err := azureshared.VMInformationFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return cloudtypes.Instance{}, err
|
||||
}
|
||||
@ -73,17 +69,6 @@ func (m *Metadata) setTag(ctx context.Context, key, value string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// splitVMProviderID splits a provider's id belonging to a single azure instance into core components.
|
||||
// A providerID for individual VMs is build after the following schema:
|
||||
// - 'azure:///subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Compute/virtualMachines/<instance-name>'
|
||||
func splitVMProviderID(providerID string) (subscriptionID, resourceGroup, instanceName string, err error) {
|
||||
matches := azureVMProviderIDRegexp.FindStringSubmatch(providerID)
|
||||
if len(matches) != 4 {
|
||||
return "", "", "", errors.New("error splitting providerID")
|
||||
}
|
||||
return matches[1], matches[2], matches[3], nil
|
||||
}
|
||||
|
||||
// convertVMToCoreInstance converts an azure virtual machine with interface configurations into a cloudtypes.Instance.
|
||||
func convertVMToCoreInstance(vm armcompute.VirtualMachine, networkInterfaces []armnetwork.Interface) (cloudtypes.Instance, error) {
|
||||
if vm.Name == nil || vm.ID == nil {
|
||||
|
@ -189,49 +189,6 @@ func TestSetTag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitVMProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantErr bool
|
||||
wantSubscriptionID string
|
||||
wantResourceGroup string
|
||||
wantInstanceName string
|
||||
}{
|
||||
"providerID for individual instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
wantInstanceName: "instance-name",
|
||||
},
|
||||
"providerID for scale set instance must fail": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name/virtualMachines/instance-id",
|
||||
wantErr: true,
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
subscriptionID, resourceGroup, instanceName, err := splitVMProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||
assert.Equal(tc.wantResourceGroup, resourceGroup)
|
||||
assert.Equal(tc.wantInstanceName, instanceName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertVMToCoreInstance(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
inVM armcompute.VirtualMachine
|
||||
|
@ -3,6 +3,7 @@ package azure
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||
@ -110,3 +111,11 @@ type scaleSetsClient struct {
|
||||
func (c *scaleSetsClient) List(resourceGroupName string, options *armcompute.VirtualMachineScaleSetsClientListOptions) virtualMachineScaleSetsClientListPager {
|
||||
return c.VirtualMachineScaleSetsClient.List(resourceGroupName, options)
|
||||
}
|
||||
|
||||
type applicationInsightsClient struct {
|
||||
*armapplicationinsights.ComponentsClient
|
||||
}
|
||||
|
||||
func (c *applicationInsightsClient) Get(ctx context.Context, resourceGroupName string, resourceName string, options *armapplicationinsights.ComponentsClientGetOptions) (armapplicationinsights.ComponentsClientGetResponse, error) {
|
||||
return c.ComponentsClient.Get(ctx, resourceGroupName, resourceName, options)
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func (c *CloudControllerManager) ConfigMaps(instance cloudtypes.Instance) (resou
|
||||
// reference: https://github.com/kubernetes/cloud-provider-gcp/blob/master/cluster/gce/gci/configure-helper.sh#L791-L892
|
||||
var config strings.Builder
|
||||
config.WriteString("[global]\n")
|
||||
projectID, _, _, err := splitProviderID(instance.ProviderID)
|
||||
projectID, _, _, err := gcpshared.SplitProviderID(instance.ProviderID)
|
||||
if err != nil {
|
||||
return resources.ConfigMaps{}, err
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ package gcp
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
compute "cloud.google.com/go/compute/apiv1"
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
"github.com/edgelesssys/constellation/internal/gcpshared"
|
||||
"google.golang.org/api/iterator"
|
||||
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@ -17,8 +17,6 @@ import (
|
||||
|
||||
const gcpSSHMetadataKey = "ssh-keys"
|
||||
|
||||
var providerIDRegex = regexp.MustCompile(`^gce://([^/]+)/([^/]+)/([^/]+)$`)
|
||||
|
||||
// Client implements the gcp.API interface.
|
||||
type Client struct {
|
||||
instanceAPI
|
||||
@ -325,7 +323,7 @@ func convertToCoreInstance(in *computepb.Instance, project string, zone string)
|
||||
metadata := extractInstanceMetadata(in.Metadata, "", false)
|
||||
return cloudtypes.Instance{
|
||||
Name: *in.Name,
|
||||
ProviderID: joinProviderID(project, zone, *in.Name),
|
||||
ProviderID: gcpshared.JoinProviderID(project, zone, *in.Name),
|
||||
Role: cloudprovider.ExtractRole(metadata),
|
||||
PrivateIPs: extractPrivateIPs(in.NetworkInterfaces),
|
||||
PublicIPs: extractPublicIPs(in.NetworkInterfaces),
|
||||
@ -334,22 +332,6 @@ func convertToCoreInstance(in *computepb.Instance, project string, zone string)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// joinProviderID builds a k8s provider ID for GCP instances.
|
||||
// A providerID is build after the schema 'gce://<project-id>/<zone>/<instance-name>'
|
||||
func joinProviderID(project, zone, instanceName string) string {
|
||||
return fmt.Sprintf("gce://%v/%v/%v", project, zone, instanceName)
|
||||
}
|
||||
|
||||
// splitProviderID splits a provider's id into core components.
|
||||
// A providerID is build after the schema 'gce://<project-id>/<zone>/<instance-name>'
|
||||
func splitProviderID(providerID string) (project, zone, instance string, err error) {
|
||||
matches := providerIDRegex.FindStringSubmatch(providerID)
|
||||
if len(matches) != 4 {
|
||||
return "", "", "", fmt.Errorf("error splitting providerID: %v", providerID)
|
||||
}
|
||||
return matches[1], matches[2], matches[3], nil
|
||||
}
|
||||
|
||||
// extractInstanceMetadata will extract the list of instance metadata key-value pairs into a map.
|
||||
// If "skipKey" is true, "key" will be skipped.
|
||||
func extractInstanceMetadata(in *computepb.Metadata, key string, skipKey bool) map[string]string {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
|
||||
"cloud.google.com/go/logging"
|
||||
"github.com/edgelesssys/constellation/internal/gcpshared"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
@ -15,7 +16,7 @@ type Logger struct {
|
||||
// NewLogger creates a new Cloud Logger for GCP.
|
||||
// https://cloud.google.com/logging/docs/setup/go
|
||||
func NewLogger(ctx context.Context, providerID string, logName string) (*Logger, error) {
|
||||
projectID, _, _, err := splitProviderID(providerID)
|
||||
projectID, _, _, err := gcpshared.SplitProviderID(providerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||
"github.com/edgelesssys/constellation/coordinator/core"
|
||||
"github.com/edgelesssys/constellation/coordinator/role"
|
||||
"github.com/edgelesssys/constellation/internal/gcpshared"
|
||||
)
|
||||
|
||||
// API handles all GCP API requests.
|
||||
@ -79,7 +80,7 @@ func (m *Metadata) Self(ctx context.Context) (cloudtypes.Instance, error) {
|
||||
|
||||
// GetInstance retrieves an instance using its providerID.
|
||||
func (m *Metadata) GetInstance(ctx context.Context, providerID string) (cloudtypes.Instance, error) {
|
||||
project, zone, instanceName, err := splitProviderID(providerID)
|
||||
project, zone, instanceName, err := gcpshared.SplitProviderID(providerID)
|
||||
if err != nil {
|
||||
return cloudtypes.Instance{}, fmt.Errorf("invalid providerID: %w", err)
|
||||
}
|
||||
|
@ -122,8 +122,10 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// TODO: Implement cloud logging for Azure
|
||||
cloudLogger = &logging.NopLogger{}
|
||||
cloudLogger, err = azurecloud.NewLogger(context.Background(), metadata)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
coreMetadata = metadata
|
||||
kube = kubernetes.New("azure", k8sapi.NewKubernetesUtil(), &k8sapi.CoreOSConfiguration{}, kubectl.New(), azurecloud.NewCloudControllerManager(metadata), &azurecloud.CloudNodeManager{}, &azurecloud.Autoscaler{}, metadata)
|
||||
|
||||
|
3
go.mod
3
go.mod
@ -50,6 +50,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.13.2
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.3.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.5.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v0.2.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.5.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v0.3.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v0.3.1
|
||||
@ -65,7 +66,6 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/ec2 v1.32.0
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.16.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.2
|
||||
github.com/aws/smithy-go v1.11.2
|
||||
github.com/coreos/go-systemd/v22 v22.3.2
|
||||
github.com/docker/docker v20.10.13+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
@ -118,6 +118,7 @@ require (
|
||||
|
||||
require (
|
||||
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
|
||||
github.com/aws/smithy-go v1.11.2 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -124,6 +124,8 @@ github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.5.0 h1:8OgHKRX8uTyIi
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.5.0/go.mod h1:uQSVRwN3dRA6hguqKpgzwonvQtpxaWo7/t5cbz3iHbE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.2.1 h1:lirjIOHv5RrmDbZXw9lUz/fY68uU05qR4uIef58WMvQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.2.1/go.mod h1:j1J9XXIo/eXD7YSrr73sYZTEY/AQ0+/Q6Aa96z1e2j8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v0.2.1 h1:H+YaV8IY4sVFxrkSmyvfvXZv+wxUq/qTQOa9TkqUqPE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v0.2.1/go.mod h1:IwvRqY+EcaQzfAGUdIZpzWELUdsZzuItWRP6cNTzgr0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.5.0 h1:kqRtiAe9aH0WzzQm3Mq7N6mzcdZHGJZrdteepKT7ymU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.5.0/go.mod h1:isx+19QmRnAX0Ls0Adm/8SL3b8bIaZiSPbhpoyZX5Mw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v0.3.1 h1:CyGPbnjITjA63agVN1nNznge7Tip0g7OiAvFPiT0btU=
|
||||
|
@ -60,6 +60,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.3.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.5.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.2.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v0.2.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.5.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v0.3.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v0.3.1 // indirect
|
||||
|
@ -113,6 +113,8 @@ github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.5.0 h1:8OgHKRX8uTyIi
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.5.0/go.mod h1:uQSVRwN3dRA6hguqKpgzwonvQtpxaWo7/t5cbz3iHbE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.2.1 h1:lirjIOHv5RrmDbZXw9lUz/fY68uU05qR4uIef58WMvQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.2.1/go.mod h1:j1J9XXIo/eXD7YSrr73sYZTEY/AQ0+/Q6Aa96z1e2j8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v0.2.1 h1:H+YaV8IY4sVFxrkSmyvfvXZv+wxUq/qTQOa9TkqUqPE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights v0.2.1/go.mod h1:IwvRqY+EcaQzfAGUdIZpzWELUdsZzuItWRP6cNTzgr0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.5.0 h1:kqRtiAe9aH0WzzQm3Mq7N6mzcdZHGJZrdteepKT7ymU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute v0.5.0/go.mod h1:isx+19QmRnAX0Ls0Adm/8SL3b8bIaZiSPbhpoyZX5Mw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v0.3.1 h1:CyGPbnjITjA63agVN1nNznge7Tip0g7OiAvFPiT0btU=
|
||||
|
61
internal/azureshared/metadata.go
Normal file
61
internal/azureshared/metadata.go
Normal file
@ -0,0 +1,61 @@
|
||||
package azureshared
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
azureVMProviderIDRegexp = regexp.MustCompile(`^azure:///subscriptions/([^/]+)/resourceGroups/([^/]+)/providers/Microsoft.Compute/virtualMachines/([^/]+)$`)
|
||||
azureVMSSProviderIDRegexp = regexp.MustCompile(`^azure:///subscriptions/([^/]+)/resourceGroups/([^/]+)/providers/Microsoft.Compute/virtualMachineScaleSets/([^/]+)/virtualMachines/([^/]+)$`)
|
||||
)
|
||||
|
||||
// BasicsFromProviderID extracts subscriptionID and resourceGroup from both types of valid azure providerID.
|
||||
func BasicsFromProviderID(providerID string) (subscriptionID, resourceGroup string, err error) {
|
||||
subscriptionID, resourceGroup, _, err = VMInformationFromProviderID(providerID)
|
||||
if err == nil {
|
||||
return subscriptionID, resourceGroup, nil
|
||||
}
|
||||
subscriptionID, resourceGroup, _, _, err = ScaleSetInformationFromProviderID(providerID)
|
||||
if err == nil {
|
||||
return subscriptionID, resourceGroup, nil
|
||||
}
|
||||
return "", "", fmt.Errorf("providerID %v is malformatted", providerID)
|
||||
}
|
||||
|
||||
// UIDFromProviderID extracts our own generated unique ID, which is the
|
||||
// suffix at the resource group, e.g., resource-group-J18dB
|
||||
// J18dB is the UID.
|
||||
func UIDFromProviderID(providerID string) (string, error) {
|
||||
_, resourceGroup, err := BasicsFromProviderID(providerID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
parts := strings.Split(resourceGroup, "-")
|
||||
return parts[len(parts)-1], nil
|
||||
}
|
||||
|
||||
// VMInformationFromProviderID splits a provider's id belonging to a single azure instance into core components.
|
||||
// A providerID for individual VMs is build after the following schema:
|
||||
// - 'azure:///subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Compute/virtualMachines/<instance-name>'
|
||||
func VMInformationFromProviderID(providerID string) (subscriptionID, resourceGroup, instanceName string, err error) {
|
||||
matches := azureVMProviderIDRegexp.FindStringSubmatch(providerID)
|
||||
if len(matches) != 4 {
|
||||
return "", "", "", errors.New("error splitting providerID")
|
||||
}
|
||||
return matches[1], matches[2], matches[3], nil
|
||||
}
|
||||
|
||||
// ScaleSetInformationFromProviderID splits a provider's id belonging to an azure scaleset into core components.
|
||||
// A providerID for scale set VMs is build after the following schema:
|
||||
// - 'azure:///subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Compute/virtualMachineScaleSets/<scale-set-name>/virtualMachines/<instance-id>'
|
||||
func ScaleSetInformationFromProviderID(providerID string) (subscriptionID, resourceGroup, scaleSet, instanceID string, err error) {
|
||||
matches := azureVMSSProviderIDRegexp.FindStringSubmatch(providerID)
|
||||
if len(matches) != 5 {
|
||||
return "", "", "", "", errors.New("error splitting providerID")
|
||||
}
|
||||
return matches[1], matches[2], matches[3], matches[4], nil
|
||||
}
|
177
internal/azureshared/metadata_test.go
Normal file
177
internal/azureshared/metadata_test.go
Normal file
@ -0,0 +1,177 @@
|
||||
package azureshared
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBasicsFromProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantErr bool
|
||||
wantSubscriptionID string
|
||||
wantResourceGroup string
|
||||
}{
|
||||
"providerID for individual instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
},
|
||||
"providerID for scale set instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name/virtualMachines/instance-id",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
subscriptionID, resourceGroup, err := BasicsFromProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||
assert.Equal(tc.wantResourceGroup, resourceGroup)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIDFromProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantUID string
|
||||
wantErr bool
|
||||
}{
|
||||
"UID from virtual machine works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group-ABC123/providers/Microsoft.Compute/virtualMachines/instance-name",
|
||||
wantUID: "ABC123",
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
uid, err := UIDFromProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.Equal(tc.wantUID, uid)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVMInformationFromProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantSubscriptionID string
|
||||
wantResourceGroup string
|
||||
wantInstanceName string
|
||||
wantErr bool
|
||||
}{
|
||||
"simple id": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-id",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
wantInstanceName: "instance-id",
|
||||
},
|
||||
"missing instance": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines",
|
||||
wantErr: true,
|
||||
},
|
||||
"providerID for scale set instance must fail": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name/virtualMachines/instance-id",
|
||||
wantErr: true,
|
||||
},
|
||||
"wrong provider": {
|
||||
providerID: "gcp:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-id",
|
||||
wantErr: true,
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
subscriptionID, resourceGroup, instanceName, err := VMInformationFromProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||
assert.Equal(tc.wantResourceGroup, resourceGroup)
|
||||
assert.Equal(tc.wantInstanceName, instanceName)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaleSetInformationFromProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantSubscriptionID string
|
||||
wantResourceGroup string
|
||||
wantScaleSet string
|
||||
wantInstanceID string
|
||||
wantErr bool
|
||||
}{
|
||||
"providerID for scale set instance works": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name/virtualMachines/instance-id",
|
||||
wantSubscriptionID: "subscription-id",
|
||||
wantResourceGroup: "resource-group",
|
||||
wantScaleSet: "scale-set-name",
|
||||
wantInstanceID: "instance-id",
|
||||
},
|
||||
"providerID for individual instance must fail": {
|
||||
providerID: "azure:///subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachines/instance-name",
|
||||
wantErr: true,
|
||||
},
|
||||
"providerID is malformed": {
|
||||
providerID: "malformed-provider-id",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
subscriptionID, resourceGroup, scaleSet, instanceName, err := ScaleSetInformationFromProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantSubscriptionID, subscriptionID)
|
||||
assert.Equal(tc.wantResourceGroup, resourceGroup)
|
||||
assert.Equal(tc.wantScaleSet, scaleSet)
|
||||
assert.Equal(tc.wantInstanceID, instanceName)
|
||||
})
|
||||
}
|
||||
}
|
24
internal/gcpshared/metadata.go
Normal file
24
internal/gcpshared/metadata.go
Normal file
@ -0,0 +1,24 @@
|
||||
package gcpshared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var providerIDRegex = regexp.MustCompile(`^gce://([^/]+)/([^/]+)/([^/]+)$`)
|
||||
|
||||
// SplitProviderID splits a provider's id into core components.
|
||||
// A providerID is build after the schema 'gce://<project-id>/<zone>/<instance-name>'
|
||||
func SplitProviderID(providerID string) (project, zone, instance string, err error) {
|
||||
matches := providerIDRegex.FindStringSubmatch(providerID)
|
||||
if len(matches) != 4 {
|
||||
return "", "", "", fmt.Errorf("error splitting providerID: %v", providerID)
|
||||
}
|
||||
return matches[1], matches[2], matches[3], nil
|
||||
}
|
||||
|
||||
// JoinProviderID builds a k8s provider ID for GCP instances.
|
||||
// A providerID is build after the schema 'gce://<project-id>/<zone>/<instance-name>'
|
||||
func JoinProviderID(project, zone, instanceName string) string {
|
||||
return fmt.Sprintf("gce://%v/%v/%v", project, zone, instanceName)
|
||||
}
|
75
internal/gcpshared/metadata_test.go
Normal file
75
internal/gcpshared/metadata_test.go
Normal file
@ -0,0 +1,75 @@
|
||||
package gcpshared
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSplitProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
providerID string
|
||||
wantProjectID string
|
||||
wantZone string
|
||||
wantInstance string
|
||||
wantErr bool
|
||||
}{
|
||||
"simple id": {
|
||||
providerID: "gce://someProject/someZone/someInstance",
|
||||
wantProjectID: "someProject",
|
||||
wantZone: "someZone",
|
||||
wantInstance: "someInstance",
|
||||
},
|
||||
"incomplete id": {
|
||||
providerID: "gce://someProject/someZone",
|
||||
wantErr: true,
|
||||
},
|
||||
"wrong provider": {
|
||||
providerID: "azure://someProject/someZone/someInstance",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
projectID, zone, instance, err := SplitProviderID(tc.providerID)
|
||||
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.wantProjectID, projectID)
|
||||
assert.Equal(tc.wantZone, zone)
|
||||
assert.Equal(tc.wantInstance, instance)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoinProviderID(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
projectID string
|
||||
zone string
|
||||
instance string
|
||||
wantProviderID string
|
||||
}{
|
||||
"simple id": {
|
||||
projectID: "someProject",
|
||||
zone: "someZone",
|
||||
instance: "someInstance",
|
||||
wantProviderID: "gce://someProject/someZone/someInstance",
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
providerID := JoinProviderID(tc.projectID, tc.zone, tc.instance)
|
||||
|
||||
assert.Equal(tc.wantProviderID, providerID)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user