Created
June 1, 2024 04:27
-
-
Save niski84/edc4e687d45f8dee0b3278dfb84d151c to your computer and use it in GitHub Desktop.
maint page
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math/rand" | |
"strings" | |
"time" | |
"github.com/aws/aws-sdk-go/aws" | |
"github.com/aws/aws-sdk-go/aws/session" | |
"github.com/aws/aws-sdk-go/service/elasticbeanstalk" | |
"github.com/aws/aws-sdk-go/service/route53" | |
) | |
type CreateMaintenanceInput struct { | |
Session *session.Session | |
RecordName string | |
HostedZoneID string | |
} | |
type CreateMaintenanceOutput struct { | |
NewRecordName string | |
} | |
type DeleteRecordInput struct { | |
Session *session.Session | |
RecordName string | |
HostedZoneID string | |
} | |
type UpdateRecordTargetInput struct { | |
Session *session.Session | |
RecordName string | |
HostedZoneID string | |
NewTargetValue string | |
} | |
type ResetRecordTargetInput struct { | |
Session *session.Session | |
RecordName string | |
HostedZoneID string | |
EnvironmentName string | |
} | |
func randomString(length int) string { | |
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) | |
b := make([]byte, length) | |
for i := range b { | |
b[i] = charset[seededRand.Intn(len(charset))] | |
} | |
return string(b) | |
} | |
func insertMaintenanceSuffix(recordName, suffix string) string { | |
parts := strings.SplitN(recordName, ".", 2) | |
if len(parts) < 2 { | |
return recordName + suffix | |
} | |
return parts[0] + suffix + "." + parts[1] | |
} | |
func CreateMaintenanceRecord(input CreateMaintenanceInput) (CreateMaintenanceOutput, error) { | |
suffix := fmt.Sprintf("-maintenance-%s", randomString(5)) | |
newRecordName := insertMaintenanceSuffix(input.RecordName, suffix) | |
svc := route53.New(input.Session) | |
describeInput := &route53.ListResourceRecordSetsInput{ | |
HostedZoneId: aws.String(input.HostedZoneID), | |
StartRecordName: aws.String(input.RecordName), | |
} | |
fmt.Printf("Retrieving original record set for [%v] in hosted zone [%v]\n", input.RecordName, input.HostedZoneID) | |
resp, err := svc.ListResourceRecordSets(describeInput) | |
if err != nil { | |
return CreateMaintenanceOutput{}, fmt.Errorf("CreateMaintenanceRecord: failed to list resource record sets: %v", err) | |
} | |
var originalRecord *route53.ResourceRecordSet | |
for _, recordSet := range resp.ResourceRecordSets { | |
if *recordSet.Name == input.RecordName { | |
originalRecord = recordSet | |
break | |
} | |
} | |
if originalRecord == nil { | |
return CreateMaintenanceOutput{}, fmt.Errorf("CreateMaintenanceRecord: original record not found") | |
} | |
newRecord := &route53.ChangeResourceRecordSetsInput{ | |
HostedZoneId: aws.String(input.HostedZoneID), | |
ChangeBatch: &route53.ChangeBatch{ | |
Changes: []*route53.Change{ | |
{ | |
Action: aws.String(route53.ChangeActionUpsert), | |
ResourceRecordSet: &route53.ResourceRecordSet{ | |
Name: aws.String(newRecordName), | |
Type: originalRecord.Type, | |
TTL: originalRecord.TTL, | |
ResourceRecords: originalRecord.ResourceRecords, | |
}, | |
}, | |
}, | |
}, | |
} | |
fmt.Printf("Creating maintenance record set with name [%v] in hosted zone [%v]\n", newRecordName, input.HostedZoneID) | |
_, err = svc.ChangeResourceRecordSets(newRecord) | |
if err != nil { | |
return CreateMaintenanceOutput{}, fmt.Errorf("CreateMaintenanceRecord: failed to create maintenance record: %v", err) | |
} | |
return CreateMaintenanceOutput{NewRecordName: newRecordName}, nil | |
} | |
func DeleteRecord(input DeleteRecordInput) error { | |
svc := route53.New(input.Session) | |
deleteInput := &route53.ChangeResourceRecordSetsInput{ | |
HostedZoneId: aws.String(input.HostedZoneID), | |
ChangeBatch: &route53.ChangeBatch{ | |
Changes: []*route53.Change{ | |
{ | |
Action: aws.String(route53.ChangeActionDelete), | |
ResourceRecordSet: &route53.ResourceRecordSet{ | |
Name: aws.String(input.RecordName), | |
}, | |
}, | |
}, | |
}, | |
} | |
fmt.Printf("Deleting record set with name [%v] in hosted zone [%v]\n", input.RecordName, input.HostedZoneID) | |
_, err := svc.ChangeResourceRecordSets(deleteInput) | |
if err != nil { | |
return fmt.Errorf("DeleteRecord: failed to delete record: %v", err) | |
} | |
return nil | |
} | |
func UpdateRecordTarget(input UpdateRecordTargetInput) error { | |
svc := route53.New(input.Session) | |
describeInput := &route53.ListResourceRecordSetsInput{ | |
HostedZoneId: aws.String(input.HostedZoneID), | |
StartRecordName: aws.String(input.RecordName), | |
} | |
fmt.Printf("Retrieving record set for [%v] in hosted zone [%v]\n", input.RecordName, input.HostedZoneID) | |
resp, err := svc.ListResourceRecordSets(describeInput) | |
if err != nil { | |
return fmt.Errorf("UpdateRecordTarget: failed to list resource record sets: %v", err) | |
} | |
var originalRecord *route53.ResourceRecordSet | |
for _, recordSet := range resp.ResourceRecordSets { | |
if *recordSet.Name == input.RecordName { | |
originalRecord = recordSet | |
break | |
} | |
} | |
if originalRecord == nil { | |
return fmt.Errorf("UpdateRecordTarget: original record not found") | |
} | |
originalRecord.ResourceRecords = []*route53.ResourceRecord{ | |
{ | |
Value: aws.String(input.NewTargetValue), | |
}, | |
} | |
updateInput := &route53.ChangeResourceRecordSetsInput{ | |
HostedZoneId: aws.String(input.HostedZoneID), | |
ChangeBatch: &route53.ChangeBatch{ | |
Changes: []*route53.Change{ | |
{ | |
Action: aws.String(route53.ChangeActionUpsert), | |
ResourceRecordSet: originalRecord, | |
}, | |
}, | |
}, | |
} | |
fmt.Printf("Updating record set with name [%v] in hosted zone [%v] to new target [%v]\n", input.RecordName, input.HostedZoneID, input.NewTargetValue) | |
_, err = svc.ChangeResourceRecordSets(updateInput) | |
if err != nil { | |
return fmt.Errorf("UpdateRecordTarget: failed to update record target: %v", err) | |
} | |
return nil | |
} | |
func ResetRecordTarget(input ResetRecordTargetInput) error { | |
albArn, err := GetApplicationLoadBalancerARN(input.Session, input.EnvironmentName) | |
if err != nil { | |
return fmt.Errorf("ResetRecordTarget: failed to get ALB ARN: %v", err) | |
} | |
updateInput := UpdateRecordTargetInput{ | |
Session: input.Session, | |
RecordName: input.RecordName, | |
HostedZoneID: input.HostedZoneID, | |
NewTargetValue: albArn, | |
} | |
err = UpdateRecordTarget(updateInput) | |
if err != nil { | |
return fmt.Errorf("ResetRecordTarget: %v", err) | |
} | |
return nil | |
} | |
func GetApplicationLoadBalancerARN(sess *session.Session, environmentName string) (string, error) { | |
svc := elasticbeanstalk.New(sess) | |
describeEnvironmentsInput := &elasticbeanstalk.DescribeEnvironmentsInput{ | |
EnvironmentNames: []*string{aws.String(environmentName)}, | |
} | |
fmt.Printf("Retrieving environment details for [%v]\n", environmentName) | |
envResp, err := svc.DescribeEnvironments(describeEnvironmentsInput) | |
if err != nil { | |
return "", fmt.Errorf("GetApplicationLoadBalancerARN: failed to describe environments: %v", err) | |
} | |
if len(envResp.Environments) == 0 { | |
return "", fmt.Errorf("GetApplicationLoadBalancerARN: environment not found") | |
} | |
envID := envResp.Environments[0].EnvironmentId | |
describeResourcesInput := &elasticbeanstalk.DescribeEnvironmentResourcesInput{ | |
EnvironmentId: envID, | |
} | |
fmt.Printf("Retrieving environment resources for [%v]\n", environmentName) | |
resResp, err := svc.DescribeEnvironmentResources(describeResourcesInput) | |
if err != nil { | |
return "", fmt.Errorf("GetApplicationLoadBalancerARN: failed to describe environment resources: %v", err) | |
} | |
if resResp.EnvironmentResources == nil || len(resResp.EnvironmentResources.LoadBalancers) == 0 { | |
return "", fmt.Errorf("GetApplicationLoadBalancerARN: load balancer not found") | |
} | |
return *resResp.EnvironmentResources.LoadBalancers[0].Name, nil | |
} | |
// Test cases to call the functions | |
func TestCreateMaintenanceRecord() { | |
sess, err := session.NewSession(&aws.Config{ | |
Region: aws.String("us-west-2"), | |
}) | |
if err != nil { | |
fmt.Printf("Test failed to create AWS session: %v\n", err) | |
return | |
} | |
input := CreateMaintenanceInput{ | |
Session: sess, | |
RecordName: "example.mydomain.com", | |
HostedZoneID: "Z3P5QSUBK4POTI", | |
} | |
_, err = CreateMaintenanceRecord(input) | |
if err != nil { | |
fmt.Printf("Test failed with error: %v\n", err) | |
} else { | |
fmt.Println("Test passed without errors") | |
} | |
} | |
func TestDeleteRecord() { | |
sess, err := session.NewSession(&aws.Config{ | |
Region: aws.String("us-west-2"), | |
}) | |
if err != nil { | |
fmt.Printf("Test failed to create AWS session: %v\n", err) | |
return | |
} | |
input := DeleteRecordInput{ | |
Session: sess, | |
RecordName: "example-maintenance-abcde.mydomain.com", | |
HostedZoneID: "Z3P5QSUBK4POTI", | |
} | |
err = DeleteRecord(input) | |
if err != nil { | |
fmt.Printf("Test failed with error: %v\n", err) | |
} else { | |
fmt.Println("Test passed without errors") | |
} | |
} | |
func TestUpdateRecordTarget() { | |
sess, err := session.NewSession(&aws.Config{ | |
Region: aws.String("us-west-2"), | |
}) | |
if err != nil { | |
fmt.Printf("Test failed to create AWS session: %v\n", err) | |
return | |
} | |
input := UpdateRecordTargetInput{ | |
Session: sess, | |
RecordName: "example.mydomain.com", | |
HostedZoneID: "Z3P5QSUBK4POTI", | |
NewTargetValue: "new-target-value", | |
} | |
err = UpdateRecordTarget(input) | |
if err != nil { | |
fmt.Printf("Test failed with error: %v\n", err) | |
} else { | |
fmt.Println("Test passed without errors") | |
} | |
} | |
func TestResetRecordTarget() { | |
sess, err := session.NewSession(&aws.Config{ | |
Region: aws.String("us-west-2"), | |
}) | |
if err != nil { | |
fmt.Printf("Test failed to create AWS session: %v\n", err) | |
return | |
} | |
input := ResetRecordTargetInput{ | |
Session: sess, | |
RecordName: "example.mydomain.com", | |
HostedZoneID: "Z3P5QSUBK4POTI", | |
EnvironmentName: "my-environment", | |
} | |
err = ResetRecordTarget(input) | |
if err != nil { | |
fmt.Printf("Test failed with error: %v\n", err) | |
} else { | |
fmt.Println("Test passed without errors") | |
} | |
} | |
func main() { | |
TestCreateMaintenanceRecord() | |
TestDeleteRecord() | |
TestUpdateRecordTarget() | |
TestResetRecordTarget() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment