Availability zone randomisation

This commit is contained in:
schulze 2023-04-17 15:54:42 +02:00
parent 3fb51d8f84
commit e8962c3cba
2 changed files with 55 additions and 5 deletions

View File

@ -7,6 +7,7 @@ import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ec2"
"github.com/google/uuid"
"github.com/thefeli73/polemos/state"
)
@ -38,6 +39,7 @@ func AWSUpdateService(config state.Config, region string, service state.CustomUU
// AWSMoveInstance moves a specified instance to a new availability region
func AWSMoveInstance(config state.Config) (state.Config) {
// pseudorandom instance from all services for testing
var serviceUUID state.CustomUUID
var instance state.Service
@ -47,7 +49,7 @@ func AWSMoveInstance(config state.Config) (state.Config) {
break
}
fmt.Println("MTD move service:\t", serviceUUID)
fmt.Println("MTD move service:\t", uuid.UUID.String(uuid.UUID(serviceUUID)))
region, instanceID := DecodeCloudID(instance.CloudID)
awsConfig := NewConfig(region, config.AWS.CredentialsPath)
@ -73,7 +75,7 @@ func AWSMoveInstance(config state.Config) (state.Config) {
}
fmt.Println("Image is ready:\t\t", imageName)
newInstanceID, err := launchInstance(svc, realInstance, imageName)
newInstanceID, err := launchInstance(svc, realInstance, imageName, region)
if err != nil {
fmt.Println("Error launching instance:\t", err)
return config

View File

@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"os"
"strings"
"time"
@ -141,14 +142,18 @@ func waitForImageReady(svc *ec2.Client, imageID string, timeout time.Duration) e
}
}
// launchInstance launches a instance based on an oldInstance and AMI (duplicating the instance)
func launchInstance(svc *ec2.Client, oldInstance *types.Instance, imageID string) (string, error) {
// launchInstance launches a instance IN RANDOM AVAILABILITY ZONE within the same region, based on an oldInstance and AMI (duplicating the instance)
func launchInstance(svc *ec2.Client, oldInstance *types.Instance, imageID string, region string) (string, error) {
securityGroupIds := make([]string, len(oldInstance.SecurityGroups))
for i, sg := range oldInstance.SecurityGroups {
securityGroupIds[i] = aws.ToString(sg.GroupId)
}
// TODO: select random zone that is not the current one.
availabilityZone := "us-east-1d"
availabilityZone, err := getRandomDifferentAvailabilityZone(svc, oldInstance, region)
if err != nil {
return "", err
}
input := &ec2.RunInstancesInput{
ImageId: aws.String(imageID),
InstanceType: oldInstance.InstanceType,
@ -171,6 +176,49 @@ func launchInstance(svc *ec2.Client, oldInstance *types.Instance, imageID string
return aws.ToString(output.Instances[0].InstanceId), nil
}
// getRandomDifferentAvailabilityZone fetches all AZ from the same region as the instance and returns a random AZ that is not equal to the one used by the instance
func getRandomDifferentAvailabilityZone(svc *ec2.Client, instance *types.Instance, region string) (string, error) {
// Seed the random generator
rand.Seed(time.Now().UnixNano())
// Get the current availability zone of the instance
currentAZ := aws.ToString(instance.Placement.AvailabilityZone)
// Describe availability zones in the region
input := &ec2.DescribeAvailabilityZonesInput{
Filters: []types.Filter{
{
Name: aws.String("region-name"),
Values: []string{region},
},
},
}
output, err := svc.DescribeAvailabilityZones(context.TODO(), input)
if err != nil {
return "", err
}
// Filter out the current availability zone
availableAZs := []string{}
for _, az := range output.AvailabilityZones {
if aws.ToString(az.ZoneName) != currentAZ {
availableAZs = append(availableAZs, aws.ToString(az.ZoneName))
}
}
// If no other availability zones are available, return an error
if len(availableAZs) == 0 {
return "", errors.New("no other availability zones available")
}
// Select a random availability zone from the remaining ones
randomIndex := rand.Intn(len(availableAZs))
randomAZ := availableAZs[randomIndex]
return randomAZ, nil
}
// terminateInstance kills an instance by id
func terminateInstance(svc *ec2.Client, instanceID string) error {
input := &ec2.TerminateInstancesInput{