Skip to content

Commit 4f7db24

Browse files
Refactor Lambda Script
1 parent 8b550f6 commit 4f7db24

File tree

1 file changed

+167
-28
lines changed

1 file changed

+167
-28
lines changed

aws-custom-cluster/template.yaml

Lines changed: 167 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ Resources:
350350
ImageId: ami-05603669082b6ebf0
351351
SecurityGroupIds:
352352
- !GetAtt "InstanceSecurityGroup.GroupId"
353+
IamInstanceProfile:
354+
Arn: !GetAtt InstanceProfile.Arn
353355
BlockDeviceMappings:
354356
- DeviceName: /dev/sda1
355357
Ebs:
@@ -360,7 +362,7 @@ Resources:
360362
Fn::Base64: !Sub |
361363
#!/bin/bash
362364
sudo apt-get update -y
363-
sudo apt-get install stunnel python3-pip -y
365+
sudo apt-get install stunnel python3-pip jq -y
364366
sudo tee /etc/stunnel/stunnel.conf > /dev/null <<EOF
365367
fips = no
366368
setuid = root
@@ -377,7 +379,11 @@ Resources:
377379
sudo systemctl enable stunnel4
378380
sudo stunnel /etc/stunnel/stunnel.conf
379381
touch /usr/local/antmedia/conf/initialized
380-
bash /usr/local/antmedia/change_server_mode.sh standalone redis://localhost:6379
382+
SECRET_KEY=$(openssl rand -base64 32 | head -c 32)
383+
sudo sed -i "/^server.jwtServerControlEnabled=/s|.*|server.jwtServerControlEnabled=true|" /usr/local/antmedia/conf/red5.properties
384+
sudo sed -i "/^server.jwtServerSecretKey=/s|.*|server.jwtServerSecretKey=$SECRET_KEY|" /usr/local/antmedia/conf/red5.properties
385+
wget -P /usr/local/antmedia/conf/ https://raw.githubusercontent.com/ant-media/Ant-Media-Server/749567900bc6fda5c614b329dceabbf5048485d3/src/main/server/conf/jwt_generator.sh
386+
bash /usr/local/antmedia/change_server_mode.sh cluster redis://localhost:6379
381387
mkdir -p /opt/aws/bin
382388
sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz
383389
sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup
@@ -393,6 +399,16 @@ Resources:
393399
- Key: Name
394400
Value: !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin
395401

