---
AWSTemplateFormatVersion: 2010-09-09
Description: Openvidu Pro CloudFormation template

Parameters:

  # Domain and SSL certificate configuration

  WhichCert:
    Description: >
      [selfsigned] Self signed certificate. Not recommended for production use.
      [owncert] Valid certificate purchased in a Internet services company.
      [letsencrypt] Generate a new certificate using Let's Encrypt.
    Type: String
    AllowedValues:
      - selfsigned
      - owncert
      - letsencrypt
    Default: selfsigned

  PublicElasticIP:
    Description: "Previously created AWS Elastic IP to associate it to the OpenVidu EC2 instance. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example 13.33.145.23."
    Type: String
    AllowedPattern: ^$|^([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])\.([01]?\d{1,2}|2[0-4]\d|25[0-5])$
    ConstraintDescription: The public Elastic IP does not have a valid IPv4 format

  MyDomainName:
    Description: "Valid domain name pointing to previous IP. If certificate type is 'selfsigned' this value is optional. If certificate type is 'owncert' or 'letsencrypt' this value is mandatory. Example: openvidu.company.com"
    Type: String
    AllowedPattern: ^$|^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$
    ConstraintDescription: The domain name does not have a valid domain name format

  OwnCertCRT:
    Description: "If certificate type is 'owncert' this is the URL where CRT file will be downloaded"
    Type: String

  OwnCertKEY:
    Description: "If certificate type is 'owncert' this is the URL where KEY file will be downloaded"
    Type: String

  LetsEncryptEmail:
    Description: "If certificate type is 'letsencrypt', this email will be used for Let's Encrypt notifications"
    Type: String
  
  Recording:
    Description: |
      If 'disabled', recordings will not be active.
      If 'local' recordings will be saved in EC2 instance locally. 
      If 's3', recordings will be stored in a S3 bucket"
    Type: String
    AllowedValues:
      - disabled
      - local
      - s3
    Default: local

  S3RecordingsBucketName:
    Description: "S3 Bucket Name"
    Type: String

  # OpenVidu Configuration

  OpenViduLicense:
    Description: "Visit https://openvidu.io/account"
    Type: String
    AllowedPattern: ^(?!\s*$).+$
    NoEcho: true
    ConstraintDescription: OpenVidu Pro License is mandatory

  OpenViduSecret:
    Description: "Secret to connect to this OpenVidu Platform. Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')"
    Type: String
    AllowedPattern: ^[a-zA-Z0-9_-]+$
    NoEcho: true
    ConstraintDescription: "Cannot be empty and must contain only alphanumeric characters [a-zA-Z0-9], hypens ('-') and underscores ('_')"

  MediaNodesStartNumber:
    Description: "How many Media Nodes do you want on startup (EC2 instances will be launched)"
    Type: Number
    Default: 1

  # Elasticsearch configuration
  ElasticsearchUser:
    Description: "Username for Elasticsearch and Kibana"
    Type: String
    AllowedPattern: ^((?!")(?! ).)+$
    ConstraintDescription: Elasticsearch user is mandatory (no whitespaces or quotations allowed)
    Default: elasticadmin

  ElasticsearchPassword:
    Description: "Password for Elasticsearch and Kibana"
    Type: String
    AllowedPattern: ^((?!")(?! ).)+$
    NoEcho: true
    ConstraintDescription: Elasticsearch password is mandatory (no whitespaces or quotations allowed)

  # Elasticsearch configuration
  ElasticsearchUrl:
    Description: "If you have an external Elasticsearch service running, put here the url to the service. If empty, an Elasticsearch service will be deployed next to OpenVidu."
    Type: String
    AllowedPattern: (^(http|https):\/\/.*:[1-9]{1,5}+.*$|^$)
    ConstraintDescription: "It is very important to specify the Elasticsearch URL with the port used by this service. For example: https://es-example:443"

  KibanaUrl:
    Description: "If you have an external Kibana service running, put here the url to the service. If empty, a Kibana service will be deployed next to OpenVidu."
    Type: String
    AllowedPattern: (^(http|https):\/\/.*:[1-9]{1,5}+.*$|^$)
    ConstraintDescription: "It is very important to specify the url with port used by this service. For example: https://kibana-example:443"

  # EC2 Instance configuration

  AwsInstanceTypeOV:
    Description: "Specifies the EC2 instance type for your OpenVidu Server Pro Node"
    Type: String
    Default: c5.xlarge
    AllowedValues:
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.8xlarge
      - m5.12xlarge
      - m5.16xlarge
      - m5.24xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
      - c5.12xlarge
      - c5.18xlarge
      - c5.24xlarge
    ConstraintDescription: "Must be a valid EC2 instance type"

  AwsInstanceTypeKMS:
    Description: "Specifies the EC2 instance type for your Media Nodes"
    Type: String
    Default: c5.xlarge
    AllowedValues:
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - t3.large
      - t3.xlarge
      - t3.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.8xlarge
      - m5.12xlarge
      - m5.16xlarge
      - m5.24xlarge
      - c4.large
      - c4.xlarge
      - c4.2xlarge
      - c4.4xlarge
      - c4.8xlarge
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5.9xlarge
      - c5.12xlarge
      - c5.18xlarge
      - c5.24xlarge
    ConstraintDescription: "Must be a valid EC2 instance type"

  KeyName:
    Description: "Name of an existing EC2 KeyPair to enable SSH access to the instance. It is mandatory to perform some administrative tasks of OpenVidu."
    Type: 'AWS::EC2::KeyPair::KeyName'
    ConstraintDescription: "must be the name of an existing EC2 KeyPair"

  # Networking configuration

  OpenViduVPC:
    Description: "Dedicated VPC for OpenVidu cluster"
    Type: AWS::EC2::VPC::Id

  OpenViduSubnet:
    Description: "Subnet for OpenVidu cluster"
    Type: AWS::EC2::Subnet::Id

  # Other configuration

  WantToDeployDemos:
    Description: "Choose if you want to deploy OpenVidu Call application alongside OpenVidu platform."
    Type: String
    AllowedValues:
      - true
      - false
    Default: true

#start_mappings
Mappings:
  OVAMIMAP:
    eu-west-1:
      AMI: OV_AMI_ID

  KMSAMIMAP:
    eu-west-1:
      AMI: KMS_AMI_ID
#end_mappings

Metadata:
  'AWS::CloudFormation::Interface':
    ParameterGroups:
      - Label:
          default: Domain and SSL certificate configuration
        Parameters:
          - WhichCert
          - PublicElasticIP
          - MyDomainName
          - OwnCertCRT
          - OwnCertKEY
          - LetsEncryptEmail
      - Label:
          default: OpenVidu configuration
        Parameters:
          - OpenViduLicense
          - OpenViduSecret
          - MediaNodesStartNumber
      - Label:
          default: OpenVidu Recording Configuration
        Parameters:
          - Recording
          - S3RecordingsBucketName
      - Label:
          default: Elasticsearch and Kibana configuration
        Parameters:
          - ElasticsearchUrl
          - KibanaUrl
          - ElasticsearchUser
          - ElasticsearchPassword
      - Label:
            default: EC2 Instance configuration
        Parameters:
            - AwsInstanceTypeOV
            - AwsInstanceTypeKMS
            - KeyName
      - Label:
          default: Networking configuration
        Parameters:
          - OpenViduVPC
          - OpenViduSubnet
      - Label:
          default: Other configuration
        Parameters:
          - WantToDeployDemos

    ParameterLabels:
      # SSL certificate configuration
      WhichCert:
        default: "Certificate Type"
      PublicElasticIP:
        default: "AWS Elastic IP (EIP)"
      MyDomainName:
        default: "Domain Name pointing to Elastic IP"
      OwnCertCRT:
        default: "URL to the CRT file (owncert)"
      OwnCertKEY:
        default: "URL to the key file (owncert)"
      LetsEncryptEmail:
        default: "Email for Let's Encrypt (letsencrypt)"
      Recording:
        default: "OpenVidu Recording"
      S3RecordingsBucketName:
        default: "S3 Bucket where recordings will be stored"
      # OpenVidu configuration
      OpenViduLicense:
        default: "OpenVidu Pro License key"
      MediaNodesStartNumber:
        default: "Initial number of Media Node in your cluster"
      OpenViduSecret:
        default: "Openvidu Secret"
      # Kibana configuration
      ElasticsearchUrl:
        default: "Elasticsearch URL"
      KibanaUrl:
        default: "Kibana URL"
      ElasticsearchUser:
        default: "Elasticsearch and Kibana username"
      ElasticsearchPassword:
        default: "Elasticsearch and Kibana password"
      # EC2 instance configuration
      AwsInstanceTypeOV:
        default: "Instance type for Openvidu Server Pro Node"
      AwsInstanceTypeKMS:
        default: "Instance type for Media Nodes"
      KeyName:
        default: "SSH Key"
      # Networking configuration
      OpenViduVPC:
        default: "OpenVidu VPC"
      OpenViduSubnet:
        default: "OpenVidu Subnet"
      # Other configuration
      WantToDeployDemos:
        default: "Deploy OpenVidu Call application"

Conditions:
  WhichCertPresent: !Not [ !Equals [!Ref WhichCert, ''] ]
  PublicElasticIPPresent: !Not [ !Equals [!Ref PublicElasticIP, ''] ]
  RecordingStorageIsS3: !Equals [ !Ref Recording, 's3' ]
  CreateS3Bucket: !And
    - !Equals [!Ref Recording, 's3' ]
    - !Equals [!Ref S3RecordingsBucketName, '']
        
Rules:

  RecordingValidation:
    RuleCondition: 
      Fn::Or: [ !Equals [!Ref Recording, 'disabled' ], !Equals [!Ref Recording, 'local' ] ]
    Assertions:
      - AssertDescription: If recording Storage is 'disabled' or 'local', you don't need to specify a S3 bucket.
        Assert: 
          Fn::Equals: [ !Ref S3RecordingsBucketName, "" ]

Resources:

  OpenViduManageEC2Role:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: OpenViduManageEC2Policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'ec2:DescribeInstances'
                  - 'ec2:RunInstances'
                  - 'ec2:TerminateInstances'
                  - 'ec2:CreateTags'
                  - 'ec2:DescribeSecurityGroups'
                  - 'ec2:AuthorizeSecurityGroupIngress'
                  - 'ec2:DescribeSubnets'
                  - 'iam:PassRole'
                  - 'route53:ChangeResourceRecordSets'
                  - 'route53:ListHostedZones'
                Resource: '*'
              - Fn::If:
                # Only apply this policy if S3 is configured
                - RecordingStorageIsS3
                - Effect: Allow
                  Action:
                    - 's3:DeleteObject'
                    - 's3:GetObject'
                    - 's3:PutObject'
                  Resource: 
                    - Fn::If:
                      # Get bucket name depending if the user defines a bucket name or not
                      - CreateS3Bucket
                      ### Unique bucket name using Stack ID
                      - !Join [ "", [ 'arn:aws:s3:::', 'openvidu-recordings-', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]], "/*" ]]
                      - !Join [ "", [ 'arn:aws:s3:::', !Ref S3RecordingsBucketName, '/*'] ]
                - Ref: AWS::NoValue
              - Fn::If:
                # Only apply this policy if S3 is configured
                - RecordingStorageIsS3
                - Effect: Allow
                  Action: 
                    - 's3:ListBucket'
                    - 's3:GetBucketLocation'
                  Resource: 
                    - Fn::If:
                      # Get bucket name depending if the user defines a bucket name or not
                      - CreateS3Bucket
                      ### Unique bucket name using Stack ID
                      - !Join [ "", [ 'arn:aws:s3:::', 'openvidu-recordings-', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
                      - !Join [ "", [ 'arn:aws:s3:::', !Ref S3RecordingsBucketName ] ]
                - Ref: AWS::NoValue
              - Fn::If:
                # Only apply this policy if S3 is configured
                - RecordingStorageIsS3
                - Effect: Allow
                  Action:
                    - s3:ListAllMyBuckets
                  Resource: 'arn:aws:s3:::'
                - Ref: AWS::NoValue
      RoleName: !Join [ "-", [ OpenViduManageEC2Role, !Ref 'AWS::StackName', !Ref 'AWS::Region'] ]

  OpenviduInstancesProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      InstanceProfileName: !Join [ "-", [ OpenViduInstanceProfile, !Ref 'AWS::StackName', !Ref 'AWS::Region'] ]
      Path: /
      Roles:
        - !Join [ "-", [ OpenViduManageEC2Role, !Ref 'AWS::StackName', !Ref 'AWS::Region'] ]
    DependsOn:
      - OpenViduManageEC2Role

  S3bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
    ### Unique bucket name using Stack ID
      BucketName: !Join ["-" , [ 'openvidu-recordings', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
      AccessControl: Private
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls : true
        RestrictPublicBuckets: true
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Condition: CreateS3Bucket

  OpenViduServer:
    Type: AWS::EC2::Instance
    Metadata:
      Comment: OpenVidu Pro
      AWS::CloudFormation::Init:
        config:
          files:
            '/usr/local/bin/check_app_ready.sh':
              content: |
                #!/bin/bash
                while true; do
                  HTTP_STATUS=$(curl -Ik http://localhost:5443/ | head -n1 | awk '{print $2}')
                  if [ $HTTP_STATUS == 200 ]; then
                    break
                  fi
                  sleep 5
                done
              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/feedGroupVars.sh':
              content: !Sub
              - |
                #!/bin/bash -xe

                WORKINGDIR=/opt/openvidu

                # Pro License
                sed -i "s/OPENVIDU_PRO_LICENSE=/OPENVIDU_PRO_LICENSE=${OpenViduLicense}/" $WORKINGDIR/.env

                # Replace secret
                sed -i "s/OPENVIDU_SECRET=/OPENVIDU_SECRET=${OpenViduSecret}/" $WORKINGDIR/.env

                # Replace domain name
                if [[ "${MyDomainName}" != ''  && "${PublicElasticIP}" != '' ]]; then
                  sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${MyDomainName}/" $WORKINGDIR/.env
                elif [[ "${MyDomainName}" == '' && "${PublicElasticIP}" != '' ]]; then
                  sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=${PublicElasticIP}/" $WORKINGDIR/.env
                else
                  [ ! -d "/usr/share/openvidu" ] && mkdir -p /usr/share/openvidu
                  PublicHostname=$(curl http://169.254.169.254/latest/meta-data/public-hostname)
                  sed -i "s/DOMAIN_OR_PUBLIC_IP=/DOMAIN_OR_PUBLIC_IP=$PublicHostname/" $WORKINGDIR/.env
                  echo $PublicHostname > /usr/share/openvidu/old-host-name
                fi

                # Openvidu Pro mode
                sed -i "s/OPENVIDU_PRO_CLUSTER_MODE=manual/OPENVIDU_PRO_CLUSTER_MODE=auto/" $WORKINGDIR/.env

                # Openvidu Pro Media Nodes
                sed -i "s/#OPENVIDU_PRO_CLUSTER_MEDIA_NODES=/OPENVIDU_PRO_CLUSTER_MEDIA_NODES=${MediaNodesStartNumber}/" $WORKINGDIR/.env

                # Openvidu Pro enviroment
                sed -i "s/OPENVIDU_PRO_CLUSTER_ENVIRONMENT=on_premise/OPENVIDU_PRO_CLUSTER_ENVIRONMENT=aws/" $WORKINGDIR/.env

                # Replace certificated type
                sed -i "s/CERTIFICATE_TYPE=selfsigned/CERTIFICATE_TYPE=${WhichCert}/" $WORKINGDIR/.env
                sed -i "s/LETSENCRYPT_EMAIL=user@example.com/LETSENCRYPT_EMAIL=${LetsEncryptEmail}/" $WORKINGDIR/.env

                # Replace Elastic Search Conf
                if [[ ! -z "${ElasticsearchUrl}" ]]; then
                  sed -i "s,#OPENVIDU_PRO_ELASTICSEARCH_HOST=,OPENVIDU_PRO_ELASTICSEARCH_HOST=${ElasticsearchUrl}," $WORKINGDIR/.env
                fi
                if [[ ! -z "${KibanaUrl}" ]]; then
                  sed -i "s,#OPENVIDU_PRO_KIBANA_HOST=,OPENVIDU_PRO_KIBANA_HOST=${KibanaUrl}," $WORKINGDIR/.env
                fi
                sed -i "s/ELASTICSEARCH_USERNAME=elasticadmin/ELASTICSEARCH_USERNAME=${ElasticsearchUser}/" $WORKINGDIR/.env
                sed -i "s/ELASTICSEARCH_PASSWORD=/ELASTICSEARCH_PASSWORD=${ElasticsearchPassword}/" $WORKINGDIR/.env

                # Replace vars AWS
                INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
                sed -i "s/#AWS_DEFAULT_REGION=/AWS_DEFAULT_REGION=${AWS::Region}/" $WORKINGDIR/.env
                sed -i "s/#AWS_IMAGE_ID=/AWS_IMAGE_ID=${kmsAmi}/" $WORKINGDIR/.env
                sed -i "s/#AWS_INSTANCE_TYPE=/AWS_INSTANCE_TYPE=${AwsInstanceTypeKMS}/" $WORKINGDIR/.env
                sed -i "s/#AWS_INSTANCE_ID=/AWS_INSTANCE_ID=$INSTANCE_ID/" $WORKINGDIR/.env
                sed -i "s/#AWS_KEY_NAME=/AWS_KEY_NAME=${KeyName}/" $WORKINGDIR/.env
                sed -i "s/#AWS_SUBNET_ID=/AWS_SUBNET_ID=${OpenViduSubnet}/" $WORKINGDIR/.env
                sed -i "s/#AWS_STACK_ID=/AWS_STACK_ID=$(echo ${AWS::StackId} | sed 's#/#\\/#g')/" $WORKINGDIR/.env
                sed -i "s/#AWS_STACK_NAME=/AWS_STACK_NAME=${AWS::StackName}/" $WORKINGDIR/.env
                sed -i "s/#AWS_CLI_DOCKER_TAG=/AWS_CLI_DOCKER_TAG=AWS_DOCKER_TAG/" $WORKINGDIR/.env
                sed -i "s/#AWS_VOLUME_SIZE=/AWS_VOLUME_SIZE=50/" $WORKINGDIR/.env
                sed -i "s/#OPENVIDU_PRO_AWS_REGION=/OPENVIDU_PRO_AWS_REGION=${AWS::Region}/" $WORKINGDIR/.env

                # Get security group id of kms and use it as env variable
                SECGRPIDKMS=$(/usr/local/bin/getSecurityGroupKms.sh)
                sed -i "s/#AWS_SECURITY_GROUP=/AWS_SECURITY_GROUP=$SECGRPIDKMS/" $WORKINGDIR/.env

                # Without Application
                if [ "${WantToDeployDemos}" == "false" ]; then
                  sed -i "s/WITH_APP=true/WITH_APP=false/" $WORKINGDIR/docker-compose.yml
                  rm $WORKINGDIR/docker-compose.override.yml
                fi

                # Recording Configuration
                if [ "${Recording}" != "disabled" ]; then
                  sed -i "s/OPENVIDU_RECORDING=false/OPENVIDU_RECORDING=true/" $WORKINGDIR/.env
                  sed -i "s/#OPENVIDU_PRO_RECORDING_STORAGE=/OPENVIDU_PRO_RECORDING_STORAGE=${Recording}/" $WORKINGDIR/.env
                  if [ ! -z "${S3RecordingsBucketName}" ]; then
                    sed -i "s/#OPENVIDU_PRO_AWS_S3_BUCKET=/OPENVIDU_PRO_AWS_S3_BUCKET=${S3RecordingsBucketName}/" $WORKINGDIR/.env
                  elif [ "${Recording}" == "s3" ]; then
                    sed -i "s/#OPENVIDU_PRO_AWS_S3_BUCKET=/OPENVIDU_PRO_AWS_S3_BUCKET=${s3BucketName}/" $WORKINGDIR/.env
                  fi
                fi
              - kmsAmi: !FindInMap [KMSAMIMAP, !Ref 'AWS::Region', AMI]
                ### Unique bucket name using Stack ID
                s3BucketName: !Join ["" , [ 'openvidu-recordings-', !Select [0, !Split ["-", !Select [2, !Split [/, !Ref AWS::StackId ]]]]]]
              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/buildCerts.sh':
              content: !Sub |
                #!/bin/bash -x
                WORKINGDIR=/opt/openvidu
                wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.cert ${OwnCertCRT}
                wget --no-check-certificate -O $WORKINGDIR/owncert/certificate.key ${OwnCertKEY}
              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/getSecurityGroupKms.sh':
              content: !Sub |
                #!/bin/bash -x
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 describe-security-groups \
                                --region ${AWS::Region} \
                                --output text \
                                --filters "Name=tag:aws:cloudformation:logical-id,Values=KMSSecurityGroup" \
                                          "Name=tag:aws:cloudformation:stack-id,Values=${AWS::StackId}" \
                                --query 'SecurityGroups[].GroupId[]'
              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/getSecurityGroupOpenVidu.sh':
              content: !Sub |
                #!/bin/bash -x
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 describe-security-groups \
                               --region ${AWS::Region} \
                               --output text \
                               --filters "Name=tag:aws:cloudformation:logical-id,Values=OpenViduSecurityGroup" \
                                         "Name=tag:aws:cloudformation:stack-id,Values=${AWS::StackId}" \
                               --query 'SecurityGroups[].GroupId[]'
              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/getCidrBlocKSubnet.sh':
              content: !Sub |
                #!/bin/bash -x
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 describe-subnets \
                                --region ${AWS::Region} \
                                --output text \
                                --filters "Name=subnet-id,Values=${OpenViduSubnet}" \
                                --query 'Subnets[].CidrBlock[]'
              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/create_security_group_rules.sh':
              content: |
                #!/bin/bash -x
                SECGRPIDKMS=$(/usr/local/bin/getSecurityGroupKms.sh)
                SECGRPIDOV=$(/usr/local/bin/getSecurityGroupOpenVidu.sh)
                SUBNET_CIDR=$(/usr/local/bin/getCidrBlocKSubnet.sh)

                # Create Security group rules OpenVidu
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 authorize-security-group-ingress --group-id $SECGRPIDOV --protocol tcp --port 5044 --cidr $SUBNET_CIDR
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 authorize-security-group-ingress --group-id $SECGRPIDOV --protocol tcp --port 9200 --cidr $SUBNET_CIDR

                # Create security group rules for KMS
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 authorize-security-group-ingress --group-id $SECGRPIDKMS --protocol tcp --port 8888 --cidr $SUBNET_CIDR
                docker run --rm amazon/aws-cli:AWS_DOCKER_TAG ec2 authorize-security-group-ingress --group-id $SECGRPIDKMS --protocol tcp --port 3000 --cidr $SUBNET_CIDR

              mode: "000755"
              owner: "root"
              group: "root"
            '/usr/local/bin/restartPRO.sh':
              content: |
                #!/bin/bash -x
                WORKINGDIR=/opt/openvidu

                # Get new amazon URL
                OldPublicHostname=$(cat /usr/share/openvidu/old-host-name)
                PublicHostname=$(curl http://169.254.169.254/latest/meta-data/public-hostname)
                sed -i "s/$OldPublicHostname/$PublicHostname/" $WORKINGDIR/.env
                echo $PublicHostname > /usr/share/openvidu/old-host-name

                # Restart all services
                pushd /opt/openvidu
                export FOLLOW_OPENVIDU_LOGS=false
                ./openvidu start
                popd
              mode: "000755"
              owner: "root"
              group: "root"
    Properties:
      ImageId: !FindInMap [OVAMIMAP, !Ref 'AWS::Region', AMI]
      InstanceType: !Ref AwsInstanceTypeOV
      KeyName: !Ref KeyName
      IamInstanceProfile: !Ref OpenviduInstancesProfile
      SubnetId: !Ref OpenViduSubnet
      SecurityGroupIds:
        - !GetAtt 'OpenViduSecurityGroup.GroupId'
      Tags:
        - Key: Name
          Value: 'OpenVidu Server'
        - Key: 'ov-cluster-member'
          Value: 'server'
      UserData:
        "Fn::Base64":
          !Sub |
            #!/bin/bash -xe

            cfn-init --region ${AWS::Region} --stack ${AWS::StackId} --resource OpenViduServer

            export HOME="/root"

            # Replace .env variables
            /usr/local/bin/feedGroupVars.sh || { echo "[Openvidu] Parameters incorrect/insufficient"; exit 1; }

            # Create security groups
            /usr/local/bin/create_security_group_rules.sh || { echo "[Openvidu] Error creating security groups"; exit 1; }

            # Launch on reboot
            echo "@reboot /usr/local/bin/restartPRO.sh" | crontab

            # Download certs if "WichCert" mode
            if [ "${WhichCert}" == "owncert" ]; then
              /usr/local/bin/buildCerts.sh || { echo "[Openvidu] error with the certificate files"; exit 1; }
            fi

            # Start openvidu application
            pushd /opt/openvidu
            export FOLLOW_OPENVIDU_LOGS=false
            ./openvidu start
            popd

            # Wait for the app
            /usr/local/bin/check_app_ready.sh

            # sending the finish call
            /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource WaitCondition --region ${AWS::Region}

      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp2
            DeleteOnTermination: true
            VolumeSize: 200

  KMSSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref OpenViduVPC
      GroupDescription: SSH, Proxy and KMS WebRTC Ports
      GroupName: !Join [ "-", [ !Ref 'AWS::StackName', 'KMSSecurityGroup'] ]
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 40000
          ToPort: 65535
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 40000
          ToPort: 65535
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 1
          ToPort: 65535
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 1
          ToPort: 65535
          CidrIp: 0.0.0.0/0

  OpenViduSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: SSH, Proxy and OpenVidu WebRTC Ports
      GroupName:  !Join [ "-", [ !Ref 'AWS::StackName', 'OpenViduSecurityGroup'] ]
      VpcId: !Ref OpenViduVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 3478
          ToPort: 3478
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 3478
          ToPort: 3478
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 40000
          ToPort: 65535
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 40000
          ToPort: 65535
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 1
          ToPort: 65535
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 1
          ToPort: 65535
          CidrIp: 0.0.0.0/0

  WaitCondition:
    Type: AWS::CloudFormation::WaitCondition
    CreationPolicy:
      ResourceSignal:
        Timeout: PT25M
        Count: 1

  MyEIP:
    Type: AWS::EC2::EIPAssociation
    Condition: PublicElasticIPPresent
    Properties:
      InstanceId: !Ref OpenViduServer
      EIP: !Ref PublicElasticIP

Outputs:
  OpenViduInspector:
    Description: "Use this URL to connect OpenVidu with user and password"
    Value: !Join
        - ''
        - - 'https://'
          - !GetAtt OpenViduServer.PublicDnsName
          - '/inspector'

  OpenViduInspectorLE:
    Description: "Use this URL to connect to OpenVidu with user and password if you're using Let's Encrypt"
    Value: !Join
        - ''
        - - 'https://'
          - !Ref MyDomainName
          - '/inspector'
    Condition: WhichCertPresent

  Kibana:
    Description: "Check out graph and performance of your OpenVidu installation"
    Value: !Join
        - ''
        - - 'https://'
          - !GetAtt OpenViduServer.PublicDnsName
          - '/kibana'

  KibanaLE:
    Description: "Check out graph and performance of your OpenVidu installation"
    Value: !Join
        - ''
        - - 'https://'
          - !Ref MyDomainName
          - '/kibana'
    Condition: WhichCertPresent
