This post is part of a bigger topic Autoscaling Publishers in AWS.
In a previous post, I mentioned the LifeCycle Termination Hooks for our Auto Scaling Policy. In this post, we see more details about this hook and how it is actually used to gracefully shutdown service on the instance that is about to be terminated.
As per earlier post, we defined one termination hook in the Auto Scaling Policy, named 'sdl_terminate_publisher':
Next, we use this a CloudWatch event to execute a Lambda Function that performs the graceful shutdown of the Publisher service on the instance, and then releases the termination hook, so the instance can be terminated properly.
In CloudWatch, create a new Rule as per below:
Lastly, we need the Lambda function that performs the actual graceful stopping of the Publisher service. This function uses the 'boto3' client to send a message to the instance to execute a cleanup script that was placed there in advance. The script stops the Publisher service, releases the license and removes the server from the AD domain.
The Lambda function does wait until the script execution finishes and only then releases the lifecycle termination hook, which then leads to the termination of the instance.
Below are the highlights of the 'cleanup.ps1' script invoked above:
In a previous post, I mentioned the LifeCycle Termination Hooks for our Auto Scaling Policy. In this post, we see more details about this hook and how it is actually used to gracefully shutdown service on the instance that is about to be terminated.
As per earlier post, we defined one termination hook in the Auto Scaling Policy, named 'sdl_terminate_publisher':
Next, we use this a CloudWatch event to execute a Lambda Function that performs the graceful shutdown of the Publisher service on the instance, and then releases the termination hook, so the instance can be terminated properly.
In CloudWatch, create a new Rule as per below:
- Event Source: Event Pattern
- Based on service: Auto Scaling
- Event Type: Instance Launch and Terminate
- Specific event: EC2 Instance-terminate Lifecycle Action
- Specific group: sdl_publisher-asg
Target a Lambda function to be executed when this event triggers:
- SDL_CleanUpPublisher
Lastly, we need the Lambda function that performs the actual graceful stopping of the Publisher service. This function uses the 'boto3' client to send a message to the instance to execute a cleanup script that was placed there in advance. The script stops the Publisher service, releases the license and removes the server from the AD domain.
The Lambda function does wait until the script execution finishes and only then releases the lifecycle termination hook, which then leads to the termination of the instance.
import boto3 import logging import time def lambda_handler(event, context): message = event['detail'] instanceId = str(message['EC2InstanceId']) ssmClient = boto3.client('ssm') ssmCommand = ssmClient.send_command( InstanceIds = [ instanceId ], DocumentName = 'AWS-RunPowerShellScript', TimeoutSeconds = 270, Parameters = { 'commands': ['D:\\scripts\\cleanup.ps1'] }, OutputS3BucketName = 'sdl-log', OutputS3KeyPrefix = 'CleanUpPublisher' ) status = ssmCommand['Command']['Status'] while status == 'Pending' or status == 'InProgress': time.sleep(3) status = (ssmClient.list_commands(CommandId=ssmCommand['Command']['CommandId']))['Commands'][0]['Status'] actionResult = "CONTINUE" if (status != 'Success'): actionResult = "ABANDON" asgClient = boto3.client('autoscaling') lifeCycleHook = message['LifecycleHookName'] autoScalingGroup = message['AutoScalingGroupName'] response = asgClient.complete_lifecycle_action( LifecycleHookName = lifeCycleHook, AutoScalingGroupName = autoScalingGroup, LifecycleActionResult = actionResult, InstanceId = instanceId ) return None
Below are the highlights of the 'cleanup.ps1' script invoked above:
Stop-Service TcmPublisher Stop-Service TCDTransportService $hostname = HostName $database = "sdl_licenses" $connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;" $connection = New-Object System.Data.SqlClient.SqlConnection $connection.ConnectionString = $connectionString $connection.Open() $query = "UPDATE licenses SET licenses.available = 'True' WHERE licenses.hostname = '$hostname'" $command = $connection.CreateCommand() $command.CommandText = $query $adapter = New-Object System.Data.SqlClient.SqlDataAdapter $command $dataset = New-Object System.Data.DataSet $adapter.Fill($dataset) | out-null $connection.Close() echo "Unlocked" $credential = New-Object System.Management.Automation.PSCredential($username,$password) Remove-Computer -UnjoinDomainCredential $credential -ComputerName $hostname -Force -PassThru -Verbose echo "Removed"
Comments