Skip to content

Instantly share code, notes, and snippets.

@niski84
Created June 1, 2024 04:27
Show Gist options
  • Save niski84/edc4e687d45f8dee0b3278dfb84d151c to your computer and use it in GitHub Desktop.
Save niski84/edc4e687d45f8dee0b3278dfb84d151c to your computer and use it in GitHub Desktop.
maint page
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