402+
OriginCPUPolicy:
403+
Type: AWS::AutoScaling::ScalingPolicy
404+
Properties:
405+
AutoScalingGroupName: !Ref OriginGroup
406+
PolicyType: TargetTrackingScaling
407+
TargetTrackingConfiguration:
408+
PredefinedMetricSpecification:
409+
PredefinedMetricType: ASGAverageCPUUtilization
410+
TargetValue: 50
411+
396412
InstanceSecurityGroup:
397413
Type: 'AWS::EC2::SecurityGroup'
398414
Properties:
@@ -813,48 +829,135 @@ Resources:
813829
Properties:
814830
Code:
815831
ZipFile: |
816-
import boto3, os
832+
import boto3, os, time, json
817833
818834
def lambda_handler(event, context):
835+
819836
listener_arn = os.environ['LISTENER_ARN']
820837
origin_asg = os.environ['ORIGIN_ASG']
821838
target_group_arn = os.environ['TARGETGROUP_ARN']
839+
alarm_name = 'AutoScalingGroupScaleDownAlarm'
822840
autoscaling_client = boto3.client('autoscaling')
823841
elb_client = boto3.client('elbv2')
842+
ec2_client = boto3.client("ec2")
843+
ssm_client = boto3.client('ssm')
844+
cloudwatch_client = boto3.client('cloudwatch')
845+
846+
script = """
847+
#/usr/bin/env bash -x
848+
sed -i 's|INSTALL_DIRECTORY="$1"|INSTALL_DIRECTORY="/usr/local/antmedia"|g' /usr/local/antmedia/conf/jwt_generator.sh
849+
. /usr/local/antmedia/conf/jwt_generator.sh
850+
generate_jwt
851+
REST_URL="http://localhost:5080/rest/v2/applications-info"
852+
curl -s -L "$REST_URL" --header "ProxyAuthorization: $JWT_KEY" -o /tmp/curl_output.txt
853+
jq '[.[] | select(.liveStreamCount > 0)] | length > 0' /tmp/curl_output.txt
854+
"""
855+
824856
asg_names = autoscaling_client.describe_auto_scaling_groups()
825857
asg_origin_name = [group for group in asg_names['AutoScalingGroups'] if
826-
origin_asg in group['AutoScalingGroupName']]
858+
origin_asg in group['AutoScalingGroupName']]
827859
asg_origin_group_names = [group['AutoScalingGroupName'] for group in asg_origin_name][0]
828-
response = autoscaling_client.update_auto_scaling_group(
829-
AutoScalingGroupName=asg_origin_group_names,
830-
MinSize=0,
831-
DesiredCapacity=0
832-
)
833860
861+
print(f"Auto Scaling Group name: {asg_origin_group_names}")
862+
origin_calculate_total_instance = autoscaling_client.describe_auto_scaling_groups(AutoScalingGroupNames=[asg_origin_group_names])
863+
origin_current_capacity = len(origin_calculate_total_instance['AutoScalingGroups'][0]['Instances'])
864+
instance = origin_calculate_total_instance['AutoScalingGroups'][0]['Instances']
865+
try:
866+
instance_id = instance[0]['InstanceId']
867+
print("Current capacity and Instance ID", {"origin_current_capacity": origin_current_capacity, "instance_id": instance_id})
868+
except IndexError:
869+
cloudwatch_set_ok(alarm_name)
870+
print("No instances found in Auto Scaling Group", asg_origin_group_names)
871+
return {
872+
'statusCode': 200,
873+
'body': json.dumps({"message": "No instances found in Auto Scaling Group"})
874+
}
834875
835-
create_rule = elb_client.create_rule(
836-
Actions=[
837-
{
838-
'Type': 'forward',
839-
'TargetGroupArn': target_group_arn
840-
}
841-
],
842-
Conditions=[
843-
{
844-
'Field': 'path-pattern',
845-
'Values': ['*']
846-
}
847-
],
848-
ListenerArn=listener_arn,
849-
Priority=1
850-
)
876+
smm_response = ssm_client.send_command(
877+
DocumentName ='AWS-RunShellScript',
878+
Parameters = {'commands': [script]},
879+
InstanceIds = [instance_id]
880+
)
851881
852-
print(response)
882+
command_id = smm_response['Command']['CommandId']
853883
884+
while True:
885+
time.sleep(2)
886+
invocation_response = ssm_client.get_command_invocation(
887+
CommandId=command_id,
888+
InstanceId=instance_id,
889+
)
890+
if invocation_response['Status'] not in ['Pending', 'InProgress']:
891+
break
892+
893+
smm_output = invocation_response['StandardOutputContent'].strip()
894+
print(f"SSM command output: {smm_output}")
895+
#debug
896+
#print(invocation_response['StandardOutputContent'])
897+
#error = invocation_response['StandardErrorContent'].strip()
898+
899+
if origin_current_capacity == 1:
900+
if smm_output == 'false':
901+
print("No live streams found. Updating Auto Scaling Group.")
902+
origin_response = autoscaling_client.update_auto_scaling_group(
903+
AutoScalingGroupName=asg_origin_group_names,
904+
MinSize=0,
905+
DesiredCapacity=0
906+
)
907+
908+
create_rule = elb_client.create_rule(
909+
Actions=[
910+
{
911+
'Type': 'forward',
912+
'TargetGroupArn': target_group_arn
913+
}
914+
],
915+
Conditions=[
916+
{
917+
'Field': 'path-pattern',
918+
'Values': ['*']
919+
}
920+
],
921+
ListenerArn=listener_arn,
922+
Priority=1
923+
)
924+
cloudwatch_set_ok(alarm_name)
925+
print(origin_response)
926+
return {
927+
'statusCode': 200,
928+
'body': 'Auto Scaling Group updated successfully!'
929+
}
930+
else:
931+
print("Live streams found.")
932+
else:
933+
print(f"Current capacity is not 1, it is {origin_current_capacity}. No updates needed.")
934+
935+
cloudwatch_set_ok(alarm_name)
854936
return {
855937
'statusCode': 200,
856-
'body': 'Auto Scaling Group updated successfully!'
938+
'body': 'Auto Scaling Group does not require update.'
857939
}
940+
941+
942+
def cloudwatch_set_ok(alarm_name):
943+
try:
944+
cloudwatch_client = boto3.client('cloudwatch')
945+
cloudwatch_response = cloudwatch_client.set_alarm_state(
946+
AlarmName=alarm_name,
947+
StateValue='OK',
948+
StateReason='Updating alarm state to OK'
949+
)
950+
print("Alarm state updated to OK", cloudwatch_response)
951+
return cloudwatch_response
952+
except Exception as e:
953+
error_message = {
954+
"error": str(e),
955+
"function": "cloudwatch_set_ok",
956+
"alarm_name": alarm_name
957+
}
958+
print(json.dumps(error_message))
959+
raise e
960+
858961
#FunctionName: InstanceDeleteFunction
859962
Handler: "index.lambda_handler"
860963
Role: !GetAtt LambdaIamRole.Arn
@@ -928,7 +1031,7 @@ Resources:
9281031
Service: "lambda.amazonaws.com"
9291032
Action: "sts:AssumeRole"
9301033
Policies:
931-
- PolicyName: "EC2FullAccessPolicy1"
1034+
- PolicyName: "AccessPolicy"
9321035
PolicyDocument:
9331036
Version: "2012-10-17"
9341037
Statement:
@@ -948,6 +1051,9 @@ Resources:
9481051
- "elasticloadbalancing:CreateRule"
9491052
- "apigateway:GET"
9501053
- "acm:DescribeCertificate"
1054+
- "ssm:GetCommandInvocation"
1055+
- "ssm:SendCommand"
1056+
- "cloudwatch:SetAlarmState"
9511057
Resource: "*"
9521058
- PolicyName: "CloudWatchLogsPolicy"
9531059
PolicyDocument:
@@ -977,6 +1083,39 @@ Resources:
9771083
Action: lambda:InvokeFunction
9781084
Principal: elasticloadbalancing.amazonaws.com
9791085

