diff --git a/.github/actions/deploy-debian-11/action.yml b/.github/actions/deploy-debian-11/action.yml new file mode 100644 index 00000000..7b00c9d8 --- /dev/null +++ b/.github/actions/deploy-debian-11/action.yml @@ -0,0 +1,19 @@ +name: Deploy on Debian 11 +runs: + using: composite + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Ant Media Server + shell: bash + run: | + apt-get update + apt-get -y install wget findutils unzip curl + curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) + bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false + /usr/local/antmedia/antmedia start + sleep 40 + if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then + echo "LiveApp started log does not exist. Check the logs above" + exit 1; + fi; diff --git a/.github/actions/deploy-debian-12/action.yml b/.github/actions/deploy-debian-12/action.yml new file mode 100644 index 00000000..66f24c80 --- /dev/null +++ b/.github/actions/deploy-debian-12/action.yml @@ -0,0 +1,19 @@ +name: Deploy on Debian 12 +runs: + using: composite + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Ant Media Server + shell: bash + run: | + apt-get update + apt-get -y install wget findutils unzip curl + curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) + bash ./install_ant-media-server.sh -i ant-media-server-community.zip -s false + /usr/local/antmedia/antmedia start + sleep 40 + if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then + echo "LiveApp started log does not exist. Check the logs above" + exit 1; + fi; diff --git a/.github/workflows/almalinux.yml b/.github/workflows/almalinux.yml index 91d82559..1f08af36 100644 --- a/.github/workflows/almalinux.yml +++ b/.github/workflows/almalinux.yml @@ -2,14 +2,8 @@ name: AlmaLinux on: [push] jobs: - Almalinux8: - runs-on: ubuntu-20.04 - container: almalinux:8 - steps: - - uses: actions/checkout@v3 - - uses: ./.github/actions/deploy-almalinux Almalinux9: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 container: almalinux:9 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/ams-utilizations.yml b/.github/workflows/ams-utilizations.yml index 27c3b3f5..5f58f848 100644 --- a/.github/workflows/ams-utilizations.yml +++ b/.github/workflows/ams-utilizations.yml @@ -25,3 +25,12 @@ jobs: - name: Set up MongoDB run: | bash ./install_mongodb.sh + mongodb_install_ubuntu_24_04: + runs-on: ubuntu-24.04 + + steps: + - name: Check out repository code + uses: actions/checkout@v3 + - name: Set up MongoDB + run: | + bash ./install_mongodb.sh \ No newline at end of file diff --git a/.github/workflows/ant-media-server-docker-multi-platform.yml b/.github/workflows/ant-media-server-docker-multi-platform.yml index 7c24d03c..840cab12 100644 --- a/.github/workflows/ant-media-server-docker-multi-platform.yml +++ b/.github/workflows/ant-media-server-docker-multi-platform.yml @@ -5,6 +5,8 @@ on: [push] jobs: ams_ubuntu_docker_test: runs-on: ubuntu-latest + env: + BRANCH_NAME: ${{ github.ref_name }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -13,10 +15,10 @@ jobs: run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) - name: Download Dockerfile - run: wget --quiet https://raw.githubusercontent.com/ant-media/Scripts/master/docker/Dockerfile_Process -O Dockerfile + run: wget --quiet https://raw.githubusercontent.com/ant-media/Scripts/$BRANCH_NAME/docker/Dockerfile_Process -O Dockerfile - name: Build Docker image - run: docker build --network=host -t antmediaserver:latest --build-arg AntMediaServer=ant-media-server-community.zip . + run: docker build --network=host -t antmediaserver:latest --build-arg AntMediaServer=ant-media-server-community.zip --build-arg BranchName=$BRANCH_NAME . - name: Run the image run: docker run -d -p 5080:5080 --name antmediaserver antmediaserver @@ -43,6 +45,8 @@ jobs: ams_rockylinux_docker_test: runs-on: ubuntu-latest + env: + BRANCH_NAME: ${{ github.ref_name }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -51,10 +55,14 @@ jobs: run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) - name: Download Dockerfile - run: wget --quiet https://raw.githubusercontent.com/ant-media/Scripts/master/docker/Dockerfile_RockyLinux -O Dockerfile + run: | + echo "Building Docker image with branch: $BRANCH_NAME" + wget --quiet https://raw.githubusercontent.com/ant-media/Scripts/$BRANCH_NAME/docker/Dockerfile_RockyLinux -O Dockerfile - name: Build Docker image - run: docker build --network=host -t antmediaserver:latest --build-arg AntMediaServer=ant-media-server-community.zip . + run: | + echo "Building Docker image with branch: $BRANCH_NAME" + docker build --network=host -t antmediaserver:latest --build-arg AntMediaServer=ant-media-server-community.zip --build-arg BranchName=$BRANCH_NAME . - name: Run the image run: docker run -d -p 5080:5080 --name antmediaserver antmediaserver diff --git a/.github/workflows/centos.yml b/.github/workflows/centos.yml deleted file mode 100644 index d69e3bec..00000000 --- a/.github/workflows/centos.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Centos -on: [push] - -jobs: - Centos8: - runs-on: ubuntu-20.04 - container: centos:8 - steps: - - uses: actions/checkout@v3 - - uses: ./.github/actions/deploy-centos - diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml new file mode 100644 index 00000000..2ad4b940 --- /dev/null +++ b/.github/workflows/debian.yml @@ -0,0 +1,16 @@ +name: Debian +on: [push] + +jobs: + Debian11: + runs-on: ubuntu-24.04 + container: debian:11 + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/deploy-debian-11 + Debian12: + runs-on: ubuntu-24.04 + container: debian:12 + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/deploy-debian-12 diff --git a/.github/workflows/install-dockerfile-and-check-ssl.yml b/.github/workflows/install-dockerfile-and-check-ssl.yml new file mode 100644 index 00000000..1c06054a --- /dev/null +++ b/.github/workflows/install-dockerfile-and-check-ssl.yml @@ -0,0 +1,72 @@ +name: Docker Build and Test + +on: +# [push] + workflow_dispatch: + schedule: + - cron: '0 0 */5 * *' + +jobs: + build: + runs-on: self-hosted + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Show current branch + run: echo "Current branch is ${{ github.event.inputs.branch_name }}" + + - name: stop the AMS service + run: sudo systemctl stop antmedia + + - name: Run Docker service + run: sudo systemctl restart docker + + - name: Build Docker image + run: docker build -f docker/Dockerfile_Process --network=host -t antmediaserver --build-arg LicenseKey="${{ secrets.ENTERPRISE_LICENSE }}" . + + - name: Run Docker container + run: docker run --restart=always -d --name antmedia --network=host -it antmediaserver + + - name: Check if SSL is enabled or not + run: | + set -e + if docker exec antmedia curl -f https://${{ secrets.CI_SSL_TEST_DOMAIN }}:5443; then + echo "Endpoint is reachable." + exit 1 + else + echo "Endpoint is not reachable, but continuing workflow." + fi + +# - name: Clone branch +# run: | +# git clone --depth=1 -b ${{ github.event.inputs.branch_name }} https://github.com/ant-media/Ant-Media-Server.git || git clone --depth=1 https://github.com/ant-media/Ant-Media-Server.git + + - name: Download enable_ssl.sh inside container + run: docker exec antmedia wget -O /usr/local/antmedia/enable_ssl.sh https://raw.githubusercontent.com/ant-media/Ant-Media-Server/master/src/main/server/enable_ssl.sh + +# - name: Copy enable_ssl.sh from cloned branch to container +# run: docker cp Ant-Media-Server/src/main/server/enable_ssl.sh antmedia:/usr/local/antmedia/enable_ssl.sh + + - name: Run enable_ssl.sh inside container + run: docker exec antmedia bash /usr/local/antmedia/enable_ssl.sh -d ${{ secrets.CI_SSL_TEST_DOMAIN }} + + - name: Verify container is running + run: | + sleep 20 + docker ps -f name=antmedia + if [ $(docker ps -f name=antmedia --format '{{.Names}}') != "antmedia" ]; then + echo "Container is not running" + exit 1 + fi + + - name: Test application + run: | + docker exec antmedia curl -f https://${{ secrets.CI_SSL_TEST_DOMAIN }}:5443 + - name: Stop and remove container + if: ${{ always() }} + run: | + docker stop antmedia + docker rm antmedia + sudo systemctl start antmedia diff --git a/.github/workflows/install-latest-snapshot-to-ubuntu-22-04.yml b/.github/workflows/install-latest-snapshot-to-ubuntu-22-04.yml index ecba1b13..b11eb6d5 100644 --- a/.github/workflows/install-latest-snapshot-to-ubuntu-22-04.yml +++ b/.github/workflows/install-latest-snapshot-to-ubuntu-22-04.yml @@ -12,7 +12,7 @@ jobs: - run: wget -O maven-metadata.xml https://oss.sonatype.org/service/local/repositories/snapshots/content/io/antmedia/ant-media-server/maven-metadata.xml #Get latest snapshot - run: | - export LATEST_SNAPSHOT=$(cat maven-metadata.xml | grep "" | tail -n 1 | xargs | cut -c 10-23) + export LATEST_SNAPSHOT=$(grep -oP '(?<=)[^<]+' maven-metadata.xml| tail -1) echo $LATEST_SNAPSHOT wget -O ant-media-server-community.zip "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.antmedia&a=ant-media-server&v=${LATEST_SNAPSHOT}&c=community&e=zip"; - run: ./install_ant-media-server.sh -i ant-media-server-community.zip diff --git a/.github/workflows/install-latest-snapshot-to-ubuntu-24-04.yml b/.github/workflows/install-latest-snapshot-to-ubuntu-24-04.yml new file mode 100644 index 00000000..884c2141 --- /dev/null +++ b/.github/workflows/install-latest-snapshot-to-ubuntu-24-04.yml @@ -0,0 +1,27 @@ +name: Install Latest Snapshot to Ubuntu 24.04 +on: [push] + +jobs: + Install-Ubuntu-24-04: + runs-on: ubuntu-24.04 + steps: + - name: Check out repository code + uses: actions/checkout@v3 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + + - run: wget -O maven-metadata.xml https://oss.sonatype.org/service/local/repositories/snapshots/content/io/antmedia/ant-media-server/maven-metadata.xml + #Get latest snapshot + - run: | + export LATEST_SNAPSHOT=$(grep -oP '(?<=)[^<]+' maven-metadata.xml| tail -1) + echo $LATEST_SNAPSHOT + wget -O ant-media-server-community.zip "https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=io.antmedia&a=ant-media-server&v=${LATEST_SNAPSHOT}&c=community&e=zip"; + - run: ./install_ant-media-server.sh -i ant-media-server-community.zip + - run: sudo service antmedia status + - run: sleep 30 + - run: cat /usr/local/antmedia/log/ant-media-server.log + - run: | + if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then + echo "LiveApp started log does not exist. Check the logs above" + exit 1; + fi; + - run: cat /usr/local/antmedia/log/antmedia-error.log diff --git a/.github/workflows/install-latest-to-ubuntu-24-04.yml b/.github/workflows/install-latest-to-ubuntu-24-04.yml new file mode 100644 index 00000000..7cf9f005 --- /dev/null +++ b/.github/workflows/install-latest-to-ubuntu-24-04.yml @@ -0,0 +1,53 @@ +name: Install Latest to Ubuntu 24.04 +on: [push] + +jobs: + Install-Ubuntu-24-04: + runs-on: ubuntu-24.04 + steps: + - name: Check out repository code + uses: actions/checkout@v3 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + #Get latest version + - run: curl -L -o ant-media-server-community.zip $(curl -s https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | grep "browser_download_url" | cut -d '"' -f 4) + - run: ./install_ant-media-server.sh -i ant-media-server-community.zip + - run: sleep 30 + - run: cat /usr/local/antmedia/log/ant-media-server.log + - run: | + if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then + echo "LiveApp started log does not exist. Check the logs above" + exit 1; + fi; + - run: cat /usr/local/antmedia/log/antmedia-error.log + Auto-Install-Community-: + runs-on: ubuntu-24.04 + steps: + - name: Check out repository code + uses: actions/checkout@v3 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + #Get latest version + - run: ./install_ant-media-server.sh + - run: sleep 30 + - run: cat /usr/local/antmedia/log/ant-media-server.log + - run: | + if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then + echo "LiveApp started log does not exist. Check the logs above" + exit 1; + fi; + - run: cat /usr/local/antmedia/log/antmedia-error.log + Auto-Install-Enterprise-: + runs-on: ubuntu-24.04 + steps: + - name: Check out repository code + uses: actions/checkout@v3 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + #Get latest version + - run: bash -x ./install_ant-media-server.sh -l"${{ secrets.ENTERPRISE_LICENSE }}" + - run: sleep 30 + - run: cat /usr/local/antmedia/log/ant-media-server.log + - run: | + if [ $(cat /usr/local/antmedia/log/ant-media-server.log | grep "LiveApp started" | wc -l | xargs) -eq 0 ]; then + echo "LiveApp started log does not exist. Check the logs above" + exit 1; + fi; + - run: cat /usr/local/antmedia/log/antmedia-error.log diff --git a/.github/workflows/rockylinux.yml b/.github/workflows/rockylinux.yml index 85998ec4..576987af 100644 --- a/.github/workflows/rockylinux.yml +++ b/.github/workflows/rockylinux.yml @@ -2,15 +2,9 @@ name: RockyLinux on: [push] jobs: - RockyLinux8: - runs-on: ubuntu-20.04 - container: rockylinux:8 - steps: - - uses: actions/checkout@v3 - - uses: ./.github/actions/deploy-rockylinux RockyLinux9: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 container: rockylinux:9 steps: - uses: actions/checkout@v3 - - uses: ./.github/actions/deploy-rockylinux-9 + - uses: ./.github/actions/deploy-rockylinux-9 \ No newline at end of file diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml new file mode 100644 index 00000000..51477105 --- /dev/null +++ b/.github/workflows/samples.yml @@ -0,0 +1,68 @@ +name: Python Samples Script + +on: + schedule: + - cron: '0 */12 * * *' + +jobs: + run-selenium: + runs-on: ubuntu-latest + + env: + WEBHOOK_URL: ${{ secrets.WEBHOOK }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python 3 + uses: actions/setup-python@v3 + with: + python-version: 3.x + + - name: Install dependencies + run: | + pip install selenium + pip install requests + + - name: Install FFmpeg + run: | + sudo apt-get update + sudo apt-get install -y ffmpeg + + - name: Install SRT + run: | + git clone https://github.com/Haivision/srt.git + cd srt + sudo apt-get install tclsh pkg-config cmake libssl-dev build-essential + ./configure + make + sudo make install + cd .. + + - name: Install Chrome + run: | + wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo dpkg -i google-chrome-stable_current_amd64.deb + + - name: Install ChromeDriver + run: | + wget https://storage.googleapis.com/chrome-for-testing-public/131.0.6778.69/linux64/chromedriver-linux64.zip + unzip chromedriver-linux64.zip + cd chromedriver-linux64 + sudo mv chromedriver /usr/bin/chromedriver + sudo chown root:root /usr/bin/chromedriver + sudo chmod +x /usr/bin/chromedriver + + - name: Run Selenium script + run: | + python Selenium/antmedia-samples.py + + - name: Install jq + run: sudo apt-get install -y jq + + - name: Send Slack notification on failure + if: ${{ failure() || cancelled() }} + run: | + SLACK_PAYLOAD=$(jq -n --arg text "<@U01UMD36SQ0> GitHub Workflow failed for ${{ github.repository }}" '{text: $text, icon_emoji: ":x:"}') + curl -X POST -H 'Content-type: application/json' --data "$SLACK_PAYLOAD" ${{ env.WEBHOOK_URL }} diff --git a/Selenium/antmedia-samples.py b/Selenium/antmedia-samples.py index 1a315b1e..aeaa5670 100644 --- a/Selenium/antmedia-samples.py +++ b/Selenium/antmedia-samples.py @@ -10,13 +10,16 @@ from selenium.webdriver.chrome.options import Options -# Function to send notification to Slack -def send_slack_message(webhook_url, message, icon_emoji=":x:"): +# Function to send notification to Slack Channel +def send_slack_message(webhook_url, message, user_id, icon_emoji=":x:"): payload = { - "text": message, + "text": f"<@{user_id}> {message}", "icon_emoji": icon_emoji } - response = requests.post(webhook_url, data={"payload": json.dumps(payload)}) + headers = {'Content-Type': 'application/json'} + #response = requests.post(webhook_url, data={"payload": json.dumps(payload)}) + response = requests.post(webhook_url, data=json.dumps(payload), headers=headers) + if response.status_code != 200: print("Error sending Slack message: ", response.text) @@ -56,26 +59,28 @@ def switch_to_first_tab(driver): # Function to remove advertisement from sample pages -def remove_ad(driver): - element = driver.find_element(By.XPATH, "/html/body/div[3]/div") - driver.execute_script("arguments[0].style.display = 'none';", element) +#def remove_ad(driver): +# element = driver.find_element(By.XPATH, "/html/body/div[3]") +# driver.execute_script("arguments[0].style.display = 'none';", element) +# element1 = driver.find_element(By.XPATH, "/html/body/div[6]/div") +# driver.execute_script("arguments[0].style.display = 'none';", element1) # Function to switch to new window and close the advertisement block def switch_window_and_frame(driver): driver.switch_to.window(driver.window_handles[1]) - time.sleep(10) - remove_ad(driver) - time.sleep(2) + time.sleep(15) driver.switch_to.frame(0) time.sleep(3) webhook_url = os.environ['WEBHOOK_URL'] icon_emoji = ":x:" +user_id = 'U01UMD36SQ0' options = Options() options.add_argument('--headless') +options.add_argument("--window-size=1920,1080"); options.add_argument("--use-fake-ui-for-media-stream") options.add_argument("--use-fake-device-for-media-stream") driver = webdriver.Chrome(options=options) @@ -89,8 +94,8 @@ def switch_window_and_frame(driver): driver.execute_script("window.open('https://antmedia.io/webrtc-samples/webrtc-virtual-background/', '_blank');") driver.switch_to.window(driver.window_handles[1]) time.sleep(20) - remove_ad(driver) - time.sleep(2) + #remove_ad(driver) + #time.sleep(2) driver.switch_to.frame(0) time.sleep(3) driver.find_element(By.XPATH, "/html/body/div/div/div[4]/div[3]/img").click() @@ -105,7 +110,7 @@ def switch_window_and_frame(driver): except: if i==1: message = "Virtual background test is failed, check -> https://antmedia.io/webrtc-samples/webrtc-virtual-background/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) continue switch_to_first_tab(driver) @@ -115,17 +120,18 @@ def switch_window_and_frame(driver): driver.execute_script("window.open('https://antmedia.io/live-demo/', '_blank');") driver.switch_to.window(driver.window_handles[1]) time.sleep(20) - remove_ad(driver) - time.sleep(2) - driver.find_element(By.XPATH, "/html/body/div[5]/div/article[2]/div[2]/div[1]/div[1]/div/div/p/button[1]").click() + #remove_ad(driver) + #time.sleep(2) + driver.find_element(By.XPATH, "/html/body/div[1]/div/article[2]/div[2]/div[1]/div[1]/div/div/p/button[1]").click() time.sleep(15) - driver.find_element(By.XPATH, "/html/body/div[5]/div/article[2]/div[2]/div[1]/div[1]/div/div/p/button[2]").click() + driver.find_element(By.XPATH, "/html/body/div[1]/div/article[2]/div[2]/div[1]/div[1]/div/div/p/button[2]").click() time.sleep(3) print("Live demo is successful") except: message = "Livedemo test is failed, check -> https://antmedia.io/live-demo/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) + switch_to_first_tab(driver) @@ -136,14 +142,14 @@ def switch_window_and_frame(driver): driver.find_element(By.XPATH, "/html/body/div/div/div[8]/button[1]").click() time.sleep(10) driver.find_element(By.XPATH, "/html/body/div/div/div[7]/div[1]/a").click() - time.sleep(5) + time.sleep(10) driver.find_element(By.XPATH, "/html/body/div/div/div[8]/button[2]").click() time.sleep(3) print("WebRTC to WebRTC is successful") except: message = "WebRTC to WebRTC test is failed, check -> https://antmedia.io/webrtc-samples/webrtc-publish-webrtc-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) driver.close() driver.switch_to.window(driver.window_handles[1]) @@ -156,14 +162,14 @@ def switch_window_and_frame(driver): driver.find_element(By.XPATH, "/html/body/div/div/div[8]/button[1]").click() time.sleep(10) driver.find_element(By.XPATH, "/html/body/div/div/div[7]/div[1]/a").click() - time.sleep(5) + time.sleep(10) driver.find_element(By.XPATH, "/html/body/div/div/div[8]/button[2]").click() time.sleep(5) print("WebRTC to HLS is successful") except: message = "WebRTC to HLS test is failed, check -> https://antmedia.io/webrtc-samples/webrtc-publish-hls-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) driver.close() driver.switch_to.window(driver.window_handles[1]) @@ -188,7 +194,7 @@ def switch_window_and_frame(driver): except: message = "WebRTC audio publish test is failed, check -> https://antmedia.io/webrtc-samples/webrtc-audio-publish-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) driver.close() driver.switch_to.window(driver.window_handles[1]) @@ -205,7 +211,7 @@ def switch_window_and_frame(driver): except: message = "RTMP to WebRTC test is failed, check -> https://antmedia.io/webrtc-samples/rtmp-publish-wertc-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) switch_to_first_tab(driver) @@ -220,7 +226,7 @@ def switch_window_and_frame(driver): except: message = "RTMP to HLS test is failed, check -> https://antmedia.io/webrtc-samples/rtmp-publish-hls-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) switch_to_first_tab(driver) @@ -238,7 +244,7 @@ def switch_window_and_frame(driver): except: message = "SRT to WebRTC test is failed, check -> https://antmedia.io/webrtc-samples/srt-publish-webrtc-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) switch_to_first_tab(driver) @@ -256,7 +262,7 @@ def switch_window_and_frame(driver): except: message = "SRT to HLS test is failed, check -> https://antmedia.io/webrtc-samples/srt-publish-hls-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) switch_to_first_tab(driver) @@ -265,41 +271,59 @@ def switch_window_and_frame(driver): driver.execute_script("window.open('https://antmedia.io/webrtc-samples/deepar-publish-play/', '_blank');") switch_window_and_frame(driver) driver.find_element(By.XPATH, "/html/body/div/div/select").click() - time.sleep(1) - driver.find_element(By.XPATH, "/html/body/div[1]/div/select/option[6]").click() - time.sleep(1) - driver.find_element(By.XPATH, "/html/body/div[1]/div/div[5]/button[1]").click() + time.sleep(2) + driver.find_element(By.XPATH, "/html/body/div[1]/div/select/option[3]").click() + time.sleep(2) + driver.find_element(By.XPATH, "/html/body/div/div/div[5]/button[1]").click() time.sleep(10) - driver.find_element(By.XPATH, "/html/body/div[1]/div/div[5]/button[2]").click() + driver.find_element(By.XPATH, "/html/body/div/div/div[5]/button[2]").click() print("WebRTC Deep AR test is successful") except: message = "WebRTC DeepAR sample test is failed, check -> https://antmedia.io/webrtc-samples/deepar-publish-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) switch_to_first_tab(driver) # Testing Whiteboard sample page try: driver.execute_script("window.open('https://antmedia.io/webrtc-samples/interactive-whiteboard-publish-play/', '_blank');") - switch_window_and_frame(driver) - driver.switch_to.frame("webrtc-publish-frame") - time.sleep(1) - driver.find_element(By.XPATH, "/html/body/div[2]/div/div/div/div[2]/div[6]/button[1]").click() + driver.switch_to.window(driver.window_handles[1]) time.sleep(5) driver.switch_to.frame(0) + time.sleep(2) + driver.find_element(By.XPATH, "/html/body/div[2]/div/div/div/div[2]/div[6]/button[1]").click() + time.sleep(2) + iframe_element = driver.find_element(By.XPATH, "/html/body/div[2]/div/div/div/div[1]/iframe") + driver.switch_to.frame(iframe_element) driver.find_element(By.XPATH, "/html/body/section[2]/canvas[4]").click() time.sleep(2) driver.switch_to.default_content() - driver.switch_to.frame(0) - driver.switch_to.frame("webrtc-play-frame") - driver.find_element(By.XPATH, "/html/body/div[2]/div/div/div/div[3]/div[4]/button[1]").click() + iframe_element1 = driver.find_element(By.XPATH, "/html/body/div/div[2]/div/div/article/div/div/div/div/div/section/div/div/div/div/div/div/div/div/div[2]/iframe") + driver.switch_to.frame(iframe_element1) + driver.find_element(By.XPATH, "/html/body/div[2]/div/div/div/div[2]/div[5]/button[1]").click() time.sleep(10) print("WebRTC white board test is successful") except: message = "WebRTC whiteboard test is failed, check -> https://antmedia.io/webrtc-samples/interactive-whiteboard-publish-play/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) + +switch_to_first_tab(driver) + +# Testing Conference sample page +try: + driver.execute_script("window.open('https://antmedia.io/webrtc-samples/multitrack-conference-solution/', '_blank');") + switch_window_and_frame(driver) + driver.find_element(By.XPATH, "/html/body/div/div[2]/div[3]/div/div[2]/button[1]").click() + time.sleep(10) + driver.find_element(By.XPATH, "/html/body/div/div[2]/div[3]/div/div[2]/button[2]").click() + time.sleep(3) + print("WebRTC Conference test is successful") + +except: + message = "WebRTC Conference sample test is failed, check -> https://antmedia.io/webrtc-samples/multitrack-conference-solution/" + send_slack_message(webhook_url, message, user_id, icon_emoji) switch_to_first_tab(driver) @@ -319,6 +343,6 @@ def switch_window_and_frame(driver): except: message = "WebRTC data channel test is failed, check -> https://antmedia.io/webrtc-samples/webrtc-data-channel-only/" - send_slack_message(webhook_url, message, icon_emoji) + send_slack_message(webhook_url, message, user_id, icon_emoji) driver.quit() diff --git a/cloudformation/antmedia-aws-autoscale-template.yaml b/cloudformation/antmedia-aws-autoscale-template.yaml index 6c46c9a1..7849c558 100644 --- a/cloudformation/antmedia-aws-autoscale-template.yaml +++ b/cloudformation/antmedia-aws-autoscale-template.yaml @@ -4,7 +4,7 @@ Description: >- If you have any questions, please just drop a line to contact (at) antmedia.io Parameters: VpcCidrBlock: - Description: 'CIDR value for Wavelength Network' + Description: 'CIDR value for Network' Type: String MinLength: '9' MaxLength: '18' @@ -292,7 +292,7 @@ Resources: AMSGetLatestAMI: Type: AWS::Lambda::Function Properties: - Runtime: python3.11 + Runtime: python3.12 Handler: index.handler Role: !Sub ${DescribeImagesRole.Arn} Timeout: 60 @@ -326,7 +326,7 @@ Resources: UbuntuGetLatestAMI: Type: AWS::Lambda::Function Properties: - Runtime: python3.11 + Runtime: python3.12 Handler: index.handler Role: !Sub ${DescribeImagesRole.Arn} Timeout: 60 @@ -380,7 +380,7 @@ Resources: Properties: ServiceToken: !Sub ${UbuntuGetLatestAMI.Arn} Owner: "099720109477" - Name: "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" + Name: "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" Architecture: "x86_64" AntMediaVPC: @@ -487,6 +487,15 @@ Resources: LoadBalancerArn: !Ref RTMPLoadBalancer Port: '1935' Protocol: TCP + SRTListener: + Type: 'AWS::ElasticLoadBalancingV2::Listener' + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref SRTTargetGroup + LoadBalancerArn: !Ref RTMPLoadBalancer + Port: '4200' + Protocol: UDP RTMPTargetGroup: Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' Properties: @@ -496,6 +505,17 @@ Resources: Protocol: TCP UnhealthyThresholdCount: 3 VpcId: !Ref AntMediaVPC + SRTTargetGroup: + Type: 'AWS::ElasticLoadBalancingV2::TargetGroup' + Properties: + HealthCheckIntervalSeconds: 30 + HealthyThresholdCount: 3 + Port: 4200 + Protocol: UDP + UnhealthyThresholdCount: 3 + HealthCheckProtocol: TCP + HealthCheckPort: '5080' + VpcId: !Ref AntMediaVPC RTMPSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: @@ -505,6 +525,10 @@ Resources: FromPort: '1935' ToPort: '1935' CidrIp: '0.0.0.0/0' + - IpProtocol: udp + FromPort: '4200' + ToPort: '4200' + CidrIp: '0.0.0.0/0' SecurityGroupEgress: - IpProtocol: tcp FromPort: 0 @@ -528,6 +552,7 @@ Resources: TargetGroupARNs: - !Ref ALBTargetGroupOrigin - !Ref RTMPTargetGroup + - !Ref SRTTargetGroup Tags: - Key: Name Value: Antmedia-Origin @@ -572,12 +597,11 @@ Resources: touch /usr/local/antmedia/conf/initialized bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} apt-get update - apt-get install -y python3-pip - apt-get install -y python3-setuptools + sudo apt-get -y install python3-pip mkdir -p /opt/aws/bin - wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} + sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup + /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} TagSpecifications: - ResourceType: instance Tags: @@ -647,13 +671,12 @@ Resources: #!/bin/bash touch /usr/local/antmedia/conf/initialized bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} - apt-get update - apt-get install -y python3-pip - apt-get install -y python3-setuptools + sudo apt-get update + sudo apt-get -y install python3-pip mkdir -p /opt/aws/bin - wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} + sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup + /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} TagSpecifications: - ResourceType: instance Tags: @@ -842,6 +865,9 @@ Resources: - IpProtocol: udp FromPort: '50000' ToPort: '60000' + - IpProtocol: udp + FromPort: '4200' + ToPort: '4200' CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: '5000' @@ -903,13 +929,8 @@ Resources: Fn::Base64: !Sub | #!/bin/bash -xe - wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - - echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list - sudo apt-get update - sudo apt-get install -y mongodb-org python3-pip python3-setuptools - sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mongod.conf - systemctl enable mongod - systemctl restart mongod + wget -P /tmp/ https://raw.githubusercontent.com/ant-media/Scripts/master/install_mongodb.sh + bash /tmp/install_mongodb.sh Outputs: diff --git a/cloudformation/aws-streaming-wizard/template-custom-cert.yaml b/cloudformation/aws-streaming-wizard/template-custom-cert.yaml index debdd014..a8f93707 100644 --- a/cloudformation/aws-streaming-wizard/template-custom-cert.yaml +++ b/cloudformation/aws-streaming-wizard/template-custom-cert.yaml @@ -345,13 +345,12 @@ Resources: #!/bin/bash touch /usr/local/antmedia/conf/initialized bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} - apt-get update - apt-get install -y python3-pip - apt-get install -y python3-setuptools + sudo apt-get update + sudo apt-get -y install python3-pip mkdir -p /opt/aws/bin - wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} + sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup + /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} TagSpecifications: - ResourceType: instance Tags: @@ -414,13 +413,12 @@ Resources: #!/bin/bash touch /usr/local/antmedia/conf/initialized bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} - apt-get update - apt-get install -y python3-pip - apt-get install -y python3-setuptools + sudo apt-get update + sudo apt-get -y install python3-pip mkdir -p /opt/aws/bin - wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} + sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup + /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} TagSpecifications: - ResourceType: instance Tags: @@ -660,13 +658,8 @@ Resources: Fn::Base64: !Sub | #!/bin/bash -xe - wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - - echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list - sudo apt-get update - sudo apt-get install -y mongodb-org python3-pip python3-setuptools - sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mongod.conf - systemctl enable mongod - systemctl restart mongod + wget -P /tmp/ https://raw.githubusercontent.com/ant-media/Scripts/master/install_mongodb.sh + bash /tmp/install_mongodb.sh Outputs: diff --git a/cloudformation/aws-streaming-wizard/template.yaml b/cloudformation/aws-streaming-wizard/template.yaml index 598de5d4..1d27dd61 100644 --- a/cloudformation/aws-streaming-wizard/template.yaml +++ b/cloudformation/aws-streaming-wizard/template.yaml @@ -292,13 +292,12 @@ Resources: #!/bin/bash touch /usr/local/antmedia/conf/initialized bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} - apt-get update - apt-get install -y python3-pip - apt-get install -y python3-setuptools + sudo apt-get update + sudo apt-get -y install python3-pip mkdir -p /opt/aws/bin - wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} + sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup + /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource OriginGroup --region ${AWS::Region} TagSpecifications: - ResourceType: instance Tags: @@ -361,13 +360,12 @@ Resources: #!/bin/bash touch /usr/local/antmedia/conf/initialized bash /usr/local/antmedia/change_server_mode.sh cluster ${DBInstance.PrivateIp} - apt-get update - apt-get install -y python3-pip - apt-get install -y python3-setuptools + sudo apt-get update + sudo apt-get -y install python3-pip mkdir -p /opt/aws/bin - wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz - python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz - /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} + sudo pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz + sudo ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup + /usr/local/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EdgeGroup --region ${AWS::Region} TagSpecifications: - ResourceType: instance Tags: @@ -607,13 +605,8 @@ Resources: Fn::Base64: !Sub | #!/bin/bash -xe - wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add - - echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list - sudo apt-get update - sudo apt-get install -y mongodb-org python3-pip python3-setuptools - sed -i 's/127.0.0.1/0.0.0.0/g' /etc/mongod.conf - systemctl enable mongod - systemctl restart mongod + wget -P /tmp/ https://raw.githubusercontent.com/ant-media/Scripts/master/install_mongodb.sh + bash /tmp/install_mongodb.sh Outputs: diff --git a/docker/Dockerfile_Process b/docker/Dockerfile_Process index 946836d2..013923b3 100644 --- a/docker/Dockerfile_Process +++ b/docker/Dockerfile_Process @@ -1,16 +1,30 @@ +# # This docker file can be used in kubernetes. # It accepts all cluster related parameters at run time. # It means it's very easy to add new containers to the cluster +# +# Usage: +# +# * AntMediaServer: Specify the name of the Ant Media Server zip file to install that specify Ant Media Server version to the docker image +# --build-arg AntMediaServer='ant-media-server.zip' +# +# * LicenseKey: Set your license key to this variable to install the latest Ant Media Server automatically to the docker image without needing a zip file. If you use this LicenseKey variable, don't specify AntMediaServer variable (# --build-arg AntMediaServer='ant-media-server.zip') +# --build-arg LicenseKey='your-license-key' +# +# * InstallMediaPush: Set this variable to 'true' to enable headless Chrome on the server for recording and streaming web pages back to Ant Media Server. +# --build-arg InstallMediaPush='true' +# FROM ubuntu:22.04 ARG AntMediaServer ARG LicenseKey +ARG InstallMediaPush ARG BranchName=master #Running update and install makes the builder not to use cache which resolves some updates -RUN apt-get update && apt-get install -y curl wget iproute2 cron logrotate +RUN apt-get update && apt-get install -y curl wget iproute2 cron logrotate dnsutils iptables ADD ./${AntMediaServer} /home @@ -30,6 +44,14 @@ RUN cd /home \ exit 1; \ fi +RUN if [ "true" = "$InstallMediaPush" ]; then \ + echo "test"; \ + echo "#!/bin/bash\n\$@" > /usr/bin/sudo; \ + chmod +x /usr/bin/sudo; \ + wget -O install_media-push-plugin.sh https://raw.githubusercontent.com/ant-media/Plugins/master/MediaPushPlugin/src/main/script/install_media-push-plugin.sh; \ + bash ./install_media-push-plugin.sh; \ + fi + # # Options: # diff --git a/docker/Dockerfile_RockyLinux b/docker/Dockerfile_RockyLinux index bc59a87c..b92ca13e 100644 --- a/docker/Dockerfile_RockyLinux +++ b/docker/Dockerfile_RockyLinux @@ -1,10 +1,10 @@ -FROM rockylinux/rockylinux:8.6 +FROM rockylinux/rockylinux:9.3 ARG AntMediaServer ARG BranchName=master #Running update and install makes the builder not to use cache which resolves some updates -RUN yum install -y curl wget iproute logrotate which findutils which crontabs unzip +RUN yum install -y curl wget iproute logrotate which findutils which crontabs unzip --allowerasing ADD ./${AntMediaServer} /home diff --git a/gcp-jinja-template/antmedia-firewall-template.jinja b/gcp-jinja-template/antmedia-firewall-template.jinja new file mode 100644 index 00000000..e33e9ec1 --- /dev/null +++ b/gcp-jinja-template/antmedia-firewall-template.jinja @@ -0,0 +1,45 @@ +{# +Copyright 2016 Google Inc. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +#} + +resources: +- type: compute.v1.firewall + name: ams-mongodb-internal + properties: + network: $(ref.antmedia-vpc-network.selfLink) + sourceRanges: + - 10.0.0.0/16 + targetTags: + - antmedia-mongodb + allowed: + - IPProtocol: tcp + ports: + - "27017" + - "22" + +- type: compute.v1.firewall + name: ams-antmedia-external + properties: + network: $(ref.antmedia-vpc-network.selfLink) + sourceRanges: + - 0.0.0.0/0 + targetTags: + - antmedia + allowed: + - IPProtocol: tcp + ports: + - "5080" + - "22" + - "1935" + diff --git a/gcp-jinja-template/antmedia-instance-group-template.jinja b/gcp-jinja-template/antmedia-instance-group-template.jinja new file mode 100644 index 00000000..bce7bc96 --- /dev/null +++ b/gcp-jinja-template/antmedia-instance-group-template.jinja @@ -0,0 +1,52 @@ +resources: +- name: origin-instance-group + type: compute.v1.instanceGroupManager + properties: + zone: {{ properties["zone"] }} + targetSize: 1 + baseInstanceName: antmedia-origin + instanceTemplate: projects/{{ env["project"] }}/global/instanceTemplates/ams-origin-template + namedPorts: + - name: http + port: 5080 + metadata: + dependsOn: + - ams-origin-template + +- name: origin-autoscaler + type: compute.v1.autoscaler + properties: + zone: {{ properties["zone"] }} + target: $(ref.origin-instance-group.selfLink) + autoscalingPolicy: + minNumReplicas: 1 + maxNumReplicas: 10 + coolDownPeriodSec: 60 + cpuUtilization: + utilizationTarget: 0.6 + +- name: edge-instance-group + type: compute.v1.instanceGroupManager + properties: + zone: {{ properties["zone"] }} + targetSize: 1 + baseInstanceName: antmedia-edge + instanceTemplate: projects/{{ env["project"] }}/global/instanceTemplates/ams-edge-template + namedPorts: + - name: http + port: 5080 + metadata: + dependsOn: + - ams-edge-template + +- name: edge-autoscaler + type: compute.v1.autoscaler + properties: + zone: {{ properties["zone"] }} + target: $(ref.edge-instance-group.selfLink) + autoscalingPolicy: + minNumReplicas: 1 + maxNumReplicas: 10 + coolDownPeriodSec: 60 + cpuUtilization: + utilizationTarget: 0.6 diff --git a/gcp-jinja-template/antmedia-instance-template.jinja b/gcp-jinja-template/antmedia-instance-template.jinja new file mode 100644 index 00000000..90495a5e --- /dev/null +++ b/gcp-jinja-template/antmedia-instance-template.jinja @@ -0,0 +1,65 @@ +resources: +- name: ams-origin-template + type: compute.v1.instanceTemplate + properties: + properties: + zone: {{ properties["zone"] }} + machineType: {{ properties["origin_machine_type"] }} + metadata: + items: + - key: startup-script + value: |- + #!/bin/bash + rm -rf /usr/local/antmedia/conf/instanceId + rm -rf /usr/local/antmedia/*.db.* + rm -rf /usr/local/antmedia/*.db + cd /usr/local/antmedia + ./change_server_mode.sh cluster $(ref.{{ env["deployment"] }}-mongodb.networkInterfaces[0].networkIP) + disks: + - deviceName: boot + type: PERSISTENT + boot: true + autoDelete: true + initializeParams: + sourceImage: projects/{{ env["project"] }}/global/images/{{ properties["image_id"] }} + networkInterfaces: + - network: $(ref.antmedia-vpc-network.selfLink) + subnetwork: $(ref.origin-subnet.selfLink) + accessConfigs: + - name: External NAT + type: ONE_TO_ONE_NAT + tags: + items: + - antmedia +- name: ams-edge-template + type: compute.v1.instanceTemplate + properties: + properties: + zone: {{ properties["zone"] }} + machineType: {{ properties["edge_machine_type"] }} + metadata: + items: + - key: startup-script + value: |- + #!/bin/bash + rm -rf /usr/local/antmedia/conf/instanceId + rm -rf /usr/local/antmedia/*.db.* + rm -rf /usr/local/antmedia/*.db + cd /usr/local/antmedia + ./change_server_mode.sh cluster $(ref.{{ env["deployment"] }}-mongodb.networkInterfaces[0].networkIP) + disks: + - deviceName: boot + type: PERSISTENT + boot: true + autoDelete: true + initializeParams: + sourceImage: projects/{{ env["project"] }}/global/images/{{ properties["image_id"] }} + networkInterfaces: + - network: $(ref.antmedia-vpc-network.selfLink) + subnetwork: $(ref.edge-subnet.selfLink) + accessConfigs: + - name: External NAT + type: ONE_TO_ONE_NAT + tags: + items: + - antmedia diff --git a/gcp-jinja-template/antmedia-loadbalancer-template.jinja b/gcp-jinja-template/antmedia-loadbalancer-template.jinja new file mode 100644 index 00000000..ad3e801f --- /dev/null +++ b/gcp-jinja-template/antmedia-loadbalancer-template.jinja @@ -0,0 +1,74 @@ +{% set scenarios = ['origin', 'edge'] %} + + +resources: +{% for scenario in scenarios %} +- name: ams-load-balancer-{{ scenario }} + type: compute.v1.globalForwardingRule + properties: + region: {{ properties["region"] }} + loadBalancingScheme: EXTERNAL + target: $(ref.ams-target-proxy-{{ scenario }}.selfLink) + IPAddress: $(ref.lb-ipaddress-{{ scenario }}.address) + IPProtocol: TCP + portRange: 443-443 + +- name: ams-target-proxy-{{ scenario }} + type: compute.v1.targetHttpsProxy + properties: + urlMap: $(ref.ams-{{ scenario }}.selfLink) + sslCertificates: + - $(ref.ams-ssl-cert-{{ scenario }}.selfLink) + +- name: lb-ipaddress-{{ scenario }} + type: compute.v1.globalAddress + +- name: ams-{{ scenario }} + type: compute.v1.urlMap + properties: + defaultService: $(ref.ams-backend-{{ scenario }}.selfLink) + +- name: ams-ssl-cert-{{ scenario }} + type: compute.v1.sslCertificate + properties: + certificate: | + -----BEGIN CERTIFICATE----- + + -----END CERTIFICATE----- + privateKey: | + -----BEGIN PRIVATE KEY----- + + -----END PRIVATE KEY----- + + +- name: ams-backend-{{ scenario }} + type: compute.v1.backendService + properties: + port: 5080 + portName: http + protocol: HTTP + backends: + - name: backend + balancingMode: UTILIZATION + capacityScaler: 1.0 + group: projects/{{ env["project"] }}/zones/{{ properties["zone"] }}/instanceGroups/{{ scenario }}-instance-group + + maxUtilization: 0.8 + connectionDraining: + drainingTimeoutSec: 300 + healthChecks: + - $(ref.ams-health-check-{{ scenario }}.selfLink) + metadata: + dependsOn: + - {{ scenario }}-instance-group + - ams-health-check-{{ scenario }} + +- name: ams-health-check-{{ scenario }} + type: compute.v1.healthCheck + properties: + type: HTTP + httpHealthCheck: + port: 5080 + requestPath: / + +{% endfor %} diff --git a/gcp-jinja-template/antmedia-mongodb-template.jinja b/gcp-jinja-template/antmedia-mongodb-template.jinja new file mode 100644 index 00000000..2f43a0a2 --- /dev/null +++ b/gcp-jinja-template/antmedia-mongodb-template.jinja @@ -0,0 +1,47 @@ +{# +Copyright 2016 Google Inc. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +#} + +resources: +- type: compute.v1.instance + name: {{ env["deployment"] }}-mongodb + properties: + zone: {{ properties["zone"] }} + machineType: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/zones/{{ properties["zone"] }}/machineTypes/{{ properties["machine_type"] }} + metadata: + items: + # For more ways to use startup scripts on an instance, see: + # https://cloud.google.com/compute/docs/startupscript + - key: startup-script + value: | + #!/bin/bash + wget https://raw.githubusercontent.com/ant-media/Scripts/master/install_mongodb.sh + bash ./install_mongodb.sh + disks: + - deviceName: boot + type: PERSISTENT + boot: true + autoDelete: true + initializeParams: + sourceImage: https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts + networkInterfaces: + - network: $(ref.antmedia-vpc-network.selfLink) + subnetwork: $(ref.origin-subnet.selfLink) + # Access Config required to give the instance a public IP address + accessConfigs: + - name: External NAT + type: ONE_TO_ONE_NAT + tags: + items: + - antmedia-mongodb diff --git a/gcp-jinja-template/antmedia-vpc-template.jinja b/gcp-jinja-template/antmedia-vpc-template.jinja new file mode 100644 index 00000000..2e365253 --- /dev/null +++ b/gcp-jinja-template/antmedia-vpc-template.jinja @@ -0,0 +1,33 @@ +resources: +- name: antmedia-vpc-network + type: compute.v1.network + properties: + region: {{ properties["region"] }} + autoCreateSubnetworks: false + +- name: origin-subnet + type: compute.v1.subnetwork + properties: + ipCidrRange: 10.0.1.0/24 + network: $(ref.antmedia-vpc-network.selfLink) + region: {{ properties["region"] }} + +- name: edge-subnet + type: compute.v1.subnetwork + properties: + ipCidrRange: 10.0.2.0/24 + network: $(ref.antmedia-vpc-network.selfLink) + region: {{ properties["region"] }} + +- name: firewall-rule + type: compute.v1.firewall + properties: + network: $(ref.antmedia-vpc-network.selfLink) + sourceRanges: + - 0.0.0.0/0 + allowed: + - IPProtocol: tcp + ports: + - "80" + - "443" + - "22" diff --git a/gcp-jinja-template/antmedia.jinja b/gcp-jinja-template/antmedia.jinja new file mode 100644 index 00000000..8af57d07 --- /dev/null +++ b/gcp-jinja-template/antmedia.jinja @@ -0,0 +1,58 @@ +{# +Copyright 2016 Google Inc. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +#} + +{% set default_zone = "us-central1-a" %} +{% set default_region = "us-central1" %} +{% set mongodb_machine_type = "e2-standard-2" %} +{% set origin_machine_type = "c2d-standard-4" %} +{% set edge_machine_type = "c2d-standard-4" %} +{% set image_id = "ams-latest" %} + + + +resources: +- name: antmedia-mongodb + type: antmedia-mongodb-template.jinja + properties: + zone: {{ default_zone }} + machine_type: {{ mongodb_machine_type }} +- name: antmedia-instance + type: antmedia-instance-template.jinja + properties: + zone: {{ default_zone }} + origin_machine_type: {{ origin_machine_type }} + edge_machine_type: {{ edge_machine_type }} + image_id: {{ image_id }} + +- name: antmedia-instance-group + type: antmedia-instance-group-template.jinja + properties: + zone: {{ default_zone }} +- name: antmedia-loadbalancer + type: antmedia-loadbalancer-template.jinja + properties: + zone: {{ default_zone }} + region: {{ default_region}} +- name: antmedia-firewall + type: antmedia-firewall-template.jinja + properties: + zone: {{ default_zone}} +- name: antmedia-vpc-network + type: antmedia-vpc-template.jinja + properties: + region: {{ default_region}} + autoCreateSubnetworks: false + + \ No newline at end of file diff --git a/gcp-jinja-template/antmedia.yaml b/gcp-jinja-template/antmedia.yaml new file mode 100644 index 00000000..f1baae8c --- /dev/null +++ b/gcp-jinja-template/antmedia.yaml @@ -0,0 +1,26 @@ +# Copyright 2016 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +imports: +- path: antmedia-vpc-template.jinja +- path: antmedia-mongodb-template.jinja +- path: antmedia-instance-template.jinja +- path: antmedia-instance-group-template.jinja +- path: antmedia-firewall-template.jinja +- path: antmedia-loadbalancer-template.jinja +- path: antmedia.jinja + +resources: +- name: antmedia + type: antmedia.jinja diff --git a/gcp-jinja-template/backend.jinja b/gcp-jinja-template/backend.jinja new file mode 100644 index 00000000..3f018c9c --- /dev/null +++ b/gcp-jinja-template/backend.jinja @@ -0,0 +1,16 @@ +--- +# Your resource definitions go here under resources key +resources: + - name: my-backend-service # Replace with your desired name + type: compute.v1.backendService # Adjust type based on resource + properties: + portName: http + protocol: HTTP + backend: + group: origin-instance-group # Assuming your instance group name + healthChecks: + - https://www.googleapis.com/compute/v1/healthChecks/default + +# You can add other outputs here if needed +output: + # ... diff --git a/install_ant-media-server.sh b/install_ant-media-server.sh index 76ad259c..7634fa9e 100755 --- a/install_ant-media-server.sh +++ b/install_ant-media-server.sh @@ -25,7 +25,6 @@ RED='\033[0;31m' NC='\033[0m' #version that is being installed. It's get filled below VERSION= -VERSION_NAME=$(curl -s https://antmedia.io/download/latest-version.json | jq -r '.versionName') update_script () { SCRIPT_NAME="$0" @@ -162,7 +161,7 @@ distro () { os_release="/etc/os-release" if [ -f "$os_release" ]; then . $os_release - msg="We are supporting Ubuntu 18.04, Ubuntu 20.04, Ubuntu 22.04, Centos 8, Centos 9, RockyLinux 8, RockyLinux 9, AlmaLinux 8 and AlmaLinux 9" + msg="We are supporting Ubuntu 20.04, Ubuntu 22.04, Ubuntu 24.04, Centos 9, RockyLinux 9 and AlmaLinux 9" if [ "$OTHER_DISTRO" == "true" ]; then echo -e """\n- OpenJDK 11 (openjdk-11-jdk)\n- De-archiver (unzip)\n- Commons Daemon (jsvc)\n- Apache Portable Runtime Library (libapr1)\n- SSL Development Files (libssl-dev)\n- Video Acceleration (VA) API (libva-drm2)\n- Video Acceleration (VA) API - X11 runtime (libva-x11-2)\n- Video Decode and Presentation API Library (libvdpau-dev)\n- Crystal HD Video Decoder Library (libcrystalhd-dev)\n""" read -p 'Are you sure that the above packages are installed? Y/N ' CUSTOM_PACKAGES @@ -177,13 +176,13 @@ distro () { $SUDO apt-get update && $SUDO apt-get install coreutils CUSTOM_JVM=$DEFAULT_JAVA fi - elif [ "$ID" == "ubuntu" ] || [ "$ID" == "centos" ] || [ "$ID" == "rocky" ] || [ "$ID" == "almalinux" ] || [ "$ID" == "rhel" ]; then + elif [ "$ID" == "ubuntu" ] || [ "$ID" == "centos" ] || [ "$ID" == "rocky" ] || [ "$ID" == "almalinux" ] || [ "$ID" == "rhel" ] || [ "$ID" == "debian" ]; then if [ "$VERSION_ID" == "18.04" ] && [ "aarch64" == $ARCH ]; then echo -e "ARM architecture is supported on Ubuntu 20.04. For 18.04 installation, use the link below to install.\nhttps://github.com/ant-media/Ant-Media-Server/wiki/Frequently-Asked-Questions#how-can-i-install-the-ant-media-server-on-ubuntu-1804-with-arm64" exit 1 fi - if [[ $VERSION_ID != 18.04 ]] && [[ $VERSION_ID != 20.04 ]] && [[ $VERSION_ID != 22.04 ]] && [[ $VERSION_ID != 8* ]] && [[ $VERSION_ID != 9* ]]; then + if [[ $VERSION_ID != 20.04 ]] && [[ $VERSION_ID != 22.04 ]] && [[ $VERSION_ID != 24.04 ]] && [[ $VERSION_ID != 9* ]] && [[ $VERSION_ID != 12 ]] && [[ $VERSION_ID != 11 ]]; then echo $msg exit 1 fi @@ -263,7 +262,7 @@ if [ "$UPDATE" == "true" ]; then fi if [ -z "$ANT_MEDIA_SERVER_ZIP_FILE" ]; then - if [ "$ID" == "ubuntu" ]; then + if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then #Added curl package for the minimal OS installations. $SUDO apt-get update $SUDO apt-get install jq curl -y @@ -276,11 +275,12 @@ if [ -z "$ANT_MEDIA_SERVER_ZIP_FILE" ]; then curl --progress-bar -o ams_community.zip -L "$(curl -s -H "Accept: application/vnd.github+json" https://api.github.com/repos/ant-media/Ant-Media-Server/releases/latest | jq -r '.assets[0].browser_download_url')" ANT_MEDIA_SERVER_ZIP_FILE="ams_community.zip" elif [ -n "${LICENSE_KEY}" ]; then - check_license=$(curl -s https://api.antmedia.io/?license="${LICENSE_KEY}" | tr -d "\"") + check_license=$(curl -s https://api-v2.antmedia.io/?license="${LICENSE_KEY}" | tr -d "\"") if [ "$check_license" == "401" ]; then echo "Invalid license key. Please check your license key." exit 1 else + VERSION_NAME=$(curl -s https://antmedia.io/download/latest-version.json | jq -r '.versionName') echo "The license key is valid. Downloading the latest version ($VERSION_NAME) of Ant Media Server Enterprise Edition." curl --progress-bar -o ams_enterprise.zip "$check_license" ANT_MEDIA_SERVER_ZIP_FILE="ams_enterprise.zip" @@ -312,7 +312,7 @@ fi REQUIRED_VERSION="2.6" -if [ "$ID" == "ubuntu" ]; then +if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then $SUDO apt-get update -y $SUDO apt-get install unzip zip libva-drm2 libva-x11-2 libvdpau-dev -y $SUDO unzip -o $ANT_MEDIA_SERVER_ZIP_FILE "ant-media-server/ant-media-server.jar" -d /tmp/ @@ -358,8 +358,8 @@ unzip $ANT_MEDIA_SERVER_ZIP_FILE check -if [[ $VERSION == 2.1* || $VERSION == 2.0* || $VERSION == 1.* ]]; then - if [ "$ID" == "ubuntu" ]; then +if [[ $VERSION == 2.1\.+.* || $VERSION == 2.0* || $VERSION == 1.* ]]; then + if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then $SUDO apt-get install openjdk-8-jre -y $SUDO apt purge openjfx libopenjfx-java libopenjfx-jni -y $SUDO apt install openjfx=8u161-b12-1ubuntu2 libopenjfx-java=8u161-b12-1ubuntu2 libopenjfx-jni=8u161-b12-1ubuntu2 -y @@ -377,14 +377,14 @@ if [[ $VERSION == 2.1* || $VERSION == 2.0* || $VERSION == 1.* ]]; then elif [[ $VERSION == 2.4* || $VERSION == 2.3* || $VERSION == 2.2* ]]; then - if [ "$ID" == "ubuntu" ]; then + if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then $SUDO apt-get update -y $SUDO apt-get install openjdk-11-jdk -y check fi elif [[ $VERSION == 2.5* || $VERSION == 2.6* || $VERSION == 2.7* ]]; then - if [ "$ID" == "ubuntu" ]; then + if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then $SUDO apt-get update -y $SUDO apt-get install openjdk-11-jre-headless -y check @@ -400,7 +400,7 @@ elif [[ $VERSION == 2.5* || $VERSION == 2.6* || $VERSION == 2.7* ]]; then else # with 2.8 we start to use java17 - if [ "$ID" == "ubuntu" ]; then + if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then $SUDO apt-get update -y $SUDO apt-get install openjdk-17-jre-headless -y check diff --git a/kubernetes/ams-k8s-deployment-edge.yaml b/kubernetes/ams-k8s-deployment-edge.yaml index 2289bf36..71b3d938 100644 --- a/kubernetes/ams-k8s-deployment-edge.yaml +++ b/kubernetes/ams-k8s-deployment-edge.yaml @@ -45,8 +45,29 @@ spec: # You may also need to add -u and -p parameters for # specifying mongodb username and passwords respectively args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] + volumeMounts: + - mountPath: /tmp + name: temp-volume + livenessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 resources: requests: cpu: 4000m + volumes: + - hostPath: + path: /temp-data + type: DirectoryOrCreate + name: temp-volume + # imagePullSecrets: # - name: docker diff --git a/kubernetes/ams-k8s-deployment-origin.yaml b/kubernetes/ams-k8s-deployment-origin.yaml index df62784e..ec0982c9 100644 --- a/kubernetes/ams-k8s-deployment-origin.yaml +++ b/kubernetes/ams-k8s-deployment-origin.yaml @@ -45,8 +45,29 @@ spec: # You may also need to add -u and -p parameters for # specifying mongodb username and passwords respectively args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] + volumeMounts: + - mountPath: /tmp + name: temp-volume + livenessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 resources: requests: cpu: 4000m + volumes: + - hostPath: + path: /temp-data + type: DirectoryOrCreate + name: temp-volume + # imagePullSecrets: # - name: docker diff --git a/kubernetes/ams-k8s-ingress-edge.yaml b/kubernetes/ams-k8s-ingress-edge.yaml index aa978215..cfae5895 100644 --- a/kubernetes/ams-k8s-ingress-edge.yaml +++ b/kubernetes/ams-k8s-ingress-edge.yaml @@ -10,6 +10,7 @@ metadata: nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" nginx.org/websocket-services: "ant-media-server" nginx.ingress.kubernetes.io/websocket-services : "ant-media-server" + nginx.ingress.kubernetes.io/proxy-body-size: "0m" spec: rules: - host: test.antmedia.cloud diff --git a/kubernetes/ams-k8s-ingress-origin.yaml b/kubernetes/ams-k8s-ingress-origin.yaml index 29df4e16..651ac640 100644 --- a/kubernetes/ams-k8s-ingress-origin.yaml +++ b/kubernetes/ams-k8s-ingress-origin.yaml @@ -10,6 +10,7 @@ metadata: nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" nginx.org/websocket-services: "ant-media-server" nginx.ingress.kubernetes.io/websocket-services : "ant-media-server" + nginx.ingress.kubernetes.io/proxy-body-size: "0m" spec: rules: - host: test.antmedia.cloud diff --git a/kubernetes/ams-k8s-mongodb.yaml b/kubernetes/ams-k8s-mongodb.yaml index 0c9229bd..46427a6e 100644 --- a/kubernetes/ams-k8s-mongodb.yaml +++ b/kubernetes/ams-k8s-mongodb.yaml @@ -26,7 +26,7 @@ spec: containers: - name: mongodb imagePullPolicy: Always - image: mongo:5.0.6 + image: mongo:6.0 ports: - containerPort: 27017 diff --git a/kubernetes/ams-with-turn-server/ams-k8s-deployment-edge.yaml b/kubernetes/ams-with-turn-server/ams-k8s-deployment-edge.yaml index 9b6130b9..33a289c2 100644 --- a/kubernetes/ams-with-turn-server/ams-k8s-deployment-edge.yaml +++ b/kubernetes/ams-with-turn-server/ams-k8s-deployment-edge.yaml @@ -34,8 +34,29 @@ spec: # specifying mongodb username and passwords respectively # args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] args: ["-r", "true", "-m", "cluster", "-h", "mongo"] + volumeMounts: + - mountPath: /tmp + name: temp-volume + livenessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 resources: requests: cpu: 4000m + volumes: + - hostPath: + path: /temp-data + type: DirectoryOrCreate + name: temp-volume + # imagePullSecrets: # - name: docker diff --git a/kubernetes/ams-with-turn-server/ams-k8s-deployment-origin.yaml b/kubernetes/ams-with-turn-server/ams-k8s-deployment-origin.yaml index 5146252e..43a0039c 100644 --- a/kubernetes/ams-with-turn-server/ams-k8s-deployment-origin.yaml +++ b/kubernetes/ams-with-turn-server/ams-k8s-deployment-origin.yaml @@ -34,8 +34,29 @@ spec: # specifying mongodb username and passwords respectively # args: ["-g", "true", "-s", "true", "-r", "true", "-m", "cluster", "-h", "mongo"] args: ["-r", "true", "-m", "cluster", "-h", "mongo"] + volumeMounts: + - mountPath: /tmp + name: temp-volume + livenessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 5080 + initialDelaySeconds: 30 + periodSeconds: 10 resources: requests: cpu: 4000m + volumes: + - hostPath: + path: /temp-data + type: DirectoryOrCreate + name: temp-volume + # imagePullSecrets: # - name: docker diff --git a/kubernetes/ams-with-turn-server/ams-k8s-ingress-edge.yaml b/kubernetes/ams-with-turn-server/ams-k8s-ingress-edge.yaml index 7a8fb870..787536dd 100644 --- a/kubernetes/ams-with-turn-server/ams-k8s-ingress-edge.yaml +++ b/kubernetes/ams-with-turn-server/ams-k8s-ingress-edge.yaml @@ -8,6 +8,7 @@ metadata: nginx.ingress.kubernetes.io/session-cookie-name: "route" nginx.ingress.kubernetes.io/session-cookie-expires: "172800" nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" + nginx.ingress.kubernetes.io/proxy-body-size: "0m" spec: rules: - host: edge.antmedia.cloud diff --git a/kubernetes/ams-with-turn-server/ams-k8s-ingress-origin.yaml b/kubernetes/ams-with-turn-server/ams-k8s-ingress-origin.yaml index 97f9c213..97d1d12e 100644 --- a/kubernetes/ams-with-turn-server/ams-k8s-ingress-origin.yaml +++ b/kubernetes/ams-with-turn-server/ams-k8s-ingress-origin.yaml @@ -8,6 +8,7 @@ metadata: nginx.ingress.kubernetes.io/session-cookie-name: "route" nginx.ingress.kubernetes.io/session-cookie-expires: "172800" nginx.ingress.kubernetes.io/session-cookie-max-age: "172800" + nginx.ingress.kubernetes.io/proxy-body-size: "0m" spec: rules: - host: origin.antmedia.cloud diff --git a/kubernetes/ams-with-turn-server/ams-k8s-mongodb.yaml b/kubernetes/ams-with-turn-server/ams-k8s-mongodb.yaml index 0c9229bd..46427a6e 100644 --- a/kubernetes/ams-with-turn-server/ams-k8s-mongodb.yaml +++ b/kubernetes/ams-with-turn-server/ams-k8s-mongodb.yaml @@ -26,7 +26,7 @@ spec: containers: - name: mongodb imagePullPolicy: Always - image: mongo:5.0.6 + image: mongo:6.0 ports: - containerPort: 27017 diff --git a/load-testing/.gitkeep b/load-testing/.gitkeep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/load-testing/.gitkeep @@ -0,0 +1 @@ + diff --git a/load-testing/hls_players.sh b/load-testing/hls_players.sh new file mode 100644 index 00000000..a6e10424 --- /dev/null +++ b/load-testing/hls_players.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +m3u8_url=$1 +viewers=$2 + +for (( i=1; i <= $viewers; ++i )) +do + COMMAND="ffmpeg -i "$m3u8_url" -codec copy -f null /dev/null" + $COMMAND &>>/dev/null & + echo "running command $COMMAND" + done diff --git a/load-testing/rtmp_publisher.sh b/load-testing/rtmp_publisher.sh new file mode 100644 index 00000000..20f0bee2 --- /dev/null +++ b/load-testing/rtmp_publisher.sh @@ -0,0 +1,12 @@ +#!/bin/bash +file=$1 +server=$2 +noofclients=$3 + +for (( i=1; i <= $noofclients; ++i )) +do + COMMAND="ffmpeg -re -stream_loop -1 -i ${file} -codec copy -f flv ${server}_${i}" + $COMMAND >/dev/null 2>&1 & + echo "running command $COMMAND" + sleep 1 +done diff --git a/load-testing/srt_publishers.sh b/load-testing/srt_publishers.sh new file mode 100644 index 00000000..f2f5cbe4 --- /dev/null +++ b/load-testing/srt_publishers.sh @@ -0,0 +1,12 @@ +#!/bin/bash +file=$1 +server=$2 +noofclients=$3 + +for (( i=1; i <= $noofclients; ++i )) +do + COMMAND="ffmpeg -re -stream_loop -1 -i ${file} -codec copy -f mpegts ${server}_${i}" + $COMMAND >/dev/null 2>&1 & + echo "running command $COMMAND" + sleep 1 +done diff --git a/monitor/ams-new-relic-dashboard.json b/monitor/ams-new-relic-dashboard.json new file mode 100644 index 00000000..f872a29b --- /dev/null +++ b/monitor/ams-new-relic-dashboard.json @@ -0,0 +1,397 @@ +{ + "name": "Ant Media Server", + "description": null, + "permissions": "PUBLIC_READ_WRITE", + "pages": [ + { + "name": "Ant Media Server", + "description": null, + "widgets": [ + { + "title": "DASH Viewer Counts", + "layout": { + "column": 1, + "row": 1, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.pie" + }, + "rawConfiguration": { + "colors": { + "seriesOverrides": [ + { + "color": "#339ac7", + "seriesName": "LiveApp, stream1" + } + ] + }, + "facet": { + "showOtherSeries": true + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(dashViewerCount) AS 'DASH Viewer Count'\nFROM Log\nWHERE event = 'viewerCount' FACET app, streamId \nSINCE 1 minutes ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "HLS Viewer Counts", + "layout": { + "column": 5, + "row": 1, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.pie" + }, + "rawConfiguration": { + "colors": { + "seriesOverrides": [ + { + "color": "#cdc837", + "seriesName": "LiveApp, stream1" + } + ] + }, + "facet": { + "showOtherSeries": true + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(hlsViewerCount) AS 'HLS Viewer Count'\nFROM Log\nWHERE event = 'viewerCount' FACET app, streamId \nSINCE 1 minutes ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "WebRTC Viewer Counts", + "layout": { + "column": 9, + "row": 1, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.pie" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": true + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(webRTCViewerCount) AS 'WebRTC Viewer Count'\nFROM Log\nWHERE event = 'viewerCount' FACET app, streamId \nSINCE 1 minutes ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Publisher Statistics", + "layout": { + "column": 1, + "row": 4, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(timestamp) FROM Log WHERE event = 'publishStarted' FACET streamId, app, protocol, videoCodec, audioCodec, height, width SINCE 1 day ago" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Stream Start and End Times", + "layout": { + "column": 7, + "row": 4, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT\n filter(latest(timestamp), WHERE event = 'publishStarted') AS 'publishStarted',\n filter(latest(timestamp), WHERE event = 'publishEnded') AS 'publishEnded'\nFROM\n Log\nWHERE\n (event = 'publishStarted' OR event = 'publishEnded')\nFACET\n streamId, app\nSINCE\n 1 day ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Subscriber Playback Duration", + "layout": { + "column": 1, + "row": 7, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "FROM Log\nSELECT \n filter(latest(timestamp), WHERE event = 'playStartedFirstTime') AS 'playStartTime',\n filter(latest(timestamp), WHERE event = 'playEnded') AS 'playEndTime',\n (filter(latest(timestamp), WHERE event = 'playEnded') - filter(latest(timestamp), WHERE event = 'playStartedFirstTime')) / 1000 / 60 AS 'playDurationMinutes'\nWHERE event IN ('playStartedFirstTime', 'playEnded')\nFACET subscriberId, app, streamId\nSINCE 1 day ago" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Per User Total Transferred (Mb)", + "layout": { + "column": 7, + "row": 7, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.bar" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(numeric(totalBytesTransferred)) / 1048576 as 'Per User Total Transferred' \nFROM Log \nWHERE event = 'playerStats'\nFACET subscriberId, app, streamId SINCE 1 day ago" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "First Play Time per Subscriber", + "layout": { + "column": 1, + "row": 10, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.bar" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(timestamp)\nFROM Log\nWHERE event = 'playStartedFirstTime'\nFACET subscriberId\nSINCE 1 day ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Start time of the viewers", + "layout": { + "column": 5, + "row": 10, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.pie" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": true + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(timestamp)\nFROM Log\nWHERE event = 'playStarted'\nFACET subscriberId\nSINCE 1 day ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "End time of the viewers", + "layout": { + "column": 9, + "row": 10, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.pie" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": true + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(timestamp)\nFROM Log\nWHERE event = 'playEnded'\nFACET subscriberId\nSINCE 1 day ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Subscriber Statistics", + "layout": { + "column": 1, + "row": 13, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "initialSorting": { + "direction": "desc", + "name": "Timestamp" + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(protocol), latest(clientIP), latest(timestamp)\nFROM Log\nWHERE event = 'watchTime'\nFACET subscriberId\nSINCE 1 day ago\n" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Key Frame Interval ", + "layout": { + "column": 5, + "row": 13, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + 0000000 + ], + "query": "SELECT latest(timestamp) FROM Log WHERE event = 'keyFrameStats' FACET streamId, app, keyFramesInLastMinute, keyFrameIntervalMs SINCE 1 day ago" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + } + ] + } + ], + "variables": [] +} diff --git a/nginx/install_and_configure_nginx.sh b/nginx/install_and_configure_nginx.sh index 03281788..cd11eef2 100644 --- a/nginx/install_and_configure_nginx.sh +++ b/nginx/install_and_configure_nginx.sh @@ -66,8 +66,10 @@ update_nginx_config() { # Generate the server blocks configuration based on the IP addresses origin_server_blocks="" + origin_server_blocks_backup="" for ip in "${origin_server_ips[@]}"; do origin_server_blocks+="\n server $ip:$HTTP_PORT;\n" + origin_server_blocks_backup+="\n server $ip:$HTTP_PORT backup;\n" done rtmp_origin_server_blocks="" @@ -81,14 +83,21 @@ update_nginx_config() { done edge_server_blocks="" + edge_server_blocks_backup="" for ip in "${edge_server_ips[@]}"; do edge_server_blocks+="\n server $ip:$HTTP_PORT;\n" + edge_server_blocks_backup+="\n server $ip:$HTTP_PORT backup;\n" done + sudo sed -i "s/{{ORIGIN_SERVER_BLOCKS}}/$origin_server_blocks/g" $nginx_config + sudo sed -i "s/{{ORIGIN_SERVER_BLOCKS_BACKUP}}/$edge_server_blocks_backup/g" $nginx_config #put edge servers as backup for origin servers + sudo sed -i "s/{{RTMP_SERVER_BLOCKS}}/$rtmp_origin_server_blocks/g" $nginx_config sudo sed -i "s/{{ORIGIN_SRT_SERVER_BLOCKS}}/$srt_origin_server_blocks/g" $nginx_config sudo sed -i "s/{{EDGE_SERVER_BLOCKS}}/$edge_server_blocks/g" $nginx_config + sudo sed -i "s/{{EDGE_SERVER_BLOCKS_BACKUP}}/$origin_server_blocks_backup/g" $nginx_config #put origin servers as backup for edge servers + sudo sed -i "s/{{YOUR_DOMAIN}}/$domain/g" $nginx_config # Check if a ssl enabled name is provided diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 5aae833e..31c8cc70 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -54,6 +54,7 @@ http { upstream antmedia_origin { least_conn; {{ORIGIN_SERVER_BLOCKS}} + {{ORIGIN_SERVER_BLOCKS_BACKUP}} #server {AMS_ORIGIN1_IP}:5080; } @@ -62,6 +63,7 @@ http { upstream antmedia_edge { least_conn; {{EDGE_SERVER_BLOCKS}} + {{EDGE_SERVER_BLOCKS_BACKUP}} #server {AMS_EDGE1_IP}:5080; } diff --git a/vod_transcode.sh b/vod_transcode.sh index 942377f2..3d5e1bc3 100644 --- a/vod_transcode.sh +++ b/vod_transcode.sh @@ -1,29 +1,37 @@ #!/bin/bash # -# This bash script converts your VoD files to HLS format. (720p,480p,240p) +# This bash script converts your VoD files to HLS format. (720p, 480p, 240p) # # Installation Instructions # sudo apt-get update && sudo apt-get install ffmpeg -y -# vim [AMS-DIR]/webapps/applications(LiveApp or etc.)/WEB-INF/red5-web.properties -# settings.vodUploadFinishScript=/Script-DIR/vod_transcode.sh +# switch to application advance properties and set the property, +# "vodUploadFinishScript": "/path/to/vod_transcode.sh ", # sudo service antmedia restart -# -# Don't forget to change the Ant Media Server App Name +# Don't forget to change the Ant Media Server App Name in which you want to save the files AMS_APP_NAME="WebRTCAppEE" file=$1 file_name=$(basename $file .mp4) -# Bitrates -# 720p -a=("1280x720" "2500k") -# 480p -b=("640x480" "1500k") -# 240p -c=("320x240" "800k") - +# Bitrates and resolutions +resolutions=("1280x720" "640x480" "320x240") +bitrates=("2500k" "1500k" "800k") +names=("720p" "480p" "240p") cd /usr/local/antmedia/webapps/$AMS_APP_NAME/streams/ -$(command -v ffmpeg) -i $file -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 -s:v:0 ${a[0]} -c:v:0 libx264 -b:v:0 ${a[1]} -s:v:1 ${b[0]} -c:v:1 libx264 -b:v:1 ${b[1]} -s:v:2 ${c[0]} -c:v:2 libx264 -b:v:2 ${c[1]} -c:a aac -f hls -hls_playlist_type vod -master_pl_name ${file_name}.m3u8 -hls_segment_filename ${file_name}_%v/${file_name}%04d.ts -use_localtime_mkdir 1 -var_stream_map "v:0,a:0,name:720p v:1,a:1,name:480p v:2,a:2,name:360p" ${file_name}_%v.m3u8 +# Create directories for each resolution +for name in "${names[@]}"; do + mkdir -p ${file_name}_${name} +done + +$(command -v ffmpeg) -i $file \ + -map 0:v -map 0:a -s:v:0 ${resolutions[0]} -c:v:0 libx264 -b:v:0 ${bitrates[0]} \ + -map 0:v -map 0:a -s:v:1 ${resolutions[1]} -c:v:1 libx264 -b:v:1 ${bitrates[1]} \ + -map 0:v -map 0:a -s:v:2 ${resolutions[2]} -c:v:2 libx264 -b:v:2 ${bitrates[2]} \ + -c:a aac -f hls -hls_playlist_type vod \ + -master_pl_name ${file_name}.m3u8 \ + -hls_segment_filename ${file_name}_%v/${file_name}%04d.ts \ + -var_stream_map "v:0,a:0,name:720p v:1,a:1,name:480p v:2,a:2,name:240p" \ + ${file_name}_%v/${file_name}.m3u8