in cloudwatch-lambda/src/main/java/com/amazonwebservices/blogs/containers/CloudWatchAlarmHandler.java [115:200]
private void processCloudWatchAlarmMessage (JsonObject alarmMessageObject) {
logger.info(alarmMessageObject);
String alarmName = alarmMessageObject.getString("AlarmName");
String accountID = alarmMessageObject.getString("AWSAccountId");
String alarmTriggerReason = alarmMessageObject.getString("NewStateReason");
String alarmArn = String.format("arn:aws:cloudwatch:%s:%s:alarm:%s", AWS_REGION, accountID, alarmName);
ComparisonOperator operator = Enum.valueOf(ComparisonOperator.class, alarmMessageObject.getJsonObject("Trigger").getString("ComparisonOperator"));
logger.info(String.format("Alarm ARN = %s", alarmArn));
logger.info(String.format("Reason for Trigger = %s", alarmTriggerReason));
//
// Get the name/namespace of the K8sMetricAlarm custom resource from the tags associated with the CloudWatch alarm
//
ListTagsForResourceRequest request = new ListTagsForResourceRequest().withResourceARN(alarmArn);
ListTagsForResourceResult response = cloudWatchClient.listTagsForResource(request);
List<Tag> tags = response.getTags();
String resourceName = null;
String resoueceNamespace = null;
for (Tag t : tags) {
switch (t.getKey()) {
case K8S_NAME:
resourceName = t.getValue();
break;
case K8S_NAMESPACE:
resoueceNamespace = t.getValue();
break;
default:
break;
}
}
if (resourceName == null || resoueceNamespace == null) {
logger.error(String.format("Unable to identify the Kubernetes name and namespace of the K8sMetricAlarm custom resource for alarm '%s'", alarmName));
return;
}
//
// Fetch the K8sMetricAlarm custom resource from the API server
// The custom resource contains the name of the Deployment resource to be scaled
//
logger.info(String.format("Retrieving K8sMetricAlarm custom resource '%s.%s'", resourceName, resoueceNamespace));
K8sMetricAlarmCustomObject cloudWatchAlarm = apiCloudWatchAlarm.get(resoueceNamespace, resourceName).getObject();
String alarmStateResetReason;
if (cloudWatchAlarm != null) {
K8sMetricAlarmCustomObjectSpec cloudWatchAlarmSpec = cloudWatchAlarm.getSpec();
int minReplicas = cloudWatchAlarmSpec.getMinReplicas();
int maxReplicas = cloudWatchAlarmSpec.getMaxReplicas();
ScalingBehavior scaleUpBehavior = cloudWatchAlarmSpec.getScaleUpBehavior();
ScalingBehavior scaleDownBehavior = cloudWatchAlarmSpec.getScaleDownBehavior();
String deploymentName = cloudWatchAlarmSpec.getDeployment();
//
// Fetch the Deployment resource from the API server
// Compute the number of replicas to be scaled up or down based on scaling policies
// Update the Deployment resource with the new number of replicas.
//
logger.info(String.format("Retrieving Deployment resource '%s.%s'", deploymentName, resoueceNamespace));
V1Deployment deployment = apiDeployment.get(resoueceNamespace, deploymentName).getObject();
V1ObjectMeta metadata = deployment.getMetadata();
boolean isCoolingDown = isResourceCoolingDown (metadata, operator, scaleUpBehavior, scaleDownBehavior);
if (isCoolingDown) {
alarmStateResetReason = String.format("Deployment '%s.%s' is still cooling down. Suspending further scaling", deploymentName, resoueceNamespace);
logger.info(alarmStateResetReason);
}
else {
int replicas = deployment.getSpec().getReplicas();
int scaledReplicas = computeScaling(operator, minReplicas, maxReplicas, replicas, scaleUpBehavior, scaleDownBehavior);
updateDeployment(deployment, metadata, replicas, scaledReplicas, alarmName, alarmTriggerReason);
alarmStateResetReason = String.format("Scaled Deployment '%s.%s' from %d to %d replicas", resoueceNamespace, deploymentName, replicas, scaledReplicas);
}
} else {
alarmStateResetReason = String.format("Unable to retrieve K8sMetricAlarm custom resource '%s.%s'", resoueceNamespace, resourceName);
logger.error(alarmStateResetReason);
}
//
// After the scaling activity is completed/suspended, set the alarm status to OK
//
SetAlarmStateRequest setStateRequest = new SetAlarmStateRequest()
.withAlarmName(alarmName)
.withStateReason(alarmStateResetReason)
.withStateValue(StateValue.OK);
cloudWatchClient.setAlarmState(setStateRequest);
logger.info(String.format("State of alarm '%s' set to %s", alarmName, StateValue.OK.toString()));
}