1086+
InstanceProfile:
1087+
Type: 'AWS::IAM::InstanceProfile'
1088+
Properties:
1089+
Roles:
1090+
- !Ref EC2Role
1091+
1092+
EC2Role:
1093+
Type: 'AWS::IAM::Role'
1094+
Properties:
1095+
AssumeRolePolicyDocument:
1096+
Version: '2012-10-17'
1097+
Statement:
1098+
- Effect: Allow
1099+
Principal:
1100+
Service: [ec2.amazonaws.com]
1101+
Action: ['sts:AssumeRole']
1102+
Policies:
1103+
- PolicyName: AllowSSM
1104+
PolicyDocument:
1105+
Version: '2012-10-17'
1106+
Statement:
1107+
- Effect: Allow
1108+
Action:
1109+
- "ssm:*"
1110+
- "cloudwatch:PutMetricData"
1111+
- "ds:CreateComputer"
1112+
- "ds:DescribeDirectories"
1113+
- "ec2:DescribeInstanceStatus"
1114+
- "logs:*"
1115+
- "ssm:*"
1116+
- "ec2messages:*"
1117+
Resource: '*'
1118+
9801119
# Cloudwatch rule to set 0 in Autoscale
9811120
AutoScalingGroupScaleDownAlarm:
9821121
Type: 'AWS::CloudWatch::Alarm'

0 commit comments

Comments
 (0)