@@ -350,6 +350,8 @@ Resources:
350
350
ImageId : ami-05603669082b6ebf0
351
351
SecurityGroupIds :
352
352
- !GetAtt " InstanceSecurityGroup.GroupId"
353
+ IamInstanceProfile :
354
+ Arn : !GetAtt InstanceProfile.Arn
353
355
BlockDeviceMappings :
354
356
- DeviceName : /dev/sda1
355
357
Ebs :
@@ -360,7 +362,7 @@ Resources:
360
362
Fn::Base64 : !Sub |
361
363
# !/bin/bash
362
364
sudo apt-get update -y
363
- sudo apt-get install stunnel python3-pip -y
365
+ sudo apt-get install stunnel python3-pip jq -y
364
366
sudo tee /etc/stunnel/stunnel.conf > /dev/null <<EOF
365
367
fips = no
366
368
setuid = root
@@ -377,7 +379,11 @@ Resources:
377
379
sudo systemctl enable stunnel4
378
380
sudo stunnel /etc/stunnel/stunnel.conf
379
381
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
381
387
mkdir -p /opt/aws/bin
382
388
sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz
383
389
sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup
@@ -393,6 +399,16 @@ Resources:
393
399
- Key : Name
394
400
Value : !Sub ${AWS::StackName}-AntMedia-LaunchTemplateOrigin
395
401
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
+
396
412
InstanceSecurityGroup :
397
413
Type : ' AWS::EC2::SecurityGroup'
398
414
Properties :
@@ -813,48 +829,135 @@ Resources:
813
829
Properties :
814
830
Code :
815
831
ZipFile : |
816
- import boto3, os
832
+ import boto3, os, time, json
817
833
818
834
def lambda_handler(event, context):
835
+
819
836
listener_arn = os.environ['LISTENER_ARN']
820
837
origin_asg = os.environ['ORIGIN_ASG']
821
838
target_group_arn = os.environ['TARGETGROUP_ARN']
839
+ alarm_name = 'AutoScalingGroupScaleDownAlarm'
822
840
autoscaling_client = boto3.client('autoscaling')
823
841
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
+
824
856
asg_names = autoscaling_client.describe_auto_scaling_groups()
825
857
asg_origin_name = [group for group in asg_names['AutoScalingGroups'] if
826
- origin_asg in group['AutoScalingGroupName']]
858
+ origin_asg in group['AutoScalingGroupName']]
827
859
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
- )
833
860
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
+ }
834
875
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
+ )
851
881
852
- print(response)
882
+ command_id = smm_response['Command']['CommandId']
853
883
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)
854
936
return {
855
937
'statusCode': 200,
856
- 'body': 'Auto Scaling Group updated successfully! '
938
+ 'body': 'Auto Scaling Group does not require update. '
857
939
}
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
+
858
961
# FunctionName: InstanceDeleteFunction
859
962
Handler : " index.lambda_handler"
860
963
Role : !GetAtt LambdaIamRole.Arn
@@ -928,7 +1031,7 @@ Resources:
928
1031
Service : " lambda.amazonaws.com"
929
1032
Action : " sts:AssumeRole"
930
1033
Policies :
931
- - PolicyName : " EC2FullAccessPolicy1 "
1034
+ - PolicyName : " AccessPolicy "
932
1035
PolicyDocument :
933
1036
Version : " 2012-10-17"
934
1037
Statement :
@@ -948,6 +1051,9 @@ Resources:
948
1051
- " elasticloadbalancing:CreateRule"
949
1052
- " apigateway:GET"
950
1053
- " acm:DescribeCertificate"
1054
+ - " ssm:GetCommandInvocation"
1055
+ - " ssm:SendCommand"
1056
+ - " cloudwatch:SetAlarmState"
951
1057
Resource : " *"
952
1058
- PolicyName : " CloudWatchLogsPolicy"
953
1059
PolicyDocument :
@@ -977,6 +1083,39 @@ Resources:
977
1083
Action : lambda:InvokeFunction
978
1084
Principal : elasticloadbalancing.amazonaws.com
979
1085
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
+
980
1119
# Cloudwatch rule to set 0 in Autoscale
981
1120
AutoScalingGroupScaleDownAlarm :
982
1121
Type : ' AWS::CloudWatch::Alarm'
0 commit comments