mirror of https://github.com/OpenVidu/openvidu.git
3451 lines
127 KiB
YAML
3451 lines
127 KiB
YAML
AWSTemplateFormatVersion: 2010-09-09
|
|
Description: OpenVidu Pro - High Availability
|
|
|
|
Parameters:
|
|
DomainName:
|
|
Type: String
|
|
Description: Domain name for the OpenVidu High Availability cluster
|
|
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
|
|
|
|
OpenViduCertificateARN:
|
|
Description: 'Amazon certificate arn resource to load into the LoadBalancer'
|
|
Type: String
|
|
AllowedPattern: '.+'
|
|
ConstraintDescription: The Load Balancer domain name must be defined
|
|
|
|
OpenViduLicense:
|
|
Description: "Visit https://openvidu.io/account"
|
|
Type: String
|
|
AllowedPattern: ^(?!\s*$).+$
|
|
NoEcho: true
|
|
ConstraintDescription: OpenVidu Pro License is mandatory
|
|
|
|
RTCEngine:
|
|
Description: "RTCEngine media engine to use"
|
|
Type: String
|
|
AllowedValues:
|
|
- pion
|
|
- mediasoup
|
|
Default: pion
|
|
|
|
MasterNodeInstanceType:
|
|
Description: "Specifies the EC2 instance type for your OpenVidu Master Node"
|
|
Type: String
|
|
Default: c6a.xlarge
|
|
AllowedValues:
|
|
- t3.nano
|
|
- t3.micro
|
|
- t3.small
|
|
- t3.medium
|
|
- t3.large
|
|
- t3.xlarge
|
|
- t3.2xlarge
|
|
- t3a.nano
|
|
- t3a.micro
|
|
- t3a.small
|
|
- t3a.medium
|
|
- t3a.large
|
|
- t3a.xlarge
|
|
- t3a.2xlarge
|
|
- t4g.nano
|
|
- t4g.micro
|
|
- t4g.small
|
|
- t4g.medium
|
|
- t4g.large
|
|
- t4g.xlarge
|
|
- t4g.2xlarge
|
|
- c5.large
|
|
- c5.xlarge
|
|
- c5.2xlarge
|
|
- c5.4xlarge
|
|
- c5.9xlarge
|
|
- c5.12xlarge
|
|
- c5.18xlarge
|
|
- c5.24xlarge
|
|
- c5.metal
|
|
- c5a.large
|
|
- c5a.xlarge
|
|
- c5a.2xlarge
|
|
- c5a.4xlarge
|
|
- c5a.8xlarge
|
|
- c5a.12xlarge
|
|
- c5a.16xlarge
|
|
- c5a.24xlarge
|
|
- c5ad.large
|
|
- c5ad.xlarge
|
|
- c5ad.2xlarge
|
|
- c5ad.4xlarge
|
|
- c5ad.8xlarge
|
|
- c5ad.12xlarge
|
|
- c5ad.16xlarge
|
|
- c5ad.24xlarge
|
|
- c5d.large
|
|
- c5d.xlarge
|
|
- c5d.2xlarge
|
|
- c5d.4xlarge
|
|
- c5d.9xlarge
|
|
- c5d.12xlarge
|
|
- c5d.18xlarge
|
|
- c5d.24xlarge
|
|
- c5d.metal
|
|
- c5n.large
|
|
- c5n.xlarge
|
|
- c5n.2xlarge
|
|
- c5n.4xlarge
|
|
- c5n.9xlarge
|
|
- c5n.18xlarge
|
|
- c5n.metal
|
|
- c6a.large
|
|
- c6a.xlarge
|
|
- c6a.2xlarge
|
|
- c6a.4xlarge
|
|
- c6a.8xlarge
|
|
- c6a.12xlarge
|
|
- c6a.16xlarge
|
|
- c6a.24xlarge
|
|
- c6a.32xlarge
|
|
- c6a.48xlarge
|
|
- c6a.metal
|
|
- c6g.medium
|
|
- c6g.large
|
|
- c6g.xlarge
|
|
- c6g.2xlarge
|
|
- c6g.4xlarge
|
|
- c6g.8xlarge
|
|
- c6g.12xlarge
|
|
- c6g.16xlarge
|
|
- c6g.metal
|
|
- c6gd.medium
|
|
- c6gd.large
|
|
- c6gd.xlarge
|
|
- c6gd.2xlarge
|
|
- c6gd.4xlarge
|
|
- c6gd.8xlarge
|
|
- c6gd.12xlarge
|
|
- c6gd.16xlarge
|
|
- c6gd.metal
|
|
- c6gn.medium
|
|
- c6gn.large
|
|
- c6gn.xlarge
|
|
- c6gn.2xlarge
|
|
- c6gn.4xlarge
|
|
- c6gn.8xlarge
|
|
- c6gn.12xlarge
|
|
- c6gn.16xlarge
|
|
- c6i.large
|
|
- c6i.xlarge
|
|
- c6i.2xlarge
|
|
- c6i.4xlarge
|
|
- c6i.8xlarge
|
|
- c6i.12xlarge
|
|
- c6i.16xlarge
|
|
- c6i.24xlarge
|
|
- c6i.32xlarge
|
|
- c6i.metal
|
|
- c6id.large
|
|
- c6id.xlarge
|
|
- c6id.2xlarge
|
|
- c6id.4xlarge
|
|
- c6id.8xlarge
|
|
- c6id.12xlarge
|
|
- c6id.16xlarge
|
|
- c6id.24xlarge
|
|
- c6id.32xlarge
|
|
- c6id.metal
|
|
- c6in.large
|
|
- c6in.xlarge
|
|
- c6in.2xlarge
|
|
- c6in.4xlarge
|
|
- c6in.8xlarge
|
|
- c6in.12xlarge
|
|
- c6in.16xlarge
|
|
- c6in.24xlarge
|
|
- c6in.32xlarge
|
|
- c6in.metal
|
|
- c7a.medium
|
|
- c7a.large
|
|
- c7a.xlarge
|
|
- c7a.2xlarge
|
|
- c7a.4xlarge
|
|
- c7a.8xlarge
|
|
- c7a.12xlarge
|
|
- c7a.16xlarge
|
|
- c7a.24xlarge
|
|
- c7a.32xlarge
|
|
- c7a.48xlarge
|
|
- c7a.metal-48xl
|
|
- c7g.medium
|
|
- c7g.large
|
|
- c7g.xlarge
|
|
- c7g.2xlarge
|
|
- c7g.4xlarge
|
|
- c7g.8xlarge
|
|
- c7g.12xlarge
|
|
- c7g.16xlarge
|
|
- c7g.metal
|
|
- c7gd.medium
|
|
- c7gd.large
|
|
- c7gd.xlarge
|
|
- c7gd.2xlarge
|
|
- c7gd.4xlarge
|
|
- c7gd.8xlarge
|
|
- c7gd.12xlarge
|
|
- c7gd.16xlarge
|
|
- c7gd.metal
|
|
- c7gn.medium
|
|
- c7gn.large
|
|
- c7gn.xlarge
|
|
- c7gn.2xlarge
|
|
- c7gn.4xlarge
|
|
- c7gn.8xlarge
|
|
- c7gn.12xlarge
|
|
- c7gn.16xlarge
|
|
- c7gn.metal
|
|
- c7i-flex.large
|
|
- c7i-flex.xlarge
|
|
- c7i-flex.2xlarge
|
|
- c7i-flex.4xlarge
|
|
- c7i-flex.8xlarge
|
|
- c7i-flex.12xlarge
|
|
- c7i-flex.16xlarge
|
|
- c7i.large
|
|
- c7i.xlarge
|
|
- c7i.2xlarge
|
|
- c7i.4xlarge
|
|
- c7i.8xlarge
|
|
- c7i.12xlarge
|
|
- c7i.16xlarge
|
|
- c7i.24xlarge
|
|
- c7i.48xlarge
|
|
- c7i.metal-24xl
|
|
- c7i.metal-48xl
|
|
- c8g.medium
|
|
- c8g.large
|
|
- c8g.xlarge
|
|
- c8g.2xlarge
|
|
- c8g.4xlarge
|
|
- c8g.8xlarge
|
|
- c8g.12xlarge
|
|
- c8g.16xlarge
|
|
- c8g.24xlarge
|
|
- c8g.48xlarge
|
|
- c8g.metal-24xl
|
|
- c8g.metal-48xl
|
|
- c8gd.medium
|
|
- c8gd.large
|
|
- c8gd.xlarge
|
|
- c8gd.2xlarge
|
|
- c8gd.4xlarge
|
|
- c8gd.8xlarge
|
|
- c8gd.12xlarge
|
|
- c8gd.16xlarge
|
|
- c8gd.24xlarge
|
|
- c8gd.48xlarge
|
|
- c8gd.metal-24xl
|
|
- c8gd.metal-48xl
|
|
- g4dn.xlarge
|
|
- g4dn.2xlarge
|
|
- g4dn.4xlarge
|
|
- g4dn.8xlarge
|
|
- g4dn.12xlarge
|
|
- g4dn.16xlarge
|
|
- g4dn.metal
|
|
- g5.xlarge
|
|
- g5.2xlarge
|
|
- g5.4xlarge
|
|
- g5.8xlarge
|
|
- g5.12xlarge
|
|
- g5.16xlarge
|
|
- g5.24xlarge
|
|
- g5.48xlarge
|
|
- g5g.xlarge
|
|
- g5g.2xlarge
|
|
- g5g.4xlarge
|
|
- g5g.8xlarge
|
|
- g5g.16xlarge
|
|
- g5g.metal
|
|
- g6.xlarge
|
|
- g6.2xlarge
|
|
- g6.4xlarge
|
|
- g6.8xlarge
|
|
- g6.12xlarge
|
|
- g6.16xlarge
|
|
- g6.24xlarge
|
|
- g6.48xlarge
|
|
- g6e.xlarge
|
|
- g6e.2xlarge
|
|
- g6e.4xlarge
|
|
- g6e.8xlarge
|
|
- g6e.12xlarge
|
|
- g6e.16xlarge
|
|
- g6e.24xlarge
|
|
- g6e.48xlarge
|
|
- g6f.large
|
|
- g6f.xlarge
|
|
- g6f.2xlarge
|
|
- g6f.4xlarge
|
|
- g7e.2xlarge
|
|
- g7e.4xlarge
|
|
- g7e.8xlarge
|
|
- g7e.12xlarge
|
|
- g7e.24xlarge
|
|
- g7e.48xlarge
|
|
- gr6.4xlarge
|
|
- gr6.8xlarge
|
|
- gr6f.4xlarge
|
|
- m6a.large
|
|
- m6a.xlarge
|
|
- m6a.2xlarge
|
|
- m6a.4xlarge
|
|
- m6a.8xlarge
|
|
- m6a.12xlarge
|
|
- m6a.16xlarge
|
|
- m6a.24xlarge
|
|
- m6a.32xlarge
|
|
- m6a.48xlarge
|
|
- m6a.metal
|
|
- m6g.medium
|
|
- m6g.large
|
|
- m6g.xlarge
|
|
- m6g.2xlarge
|
|
- m6g.4xlarge
|
|
- m6g.8xlarge
|
|
- m6g.12xlarge
|
|
- m6g.16xlarge
|
|
- m6g.metal
|
|
- m6gd.medium
|
|
- m6gd.large
|
|
- m6gd.xlarge
|
|
- m6gd.2xlarge
|
|
- m6gd.4xlarge
|
|
- m6gd.8xlarge
|
|
- m6gd.12xlarge
|
|
- m6gd.16xlarge
|
|
- m6gd.metal
|
|
- m6i.large
|
|
- m6i.xlarge
|
|
- m6i.2xlarge
|
|
- m6i.4xlarge
|
|
- m6i.8xlarge
|
|
- m6i.12xlarge
|
|
- m6i.16xlarge
|
|
- m6i.24xlarge
|
|
- m6i.32xlarge
|
|
- m6i.metal
|
|
- m6id.large
|
|
- m6id.xlarge
|
|
- m6id.2xlarge
|
|
- m6id.4xlarge
|
|
- m6id.8xlarge
|
|
- m6id.12xlarge
|
|
- m6id.16xlarge
|
|
- m6id.24xlarge
|
|
- m6id.32xlarge
|
|
- m6id.metal
|
|
- m6idn.large
|
|
- m6idn.xlarge
|
|
- m6idn.2xlarge
|
|
- m6idn.4xlarge
|
|
- m6idn.8xlarge
|
|
- m6idn.12xlarge
|
|
- m6idn.16xlarge
|
|
- m6idn.24xlarge
|
|
- m6idn.32xlarge
|
|
- m6idn.metal
|
|
- m6in.large
|
|
- m6in.xlarge
|
|
- m6in.2xlarge
|
|
- m6in.4xlarge
|
|
- m6in.8xlarge
|
|
- m6in.12xlarge
|
|
- m6in.16xlarge
|
|
- m6in.24xlarge
|
|
- m6in.32xlarge
|
|
- m6in.metal
|
|
- m7a.medium
|
|
- m7a.large
|
|
- m7a.xlarge
|
|
- m7a.2xlarge
|
|
- m7a.4xlarge
|
|
- m7a.8xlarge
|
|
- m7a.12xlarge
|
|
- m7a.16xlarge
|
|
- m7a.24xlarge
|
|
- m7a.32xlarge
|
|
- m7a.48xlarge
|
|
- m7a.metal-48xl
|
|
- m7g.medium
|
|
- m7g.large
|
|
- m7g.xlarge
|
|
- m7g.2xlarge
|
|
- m7g.4xlarge
|
|
- m7g.8xlarge
|
|
- m7g.12xlarge
|
|
- m7g.16xlarge
|
|
- m7g.metal
|
|
- m7gd.medium
|
|
- m7gd.large
|
|
- m7gd.xlarge
|
|
- m7gd.2xlarge
|
|
- m7gd.4xlarge
|
|
- m7gd.8xlarge
|
|
- m7gd.12xlarge
|
|
- m7gd.16xlarge
|
|
- m7gd.metal
|
|
- m7i-flex.large
|
|
- m7i-flex.xlarge
|
|
- m7i-flex.2xlarge
|
|
- m7i-flex.4xlarge
|
|
- m7i-flex.8xlarge
|
|
- m7i-flex.12xlarge
|
|
- m7i-flex.16xlarge
|
|
- m7i.large
|
|
- m7i.xlarge
|
|
- m7i.2xlarge
|
|
- m7i.4xlarge
|
|
- m7i.8xlarge
|
|
- m7i.12xlarge
|
|
- m7i.16xlarge
|
|
- m7i.24xlarge
|
|
- m7i.48xlarge
|
|
- m7i.metal-24xl
|
|
- m7i.metal-48xl
|
|
- m8g.medium
|
|
- m8g.large
|
|
- m8g.xlarge
|
|
- m8g.2xlarge
|
|
- m8g.4xlarge
|
|
- m8g.8xlarge
|
|
- m8g.12xlarge
|
|
- m8g.16xlarge
|
|
- m8g.24xlarge
|
|
- m8g.48xlarge
|
|
- m8g.metal-24xl
|
|
- m8g.metal-48xl
|
|
- m8gd.medium
|
|
- m8gd.large
|
|
- m8gd.xlarge
|
|
- m8gd.2xlarge
|
|
- m8gd.4xlarge
|
|
- m8gd.8xlarge
|
|
- m8gd.12xlarge
|
|
- m8gd.16xlarge
|
|
- m8gd.24xlarge
|
|
- m8gd.48xlarge
|
|
- m8gd.metal-24xl
|
|
- m8gd.metal-48xl
|
|
- p4d.24xlarge
|
|
- p4de.24xlarge
|
|
- p5.4xlarge
|
|
- p5.48xlarge
|
|
- p5e.48xlarge
|
|
- p5en.48xlarge
|
|
- p6-b200.48xlarge
|
|
- p6-b300.48xlarge
|
|
- p6e-gb200.36xlarge
|
|
- r6g.medium
|
|
- r6g.large
|
|
- r6g.xlarge
|
|
- r6g.2xlarge
|
|
- r6g.4xlarge
|
|
- r6g.8xlarge
|
|
- r6g.12xlarge
|
|
- r6g.16xlarge
|
|
- r6g.metal
|
|
- r6gd.medium
|
|
- r6gd.large
|
|
- r6gd.xlarge
|
|
- r6gd.2xlarge
|
|
- r6gd.4xlarge
|
|
- r6gd.8xlarge
|
|
- r6gd.12xlarge
|
|
- r6gd.16xlarge
|
|
- r6gd.metal
|
|
- r7g.medium
|
|
- r7g.large
|
|
- r7g.xlarge
|
|
- r7g.2xlarge
|
|
- r7g.4xlarge
|
|
- r7g.8xlarge
|
|
- r7g.12xlarge
|
|
- r7g.16xlarge
|
|
- r7g.metal
|
|
- r7gd.medium
|
|
- r7gd.large
|
|
- r7gd.xlarge
|
|
- r7gd.2xlarge
|
|
- r7gd.4xlarge
|
|
- r7gd.8xlarge
|
|
- r7gd.12xlarge
|
|
- r7gd.16xlarge
|
|
- r7gd.metal
|
|
- r8g.medium
|
|
- r8g.large
|
|
- r8g.xlarge
|
|
- r8g.2xlarge
|
|
- r8g.4xlarge
|
|
- r8g.8xlarge
|
|
- r8g.12xlarge
|
|
- r8g.16xlarge
|
|
- r8g.24xlarge
|
|
- r8g.48xlarge
|
|
- r8g.metal-24xl
|
|
- r8g.metal-48xl
|
|
ConstraintDescription: "Must be a valid EC2 instance type"
|
|
|
|
MediaNodeInstanceType:
|
|
Description: "Specifies the EC2 instance type for your OpenVidu Media Nodes"
|
|
Type: String
|
|
Default: c6a.xlarge
|
|
AllowedValues:
|
|
- t3.nano
|
|
- t3.micro
|
|
- t3.small
|
|
- t3.medium
|
|
- t3.large
|
|
- t3.xlarge
|
|
- t3.2xlarge
|
|
- t3a.nano
|
|
- t3a.micro
|
|
- t3a.small
|
|
- t3a.medium
|
|
- t3a.large
|
|
- t3a.xlarge
|
|
- t3a.2xlarge
|
|
- t4g.nano
|
|
- t4g.micro
|
|
- t4g.small
|
|
- t4g.medium
|
|
- t4g.large
|
|
- t4g.xlarge
|
|
- t4g.2xlarge
|
|
- c5.large
|
|
- c5.xlarge
|
|
- c5.2xlarge
|
|
- c5.4xlarge
|
|
- c5.9xlarge
|
|
- c5.12xlarge
|
|
- c5.18xlarge
|
|
- c5.24xlarge
|
|
- c5.metal
|
|
- c5a.large
|
|
- c5a.xlarge
|
|
- c5a.2xlarge
|
|
- c5a.4xlarge
|
|
- c5a.8xlarge
|
|
- c5a.12xlarge
|
|
- c5a.16xlarge
|
|
- c5a.24xlarge
|
|
- c5ad.large
|
|
- c5ad.xlarge
|
|
- c5ad.2xlarge
|
|
- c5ad.4xlarge
|
|
- c5ad.8xlarge
|
|
- c5ad.12xlarge
|
|
- c5ad.16xlarge
|
|
- c5ad.24xlarge
|
|
- c5d.large
|
|
- c5d.xlarge
|
|
- c5d.2xlarge
|
|
- c5d.4xlarge
|
|
- c5d.9xlarge
|
|
- c5d.12xlarge
|
|
- c5d.18xlarge
|
|
- c5d.24xlarge
|
|
- c5d.metal
|
|
- c5n.large
|
|
- c5n.xlarge
|
|
- c5n.2xlarge
|
|
- c5n.4xlarge
|
|
- c5n.9xlarge
|
|
- c5n.18xlarge
|
|
- c5n.metal
|
|
- c6a.large
|
|
- c6a.xlarge
|
|
- c6a.2xlarge
|
|
- c6a.4xlarge
|
|
- c6a.8xlarge
|
|
- c6a.12xlarge
|
|
- c6a.16xlarge
|
|
- c6a.24xlarge
|
|
- c6a.32xlarge
|
|
- c6a.48xlarge
|
|
- c6a.metal
|
|
- c6g.medium
|
|
- c6g.large
|
|
- c6g.xlarge
|
|
- c6g.2xlarge
|
|
- c6g.4xlarge
|
|
- c6g.8xlarge
|
|
- c6g.12xlarge
|
|
- c6g.16xlarge
|
|
- c6g.metal
|
|
- c6gd.medium
|
|
- c6gd.large
|
|
- c6gd.xlarge
|
|
- c6gd.2xlarge
|
|
- c6gd.4xlarge
|
|
- c6gd.8xlarge
|
|
- c6gd.12xlarge
|
|
- c6gd.16xlarge
|
|
- c6gd.metal
|
|
- c6gn.medium
|
|
- c6gn.large
|
|
- c6gn.xlarge
|
|
- c6gn.2xlarge
|
|
- c6gn.4xlarge
|
|
- c6gn.8xlarge
|
|
- c6gn.12xlarge
|
|
- c6gn.16xlarge
|
|
- c6i.large
|
|
- c6i.xlarge
|
|
- c6i.2xlarge
|
|
- c6i.4xlarge
|
|
- c6i.8xlarge
|
|
- c6i.12xlarge
|
|
- c6i.16xlarge
|
|
- c6i.24xlarge
|
|
- c6i.32xlarge
|
|
- c6i.metal
|
|
- c6id.large
|
|
- c6id.xlarge
|
|
- c6id.2xlarge
|
|
- c6id.4xlarge
|
|
- c6id.8xlarge
|
|
- c6id.12xlarge
|
|
- c6id.16xlarge
|
|
- c6id.24xlarge
|
|
- c6id.32xlarge
|
|
- c6id.metal
|
|
- c6in.large
|
|
- c6in.xlarge
|
|
- c6in.2xlarge
|
|
- c6in.4xlarge
|
|
- c6in.8xlarge
|
|
- c6in.12xlarge
|
|
- c6in.16xlarge
|
|
- c6in.24xlarge
|
|
- c6in.32xlarge
|
|
- c6in.metal
|
|
- c7a.medium
|
|
- c7a.large
|
|
- c7a.xlarge
|
|
- c7a.2xlarge
|
|
- c7a.4xlarge
|
|
- c7a.8xlarge
|
|
- c7a.12xlarge
|
|
- c7a.16xlarge
|
|
- c7a.24xlarge
|
|
- c7a.32xlarge
|
|
- c7a.48xlarge
|
|
- c7a.metal-48xl
|
|
- c7g.medium
|
|
- c7g.large
|
|
- c7g.xlarge
|
|
- c7g.2xlarge
|
|
- c7g.4xlarge
|
|
- c7g.8xlarge
|
|
- c7g.12xlarge
|
|
- c7g.16xlarge
|
|
- c7g.metal
|
|
- c7gd.medium
|
|
- c7gd.large
|
|
- c7gd.xlarge
|
|
- c7gd.2xlarge
|
|
- c7gd.4xlarge
|
|
- c7gd.8xlarge
|
|
- c7gd.12xlarge
|
|
- c7gd.16xlarge
|
|
- c7gd.metal
|
|
- c7gn.medium
|
|
- c7gn.large
|
|
- c7gn.xlarge
|
|
- c7gn.2xlarge
|
|
- c7gn.4xlarge
|
|
- c7gn.8xlarge
|
|
- c7gn.12xlarge
|
|
- c7gn.16xlarge
|
|
- c7gn.metal
|
|
- c7i-flex.large
|
|
- c7i-flex.xlarge
|
|
- c7i-flex.2xlarge
|
|
- c7i-flex.4xlarge
|
|
- c7i-flex.8xlarge
|
|
- c7i-flex.12xlarge
|
|
- c7i-flex.16xlarge
|
|
- c7i.large
|
|
- c7i.xlarge
|
|
- c7i.2xlarge
|
|
- c7i.4xlarge
|
|
- c7i.8xlarge
|
|
- c7i.12xlarge
|
|
- c7i.16xlarge
|
|
- c7i.24xlarge
|
|
- c7i.48xlarge
|
|
- c7i.metal-24xl
|
|
- c7i.metal-48xl
|
|
- c8g.medium
|
|
- c8g.large
|
|
- c8g.xlarge
|
|
- c8g.2xlarge
|
|
- c8g.4xlarge
|
|
- c8g.8xlarge
|
|
- c8g.12xlarge
|
|
- c8g.16xlarge
|
|
- c8g.24xlarge
|
|
- c8g.48xlarge
|
|
- c8g.metal-24xl
|
|
- c8g.metal-48xl
|
|
- c8gd.medium
|
|
- c8gd.large
|
|
- c8gd.xlarge
|
|
- c8gd.2xlarge
|
|
- c8gd.4xlarge
|
|
- c8gd.8xlarge
|
|
- c8gd.12xlarge
|
|
- c8gd.16xlarge
|
|
- c8gd.24xlarge
|
|
- c8gd.48xlarge
|
|
- c8gd.metal-24xl
|
|
- c8gd.metal-48xl
|
|
- g4dn.xlarge
|
|
- g4dn.2xlarge
|
|
- g4dn.4xlarge
|
|
- g4dn.8xlarge
|
|
- g4dn.12xlarge
|
|
- g4dn.16xlarge
|
|
- g4dn.metal
|
|
- g5.xlarge
|
|
- g5.2xlarge
|
|
- g5.4xlarge
|
|
- g5.8xlarge
|
|
- g5.12xlarge
|
|
- g5.16xlarge
|
|
- g5.24xlarge
|
|
- g5.48xlarge
|
|
- g5g.xlarge
|
|
- g5g.2xlarge
|
|
- g5g.4xlarge
|
|
- g5g.8xlarge
|
|
- g5g.16xlarge
|
|
- g5g.metal
|
|
- g6.xlarge
|
|
- g6.2xlarge
|
|
- g6.4xlarge
|
|
- g6.8xlarge
|
|
- g6.12xlarge
|
|
- g6.16xlarge
|
|
- g6.24xlarge
|
|
- g6.48xlarge
|
|
- g6e.xlarge
|
|
- g6e.2xlarge
|
|
- g6e.4xlarge
|
|
- g6e.8xlarge
|
|
- g6e.12xlarge
|
|
- g6e.16xlarge
|
|
- g6e.24xlarge
|
|
- g6e.48xlarge
|
|
- g6f.large
|
|
- g6f.xlarge
|
|
- g6f.2xlarge
|
|
- g6f.4xlarge
|
|
- g7e.2xlarge
|
|
- g7e.4xlarge
|
|
- g7e.8xlarge
|
|
- g7e.12xlarge
|
|
- g7e.24xlarge
|
|
- g7e.48xlarge
|
|
- gr6.4xlarge
|
|
- gr6.8xlarge
|
|
- gr6f.4xlarge
|
|
- m6a.large
|
|
- m6a.xlarge
|
|
- m6a.2xlarge
|
|
- m6a.4xlarge
|
|
- m6a.8xlarge
|
|
- m6a.12xlarge
|
|
- m6a.16xlarge
|
|
- m6a.24xlarge
|
|
- m6a.32xlarge
|
|
- m6a.48xlarge
|
|
- m6a.metal
|
|
- m6g.medium
|
|
- m6g.large
|
|
- m6g.xlarge
|
|
- m6g.2xlarge
|
|
- m6g.4xlarge
|
|
- m6g.8xlarge
|
|
- m6g.12xlarge
|
|
- m6g.16xlarge
|
|
- m6g.metal
|
|
- m6gd.medium
|
|
- m6gd.large
|
|
- m6gd.xlarge
|
|
- m6gd.2xlarge
|
|
- m6gd.4xlarge
|
|
- m6gd.8xlarge
|
|
- m6gd.12xlarge
|
|
- m6gd.16xlarge
|
|
- m6gd.metal
|
|
- m6i.large
|
|
- m6i.xlarge
|
|
- m6i.2xlarge
|
|
- m6i.4xlarge
|
|
- m6i.8xlarge
|
|
- m6i.12xlarge
|
|
- m6i.16xlarge
|
|
- m6i.24xlarge
|
|
- m6i.32xlarge
|
|
- m6i.metal
|
|
- m6id.large
|
|
- m6id.xlarge
|
|
- m6id.2xlarge
|
|
- m6id.4xlarge
|
|
- m6id.8xlarge
|
|
- m6id.12xlarge
|
|
- m6id.16xlarge
|
|
- m6id.24xlarge
|
|
- m6id.32xlarge
|
|
- m6id.metal
|
|
- m6idn.large
|
|
- m6idn.xlarge
|
|
- m6idn.2xlarge
|
|
- m6idn.4xlarge
|
|
- m6idn.8xlarge
|
|
- m6idn.12xlarge
|
|
- m6idn.16xlarge
|
|
- m6idn.24xlarge
|
|
- m6idn.32xlarge
|
|
- m6idn.metal
|
|
- m6in.large
|
|
- m6in.xlarge
|
|
- m6in.2xlarge
|
|
- m6in.4xlarge
|
|
- m6in.8xlarge
|
|
- m6in.12xlarge
|
|
- m6in.16xlarge
|
|
- m6in.24xlarge
|
|
- m6in.32xlarge
|
|
- m6in.metal
|
|
- m7a.medium
|
|
- m7a.large
|
|
- m7a.xlarge
|
|
- m7a.2xlarge
|
|
- m7a.4xlarge
|
|
- m7a.8xlarge
|
|
- m7a.12xlarge
|
|
- m7a.16xlarge
|
|
- m7a.24xlarge
|
|
- m7a.32xlarge
|
|
- m7a.48xlarge
|
|
- m7a.metal-48xl
|
|
- m7g.medium
|
|
- m7g.large
|
|
- m7g.xlarge
|
|
- m7g.2xlarge
|
|
- m7g.4xlarge
|
|
- m7g.8xlarge
|
|
- m7g.12xlarge
|
|
- m7g.16xlarge
|
|
- m7g.metal
|
|
- m7gd.medium
|
|
- m7gd.large
|
|
- m7gd.xlarge
|
|
- m7gd.2xlarge
|
|
- m7gd.4xlarge
|
|
- m7gd.8xlarge
|
|
- m7gd.12xlarge
|
|
- m7gd.16xlarge
|
|
- m7gd.metal
|
|
- m7i-flex.large
|
|
- m7i-flex.xlarge
|
|
- m7i-flex.2xlarge
|
|
- m7i-flex.4xlarge
|
|
- m7i-flex.8xlarge
|
|
- m7i-flex.12xlarge
|
|
- m7i-flex.16xlarge
|
|
- m7i.large
|
|
- m7i.xlarge
|
|
- m7i.2xlarge
|
|
- m7i.4xlarge
|
|
- m7i.8xlarge
|
|
- m7i.12xlarge
|
|
- m7i.16xlarge
|
|
- m7i.24xlarge
|
|
- m7i.48xlarge
|
|
- m7i.metal-24xl
|
|
- m7i.metal-48xl
|
|
- m8g.medium
|
|
- m8g.large
|
|
- m8g.xlarge
|
|
- m8g.2xlarge
|
|
- m8g.4xlarge
|
|
- m8g.8xlarge
|
|
- m8g.12xlarge
|
|
- m8g.16xlarge
|
|
- m8g.24xlarge
|
|
- m8g.48xlarge
|
|
- m8g.metal-24xl
|
|
- m8g.metal-48xl
|
|
- m8gd.medium
|
|
- m8gd.large
|
|
- m8gd.xlarge
|
|
- m8gd.2xlarge
|
|
- m8gd.4xlarge
|
|
- m8gd.8xlarge
|
|
- m8gd.12xlarge
|
|
- m8gd.16xlarge
|
|
- m8gd.24xlarge
|
|
- m8gd.48xlarge
|
|
- m8gd.metal-24xl
|
|
- m8gd.metal-48xl
|
|
- p4d.24xlarge
|
|
- p4de.24xlarge
|
|
- p5.4xlarge
|
|
- p5.48xlarge
|
|
- p5e.48xlarge
|
|
- p5en.48xlarge
|
|
- p6-b200.48xlarge
|
|
- p6-b300.48xlarge
|
|
- p6e-gb200.36xlarge
|
|
- r6g.medium
|
|
- r6g.large
|
|
- r6g.xlarge
|
|
- r6g.2xlarge
|
|
- r6g.4xlarge
|
|
- r6g.8xlarge
|
|
- r6g.12xlarge
|
|
- r6g.16xlarge
|
|
- r6g.metal
|
|
- r6gd.medium
|
|
- r6gd.large
|
|
- r6gd.xlarge
|
|
- r6gd.2xlarge
|
|
- r6gd.4xlarge
|
|
- r6gd.8xlarge
|
|
- r6gd.12xlarge
|
|
- r6gd.16xlarge
|
|
- r6gd.metal
|
|
- r7g.medium
|
|
- r7g.large
|
|
- r7g.xlarge
|
|
- r7g.2xlarge
|
|
- r7g.4xlarge
|
|
- r7g.8xlarge
|
|
- r7g.12xlarge
|
|
- r7g.16xlarge
|
|
- r7g.metal
|
|
- r7gd.medium
|
|
- r7gd.large
|
|
- r7gd.xlarge
|
|
- r7gd.2xlarge
|
|
- r7gd.4xlarge
|
|
- r7gd.8xlarge
|
|
- r7gd.12xlarge
|
|
- r7gd.16xlarge
|
|
- r7gd.metal
|
|
- r8g.medium
|
|
- r8g.large
|
|
- r8g.xlarge
|
|
- r8g.2xlarge
|
|
- r8g.4xlarge
|
|
- r8g.8xlarge
|
|
- r8g.12xlarge
|
|
- r8g.16xlarge
|
|
- r8g.24xlarge
|
|
- r8g.48xlarge
|
|
- r8g.metal-24xl
|
|
- r8g.metal-48xl
|
|
ConstraintDescription: "Must be a valid EC2 instance type"
|
|
|
|
InitialMeetAdminPassword:
|
|
Description: 'Initial password for the "admin" user in OpenVidu Meet. If not provided, a random password will be generated.'
|
|
Type: String
|
|
NoEcho: true
|
|
Default: ''
|
|
# Only allow alphanumeric characters
|
|
AllowedPattern: '^[A-Za-z0-9_-]*$'
|
|
ConstraintDescription: 'Must contain only alphanumeric characters (A-Z, a-z, 0-9). Leave empty to generate a random password.'
|
|
|
|
InitialMeetApiKey:
|
|
Description: 'Initial API key for OpenVidu Meet. If not provided, no API key will be set and the user can set it later from Meet Console.'
|
|
Type: String
|
|
NoEcho: true
|
|
Default: ''
|
|
# Only allow alphanumeric characters
|
|
AllowedPattern: '^[A-Za-z0-9_-]*$'
|
|
ConstraintDescription: 'Must contain only alphanumeric characters (A-Z, a-z, 0-9). Leave empty to not set an initial API key.'
|
|
|
|
KeyName:
|
|
Type: AWS::EC2::KeyPair::KeyName
|
|
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
|
|
AllowedPattern: ^.+$
|
|
ConstraintDescription: must be the name of an existing EC2 KeyPair.
|
|
|
|
OperatingSystem:
|
|
Description: EC2 Operating System
|
|
Type: String
|
|
Default: "Ubuntu-24"
|
|
AllowedValues: ['Ubuntu-22', 'Ubuntu-24']
|
|
|
|
InitialNumberOfMediaNodes:
|
|
Type: Number
|
|
Default: 1
|
|
Description: Number of initial media nodes to deploy
|
|
|
|
MinNumberOfMediaNodes:
|
|
Type: Number
|
|
Default: 1
|
|
Description: Minimum number of media nodes to deploy
|
|
|
|
MaxNumberOfMediaNodes:
|
|
Type: Number
|
|
Default: 5
|
|
Description: Maximum number of media nodes to deploy
|
|
|
|
ScaleTargetCPU:
|
|
Type: Number
|
|
Default: 50
|
|
Description: Target CPU percentage to scale up or down
|
|
|
|
S3AppDataBucketName:
|
|
Type: String
|
|
Description: Name of the S3 bucket to store data and recordings. If empty, a bucket will be created
|
|
|
|
S3ClusterDataBucketName:
|
|
Type: String
|
|
Description: Name of the S3 bucket to store cluster data. If empty, a bucket will be created
|
|
|
|
AdditionalInstallFlags:
|
|
Description: Additional optional flags to pass to the OpenVidu installer (comma-separated, e.g., "--flag1=value, --flag2").
|
|
Type: String
|
|
Default: ""
|
|
AllowedPattern: '^[A-Za-z0-9, =_.\-]*$' # Allows letters, numbers, comma, space, underscore, dot, equals, and hyphen
|
|
ConstraintDescription: Must be a comma-separated list of flags (for example, --flag=value, --bool-flag).
|
|
|
|
OpenViduVPC:
|
|
Description: "Dedicated VPC for OpenVidu cluster"
|
|
Type: AWS::EC2::VPC::Id
|
|
AllowedPattern: ^.+$
|
|
ConstraintDescription: You must specify a VPC ID
|
|
|
|
OpenViduMasterNodeSubnets:
|
|
Description: "Subnets for OpenVidu Master Node"
|
|
Type: List<AWS::EC2::Subnet::Id>
|
|
AllowedPattern: ^.+$
|
|
ConstraintDescription: You must specify a list of subnet IDs
|
|
|
|
OpenViduMediaNodeSubnets:
|
|
Description: "Subnets for OpenVidu Media Nodes"
|
|
Type: List<AWS::EC2::Subnet::Id>
|
|
AllowedPattern: ^.+$
|
|
ConstraintDescription: You must specify a list of subnet IDs
|
|
|
|
LoadBalancerSubnets:
|
|
Description: "(Optional) Public subnets for the internet-facing Load Balancer. Leave empty to place the Load Balancer in the OpenViduMasterNodeSubnets (default behavior). Set it to dedicated public subnets to keep the Master Nodes in private subnets with NAT egress."
|
|
Type: CommaDelimitedList
|
|
Default: ""
|
|
|
|
MasterNodesDiskSize:
|
|
Description: Size of the disk in GB
|
|
Type: Number
|
|
Default: 100
|
|
MinValue: 50
|
|
ConstraintDescription: The disk size must be at least 50 GB
|
|
|
|
Metadata:
|
|
'AWS::CloudFormation::Interface':
|
|
ParameterGroups:
|
|
- Label:
|
|
default: Domain and Load Blancer configuration
|
|
Parameters:
|
|
- DomainName
|
|
- OpenViduCertificateARN
|
|
- Label:
|
|
default: OpenVidu High Availability configuration
|
|
Parameters:
|
|
- OpenViduLicense
|
|
- RTCEngine
|
|
- Label:
|
|
default: OpenVidu Meet configuration
|
|
Parameters:
|
|
- InitialMeetAdminPassword
|
|
- InitialMeetApiKey
|
|
- Label:
|
|
default: EC2 Instance configuration
|
|
Parameters:
|
|
- MasterNodeInstanceType
|
|
- MediaNodeInstanceType
|
|
- KeyName
|
|
- OperatingSystem
|
|
- Label:
|
|
default: Media Nodes Autoscaling Group configuration
|
|
Parameters:
|
|
- InitialNumberOfMediaNodes
|
|
- MinNumberOfMediaNodes
|
|
- MaxNumberOfMediaNodes
|
|
- ScaleTargetCPU
|
|
- Label:
|
|
default: S3 bucket for application data, cluster data and recordings
|
|
Parameters:
|
|
- S3AppDataBucketName
|
|
- S3ClusterDataBucketName
|
|
- Label:
|
|
default: VPC configuration
|
|
Parameters:
|
|
- OpenViduVPC
|
|
- OpenViduMasterNodeSubnets
|
|
- OpenViduMediaNodeSubnets
|
|
- LoadBalancerSubnets
|
|
- Label:
|
|
default: Volumes configuration
|
|
Parameters:
|
|
- MasterNodesDiskSize
|
|
- Label:
|
|
default: "(Optional) Additional Installer Flags"
|
|
Parameters:
|
|
- AdditionalInstallFlags
|
|
|
|
Conditions:
|
|
CreateRecordingsBucket: !Equals [!Ref S3AppDataBucketName, ""]
|
|
CreateClusterDataBucket: !Equals [!Ref S3ClusterDataBucketName, ""]
|
|
HasLoadBalancerSubnets: !Not [!Equals [!Join ["", !Ref LoadBalancerSubnets], ""]]
|
|
IsMasterGraviton: !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 't4g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c6g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c6gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c6gn']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c7g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c7gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c7gn']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c8g']
|
|
- !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'c8gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm6g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm6gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm7g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm7gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm8g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'm8gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r6g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r6gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r7g']
|
|
- !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r7gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'r8g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g5g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6e-gb200']
|
|
IsMediaGraviton: !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 't4g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c6g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c6gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c6gn']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c7g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c7gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c7gn']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c8g']
|
|
- !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'c8gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm6g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm6gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm7g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm7gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm8g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'm8gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r6g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r6gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r7g']
|
|
- !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r7gd']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'r8g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g5g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6e-gb200']
|
|
IsMasterNodeNvidia: !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g4dn']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g5']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g5g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g6']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g6e']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g6f']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'gr6']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'gr6f']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'g7e']
|
|
- !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p4d']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p4de']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p5']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p5e']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p5en']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6-b200']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6-b300']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MasterNodeInstanceType ]], 'p6e-gb200']
|
|
IsMediaNodeNvidia: !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g4dn']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g5']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g5g']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g6']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g6e']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g6f']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'gr6']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'gr6f']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'g7e']
|
|
- !Or
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p4d']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p4de']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p5']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p5e']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p5en']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6-b200']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6-b300']
|
|
- !Equals [ !Select [ 0, !Split ['.', !Ref MediaNodeInstanceType ]], 'p6e-gb200']
|
|
|
|
Mappings:
|
|
ArmImage:
|
|
# aws ssm get-parameters-by-path --path "/aws/service/canonical/ubuntu/" --recursive --query "Parameters[*].Name" > canonical-ami.txt
|
|
Ubuntu-22:
|
|
ImageId: '{{resolve:ssm:/aws/service/canonical/ubuntu/server/jammy/stable/current/arm64/hvm/ebs-gp2/ami-id}}'
|
|
Ubuntu-24:
|
|
ImageId: '{{resolve:ssm:/aws/service/canonical/ubuntu/server/noble/stable/current/arm64/hvm/ebs-gp3/ami-id}}'
|
|
AmdImage:
|
|
Ubuntu-22:
|
|
ImageId: '{{resolve:ssm:/aws/service/canonical/ubuntu/server/jammy/stable/current/amd64/hvm/ebs-gp2/ami-id}}'
|
|
Ubuntu-24:
|
|
ImageId: '{{resolve:ssm:/aws/service/canonical/ubuntu/server/noble/stable/current/amd64/hvm/ebs-gp3/ami-id}}'
|
|
|
|
Resources:
|
|
|
|
OpenViduSharedInfo:
|
|
Type: AWS::SecretsManager::Secret
|
|
UpdateReplacePolicy: Retain
|
|
DeletionPolicy: Delete
|
|
Properties:
|
|
Name: !Sub openvidu-ha-${AWS::Region}-${AWS::StackName}
|
|
Description: Secret for OpenVidu High Availability to store deployment info and seed secret
|
|
# All the values are initialized by one master node and shared with the rest of the nodes
|
|
SecretString: |
|
|
{
|
|
"OPENVIDU_URL": "none",
|
|
"MEET_INITIAL_ADMIN_USER": "none",
|
|
"MEET_INITIAL_ADMIN_PASSWORD": "none",
|
|
"MEET_INITIAL_API_KEY": "none",
|
|
"LIVEKIT_URL": "none",
|
|
"LIVEKIT_API_KEY": "none",
|
|
"LIVEKIT_API_SECRET": "none",
|
|
"DASHBOARD_URL": "none",
|
|
"GRAFANA_URL": "none",
|
|
"MINIO_URL": "none",
|
|
"DOMAIN_NAME": "none",
|
|
"OPENVIDU_PRO_LICENSE": "none",
|
|
"OPENVIDU_RTC_ENGINE": "none",
|
|
"REDIS_PASSWORD": "none",
|
|
"MONGO_ADMIN_USERNAME": "none",
|
|
"MONGO_ADMIN_PASSWORD": "none",
|
|
"MONGO_REPLICA_SET_KEY": "none",
|
|
"MINIO_ACCESS_KEY": "none",
|
|
"MINIO_SECRET_KEY": "none",
|
|
"DASHBOARD_ADMIN_USERNAME": "none",
|
|
"DASHBOARD_ADMIN_PASSWORD": "none",
|
|
"GRAFANA_ADMIN_USERNAME": "none",
|
|
"GRAFANA_ADMIN_PASSWORD": "none",
|
|
"ENABLED_MODULES": "none",
|
|
"OPENVIDU_VERSION": "none",
|
|
"ALL_SECRETS_GENERATED": "false"
|
|
}
|
|
|
|
# One SSM parameter per master: atomic per-key writes
|
|
MasterNode1PrivateIpParameter:
|
|
Type: AWS::SSM::Parameter
|
|
Properties:
|
|
Name: !Sub /openvidu/${AWS::StackName}/master-node-1-private-ip
|
|
Type: String
|
|
Value: "none"
|
|
|
|
MasterNode2PrivateIpParameter:
|
|
Type: AWS::SSM::Parameter
|
|
Properties:
|
|
Name: !Sub /openvidu/${AWS::StackName}/master-node-2-private-ip
|
|
Type: String
|
|
Value: "none"
|
|
|
|
MasterNode3PrivateIpParameter:
|
|
Type: AWS::SSM::Parameter
|
|
Properties:
|
|
Name: !Sub /openvidu/${AWS::StackName}/master-node-3-private-ip
|
|
Type: String
|
|
Value: "none"
|
|
|
|
MasterNode4PrivateIpParameter:
|
|
Type: AWS::SSM::Parameter
|
|
Properties:
|
|
Name: !Sub /openvidu/${AWS::StackName}/master-node-4-private-ip
|
|
Type: String
|
|
Value: "none"
|
|
|
|
S3AppDataBucketResource:
|
|
Type: 'AWS::S3::Bucket'
|
|
Properties:
|
|
### Unique bucket name using Stack ID
|
|
BucketName: !Join ["-" , [ 'openvidu-appdata', !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: CreateRecordingsBucket
|
|
|
|
S3ClusterDataBucketResource:
|
|
Type: 'AWS::S3::Bucket'
|
|
Properties:
|
|
### Unique bucket name using Stack ID
|
|
BucketName: !Join ["-" , [ 'openvidu-clusterdata', !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: CreateClusterDataBucket
|
|
|
|
# -------------------------
|
|
# Normalize the master node subnet list to exactly 4 entries, one per OpenVidu Master Node
|
|
# -------------------------
|
|
SubnetProcessorFunction:
|
|
Type: AWS::Lambda::Function
|
|
Properties:
|
|
FunctionName: !Sub 'SubnetProcessor-${AWS::Region}-${AWS::StackName}'
|
|
Handler: index.lambda_handler
|
|
Role: !GetAtt LambdaExecutionRole.Arn
|
|
Code:
|
|
ZipFile: |
|
|
import cfnresponse
|
|
|
|
def lambda_handler(event, context):
|
|
try:
|
|
# Process event data
|
|
subnets = event['ResourceProperties']['Subnets']
|
|
|
|
# Ensure we have at least four subnets by cycling through the available subnets
|
|
subnets = (subnets * 4)[:4] # Repeat the list to have at least 4 elements and then take the first 4
|
|
|
|
# Prepare the response
|
|
responseData = {
|
|
'Subnet1': subnets[0],
|
|
'Subnet2': subnets[1],
|
|
'Subnet3': subnets[2],
|
|
'Subnet4': subnets[3],
|
|
}
|
|
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
|
|
|
|
except Exception as e:
|
|
cfnresponse.send(event, context, cfnresponse.FAILED, {'Message': str(e)})
|
|
|
|
|
|
Runtime: python3.12
|
|
Timeout: 120
|
|
|
|
SubnetProcessor:
|
|
Type: Custom::SubnetProcessor
|
|
Properties:
|
|
ServiceToken: !GetAtt SubnetProcessorFunction.Arn
|
|
Subnets: !Ref OpenViduMasterNodeSubnets
|
|
|
|
LambdaLogGroup:
|
|
UpdateReplacePolicy: Retain
|
|
DeletionPolicy: Delete
|
|
Type: AWS::Logs::LogGroup
|
|
Properties:
|
|
LogGroupName: !Sub '/aws/lambda/SubnetProcessor-${AWS::Region}-${AWS::StackName}'
|
|
RetentionInDays: 7
|
|
|
|
LambdaExecutionRole:
|
|
Type: AWS::IAM::Role
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- lambda.amazonaws.com
|
|
Action: 'sts:AssumeRole'
|
|
Policies:
|
|
- PolicyName: LambdaLogsPolicy
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- logs:CreateLogStream
|
|
- logs:PutLogEvents
|
|
Resource: !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/SubnetProcessor-${AWS::Region}-${AWS::StackName}:*'
|
|
|
|
OpenViduMasterNodeRole:
|
|
Type: AWS::IAM::Role
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- ec2.amazonaws.com
|
|
Action:
|
|
- 'sts:AssumeRole'
|
|
Path: "/"
|
|
ManagedPolicyArns:
|
|
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore
|
|
Policies:
|
|
- PolicyName: !Sub openvidu-master-policy-${AWS::Region}-${AWS::StackName}
|
|
PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- autoscaling:SetInstanceHealth
|
|
Resource: '*'
|
|
Condition:
|
|
StringEquals:
|
|
'aws:ResourceTag/aws:cloudformation:stack-id': !Ref 'AWS::StackId'
|
|
- Effect: Allow
|
|
Action:
|
|
- secretsmanager:GetSecretValue
|
|
- secretsmanager:UpdateSecret
|
|
Resource: !Ref OpenViduSharedInfo
|
|
- Effect: Allow
|
|
Action:
|
|
- ssm:GetParameter
|
|
- ssm:PutParameter
|
|
Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/openvidu/${AWS::StackName}/*
|
|
- Fn::If:
|
|
- CreateRecordingsBucket
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:DeleteObject
|
|
- s3:GetObject
|
|
- s3:PutObject
|
|
Resource: !Sub ${S3AppDataBucketResource.Arn}/*
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:DeleteObject
|
|
- s3:GetObject
|
|
- s3:PutObject
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}/*
|
|
- Fn::If:
|
|
- CreateRecordingsBucket
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListBucket
|
|
- s3:GetBucketLocation
|
|
Resource: !GetAtt S3AppDataBucketResource.Arn
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListBucket
|
|
- s3:GetBucketLocation
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}
|
|
- Fn::If:
|
|
- CreateClusterDataBucket
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:DeleteObject
|
|
- s3:GetObject
|
|
- s3:PutObject
|
|
Resource: !Sub ${S3ClusterDataBucketResource.Arn}/*
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:DeleteObject
|
|
- s3:GetObject
|
|
- s3:PutObject
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${S3ClusterDataBucketName}/*
|
|
- Fn::If:
|
|
- CreateClusterDataBucket
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListBucket
|
|
- s3:GetBucketLocation
|
|
Resource: !GetAtt S3ClusterDataBucketResource.Arn
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListBucket
|
|
- s3:GetBucketLocation
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${S3ClusterDataBucketName}
|
|
RoleName:
|
|
Fn::Join:
|
|
# Generate a not too long and unique role name
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - openvidu-master-role-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
|
|
OpenViduMediaNodeRole:
|
|
Type: 'AWS::IAM::Role'
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: 2012-10-17
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- ec2.amazonaws.com
|
|
Action:
|
|
- 'sts:AssumeRole'
|
|
Path: /
|
|
ManagedPolicyArns:
|
|
- !Sub arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore
|
|
Policies:
|
|
- PolicyName: !Sub openvidu-media-policy-${AWS::Region}-${AWS::StackName}
|
|
PolicyDocument:
|
|
Version: 2012-10-17
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- secretsmanager:GetSecretValue
|
|
Resource: !Ref OpenViduSharedInfo
|
|
- Effect: Allow
|
|
Action:
|
|
- ssm:GetParameter
|
|
Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/openvidu/${AWS::StackName}/*
|
|
- Effect: Allow
|
|
Action:
|
|
- autoscaling:SetInstanceHealth
|
|
- autoscaling:CompleteLifecycleAction
|
|
- autoscaling:RecordLifecycleActionHeartbeat
|
|
Resource: '*'
|
|
Condition:
|
|
StringEquals:
|
|
'aws:ResourceTag/aws:cloudformation:stack-name': !Ref 'AWS::StackName'
|
|
- Fn::If:
|
|
- CreateRecordingsBucket
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:DeleteObject
|
|
- s3:GetObject
|
|
- s3:PutObject
|
|
Resource: !Sub ${S3AppDataBucketResource.Arn}/*
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:DeleteObject
|
|
- s3:GetObject
|
|
- s3:PutObject
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}/*
|
|
- Fn::If:
|
|
- CreateRecordingsBucket
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListBucket
|
|
- s3:GetBucketLocation
|
|
Resource: !GetAtt S3AppDataBucketResource.Arn
|
|
- Effect: Allow
|
|
Action:
|
|
- s3:ListBucket
|
|
- s3:GetBucketLocation
|
|
Resource: !Sub arn:${AWS::Partition}:s3:::${S3AppDataBucketName}
|
|
RoleName:
|
|
Fn::Join:
|
|
# Generate a not too long and unique role name
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - openvidu-media-role-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
|
|
OpenViduMasterInstanceProfile:
|
|
Type: AWS::IAM::InstanceProfile
|
|
Properties:
|
|
InstanceProfileName: !Sub OpenViduMasterInstanceProfile-${AWS::Region}-${AWS::StackName}
|
|
Roles:
|
|
- !Ref OpenViduMasterNodeRole
|
|
|
|
OpenViduMediaInstanceProfile:
|
|
Type: AWS::IAM::InstanceProfile
|
|
Properties:
|
|
InstanceProfileName: !Sub OpenViduMediaInstanceProfile-${AWS::Region}-${AWS::StackName}
|
|
Roles:
|
|
- !Ref OpenViduMediaNodeRole
|
|
|
|
OpenViduMasterLaunchTemplate:
|
|
Type: AWS::EC2::LaunchTemplate
|
|
Metadata:
|
|
Comment: Launch template for OpenVidu Master Node
|
|
AWS::CloudFormation::Init:
|
|
config:
|
|
files:
|
|
'/usr/local/bin/install.sh':
|
|
content: !Sub |
|
|
#!/bin/bash -x
|
|
set -e
|
|
OPENVIDU_VERSION=main
|
|
DOMAIN=
|
|
YQ_VERSION=v4.53.6
|
|
|
|
# Install dependencies
|
|
apt-get update && apt-get install -y \
|
|
curl \
|
|
unzip \
|
|
jq \
|
|
wget
|
|
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
|
|
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
|
|
|
|
AWS_CLI_VERSION=2.36.40
|
|
# Install aws-cli if not already installed
|
|
if ! command -v aws &> /dev/null; then
|
|
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"
|
|
unzip -qq awscliv2.zip
|
|
./aws/install
|
|
rm -rf awscliv2.zip aws
|
|
fi
|
|
|
|
# Signal to notify instance is waiting
|
|
SIGNAL_NAME="$1"
|
|
|
|
# Exported earlier in this instance's UserData
|
|
MASTER_NODE_NUM="${!MASTER_NODE_NUM}"
|
|
|
|
# Token for IMDSv2
|
|
TOKEN="$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")"
|
|
|
|
# Get own private IP
|
|
PRIVATE_IP="$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/local-ipv4)"
|
|
|
|
if [[ "$PRIVATE_IP" == "" ]]; then
|
|
echo "Error: Private IP not found"
|
|
exit 1
|
|
fi
|
|
|
|
aws ssm put-parameter \
|
|
--region ${AWS::Region} \
|
|
--name "/openvidu/${AWS::StackName}/master-node-${!MASTER_NODE_NUM}-private-ip" \
|
|
--value "${!PRIVATE_IP}" \
|
|
--type String \
|
|
--overwrite > /dev/null
|
|
|
|
SHARED_SECRET=$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text)
|
|
ALL_SECRETS_GENERATED=$(echo "$SHARED_SECRET" | jq -r '.ALL_SECRETS_GENERATED')
|
|
|
|
# If the private IP is the same as the first master node, generate the secrets
|
|
if [[ $MASTER_NODE_NUM -eq 1 ]] && [[ "$ALL_SECRETS_GENERATED" == "false" ]]; then
|
|
DOMAIN="$(/usr/local/bin/store_secret.sh save DOMAIN_NAME "${DomainName}")"
|
|
# Publish access URLs early so other nodes can read them during phase 2
|
|
# (idempotent: after_install rewrites these same byte-identical values later)
|
|
/usr/local/bin/store_secret.sh save OPENVIDU_URL "https://${!DOMAIN}/"
|
|
/usr/local/bin/store_secret.sh save LIVEKIT_URL "wss://${!DOMAIN}/"
|
|
/usr/local/bin/store_secret.sh save DASHBOARD_URL "https://${!DOMAIN}/dashboard/"
|
|
/usr/local/bin/store_secret.sh save GRAFANA_URL "https://${!DOMAIN}/grafana/"
|
|
/usr/local/bin/store_secret.sh save MINIO_URL "https://${!DOMAIN}/minio-console/"
|
|
OPENVIDU_PRO_LICENSE="$(/usr/local/bin/store_secret.sh save OPENVIDU_PRO_LICENSE "${OpenViduLicense}")"
|
|
OPENVIDU_RTC_ENGINE="$(/usr/local/bin/store_secret.sh save OPENVIDU_RTC_ENGINE "${RTCEngine}")"
|
|
# Store version so media nodes can use it to install the same version
|
|
/usr/local/bin/store_secret.sh save OPENVIDU_VERSION "${!OPENVIDU_VERSION}"
|
|
|
|
# Meet initial admin user and password
|
|
MEET_INITIAL_ADMIN_USER="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_ADMIN_USER "admin")"
|
|
if [[ "${InitialMeetAdminPassword}" != '' ]]; then
|
|
MEET_INITIAL_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_ADMIN_PASSWORD "${InitialMeetAdminPassword}")"
|
|
else
|
|
MEET_INITIAL_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate MEET_INITIAL_ADMIN_PASSWORD)"
|
|
fi
|
|
if [[ "${InitialMeetApiKey}" != '' ]]; then
|
|
MEET_INITIAL_API_KEY="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_API_KEY "${InitialMeetApiKey}")"
|
|
else
|
|
MEET_INITIAL_API_KEY="$(/usr/local/bin/store_secret.sh save MEET_INITIAL_API_KEY "")"
|
|
fi
|
|
|
|
# Store usernames and generate random passwords
|
|
REDIS_PASSWORD="$(/usr/local/bin/store_secret.sh generate REDIS_PASSWORD)"
|
|
MONGO_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save MONGO_ADMIN_USERNAME "mongoadmin")"
|
|
MONGO_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate MONGO_ADMIN_PASSWORD)"
|
|
MONGO_REPLICA_SET_KEY="$(/usr/local/bin/store_secret.sh generate MONGO_REPLICA_SET_KEY)"
|
|
MINIO_ACCESS_KEY="$(/usr/local/bin/store_secret.sh save MINIO_ACCESS_KEY "minioadmin")"
|
|
MINIO_SECRET_KEY="$(/usr/local/bin/store_secret.sh generate MINIO_SECRET_KEY)"
|
|
DASHBOARD_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save DASHBOARD_ADMIN_USERNAME "dashboardadmin")"
|
|
DASHBOARD_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate DASHBOARD_ADMIN_PASSWORD)"
|
|
GRAFANA_ADMIN_USERNAME="$(/usr/local/bin/store_secret.sh save GRAFANA_ADMIN_USERNAME "grafanaadmin")"
|
|
GRAFANA_ADMIN_PASSWORD="$(/usr/local/bin/store_secret.sh generate GRAFANA_ADMIN_PASSWORD)"
|
|
LIVEKIT_API_KEY="$(/usr/local/bin/store_secret.sh generate LIVEKIT_API_KEY "API" 12)"
|
|
LIVEKIT_API_SECRET="$(/usr/local/bin/store_secret.sh generate LIVEKIT_API_SECRET)"
|
|
ENABLED_MODULES="$(/usr/local/bin/store_secret.sh save ENABLED_MODULES "observability,v2compatibility,openviduMeet")"
|
|
ALL_SECRETS_GENERATED="$(/usr/local/bin/store_secret.sh save ALL_SECRETS_GENERATED "true")"
|
|
fi
|
|
|
|
# Fetch the shared secret again, waiting until master-1 has generated all secrets.
|
|
# Bounded (up to 900s at 5s): a genuinely stuck master-1 still surfaces after the deadline.
|
|
SECRETS_WAIT_ATTEMPTS=0
|
|
SECRETS_WAIT_MAX=180
|
|
while true; do
|
|
SHARED_SECRET=$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text || echo 'none')
|
|
|
|
ALL_SECRETS_GENERATED=$(echo "$SHARED_SECRET" | jq -r '.ALL_SECRETS_GENERATED')
|
|
if [[ "${!ALL_SECRETS_GENERATED}" == "true" ]]; then
|
|
break
|
|
fi
|
|
|
|
SECRETS_WAIT_ATTEMPTS=$((SECRETS_WAIT_ATTEMPTS + 1))
|
|
if [[ $SECRETS_WAIT_ATTEMPTS -ge $SECRETS_WAIT_MAX ]]; then
|
|
echo "Error: Secrets not generated"
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
# sending the signal call
|
|
cfn-signal -e $? --stack ${AWS::StackId} --resource "$SIGNAL_NAME" --region ${AWS::Region}
|
|
|
|
IP_WAIT_ATTEMPTS=0
|
|
IP_WAIT_MAX=360
|
|
while true; do
|
|
MASTER_NODE_1_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-1-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_NODE_2_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-2-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_NODE_3_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-3-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_NODE_4_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-4-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
|
|
# Check if all master nodes have published their private IPs
|
|
if [[ "$MASTER_NODE_1_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_1_PRIVATE_IP" ]] &&
|
|
[[ "$MASTER_NODE_2_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_2_PRIVATE_IP" ]] &&
|
|
[[ "$MASTER_NODE_3_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_3_PRIVATE_IP" ]] &&
|
|
[[ "$MASTER_NODE_4_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_4_PRIVATE_IP" ]]; then
|
|
break
|
|
fi
|
|
|
|
IP_WAIT_ATTEMPTS=$((IP_WAIT_ATTEMPTS + 1))
|
|
if [[ $IP_WAIT_ATTEMPTS -ge $IP_WAIT_MAX ]]; then
|
|
echo "Error: timed out after 30 minutes waiting for all master nodes to publish their private IPs to SSM"
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
# Comma-separated 1-4: must match installer's --master-node-private-ip-list format
|
|
MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP"
|
|
|
|
# Re-read: other (non-IP) values still come from the shared secret.
|
|
# GetSecretValue is eventually consistent: retry until a read returns the generated values
|
|
SECRET_READ_ATTEMPTS=0
|
|
while true; do
|
|
SHARED_SECRET=$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text)
|
|
if echo "$SHARED_SECRET" | jq -e '(.ALL_SECRETS_GENERATED == "true") and ([.DOMAIN_NAME, .OPENVIDU_VERSION, .REDIS_PASSWORD, .MONGO_ADMIN_PASSWORD, .MONGO_REPLICA_SET_KEY, .MINIO_SECRET_KEY, .DASHBOARD_ADMIN_PASSWORD, .GRAFANA_ADMIN_PASSWORD, .LIVEKIT_API_KEY, .LIVEKIT_API_SECRET] | all(. != "none"))' > /dev/null; then
|
|
break
|
|
fi
|
|
SECRET_READ_ATTEMPTS=$((SECRET_READ_ATTEMPTS + 1))
|
|
if [[ $SECRET_READ_ATTEMPTS -ge 60 ]]; then
|
|
echo "Error: shared secret still incomplete after 5 minutes of stale reads"
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
DOMAIN=$(echo "$SHARED_SECRET" | jq -r '.DOMAIN_NAME')
|
|
OPENVIDU_PRO_LICENSE=$(echo "$SHARED_SECRET" | jq -r '.OPENVIDU_PRO_LICENSE')
|
|
OPENVIDU_RTC_ENGINE=$(echo "$SHARED_SECRET" | jq -r '.OPENVIDU_RTC_ENGINE')
|
|
REDIS_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.REDIS_PASSWORD')
|
|
MONGO_ADMIN_USERNAME=$(echo "$SHARED_SECRET" | jq -r '.MONGO_ADMIN_USERNAME')
|
|
MONGO_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.MONGO_ADMIN_PASSWORD')
|
|
MONGO_REPLICA_SET_KEY=$(echo "$SHARED_SECRET" | jq -r '.MONGO_REPLICA_SET_KEY')
|
|
MINIO_ACCESS_KEY=$(echo "$SHARED_SECRET" | jq -r '.MINIO_ACCESS_KEY')
|
|
MINIO_SECRET_KEY=$(echo "$SHARED_SECRET" | jq -r '.MINIO_SECRET_KEY')
|
|
DASHBOARD_ADMIN_USERNAME=$(echo "$SHARED_SECRET" | jq -r '.DASHBOARD_ADMIN_USERNAME')
|
|
DASHBOARD_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.DASHBOARD_ADMIN_PASSWORD')
|
|
GRAFANA_ADMIN_USERNAME=$(echo "$SHARED_SECRET" | jq -r '.GRAFANA_ADMIN_USERNAME')
|
|
GRAFANA_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.GRAFANA_ADMIN_PASSWORD')
|
|
MEET_INITIAL_ADMIN_USER=$(echo "$SHARED_SECRET" | jq -r '.MEET_INITIAL_ADMIN_USER')
|
|
MEET_INITIAL_ADMIN_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.MEET_INITIAL_ADMIN_PASSWORD')
|
|
MEET_INITIAL_API_KEY=""
|
|
if [[ "${InitialMeetApiKey}" != '' ]]; then
|
|
MEET_INITIAL_API_KEY=$(echo "$SHARED_SECRET" | jq -r '.MEET_INITIAL_API_KEY')
|
|
fi
|
|
LIVEKIT_API_KEY=$(echo "$SHARED_SECRET" | jq -r '.LIVEKIT_API_KEY')
|
|
LIVEKIT_API_SECRET=$(echo "$SHARED_SECRET" | jq -r '.LIVEKIT_API_SECRET')
|
|
ENABLED_MODULES=$(echo "$SHARED_SECRET" | jq -r '.ENABLED_MODULES')
|
|
|
|
# Download first: sh <(curl ...) would silently run an empty script on a transient curl failure
|
|
INSTALLER_SCRIPT="/tmp/install_ov_master_node.sh"
|
|
curl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o "$INSTALLER_SCRIPT" "http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_master_node.sh"
|
|
if [ ! -s "$INSTALLER_SCRIPT" ]; then
|
|
echo "Downloaded OpenVidu master node installer is empty or missing" >&2
|
|
exit 1
|
|
fi
|
|
INSTALL_COMMAND="sh $INSTALLER_SCRIPT"
|
|
|
|
# Common arguments
|
|
COMMON_ARGS=(
|
|
"--no-tty"
|
|
"--install"
|
|
"--environment=aws"
|
|
"--deployment-type='ha'"
|
|
"--node-role='master-node'"
|
|
"--external-load-balancer"
|
|
"--master-node-private-ip-list='$MASTER_NODE_PRIVATE_IP_LIST'"
|
|
"--openvidu-pro-license='$OPENVIDU_PRO_LICENSE'"
|
|
"--domain-name='$DOMAIN'"
|
|
"--enabled-modules='$ENABLED_MODULES'"
|
|
"--rtc-engine=$OPENVIDU_RTC_ENGINE"
|
|
"--redis-password=$REDIS_PASSWORD"
|
|
"--mongo-admin-user=$MONGO_ADMIN_USERNAME"
|
|
"--mongo-admin-password=$MONGO_ADMIN_PASSWORD"
|
|
"--mongo-replica-set-key=$MONGO_REPLICA_SET_KEY"
|
|
"--minio-access-key=$MINIO_ACCESS_KEY"
|
|
"--minio-secret-key=$MINIO_SECRET_KEY"
|
|
"--dashboard-admin-user=$DASHBOARD_ADMIN_USERNAME"
|
|
"--dashboard-admin-password=$DASHBOARD_ADMIN_PASSWORD"
|
|
"--grafana-admin-user=$GRAFANA_ADMIN_USERNAME"
|
|
"--grafana-admin-password=$GRAFANA_ADMIN_PASSWORD"
|
|
"--meet-initial-admin-password=$MEET_INITIAL_ADMIN_PASSWORD"
|
|
"--meet-initial-api-key=$MEET_INITIAL_API_KEY"
|
|
"--livekit-api-key=$LIVEKIT_API_KEY"
|
|
"--livekit-api-secret=$LIVEKIT_API_SECRET"
|
|
)
|
|
|
|
# Include additional installer flags provided by the user
|
|
if [[ "${AdditionalInstallFlags}" != "" ]]; then
|
|
IFS=',' read -ra EXTRA_FLAGS <<< "${AdditionalInstallFlags}"
|
|
for extra_flag in "${!EXTRA_FLAGS[@]}"; do
|
|
# Trim whitespace around each flag
|
|
extra_flag="$(echo -e "${!extra_flag}" | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//')"
|
|
if [[ "$extra_flag" != "" ]]; then
|
|
COMMON_ARGS+=("$extra_flag")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Construct the final command
|
|
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${!COMMON_ARGS[@]}")"
|
|
|
|
# Install OpenVidu
|
|
exec bash -c "$FINAL_COMMAND"
|
|
|
|
mode: '000755'
|
|
owner: root
|
|
group: root
|
|
'/usr/local/bin/config_s3.sh':
|
|
content: !Sub
|
|
- |
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
# Install dir and config dir
|
|
INSTALL_DIR="/opt/openvidu"
|
|
CLUSTER_CONFIG_DIR="${!INSTALL_DIR}/config/cluster"
|
|
|
|
# Config S3 bucket
|
|
EXTERNAL_S3_ENDPOINT="https://s3.${AWS::Region}.amazonaws.com"
|
|
EXTERNAL_S3_REGION="${AWS::Region}"
|
|
EXTERNAL_S3_PATH_STYLE_ACCESS="false"
|
|
EXTERNAL_S3_BUCKET_APP_DATA=${S3AppDataBucketResourceName}
|
|
EXTERNAL_S3_BUCKET_CLUSTER_DATA=${S3ClusterDataBucketResourceName}
|
|
sed -i "s|EXTERNAL_S3_ENDPOINT=.*|EXTERNAL_S3_ENDPOINT=$EXTERNAL_S3_ENDPOINT|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s|EXTERNAL_S3_REGION=.*|EXTERNAL_S3_REGION=$EXTERNAL_S3_REGION|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s|EXTERNAL_S3_PATH_STYLE_ACCESS=.*|EXTERNAL_S3_PATH_STYLE_ACCESS=$EXTERNAL_S3_PATH_STYLE_ACCESS|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s|EXTERNAL_S3_BUCKET_APP_DATA=.*|EXTERNAL_S3_BUCKET_APP_DATA=$EXTERNAL_S3_BUCKET_APP_DATA|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s|EXTERNAL_S3_BUCKET_CLUSTER_DATA=.*|EXTERNAL_S3_BUCKET_CLUSTER_DATA=$EXTERNAL_S3_BUCKET_CLUSTER_DATA|" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
- S3AppDataBucketResourceName: !If
|
|
- CreateRecordingsBucket
|
|
- !Ref S3AppDataBucketResource
|
|
- !Ref S3AppDataBucketName
|
|
S3ClusterDataBucketResourceName: !If
|
|
- CreateClusterDataBucket
|
|
- !Ref S3ClusterDataBucketResource
|
|
- !Ref S3ClusterDataBucketName
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/after_install.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
# Only master 1 writes the shared secret, to avoid a lost-update race
|
|
if [[ "${!MASTER_NODE_NUM:-}" != "1" ]]; then
|
|
exit 0
|
|
fi
|
|
# Get current shared secret
|
|
SHARED_SECRET=$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text)
|
|
|
|
# Save access URLs
|
|
DOMAIN=$(echo "$SHARED_SECRET" | jq -r '.DOMAIN_NAME')
|
|
OPENVIDU_URL="https://${!DOMAIN}/"
|
|
LIVEKIT_URL="wss://${!DOMAIN}/"
|
|
DASHBOARD_URL="https://${!DOMAIN}/dashboard/"
|
|
GRAFANA_URL="https://${!DOMAIN}/grafana/"
|
|
MINIO_URL="https://${!DOMAIN}/minio-console/"
|
|
|
|
# Update shared secret
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_URL": "'"$OPENVIDU_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_URL": "'"$LIVEKIT_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DOMAIN_NAME": "'"$DOMAIN"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_URL": "'"$DASHBOARD_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_URL": "'"$GRAFANA_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_URL": "'"$MINIO_URL"'" }')"
|
|
|
|
# Update shared secret
|
|
aws secretsmanager update-secret \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--secret-string "$SHARED_SECRET"
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/update_config_from_secret.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
# Token for IMDSv2
|
|
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
|
# Get current shared secret
|
|
SHARED_SECRET=$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text)
|
|
|
|
# Installation directory
|
|
INSTALL_DIR="/opt/openvidu"
|
|
CLUSTER_CONFIG_DIR="${!INSTALL_DIR}/config/cluster"
|
|
MASTER_NODE_CONFIG_DIR="${!INSTALL_DIR}/config/node"
|
|
|
|
# Replace DOMAIN_NAME
|
|
export DOMAIN=$(echo $SHARED_SECRET | jq -r .DOMAIN_NAME)
|
|
if [[ -n "$DOMAIN" ]]; then
|
|
sed -i "s/DOMAIN_NAME=.*/DOMAIN_NAME=$DOMAIN/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
else
|
|
exit 1
|
|
fi
|
|
|
|
# Replace rest of the values
|
|
sed -i "s/REDIS_PASSWORD=.*/REDIS_PASSWORD=$(echo $SHARED_SECRET | jq -r .REDIS_PASSWORD)/" "${!MASTER_NODE_CONFIG_DIR}/master_node.env"
|
|
sed -i "s/OPENVIDU_RTC_ENGINE=.*/OPENVIDU_RTC_ENGINE=$(echo $SHARED_SECRET | jq -r .OPENVIDU_RTC_ENGINE)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/OPENVIDU_PRO_LICENSE=.*/OPENVIDU_PRO_LICENSE=$(echo $SHARED_SECRET | jq -r .OPENVIDU_PRO_LICENSE)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/MONGO_ADMIN_USERNAME=.*/MONGO_ADMIN_USERNAME=$(echo $SHARED_SECRET | jq -r .MONGO_ADMIN_USERNAME)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/MONGO_ADMIN_PASSWORD=.*/MONGO_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .MONGO_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/DASHBOARD_ADMIN_USERNAME=.*/DASHBOARD_ADMIN_USERNAME=$(echo $SHARED_SECRET | jq -r .DASHBOARD_ADMIN_USERNAME)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/DASHBOARD_ADMIN_PASSWORD=.*/DASHBOARD_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .DASHBOARD_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/MINIO_ACCESS_KEY=.*/MINIO_ACCESS_KEY=$(echo $SHARED_SECRET | jq -r .MINIO_ACCESS_KEY)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/MINIO_SECRET_KEY=.*/MINIO_SECRET_KEY=$(echo $SHARED_SECRET | jq -r .MINIO_SECRET_KEY)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/GRAFANA_ADMIN_USERNAME=.*/GRAFANA_ADMIN_USERNAME=$(echo $SHARED_SECRET | jq -r .GRAFANA_ADMIN_USERNAME)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/GRAFANA_ADMIN_PASSWORD=.*/GRAFANA_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .GRAFANA_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/LIVEKIT_API_KEY=.*/LIVEKIT_API_KEY=$(echo $SHARED_SECRET | jq -r .LIVEKIT_API_KEY)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/LIVEKIT_API_SECRET=.*/LIVEKIT_API_SECRET=$(echo $SHARED_SECRET | jq -r .LIVEKIT_API_SECRET)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
sed -i "s/MEET_INITIAL_ADMIN_USER=.*/MEET_INITIAL_ADMIN_USER=$(echo $SHARED_SECRET | jq -r .MEET_INITIAL_ADMIN_USER)/" "${!CLUSTER_CONFIG_DIR}/master_node/meet.env"
|
|
sed -i "s/MEET_INITIAL_ADMIN_PASSWORD=.*/MEET_INITIAL_ADMIN_PASSWORD=$(echo $SHARED_SECRET | jq -r .MEET_INITIAL_ADMIN_PASSWORD)/" "${!CLUSTER_CONFIG_DIR}/master_node/meet.env"
|
|
if [[ "${InitialMeetApiKey}" != '' ]]; then
|
|
sed -i "s/MEET_INITIAL_API_KEY=.*/MEET_INITIAL_API_KEY=$(echo $SHARED_SECRET | jq -r .MEET_INITIAL_API_KEY)/" "${!CLUSTER_CONFIG_DIR}/master_node/meet.env"
|
|
fi
|
|
sed -i "s/ENABLED_MODULES=.*/ENABLED_MODULES=$(echo $SHARED_SECRET | jq -r .ENABLED_MODULES)/" "${!CLUSTER_CONFIG_DIR}/openvidu.env"
|
|
|
|
# Update URLs in secret
|
|
OPENVIDU_URL="https://${!DOMAIN}/"
|
|
LIVEKIT_URL="wss://${!DOMAIN}/"
|
|
DASHBOARD_URL="https://${!DOMAIN}/dashboard/"
|
|
GRAFANA_URL="https://${!DOMAIN}/grafana/"
|
|
MINIO_URL="https://${!DOMAIN}/minio-console/"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_URL": "'"$OPENVIDU_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_URL": "'"$LIVEKIT_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DOMAIN_NAME": "'"$DOMAIN"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_URL": "'"$DASHBOARD_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_URL": "'"$GRAFANA_URL"'" }')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_URL": "'"$MINIO_URL"'" }')"
|
|
aws secretsmanager update-secret \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--secret-string "$SHARED_SECRET"
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/update_secret_from_config.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
# Get current shared secret
|
|
SHARED_SECRET=$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text)
|
|
|
|
# Installation directory
|
|
INSTALL_DIR="/opt/openvidu"
|
|
CLUSTER_CONFIG_DIR="${!INSTALL_DIR}/config/cluster"
|
|
MASTER_NODE_CONFIG_DIR="${!INSTALL_DIR}/config/node"
|
|
|
|
|
|
# Update shared secret
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"REDIS_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh REDIS_PASSWORD "${!MASTER_NODE_CONFIG_DIR}/master_node.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DOMAIN_NAME": "'"$(/usr/local/bin/get_value_from_config.sh DOMAIN_NAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_RTC_ENGINE": "'"$(/usr/local/bin/get_value_from_config.sh OPENVIDU_RTC_ENGINE "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"OPENVIDU_PRO_LICENSE": "'"$(/usr/local/bin/get_value_from_config.sh OPENVIDU_PRO_LICENSE "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MONGO_ADMIN_USERNAME": "'"$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_USERNAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MONGO_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh MONGO_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_ACCESS_KEY": "'"$(/usr/local/bin/get_value_from_config.sh MINIO_ACCESS_KEY "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MINIO_SECRET_KEY": "'"$(/usr/local/bin/get_value_from_config.sh MINIO_SECRET_KEY "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_ADMIN_USERNAME": "'"$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_USERNAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"DASHBOARD_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh DASHBOARD_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_ADMIN_USERNAME": "'"$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_USERNAME "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"GRAFANA_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh GRAFANA_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_API_KEY": "'"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_KEY "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"LIVEKIT_API_SECRET": "'"$(/usr/local/bin/get_value_from_config.sh LIVEKIT_API_SECRET "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MEET_INITIAL_ADMIN_USER": "'"$(/usr/local/bin/get_value_from_config.sh MEET_INITIAL_ADMIN_USER "${!CLUSTER_CONFIG_DIR}/master_node/meet.env")"'"}')"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MEET_INITIAL_ADMIN_PASSWORD": "'"$(/usr/local/bin/get_value_from_config.sh MEET_INITIAL_ADMIN_PASSWORD "${!CLUSTER_CONFIG_DIR}/master_node/meet.env")"'"}')"
|
|
if [[ "${InitialMeetApiKey}" != '' ]]; then
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"MEET_INITIAL_API_KEY": "'"$(/usr/local/bin/get_value_from_config.sh MEET_INITIAL_API_KEY "${!CLUSTER_CONFIG_DIR}/master_node/meet.env")"'"}')"
|
|
fi
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"ENABLED_MODULES": "'"$(/usr/local/bin/get_value_from_config.sh ENABLED_MODULES "${!CLUSTER_CONFIG_DIR}/openvidu.env")"'"}')"
|
|
|
|
# Update shared secret
|
|
aws secretsmanager update-secret \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--secret-string "$SHARED_SECRET"
|
|
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/get_value_from_config.sh':
|
|
content: |
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
# Function to get the value of a given key from the environment file
|
|
get_value() {
|
|
local key="$1"
|
|
local file_path="$2"
|
|
|
|
# Use grep to find the line with the key, ignoring lines starting with #
|
|
# Use awk to split on '=' and print the second field, which is the value
|
|
local value=$(grep -E "^\s*$key\s*=" "$file_path" | awk -F= '{print $2}' | sed 's/#.*//; s/^\s*//; s/\s*$//')
|
|
|
|
# If the value is empty, return "none"
|
|
if [ -z "$value" ]; then
|
|
echo "none"
|
|
else
|
|
echo "$value"
|
|
fi
|
|
}
|
|
|
|
# Check if the correct number of arguments are supplied
|
|
if [ "$#" -ne 2 ]; then
|
|
echo "Usage: $0 <key> <file_path>"
|
|
exit 1
|
|
fi
|
|
|
|
# Get the key and file path from the arguments
|
|
key="$1"
|
|
file_path="$2"
|
|
|
|
# Get and print the value
|
|
get_value "$key" "$file_path"
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/store_secret.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
# Modes: save, generate
|
|
# save mode: save the secret in the secret manager
|
|
# generate mode: generate a random password and save it in the secret manager
|
|
MODE="$1"
|
|
SHARED_SECRET="$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id ${OpenViduSharedInfo} \
|
|
--query SecretString --output text)"
|
|
if [[ "$MODE" == "generate" ]]; then
|
|
SECRET_KEY_NAME="$2"
|
|
PREFIX="${!3:-}"
|
|
LENGTH="${!4:-44}"
|
|
RANDOM_PASSWORD="$(openssl rand -base64 64 | tr -d '+/=\n' | cut -c -${!LENGTH})"
|
|
RANDOM_PASSWORD="${!PREFIX}${!RANDOM_PASSWORD}"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"'"$SECRET_KEY_NAME"'": "'"$RANDOM_PASSWORD"'"}')"
|
|
aws secretsmanager update-secret \
|
|
--region ${AWS::Region} \
|
|
--secret-id ${OpenViduSharedInfo} \
|
|
--secret-string "$SHARED_SECRET" > /dev/null 2>&1
|
|
echo "$RANDOM_PASSWORD"
|
|
elif [[ "$MODE" == "save" ]]; then
|
|
SECRET_KEY_NAME="$2"
|
|
SECRET_VALUE="$3"
|
|
SHARED_SECRET="$(echo "$SHARED_SECRET" | jq '. + {"'"$SECRET_KEY_NAME"'": "'"$SECRET_VALUE"'"}')"
|
|
aws secretsmanager update-secret \
|
|
--region ${AWS::Region} \
|
|
--secret-id ${OpenViduSharedInfo} \
|
|
--secret-string "$SHARED_SECRET" > /dev/null 2>&1
|
|
echo "$SECRET_VALUE"
|
|
else
|
|
exit 1
|
|
fi
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/restart.sh':
|
|
content: |
|
|
#!/bin/bash
|
|
set -e
|
|
# Stop all services
|
|
systemctl stop openvidu
|
|
|
|
# Update config from secret
|
|
/usr/local/bin/update_config_from_secret.sh
|
|
|
|
# Start all services
|
|
systemctl start openvidu
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
Properties:
|
|
LaunchTemplateName: !Sub 'openvidu-ha-master-${AWS::Region}-${AWS::StackName}'
|
|
LaunchTemplateData:
|
|
# Enable IMDSv2
|
|
MetadataOptions:
|
|
HttpEndpoint: enabled
|
|
HttpPutResponseHopLimit: 1
|
|
HttpTokens: required
|
|
IamInstanceProfile:
|
|
Name: !Ref OpenViduMasterInstanceProfile
|
|
ImageId: !If
|
|
- IsMasterGraviton
|
|
- !If
|
|
- IsMasterNodeNvidia
|
|
- '{{resolve:ssm:/aws/service/deeplearning/ami/arm64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
|
|
- !FindInMap [ArmImage, !Ref OperatingSystem, ImageId]
|
|
- !If
|
|
- IsMasterNodeNvidia
|
|
- '{{resolve:ssm:/aws/service/deeplearning/ami/x86_64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
|
|
- !FindInMap [AmdImage, !Ref OperatingSystem, ImageId]
|
|
InstanceType: !Ref MasterNodeInstanceType
|
|
KeyName: !Ref KeyName
|
|
SecurityGroupIds:
|
|
- !Ref OpenViduMasterNodeSG
|
|
BlockDeviceMappings:
|
|
- DeviceName: /dev/sda1
|
|
Ebs:
|
|
VolumeSize: !Ref MasterNodesDiskSize
|
|
VolumeType: gp3
|
|
DeleteOnTermination: true
|
|
|
|
OpenViduMasterNode1:
|
|
Type: AWS::EC2::Instance
|
|
# Depends on its own SSM parameter so its put-parameter can't race the parameter's creation
|
|
DependsOn: MasterNode1PrivateIpParameter
|
|
Properties:
|
|
LaunchTemplate:
|
|
LaunchTemplateId: !Ref OpenViduMasterLaunchTemplate
|
|
Version: !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Master Node 1
|
|
SubnetId: !GetAtt SubnetProcessor.Subnet1
|
|
UserData:
|
|
Fn::Base64: !Sub |
|
|
#!/bin/bash
|
|
set -eu -o pipefail
|
|
|
|
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
|
|
|
|
apt-get update && apt-get install -y \
|
|
python3-pip \
|
|
ec2-instance-connect
|
|
|
|
CFN_BOOTSTRAP_VERSION=2.0-39
|
|
# Detect Ubuntu version and install cfn-bootstrap accordingly
|
|
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
|
|
if [ "$UBUNTU_VERSION" -ge 24 ]; then
|
|
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
else
|
|
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
fi
|
|
|
|
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
|
|
|
|
export MASTER_NODE_NUM=1
|
|
|
|
# Install OpenVidu
|
|
/usr/local/bin/install.sh "MasterNodesWaitCondition1" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
|
|
|
|
# Config S3 bucket
|
|
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
|
|
|
|
# Start OpenVidu
|
|
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
|
|
|
|
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
|
|
OPENVIDU_READY=false
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
if [ "$OPENVIDU_READY" != "true" ]; then
|
|
echo "[OpenVidu] not healthy after 300s, restarting once"
|
|
systemctl restart openvidu || true
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
fi
|
|
|
|
# Update shared secret
|
|
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
|
|
|
|
# Launch on reboot
|
|
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
|
|
|
|
|
|
MasterNodesWaitCondition1:
|
|
Type: 'AWS::CloudFormation::WaitCondition'
|
|
CreationPolicy:
|
|
ResourceSignal:
|
|
Timeout: PT20M
|
|
Count: '1'
|
|
|
|
OpenViduMasterNode2:
|
|
Type: AWS::EC2::Instance
|
|
DependsOn: MasterNode2PrivateIpParameter
|
|
Properties:
|
|
LaunchTemplate:
|
|
LaunchTemplateId: !Ref OpenViduMasterLaunchTemplate
|
|
Version: !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Master Node 2
|
|
SubnetId: !GetAtt SubnetProcessor.Subnet2
|
|
UserData:
|
|
Fn::Base64: !Sub |
|
|
#!/bin/bash
|
|
set -eu -o pipefail
|
|
|
|
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
|
|
|
|
apt-get update && apt-get install -y \
|
|
python3-pip \
|
|
ec2-instance-connect
|
|
|
|
CFN_BOOTSTRAP_VERSION=2.0-39
|
|
# Detect Ubuntu version and install cfn-bootstrap accordingly
|
|
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
|
|
if [ "$UBUNTU_VERSION" -ge 24 ]; then
|
|
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
else
|
|
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
fi
|
|
|
|
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
|
|
|
|
export MASTER_NODE_NUM=2
|
|
|
|
# Install OpenVidu
|
|
/usr/local/bin/install.sh "MasterNodesWaitCondition2" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
|
|
|
|
# Config S3 bucket
|
|
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
|
|
|
|
# Start OpenVidu
|
|
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
|
|
|
|
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
|
|
OPENVIDU_READY=false
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
if [ "$OPENVIDU_READY" != "true" ]; then
|
|
echo "[OpenVidu] not healthy after 300s, restarting once"
|
|
systemctl restart openvidu || true
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
fi
|
|
|
|
# Update shared secret
|
|
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
|
|
|
|
# Launch on reboot
|
|
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
|
|
|
|
|
|
MasterNodesWaitCondition2:
|
|
Type: 'AWS::CloudFormation::WaitCondition'
|
|
CreationPolicy:
|
|
ResourceSignal:
|
|
Timeout: PT20M
|
|
Count: '1'
|
|
|
|
OpenViduMasterNode3:
|
|
Type: AWS::EC2::Instance
|
|
DependsOn: MasterNode3PrivateIpParameter
|
|
Properties:
|
|
LaunchTemplate:
|
|
LaunchTemplateId: !Ref OpenViduMasterLaunchTemplate
|
|
Version: !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Master Node 3
|
|
SubnetId: !GetAtt SubnetProcessor.Subnet3
|
|
UserData:
|
|
Fn::Base64: !Sub |
|
|
#!/bin/bash
|
|
set -eu -o pipefail
|
|
|
|
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
|
|
|
|
apt-get update && apt-get install -y \
|
|
python3-pip \
|
|
ec2-instance-connect
|
|
|
|
CFN_BOOTSTRAP_VERSION=2.0-39
|
|
# Detect Ubuntu version and install cfn-bootstrap accordingly
|
|
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
|
|
if [ "$UBUNTU_VERSION" -ge 24 ]; then
|
|
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
else
|
|
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
fi
|
|
|
|
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
|
|
|
|
export MASTER_NODE_NUM=3
|
|
|
|
# Install OpenVidu
|
|
/usr/local/bin/install.sh "MasterNodesWaitCondition3" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
|
|
|
|
# Config S3 bucket
|
|
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
|
|
|
|
# Start OpenVidu
|
|
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
|
|
|
|
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
|
|
OPENVIDU_READY=false
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
if [ "$OPENVIDU_READY" != "true" ]; then
|
|
echo "[OpenVidu] not healthy after 300s, restarting once"
|
|
systemctl restart openvidu || true
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
fi
|
|
|
|
# Update shared secret
|
|
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
|
|
|
|
# Launch on reboot
|
|
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
|
|
|
|
|
|
MasterNodesWaitCondition3:
|
|
Type: 'AWS::CloudFormation::WaitCondition'
|
|
CreationPolicy:
|
|
ResourceSignal:
|
|
Timeout: PT20M
|
|
Count: '1'
|
|
|
|
OpenViduMasterNode4:
|
|
Type: AWS::EC2::Instance
|
|
DependsOn: MasterNode4PrivateIpParameter
|
|
Properties:
|
|
LaunchTemplate:
|
|
LaunchTemplateId: !Ref OpenViduMasterLaunchTemplate
|
|
Version: !GetAtt OpenViduMasterLaunchTemplate.LatestVersionNumber
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Master Node 4
|
|
SubnetId: !GetAtt SubnetProcessor.Subnet4
|
|
UserData:
|
|
Fn::Base64: !Sub |
|
|
#!/bin/bash
|
|
set -eu -o pipefail
|
|
|
|
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
|
|
|
|
apt-get update && apt-get install -y \
|
|
python3-pip \
|
|
ec2-instance-connect
|
|
|
|
CFN_BOOTSTRAP_VERSION=2.0-39
|
|
# Detect Ubuntu version and install cfn-bootstrap accordingly
|
|
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
|
|
if [ "$UBUNTU_VERSION" -ge 24 ]; then
|
|
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
else
|
|
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
fi
|
|
|
|
cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMasterLaunchTemplate
|
|
|
|
export MASTER_NODE_NUM=4
|
|
|
|
# Install OpenVidu
|
|
/usr/local/bin/install.sh "MasterNodesWaitCondition4" || { echo "[OpenVidu] error installing OpenVidu"; exit 1; }
|
|
|
|
# Config S3 bucket
|
|
/usr/local/bin/config_s3.sh || { echo "[OpenVidu] error configuring S3 bucket"; exit 1; }
|
|
|
|
# Start OpenVidu
|
|
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; exit 1; }
|
|
|
|
# Local readiness gate: wait up to 300s for Caddy health, restart once if it does not converge
|
|
OPENVIDU_READY=false
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
if [ "$OPENVIDU_READY" != "true" ]; then
|
|
echo "[OpenVidu] not healthy after 300s, restarting once"
|
|
systemctl restart openvidu || true
|
|
for i in $(seq 1 60); do
|
|
if curl -fsS http://127.0.0.1:7880/health/caddy >/dev/null 2>&1; then
|
|
OPENVIDU_READY=true
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
fi
|
|
|
|
# Update shared secret
|
|
/usr/local/bin/after_install.sh || { echo "[OpenVidu] error updating shared secret"; exit 1; }
|
|
|
|
# Launch on reboot
|
|
echo "@reboot /usr/local/bin/restart.sh &> /var/log/openvidu-restart.log" | crontab
|
|
|
|
MasterNodesWaitCondition4:
|
|
Type: 'AWS::CloudFormation::WaitCondition'
|
|
CreationPolicy:
|
|
ResourceSignal:
|
|
Timeout: PT20M
|
|
Count: '1'
|
|
|
|
OpenViduMediaNodeLaunchTemplate:
|
|
Type: AWS::EC2::LaunchTemplate
|
|
Metadata:
|
|
Comment: Launch template for OpenVidu Media Node
|
|
AWS::CloudFormation::Init:
|
|
config:
|
|
files:
|
|
'/usr/local/bin/install.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
YQ_VERSION=v4.53.6
|
|
|
|
# Install dependencies
|
|
apt-get update && apt-get install -y \
|
|
curl \
|
|
unzip \
|
|
jq \
|
|
wget
|
|
wget https://github.com/mikefarah/yq/releases/download/${!YQ_VERSION}/yq_linux_$(dpkg --print-architecture).tar.gz -O - |\
|
|
tar xz && mv yq_linux_$(dpkg --print-architecture) /usr/bin/yq
|
|
|
|
AWS_CLI_VERSION=2.36.40
|
|
# Install aws-cli if not already installed
|
|
if ! command -v aws &> /dev/null; then
|
|
curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m)-${!AWS_CLI_VERSION}.zip" -o "awscliv2.zip"
|
|
unzip -qq awscliv2.zip
|
|
./aws/install
|
|
rm -rf awscliv2.zip aws
|
|
fi
|
|
|
|
# Token for IMDSv2
|
|
TOKEN="$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")"
|
|
|
|
# Get own private IP
|
|
PRIVATE_IP="$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/local-ipv4)"
|
|
|
|
SHARED_SECRET="$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text || echo 'none')"
|
|
if [[ "$SHARED_SECRET" == "none" ]]; then
|
|
echo "Error: Shared secret not found"
|
|
exit 1
|
|
fi
|
|
|
|
SECRETS_WAIT_ATTEMPTS=0
|
|
SECRETS_WAIT_MAX=360
|
|
while true; do
|
|
# Validate content, not just the flag: stale eventually-consistent reads can return pre-generation values
|
|
if echo "$SHARED_SECRET" | jq -e '(.ALL_SECRETS_GENERATED == "true") and (.OPENVIDU_VERSION != "none") and (.REDIS_PASSWORD != "none")' > /dev/null; then
|
|
break
|
|
fi
|
|
SECRETS_WAIT_ATTEMPTS=$((SECRETS_WAIT_ATTEMPTS + 1))
|
|
if [[ $SECRETS_WAIT_ATTEMPTS -ge $SECRETS_WAIT_MAX ]]; then
|
|
echo "Error: timed out after 30 minutes waiting for shared secrets to be generated"
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
SHARED_SECRET="$(aws secretsmanager get-secret-value \
|
|
--region ${AWS::Region} \
|
|
--secret-id openvidu-ha-${AWS::Region}-${AWS::StackName} \
|
|
--query SecretString --output text || echo 'none')"
|
|
done
|
|
|
|
# Get OpenVidu Media Nodes version to deploy
|
|
OPENVIDU_VERSION=$(echo "$SHARED_SECRET" | jq -r '.OPENVIDU_VERSION')
|
|
if [[ "$OPENVIDU_VERSION" == "none" ]]; then
|
|
echo "OpenVidu version not found"
|
|
exit 1
|
|
fi
|
|
|
|
IP_WAIT_ATTEMPTS=0
|
|
IP_WAIT_MAX=360
|
|
while true; do
|
|
MASTER_NODE_1_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-1-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_NODE_2_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-2-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_NODE_3_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-3-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_NODE_4_PRIVATE_IP=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-4-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
|
|
if [[ "$MASTER_NODE_1_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_1_PRIVATE_IP" ]] &&
|
|
[[ "$MASTER_NODE_2_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_2_PRIVATE_IP" ]] &&
|
|
[[ "$MASTER_NODE_3_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_3_PRIVATE_IP" ]] &&
|
|
[[ "$MASTER_NODE_4_PRIVATE_IP" != "none" ]] && [[ -n "$MASTER_NODE_4_PRIVATE_IP" ]]; then
|
|
break
|
|
fi
|
|
|
|
IP_WAIT_ATTEMPTS=$((IP_WAIT_ATTEMPTS + 1))
|
|
if [[ $IP_WAIT_ATTEMPTS -ge $IP_WAIT_MAX ]]; then
|
|
echo "Error: timed out after 30 minutes waiting for all master nodes to publish their private IPs to SSM"
|
|
exit 1
|
|
fi
|
|
sleep 5
|
|
done
|
|
MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP"
|
|
REDIS_PASSWORD=$(echo "$SHARED_SECRET" | jq -r '.REDIS_PASSWORD')
|
|
|
|
# Download first: sh <(curl ...) would silently run an empty script on a transient curl failure
|
|
INSTALLER_SCRIPT="/tmp/install_ov_media_node.sh"
|
|
curl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o "$INSTALLER_SCRIPT" "http://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_media_node.sh"
|
|
if [ ! -s "$INSTALLER_SCRIPT" ]; then
|
|
echo "Downloaded OpenVidu media node installer is empty or missing" >&2
|
|
exit 1
|
|
fi
|
|
INSTALL_COMMAND="sh $INSTALLER_SCRIPT"
|
|
|
|
# Common arguments
|
|
COMMON_ARGS=(
|
|
"--no-tty"
|
|
"--install"
|
|
"--environment=aws"
|
|
"--deployment-type='ha'"
|
|
"--node-role='media-node'"
|
|
"--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST"
|
|
"--private-ip=$PRIVATE_IP"
|
|
"--redis-password=$REDIS_PASSWORD"
|
|
)
|
|
|
|
# Construct the final command with all arguments
|
|
FINAL_COMMAND="$INSTALL_COMMAND $(printf "%s " "${!COMMON_ARGS[@]}")"
|
|
|
|
# Install OpenVidu
|
|
exec bash -c "$FINAL_COMMAND"
|
|
mode: '000755'
|
|
owner: root
|
|
group: root
|
|
'/usr/local/bin/set_as_unhealthy.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
# Token for IMDSv2
|
|
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
|
|
|
# Get own instance ID
|
|
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
|
|
|
|
# Set instance as unhealthy
|
|
aws autoscaling set-instance-health \
|
|
--region ${AWS::Region} \
|
|
--instance-id "$INSTANCE_ID" \
|
|
--health-status Unhealthy
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
'/usr/local/bin/stop_media_node.sh':
|
|
content: !Sub |
|
|
#!/bin/bash
|
|
set -e
|
|
# Token for IMDSv2
|
|
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
|
|
|
|
# Get own instance ID
|
|
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
|
|
ASG_NAME=openvidu-ha-media-asg-${AWS::Region}-${AWS::StackName}
|
|
|
|
# Execute if docker is installed
|
|
if [ -x "$(command -v docker)" ]; then
|
|
echo "Stopping media node services and waiting for termination..."
|
|
docker container kill --signal=SIGQUIT openvidu 2>/dev/null || true
|
|
docker container kill --signal=SIGQUIT ingress 2>/dev/null || true
|
|
docker container kill --signal=SIGQUIT egress 2>/dev/null || true
|
|
for agent_container in $(docker ps --filter "label=openvidu-agent=true" --format '{{.Names}}' 2>/dev/null); do
|
|
docker container kill --signal=SIGQUIT "$agent_container" 2>/dev/null || true
|
|
done
|
|
TIME_PASSED=0
|
|
HEARTBEAT_MAX=1800
|
|
# Wait for running containers to not be openvidu, ingress, egress or an openvidu agent
|
|
while [ "$(docker ps --filter 'label=openvidu-agent=true' -q 2>/dev/null | wc -l)" -gt 0 ] || \
|
|
[ "$(docker inspect -f '{{.State.Running}}' openvidu 2>/dev/null)" = "true" ] || \
|
|
[ "$(docker inspect -f '{{.State.Running}}' ingress 2>/dev/null)" = "true" ] || \
|
|
[ "$(docker inspect -f '{{.State.Running}}' egress 2>/dev/null)" = "true" ]; do
|
|
echo "Waiting for containers to stop..."
|
|
sleep 5
|
|
TIME_PASSED=$((TIME_PASSED+5))
|
|
if [ $TIME_PASSED -ge $HEARTBEAT_MAX ]; then
|
|
echo "Increase lifecycle hook timeout to continue waiting for termination"
|
|
# Increase lifecycle hook timeout
|
|
aws autoscaling record-lifecycle-action-heartbeat \
|
|
--region ${AWS::Region} \
|
|
--lifecycle-hook-name StopMediaNodeLifecycleHook-${AWS::Region}-${AWS::StackName} \
|
|
--auto-scaling-group-name "$ASG_NAME" \
|
|
--instance-id "$INSTANCE_ID"
|
|
TIME_PASSED=0
|
|
fi
|
|
done
|
|
fi
|
|
|
|
aws autoscaling complete-lifecycle-action \
|
|
--region ${AWS::Region} \
|
|
--lifecycle-hook-name StopMediaNodeLifecycleHook-${AWS::Region}-${AWS::StackName} \
|
|
--auto-scaling-group-name "$ASG_NAME" \
|
|
--lifecycle-action-result CONTINUE \
|
|
--instance-id "$INSTANCE_ID"
|
|
mode: "000755"
|
|
owner: "root"
|
|
group: "root"
|
|
Properties:
|
|
LaunchTemplateName: !Sub 'openvidu-ha-media-${AWS::Region}-${AWS::StackName}'
|
|
LaunchTemplateData:
|
|
# Enable IMDSv2 by default
|
|
MetadataOptions:
|
|
HttpEndpoint: enabled
|
|
HttpPutResponseHopLimit: 1
|
|
HttpTokens: required
|
|
IamInstanceProfile:
|
|
Arn: !GetAtt OpenViduMediaInstanceProfile.Arn
|
|
SecurityGroupIds:
|
|
- !GetAtt OpenViduMediaNodeSG.GroupId
|
|
ImageId: !If
|
|
- IsMediaGraviton
|
|
- !If
|
|
- IsMediaNodeNvidia
|
|
- '{{resolve:ssm:/aws/service/deeplearning/ami/arm64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
|
|
- !FindInMap [ArmImage, !Ref OperatingSystem, ImageId]
|
|
- !If
|
|
- IsMediaNodeNvidia
|
|
- '{{resolve:ssm:/aws/service/deeplearning/ami/x86_64/base-oss-nvidia-driver-gpu-ubuntu-24.04/latest/ami-id}}'
|
|
- !FindInMap [AmdImage, !Ref OperatingSystem, ImageId]
|
|
KeyName: !Ref KeyName
|
|
InstanceType: !Ref MediaNodeInstanceType
|
|
UserData:
|
|
Fn::Base64: !Sub |
|
|
#!/bin/bash
|
|
set -eu -o pipefail
|
|
|
|
echo "DPkg::Lock::Timeout \"-1\";" > /etc/apt/apt.conf.d/99timeout
|
|
|
|
apt-get update && apt-get install -y \
|
|
python3-pip \
|
|
ec2-instance-connect
|
|
|
|
CFN_BOOTSTRAP_VERSION=2.0-39
|
|
# Detect Ubuntu version and install cfn-bootstrap accordingly
|
|
UBUNTU_VERSION=$(lsb_release -rs | cut -d. -f1)
|
|
if [ "$UBUNTU_VERSION" -ge 24 ]; then
|
|
python3 -m pip install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
else
|
|
python3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-${!CFN_BOOTSTRAP_VERSION}.tar.gz
|
|
fi
|
|
|
|
cfn-init --region ${AWS::Region} --stack ${AWS::StackName} --resource OpenViduMediaNodeLaunchTemplate
|
|
|
|
export HOME="/root"
|
|
|
|
# Install OpenVidu
|
|
/usr/local/bin/install.sh || { echo "[OpenVidu] error installing OpenVidu"; /usr/local/bin/set_as_unhealthy.sh; exit 1; }
|
|
|
|
MASTER_IP_1=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-1-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_IP_2=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-2-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_IP_3=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-3-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_IP_4=$(aws ssm get-parameter --region ${AWS::Region} --name "/openvidu/${AWS::StackName}/master-node-4-private-ip" --query Parameter.Value --output text 2>/dev/null || echo 'none')
|
|
MASTER_HEALTHY=false
|
|
for i in $(seq 1 360); do
|
|
for MASTER_IP in "$MASTER_IP_1" "$MASTER_IP_2" "$MASTER_IP_3" "$MASTER_IP_4"; do
|
|
if [ "$MASTER_IP" != "none" ] && [ -n "$MASTER_IP" ] && curl -sf "http://$MASTER_IP:7880/health/caddy" >/dev/null 2>&1; then
|
|
MASTER_HEALTHY=true
|
|
break
|
|
fi
|
|
done
|
|
if [ "$MASTER_HEALTHY" = "true" ]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
done
|
|
if [ "$MASTER_HEALTHY" != "true" ]; then
|
|
echo "[OpenVidu] no master node became healthy after 30 minutes"
|
|
/usr/local/bin/set_as_unhealthy.sh
|
|
exit 1
|
|
fi
|
|
|
|
# Start OpenVidu
|
|
systemctl start openvidu || { echo "[OpenVidu] error starting OpenVidu"; /usr/local/bin/set_as_unhealthy.sh; exit 1; }
|
|
|
|
# Wait for the app
|
|
# /usr/local/bin/check_app_ready.sh
|
|
BlockDeviceMappings:
|
|
- DeviceName: /dev/sda1
|
|
Ebs:
|
|
VolumeType: gp3
|
|
DeleteOnTermination: true
|
|
VolumeSize: !If [IsMediaNodeNvidia, 100, 50]
|
|
|
|
OpenViduMediaNodeASG:
|
|
DependsOn:
|
|
- OpenViduMediaInstanceProfile
|
|
- OpenViduMasterInstanceProfile
|
|
- StopMediaNodeCloudWatchEventRule
|
|
Type: AWS::AutoScaling::AutoScalingGroup
|
|
Properties:
|
|
AutoScalingGroupName: !Sub openvidu-ha-media-asg-${AWS::Region}-${AWS::StackName}
|
|
LaunchTemplate:
|
|
LaunchTemplateId: !Ref OpenViduMediaNodeLaunchTemplate
|
|
Version: !GetAtt OpenViduMediaNodeLaunchTemplate.DefaultVersionNumber
|
|
TargetGroupARNs:
|
|
- !Ref OpenViduMediaNodeRTMPTG
|
|
MinSize: !Ref MinNumberOfMediaNodes
|
|
MaxSize: !Ref MaxNumberOfMediaNodes
|
|
DesiredCapacity: !Ref InitialNumberOfMediaNodes
|
|
VPCZoneIdentifier: !Ref OpenViduMediaNodeSubnets
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Media Node
|
|
PropagateAtLaunch: true
|
|
|
|
StopMediaNodeLifecycleHook:
|
|
Type: 'AWS::AutoScaling::LifecycleHook'
|
|
Properties:
|
|
LifecycleHookName: !Sub StopMediaNodeLifecycleHook-${AWS::Region}-${AWS::StackName}
|
|
AutoScalingGroupName: !Ref OpenViduMediaNodeASG
|
|
LifecycleTransition: 'autoscaling:EC2_INSTANCE_TERMINATING'
|
|
DefaultResult: 'CONTINUE'
|
|
HeartbeatTimeout: 3600
|
|
|
|
StopMediaNodeDocumentRole:
|
|
Type: AWS::IAM::Role
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- ssm.amazonaws.com
|
|
Action:
|
|
- sts:AssumeRole
|
|
Policies:
|
|
- PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- ssm:DescribeInstanceInformation
|
|
- ssm:ListCommands
|
|
- ssm:ListCommandInvocations
|
|
Resource: "*"
|
|
- Effect: Allow
|
|
Action:
|
|
- ssm:SendCommand
|
|
Resource: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}::document/AWS-RunShellScript
|
|
- Action:
|
|
- ssm:SendCommand
|
|
Resource: !Sub arn:${AWS::Partition}:ec2:*:*:instance/*
|
|
Condition:
|
|
StringEquals:
|
|
'aws:ResourceTag/aws:cloudformation:stack-name': !Ref 'AWS::StackName'
|
|
Effect: Allow
|
|
PolicyName: SSM-Automation-Policy
|
|
|
|
StopMediaNodeAutomationDocument:
|
|
Type: AWS::SSM::Document
|
|
Properties:
|
|
Name:
|
|
Fn::Join:
|
|
# Generate a not too long and unique document name
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - 'StopMediaNodeAutomationDocument-'
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
DocumentType: Automation
|
|
Content:
|
|
schemaVersion: '0.3'
|
|
assumeRole: "{{automationAssumeRole}}"
|
|
description: This document stops the OpenVidu services in a Media Node and
|
|
terminates the instance. It stop the OpenVidu services without interrupting
|
|
the running sessions, ingress and egress running in the Media Node.
|
|
Also it sends a CONTINUE signal to the Auto Scaling Group to continue the
|
|
instance termination when the services are stopped.
|
|
parameters:
|
|
InstanceId:
|
|
type: String
|
|
automationAssumeRole:
|
|
type: String
|
|
default: !GetAtt StopMediaNodeDocumentRole.Arn
|
|
description: "(Required) The ARN of the role that allows Automation to
|
|
perform the actions."
|
|
mainSteps:
|
|
- name: RunCommand
|
|
action: aws:runCommand
|
|
inputs:
|
|
DocumentName: AWS-RunShellScript
|
|
InstanceIds:
|
|
- "{{ InstanceId }}"
|
|
Parameters:
|
|
# 24 hours as a timeout to wait for the instance to stop all services
|
|
executionTimeout: "60"
|
|
commands:
|
|
- nohup /usr/local/bin/stop_media_node.sh > /var/log/stop_media_node.log 2>&1 &
|
|
|
|
|
|
StopMediaNodeCloudWatchEventRole:
|
|
Type: AWS::IAM::Role
|
|
Properties:
|
|
AssumeRolePolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Principal:
|
|
Service:
|
|
- events.amazonaws.com
|
|
Action:
|
|
- sts:AssumeRole
|
|
Policies:
|
|
- PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- ssm:StartAutomationExecution
|
|
Resource:
|
|
- !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-execution/*
|
|
- !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:document/${StopMediaNodeAutomationDocument}
|
|
PolicyName: !Sub StopMediaNodeCloudWatchEventPolicy-${AWS::Region}-${AWS::StackName}
|
|
- PolicyDocument:
|
|
Version: '2012-10-17'
|
|
Statement:
|
|
- Effect: Allow
|
|
Action:
|
|
- iam:PassRole
|
|
Resource: !GetAtt StopMediaNodeDocumentRole.Arn
|
|
PolicyName: Pass-Role-SSM-Automation-Policy
|
|
|
|
StopMediaNodeCloudWatchEventRule:
|
|
Type: AWS::Events::Rule
|
|
Properties:
|
|
Description: Rule to trigger the StopMediaNodeAutomationDocument when an instance is terminated
|
|
EventPattern:
|
|
source:
|
|
- aws.autoscaling
|
|
detail-type:
|
|
- EC2 Instance-terminate Lifecycle Action
|
|
detail:
|
|
AutoScalingGroupName:
|
|
- !Sub openvidu-ha-media-asg-${AWS::Region}-${AWS::StackName}
|
|
Name:
|
|
Fn::Join:
|
|
# Generate a not too long and unique rule name
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - StopMediaNodeCloudWatchEventRule-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
Targets:
|
|
- Arn: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${StopMediaNodeAutomationDocument}:$DEFAULT
|
|
RoleArn: !GetAtt StopMediaNodeCloudWatchEventRole.Arn
|
|
Id:
|
|
Fn::Join:
|
|
# Generate a not too long and unique target id
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - StopMediaNodeCloudWatchEventRule-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
InputTransformer:
|
|
InputPathsMap:
|
|
instanceid: "$.detail.EC2InstanceId"
|
|
InputTemplate: |
|
|
{
|
|
"InstanceId": [ <instanceid> ]
|
|
}
|
|
|
|
OpenViduMediaNodeASGScalingPolicy:
|
|
Type: AWS::AutoScaling::ScalingPolicy
|
|
Properties:
|
|
AutoScalingGroupName: !Ref OpenViduMediaNodeASG
|
|
PolicyType: TargetTrackingScaling
|
|
EstimatedInstanceWarmup: 120
|
|
TargetTrackingConfiguration:
|
|
PredefinedMetricSpecification:
|
|
PredefinedMetricType: ASGAverageCPUUtilization
|
|
TargetValue: !Ref ScaleTargetCPU
|
|
|
|
OpenViduMasterNodeSG:
|
|
Type: AWS::EC2::SecurityGroup
|
|
Properties:
|
|
GroupDescription: Security group for OpenVidu Master Node
|
|
GroupName: !Sub openvidu-ha-master-sg-${AWS::Region}-${AWS::StackName}
|
|
VpcId: !Ref OpenViduVPC
|
|
SecurityGroupIngress:
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 22
|
|
ToPort: 22
|
|
CidrIpv6: ::/0
|
|
|
|
OpenViduLoadBalancerToMasterHTTPIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 80
|
|
ToPort: 80
|
|
SourceSecurityGroupId: !Ref OpenViduLoadBalancerSG
|
|
|
|
OpenViduLoadBalancerToMasterIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7880
|
|
ToPort: 7880
|
|
SourceSecurityGroupId: !Ref OpenViduLoadBalancerSG
|
|
|
|
OpenViduMasterToMasterRedisIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7000
|
|
ToPort: 7001
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterNodeClusterPortIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7880
|
|
ToPort: 7880
|
|
SourceSecurityGroupId: !Ref OpenViduMediaNodeSG
|
|
|
|
OpenViduMediaNodeToMasterRedisIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7000
|
|
ToPort: 7001
|
|
SourceSecurityGroupId: !Ref OpenViduMediaNodeSG
|
|
|
|
OpenViduMasterToMasterMinioIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9100
|
|
ToPort: 9100
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMasterMinioConsoleSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9101
|
|
ToPort: 9101
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterMinioIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9100
|
|
ToPort: 9100
|
|
SourceSecurityGroupId: !Ref OpenViduMediaNodeSG
|
|
|
|
OpenViduMasterToMasterMongoIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 20000
|
|
ToPort: 20000
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterMongoIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 20000
|
|
ToPort: 20000
|
|
SourceSecurityGroupId: !Ref OpenViduMediaNodeSG
|
|
|
|
OpenViduMasterToMasterMimirGrpcIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9095
|
|
ToPort: 9095
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMasterMimirGossipIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7946
|
|
ToPort: 7946
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterHTTPMimirSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9009
|
|
ToPort: 9009
|
|
SourceSecurityGroupId: !Ref OpenViduMediaNodeSG
|
|
|
|
OpenViduMasterToMasterLokiGrpcIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9096
|
|
ToPort: 9096
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMasterLokiGossipIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7947
|
|
ToPort: 7947
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMasterDashboardsIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 5000
|
|
ToPort: 5000
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMasterGrafanaIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 3000
|
|
ToPort: 3000
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterHTTPLokiSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 3100
|
|
ToPort: 3100
|
|
SourceSecurityGroupId: !Ref OpenViduMediaNodeSG
|
|
|
|
OpenViduMasterToMasterV2CompatibilityIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 4443
|
|
ToPort: 4443
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterV2CompatibilityWebhookIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !GetAtt OpenViduMasterNodeSG.GroupId
|
|
IpProtocol: tcp
|
|
FromPort: 4443
|
|
ToPort: 4443
|
|
SourceSecurityGroupId: !GetAtt OpenViduMediaNodeSG.GroupId
|
|
|
|
OpenViduMasterToMasterMeetIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9080
|
|
ToPort: 9080
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMasterCustomAppIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 6080
|
|
ToPort: 6080
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMediaNodeToMasterMeetWebhookIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !GetAtt OpenViduMasterNodeSG.GroupId
|
|
IpProtocol: tcp
|
|
FromPort: 9080
|
|
ToPort: 9080
|
|
SourceSecurityGroupId: !GetAtt OpenViduMediaNodeSG.GroupId
|
|
|
|
OpenViduMediaNodeToMasterCustomAppIngress:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !GetAtt OpenViduMasterNodeSG.GroupId
|
|
IpProtocol: tcp
|
|
FromPort: 6080
|
|
ToPort: 6080
|
|
SourceSecurityGroupId: !GetAtt OpenViduMediaNodeSG.GroupId
|
|
|
|
OpenViduMediaNodeSG:
|
|
Type: AWS::EC2::SecurityGroup
|
|
Properties:
|
|
GroupDescription: Security group for OpenVidu Media Node
|
|
GroupName: !Sub openvidu-ha-media-sg-${AWS::Region}-${AWS::StackName}
|
|
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: udp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 7881
|
|
ToPort: 7881
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 7881
|
|
ToPort: 7881
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 7885
|
|
ToPort: 7885
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 7885
|
|
ToPort: 7885
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: udp
|
|
FromPort: 50000
|
|
ToPort: 60000
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: udp
|
|
FromPort: 50000
|
|
ToPort: 60000
|
|
CidrIpv6: ::/0
|
|
- IpProtocol: tcp
|
|
FromPort: 50000
|
|
ToPort: 60000
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 50000
|
|
ToPort: 60000
|
|
CidrIpv6: ::/0
|
|
|
|
OpenViduLoadBalancerToMediaNodeRTMPIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMediaNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 1945
|
|
ToPort: 1945
|
|
SourceSecurityGroupId: !Ref OpenViduLoadBalancerSG
|
|
|
|
OpenViduLoadBalancerToMediaNodeIngressHealthCheckSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMediaNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 9092
|
|
ToPort: 9092
|
|
SourceSecurityGroupId: !Ref OpenViduLoadBalancerSG
|
|
|
|
OpenViduMasterToMediaNodeServerIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMediaNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 7880
|
|
ToPort: 7880
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduMasterToMediaNodeClientIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMediaNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 8080
|
|
ToPort: 8080
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduTurnTLSMasterNodeToMediaNodeIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMediaNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 5349
|
|
ToPort: 5349
|
|
SourceSecurityGroupId: !Ref OpenViduMasterNodeSG
|
|
|
|
OpenViduTurnTLSLoadBalancerToMediaNodeIngressSG:
|
|
Type: AWS::EC2::SecurityGroupIngress
|
|
Properties:
|
|
GroupId: !Ref OpenViduMasterNodeSG
|
|
IpProtocol: tcp
|
|
FromPort: 443
|
|
ToPort: 443
|
|
SourceSecurityGroupId: !Ref OpenViduLoadBalancerSG
|
|
|
|
OpenViduLoadBalancerSG:
|
|
Type: AWS::EC2::SecurityGroup
|
|
Properties:
|
|
GroupDescription: Security group for the Load Balancer
|
|
GroupName: !Sub openvidu-ha-lb-sg-${AWS::Region}-${AWS::StackName}
|
|
VpcId: !Ref OpenViduVPC
|
|
SecurityGroupIngress:
|
|
- 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: 1935
|
|
ToPort: 1935
|
|
CidrIp: 0.0.0.0/0
|
|
- IpProtocol: tcp
|
|
FromPort: 1935
|
|
ToPort: 1935
|
|
CidrIpv6: ::/0
|
|
|
|
LoadBalancer:
|
|
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
|
|
Properties:
|
|
Name:
|
|
Fn::Join:
|
|
# Generate a not too long and unique load balancer name
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - OpenViduHA-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
Subnets: !If [HasLoadBalancerSubnets, !Ref LoadBalancerSubnets, !Ref OpenViduMasterNodeSubnets]
|
|
SecurityGroups:
|
|
- !Ref OpenViduLoadBalancerSG
|
|
Type: network
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Load Balancer
|
|
|
|
OpenViduMasterNodeWithTurnTLSHTTPListener:
|
|
Type: 'AWS::ElasticLoadBalancingV2::Listener'
|
|
Properties:
|
|
DefaultActions:
|
|
- Type: forward
|
|
TargetGroupArn: !Ref OpenViduMasterNodeHTTPTG
|
|
LoadBalancerArn: !Ref LoadBalancer
|
|
Port: 80
|
|
Protocol: TCP
|
|
|
|
OpenViduMasterNodeWithTurnTLSListener:
|
|
Type: 'AWS::ElasticLoadBalancingV2::Listener'
|
|
Properties:
|
|
DefaultActions:
|
|
- Type: forward
|
|
TargetGroupArn: !Ref OpenViduMasterNodeWithTurnTLSTG
|
|
LoadBalancerArn: !Ref LoadBalancer
|
|
Port: 443
|
|
Protocol: TLS
|
|
Certificates:
|
|
- CertificateArn: !Ref OpenViduCertificateARN
|
|
|
|
OpenViduRTMPMediaNodeListener:
|
|
Type: 'AWS::ElasticLoadBalancingV2::Listener'
|
|
Properties:
|
|
DefaultActions:
|
|
- Type: forward
|
|
TargetGroupArn: !Ref OpenViduMediaNodeRTMPTG
|
|
LoadBalancerArn: !Ref LoadBalancer
|
|
Port: 1935
|
|
Protocol: TLS
|
|
Certificates:
|
|
- CertificateArn: !Ref OpenViduCertificateARN
|
|
|
|
OpenViduMasterNodeHTTPTG:
|
|
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
|
Properties:
|
|
Name:
|
|
Fn::Join:
|
|
# Generate a not too long and unique target id
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - OVHTTP-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
TargetType: instance
|
|
Targets:
|
|
- Id: !Ref OpenViduMasterNode1
|
|
- Id: !Ref OpenViduMasterNode2
|
|
- Id: !Ref OpenViduMasterNode3
|
|
- Id: !Ref OpenViduMasterNode4
|
|
VpcId: !Ref OpenViduVPC
|
|
Port: 80
|
|
Protocol: TCP
|
|
Matcher:
|
|
HttpCode: '200'
|
|
HealthCheckIntervalSeconds: 10
|
|
HealthCheckPath: /health/caddy
|
|
HealthCheckProtocol: HTTP
|
|
HealthCheckPort: '7880'
|
|
HealthCheckTimeoutSeconds: 5
|
|
HealthyThresholdCount: 3
|
|
UnhealthyThresholdCount: 4
|
|
TargetGroupAttributes:
|
|
- Key: deregistration_delay.timeout_seconds
|
|
Value: 60
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - Master HTTP Target Group
|
|
|
|
OpenViduMasterNodeWithTurnTLSTG:
|
|
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
|
Properties:
|
|
Name:
|
|
Fn::Join:
|
|
# Generate a not too long and unique target id
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - OVTurnTLSMaster-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
TargetType: instance
|
|
Targets:
|
|
- Id: !Ref OpenViduMasterNode1
|
|
- Id: !Ref OpenViduMasterNode2
|
|
- Id: !Ref OpenViduMasterNode3
|
|
- Id: !Ref OpenViduMasterNode4
|
|
VpcId: !Ref OpenViduVPC
|
|
Port: 443
|
|
Protocol: TCP
|
|
Matcher:
|
|
HttpCode: '200'
|
|
HealthCheckIntervalSeconds: 10
|
|
HealthCheckPath: /health/caddy
|
|
HealthCheckProtocol: HTTP
|
|
HealthCheckPort: '7880'
|
|
HealthCheckTimeoutSeconds: 5
|
|
HealthyThresholdCount: 3
|
|
UnhealthyThresholdCount: 4
|
|
TargetGroupAttributes:
|
|
- Key: deregistration_delay.timeout_seconds
|
|
Value: 60
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - TURN TLS Master Target Group
|
|
|
|
OpenViduMediaNodeRTMPTG:
|
|
Type: AWS::ElasticLoadBalancingV2::TargetGroup
|
|
Properties:
|
|
Name:
|
|
Fn::Join:
|
|
# Generate a not too long and unique target id
|
|
# Getting a unique identifier from the stack id
|
|
- ''
|
|
- - OVRTMP-
|
|
- !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]
|
|
VpcId: !Ref OpenViduVPC
|
|
Port: 1945
|
|
Protocol: TCP
|
|
Matcher:
|
|
HttpCode: '200'
|
|
HealthCheckIntervalSeconds: 10
|
|
HealthCheckPath: /
|
|
HealthCheckProtocol: HTTP
|
|
# Ingress health check port
|
|
HealthCheckPort: '9092'
|
|
HealthCheckTimeoutSeconds: 5
|
|
HealthyThresholdCount: 3
|
|
UnhealthyThresholdCount: 4
|
|
TargetGroupAttributes:
|
|
- Key: deregistration_delay.timeout_seconds
|
|
Value: 60
|
|
Tags:
|
|
- Key: Name
|
|
Value: !Sub ${AWS::StackName} - OpenVidu HA - RTMP Target Group
|
|
|
|
Outputs:
|
|
ServicesAndCredentials:
|
|
Description: Services and credentials
|
|
Value: !Sub https://${AWS::Region}.console.aws.amazon.com/secretsmanager/home?region=${AWS::Region}#!/secret?name=openvidu-ha-${AWS::Region}-${AWS::StackName}
|