From fb19544718fb5c6abd496e0bd490797e52dfe28f Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Wed, 1 May 2024 10:41:09 +0300 Subject: [PATCH] Revise pjsua role - changed default version to 2.14.1 - ensured that tutorial call scrips still use 2.9 - made role idempotent - added pjsua_helper_scripts default var that if set to true will deploy two scripts: pjsua_listen and pjsua_call (defaults to false) - added option to decide whether we delete the pjsua repo post install - made binary path configurable (will be used for both pjsua as well as the helper scripts - use copy instead of command when copying binary to its final path - import roles directly instead of through tasks where applicable (call roles) --- data/ansible/calls/asterisk/main.yaml | 23 ++--- data/ansible/calls/freeswitch/main.yaml | 30 +++--- data/ansible/calls/kamailio/main.yaml | 20 ++-- data/ansible/roles/pjsua/defaults/main.yaml | 13 +-- data/ansible/roles/pjsua/files/pjsua_call | 107 ++++++++++++++++++++ data/ansible/roles/pjsua/files/pjsua_listen | 107 ++++++++++++++++++++ data/ansible/roles/pjsua/tasks/main.yaml | 57 ++++++++--- 7 files changed, 292 insertions(+), 65 deletions(-) create mode 100755 data/ansible/roles/pjsua/files/pjsua_call create mode 100755 data/ansible/roles/pjsua/files/pjsua_listen diff --git a/data/ansible/calls/asterisk/main.yaml b/data/ansible/calls/asterisk/main.yaml index ce76284d8..90367ea94 100644 --- a/data/ansible/calls/asterisk/main.yaml +++ b/data/ansible/calls/asterisk/main.yaml @@ -1,19 +1,10 @@ --- - name: Set up environment in order to run call tests for Asterisk hosts: all - tasks: - - name: Install Go - import_role: - name: ../../roles/go - - - name: Install and configure CGRateS - import_role: - name: ../../roles/cgrates - - - name: Install Asterisk - import_role: - name: ../../roles/asterisk - - - name: Install PJSUA - import_role: - name: ../../roles/pjsua + roles: + - ../../roles/go + - ../../roles/cgrates + - ../../roles/asterisk + - role: ../../roles/pjsua + vars: + pjsua_version: '2.9' diff --git a/data/ansible/calls/freeswitch/main.yaml b/data/ansible/calls/freeswitch/main.yaml index bcd069080..67334df84 100644 --- a/data/ansible/calls/freeswitch/main.yaml +++ b/data/ansible/calls/freeswitch/main.yaml @@ -3,46 +3,48 @@ hosts: all tasks: - name: Install freeswitch - import_role: + ansible.builtin.import_role: name: ../../roles/freeswitch - name: Install Go - import_role: + ansible.builtin.import_role: name: ../../roles/go - name: Install and config CGRateS - import_role: + ansible.builtin.import_role: name: ../../roles/cgrates - name: Unzip FreeSWITCH config become: yes - shell: "sudo tar -xvf freeswitch_conf.tar.gz" + shell: 'sudo tar -xvf freeswitch_conf.tar.gz' args: - chdir: "{{ cgrates_dir }}/data/tutorial_tests/fs_evsock/freeswitch/etc" + chdir: '{{ cgrates_dir }}/data/tutorial_tests/fs_evsock/freeswitch/etc' - name: Unzip FreeSWITCH config 2 become: yes - shell: "sudo tar -xvf freeswitch_conf.tar.gz" + shell: 'sudo tar -xvf freeswitch_conf.tar.gz' args: - chdir: "{{ cgrates_dir }}/data/tutorials/fs_evsock/freeswitch/etc" + chdir: '{{ cgrates_dir }}/data/tutorials/fs_evsock/freeswitch/etc' - name: Update internal.xml with the correct IP ansible.builtin.replace: - path: "{{ cgrates_dir }}/data/tutorial_tests/fs_evsock/freeswitch/etc/freeswitch/sip_profiles/internal.xml" + path: '{{ cgrates_dir }}/data/tutorial_tests/fs_evsock/freeswitch/etc/freeswitch/sip_profiles/internal.xml' regexp: '192\.168\.56\.203' - replace: "{{ ansible_host }}" + replace: '{{ ansible_host }}' - name: Remove FreeSWITCH default config from /etc/freeswitch become: yes - shell: "sudo rm -rf *" + shell: 'sudo rm -rf *' args: - chdir: "/etc/freeswitch" + chdir: '/etc/freeswitch' - name: Copy our custom config for FreeSWITCH in /etc/freeswitch become: yes - shell: "sudo cp -r {{ cgrates_dir }}/data/tutorial_tests/fs_evsock/freeswitch/etc/freeswitch/* /etc/freeswitch" + shell: 'sudo cp -r {{ cgrates_dir }}/data/tutorial_tests/fs_evsock/freeswitch/etc/freeswitch/* /etc/freeswitch' args: - chdir: "/etc/freeswitch" + chdir: '/etc/freeswitch' - name: Configure PJSUA - import_role: + ansible.builtin.import_role: name: ../../roles/pjsua + vars: + pjsua_version: '2.9' diff --git a/data/ansible/calls/kamailio/main.yaml b/data/ansible/calls/kamailio/main.yaml index e3b745015..cb3aac0c8 100644 --- a/data/ansible/calls/kamailio/main.yaml +++ b/data/ansible/calls/kamailio/main.yaml @@ -1,18 +1,12 @@ --- - hosts: all - tasks: - - name: Install Kamailio - import_role: - name: ../../roles/kamailio + roles: + - ../../roles/kamailio - - name: Install Go - import_role: - name: ../../roles/go + - ../../roles/go - - name: Install and configure CGRateS - import_role: - name: ../../roles/cgrates + - ../../roles/cgrates - - name: Install PJSUA - import_role: - name: ../../roles/pjsua + - role: ../../roles/pjsua + vars: + pjsua_version: '2.9' diff --git a/data/ansible/roles/pjsua/defaults/main.yaml b/data/ansible/roles/pjsua/defaults/main.yaml index 273ed18fe..04543c672 100644 --- a/data/ansible/roles/pjsua/defaults/main.yaml +++ b/data/ansible/roles/pjsua/defaults/main.yaml @@ -1,10 +1,11 @@ --- -pjsua_version: "2.9" -pjsua_url: "https://github.com/pjsip/pjproject/archive/refs/tags/{{ pjsua_version }}.tar.gz" -tmp_dir: "/tmp" - -# PJSUA dependencies +pjsua_version: '2.14.1' +pjsua_url: 'https://github.com/pjsip/pjproject/archive/refs/tags/{{ pjsua_version }}.tar.gz' +pjsua_tmp_install_dir: '/tmp' +pjsua_post_install_cleanup: true +pjsua_bin_path: '/usr/local/bin' pjsua_dependencies: - libasound2-dev - libssl-dev - - build-essential \ No newline at end of file + - build-essential +pjsua_helper_scripts: false diff --git a/data/ansible/roles/pjsua/files/pjsua_call b/data/ansible/roles/pjsua/files/pjsua_call new file mode 100755 index 000000000..a44851c36 --- /dev/null +++ b/data/ansible/roles/pjsua/files/pjsua_call @@ -0,0 +1,107 @@ +#!/bin/bash + +# Default values +HOST=127.0.0.1 +LOCAL_PORT=$(comm -23 <(seq 32768 60999 | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) | shuf | head -n 1) +REGISTRAR_PORT=5060 +PASSWORD="CGRateS.org" +VERBOSE=false +DRYRUN=false + +# Parse command line options +OPTS=$(getopt -o f:t:d:p:r:P:vDh --long from:,to:,dur:,port:,registrar:,passwd:,verbose,dryrun,help -n "$(basename "$0")" -- "$@") +if [ $? -ne 0 ]; then + echo "Failed to parse options." >&2 + exit 1 +fi + +eval set -- "$OPTS" + +while true; do + case "$1" in + -f|--from) + from="$2" + shift 2 + ;; + -t|--to) + to="$2" + shift 2 + ;; + -d|--dur) + duration="$2" + shift 2 + ;; + -H|--host) + HOST=$2 + shift 2 + ;; + -p|--port) + LOCAL_PORT="$2" + shift 2 + ;; + -r|--registrar) + REGISTRAR_PORT="$2" + shift 2 + ;; + -P|--passwd) + PASSWORD="$2" + shift 2 + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -D|--dryrun) + DRYRUN=true + VERBOSE=true + shift + ;; + -h|--help) + echo "Usage: $(basename "$0") [OPTIONS]" + echo + echo "Options:" + echo "-f, --from ID of calling party" + echo "-t, --to ID of called party" + echo "-d, --dur Duration of the call" + echo "-H, --host Set the host of accounts" + echo " Defaults to 127.0.0.1" + echo "-p, --port Set the call port" + echo " Defaults to a random one" + echo "-r, --registrar Set the registrar port" + echo " Default: ${REGISTRAR_PORT}" + echo "-P, --passwd Input account password" + echo "-v, --verbose Print command before executing" + echo "-D, --dryrun Print command without executing" + echo "-h, --help Display this usage information" + + shift + exit 1 + ;; + --) + shift + break + ;; + *) + echo "Internal error!" + exit 1 + ;; + esac +done + +# Check for missing options +if [ -z "$from" ] || [ -z "$to" ] || [ -z "$duration" ]; then + echo "Mandatory options are missing: -f/--from, -t/--to, -d/--dur" + exit 1 +fi + +# Build the command +cmd="pjsua --null-audio --app-log-level=0 --local-port=${LOCAL_PORT} --duration=${duration} --outbound=sip:${HOST}:${REGISTRAR_PORT}" +cmd+=" --id=sip:${from}@${HOST} --username=${from} --password=${PASSWORD} --realm=* sip:${to}@${HOST}" + +# Execute the command +if [ "${VERBOSE}" = true ]; then + echo "Executing: ${cmd}" +fi +if [ "${DRYRUN}" = false ]; then + ${cmd} +fi \ No newline at end of file diff --git a/data/ansible/roles/pjsua/files/pjsua_listen b/data/ansible/roles/pjsua/files/pjsua_listen new file mode 100755 index 000000000..54440b79b --- /dev/null +++ b/data/ansible/roles/pjsua/files/pjsua_listen @@ -0,0 +1,107 @@ +#!/bin/bash + +# Default values +HOST=127.0.0.1 +LOCAL_PORT=$(comm -23 <(seq 32768 60999 | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) | shuf | head -n 1) +REGISTRAR_PORT=5060 +PASSWORD="CGRateS.org" +VERBOSE=false +DRYRUN=false + +# Parse command line options +OPTS=$(getopt -o a:H:p:r:P:vDh --long accounts:,host:,port:,registrar:,passwd:,verbose,dryrun,help -n "$(basename "$0")" -- "$@") +if [ $? -ne 0 ]; then + echo "Failed to parse options." >&2 + exit 1 +fi + +eval set -- "$OPTS" + +while true; do + case "$1" in + -a|--accounts) + IFS=',' read -r -a accounts <<< "$2" + shift 2 + ;; + -H|--host) + HOST=$2 + shift 2 + ;; + -p|--port) + LOCAL_PORT="$2" + shift 2 + ;; + -r|--registrar) + REGISTRAR_PORT="$2" + shift 2 + ;; + -P|--passwd) + PASSWORD="$2" + shift 2 + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -D|--dryrun) + DRYRUN=true + VERBOSE=true + shift + ;; + -h|--help) + echo "Usage: $(basename "$0") [OPTIONS]" + echo + echo "Options:" + echo "-a, --accounts List of accounts to register" + echo "-H, --host Set the host of account" + echo " Defaults to 127.0.0.1" + echo "-p, --port Set the PJSUA listener port" + echo " Defaults to a random one" + echo "-r, --registrar Set the registrar port" + echo " Default: ${REGISTRAR_PORT}" + echo "-P, --passwd Set account password" + echo "-v, --verbose Print command before executing" + echo "-D, --dryrun Print command without executing" + echo "-h, --help Display this usage information" + + shift + exit 1 + ;; + --) + shift + break + ;; + *) + echo "Internal error!" + exit 1 + ;; + esac +done + +# Check for missing accounts +if [ ${#accounts[@]} -eq 0 ]; then + echo "No accounts specified. Use -a or --accounts to specify comma-separated accounts." + exit 1 +fi + +# Start building the command +cmd="pjsua --local-port=${LOCAL_PORT} --null-audio --auto-answer=200 --max-calls=4 --app-log-level=0" + +# Add accounts +first=true +for acc in "${accounts[@]}"; do + if [ "${first}" != true ]; then + cmd+=" --next-account" + fi + first=false + cmd+=" --id=sip:${acc}@${HOST} --registrar=sip:${HOST}:${REGISTRAR_PORT} --username=${acc} --password=${PASSWORD} --realm=*" +done + +# Execute the command +if [ "${VERBOSE}" = true ]; then + echo "Executing: ${cmd}" +fi +if [ "${DRYRUN}" = false ]; then + ${cmd} +fi + diff --git a/data/ansible/roles/pjsua/tasks/main.yaml b/data/ansible/roles/pjsua/tasks/main.yaml index 41c9aea7d..7ae807069 100644 --- a/data/ansible/roles/pjsua/tasks/main.yaml +++ b/data/ansible/roles/pjsua/tasks/main.yaml @@ -1,38 +1,63 @@ --- +- name: Check if PJSUA is installed and get version + ansible.builtin.shell: + cmd: pjsua --version | grep 'PJ_VERSION' | awk '{print $NF}' + register: installed_pjsua_version + ignore_errors: true + changed_when: false + - name: Install PJSUA dependencies - become: yes + become: true ansible.builtin.package: name: '{{ pjsua_dependencies }}' state: present update_cache: yes - cache_valid_time: 86400 + when: installed_pjsua_version.stdout != pjsua_version - name: Download PJSUA ansible.builtin.get_url: - url: "{{ pjsua_url }}" - dest: "{{ tmp_dir }}/{{ pjsua_version }}.tar.gz" + url: '{{ pjsua_url }}' + dest: '{{ pjsua_tmp_install_dir }}/{{ pjsua_version }}.tar.gz' + when: installed_pjsua_version.stdout != pjsua_version - name: Unzip PJSUA - become: yes + become: true ansible.builtin.unarchive: - src: "{{ tmp_dir }}/{{ pjsua_version }}.tar.gz" - dest: "{{ tmp_dir }}" + src: '{{ pjsua_tmp_install_dir }}/{{ pjsua_version }}.tar.gz' + dest: '{{ pjsua_tmp_install_dir }}' remote_src: yes + when: installed_pjsua_version.stdout != pjsua_version - name: Install PJSUA - become: yes + become: true ansible.builtin.shell: cmd: './configure CFLAGS="$CFLAGS -fPIC" && make dep && make && make install' - chdir: '{{ tmp_dir }}/pjproject-{{ pjsua_version }}' + chdir: '{{ pjsua_tmp_install_dir }}/pjproject-{{ pjsua_version }}' + when: installed_pjsua_version.stdout != pjsua_version -- name: Copy PJSUA into /usr/bin - become: yes - ansible.builtin.command: - cmd: 'cp pjsua-x86_64-unknown-linux-gnu /usr/bin/pjsua' - chdir: '{{ tmp_dir }}/pjproject-{{ pjsua_version }}/pjsip-apps/bin' +- name: Copy PJSUA into configured bin path + become: true + ansible.builtin.copy: + src: '{{ pjsua_tmp_install_dir }}/pjproject-{{ pjsua_version }}/pjsip-apps/bin/pjsua-x86_64-unknown-linux-gnu' + dest: '{{ pjsua_bin_path }}/pjsua' + remote_src: yes + mode: '0755' + when: installed_pjsua_version.stdout != pjsua_version - name: Cleanup temporary PJSUA files - become: yes + become: true ansible.builtin.file: - path: '{{ tmp_dir }}/pjproject-{{ pjsua_version }}' + path: '{{ pjsua_tmp_install_dir }}/pjproject-{{ pjsua_version }}' state: absent + when: pjsua_post_install_cleanup | bool + +- name: Deploy pjsua helper scripts + become: true + ansible.builtin.copy: + src: '{{ item }}' + dest: '{{ pjsua_bin_path }}/{{ item }}' + mode: '0755' + loop: + - pjsua_call + - pjsua_listen + when: pjsua_helper_scripts | bool