mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-06-19 11:44:20 -04:00
AB#2104 Feat/azure logging (#198)
implementation for azure early boot logging
This commit is contained in:
parent
963c6f98e5
commit
84552ca8f7
33 changed files with 526 additions and 212 deletions
|
@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- Early boot logging for Cloud Provider: GCP & Azure
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/profiles/latest/authorization/mgmt/authorization"
|
"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/compute/armcompute"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
"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,
|
BeginCreateOrUpdate(ctx context.Context, resourceGroupName string, vmName string, parameters armcompute.VirtualMachine,
|
||||||
options *armcompute.VirtualMachinesClientBeginCreateOrUpdateOptions) (virtualMachinesClientCreateOrUpdatePollerResponse, error)
|
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/profiles/latest/authorization/mgmt/authorization"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
"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/compute/armcompute"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
"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)]
|
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/profiles/latest/authorization/mgmt/authorization"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
"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/compute/armcompute"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||||
|
@ -38,6 +39,7 @@ type Client struct {
|
||||||
applicationsAPI
|
applicationsAPI
|
||||||
servicePrincipalsAPI
|
servicePrincipalsAPI
|
||||||
roleAssignmentsAPI
|
roleAssignmentsAPI
|
||||||
|
applicationInsightsAPI
|
||||||
|
|
||||||
adReplicationLagCheckInterval time.Duration
|
adReplicationLagCheckInterval time.Duration
|
||||||
adReplicationLagCheckMaxRetries int
|
adReplicationLagCheckMaxRetries int
|
||||||
|
@ -82,6 +84,7 @@ func NewFromDefault(subscriptionID, tenantID string) (*Client, error) {
|
||||||
networkInterfacesAPI := armnetwork.NewInterfacesClient(subscriptionID, cred, nil)
|
networkInterfacesAPI := armnetwork.NewInterfacesClient(subscriptionID, cred, nil)
|
||||||
loadBalancersAPI := armnetwork.NewLoadBalancersClient(subscriptionID, cred, nil)
|
loadBalancersAPI := armnetwork.NewLoadBalancersClient(subscriptionID, cred, nil)
|
||||||
virtualMachinesAPI := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
|
virtualMachinesAPI := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
|
||||||
|
applicationInsightsAPI := armapplicationinsights.NewComponentsClient(subscriptionID, cred, nil)
|
||||||
applicationsAPI := graphrbac.NewApplicationsClient(tenantID)
|
applicationsAPI := graphrbac.NewApplicationsClient(tenantID)
|
||||||
applicationsAPI.Authorizer = graphAuthorizer
|
applicationsAPI.Authorizer = graphAuthorizer
|
||||||
servicePrincipalsAPI := graphrbac.NewServicePrincipalsClient(tenantID)
|
servicePrincipalsAPI := graphrbac.NewServicePrincipalsClient(tenantID)
|
||||||
|
@ -101,6 +104,7 @@ func NewFromDefault(subscriptionID, tenantID string) (*Client, error) {
|
||||||
servicePrincipalsAPI: &servicePrincipalsClient{&servicePrincipalsAPI},
|
servicePrincipalsAPI: &servicePrincipalsClient{&servicePrincipalsAPI},
|
||||||
roleAssignmentsAPI: &roleAssignmentsClient{&roleAssignmentsAPI},
|
roleAssignmentsAPI: &roleAssignmentsClient{&roleAssignmentsAPI},
|
||||||
virtualMachinesAPI: &virtualMachinesClient{virtualMachinesAPI},
|
virtualMachinesAPI: &virtualMachinesClient{virtualMachinesAPI},
|
||||||
|
applicationInsightsAPI: applicationInsightsAPI,
|
||||||
subscriptionID: subscriptionID,
|
subscriptionID: subscriptionID,
|
||||||
tenantID: tenantID,
|
tenantID: tenantID,
|
||||||
nodes: cloudtypes.Instances{},
|
nodes: cloudtypes.Instances{},
|
||||||
|
|
|
@ -25,6 +25,7 @@ type gcpclient interface {
|
||||||
type azureclient interface {
|
type azureclient interface {
|
||||||
GetState() (state.ConstellationState, error)
|
GetState() (state.ConstellationState, error)
|
||||||
SetState(state.ConstellationState) error
|
SetState(state.ConstellationState) error
|
||||||
|
CreateApplicationInsight(ctx context.Context) error
|
||||||
CreateResourceGroup(ctx context.Context) error
|
CreateResourceGroup(ctx context.Context) error
|
||||||
CreateExternalLoadBalancer(ctx context.Context) error
|
CreateExternalLoadBalancer(ctx context.Context) error
|
||||||
CreateVirtualNetwork(ctx context.Context) error
|
CreateVirtualNetwork(ctx context.Context) error
|
||||||
|
|
|
@ -69,6 +69,10 @@ func (c *fakeAzureClient) SetState(stat state.ConstellationState) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *fakeAzureClient) CreateApplicationInsight(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *fakeAzureClient) CreateResourceGroup(ctx context.Context) error {
|
func (c *fakeAzureClient) CreateResourceGroup(ctx context.Context) error {
|
||||||
c.resourceGroup = "resource-group"
|
c.resourceGroup = "resource-group"
|
||||||
return nil
|
return nil
|
||||||
|
@ -156,6 +160,7 @@ type stubAzureClient struct {
|
||||||
|
|
||||||
getStateErr error
|
getStateErr error
|
||||||
setStateErr error
|
setStateErr error
|
||||||
|
createApplicationInsightErr error
|
||||||
createResourceGroupErr error
|
createResourceGroupErr error
|
||||||
createVirtualNetworkErr error
|
createVirtualNetworkErr error
|
||||||
createSecurityGroupErr error
|
createSecurityGroupErr error
|
||||||
|
@ -178,6 +183,10 @@ func (c *stubAzureClient) CreateExternalLoadBalancer(ctx context.Context) error
|
||||||
return c.createLoadBalancerErr
|
return c.createLoadBalancerErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *stubAzureClient) CreateApplicationInsight(ctx context.Context) error {
|
||||||
|
return c.createApplicationInsightErr
|
||||||
|
}
|
||||||
|
|
||||||
func (c *stubAzureClient) CreateResourceGroup(ctx context.Context) error {
|
func (c *stubAzureClient) CreateResourceGroup(ctx context.Context) error {
|
||||||
return c.createResourceGroupErr
|
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 {
|
if err := cl.CreateInstances(ctx, createInput); err != nil {
|
||||||
return state.ConstellationState{}, err
|
return state.ConstellationState{}, err
|
||||||
}
|
}
|
||||||
|
if err := cl.CreateApplicationInsight(ctx); err != nil {
|
||||||
|
return state.ConstellationState{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return cl.GetState()
|
return cl.GetState()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package azure
|
||||||
import (
|
import (
|
||||||
"context"
|
"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/compute/armcompute"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
"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)
|
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)
|
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.
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return resources.Secrets{}, err
|
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
|
// 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/
|
// 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 {
|
if err != nil {
|
||||||
return resources.Secrets{}, err
|
return resources.Secrets{}, err
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func (c *CloudControllerManager) Secrets(ctx context.Context, instance cloudtype
|
||||||
}
|
}
|
||||||
|
|
||||||
vmType := "standard"
|
vmType := "standard"
|
||||||
if _, _, _, _, err := splitScaleSetProviderID(instance.ProviderID); err == nil {
|
if _, _, _, _, err := azureshared.ScaleSetInformationFromProviderID(instance.ProviderID); err == nil {
|
||||||
vmType = "vmss"
|
vmType = "vmss"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
package azure
|
package azure
|
||||||
|
|
||||||
import (
|
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"
|
"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
|
// NewLogger creates a new client to store information in Azure Application Insights
|
||||||
// https://github.com/Microsoft/ApplicationInsights-go
|
// https://github.com/Microsoft/ApplicationInsights-go
|
||||||
func NewLogger(instrumentationKey string) *Logger {
|
func NewLogger(ctx context.Context, metadata *Metadata) (*Logger, error) {
|
||||||
return &Logger{
|
providerID, err := metadata.providerID(ctx)
|
||||||
client: appinsights.NewTelemetryClient(instrumentationKey),
|
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!
|
// Disclose stores log information in Azure Application Insights!
|
||||||
|
|
|
@ -7,12 +7,14 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
"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/compute/armcompute"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||||
"github.com/edgelesssys/constellation/coordinator/core"
|
"github.com/edgelesssys/constellation/coordinator/core"
|
||||||
"github.com/edgelesssys/constellation/coordinator/role"
|
"github.com/edgelesssys/constellation/coordinator/role"
|
||||||
|
"github.com/edgelesssys/constellation/internal/azureshared"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -32,6 +34,7 @@ type Metadata struct {
|
||||||
virtualMachinesAPI
|
virtualMachinesAPI
|
||||||
virtualMachineScaleSetVMsAPI
|
virtualMachineScaleSetVMsAPI
|
||||||
tagsAPI
|
tagsAPI
|
||||||
|
applicationInsightsAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMetadata creates a new Metadata.
|
// NewMetadata creates a new Metadata.
|
||||||
|
@ -50,7 +53,7 @@ func NewMetadata(ctx context.Context) (*Metadata, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
subscriptionID, _, err := extractBasicsFromProviderID("azure://" + instanceMetadata.Compute.ResourceID)
|
subscriptionID, _, err := azureshared.BasicsFromProviderID("azure://" + instanceMetadata.Compute.ResourceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -63,6 +66,7 @@ func NewMetadata(ctx context.Context) (*Metadata, error) {
|
||||||
virtualMachinesAPI := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
|
virtualMachinesAPI := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
|
||||||
virtualMachineScaleSetVMsAPI := armcompute.NewVirtualMachineScaleSetVMsClient(subscriptionID, cred, nil)
|
virtualMachineScaleSetVMsAPI := armcompute.NewVirtualMachineScaleSetVMsClient(subscriptionID, cred, nil)
|
||||||
tagsAPI := armresources.NewTagsClient(subscriptionID, cred, nil)
|
tagsAPI := armresources.NewTagsClient(subscriptionID, cred, nil)
|
||||||
|
applicationInsightsAPI := armapplicationinsights.NewComponentsClient(subscriptionID, cred, nil)
|
||||||
|
|
||||||
return &Metadata{
|
return &Metadata{
|
||||||
imdsAPI: &imdsAPI,
|
imdsAPI: &imdsAPI,
|
||||||
|
@ -75,6 +79,7 @@ func NewMetadata(ctx context.Context) (*Metadata, error) {
|
||||||
virtualMachinesAPI: &virtualMachinesClient{virtualMachinesAPI},
|
virtualMachinesAPI: &virtualMachinesClient{virtualMachinesAPI},
|
||||||
virtualMachineScaleSetVMsAPI: &virtualMachineScaleSetVMsClient{virtualMachineScaleSetVMsAPI},
|
virtualMachineScaleSetVMsAPI: &virtualMachineScaleSetVMsClient{virtualMachineScaleSetVMsAPI},
|
||||||
tagsAPI: &tagsClient{tagsAPI},
|
tagsAPI: &tagsClient{tagsAPI},
|
||||||
|
applicationInsightsAPI: &applicationInsightsClient{applicationInsightsAPI},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +89,7 @@ func (m *Metadata) List(ctx context.Context) ([]cloudtypes.Instance, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -131,7 +136,7 @@ func (m *Metadata) SignalRole(ctx context.Context, role role.Role) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// scale set instances cannot store tags and role can be inferred from scale set name.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -144,7 +149,7 @@ func (m *Metadata) GetNetworkSecurityGroupName(ctx context.Context) (string, err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -165,7 +170,7 @@ func (m *Metadata) GetSubnetworkCIDR(ctx context.Context) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -187,7 +192,7 @@ func (m *Metadata) getLoadBalancer(ctx context.Context) (*armnetwork.LoadBalance
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -253,7 +258,7 @@ func (m *Metadata) GetLoadBalancerIP(ctx context.Context) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
_, resourceGroup, err := extractBasicsFromProviderID(providerID)
|
_, resourceGroup, err := azureshared.BasicsFromProviderID(providerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -286,19 +291,6 @@ func (m *Metadata) providerID(ctx context.Context) (string, error) {
|
||||||
return "azure://" + instanceMetadata.Compute.ResourceID, nil
|
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.
|
// extractInstanceTags converts azure tags into metadata key-value pairs.
|
||||||
func extractInstanceTags(tags map[string]*string) map[string]string {
|
func extractInstanceTags(tags map[string]*string) map[string]string {
|
||||||
metadataMap := 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) {
|
func TestExtractInstanceTags(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
in map[string]*string
|
in map[string]*string
|
||||||
|
|
|
@ -9,17 +9,17 @@ import (
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||||
"github.com/edgelesssys/constellation/coordinator/role"
|
"github.com/edgelesssys/constellation/coordinator/role"
|
||||||
|
"github.com/edgelesssys/constellation/internal/azureshared"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
azureVMSSProviderIDRegexp = regexp.MustCompile(`^azure:///subscriptions/([^/]+)/resourceGroups/([^/]+)/providers/Microsoft.Compute/virtualMachineScaleSets/([^/]+)/virtualMachines/([^/]+)$`)
|
|
||||||
coordinatorScaleSetRegexp = regexp.MustCompile(`constellation-scale-set-coordinators-[0-9a-zA-Z]+$`)
|
coordinatorScaleSetRegexp = regexp.MustCompile(`constellation-scale-set-coordinators-[0-9a-zA-Z]+$`)
|
||||||
nodeScaleSetRegexp = regexp.MustCompile(`constellation-scale-set-nodes-[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.
|
// getScaleSetVM tries to get an azure vm belonging to a scale set.
|
||||||
func (m *Metadata) getScaleSetVM(ctx context.Context, providerID string) (cloudtypes.Instance, error) {
|
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 {
|
if err != nil {
|
||||||
return cloudtypes.Instance{}, err
|
return cloudtypes.Instance{}, err
|
||||||
}
|
}
|
||||||
|
@ -70,17 +70,6 @@ func (m *Metadata) listScaleSetVMs(ctx context.Context, resourceGroup string) ([
|
||||||
return instances, nil
|
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.
|
// 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) {
|
func convertScaleSetVMToCoreInstance(scaleSet string, vm armcompute.VirtualMachineScaleSetVM, networkInterfaces []armnetwork.Interface, publicIPAddresses []string) (cloudtypes.Instance, error) {
|
||||||
if vm.ID == nil {
|
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) {
|
func TestConvertScaleSetVMToCoreInstance(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
inVM armcompute.VirtualMachineScaleSetVM
|
inVM armcompute.VirtualMachineScaleSetVM
|
||||||
|
|
|
@ -2,9 +2,7 @@ package azure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
|
"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/network/armnetwork"
|
||||||
|
@ -12,13 +10,11 @@ import (
|
||||||
"github.com/Azure/go-autorest/autorest/to"
|
"github.com/Azure/go-autorest/autorest/to"
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider"
|
"github.com/edgelesssys/constellation/coordinator/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
"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) {
|
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 {
|
if err != nil {
|
||||||
return cloudtypes.Instance{}, err
|
return cloudtypes.Instance{}, err
|
||||||
}
|
}
|
||||||
|
@ -73,17 +69,6 @@ func (m *Metadata) setTag(ctx context.Context, key, value string) error {
|
||||||
return err
|
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.
|
// convertVMToCoreInstance converts an azure virtual machine with interface configurations into a cloudtypes.Instance.
|
||||||
func convertVMToCoreInstance(vm armcompute.VirtualMachine, networkInterfaces []armnetwork.Interface) (cloudtypes.Instance, error) {
|
func convertVMToCoreInstance(vm armcompute.VirtualMachine, networkInterfaces []armnetwork.Interface) (cloudtypes.Instance, error) {
|
||||||
if vm.Name == nil || vm.ID == nil {
|
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) {
|
func TestConvertVMToCoreInstance(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
inVM armcompute.VirtualMachine
|
inVM armcompute.VirtualMachine
|
||||||
|
|
|
@ -3,6 +3,7 @@ package azure
|
||||||
import (
|
import (
|
||||||
"context"
|
"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/compute/armcompute"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
||||||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
"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 {
|
func (c *scaleSetsClient) List(resourceGroupName string, options *armcompute.VirtualMachineScaleSetsClientListOptions) virtualMachineScaleSetsClientListPager {
|
||||||
return c.VirtualMachineScaleSetsClient.List(resourceGroupName, options)
|
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
|
// reference: https://github.com/kubernetes/cloud-provider-gcp/blob/master/cluster/gce/gci/configure-helper.sh#L791-L892
|
||||||
var config strings.Builder
|
var config strings.Builder
|
||||||
config.WriteString("[global]\n")
|
config.WriteString("[global]\n")
|
||||||
projectID, _, _, err := splitProviderID(instance.ProviderID)
|
projectID, _, _, err := gcpshared.SplitProviderID(instance.ProviderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resources.ConfigMaps{}, err
|
return resources.ConfigMaps{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ package gcp
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
compute "cloud.google.com/go/compute/apiv1"
|
compute "cloud.google.com/go/compute/apiv1"
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider"
|
"github.com/edgelesssys/constellation/coordinator/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||||
"github.com/edgelesssys/constellation/coordinator/core"
|
"github.com/edgelesssys/constellation/coordinator/core"
|
||||||
|
"github.com/edgelesssys/constellation/internal/gcpshared"
|
||||||
"google.golang.org/api/iterator"
|
"google.golang.org/api/iterator"
|
||||||
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
|
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
@ -17,8 +17,6 @@ import (
|
||||||
|
|
||||||
const gcpSSHMetadataKey = "ssh-keys"
|
const gcpSSHMetadataKey = "ssh-keys"
|
||||||
|
|
||||||
var providerIDRegex = regexp.MustCompile(`^gce://([^/]+)/([^/]+)/([^/]+)$`)
|
|
||||||
|
|
||||||
// Client implements the gcp.API interface.
|
// Client implements the gcp.API interface.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
instanceAPI
|
instanceAPI
|
||||||
|
@ -325,7 +323,7 @@ func convertToCoreInstance(in *computepb.Instance, project string, zone string)
|
||||||
metadata := extractInstanceMetadata(in.Metadata, "", false)
|
metadata := extractInstanceMetadata(in.Metadata, "", false)
|
||||||
return cloudtypes.Instance{
|
return cloudtypes.Instance{
|
||||||
Name: *in.Name,
|
Name: *in.Name,
|
||||||
ProviderID: joinProviderID(project, zone, *in.Name),
|
ProviderID: gcpshared.JoinProviderID(project, zone, *in.Name),
|
||||||
Role: cloudprovider.ExtractRole(metadata),
|
Role: cloudprovider.ExtractRole(metadata),
|
||||||
PrivateIPs: extractPrivateIPs(in.NetworkInterfaces),
|
PrivateIPs: extractPrivateIPs(in.NetworkInterfaces),
|
||||||
PublicIPs: extractPublicIPs(in.NetworkInterfaces),
|
PublicIPs: extractPublicIPs(in.NetworkInterfaces),
|
||||||
|
@ -334,22 +332,6 @@ func convertToCoreInstance(in *computepb.Instance, project string, zone string)
|
||||||
}, nil
|
}, 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.
|
// extractInstanceMetadata will extract the list of instance metadata key-value pairs into a map.
|
||||||
// If "skipKey" is true, "key" will be skipped.
|
// If "skipKey" is true, "key" will be skipped.
|
||||||
func extractInstanceMetadata(in *computepb.Metadata, key string, skipKey bool) map[string]string {
|
func extractInstanceMetadata(in *computepb.Metadata, key string, skipKey bool) map[string]string {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"cloud.google.com/go/logging"
|
"cloud.google.com/go/logging"
|
||||||
|
"github.com/edgelesssys/constellation/internal/gcpshared"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
|
@ -15,7 +16,7 @@ type Logger struct {
|
||||||
// NewLogger creates a new Cloud Logger for GCP.
|
// NewLogger creates a new Cloud Logger for GCP.
|
||||||
// https://cloud.google.com/logging/docs/setup/go
|
// https://cloud.google.com/logging/docs/setup/go
|
||||||
func NewLogger(ctx context.Context, providerID string, logName string) (*Logger, error) {
|
func NewLogger(ctx context.Context, providerID string, logName string) (*Logger, error) {
|
||||||
projectID, _, _, err := splitProviderID(providerID)
|
projectID, _, _, err := gcpshared.SplitProviderID(providerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
"github.com/edgelesssys/constellation/coordinator/cloudprovider/cloudtypes"
|
||||||
"github.com/edgelesssys/constellation/coordinator/core"
|
"github.com/edgelesssys/constellation/coordinator/core"
|
||||||
"github.com/edgelesssys/constellation/coordinator/role"
|
"github.com/edgelesssys/constellation/coordinator/role"
|
||||||
|
"github.com/edgelesssys/constellation/internal/gcpshared"
|
||||||
)
|
)
|
||||||
|
|
||||||
// API handles all GCP API requests.
|
// 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.
|
// GetInstance retrieves an instance using its providerID.
|
||||||
func (m *Metadata) GetInstance(ctx context.Context, providerID string) (cloudtypes.Instance, error) {
|
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 {
|
if err != nil {
|
||||||
return cloudtypes.Instance{}, fmt.Errorf("invalid providerID: %w", err)
|
return cloudtypes.Instance{}, fmt.Errorf("invalid providerID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,10 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
// TODO: Implement cloud logging for Azure
|
cloudLogger, err = azurecloud.NewLogger(context.Background(), metadata)
|
||||||
cloudLogger = &logging.NopLogger{}
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
coreMetadata = metadata
|
coreMetadata = metadata
|
||||||
kube = kubernetes.New("azure", k8sapi.NewKubernetesUtil(), &k8sapi.CoreOSConfiguration{}, kubectl.New(), azurecloud.NewCloudControllerManager(metadata), &azurecloud.CloudNodeManager{}, &azurecloud.Autoscaler{}, 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/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/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/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/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/network/armnetwork v0.3.1
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources 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/ec2 v1.32.0
|
||||||
github.com/aws/aws-sdk-go-v2/service/kms v1.16.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/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/coreos/go-systemd/v22 v22.3.2
|
||||||
github.com/docker/docker v20.10.13+incompatible
|
github.com/docker/docker v20.10.13+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
|
@ -118,6 +118,7 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c // indirect
|
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/gofrs/uuid v4.0.0+incompatible // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // 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/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 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/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 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/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=
|
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/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/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/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/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/network/armnetwork v0.3.1 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources 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/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 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/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 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/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=
|
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…
Add table
Add a link
Reference in a new issue