mirror of https://github.com/OpenVidu/openvidu.git
1159 lines
43 KiB
Plaintext
1159 lines
43 KiB
Plaintext
---
|
|
AWSTemplateFormatVersion: 2010-09-09
|
|
Description: OpenVidu Pro CloudFormation template
|
|
|
|
Parameters:
|
|
|
|
# Domain and SSL certificate configuration
|
|
|
|
WhichCert:
|
|
Description: >
|
|
[selfsigned] Self signed certificate. Not recommended for production use.
|
|
[owncert] Valid certificate purchased in a Internet services company.
|
|
[letsencrypt] Generate a new certificate using Let's Encrypt.
|
|
Type: String
|
|
AllowedValues:
|
|
- selfsigned
|
|
- owncert
|
|
- letsencrypt
|
|
Default: selfsigned
|
|
|
|
PublicElasticIP:
|
|
Description: "Previously created AWS Elastic IP to associate it to the OpenVidu EC2 instance. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example 13.33.145.23."
|
|
Type: String
|
|
AllowedPattern: ^$|^([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])$
|
|
ConstraintDescription: The public Elastic IP does not have a valid IPv4 format
|
|
|
|
MyDomainName:
|
|
Description: "Valid domain name pointing to previous IP. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example: openvidu.company.com"
|
|
Type: String
|
|
AllowedPattern: ^$|^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
|
|
ConstraintDescription: The domain name does not have a valid domain name format
|
|
|
|
OwnCertCRT:
|
|
Description: "If certificate type is 'owncert' this is the URL where CRT file will be downloaded"
|
|
Type: String
|
|
|
|
OwnCertKEY:
|
|
Description: "If certificate type is 'owncert' this is the URL where KEY file will be downloaded"
|
|
Type: String
|
|
|
|
LetsEncryptEmail:
|
|
Description: "If certificate type is 'letsencrypt', this email will be used for Let's Encrypt notifications"
|
|
Type: String
|
|
|
|
Recording:
|
|
Description: |
|
|
If 'disabled', recordings will not be active.
|
|
If 'local' recordings will be saved in EC2 instance locally.
|
|
If 's3', recordings will be stored in a S3 bucket"
|
|
Type: String
|
|
AllowedValues:
|
|
- disabled
|
|
- local
|
|
- s3
|
|
Default: local
|
|
|
|
S3RecordingsBucketName:
|
|
Description: "S3 Bucket Name"
|
|
Type: String
|
|
|
|
# OpenVidu Configuration
|
|
OpenViduLicense:
|
|
Description: "Visit https://openvidu.io/account"
|
|
Type: String
|
|
AllowedPattern: ^(?!\s*$).+$
|
|
NoEcho: true
|
|
ConstraintDescription: OpenVidu Pro License is mandatory
|
|
|
|
OpenViduEdition:
|
|
Description: "Visit https://docs.openvidu.io/en/stable/deployment/#openvidu-editions"
|
|
Type: String
|
|
AllowedValues:
|
|
- pro
|
|
- enterprise
|
|
Default: pro
|
|
|
|
OpenViduSecret:
|
|
Description: "Secret to connect to this OpenVidu Platform. Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')"
|
|
Type: String
|
|
AllowedPattern: ^[a-zA-Z0-9_-]+$
|
|
NoEcho: true
|
|
ConstraintDescription: "Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')"
|
|
|
|
MediaNodesStartNumber:
|
|
Description: "How many Media Nodes do you want on startup (EC2 instances will be launched)"
|
|
Type: Number
|
|
Default: 1
|
|
|
|
# Enable Elasticsearch and Kibana
|
|
ElasticsearchEnabled:
|
|
Description: "Choose if you want OpenVidu to use Elasticsearch."
|
|
Type: String
|
|
AllowedValues:
|
|
- true
|
|
- false
|
|
Default: true
|
|
|
|
# Elasticsearch configuration
|
|
ElasticsearchUser:
|
|
Description: "Username for Elasticsearch and Kibana. ('ElasticSearch Enabled' must be true)"
|
|
Type: String
|
|
AllowedPattern: ^$|^[^" ]+$
|
|
ConstraintDescription: Elasticsearch user is mandatory (no whitespaces or quotations allowed)
|
|
Default: elasticadmin
|
|
|
|
ElasticsearchPassword:
|
|
Description: "Password for Elasticsearch and Kibana ('ElasticSearch Enabled' must be true)"
|
|
Type: String
|
|
AllowedPattern: ^$|^[^" ]+$
|
|
NoEcho: true
|
|
ConstraintDescription: Elasticsearch password is mandatory and it should have at least 6 characters (no whitespaces or quotations allowed)
|
|
|
|
# Elasticsearch configuration
|
|
ElasticsearchUrl:
|
|
Description: "If you have an external Elasticsearch service running, put here the url to the service. If empty, an Elasticsearch service will be deployed next to OpenVidu. ('ElasticSearch Enabled' must be true)"
|
|
Type: String
|
|
AllowedPattern: (^(https?:\/\/)?([^:\/]+)(:([0-9]+))?(\/.*)?$|^$)
|
|
ConstraintDescription: "It is very important to specify the Elasticsearch URL with the port used by this service. For example: https://es-example"
|
|
|
|
KibanaUrl:
|
|
Description: "If you have an external Kibana service running, put here the url to the service. If empty, a Kibana service will be deployed next to OpenVidu. ('ElasticSearch Enabled' must be true)"
|
|
Type: String
|
|
AllowedPattern: (^(https?:\/\/)?([^:\/]+)(:([0-9]+))?(\/.*)?$|^$)
|
|
ConstraintDescription: "It is very important to specify the url with port used by this service. For example: https://kibana-example"
|
|
|
|
# EC2 Instance configuration
|
|
|
|
AwsInstanceTypeOV:
|
|
Description: "Specifies the EC2 instance type for your OpenVidu Server Pro Node"
|
|
Type: String
|
|
Default: c5.xlarge
|
|
AllowedValues:
|
|
- t2.large
|
|
- t2.xlarge
|
|
- t2.2xlarge
|
|
- t3.large
|
|
- t3.xlarge
|
|
- t3.2xlarge
|
|
- m4.large
|
|
- m4.xlarge
|
|
- m4.2xlarge
|
|
- m4.4xlarge
|
|
- m4.10xlarge
|
|
- m4.16xlarge
|
|
- m5.large
|
|
- m5.xlarge
|
|
- m5.2xlarge
|
|
- m5.4xlarge
|
|
- m5.8xlarge
|
|
- m5.12xlarge
|
|
- m5.16xlarge
|
|
- m5.24xlarge
|
|
- c4.large
|
|
- c4.xlarge
|
|
- c4.2xlarge
|
|
- c4.4xlarge
|
|
- c4.8xlarge
|
|
- c5.large
|
|
- c5.xlarge
|
|
- c5.2xlarge
|
|
- c5.4xlarge
|
|
- c5.9xlarge
|
|
- c5.12xlarge
|
|
- c5.18xlarge
|
|
- c5.24xlarge
|
|
- c6a.large
|
|
- c6a.xlarge
|
|
- c6a.2xlarge
|
|
- c6a.4xlarge
|
|
- c6a.8xlarge
|
|
- c6a.12xlarge
|
|
- c6a.16xlarge
|
|
- c6a.24xlarge
|
|
- c6a.32xlarge
|
|
- c6a.48xlarge
|
|
- c6a.metal
|
|
ConstraintDescription: "Must be a valid EC2 instance type"
|
|
|
|
AwsInstanceTypeKMS:
|
|
Description: "Specifies the EC2 instance type for your Media Nodes"
|
|
Type: String
|
|
Default: c5.xlarge
|
|
AllowedValues:
|
|
- t2.large
|
|
- t2.xlarge
|
|
- t2.2xlarge
|
|
- t3.large
|
|
- t3.xlarge
|
|
- t3.2xlarge
|
|
- m4.large
|
|
- m4.xlarge
|
|
- m4.2xlarge
|
|
- m4.4xlarge
|
|
- m4.10xlarge
|
|
- m4.16xlarge
|
|
- m5.large
|
|
- m5.xlarge
|
|
- m5.2xlarge
|
|
- m5.4xlarge
|
|
- m5.8xlarge
|
|
- m5.12xlarge
|
|
- m5.16xlarge
|
|
- m5.24xlarge
|
|
- c4.large
|
|
- c4.xlarge
|
|
- c4.2xlarge
|
|
- c4.4xlarge
|
|
- c4.8xlarge
|
|
- c5.large
|
|
- c5.xlarge
|
|
- c5.2xlarge
|
|
- c5.4xlarge
|
|
- c5.9xlarge
|
|
- c5.12xlarge
|
|
- c5.18xlarge
|
|
- c5.24xlarge
|
|
- c6a.large
|
|
- c6a.xlarge
|
|
- c6a.2xlarge
|
|
- c6a.4xlarge
|
|
- c6a.8xlarge
|
|
- c6a.12xlarge
|
|
- c6a.16xlarge
|
|
- c6a.24xlarge
|
|
- c6a.32xlarge
|
|
- c6a.48xlarge
|
|
- c6a.metal
|
|
ConstraintDescription: "Must be a valid EC2 instance type"
|
|
|
|
KeyName:
|
|
Description: "Name of an existing EC2 KeyPair to enable SSH access to the instance. It is mandatory to perform some administrative tasks of OpenVidu."
|
|
Type: 'AWS::EC2::KeyPair::KeyName'
|
|
ConstraintDescription: "must be the name of an existing EC2 KeyPair"
|
|
|
|
# Networking configuration
|
|
OpenViduVPC:
|
|
Description: "Dedicated VPC for OpenVidu cluster"
|
|
Type: AWS::EC2::VPC::Id
|
|
AllowedPattern: ^.+$
|
|
ConstraintDescription: You must specify a VPC ID
|
|
|
|
OpenViduSubnet:
|
|
Description: "Subnet for OpenVidu cluster"
|
|
Type: AWS::EC2::Subnet::Id
|
|
AllowedPattern: ^.+$
|
|
ConstraintDescription: You must specify a subnet ID
|
|
|
|
# Other configuration
|
|
|
|
WantToDeployDemos:
|
|
Description: "Choose if you want to deploy OpenVidu Call application alongside OpenVidu platform."
|
|
Type: String
|
|
AllowedValues:
|
|
- true
|
|
- false
|
|
Default: true
|
|
|
|
CoturnInMediaNodes:
|
|
Description: "If true, Coturn will be deployed on media nodes. Otherwise it will be deployed in master nodes."
|
|
Type: String
|
|
AllowedValues:
|
|
- true
|
|
- false
|
|
Default: false
|
|
|
|
#start_mappings
|
|
Mappings:
|
|
OVAMIMAP:
|
|
eu-west-1:
|
|
AMI: OV_AMI_ID
|
|
|
|
KMSAMIMAP:
|
|
eu-west-1:
|
|
AMI: KMS_AMI_ID
|
|
#end_mappings
|
|
|
|
Metadata:
|
|
'AWS::CloudFormation::Interface':
|
|
ParameterGroups:
|
|
- Label:
|
|
default: Domain and SSL certificate configuration
|
|
Parameters:
|
|
- WhichCert
|
|
- PublicElasticIP
|
|
- MyDomainName
|
|
- OwnCertCRT
|
|
- OwnCertKEY
|
|
- LetsEncryptEmail
|
|
- Label:
|
|
default: OpenVidu configuration
|
|
Parameters:
|
|
- OpenViduLicense
|
|
- OpenViduEdition
|
|
- OpenViduSecret
|
|
- MediaNodesStartNumber
|
|
- Label:
|
|
default: OpenVidu Recording Configuration
|
|
Parameters:
|
|
- Recording
|
|
- S3RecordingsBucketName
|
|
- Label:
|
|
default: Elasticsearch and Kibana configuration
|
|
Parameters:
|
|
- ElasticsearchEnabled
|
|
- ElasticsearchUrl
|
|
- KibanaUrl
|
|
- ElasticsearchUser
|
|
- ElasticsearchPassword
|
|
- Label:
|
|
default: EC2 Instance configuration
|
|
Parameters:
|
|
- AwsInstanceTypeOV
|
|
- AwsInstanceTypeKMS
|
|
- KeyName
|
|
- Label:
|
|
default: Networking configuration
|
|
Parameters:
|
|
- OpenViduVPC
|
|
- OpenViduSubnet
|
|
- Label:
|
|
default: Other configuration
|
|
Parameters:
|
|
- WantToDeployDemos
|
|
- CoturnInMediaNodes
|
|
|
|
ParameterLabels:
|
|
# SSL certificate configuration
|
|
WhichCert:
|
|
default: "Certificate Type"
|
|
PublicElasticIP:
|
|
default: "AWS Elastic IP (EIP)"
|
|
MyDomainName:
|
|
default: "Domain Name pointing to Elastic IP"
|
|
OwnCertCRT:
|
|
default: "URL to the CRT file (owncert)"
|
|
OwnCertKEY:
|
|
default: "URL to the key file (owncert)"
|
|
LetsEncryptEmail:
|
|
default: "Email for Let's Encrypt (letsencrypt)"
|
|
Recording:
|
|
default: "OpenVidu Recording"
|
|
S3RecordingsBucketName:
|
|
default: "S3 Bucket where recordings will be stored"
|
|
# OpenVidu configuration
|
|
OpenViduLicense:
|
|
default: "OpenVidu Pro License key"
|
|
OpenViduEdition:
|
|
default: "Which OpenVidu Edition you want to deploy"
|
|
MediaNodesStartNumber:
|
|
default: "Initial number of Media Node in your cluster"
|
|
OpenViduSecret:
|
|
default: "Openvidu Secret"
|
|
# Kibana configuration
|
|
ElasticsearchEnabled:
|
|
default: "Enable Elasticsearch and Kibana"
|
|
ElasticsearchUrl:
|
|
default: "Elasticsearch URL"
|
|
KibanaUrl:
|
|
default: "Kibana URL"
|
|
ElasticsearchUser:
|
|
default: "Elasticsearch and Kibana username"
|
|
ElasticsearchPassword:
|
|
default: "Elasticsearch and Kibana password"
|
|
# EC2 instance configuration
|
|
AwsInstanceTypeOV:
|
|
default: "Instance type for Openvidu Server Pro Node"
|
|
AwsInstanceTypeKMS:
|
|
default: "Instance type for Media Nodes"
|
|
KeyName:
|
|
default: "SSH Key"
|
|
# Networking configuration
|
|
OpenViduVPC:
|
|
default: "OpenVidu VPC"
|
|
OpenViduSubnet:
|
|
default: "OpenVidu Subnet"
|
|
# Other configuration
|
|
WantToDeployDemos:
|
|
default: "Deploy OpenVidu Call application"
|
|
CoturnInMediaNodes:
|
|
default: "Deploy Coturn in Media Nodes. (Experimental)"
|
|
|
|
Conditions:
|
|
WhichCertPresent: !Not [ !Equals [!Ref WhichCert, ''] ]
|
|
PublicElasticIPPresent: !Not [ !Equals [!Ref PublicElasticIP, ''] ]
|
|
RecordingStorageIsS3: !Equals [ !Ref Recording, 's3' ]
|
|
CreateS3Bucket: !And
|
|
- !Equals [!Ref Recording, 's3' ]
|
|
- !Equals [!Ref S3RecordingsBucketName, '']
|
|
|
|
Rules:
|
|
|
|
# Check recording
|
|
RecordingValidation:
|
|
RuleCondition: !Or [ !Equals [!Ref Recording, 'disabled' ], !Equals [!Ref Recording, 'local' ] ]
|
|
Assertions:
|
|
- AssertDescription: Parameter 'S3 Bucket where recordings will be stored' (S3RecordingsBucketName) is not needed when 'Recording' is 'disabled' or 'local'.
|
|
Assert: !Equals [ !Ref S3RecordingsBucketName, '' ]
|
|
|
|
# Check when Elasticsearch is enabled that all the parameters are present
|
|
ElasticsearchValidation:
|
|
RuleCondition: !Equals [ !Ref ElasticsearchEnabled, 'true' ]
|
|
Assertions:
|
|
- AssertDescription: Paramter 'Elasticsearch and Kibana username' (ElasticsearchUser) is needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'true'.
|
|
Assert: !Not [ !Equals [!Ref ElasticsearchUser, ''] ]
|
|
- AssertDescription: Parameter 'Elasticsearch and Kibana password' (ElasticsearchPassword) is needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'true'.
|
|
Assert: !Not [ !Equals [!Ref ElasticsearchPassword, ''] ]
|
|
|
|
# Check when Elasticsearch is disabled that any parameter of elasticsearch is not present
|
|
ElasticsearchDisabledValidation:
|
|
RuleCondition: !Equals [ !Ref ElasticsearchEnabled, 'false' ]
|
|
Assertions:
|
|
- AssertDescription: Parameter 'Elasticsearch URL' (ElasticsearchUrl) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'.
|
|
Assert: !Equals [ !Ref ElasticsearchUrl, "" ]
|
|
- AssertDescription: Parameter 'Kibana URL' (KibanaUrl) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'.
|
|
Assert: !Equals [ !Ref KibanaUrl, "" ]
|
|
- AssertDescription: Parameter 'Elasticsearch and Kibana username' (ElasticsearchUser) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'.
|
|
Assert: !Equals [ !Ref ElasticsearchUser, "" ]
|
|
- AssertDescription: Parameter 'Elasticsearch and Kibana password' (ElasticsearchPassword) is not needed when 'Enable Elasticsearch and Kibana' (ElasticsearchEnabled) is 'false'.
|
|
Assert: !Equals [ !Ref ElasticsearchPassword, "" ]
|
|
|
|
# Check selfsigend parameters
|
|
SelfSignedValidation:
|
|
RuleCondition: !Equals [!Ref WhichCert, 'selfsigned' ]
|
|
Assertions:
|
|
- AssertDescription: Parameter 'URL to the CRT file' (OwnCertCRT) is not necessary when using 'selfsigned' as 'Certificate Type' (WhichCert).
|
|
Assert: !Equals [ !Ref OwnCertCRT, '' ]
|
|
- AssertDescription: Parameter 'URL to the key file' (OwnCertKEY) is not necessary when using 'selfsigned' as 'Certificate Type' (WhichCert).
|
|
Assert: !Equals [!Ref OwnCertKEY, '']
|
|
- AssertDescription: Parameter 'Email for Let's Encrypt' (LetsEncryptEmail) is not necessary when using 'selfsigned' as 'Certificate Type' (WhichCert).
|
|
Assert: !Equals [!Ref LetsEncryptEmail, '']
|
|
|
|
# Check Letsencrypt parameters
|
|
LetsEncryptValidation:
|
|
RuleCondition: !Equals [!Ref WhichCert, 'letsencrypt' ]
|
|
Assertions:
|
|
- AssertDescription: Parameter 'AWS Elastic IP' (PublicElasticIP) is needed when using 'letsencrypt' as 'Certificate Type' (WhichCert).
|
|
Assert: !Not [ !Equals [ !Ref PublicElasticIP, '' ] ]
|
|
- AssertDescription: Parameter 'Email for Let's Encrypt' (LetsEncryptEmail) is needed when using 'letsencrypt' as 'Certificate Type' (WhichCert).
|
|
Assert: !Not [ !Equals [!Ref LetsEncryptEmail, ''] ]
|
|
|
|
# Check OwnCertCRT and OwnCertKEY are defined if owncert is selected
|
|
OwnCertValidation:
|
|
RuleCondition: !Equals [ !Ref WhichCert, 'owncert' ]
|
|
Assertions:
|
|
- AssertDescription: Parameter 'AWS Elastic IP' (PublicElasticIP) is needed when using 'owncert' as 'Certificate Type' (WhichCert).
|
|
Assert: !Not [ !Equals [ !Ref PublicElasticIP, '' ] ]
|
|
- AssertDescription: Parameter 'URL to the CRT file' (OwnCertCRT) is needed when using 'owncert' as 'Certificate Type' (WhichCert).
|
|
Assert: !Not [ !Equals [!Ref OwnCertCRT, ''] ]
|
|
- AssertDescription: Parameter 'URL to the key file' (OwnCertKEY) is needed when using 'owncert' as 'Certificate Type' (WhichCert).
|
|
Assert: !Not [ !Equals [!Ref OwnCertKEY, ''] ]
|
|
|
|
Resources:
|
|
|
|
OpenViduManageEC2Role:
|
|
Type: 'AWS::IAM::Role'
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: 2012-10-17
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- ec2.amazonaws.com
|
|
Action:
|
|
- 'sts:AssumeRole'
|
|
Path: /
|
|
Policies:
|
|
- PolicyName: OpenViduManageEC2Policy
|
|
PolicyDocument:
|
|
Version: 2012-10-17
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- 'ec2:DescribeInstances'
|
|
- 'ec2:RunInstances'
|
|
- 'ec2:TerminateInstances'
|
|
- 'ec2:CreateTags'
|
|
- 'ec2:DescribeSecurityGroups'
|
|
- 'ec2:DescribeSubnets'
|
|
- 'iam:PassRole'
|
|
- 'route53:ChangeResourceRecordSets'
|
|
- 'route53:ListHostedZones'
|
|
Resource: '*'
|
|
- Fn::If:
|
|
# Only apply this policy if S3 is configured
|
|
- RecordingStorageIsS3
|
|
- Effect: Allow
|
|
Action:
|
|
- 's3:DeleteObject'
|
|
- 's3:GetObject'
|
|
- 's3:PutObject'
|
|
Resource:
|
|
- Fn::If:
|
|
# Get bucket name depending if the user defines a bucket name or not
|
|
- CreateS3Bucket
|
|
### Unique bucket name using Stack ID
|
|
- !Join [ "", [ 'arn:aws:s3:::', 'openvidu-recordings-', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]], "/*" ]]
|
|
- !Join [ "", [ 'arn:aws:s3:::', !Ref S3RecordingsBucketName, '/*'] ]
|
|
- Ref: AWS::NoValue
|
|
- Fn::If:
|
|
# Only apply this policy if S3 is configured
|
|
- RecordingStorageIsS3
|
|
- Effect: Allow
|
|
Action:
|
|
- 's3:ListBucket'
|
|
- 's3:GetBucketLocation'
|
|
Resource:
|
|
- Fn::If:
|
|
# Get bucket name depending if the user defines a bucket name or not
|
|
- CreateS3Bucket
|
|
### Unique bucket name using Stack ID
|
|
- !Join [ "", [ 'arn:aws:s3:::', 'openvidu-recordings-', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
|
|
- !Join [ "", [ 'arn:aws:s3:::', !Ref S3RecordingsBucketName ] ]
|
|
- Ref: AWS::NoValue
|
|
- Fn::If:
|
|
# Only apply this policy if S3 is configured
|
|
- RecordingStorageIsS3
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListAllMyBuckets
|
|
Resource: 'arn:aws:s3:::'
|
|
- Ref: AWS::NoValue
|
|
RoleName: !Join [ "-", [ OpenViduManageEC2Role, !Ref 'AWS::StackName', !Ref 'AWS::Region'] ]
|
|
|
|
OpenviduInstancesProfile:
|
|
Type: 'AWS::IAM::InstanceProfile'
|
|
Properties:
|
|
InstanceProfileName: !Join [ "-", [ OpenViduInstanceProfile, !Ref 'AWS::StackName', !Ref 'AWS::Region'] ]
|
|
Path: /
|
|
Roles:
|
|
- !Join [ "-", [ OpenViduManageEC2Role, !Ref 'AWS::StackName', !Ref 'AWS::Region'] ]
|
|
DependsOn:
|
|
- OpenViduManageEC2Role
|
|
|
|
S3bucket:
|
|
Type: 'AWS::S3::Bucket'
|
|
Properties:
|
|
### Unique bucket name using Stack ID
|
|
BucketName: !Join ["-" , [ 'openvidu-recordings', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
|
|
AccessControl: Private
|
|
PublicAccessBlockConfiguration:
|
|
BlockPublicAcls: true
|
|
BlockPublicPolicy: true
|
|
IgnorePublicAcls : true
|
|
RestrictPublicBuckets: true
|
|
DeletionPolicy: Retain
|
|
UpdateReplacePolicy: Retain
|
|
Condition: CreateS3Bucket
|
|
|
|
LaunchTemplate:
|
|
Type: AWS::EC2::LaunchTemplate
|
|
Properties:
|
|
LaunchTemplateName: IMDSV2
|
|
LaunchTemplateData:
|
|
MetadataOptions:
|
|
HttpEndpoint: enabled
|
|
HttpPutResponseHopLimit: 1
|
|
HttpTokens: required
|
|
|
|
OpenViduServer:
|
|
Type: AWS::EC2::Instance
|
|
Metadata:
|
|
Comment: OpenVidu Pro
|
|
AWS::CloudFormation::Init:
|
|
config:
|
|
files:
|
|
'/usr/local/bin/check_app_ready.sh':
|
|
content: |
|
|
#!/bin/bash
|
|
while true; do
|
|
HTTP_STATUS=$(curl -Ik http://localhost:5443/ | head -n1 | awk '{print $2}')
|
|
if [ $HTTP_STATUS == 200 ]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/feedGroupVars.sh':
|
|
content: !Sub
|
|
- |
|
|
#!/bin/bash -xe
|
|
|
|
WORKINGDIR=/opt/openvidu
|
|
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
|
|
|
# Pro License
|
|
sed -i "s/OPENVIDU_PRO_LICENSE=/OPENVIDU_PRO_LICENSE=${OpenViduLicense}/" $WORKINGDIR/.env
|
|
|
|
# OpenVidu Edition
|
|
sed -i "s/OPENVIDU_EDITION=pro/OPENVIDU_EDITION=${OpenViduEdition}/" $WORKINGDIR/.env
|
|
|
|
# Replace secret
|
|
sed -i "s/OPENVIDU_SECRET=/OPENVIDU_SECRET=${OpenViduSecret}/" $WORKINGDIR/.env
|
|
|
|
# Replace domain name
|
|
if [[ "${MyDomainName}" != '' && "${PublicElasticIP}" != '' ]]; then
|
|
sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${MyDomainName}/" $WORKINGDIR/.env
|
|
elif [[ "${MyDomainName}" == '' && "${PublicElasticIP}" != '' ]]; then
|
|
sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${PublicElasticIP}/" $WORKINGDIR/.env
|
|
else
|
|
[ ! -d "/usr/share/openvidu" ] && mkdir -p /usr/share/openvidu
|
|
PublicHostname=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname)
|
|
sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=$PublicHostname/" $WORKINGDIR/.env
|
|
echo $PublicHostname > /usr/share/openvidu/old-host-name
|
|
fi
|
|
|
|
# OpenVidu Pro mode
|
|
sed -i "s/OPENVIDU_PRO_CLUSTER_MODE=manual/OPENVIDU_PRO_CLUSTER_MODE=auto/" $WORKINGDIR/.env
|
|
|
|
# OpenVidu Pro Media Nodes
|
|
sed -i "s/#OPENVIDU_PRO_CLUSTER_MEDIA_NODES=/OPENVIDU_PRO_CLUSTER_MEDIA_NODES=${MediaNodesStartNumber}/" $WORKINGDIR/.env
|
|
|
|
# OpenVidu Pro enviroment
|
|
sed -i "s/OPENVIDU_PRO_CLUSTER_ENVIRONMENT=on_premise/OPENVIDU_PRO_CLUSTER_ENVIRONMENT=aws/" $WORKINGDIR/.env
|
|
|
|
# Replace certificated type
|
|
sed -i "s/CERTIFICATE_TYPE=selfsigned/CERTIFICATE_TYPE=${WhichCert}/" $WORKINGDIR/.env
|
|
sed -i "s/LETSENCRYPT_EMAIL=user@example.com/LETSENCRYPT_EMAIL=${LetsEncryptEmail}/" $WORKINGDIR/.env
|
|
|
|
# Replace Elastic Search Conf
|
|
if [[ "${ElasticsearchEnabled}" == "true" ]]; then
|
|
if [[ ! -z "${ElasticsearchUrl}" ]]; then
|
|
sed -i "s,#OPENVIDU_PRO_ELASTICSEARCH_HOST=,OPENVIDU_PRO_ELASTICSEARCH_HOST=${ElasticsearchUrl}," $WORKINGDIR/.env
|
|
fi
|
|
if [[ ! -z "${KibanaUrl}" ]]; then
|
|
sed -i "s,#OPENVIDU_PRO_KIBANA_HOST=,OPENVIDU_PRO_KIBANA_HOST=${KibanaUrl}," $WORKINGDIR/.env
|
|
fi
|
|
sed -i "s/ELASTICSEARCH_USERNAME=elasticadmin/ELASTICSEARCH_USERNAME=${ElasticsearchUser}/" $WORKINGDIR/.env
|
|
sed -i "s/ELASTICSEARCH_PASSWORD=/ELASTICSEARCH_PASSWORD=${ElasticsearchPassword}/" $WORKINGDIR/.env
|
|
else
|
|
sed -i "s/OPENVIDU_PRO_ELASTICSEARCH=true/OPENVIDU_PRO_ELASTICSEARCH=false/" $WORKINGDIR/.env
|
|
fi
|
|
|
|
# Replace vars AWS
|
|
INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
|
|
sed -i "s/#AWS_DEFAULT_REGION=/AWS_DEFAULT_REGION=${AWS::Region}/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_IMAGE_ID=/AWS_IMAGE_ID=${kmsAmi}/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_INSTANCE_TYPE=/AWS_INSTANCE_TYPE=${AwsInstanceTypeKMS}/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_INSTANCE_ID=/AWS_INSTANCE_ID=$INSTANCE_ID/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_KEY_NAME=/AWS_KEY_NAME=${KeyName}/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_SUBNET_ID=/AWS_SUBNET_ID=${OpenViduSubnet}/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_STACK_ID=/AWS_STACK_ID=$(echo ${AWS::StackId} | sed 's#/#\\/#g')/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_STACK_NAME=/AWS_STACK_NAME=${AWS::StackName}/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_CLI_DOCKER_TAG=/AWS_CLI_DOCKER_TAG=_AWS_CLI_DOCKER_TAG_/" $WORKINGDIR/.env
|
|
sed -i "s/#AWS_VOLUME_SIZE=/AWS_VOLUME_SIZE=50/" $WORKINGDIR/.env
|
|
sed -i "s/#OPENVIDU_PRO_AWS_REGION=/OPENVIDU_PRO_AWS_REGION=${AWS::Region}/" $WORKINGDIR/.env
|
|
|
|
# Get security group id of kms and use it as env variable
|
|
SECGRPIDKMS=$(/usr/local/bin/getSecurityGroupKms.sh)
|
|
sed -i "s/#AWS_SECURITY_GROUP=/AWS_SECURITY_GROUP=$SECGRPIDKMS/" $WORKINGDIR/.env
|
|
|
|
# Without Application
|
|
if [ "${WantToDeployDemos}" == "false" ]; then
|
|
sed -i "s/WITH_APP=true/WITH_APP=false/" $WORKINGDIR/docker-compose.yml
|
|
rm $WORKINGDIR/docker-compose.override.yml
|
|
fi
|
|
|
|
# Deploy Coturn in media nodes
|
|
if [ "${CoturnInMediaNodes}" == "true" ]; then
|
|
sed -i "s/OPENVIDU_PRO_COTURN_IN_MEDIA_NODES=false/OPENVIDU_PRO_COTURN_IN_MEDIA_NODES=true/" $WORKINGDIR/.env
|
|
fi
|
|
|
|
# Recording Configuration
|
|
if [ "${Recording}" != "disabled" ]; then
|
|
sed -i "s/OPENVIDU_RECORDING=false/OPENVIDU_RECORDING=true/" $WORKINGDIR/.env
|
|
sed -i "s/#OPENVIDU_PRO_RECORDING_STORAGE=/OPENVIDU_PRO_RECORDING_STORAGE=${Recording}/" $WORKINGDIR/.env
|
|
if [ ! -z "${S3RecordingsBucketName}" ]; then
|
|
sed -i "s/#OPENVIDU_PRO_AWS_S3_BUCKET=/OPENVIDU_PRO_AWS_S3_BUCKET=${S3RecordingsBucketName}/" $WORKINGDIR/.env
|
|
elif [ "${Recording}" == "s3" ]; then
|
|
sed -i "s/#OPENVIDU_PRO_AWS_S3_BUCKET=/OPENVIDU_PRO_AWS_S3_BUCKET=${s3BucketName}/" $WORKINGDIR/.env
|
|
fi
|
|
fi
|
|
- kmsAmi: !GetAtt CloudformationLambdaInvoke.MediaNodeImageId
|
|
### Unique bucket name using Stack ID
|
|
s3BucketName: !Join ["" , [ 'openvidu-recordings-', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/buildCerts.sh':
|
|
content: !Sub |
|
|
#!/bin/bash -x
|
|
WORKINGDIR=/opt/openvidu
|
|
wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.cert ${OwnCertCRT}
|
|
wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.key ${OwnCertKEY}
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/getSecurityGroupKms.sh':
|
|
content: !Sub |
|
|
#!/bin/bash -x
|
|
docker run --rm amazon/aws-cli:_AWS_CLI_DOCKER_TAG_ ec2 describe-security-groups \
|
|
--region ${AWS::Region} \
|
|
--output text \
|
|
--filters "Name=tag:aws:cloudformation:logical-id,Values=KMSSecurityGroup" \
|
|
"Name=tag:aws:cloudformation:stack-id,Values=${AWS::StackId}" \
|
|
--query 'SecurityGroups[].GroupId[]'
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/restartPRO.sh':
|
|
content: |
|
|
#!/bin/bash -x
|
|
WORKINGDIR=/opt/openvidu
|
|
|
|
# Get new amazon URL
|
|
OldPublicHostname=$(cat /usr/share/openvidu/old-host-name)
|
|
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
|
PublicHostname=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/public-hostname)
|
|
sed -i "s/$OldPublicHostname/$PublicHostname/" $WORKINGDIR/.env
|
|
echo $PublicHostname > /usr/share/openvidu/old-host-name
|
|
|
|
# Restart all services
|
|
pushd /opt/openvidu
|
|
export FOLLOW_OPENVIDU_LOGS=false
|
|
./openvidu stop
|
|
./openvidu start
|
|
popd
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
Properties:
|
|
ImageId: !GetAtt CloudformationLambdaInvoke.MasterNodeImageId
|
|
InstanceType: !Ref AwsInstanceTypeOV
|
|
KeyName: !Ref KeyName
|
|
IamInstanceProfile: !Ref OpenviduInstancesProfile
|
|
SubnetId: !Ref OpenViduSubnet
|
|
SecurityGroupIds:
|
|
- !GetAtt 'OpenViduSecurityGroup.GroupId'
|
|
Tags:
|
|
- Key: Name
|
|
Value: 'OpenVidu Pro Master Node'
|
|
- Key: 'ov-cluster-member'
|
|
Value: 'server'
|
|
UserData:
|
|
"Fn::Base64":
|
|
!Sub |
|
|
#!/bin/bash -xe
|
|
|
|
cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenViduServer
|
|
|
|
export HOME="/root"
|
|
|
|
# Replace .env variables
|
|
/usr/local/bin/feedGroupVars.sh || { echo "[OpenVidu] Parameters incorrect/insufficient"; exit 1; }
|
|
|
|
# Launch on reboot
|
|
echo "@reboot /usr/local/bin/restartPRO.sh" | crontab
|
|
|
|
# Download certs if "WichCert" mode
|
|
if [ "${WhichCert}" == "owncert" ]; then
|
|
/usr/local/bin/buildCerts.sh || { echo "[OpenVidu] error with the certificate files"; exit 1; }
|
|
fi
|
|
|
|
# Start openvidu application
|
|
pushd /opt/openvidu
|
|
export FOLLOW_OPENVIDU_LOGS=false
|
|
./openvidu start
|
|
popd
|
|
|
|
# Wait for the app
|
|
/usr/local/bin/check_app_ready.sh
|
|
|
|
# sending the finish call
|
|
/usr/local/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region}
|
|
|
|
BlockDeviceMappings:
|
|
- DeviceName: /dev/sda1
|
|
Ebs:
|
|
VolumeType: gp3
|
|
DeleteOnTermination: true
|
|
VolumeSize: 200
|
|
|
|
##########
|
|
# Security groups
|
|
##########
|
|
KMSSecurityGroup:
|
|
Type: 'AWS::EC2::SecurityGroup'
|
|
Properties:
|
|
VpcId: !Ref OpenViduVPC
|
|
GroupDescription: SSH, Proxy and KMS WebRTC Ports
|
|
GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'KMSSecurityGroup'] ]
|
|
SecurityGroupIngress:
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 3000
|
|
ToPort: 3000
|
|
SourceSecurityGroupId: !Ref OpenViduSecurityGroup
|
|
- IpProtocol: tcp
|
|
FromPort: 4000
|
|
ToPort: 4000
|
|
SourceSecurityGroupId: !Ref OpenViduSecurityGroup
|
|
- IpProtocol: tcp
|
|
FromPort: 8888
|
|
ToPort: 8888
|
|
SourceSecurityGroupId: !Ref OpenViduSecurityGroup
|
|
- IpProtocol: udp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
SecurityGroupEgress:
|
|
- IpProtocol: tcp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
|
|
OpenViduSecurityGroup:
|
|
Type: 'AWS::EC2::SecurityGroup'
|
|
Properties:
|
|
GroupDescription: SSH, Proxy and OpenVidu WebRTC Ports
|
|
GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'OpenViduSecurityGroup'] ]
|
|
VpcId: !Ref OpenViduVPC
|
|
SecurityGroupIngress:
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 80
|
|
ToPort: 80
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 80
|
|
ToPort: 80
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 3478
|
|
ToPort: 3478
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 3478
|
|
ToPort: 3478
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 3478
|
|
ToPort: 3478
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 3478
|
|
ToPort: 3478
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 40000
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
SecurityGroupEgress:
|
|
- IpProtocol: tcp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 1
|
|
ToPort: 65535
|
|
CidrIpv6: ::/0
|
|
|
|
OpenViduSecurityGroupIngressELK:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduSecurityGroup
|
|
IpProtocol: tcp
|
|
FromPort: 9200
|
|
ToPort: 9200
|
|
SourceSecurityGroupId: !Ref KMSSecurityGroup
|
|
|
|
WaitCondition:
|
|
Type: AWS::CloudFormation::WaitCondition
|
|
CreationPolicy:
|
|
ResourceSignal:
|
|
Timeout: PT25M
|
|
Count: 1
|
|
|
|
MyEIP:
|
|
Type: AWS::EC2::EIPAssociation
|
|
Condition: PublicElasticIPPresent
|
|
Properties:
|
|
InstanceId: !Ref OpenViduServer
|
|
EIP: !Ref PublicElasticIP
|
|
|
|
##########
|
|
# Lambda which complements Cloudformation to:
|
|
# 1. On create: Copy original AMIs from eu-west-1 to the deployment region
|
|
# 2. On Delete: Removes media nodes created by OpenVidu Server PRO
|
|
##########
|
|
CloudformationLambdaRole:
|
|
Type: 'AWS::IAM::Role'
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: 2012-10-17
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- lambda.amazonaws.com
|
|
Action:
|
|
- 'sts:AssumeRole'
|
|
Path: /
|
|
Policies:
|
|
- PolicyName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda-policy'] ]
|
|
PolicyDocument:
|
|
Version: 2012-10-17
|
|
Statement:
|
|
# Permissions to copy original Lambda to the region where it is being deployed
|
|
- Effect: Allow
|
|
Action:
|
|
- 'ec2:DescribeImages'
|
|
- 'ec2:CopyImage'
|
|
Resource: '*'
|
|
# Describe instances to get instances which OpenVidu PRO creates
|
|
- Effect: Allow
|
|
Action:
|
|
- 'ec2:DescribeInstances'
|
|
Resource: '*'
|
|
# Permissions to remove media nodes while destroying the Cloudformation
|
|
# Only those created by OpenVidu PRO can be deleted
|
|
- Effect: Allow
|
|
Action:
|
|
- 'ec2:TerminateInstances'
|
|
Resource: '*'
|
|
Condition:
|
|
StringEquals:
|
|
'aws:ResourceTag/ov-cluster-member': 'kms'
|
|
'aws:ResourceTag/ov-stack-name': !Ref AWS::StackName
|
|
'aws:ResourceTag/ov-stack-region': !Ref AWS::Region
|
|
RoleName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda-role'] ]
|
|
|
|
CloudformationLambda:
|
|
Type: AWS::Lambda::Function
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
FunctionName: !Join ['', [ !Ref AWS::StackName, '-cf-lambda'] ]
|
|
Code:
|
|
ZipFile: |
|
|
import boto3
|
|
import cfnresponse
|
|
from botocore.config import Config
|
|
|
|
def handler(event, context):
|
|
try:
|
|
if (event['RequestType'] == 'Create'):
|
|
copy_ami(event, context)
|
|
elif (event['RequestType'] == 'Delete'):
|
|
removeMediaNodes(event, context)
|
|
else:
|
|
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
|
|
except Exception:
|
|
cfnresponse.send(event, context, cfnresponse.FAILED, {})
|
|
|
|
def copy_ami_operation(source_image_id, source_region, new_ami_name, ec2_client):
|
|
own_ami_filter = [{ 'Name': 'name', 'Values': [new_ami_name] }]
|
|
amis_response = ec2_client.describe_images(Filters=own_ami_filter)
|
|
if (len(amis_response['Images']) == 1):
|
|
# If AMI exists, don't copy
|
|
return amis_response['Images'][0]['ImageId']
|
|
else:
|
|
# If AMI does not exist, copy
|
|
new_amis_response = ec2_client.copy_image(
|
|
SourceImageId=source_image_id,
|
|
SourceRegion=source_region,
|
|
Name=new_ami_name
|
|
)
|
|
return new_amis_response['ImageId']
|
|
|
|
def copy_ami(event, context):
|
|
new_images=[]
|
|
cfn_output = {}
|
|
source_image_id_master_node = event['ResourceProperties']['MasterNodeAmiSourceId']
|
|
source_image_id_media_node = event['ResourceProperties']['MediaNodeAmiSourceId']
|
|
source_region = event['ResourceProperties']['AmiSourceRegion']
|
|
deployment_region = event['ResourceProperties']['DeploymentRegion']
|
|
|
|
# Clients init
|
|
ec2_client = boto3.client('ec2', config = Config(region_name=deployment_region))
|
|
ec2_client_ov = boto3.client('ec2', config = Config(region_name=source_region))
|
|
img_exists_waiter= ec2_client.get_waiter('image_exists')
|
|
img_avail_waiter = ec2_client.get_waiter('image_available')
|
|
|
|
# Get original ami name
|
|
public_ami_master_node_filter = [{ 'Name': 'image-id', 'Values': [ source_image_id_master_node ] }]
|
|
public_ami_media_node_filter = [{ 'Name': 'image-id', 'Values': [ source_image_id_media_node ] }]
|
|
|
|
response = ec2_client_ov.describe_images(Filters=public_ami_master_node_filter)
|
|
new_ami_name_master_node = "[ OpenVidu PRO Master Node AMI Copy ] - " + response['Images'][0]['Name']
|
|
response = ec2_client_ov.describe_images(Filters=public_ami_media_node_filter)
|
|
new_ami_name_media_node = "[ OpenVidu PRO/ENTERPRISE Media Node AMI Copy ] - " + response['Images'][0]['Name']
|
|
|
|
# Copy master node AMI and media node AMI
|
|
master_node_ami_id = copy_ami_operation(source_image_id_master_node, source_region, new_ami_name_master_node, ec2_client)
|
|
new_images.append(master_node_ami_id)
|
|
cfn_output['MasterNodeImageId'] = master_node_ami_id
|
|
media_node_ami_id = copy_ami_operation(source_image_id_media_node, source_region, new_ami_name_media_node, ec2_client)
|
|
new_images.append(media_node_ami_id)
|
|
cfn_output['MediaNodeImageId'] = media_node_ami_id
|
|
|
|
# Wait images to be available
|
|
waiter_config = {'Delay': 15, 'MaxAttempts': 59 }
|
|
response = img_exists_waiter.wait(ImageIds=new_images, WaiterConfig=waiter_config)
|
|
response = img_avail_waiter.wait(ImageIds=new_images, WaiterConfig=waiter_config)
|
|
|
|
# Return AMIs
|
|
cfnresponse.send(event, context, cfnresponse.SUCCESS, cfn_output)
|
|
|
|
def removeMediaNodes(event, context):
|
|
cluster_stack_name = event['ResourceProperties']['StackName']
|
|
deployment_region = event['ResourceProperties']['DeploymentRegion']
|
|
|
|
# Clients init
|
|
ec2_client = boto3.client('ec2', config = Config(region_name=deployment_region))
|
|
ec2_media_node_filter = [
|
|
{ 'Name': 'tag:ov-cluster-member', 'Values': [ 'kms' ] },
|
|
{ 'Name': 'tag:ov-stack-region', 'Values': [ deployment_region ] },
|
|
{ 'Name': 'tag:ov-stack-name', 'Values': [ cluster_stack_name ] }
|
|
]
|
|
|
|
# Get instances to remove
|
|
response_media_nodes = ec2_client.describe_instances(Filters=ec2_media_node_filter, MaxResults=1000)
|
|
|
|
# Remove instances
|
|
instance_ids_to_remove = []
|
|
for reservation in response_media_nodes['Reservations']:
|
|
for instance in reservation['Instances']:
|
|
instance_ids_to_remove.append(instance['InstanceId'])
|
|
print(instance_ids_to_remove)
|
|
ec2_client.terminate_instances(InstanceIds=instance_ids_to_remove)
|
|
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
|
|
|
|
Handler: index.handler
|
|
Role:
|
|
!GetAtt CloudformationLambdaRole.Arn
|
|
Runtime: python3.11
|
|
Timeout: 900
|
|
|
|
CloudformationLambdaInvoke:
|
|
Type: AWS::CloudFormation::CustomResource
|
|
DeletionPolicy: Delete
|
|
Version: "1.0"
|
|
Properties:
|
|
ServiceToken: !GetAtt CloudformationLambda.Arn
|
|
AmiSourceRegion: 'eu-west-1'
|
|
MasterNodeAmiSourceId: !FindInMap [OVAMIMAP, 'eu-west-1', AMI]
|
|
MediaNodeAmiSourceId: !FindInMap [KMSAMIMAP, 'eu-west-1', AMI]
|
|
StackName: !Ref AWS::StackName
|
|
DeploymentRegion: !Ref AWS::Region
|
|
|
|
Outputs:
|
|
OpenViduInspector:
|
|
Description: "Use this URL to connect OpenVidu with user and password"
|
|
Value: !Join
|
|
- ''
|
|
- - 'https://'
|
|
- !GetAtt OpenViduServer.PublicDnsName
|
|
- '/inspector'
|
|
|
|
OpenViduInspectorLE:
|
|
Description: "Use this URL to connect to OpenVidu with user and password if you're using Let's Encrypt"
|
|
Value: !Join
|
|
- ''
|
|
- - 'https://'
|
|
- !Ref MyDomainName
|
|
- '/inspector'
|
|
Condition: WhichCertPresent
|
|
|
|
Kibana:
|
|
Description: "Check out graph and performance of your OpenVidu installation"
|
|
Value: !Join
|
|
- ''
|
|
- - 'https://'
|
|
- !GetAtt OpenViduServer.PublicDnsName
|
|
- '/kibana'
|
|
|
|
KibanaLE:
|
|
Description: "Check out graph and performance of your OpenVidu installation"
|
|
Value: !Join
|
|
- ''
|
|
- - 'https://'
|
|
- !Ref MyDomainName
|
|
- '/kibana'
|
|
Condition: WhichCertPresent
|