mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-02 06:16:08 -04:00
Use tags for UID and role parsing (#242)
* Apply tags to all applicable GCP resources * Move GCP UID and role from VM metadata to labels * Adjust Azure tags to be in line with GCP and AWS * Dont rely on resource name to find resources Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
c2814aeddb
commit
b35b74b772
34 changed files with 344 additions and 360 deletions
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// getScaleSets retrieves the IDs of all scale sets of a resource group.
|
||||
func (c *Client) getScaleSets(ctx context.Context) ([]string, error) {
|
||||
pager := c.scaleSetsAPI.NewListPager(c.config.ResourceGroup, nil)
|
||||
var scaleSets []string
|
||||
|
||||
for pager.More() {
|
||||
page, err := pager.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("paging scale sets: %w", err)
|
||||
}
|
||||
for _, scaleSet := range page.Value {
|
||||
if scaleSet == nil || scaleSet.ID == nil {
|
||||
continue
|
||||
}
|
||||
scaleSets = append(scaleSets, *scaleSet.ID)
|
||||
}
|
||||
}
|
||||
return scaleSets, nil
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
|
||||
armcomputev2 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetScaleSets(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
scaleSet armcomputev2.VirtualMachineScaleSet
|
||||
fetchPageErr error
|
||||
wantScaleSets []string
|
||||
wantErr bool
|
||||
}{
|
||||
"fetching scale sets works": {
|
||||
scaleSet: armcomputev2.VirtualMachineScaleSet{
|
||||
ID: to.Ptr("/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name"),
|
||||
},
|
||||
wantScaleSets: []string{"/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/scale-set-name"},
|
||||
},
|
||||
"fetching scale sets fails": {
|
||||
fetchPageErr: errors.New("fetch page error"),
|
||||
wantErr: true,
|
||||
},
|
||||
"scale set is invalid": {},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
client := Client{
|
||||
scaleSetsAPI: &stubScaleSetsAPI{
|
||||
pager: &stubVMSSPager{
|
||||
list: []armcomputev2.VirtualMachineScaleSet{tc.scaleSet},
|
||||
fetchErr: tc.fetchPageErr,
|
||||
},
|
||||
},
|
||||
}
|
||||
gotScaleSets, err := client.getScaleSets(context.Background())
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.ElementsMatch(tc.wantScaleSets, gotScaleSets)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -80,34 +80,35 @@ func (c *Client) GetAutoscalingGroupName(scalingGroupID string) (string, error)
|
|||
|
||||
// ListScalingGroups retrieves a list of scaling groups for the cluster.
|
||||
func (c *Client) ListScalingGroups(ctx context.Context, uid string) (controlPlaneGroupIDs []string, workerGroupIDs []string, err error) {
|
||||
scaleSetIDs, err := c.getScaleSets(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("listing scaling groups: %w", err)
|
||||
}
|
||||
for _, scaleSetID := range scaleSetIDs {
|
||||
_, _, scaleSet, err := splitVMSSID(scaleSetID)
|
||||
pager := c.scaleSetsAPI.NewListPager(c.config.ResourceGroup, nil)
|
||||
|
||||
for pager.More() {
|
||||
page, err := pager.NextPage(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("getting scaling group name: %w", err)
|
||||
return nil, nil, fmt.Errorf("paging scale sets: %w", err)
|
||||
}
|
||||
if isControlPlaneInstanceGroup(scaleSet) {
|
||||
controlPlaneGroupIDs = append(controlPlaneGroupIDs, scaleSetID)
|
||||
} else if isWorkerInstanceGroup(scaleSet) {
|
||||
workerGroupIDs = append(workerGroupIDs, scaleSetID)
|
||||
for _, scaleSet := range page.Value {
|
||||
if scaleSet == nil || scaleSet.ID == nil {
|
||||
continue
|
||||
}
|
||||
if scaleSet.Tags == nil || scaleSet.Tags["constellation-uid"] == nil || *scaleSet.Tags["constellation-uid"] != uid {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("getting scaling group name: %w", err)
|
||||
}
|
||||
switch *scaleSet.Tags["constellation-role"] {
|
||||
case "control-plane", "controlplane":
|
||||
controlPlaneGroupIDs = append(controlPlaneGroupIDs, *scaleSet.ID)
|
||||
case "worker":
|
||||
workerGroupIDs = append(workerGroupIDs, *scaleSet.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return controlPlaneGroupIDs, workerGroupIDs, nil
|
||||
}
|
||||
|
||||
// isControlPlaneInstanceGroup returns true if the instance group is a control plane instance group.
|
||||
func isControlPlaneInstanceGroup(instanceGroupName string) bool {
|
||||
return strings.Contains(instanceGroupName, "control-plane")
|
||||
}
|
||||
|
||||
// isWorkerInstanceGroup returns true if the instance group is a worker instance group.
|
||||
func isWorkerInstanceGroup(instanceGroupName string) bool {
|
||||
return strings.Contains(instanceGroupName, "worker")
|
||||
}
|
||||
|
||||
func imageReferenceFromImage(img string) *armcompute.ImageReference {
|
||||
ref := &armcompute.ImageReference{}
|
||||
|
||||
|
|
|
@ -193,15 +193,33 @@ func TestListScalingGroups(t *testing.T) {
|
|||
"listing control-plane works": {
|
||||
scaleSet: armcomputev2.VirtualMachineScaleSet{
|
||||
ID: to.Ptr("/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/constellation-scale-set-control-planes-uid"),
|
||||
Tags: map[string]*string{
|
||||
"constellation-uid": to.Ptr("uid"),
|
||||
"constellation-role": to.Ptr("control-plane"),
|
||||
},
|
||||
},
|
||||
wantControlPlanes: []string{"/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/constellation-scale-set-control-planes-uid"},
|
||||
},
|
||||
"listing worker works": {
|
||||
scaleSet: armcomputev2.VirtualMachineScaleSet{
|
||||
ID: to.Ptr("/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/constellation-scale-set-workers-uid"),
|
||||
Tags: map[string]*string{
|
||||
"constellation-uid": to.Ptr("uid"),
|
||||
"constellation-role": to.Ptr("worker"),
|
||||
},
|
||||
},
|
||||
wantWorkers: []string{"/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/constellation-scale-set-workers-uid"},
|
||||
},
|
||||
"listing is not dependent on resource name": {
|
||||
scaleSet: armcomputev2.VirtualMachineScaleSet{
|
||||
ID: to.Ptr("/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/some-scale-set"),
|
||||
Tags: map[string]*string{
|
||||
"constellation-uid": to.Ptr("uid"),
|
||||
"constellation-role": to.Ptr("control-plane"),
|
||||
},
|
||||
},
|
||||
wantControlPlanes: []string{"/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/some-scale-set"},
|
||||
},
|
||||
"listing other works": {
|
||||
scaleSet: armcomputev2.VirtualMachineScaleSet{
|
||||
ID: to.Ptr("/subscriptions/subscription-id/resourceGroups/resource-group/providers/Microsoft.Compute/virtualMachineScaleSets/other"),
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var instanceGroupIDRegex = regexp.MustCompile(`^projects/([^/]+)/zones/([^/]+)/instanceGroupManagers/([^/]+)$`)
|
||||
|
@ -36,16 +35,6 @@ func splitInstanceGroupID(instanceGroupID string) (project, zone, instanceGroup
|
|||
return matches[1], matches[2], matches[3], nil
|
||||
}
|
||||
|
||||
// isControlPlaneInstanceGroup returns true if the instance group is a control plane instance group.
|
||||
func isControlPlaneInstanceGroup(instanceGroupName string) bool {
|
||||
return strings.Contains(instanceGroupName, "control-plane")
|
||||
}
|
||||
|
||||
// isWorkerInstanceGroup returns true if the instance group is a worker instance group.
|
||||
func isWorkerInstanceGroup(instanceGroupName string) bool {
|
||||
return strings.Contains(instanceGroupName, "worker")
|
||||
}
|
||||
|
||||
// generateInstanceName generates a random instance name.
|
||||
func generateInstanceName(baseInstanceName string, random prng) string {
|
||||
letters := []byte("abcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
|
|
@ -10,10 +10,10 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/api/iterator"
|
||||
computepb "google.golang.org/genproto/googleapis/cloud/compute/v1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// GetScalingGroupImage returns the image URI of the scaling group.
|
||||
|
@ -108,7 +108,6 @@ func (c *Client) GetAutoscalingGroupName(scalingGroupID string) (string, error)
|
|||
// ListScalingGroups retrieves a list of scaling groups for the cluster.
|
||||
func (c *Client) ListScalingGroups(ctx context.Context, uid string) (controlPlaneGroupIDs []string, workerGroupIDs []string, err error) {
|
||||
iter := c.instanceGroupManagersAPI.AggregatedList(ctx, &computepb.AggregatedListInstanceGroupManagersRequest{
|
||||
Filter: proto.String(fmt.Sprintf("name eq \".+-%s-.+\"", uid)), // filter by constellation UID
|
||||
Project: c.projectID,
|
||||
})
|
||||
for instanceGroupManagerScopedListPair, err := iter.Next(); ; instanceGroupManagerScopedListPair, err = iter.Next() {
|
||||
|
@ -121,18 +120,38 @@ func (c *Client) ListScalingGroups(ctx context.Context, uid string) (controlPlan
|
|||
if instanceGroupManagerScopedListPair.Value == nil {
|
||||
continue
|
||||
}
|
||||
for _, instanceGroupManager := range instanceGroupManagerScopedListPair.Value.InstanceGroupManagers {
|
||||
if instanceGroupManager == nil || instanceGroupManager.Name == nil || instanceGroupManager.SelfLink == nil {
|
||||
for _, grpManager := range instanceGroupManagerScopedListPair.Value.InstanceGroupManagers {
|
||||
if grpManager == nil || grpManager.Name == nil || grpManager.SelfLink == nil || grpManager.InstanceTemplate == nil {
|
||||
continue
|
||||
}
|
||||
groupID, err := c.canonicalInstanceGroupID(ctx, *instanceGroupManager.SelfLink)
|
||||
|
||||
templateURI := strings.Split(*grpManager.InstanceTemplate, "/")
|
||||
if len(templateURI) < 1 {
|
||||
continue // invalid template URI
|
||||
}
|
||||
template, err := c.instanceTemplateAPI.Get(ctx, &computepb.GetInstanceTemplateRequest{
|
||||
Project: c.projectID,
|
||||
InstanceTemplate: templateURI[len(templateURI)-1],
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("getting instance template: %w", err)
|
||||
}
|
||||
if template.Properties == nil || template.Properties.Labels == nil {
|
||||
continue
|
||||
}
|
||||
if template.Properties.Labels["constellation-uid"] != uid {
|
||||
continue
|
||||
}
|
||||
|
||||
groupID, err := c.canonicalInstanceGroupID(ctx, *grpManager.SelfLink)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("normalizing instance group ID: %w", err)
|
||||
}
|
||||
|
||||
if isControlPlaneInstanceGroup(*instanceGroupManager.Name) {
|
||||
switch strings.ToLower(template.Properties.Labels["constellation-role"]) {
|
||||
case "control-plane", "controlplane":
|
||||
controlPlaneGroupIDs = append(controlPlaneGroupIDs, groupID)
|
||||
} else if isWorkerInstanceGroup(*instanceGroupManager.Name) {
|
||||
case "worker":
|
||||
workerGroupIDs = append(workerGroupIDs, groupID)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -326,7 +326,10 @@ func TestListScalingGroups(t *testing.T) {
|
|||
testCases := map[string]struct {
|
||||
name *string
|
||||
groupID *string
|
||||
templateRef *string
|
||||
templateLabels map[string]string
|
||||
listInstanceGroupManagersErr error
|
||||
templateGetErr error
|
||||
wantControlPlanes []string
|
||||
wantWorkers []string
|
||||
wantErr bool
|
||||
|
@ -335,23 +338,56 @@ func TestListScalingGroups(t *testing.T) {
|
|||
listInstanceGroupManagersErr: errors.New("list instance group managers error"),
|
||||
wantErr: true,
|
||||
},
|
||||
"get instance template fails": {
|
||||
name: proto.String("test-control-plane-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-control-plane-uid"),
|
||||
templateRef: proto.String("projects/project/global/instanceTemplates/test-control-plane-uid"),
|
||||
templateGetErr: errors.New("get instance template error"),
|
||||
wantErr: true,
|
||||
},
|
||||
"list instance group managers for control plane": {
|
||||
name: proto.String("test-control-plane-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-control-plane-uid"),
|
||||
name: proto.String("test-control-plane-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-control-plane-uid"),
|
||||
templateRef: proto.String("projects/project/global/instanceTemplates/test-control-plane-uid"),
|
||||
templateLabels: map[string]string{
|
||||
"constellation-uid": "uid",
|
||||
"constellation-role": "control-plane",
|
||||
},
|
||||
wantControlPlanes: []string{
|
||||
"projects/project/zones/zone/instanceGroupManagers/test-control-plane-uid",
|
||||
},
|
||||
},
|
||||
"list instance group managers for worker": {
|
||||
name: proto.String("test-worker-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-worker-uid"),
|
||||
name: proto.String("test-worker-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-worker-uid"),
|
||||
templateRef: proto.String("projects/project/global/instanceTemplates/test-control-plane-uid"),
|
||||
templateLabels: map[string]string{
|
||||
"constellation-uid": "uid",
|
||||
"constellation-role": "worker",
|
||||
},
|
||||
wantWorkers: []string{
|
||||
"projects/project/zones/zone/instanceGroupManagers/test-worker-uid",
|
||||
},
|
||||
},
|
||||
"listing instance group managers is not dependant on resource name": {
|
||||
name: proto.String("some-instance-group-manager"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/some-instance-group-manager"),
|
||||
templateRef: proto.String("projects/project/global/instanceTemplates/some-instance-group-template"),
|
||||
templateLabels: map[string]string{
|
||||
"constellation-uid": "uid",
|
||||
"constellation-role": "control-plane",
|
||||
},
|
||||
wantControlPlanes: []string{
|
||||
"projects/project/zones/zone/instanceGroupManagers/some-instance-group-manager",
|
||||
},
|
||||
},
|
||||
"unrelated instance group manager": {
|
||||
name: proto.String("test-unrelated-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-unrelated-uid"),
|
||||
name: proto.String("test-control-plane-uid"),
|
||||
groupID: proto.String("projects/project/zones/zone/instanceGroupManagers/test-unrelated-uid"),
|
||||
templateRef: proto.String("projects/project/global/instanceTemplates/test-control-plane-uid"),
|
||||
templateLabels: map[string]string{
|
||||
"label": "value",
|
||||
},
|
||||
},
|
||||
"invalid instance group manager": {},
|
||||
}
|
||||
|
@ -365,10 +401,19 @@ func TestListScalingGroups(t *testing.T) {
|
|||
instanceGroupManagersAPI: &stubInstanceGroupManagersAPI{
|
||||
aggregatedListErr: tc.listInstanceGroupManagersErr,
|
||||
instanceGroupManager: &computepb.InstanceGroupManager{
|
||||
Name: tc.name,
|
||||
SelfLink: tc.groupID,
|
||||
Name: tc.name,
|
||||
SelfLink: tc.groupID,
|
||||
InstanceTemplate: tc.templateRef,
|
||||
},
|
||||
},
|
||||
instanceTemplateAPI: &stubInstanceTemplateAPI{
|
||||
template: &computepb.InstanceTemplate{
|
||||
Properties: &computepb.InstanceProperties{
|
||||
Labels: tc.templateLabels,
|
||||
},
|
||||
},
|
||||
getErr: tc.templateGetErr,
|
||||
},
|
||||
}
|
||||
gotControlPlanes, gotWorkers, err := client.ListScalingGroups(context.Background(), "uid")
|
||||
if tc.wantErr {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue