From 3d689b2dcad798aba952a0623ec692930979e29c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 12 Dec 2024 11:58:07 +0200 Subject: [PATCH] New debian repository and 1.13 version --- en/general.rst | 6 +- en/installation/index.rst | 6 +- .../installation-1.10/call-trace.rst | 126 ----------- .../installation-1.10/cdr-database.rst | 94 -------- .../installation-1.10/cdr-export-download.png | Bin 62512 -> 0 bytes .../installation-1.10/cdr-export.rst | 91 -------- .../installation-1.10/database-tuning.rst | 32 --- en/installation/installation-1.10/index.rst | 27 --- .../installation-1.10/management.rst | 200 ----------------- en/installation/installation-1.10/redis.rst | 40 ---- .../installation-1.10/release-notes.rst | 19 -- .../installation-1.10/repositories.rst | 47 ---- .../installation-1.10/routing-database.rst | 69 ------ .../installation-1.10/sems-prometheus.rst | 34 --- en/installation/installation-1.10/sems.rst | 167 -------------- .../installation-1.10/upgrade-from-1.9.rst | 53 ----- en/installation/installation-1.10/web.rst | 204 ----------------- .../installation-1.10/yeti-web-prometheus.rst | 36 --- .../installation-1.11/call-trace.rst | 126 ----------- .../installation-1.11/cdr-export-download.png | Bin 62512 -> 0 bytes .../installation-1.11/cdr-export.rst | 91 -------- .../installation-1.11/release-notes.rst | 15 -- .../installation-1.11/repositories.rst | 27 --- .../installation-1.11/upgrade-from-1.10.rst | 130 ----------- .../cdr-database.rst | 8 +- .../index.rst | 10 +- .../redis.rst | 2 +- .../installation-1.13/release-notes.rst | 18 ++ .../installation-1.13/repositories.rst | 29 +++ .../routing-database.rst | 6 +- .../sems.rst | 106 +++++---- .../installation-1.13/upgrade-from-1.12.rst | 61 ++++++ .../web.rst | 144 +++++------- .../installation-1.7/call-trace.rst | 104 --------- .../installation-1.7/cdr-database.rst | 100 --------- .../installation-1.7/cli-utility.rst | 62 ------ .../installation-1.7/database-tuning.rst | 33 --- en/installation/installation-1.7/index.rst | 23 -- .../installation-1.7/management.rst | 194 ---------------- en/installation/installation-1.7/redis.rst | 31 --- .../installation-1.7/repositories.rst | 51 ----- .../installation-1.7/routing-database.rst | 75 ------- en/installation/installation-1.7/sems.rst | 129 ----------- en/installation/installation-1.7/web.rst | 205 ----------------- .../installation-1.8/call-trace.rst | 120 ---------- .../installation-1.8/cdr-database.rst | 94 -------- .../installation-1.8/cli-utility.rst | 62 ------ .../installation-1.8/database-tuning.rst | 33 --- en/installation/installation-1.8/index.rst | 25 --- .../installation-1.8/management.rst | 194 ---------------- en/installation/installation-1.8/redis.rst | 31 --- .../installation-1.8/release-notes.rst | 36 --- .../installation-1.8/repositories.rst | 51 ----- .../installation-1.8/routing-database.rst | 69 ------ en/installation/installation-1.8/sems.rst | 168 -------------- .../installation-1.8/upgrade-from-1.7.rst | 143 ------------ en/installation/installation-1.8/web.rst | 207 ------------------ .../installation-1.9/call-trace.rst | 126 ----------- .../installation-1.9/cdr-database.rst | 94 -------- .../installation-1.9/database-tuning.rst | 33 --- en/installation/installation-1.9/index.rst | 24 -- .../installation-1.9/management.rst | 200 ----------------- en/installation/installation-1.9/redis.rst | 31 --- .../installation-1.9/release-notes.rst | 17 -- .../installation-1.9/repositories.rst | 40 ---- .../installation-1.9/routing-database.rst | 69 ------ en/installation/installation-1.9/sems.rst | 167 -------------- .../installation-1.9/upgrade-from-1.8.rst | 82 ------- en/installation/installation-1.9/web.rst | 204 ----------------- en/quick-start/quick_start.rst | 2 +- en/web-interface/system/nodes.rst | 2 +- 71 files changed, 242 insertions(+), 5113 deletions(-) delete mode 100644 en/installation/installation-1.10/call-trace.rst delete mode 100644 en/installation/installation-1.10/cdr-database.rst delete mode 100644 en/installation/installation-1.10/cdr-export-download.png delete mode 100644 en/installation/installation-1.10/cdr-export.rst delete mode 100644 en/installation/installation-1.10/database-tuning.rst delete mode 100644 en/installation/installation-1.10/index.rst delete mode 100644 en/installation/installation-1.10/management.rst delete mode 100644 en/installation/installation-1.10/redis.rst delete mode 100644 en/installation/installation-1.10/release-notes.rst delete mode 100644 en/installation/installation-1.10/repositories.rst delete mode 100644 en/installation/installation-1.10/routing-database.rst delete mode 100644 en/installation/installation-1.10/sems-prometheus.rst delete mode 100644 en/installation/installation-1.10/sems.rst delete mode 100644 en/installation/installation-1.10/upgrade-from-1.9.rst delete mode 100644 en/installation/installation-1.10/web.rst delete mode 100644 en/installation/installation-1.10/yeti-web-prometheus.rst delete mode 100644 en/installation/installation-1.11/call-trace.rst delete mode 100644 en/installation/installation-1.11/cdr-export-download.png delete mode 100644 en/installation/installation-1.11/cdr-export.rst delete mode 100644 en/installation/installation-1.11/release-notes.rst delete mode 100644 en/installation/installation-1.11/repositories.rst delete mode 100644 en/installation/installation-1.11/upgrade-from-1.10.rst rename en/installation/{installation-1.11 => installation-1.13}/cdr-database.rst (86%) rename en/installation/{installation-1.11 => installation-1.13}/index.rst (55%) rename en/installation/{installation-1.11 => installation-1.13}/redis.rst (74%) create mode 100644 en/installation/installation-1.13/release-notes.rst create mode 100644 en/installation/installation-1.13/repositories.rst rename en/installation/{installation-1.11 => installation-1.13}/routing-database.rst (83%) rename en/installation/{installation-1.11 => installation-1.13}/sems.rst (72%) create mode 100644 en/installation/installation-1.13/upgrade-from-1.12.rst rename en/installation/{installation-1.11 => installation-1.13}/web.rst (52%) delete mode 100644 en/installation/installation-1.7/call-trace.rst delete mode 100644 en/installation/installation-1.7/cdr-database.rst delete mode 100644 en/installation/installation-1.7/cli-utility.rst delete mode 100644 en/installation/installation-1.7/database-tuning.rst delete mode 100644 en/installation/installation-1.7/index.rst delete mode 100644 en/installation/installation-1.7/management.rst delete mode 100644 en/installation/installation-1.7/redis.rst delete mode 100644 en/installation/installation-1.7/repositories.rst delete mode 100644 en/installation/installation-1.7/routing-database.rst delete mode 100644 en/installation/installation-1.7/sems.rst delete mode 100644 en/installation/installation-1.7/web.rst delete mode 100644 en/installation/installation-1.8/call-trace.rst delete mode 100644 en/installation/installation-1.8/cdr-database.rst delete mode 100644 en/installation/installation-1.8/cli-utility.rst delete mode 100644 en/installation/installation-1.8/database-tuning.rst delete mode 100644 en/installation/installation-1.8/index.rst delete mode 100644 en/installation/installation-1.8/management.rst delete mode 100644 en/installation/installation-1.8/redis.rst delete mode 100644 en/installation/installation-1.8/release-notes.rst delete mode 100644 en/installation/installation-1.8/repositories.rst delete mode 100644 en/installation/installation-1.8/routing-database.rst delete mode 100644 en/installation/installation-1.8/sems.rst delete mode 100644 en/installation/installation-1.8/upgrade-from-1.7.rst delete mode 100644 en/installation/installation-1.8/web.rst delete mode 100644 en/installation/installation-1.9/call-trace.rst delete mode 100644 en/installation/installation-1.9/cdr-database.rst delete mode 100644 en/installation/installation-1.9/database-tuning.rst delete mode 100644 en/installation/installation-1.9/index.rst delete mode 100644 en/installation/installation-1.9/management.rst delete mode 100644 en/installation/installation-1.9/redis.rst delete mode 100644 en/installation/installation-1.9/release-notes.rst delete mode 100644 en/installation/installation-1.9/repositories.rst delete mode 100644 en/installation/installation-1.9/routing-database.rst delete mode 100644 en/installation/installation-1.9/sems.rst delete mode 100644 en/installation/installation-1.9/upgrade-from-1.8.rst delete mode 100644 en/installation/installation-1.9/web.rst diff --git a/en/general.rst b/en/general.rst index bd2a792..93342cb 100644 --- a/en/general.rst +++ b/en/general.rst @@ -135,14 +135,14 @@ Components Yeti consists of the following components: -- Traffic routing server (SEMS + YETI module) -- Management daemon - used as configuration storage across cluster +- Switch server (SEMS + YETI module) - Incoming traffic balancer (Kamailio) - Routing database (Postgresql) - CDR database (Postgresql) - Realtime data storage(Redis) -- Web-interface (RoR, ruby) +- Management Web-interface (RoR, ruby) - CLI interface (python) [optional] +- Customer portal (VueJS SPA) [optional] - CDRs billing and statistics calculation daemons based on PGQ YETI designed as cluster system, but you can run all components on the one server, as well as on the different hosts. diff --git a/en/installation/index.rst b/en/installation/index.rst index 1a31773..822514b 100644 --- a/en/installation/index.rst +++ b/en/installation/index.rst @@ -9,10 +9,6 @@ Components: .. toctree:: :maxdepth: 2 + installation-1.13/index installation-1.12/index - installation-1.11/index - installation-1.10/index - installation-1.9/index - installation-1.8/index - installation-1.7/index diff --git a/en/installation/installation-1.10/call-trace.rst b/en/installation/installation-1.10/call-trace.rst deleted file mode 100644 index 6a01fe2..0000000 --- a/en/installation/installation-1.10/call-trace.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. :maxdepth: 2 - - -================================ -Call trace storage configuration -================================ - - -SEMS and Web are running on same server ---------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content: - -.. code-block:: nginx - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/spool/sems; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -SEMS and Web located on different servers ------------------------------------------ - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create directory **/var/www/dump** with owner **www-data** to store PCAP files. - -Edit **/etc/nginx/sites-enabled/yeti-web** and add such server block: - -.. code-block:: nginx - - server { - listen :8081; - server_name _; - access_log /var/log/nginx/pcap-upload.access.log; - error_log /var/log/nginx/pcap-upload.error.log; - - root /var/www/dump; - - location /upload { - allow /32; - deny all; - - alias /var/www/dump; - dav_methods PUT; - dav_access group:rw all:r; - create_full_put_path on; - client_max_body_size 10000M; - } - } - - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content: - -.. code-block:: nginx - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/www; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -Configure SEMS to upload traces to WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add **http_client** module configuration to **modules** section of **/etc/sems/sems.conf**:: - - modules { - path = /usr/lib/sems/plug-in - config_path=/etc/sems/etc/ - ... - module "http_client" { - resend_interval=5000 - resend_queue_max=10000 - - destination "pcap" { - mode=put - urls={ http://:8081/upload } - on_success { - action = remove - } - on_failure { - action = requeue - } - } - } - ... - } - -Add **pcap_upload_queue=pcap** directive to section **general** of **/etc/sems/sems.conf**:: - - general { - ... - pcap_upload_queue=pcap - ... - } - - -Restart SEMS: - -.. code-block:: console - - # systemctl restart sems - - - - - diff --git a/en/installation/installation-1.10/cdr-database.rst b/en/installation/installation-1.10/cdr-database.rst deleted file mode 100644 index 5935f28..0000000 --- a/en/installation/installation-1.10/cdr-database.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. :maxdepth: 2 - - -========================== -CDR databases installation -========================== - -.. note:: System requires two databases: one for routing and one for CDRs. Setting up different PostgreSQL instances is highly recommended to make replication possible. - -Packages installation -===================== - -CDRs databases require similar set of packages as routing database - -.. code-block:: console - - # apt update && apt install postgresql-11 postgresql-contrib-11 postgresql-11-prefix postgresql-11-pgq3 postgresql-11-pgq-ext postgresql-11-yeti postgresql-11-pllua pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - - -Databases creation -================== - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user cdr encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database cdr owner cdr; - CREATE DATABASE - postgres=# \q - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - - -PGQd ticker -=========== - -After initialization of CDR database you should run pgq ticker daemon(**pgqd**) on server with CDR database. - -Create configuration file /etc/pgqd.ini - -.. code-block:: ini - - [pgqd] - base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=somepassword - initial_database = cdr - database_list = cdr - script = /usr/bin/pgqd - pidfile = /var/run/postgresql/pgqd.pid - ticker_max_count=1 - ticker_max_lag=3 - ticker_idle_period=360 - - -Then you should start ticker: - -.. code-block:: console - - # service pgqd start - - -Checks -====== - -Check if databases were successfully created and are accessible: - -.. code-block:: psql - - root@cdr-server:/# psql -h 127.0.0.1 -U cdr -d cdr - Password for user cdr: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - cdr=# \q - root@cdr-server:/# - -Don't forget to make changes in /etc/postgresql/11/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.10/cdr-export-download.png b/en/installation/installation-1.10/cdr-export-download.png deleted file mode 100644 index 0b5ff7fd7eacb9303ee6cc9fe74548171b6582cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62512 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

CY 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 tfLmi=xX|{Wg9rfW(&2q_<>N2`_ method for CSV generation, so the file will be saved by postgresql daemon. - -.. figure:: cdr-export-download.png - - CDR export download link - -Yeti Web interface uses Nginx `X-Accel-Redirect `_ mechanism to provide file download. -Web interface responds on download request with 200Ok with header **X-Accel-Redirect: /x-redirect/cdr_export/4.csv**. Nginx should be configured to handle this redirection properly. - - -CDR database and yeti-web on the same server --------------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **/x-redirect/cdr_export** with the following content: - -.. code-block:: nginx - - location /x-redirect/cdr_export { - internal; - alias /tmp; - } - -Where **/tmp** is the storage directory defined in **/opt/yeti-web/config/yeti_web.yml**: - -.. code-block:: yaml - - cdr_export: - dir_path: "/tmp" - -.. warning:: You can use any directory as **cdr_export dir_path** but this directory should be writable by **postgres** system user and readable by **www-data** system user. - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -CDR database and yeti-web located on different servers ------------------------------------------------------- - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **/x-redirect/cdr_export** with the following content: - -.. code-block:: nginx - - location /x-redirect/cdr_export { - internal; - proxy_pass http://:8080; - } - -Where **** is IP address of remote CDR database server. - -Configure nginx on CDR database server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Install **nginx** package and add the next server block to **/etc/nginx/nginx.conf**: - -.. code-block:: nginx - - server { - listen 8080; - server_name _; - root /tmp; - - allow /32; - deny all; - - location /x-redirect/cdr_export { - alias /tmp; - } - } - -Where **/tmp** is **cdr_export dir_path** from **/opt/yeti-web/config/yeti_web.yml** config file and **** is IP address of your web interface server. - -.. warning:: Make sure you configure **allow/deny** ACL properly. Wrong nginx configuration will cause data leak especially if CDR server uses public IP address(we recommend using private IP for CDR db server). - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - diff --git a/en/installation/installation-1.10/database-tuning.rst b/en/installation/installation-1.10/database-tuning.rst deleted file mode 100644 index 7b5d3ab..0000000 --- a/en/installation/installation-1.10/database-tuning.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. :maxdepth: 2 - -============================ -Databases performance tuning -============================ - -By default Postgresql RDBMS configured to consume minimal system resources. This approach allows Postgresql to start on any server after installation. YETI as well as any other system uses Postgresql requires changing default configuration in order to archive best performance. - -We recommends to change next configuration variables at /etc/postgresql/11/yeti/postgresql.conf - -.. code-block:: ini - - shared_buffers = 10GB - work_mem = 8MB - fsync = on - checkpoint_timeout = 50min - - -Set **shared_buffers** variable to 1/3 of total RAM installed to server if you share this server with some another application. For example we recommends install yeti-web on same server as routing database. -If your server is dedicated for postgresql set **shared_buffers** to 2/3 of your RAM. - -When configuration changed you should restart your postgresql instance using `service postgresql restart` - -.. seealso:: Read Postgresql manual https://www.postgresql.org/docs/11/ to understand postgresql architecture and features - - - - - - - - diff --git a/en/installation/installation-1.10/index.rst b/en/installation/installation-1.10/index.rst deleted file mode 100644 index ae41789..0000000 --- a/en/installation/installation-1.10/index.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _install_1.10: - -Version 1.10 -============ - -Supported Operating systems are Debian GNU/Linux 9 and Debian GNU/Linux 10 the only supported architecture is amd64 - -Components: - -.. toctree:: - :maxdepth: 2 - - repositories - routing-database - cdr-database - web - redis - management - sems - call-trace - cdr-export - database-tuning - sems-prometheus - yeti-web-prometheus - release-notes - upgrade-from-1.9 - diff --git a/en/installation/installation-1.10/management.rst b/en/installation/installation-1.10/management.rst deleted file mode 100644 index 2f4855c..0000000 --- a/en/installation/installation-1.10/management.rst +++ /dev/null @@ -1,200 +0,0 @@ -.. :maxdepth: 2 - - -============================== -Management server installation -============================== - -Since version 1.6.3-175 we started to use central configuration server -to store yeti module configuration for all nodes in cluster. - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-management - -Configuration files -------------------- - -/etc/yeti/management.cfg -~~~~~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for management daemon. - -Set desired logging level and address to listen. - -You can set multiple addresses separated by comma to listen on multiple interfaces. - -Possible log_level values are: (1 - error, 2 - info, 3 - debug) - -.. code-block:: c - - daemon { - listen = { - "tcp://0.0.0.0:4444" - } - - sctp { - address = "127.0.0.1" - port = 4444 - } - - http { - address = "127.0.0.1" - port = 3000 - } - log_level = 2 - } - -/etc/yeti/system.cfg -~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for all nodes. -Each top-level section defines configuration for node of certain type -(signaling is for traffic switch nodes). -All top-level sections contains mandatory section globals -which must have all possible values common for all nodes. -Then there is named sections for each node_id which may contain -values overriding ones set in global section. - -.. note:: Even if your node does not have any specific values you have to define empty section for this node anyway, otherwise management node will not provide configuration for node with this id. - -Example of minimal configuration file for node with id 8 - -.. code-block:: c - - signalling { - globals { - yeti { - pop_id = 4 - msg_logger_dir = /var/spool/sems/dump - log_dir = /var/spool/sems/logdump - audio_recorder_dir = /var/spool/sems/records - audio_recorder_compress = true - routing { - schema = switch18 - function = route_release - init = init - master_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - failover_to_slave = false - slave_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - cache { - enabled = false - check_interval = 60 - buckets = 100000 - } - } - cdr { - dir = /var/spool/sems/cdrs - completed_dir = /var/spool/sems/cdrs/completed - pool_size = 2 - schema = switch - function = writecdr - master { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_to_slave = false - slave { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_requeue = true - failover_to_file = false - serialize_dynamic_fields = true - batch_size = 1 - batch_timeout = 5000 - } - resources { - reject_on_error = false - write { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 500 - } - read { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 1000 - } - } - registrations { - check_interval = 5000 - } - registrar { - enabled = true - redis { - host = 127.0.0.1 - port = 6379 - } - } - rpc { - calls_show_limit = 10000 - } - } - } - node 8 { } - } - -.. warning:: You should define all Nodes that has been created at web interface by their IDs. See :ref:`System->Nodes ` menu. SEMS node will refuse to start if corresponding node is not defined at system.cfg - - -Management server launch ------------------------- - -Launch configured management server instance: - -.. code-block:: console - - # service yeti-management start - -Checks ------- - -Check file /var/log/yeti/yeti-management.log for daemon logs: - -.. code-block:: console - - # tail -2 /var/log/yeti/yeti-management.log - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/yeti_mgmt_server.cpp:148: starting version 1.0.5 - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/mgmt_server.cpp:123: listen on tcp://0.0.0.0:4444 - -Check listening port: - -.. code-block:: console - - # netstat -lpn | grep yeti_management - 4444 tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN 25376/yeti_manageme - diff --git a/en/installation/installation-1.10/redis.rst b/en/installation/installation-1.10/redis.rst deleted file mode 100644 index 8aa6cd6..0000000 --- a/en/installation/installation-1.10/redis.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. :maxdepth: 2 - - -================== -Redis installation -================== - -Redis is used to synchronize data between traffic switch instances. It stores information about used resources (e.g gateways capacity limits) to provide correct limitation among all nodes for distributed installations. - -Install packages -================ - -.. code-block:: console - - # apt update && apt install redis-server - -Configuration -============= - -Add - -.. code-block:: ini - - notify-keyspace-events "Egx" - -to your **/etc/redis/redis.conf** to enable notifications. This configuration required for incoming registrations functionality. - -Checks -====== - -Try to enter redis console from traffic switch host -(redis installed at the same host -with traffic switch in this example): - -.. code-block:: console - - # redis-cli - 127.0.0.1:6379> ping - PONG - 127.0.0.1:6379> quit diff --git a/en/installation/installation-1.10/release-notes.rst b/en/installation/installation-1.10/release-notes.rst deleted file mode 100644 index 7eab893..0000000 --- a/en/installation/installation-1.10/release-notes.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. :maxdepth: 2 - -============= -Release notes -============= - - -Changes in 1.10 version -~~~~~~~~~~~~~~~~~~~~~~~ - - * Yeti web refactoring and more tests - * New Customer API controllers - :doc:`Active Calls Chart, Networks, Network prefixes, Network types ` - * Dictionaries REST API for integration with Clickhouse/Grafana - * :doc:`Prometheus exporter for yeti-web application ` - * Support for exception repoting to `Sentry `_ - * :doc:`Prometheus exporter for SEMS ` - * Customer/Vendor call duration(based on billing intervals) for reports and :ref:`invoices ` - * Support for Debian 10 Buster - diff --git a/en/installation/installation-1.10/repositories.rst b/en/installation/installation-1.10/repositories.rst deleted file mode 100644 index 251a66c..0000000 --- a/en/installation/installation-1.10/repositories.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. :maxdepth: 2 - - -========================== -Repositories configuration -========================== - -Most of servers may use same repositories set:: - - deb http://ftp.us.debian.org/debian/ buster main contrib non-free - deb http://ftp.us.debian.org/debian/ buster-updates main - deb http://security.debian.org/ buster/updates main - deb http://pkg.yeti-switch.org/debian/buster 1.10 main - deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main - -for Debian 9:: - - deb http://ftp.us.debian.org/debian/ stretch main contrib non-free - deb http://ftp.us.debian.org/debian/ stretch-updates main - deb http://security.debian.org/ stretch/updates main - deb http://pkg.yeti-switch.org/debian/stretch 1.10 main - deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main - deb http://ftp.debian.org/debian stretch-backports main - -.. note:: Debian 9 stretch requires **stretch-backports** repository to be connected for successful installation. - -System repositories can be changed by editing of file: /etc/apt/sources.list. Since we use our own package repository you have add our key to trusted. -There is two ways to do it: - -.. code-block:: console - - # apt-key adv --keyserver keys.gnupg.net --recv-key 9CEBFFC569A832B6 - -or - -.. code-block:: console - - # wget http://pkg.yeti-switch.org/key.gpg -O - | apt-key add - - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. - -PGDG repository key also should be added to trusted list - -.. code-block:: console - - # wget https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - diff --git a/en/installation/installation-1.10/routing-database.rst b/en/installation/installation-1.10/routing-database.rst deleted file mode 100644 index 2d6e29a..0000000 --- a/en/installation/installation-1.10/routing-database.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. :maxdepth: 2 - - -============================= -Routing database installation -============================= - -.. note:: We recommend placing routing database on the same host with management WEB interface for best performance and web interface responsiveness. - - -Supported versions ------------------- - -The only supported postgresql version is 11. - - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install postgresql-11 postgresql-contrib-11 postgresql-11-prefix postgresql-11-pgq3 postgresql-11-pgq-ext postgresql-11-yeti postgresql-11-pllua pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - -Databases creation ------------------- - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user yeti encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database yeti owner yeti; - CREATE DATABASE - postgres=# \q - - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - -Checks ------- - -Check if databases were successfully created and are accessible:: - - root@evial:/# psql -h 127.0.0.1 -U yeti -d yeti - Password for user yeti: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - yeti=# \q - root@evial:/# - - -Don't forget to make changes in /etc/postgresql/11/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.10/sems-prometheus.rst b/en/installation/installation-1.10/sems-prometheus.rst deleted file mode 100644 index 6dc16c9..0000000 --- a/en/installation/installation-1.10/sems-prometheus.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. :maxdepth: 2 - - -======================== -SEMS Prometheus exporter -======================== - - -Module **prometheus_exporter** allows to expose SEMS internal metrics to `Prometheus `_ metric storage. To enable exporter just add new module to your **sems.conf**: - -.. code-block:: c - - modules { - ... - module "prometheus_exporter" { - address = 127.0.0.1 - port = 8080 - label(system, yeti) - label(pop, us-east-1) - label(host, yeti.example.com) - } - ... - } - - -address - IP address where exporter will listen - -port - port to listen - -label - label function allow to add custom labels to all metrics exposed by exporter. Label can be used multiple times - diff --git a/en/installation/installation-1.10/sems.rst b/en/installation/installation-1.10/sems.rst deleted file mode 100644 index 14b518b..0000000 --- a/en/installation/installation-1.10/sems.rst +++ /dev/null @@ -1,167 +0,0 @@ -.. :maxdepth: 2 - - -====================== -SEMS node installation -====================== - -Install packages ----------------- - -.. code-block:: console - - # apt update && apt install sems sems-modules-yeti - -Configuration files -------------------- - -.. _sems_conf_1.10: - -/etc/sems/sems.conf -~~~~~~~~~~~~~~~~~~~ - -Add new node to the routing database using web interface -[ System -> Nodes -> New Node ]. -Use id of newly created node as value for **node_id** parameter - -node_id - unique signaling node id. - -.. warning:: You should create Node at web interface and use ID from web interface at **node_id** variable. See :ref:`System->Nodes ` menu. - -Replace , with correct values for your server : - -.. code-block:: c - - general { - daemon = yes - stderr = no - syslog_loglevel = 2 - syslog_facility = LOCAL0 - - node_id = 8 - - shutdown_mode { - code = 508 - reason = "Yeti node in shutdown mode" - allow_uac = true - } - - #pcap_upload_queue = pcap - - media_processor_threads = 2 - rtp_receiver_threads = 2 - session_processor_threads = 10 - sip_udp_server_threads = 2 - sip_tcp_server_threads = 2 - - dead_rtp_time=30 - } - - - signaling-interfaces { - interface input { - default-media-interface = input - ip4 { - sip-udp { - address = - port = 5061 - use-raw-sockets = off - } - sip-tcp { - address = - port = 5061 - connect-timeout = 2000 - static-client-port = on - idle-timeout=900000 - use-raw-sockets = off - } - } - } - } - - media-interfaces { - interface input { - ip4 { - rtp { - address = - low-port = 16384 - high-port = 32767 - dscp = 46 - use-raw-sockets = off - } - } - } - } - - modules { - module "di_log"{} - module "mp3"{} - module "opus"{} - module "wav"{} - module "gsm"{} - module "ilbc"{} - module "adpcm"{} - module "l16"{} - module "g722"{} - - module "registrar_client" {} - module "sctp_bus"{} - module "http_client"{} - module "session_timer"{} - module "jsonrpc"{ - listen{ - address = 127.0.0.1 - port = 7080 - } - server_threads=1 - } - - module-global "uac_auth" { } - - module "yeti" { - management { - address = 127.0.0.1 - port = 4444 - timeout = 60000 - } - core_options_handling = yes - } - } - - routing { - application = yeti - } - - - - -.. warning:: RPC allows shutdown SEMS node or make it non-operational. RPC interface should be secured by firewall to prevent connections from not trusted hosts. In YETI systems only two components should have ability to connect to RPC - WEB interface and yeti-cli console - -Launch traffic switch ---------------------- - -Launch configured traffic switch instance: - -.. code-block:: console - - # service sems start - -In case of errors it's useful to use **sems -E -D3** command -which will launch daemon in foreground with debug logging level - -Checks ------- - -Check if **sems** process exists and signaling/media/rpc sockets are opened: - -.. code-block:: console - - # pgrep sems - 29749 - # netstat -lpn | grep sems - tcp 0 0 127.0.0.1:8090 0.0.0.0:* LISTEN 29749/sems - udp 0 0 127.0.0.1:5061 0.0.0.0:* 29749/sems - raw 2688 0 0.0.0.0:17 0.0.0.0:* 7 29749/sems - -Check logfile /var/log/sems/sems-main.log for possible errors diff --git a/en/installation/installation-1.10/upgrade-from-1.9.rst b/en/installation/installation-1.10/upgrade-from-1.9.rst deleted file mode 100644 index 57b55d3..0000000 --- a/en/installation/installation-1.10/upgrade-from-1.9.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. :maxdepth: 2 - -==================== -Upgrade instructions -==================== - -This instuctions describe how to upgrade Yeti system from version 1.9.9 to version 1.10. If you have any other Yeti version you should previously upgrade it to 1.9.9 - - -Shutdown CDR billing process and other pgq-processor consumers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: console - - # systemctl stop yeti-cdr-billing@cdr_billing - # systemctl stop yeti-delayed-job - - -Upgrade yeti-web package to 1.10.0 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# apt update - root@yeti:/# apt install yeti-web=1.10.0 - - -Postgresql 11 installation -~~~~~~~~~~~~~~~~~~~~~~~~~~ -You should install postgresql-11 packages, as described at :doc:`routing-database` and :doc:`cdr-database` and create appropriate databases. - - -Apply migrations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# cd /opt/yeti-web - root@yeti:/# su -s /bin/bash yeti-web - root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - root@yeti:/opt/yeti-web# - - -Restart all components of yeti-web -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# systemctl restart yeti-web - root@yeti:/# systemctl restart yeti-cdr-billing@cdr_billing - root@yeti:/# systemctl restart yeti-delayed-job - - diff --git a/en/installation/installation-1.10/web.rst b/en/installation/installation-1.10/web.rst deleted file mode 100644 index 87acf8d..0000000 --- a/en/installation/installation-1.10/web.rst +++ /dev/null @@ -1,204 +0,0 @@ -.. :maxdepth: 2 - - -========================== -WEB interface installation -========================== - -Server requirements: - -- amd64 architecture -- Debian 9 Stretch distibution -- at least 4GB of RAM - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-web nginx - -Databases connection configuration ----------------------------------- - -To configure databases connection parameters create /opt/yeti-web/config/database.yml file with the following content: - -.. code-block:: yaml - - production: - adapter: postgresql - encoding: unicode - database: yeti - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import' - port: 5432 - min_messages: notice - - secondbase: - production: - adapter: postgresql - encoding: unicode - database: cdr - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'cdr, reports, billing' - port: 5432 - min_messages: notice - -Warning: you should specify correct addresses and credentials that were used in previous section - -Databases data initialization ------------------------------ - -To initialize empty databases during initial installation: - -.. code-block:: console - - # cd /opt/yeti-web - # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:structure:load db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:structure:load db:second_base:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:seed - - -To upgrade databases to the latest version: - -.. code-block:: console - - # cd /opt/yeti-web - # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - - -Nginx configuration -------------------- - -For basic configuration remove default config and copy yeti-web.dist.nginx: - -.. code-block:: console - - # rm /etc/nginx/sites-enabled/default - # cp /opt/yeti-web/config/yeti-web.dist.nginx /etc/nginx/sites-enabled/yeti - # nginx -t - nginx: the configuration file /etc/nginx/nginx.conf syntax is ok - nginx: configuration file /etc/nginx/nginx.conf test is successful - # service nginx restart - - -Launch ------- - -After successful configuration of databases you finally can run software using following commands: - -.. code-block:: console - - # service yeti-web start - # service yeti-cdr-billing@cdr_billing start - # service yeti-delayed-job start - -This will run web-interface and CDR processing workers - -Checks ------- - -check if unicorn listens on local socket: - -.. code-block:: console - - # netstat -lpn | grep unicorn - unix 2 [ ACC ] STREAM LISTENING 2535145 24728/unicorn.rb -E /tmp/yeti-unicorn.sock - -check if nginx listens on correct TCP/IP addresses and ports: - -.. code-block:: console - - # netstat -lpn | grep nginx - tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 23627/nginx - tcp 0 0 127.0.0.1:6666 0.0.0.0:* LISTEN 23627/nginx - -Log files to check for possible warnings/errors: - -- /var/log/yeti-admin.log -- /var/log/yeti-cdr-billing.log -- /opt/yeti-web/log/unicorn.stdout.log -- /opt/yeti-web/log/unicorn.stderr.log - -Try to open management interface in your favorite browser and login with default credentials: - -:user: admin -:password: 111111 - - -Invoice PDF generation ----------------------- - -If you need to generate invoices in PDF format, you have to install additional packages. -It is accomplished via LibreOffice software, so our package just a wrapper for a LibreOffice installation. - -.. warning:: - This operation will install a lot of packages in your system! - -.. code-block:: console - - # apt install yeti-libreoffice-headless - -Make sure, that service is enabled for autostart - -.. code-block:: console - - # systemctl enable yeti-libreoffice-headless - -Run it - -.. code-block:: console - - # systemctl start yeti-libreoffice-headless - - -LDAP Authentication -------------------- -Yeti's web-interface may use LDAP in order to authnticate users. - -Copy configuration from example file - -.. code-block:: console - - # cp /opt/yeti-web/config/ldap.yml.dist /opt/yeti-web/config/ldap.yml - -and edit it - -.. code-block:: console - - production: - host: yeti-host.com - port: 389 - ssl: false - attribute: uid - base: ou=employees,dc=yeti,dc=com - group_base: ou=groups,dc=yeti,dc=com - required_groups: - - ["member", "cn=yeti,ou=groups,dc=yeti,dc=com"] - -* **host** - address of LDAP server -* **port** - port of LDAP server -* **ssl** - enable/disable SSL -* **attribute** - name of attribute which contains user login -* **base** - base DN where YETI will try find users -* **group_base** - base DN where YETI will try find groups -* **required_groups** - array of groups where user must present -* **member** - attribute where group stored -* **cn=yeti,ou=groups,dc=yeti,dc=com** - group - - -After editing file, restart YETI web interface - -.. code-block:: console - - # systemctl restart yeti-web - diff --git a/en/installation/installation-1.10/yeti-web-prometheus.rst b/en/installation/installation-1.10/yeti-web-prometheus.rst deleted file mode 100644 index c5c52b1..0000000 --- a/en/installation/installation-1.10/yeti-web-prometheus.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. :maxdepth: 2 - - -============================ -Yeti WEB Prometheus exporter -============================ - - -It is possible to expose yeti-web ruby application internal metrics to `Prometheus `_ metric storage. You can enable exporter in **yeti_web.yml**: - -.. code-block:: yaml - - prometheus: - enabled: true - host: localhost - port: 8080 - default_labels: - host: yeti.example.com - - -address - IP address where exporter will listen - -port - port to listen - -label - label function allow to add custom labels to all metrics exposed by exporter. Label can be used multiple times - -Prometheus exporter require additional daemon to be started. To start and enable **yeti-prometheus** daemon run: - -.. code-block:: console - - root@yeti:/# systemctl start yeti-prometheus - root@yeti:/# systemctl enable yeti-prometheus - diff --git a/en/installation/installation-1.11/call-trace.rst b/en/installation/installation-1.11/call-trace.rst deleted file mode 100644 index 6a01fe2..0000000 --- a/en/installation/installation-1.11/call-trace.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. :maxdepth: 2 - - -================================ -Call trace storage configuration -================================ - - -SEMS and Web are running on same server ---------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content: - -.. code-block:: nginx - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/spool/sems; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -SEMS and Web located on different servers ------------------------------------------ - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create directory **/var/www/dump** with owner **www-data** to store PCAP files. - -Edit **/etc/nginx/sites-enabled/yeti-web** and add such server block: - -.. code-block:: nginx - - server { - listen :8081; - server_name _; - access_log /var/log/nginx/pcap-upload.access.log; - error_log /var/log/nginx/pcap-upload.error.log; - - root /var/www/dump; - - location /upload { - allow /32; - deny all; - - alias /var/www/dump; - dav_methods PUT; - dav_access group:rw all:r; - create_full_put_path on; - client_max_body_size 10000M; - } - } - - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content: - -.. code-block:: nginx - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/www; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -Configure SEMS to upload traces to WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add **http_client** module configuration to **modules** section of **/etc/sems/sems.conf**:: - - modules { - path = /usr/lib/sems/plug-in - config_path=/etc/sems/etc/ - ... - module "http_client" { - resend_interval=5000 - resend_queue_max=10000 - - destination "pcap" { - mode=put - urls={ http://:8081/upload } - on_success { - action = remove - } - on_failure { - action = requeue - } - } - } - ... - } - -Add **pcap_upload_queue=pcap** directive to section **general** of **/etc/sems/sems.conf**:: - - general { - ... - pcap_upload_queue=pcap - ... - } - - -Restart SEMS: - -.. code-block:: console - - # systemctl restart sems - - - - - diff --git a/en/installation/installation-1.11/cdr-export-download.png b/en/installation/installation-1.11/cdr-export-download.png deleted file mode 100644 index 0b5ff7fd7eacb9303ee6cc9fe74548171b6582cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62512 zcmcG#1yo$Y(=SMjgb)G)0RjX_2KV3&0S0$>2<{NvhY%pl5Zs;M?(QMDySwY)KEUjd z@BQEIo^SV@eP?&?Idi6O_r2BC-F2(0s(%GlkQ2vvP52rG1qDM=0;Gh3@*Eol<>|<) zr^uR&zK(auKeTTWnvN(aZ#y1;Ph#la5}}}cM3DpuskrGKEV}EwyFk1==6qWDo&G0% zVx#%@mw8VTsnM3)NXhZs6|}PS+51_W*hOR`*eIm$P2-~p*5ommRNgUteiyY~SeA$W zsfhB|yFz-_4{*4Vfu^bN3tS3seo_IFilbq(!`XykPg8+PG0W;iBqzwrayppwze;&; zEuQ@=z5ibI<=hc@h`LuL&bTkZfbWC(i>X}4nk1co7pKQ$ObtGx}?Imy@D^^~7 zuUg$jK4zj>az{h?#*&?Y;Kc8-1x3CDEGtW<^VX+9N=jO_lV0$ad;;{dmh7?Z&w7El zAC7KDTF%&5MQ$={_^Rxy$NFQ?-slQw?sy_PE)E|T|19&d5(NR4AW9|Nc=K33&hW@! z92FH6-4|)0%=kSVcha94xy+>hiT%PYGbulxru6{r9WHK4F!X+1OX)J@1JH7MYG^ip zTq8{p4-XG??mcs8@kIH$eFBQ)nn|1q@JQ8-ng3xCRdy)cn<}@QSCx)bpy^gzNm3H6 zb;Vv6(s(|bu^E^VYVLpv>}!c~WZ4=p`xUE?tVa^7yIwBDGOdhS9^OREcW^004{4u?v% zs@%fDXxw2f3yP4I-JEsn^9PZ`0?!=A&5zoaRh|@@#ct&=x(a*1Hke zDiuVt+4AR`NP+zBQ;T|K;}*;9_mk4G&VxZR-^=YHEQ@M)``g+C!Jzlg7QJS7(d9r` ztm(qWi~W2Z-670LxooA`nW~998>8{lHoqTxo6fW{H|~RTWvmHO=`;JyD9oAKl!7=- zrqU`I$+$djH!n-x?pTO|5)8n~tjpTAIK&l*pdX-;c0ANUW1zbAOj>;B>lD->9b%Qy zYtzlqq-pD4QUiuB45xjcpg+4$4&Wghese~INK)^xb0lU7yw}XcHhY$=XuxFeM1ai)r}b9VvnYQPg%eEB_BgaK;${S>f829XWi7p zu6EhoD}oMCZieSR9OAnCq0&A4J7mnSyCn_xn@3XrLl7Wxsp==X#!bSYRSk%$FXn0b zjH7|Z@wY+aO=yyt?XnNWFWi|%_=}R%{cJ(b>Y~7b&#jvEjx8{PW(Scf6}GcnZ&L1E zYxI|;SEiWJjG+#K8r9$XHVRqxNsKx`Ad0J~FjA;w>?UrKhL$TK&gb4@iU?ZxT8p0< z>mgp!3{MO9pBl@zhiQv<%S`~pZgkVtH-}XBv@rZ&EOlJVn0GpYBm~~gMQHF<0l6#bs4kd6BU2HOSE zwFo1bz$6Wl92%lyFSi}9M%0bk1r1(o8T76EfHe1FLWS|W0nUkax0!OTOeB2olkBey z%ApB1jU<^=w_Ll2j7SMSUbE1cJ3eqk4atq+zO!e5LVjY9bo>(3^Fb}Xb^ZBZDe?+1 zn8aJE^?9Rk_^IG{$b>MU*>DQ)rfj9hPB-DM!-h^h%b~>1B4~!LFt#|&@rl+H-0YA>rzu7UlMO5^QLfJhLKru4WKyW&sqEea96 zeL>UQo(#UVDZv2%Of1Da;z()?e|fEJL5`B&o5ZqJj|hQ;U74slPbPF6Vz81NC?m=Z zl!nMF{F=?hBprAv`%%THb~%;ZGk^* zqM`Hn3_4An{HD&NOBmriQ+_~jyP<_VVkIpF1oQ-MCa|B?WMS&upG_YMi!RhuTV=$Q z9IBGhO0*;{<^<{^S5y-7Fetj3;Nh@4rAQimBfD4&JA%bsU&ASNzJvP-Oy)IFSAMVxbZbE#t$#}JEiTchP0b`UbhIEMb;~McpbHsNv!^m)E%VTVwfMjB5Re4 zEjaM^i{QOX975X}jdVL3k*fQxQh#Zk6o!8dfkHOA$-?lR(BjWX%O&mgYGfu~b0hW5 zpI;1u2%+||pUy-ai@m)R8NA%}q{DiDm`Wx}iWk?LwRf-j)ua0Y@64SOb7PjycY2xf zUJederOA#Z;(g9eFO?fpMaZqzpAx3N9UdIq47ALGAQ(akTDZT3`+b*S^I8oYE&oMF zGDH)M@ryFe#<7VUw6VuIzP)_~T*nmv1A)Nw>0s_e0|Ae2XL-oykKgJl!zB*3x9h!~ zEh%rHuZ?^{O#|)pE@KP7LqLvkFFHane?_;bj$%;(Bi~%vFE&x}c!yT9DjFC%AqgHZ z<~cT8v;(Bogo)_rd}9hFqH-k`bVZZamC)}g)W&8&ZGXb})_p=_BIB$Kqzq$c7Ik&h zNtDXzg~0qTKpP77uKo}Su5Vp`h2)+BM}HH5OB5rNxGzR&C}Cx{`@Wyn-eDus)UH+N zHCLfMtZZJ6E8onXL|hl+vaT6!Z>opvfF0HrUF_s)D1nn9j=cqpQB;@qEEE}P#Sn;u zJO8Kltp1HrUF`&HG|ylHFMjvZAxE`rDXXxsWtgIswoZ)0CGADLKvzC401Y1e?HBxV z&v`S++kZ>f+dHZ?i0{3&rHdjZN#z&b*OeuH;;uMJ*qV*-x2+@}65`0{O9!jrOw4{t}Z7pnVEtg8H!YoZ5RmRhba*Nrr zs`S*oI-N2)qKcNWN~v6xb}FI-g&Q69uYmvnv!R)N z=jY&X1CU{0P|oi!)L*&QB=E&9$IP{t@_6-qpZK=QXd+JEHCe zrgMV4yH6W3JoU8e%J0t8uP0Tff4zFX_krJ)rlgsXpFJ?WGk?Z}p$1>PT86{s3PbsuP~Yr~>RoePJs_ueML*lXqCGO;jGgntTy?ef z2d<-h!K`!BQmvy;(b3U5_hgbc$LR{@vzeZpVEg;3>Zpa@-oc@kOrLh4%)C7F?ULgf z7nc^hkgd4Mp`M<+QP%7Rdr)xy0BK7}(|b7(dC{HrpPftJyvy_-dhmM63}1o6PxBdL z+e5M9-K={0jp%P=YQ-W~_pdHgumQ}%%z%g2oW0iIcA@eOl9<2p4;s zXqBQY8Enq>^g%evBKk5>9D1ZL&dW<)$E((y#JqTs4a)9=_hEZPZh57geRMias4fbl z-&~uGFI(ZNy%GdZ_x@Q!x(t6>b=sG*j13IRjaTn#Tp|y6xse7hBQ5RPwE2gonoe)_9`y8G?s~SXHHN8cr;eJ!M-7T6+-lb=N+Oi4!C^BArl1pC% zdP^8tkoYuWU;9_fQte#n-^NhAT2Us$BzYorW_R7q3643M@!(8#5utf6WBH8wUm8j^zJD@Q#Dggh@tzw zuadq^zi*YlI9KA%D+#5Jf$}of=uTD)H}V5@seE=66R`*~Q!Fj?YFrEp8Y}oJYHCW} z%cl-CEw<7zRpZT1UBYOKAMzqCq`OH3o}4}Nh^FjbRM?G0irgRcJOhho{9yyD7MpKC zY}P#=9UUu?b~{st?phoGY2RnT&Ih(& z<<^^`c7?u282DW!dgo`I13CdfPX5DMZ+nbu8`eVKC*Z$37*?6%xB)=}b)-{2dv%x3 z9D$KPZ#-M8dCD`Kt=UJqr3qSX?o@uN6$4xNfu!9bk&frlHsFxbr&sKAP{vUs*tUEr;O`t?xR@xcLaqFV!- zk(tIdX5(MzP9`SRFAxUYfCVS&mLrjTjd0GG9n}g**m66cu-3s2_G@0&dPk86*va<3 z*4e2xG&|P*k%zn9{g#l=#Zb*yF^b$I3pyObxdioh*7TISf9{QAztw7XbeDIZ88{&m4^C@j7&=bO)9RX= zewJo_y=P|z!B)S%xBy$}W&IiM7CnoO+!HhW=^j^5j}(pP>rH+)tY%Ei~i4S3qsBDMRnYn#;%5g)EdhcrmuilMQL zQ0}Nv@&Ht3KI9Un_@P!liYuP0Wwv``O`d4_CF06WPkR}qHAp;2hPeCQ%#g}t0F!9C zL24W8?ldWwCvFCgc(} z#gib??=mugHiCiOo_0#!=1axrDh{Z{f+ZB*q&3>vYx*nfoSaF>g}qO6$_on=EjT?z zz4K^qjREduuFj|Y4P|iJjB8q8X}7#L2--e;m>o=?Ue;mTAJp>XLK<%NO$Wz3Ll>7k3dnTJ#-V6D=#*%bk2y$b;Z|>Hy{u> zd8ZxGmQDD!W3a-(M*X+`Q_2L^M;7>q>*kNyVxnUUf=Kr#(;ll(WM|f!B+)F5EDa3} zrhcohO*|Xpd8{{AxiJ5>X4^iluBWG$Ma$?DM5k7qV|Mn-;j#6&B41w_$3nztRZ2=T zw0-XdvhF)R%Gl2?RW&s=B`q~IJvF_Ot^(A@dLNps$M66O%2$*I(BlA5zCV#b2C|UX zAC&*uH1_x`3d-j{8(T2J8|HsED8yp0l*Q}++_*{n3n`(z`7-xk&8Q!3{;TjToa0~N z|3DZAyuuB56_2@0WM@h_f?@mMl6!enUzxKPjRmloCs@jLm5(b)ako#^6%@U`4R*^8 zz-|4FhtH&IVPKLkI5%#_l%prV{o-GEOAl3c)Am`vgU?d0qWW~-l$f$5Mb!rGy|ZAL z2{&-9(@JI7QmcA$Izj)Di|=s~%92Eo9k8B2X@V`qJIf%gsmNpiUR)) zfT@@=8oB)!Yirs$dFsLyXPSUEShH0saq87`c8h%l*V4sPAy&!F-*&}3e%fwqHzRWI zJ-;k-HgfUqzQf+dVEKKNbekzU^%$cw={}5HGNQMppfnx4F&UP(ILXXtT3C<{Bwc9g zVnVL(#|$x9q9#6mLXUtJXS(^R(wZr-wFOxp0!|8aaCBs6XP@ethv23*djb@@-x53T zTh%o!ZQ|~$y9pKFzEMi!sb*$j3Hl|!BK`ygqQ!Hub2r2Xu0s3FY-KxH6Qw%;!UEn3 z{@C2dgp?Tbi7Fx0tXndg0McTd_V~FujeRlfQazl{Kc;zI$HX*Zc|GpPyJN5->{(e@ z*32kr@~6kMINkr#k$Ywmo#1nnFCdUhv-p{aY_RUp=%Z-<77K~z;6n|itB)d!lbACn z14dw!8nvhB)Ki*$1XefX$i3D+2x>kf0zHX0xHLWbWzo=5?$iAu74f zH$*J)kXw%nW)6;_{>C(q`vy}!VQGV%oC{Eu+bq7Nb3GW|QXA-Lhv^Eez=i7hH1E${ zB(c~ojm1uJy<#HEL-K*VzQ=V}N)we(WIL659WLi92UL6YvA~dQRe5xA{D; z5?44G;c_KPH)Tyax_TvQIExL=@Y|5{65V88Cv%_ungc~e#RtEaHZXEg(SpwY){hwu z>@oYzrxJxay6t|V?3haYRR5>`vN-MB-93;tJ61$MK>hhv@u4jv@>OJa5bB4q%{D(& zCs)T_pW`ptN-=S9QHc|l)%p2Qtzt^{@()PWWNT=>x4A0>qKji#sP-JrIyr(^g9;2) zm6W7@scSjeyD%~^DCP$-b#&rHH0a1?Js5APJVs>Ui+awk63&U6-HT}dST(48gy zE2Ov=2B{(=q&Znj$f#<0+2=4GhbB$d%!m8i_@o4!(U9}=3~|vz{w23&D|J>@UsFCK zF^uVfpIb%|QmWO-kJE_4lx!BqK~9m2hnt_w$S~{!?-E=#%+|J~ zVt^i4&9<&)supYNZ|Tep5GCd=>G8q(+_^j?Ck(PwinBU2QQ5*}(VS{-Jzdag1ecq( z2P)sC@HjU`#=G4PXae`9rwg46)mRdOB~ngX5xp#k zLqyMbCCuSW69}Y@?!2#~+4#cKU8stl1Z~8`;NBtrmRBG!PPMb)CHkjMAwjO0>Qmwe zaK&~iry#%LuzLY#&QV-H`fO3El7cxRv+SDV=Mb%WX}iKp)~f?hlzN z)-tv@=)AOlk;Gaqy--xSKHjKq#7Cb1nMQSSy)~9X(2xOvMzl(N*Azk#dPS^VW@}K+ z@F&Ao-Q(+32j-}lP$ibVa84y98SrnZd`Pg?FZbCf_kDRQw+NqECVQ4@-Y(e` zXA^%!0SNydLpob!4%_uIJm@Zdowy_|0SbyA;odjGWmm(&e51wLma&}wB@IoDKXpM{EoEjasm1+Nx~aFB z$?Ao8!dH^x3qIU21>J9%WD$9!dp_@l^ zZp(Y#D>iXZ2c+8u12Z*^$I0SZYw;X$WFeOre}o6=B>`vJEZKVKhd2&v+jO2T-fw=c z4}Z}r8L6QXe3t9AmAPGMrSkAP%f>TlJwA&hO8Bu6LQB44)xSN~=Me1K=7yk?8ikZ% z4yW0l|DEGo-t>*6Mzq0Ag8M7<{o*{ShMEuZ)frSOj5TXFG(|Wid)s`b5C1^bO<~0@ zZ&Ws3p~@Z9dvD@~LL~U^Y$P{vLp%%@o=sy6XtD^b1Szpx?(?U?sbm&JqvDw2l8;I2 z#ZB4i-7>?(L6*TBc35wA}_^XE($?<`lQSa4GnEg)v}Z53 zJCeEa9k+C}c_mlw9y8ftZ&$^^kZ|J5oMwXQYT3Bc$&W(6{~N^1%T;U|!4QP`ARZ z8#j9$@_R*I=XpT#m)|niE}MPh4zj`rpEfj}v{TxpHJ*d?(tbysB|OhoHq+eU-QTdY z(-B-$OepMWEyg-Fs|39A7xooS%_KMU`pbBoOvuNc@9`o>ex&~9HNxKW78bfg#j8kN zQ5ypZNNC(*ghWCEU)ZIr3kB%}oO57U``9=6xas1nq<+eopD6XCf}lH|IhwrgZqe!K zf$6#gx-M}$99o3FA6|*)c318Slw$i;)4IHL{OR;sxT{MFh?irRrdh8jmyLcvewh*g zx9GH#nvE2V<{efa3U-g&a!jGKB*-CwI zp$?~A;1<_KGIiAYSoAYuiZ{Ihe)unk59y3GD-5%FV@tThX%buFYPIk-htfvn|8jvz z>%eix{j5D%LTovz^K#-ppW>Ha186K&fR_1oWdGseLc_Yx>AGwaA2`VUynz!TZ3g-@8Lk zV@;m-U9+PL(~hT3Q-U?iMM@GV?vJa6^V^i8a#Rn(VH9#11N?$p4d;${ygUvs@w}SI z62=i8Qx!ALB$urG>P!UYR1ULe6oWbxF!eL2E-dOlSb!#eeUC;VO4Scnr>BllxS@Xa z;SqFE3vN`U6J~e(6k;E-%yVf38~$8TM~ryh*K3}Bw@$30N_ApmM#HQ z6QfTBJOo!vCC<^_Zo7`nZ|?E<6(!&)A<%Ddqs!?i$?^JPKw07a=r4pnp%FKyjJ+L- z0s!JXRx%utYSA6FN(t8mI%L64QPE@>13P31tUu2Ihx}QUbY*>6#wLRLu3J)k;u~BJ z@zngx-60T(R@K=4H-&r|lqJb{iN7_2hMw`ybcps!0sHvzQaF}d)2^R~l*!K!(5yq= zQQ^tvgB3*x8V!Zlkg6&&QkmVtZ);MFfYT0XYzerHprnnGA&qcF@ldmcrff+fq*k)L z<=Dx=a4lHogh2Spz8)5pXNu$I2bJjDx8KI7OUPPQKQJ+>KpUfv#ayQ&L;~OC2Tf#6 zohK?3_PgumA_iJSED8C({SgcZpvQ;gil5_dYwWgNO0L7o%d<{?m5878+a8XrE>1;SnwBeIEN`Ka3jib_Xl}+{vjEYG`W*;W*{R(o#jxd`-kZj zRJW~y9MCV2(4c0EnDvG14psgHCrT{s4-cN&2SfI*Zr%u8!v(s}BzFkBzG<%Po;;4B zvmQOCWRSf32H;6q_mgoJ3>N;nG^WWrb~B!7)}ZwsS{wF~3`27J{n4LEZ`SSG64{j= zd&}zw3W03|&Ty%mre|wN>Wt<)76$Tk^>7YLD#f9cGLDeSggW?0;8HqT0P9l<`-hfv ziw!n!SFXv4Aj=ICHp}rJiW~WC++ho zR{D3Z3Qk>OO>C%aMreG33OKN!UTRDL(gZ$mY4ZE+SvZ2%^Ee=!&_&L7$>k0tx$!lI z4?Ls9&3sq__H~ywgN3`J+PzCd3}2UyLG8~HU>{A-TV91Ug%sd4H1P|2!KDf!^X7|w zLxZZ1yb|-slN6Wls;nK7mp_%O9;Vhy%VpXBRb2k?<^z$tLGD&GBG)Cb>5BlVTIhfr zFpb-`Smt~vHJ*S3-OJ3@kY6C|70G@BohGy7(SAKkea*8k#DVwspH{&lx1d`l{x&Gz z#TLUa&J42#N+=}nXXzQO&?pl#@p*90aCOjzLO&^x5yCk0wy+@6VqJ%I;Nf{@6N<4HeV< z0xVw|!kL6c^+jcVTiMDK0D+uSl!cwUw!Ts%aXKmsj62TuIv+V9oNYvtsuiJL=X11l znlPYB>ax|$<{qCP8yC|5Uwh{;*eMRTSAJQ+{0o~aX%@&KuQ>X?uUB=h0s8!QGC0}v zRrEGpVsjtg3%Yl+SgQRW&*aj2bl1k^-;-uK5ppVhvy7T(AA~~uJ&G%0dR3f3#T}3i zwE$=gC-v!Bw6Hk*?Ne=v3mp=UNlEgrCV|3g{`&%19W)y^!)!JmfrCWhRcvvv3$mJ; zjQhY0r*)8u!Z9a6^guB0#*K=~^=jA?2Gbw+8c^ozsiPn(uv|u}Dt6BY!@=b_!5Uk* z9`7rF1!{e4^l5)7LL8KM_(%77oC^VO58Ujd!6CMQZdHPwBey_07`PtBx{q001w*S+FB$1Qp`2 zk=`hNSm=I3VQ-x#x>!nzvz@loAU}~cQbCx$4T)f#sPlc#c{K#2>Yai>L7-qPDpEr|Gj{qlc9k0)AZtSXl*b|dcKZ5y(_OfAa~WPvPv`XRl|z6`%JT2OP8M$gxLez}eNki4 zpy;^5cTRZNM#}Bel~Yye!m@$h1r6rP@ui%09YjX!rIIa|9{Of+avOQ!ls!-hcbJBu zoc@!^Z>I%9>qC50i}3s-1XTC-!r^LXztUswpy_D)=16AIQvtxy_NyL9%s)oC3fC~v zddP3OXloSRF6~GWtnsmHh)kvv8)*sqRqX%6=K=|T_-O)z#d85+2AYa_;kms~iPYS$ z&)JC&h+Lmo&A5YL#MZ_Ds1#6%GF3h|D9XrY``u!MqUqmFFXT7eCoE>XW4Scm#?`oA ztqOYGeAf8DsE%NjXn&GuH0nnRweY{CR?jv(qHaQ$vbEVA$^v%VdE$;o=Zx^ zuP#Oc0%c9u#Q-M1frY8Ge;&Qfc&e;+cb?nAbhr7?`mj@+&Z<=4xl1-EE`de%#PZ zZYI-pD(_DtzrsD4IQfTKa&w8pCRYJjmB?|kmo3$W^t2P9rKg0s-)SGrRg(D*|7`wQ zX<-artxBi7h!-FHqkc30;5m6gGdP6Mx!RmG#WlIfaahA$sbcG|%%Y_hL(Dn8Y;FbEAfQV}%=uCX12hGIbIF&NZd3|9&O7_r*)sG}S3$Xh!)2y#Q{OQbfh@{?SU`*pa*3HP445*Yk zeQty0fqLJtaOsc{Og0G2@)n#F%&>GJk7`%v?Y@G3BP`OOne7D5S7 zb#33ZxQg5-rmBisBkDLZAdz+i%cp&&2w)mx4$}W8@dVX)MP`PV>?GTWrVbVeurY6X zocs6-oi$qXIddNEvmzyr&7EVBvQ+<&a`D6)2=#v|msO2Q?}T&PZ2vBt6PADoGkPK_Lv2gm0H7~JOLjdf zr>+DKy>DOc&)KtBg!W`7#Y5sRy>)G%kQrgQuXNa0fc2fVp7|ed)@P=5B|yUXnB8|( zZ1-I;Z{-p{;$U977(yWSH!J;r+JInOjM(^wu*~7F)jfZw4-{^n54svaZ1p1|E6rSg zBFQe5s8w{ZmBdaeiIk{@n2OuTgM!Dg?5M!yp0QrBC_e$Qkuhnu=G+k}a^p?ST5e#(G#4k)B2@?E%~81O-u(re(+pKCEuk># zmTY&WMpVqXtKUTMz=sHBGiCrWRk1_-e>Q3LRq-dSe~*g}bKv zhX|m@vE=sJUt{I1Iw)!)-%TZ1YT^J4TRfSoeVdHX3vXpK6EffL)kv;XJ zYE%g>@+CBT0?jwrR$LfT;kk4$fJki2hAmrE^^SgUFQ`?uZ_DR$g`V3RL;Mfdn*z|fvAORpb@uYh-v!ouP#nQp%7Z{4F`K;LQy59PgkknfIh$1a z%2bgf=EG@j8$BHs^)QpJyKjG7KzFEi8LOpni!fgO`tR-28zG}wHJDkSQF=Prw4DH6 zL>!fTU$m0!m3G?el$V|}3+PsAcLn#aCrR-uo#FG^esUxV8(TR`a@%ufbbMr!q)I@k zB^Fbm33b3Tzjn;f{{G>?=xr>(X4>npR4$+GRDo0B0HC_!JQz_JJJ$cQJN|WQo@=n(=vui_Wj;$MfI*t5@cl9EQj%mq1y27 zr51+kTMZCbGj<}Zc}2m8#rSY38K{&>rw_TQ=!2%zAT)TeJ9LjN2m+CMO)8dJ?^^EB ziVCD{@H~p+CC>5C$W5ck%eU%c&8+k-0TpX(Rv4&)-u0tBxBffT$&vx~;H473owwJR zye@EQ!bP6DCSl%|(*tOReOjAO2mOWvPYrhx#{ooY%~8i`_mayc3n!bWWtm|5{>M1W zQH(_pzohmv%%cl+Y9;W^gMatkpG|yxHNF7-dJ(Nb=^}wX!pZZC3Du+a7Q}Ade5EPr zgBX`<)I*c3u6x7KFZ7TvS6|}b`#?mBN29OKdyj7`d&hq34x1Hh7H`Wz4hb^vbnZ7U ztnJbE@d6mp7Q6=Z|5Oxx`O{~pP9G9&5%iW)%LW(WCL;$*rZ4=aw(@Y&Q9=HdRV0qm zp+0N&Fg?v$(~X|`n`?)4ETC+Rv^CsecpIY3dgvg_JA9QcNfejH_q#_~!X!beaBeI5?H#PIS)Xy46i1??FSJ-QFR73VE_+~NG_h1a zWK|&lr+-{ze(-m?zpz1fXlT>Q1tPm#r@Bk3vBm|cO|YEsx+{) z8ub{u(CyBO1~{oFKY*Kboc zP9?wK;u4-)R%SC#XsfJUo!4MP6SLGeFfax#vJc;%9(U3oS4rbJ7FNPjs_ontjPERe z`m?#ogfWzcDNH!~x4gp41~+~GtLRZH4*vV(Cn$sxy=Z|9^Y@?1lfQ59wm>W!w!fAS zZylLADT5eqpL2`g1f0Q@MT^QAw;{}Jgw@wX-HTGMnEGHNpXBM`S`AXqUDb6@6s;0SA0!tgfHFgZ~qGe!S;hP zkpoNh{_cmIgy8RzbVB)y*N^9}3jZjmYUvmonzn^;P-G`gHz09?I~EO0Usdt zQ6rB$BkZL|3-8{eps+nveOMH~VtJtkH1gGCjp~L&bHx<3?sire>1Uy&q{eq`{}2Me zh5rHE@JqB^{x9H%Iq<(@IQ|bM2cOymq%1tbk_@V zrx3!H?%jvQe|S6IwMb4w)eJlsu5H#86su=qn4029M~Qo*EEkts1$Ad!8I%5@R!~qT z>MWkEBfZ1Pd4{9pkcE~DJgP%>%fF4%A`ILJ=QxtnLc(z8gF@L{bXr0F9=Am9XNrvv z;{xY{b?(PHE@-X)^080|*=@?sNq8GD;u^eFS5iL!GsaKUqr{y1T1AZKc8jyEavSGa zF-uZo(b%dJ9zJ!)wt#PXNQr;8*u#F+PEqXTp!OY9Nyj-lJ#|?ZuBEq#t6*FC<;bwS z*m6&ngkG3KdbLn(zq1%mrZfGdv^J|Tu06JxC$TL;w$>GY_!72QPC;{ILVhq`b-06& zFw-K4dwqL#B(YI-0=X_k)87a~cwL51&uc`U>UHgwnGg*xPA1SkuKb_=d;pwd#??*r z3noj+y()p*dFwj-t|0=D+BsMR99olA1vlz zn)Y~>V9IdEm4296uj7N+lQgeOaIU9#%Z%IZlWu!Z%G_P`ZZq1G2-mrDjQGvPWO_K$ z!)fNyyVe1p(_p(X8`NPvcs`v7&-m?;YZ^F4=6vNi60I^!J1l7xe(U!N0a(9l;fu3d zpUc#(o_*vO#f_VNZSm)8Tnz7&FZk2b&!g>cdq`)w&$Yd#W=>R1YD2+3d=#yFjxTZv z1Um-vu9IZ1El139>pXK?uKS#a8%}U$=LLtB9=h9uc8!w-;@V9w@a~A*C7EqLT}o zKVAvl((@0IwL-##i#iz?ptRC-mG59&)jr1)Y{fs6^}W2Vs?2;a)#DD=1xfeeT|at- z;zn2h3!CKPZ?|YS~jz;aOD)*1J zErv-;DBqBcJa|^atYSNy+^){#dAE9QEmc!F*nrJ9rsyJS`Cz*ST_N+B zQER2N`Qxvamtb11rzDe&7$&;E5S4RzP%=YkxyATgMg6`%Q=E(!Y^ZeEtNNf&S<{#X zJXqnO`#2rn;}pr3Y(6r2kDK+M3Szv!nhIuOXZpH$wV6X4cgj6p%)2lxcZIRI1m8P} zrnjUsriIf_`~`2ArIS^sk$ljrx?G*O;$7tB_Uz6Uq)&J-kltn@jv)~PMPKCZMwixH znD?4=S}%Lt0Y>XDq_vqI1~`qwn2_JV2e{>Zs8hz&oIL>GdOw!kX!}fH{uGzh%u2Xz z2Xk6%_$$QwWAkzQ)cV{s=fA0JY6@O}zuD}5NQt*i69cpI2s#OWA)mYbx2p2WNbtb( ze?_LB_}jMsfP5%y*#FVw{}&Lv|LEQSCB63l(Jm0IVvQ#FUpve1XRiOZXv6>i6?Xjb zv!BQ;g?x>grXrnUwX=Q{Jwv2DG#H$u8P7~fiSeNIIQMM!7*@;Cv9WmhK?turfe5{i zh}^ootYrOXE7`^db21Bmt>Y^%tTsCb83w|+kuUr~?~>?@JvOSQ^U`pFAC19I9KcUd zumGcP;H!T7D+;n4MUn}!ZH%k zewvA*uzM&--*Ep(`ByFy`wqw-Nqh3!<@(3JzVh4t$Hv=a{omK8N%tXpg%;2Pn<|K* zFlu{$)}Qz$bUiXM^4)7uO-+K*o|&1MuC5%!XYgmg<e9_~OqWtuepkw@x!h{MlJq2)Cy! z&-ZJ@?jk9-ua8K%f#1v0SsyXNuB=5$#}-JLl4s z2mL#9Sdn(M?d+{8xJqt6P^w5DfE+vWLYTTq?7o=JkLir}5gGaddL5AA4Zqy1HeYUO z7EWKmRPKeCBfA_b#<=TA+!A;usFjQ48kgUzC+sm@yUF-Cd<@;zNnIP9mru*cXgb>f z#sy_7orv%x5)gzO7<#TRk%4_ff3zMVtLO)1pgRW4hzIR9{VRHU-s8tfMq$Fu!eFX% zVHmtl&nd{t@?YlytB51>iG_xZz8PrN#FG{nTbSMso__+J?}jQj4fxWPI6oR+-{U}J zxfp{sYS%TkXJu7+EDBCkt|?8OQtFK79m|X&JUnJufe-n%XLEEJtq*dd^F@HF&xMXS z+Y}GSK4XUHUH*B|!P?F+{v2^4)|8LP+@v9qWe4>S%l0Q}TXNLvy23SK*F?HKFy}`Pe1Ia%WU8rj%@Ozf}I_ezSO;<`Rz! zo19Q~Q9<6o%-9Klto~=tdX0fT?eFG?z_MK~{MmF9McTUwF;vM%x_I9|D1}@5R zyg}Tk&RU3?eggO;3Hs@XA@eC}B_A>)(7@I*;BL<+{RsOK`9TNd( zj|P>-Zp4p7-m5f$-xvVJ-DR}EjNu;gmQX}T+MqS}MECTRe;zfgBmerq#pnZFAWd|t z496v*;82@CWRTmPnr6|!yfy+{iWAc(cO-H2*?Yq(q!mGslf>#(k>XSMPetx%W?^{9 z%uBTF=`}oP2mk;C)kl_`QsmUT_gbTq2hYbjlywIg`XIsmFXIdA}X$W&q$8^d}q-Rk$x`-(R2Q0y}gj0Qdd7jVzQX- z)2Q72mrPrNoS67SGH;E=$%1R`9#X)4ZU%C*N8UW9NuqpNBy1%%vp(c37|-jIcP%yh zId#e*t-QYl8yE!L&tsAUElm}>p!AYLDk{I5bmc&uJ_{Bc*{yyOB{I#*ZW3LOd`06* zTpjgtd;%KIHI23gvMZ9r;7a&l3>VFCKZl70UzL6Ga5`JVtnX6k;x|mFX}%2$kH=E{ z75YrTL7}hG@yJ*TQ(w;EJ&)y%)ttRH*Bdu0kKsGs*?LYp-P;?fUqVLByxJDhH!?DB z4nk1r*e1-@`LtdS&O}y-3Z{wx*YBE}y z@w@NpyQFb;Ih=Nfz#6a2#&!+Qn?7kN8+j`?>#iv|qe54sk>@wwM36++gR{}^94a0N znGOm|-IK8l!80cQoGBC0uG0*EGvt8+qaiO_aRL1zu z;O40`HMh+eb=&2Z#TIW*@Dl(4`9D85mq_Z(qE9TbGdGkIQoVUg^Xy#z_rLvGOLlF0 zNh&WPpE>3oUqe6JRT(=Fs9dO?bMBF?1vaqcE(olaxS(F$(&sJZC$~b6u%+Q+r7Y%y zR}JvFt_uKg^_EHP8H*K^6>h(zTQXKnm}Z2H4c&da_GsCP$Q=v33FsOOkTEg9(9zX} zQZq9%3&|TAW@r_=*ykUJBBJ@|8E?Lwm211A^8^*QCJ2De9-UYu#=7+6h~vG=P!3%% z<%K<)?7%|GSLSNOp6Hm73fp1 zXlgBEyf9WjJi@b_Y;0q*m?<7MHkR0^_MV7HTTAOSQ~tofzL#oV-X?_^6ve%g`cHa8 zkha7#Ldh3Cbogllo8swc=-%D4E2RWYpC4!#QYFI?A`GNX1A^`|`BM6eS6ODowK|5pE)ygZ%f_kuIf*H zs@rH0X7R+jJJ#MlBzvQwKYIozpIaCGahFs7HkerRzn}U(Q5Bk;zFuBN80USpa}Dt^1PAnpDIaY ztNC=jPu!1F(BF66850r`iU`lLKUG3*^85g47W&EC^3ux6(u3B2W>fHRq~_nW`u{DZ zE{$@JiVlYU5hDHfrO9^@6%sa~p9rCwCEqglNGw6d|&-4=CTgmPv$s;bvdZT|V&g^KT@x+-(dr+7BhX78WD= zXhG`xS{Q}Qcfz|J>G|{j-;cEizEmpFZ;9-oQy!C<3Nm!wQPXrH^{eOAEVkjaai*K^ zxPN%nuCy;@n%E5*A|PYhwjWYFEkab(>*VIW1n+!z{#FY?uA%_J$4QcQ>+hFD++$j* zmTxQv=w!wJwFbq7eUOmdP@4zqF3oay#VPAget{~6*8Tp^^HAakn6E-phfCn`Sz{u{ zI;UE5e5zW|(^#JY@aQYLL!u5;)ID+2(v#Dif2Z*Q)unSfsN)?eyEmU(TGv-Jlrn=j z^8a+6RsGB#-Cwk`lW9`}^)EZlns!M8(&sH+z_Ji-Va>~YX(})D9k3#lzeX&&u-LRx zE*xnUQ9D;@TkgFYiHBT2RsEKl2dInL)?B3t{x5;DCTyV-)GA;yw$;`4EL)*|!N34% zYp3uYz6X&3AEkZ^tZ-gmoG4K)_DMCWuI;tz;kpF5GXDJcGG32~4f1|Sq{e&Au4|!V z&4^qf+*$PWaC;Yc@D_vzAUeIXlO{^;bl1p}ELe-yphal-J3eXu=0BZ@=rUWHLJ|?O zs!v>BSxPT)L&oX@Ki&k9SG?AzQz=6>#ryuTb9Om41rhj&mGJSnQR!uOGJ;QW?RzHV zlUy|fmNy-F+vNWdK3V8gqn?PB@IdO!+i-wH0Qt|g_MiN}l|{-IHH6qyl-nIs246}u zxxCz7HVo6eD_{L!j9sy}GD6F}+Lc~l-28LxZ+}p`3dUzbt&bvEl6(xas_ zqC*`M{Y-G(4|g8371Ap+1k6`4HTIH+2z;8Iv4HOWDn3DsD;=)>eEudU2A|vIw02++ zKSW92Y<4Og{G`f#;&uD!zXS$FlM1SI1B#ZfYygjdmI+OQLEcD;c zs@Y-6-F{KPyA*t_ZP=u}+*^Ul6Z0%^w)9f(*JB}QNIu#n$5TZFJnM)yr)yt*+FCai z*u*2>C?h}%KeB*GQO zSTUe}11mY}tLakd>gD15?(Xj4d`(ShsqXfhF=5!|KG``r2x&d(qY{#mv*OQ9G?h=} zu!!j2#A1nv9cpiHZ)+1`h-<0U^SSMrXw%6F?sNx6cHa+!2XEbLw^7g8bJR5m&hfxU zOE5}_7TYIZ89w0-e<$pWm8~VqyCJG=k(CL9zjw!u*yYsEYTk1;344`#dSsnw8Ci8hZ7`@zK zt&b4dMN1NPih+ZJA)=Q1y(8{2H@Zs)$J?z2>0W4bQ23EmF+>`oNdtM7D*6bl!of-t zlZzYDzPl$G&*|x)6j2lx6>>26sxk8w8#l|YX!GMOcvm;gZ=9!spJe5O4sN~7yANVA zHc4fh1`z1Ww<-a}Q!na7vU?>}q00#^KYsDZrkw1TJBmVE1(A2%f^i$k;G$a?@1Wg= zsbU|_(MN6S2FV85t#kA$gYCD_8WdF228UgRPEj!U>Ez@@;)ed0ip!qT z&k2|n9RuIkmDoJS-W>7fGBOa<+~y7=ISEG6FIIc_XF)%pVYwVF7edH>-u9U2CCMUs zun1-fkAz$x@FL1Ra-U{G^q1q0U2Mm5pS1d2IgZq1IcqhsEw8=Vp1I4qsVb`f+mKQPYzS z3;PFgOe}lta7;r%a8f}qFD14Y?4zMT(y~AZrv4G?d{3pTR)*JKXKPQq<=5LOj{U>T zkynnYOT`0)gv9C!hNS3Ev`e`@IVz|vh*GN}p8;7G#GIMB${QAVZZf{CDZAr2;rML% z&~AwYdf|n7TRj1I;CX-Pn(de=6``l>!NTi{Uh17S;`JzaJD3!CA7r!>C4>eTnFz9EGxJR|nh+u2bR zVjDtH#QQg<*!2neNMnug@bLE!525H7kB^UVaBv528Mz@rW$59%txWtRg*x(FY+SEG zyj-Al_$m0hUcQ4mk3l!f;C%|O+nyYsCqrC>_v_&HCDdy7gP|eAf=%WY{|7Ebt@8_1QMx~|TodhsowI|Jo!6r4TY}H?H-#cd z_-w4pPZaA#=z#&EwxAk`CF~s*F?S5j&tn6H7M3pRmfp%XYLMt(J%pqT5pV^5fQ090{ z!U-SQ$Z0QKr8aI@ZNAD>hbk;YuO!R~Z^;U|X$4MYKwTib?&k%yvF z5u;>Nne3+?hrJ}LEno?xW25A*tsFn_ob`n0Eiq&9rwD?$TzGVo@r`=Zrh=)-;~@u<@0W&pSkTj zwOn0y5Zna-a@09jsV$r6vTrImrb6Fwivz#l`5)O=)~Tc5Y#?QB;FuQ^{GWwX&E9dk z%J(2^Dn^aHZ7R+!mD7L^+c-=J4oI+-%b3P7dv)P3E(>e%{a~v3%xgU2?RV9C;sF#5 z-UbgG*5QpB1~Whde>zB#-Hq`yJ=dF;kx`mQq~bMGy<~yF10wIY9BlOX3-5Ogt>crA zr8-wT=|}RDSqeqB-m#05fzKlmOcF(2l$vtsaDzGVo1Oh&BIoX6T1Ura6B}g4x0xKz zf7IepV@WKg72SinQquBxJKgfwDN_^(^=uAx^jXHaE&u!;jib1;p|-Y^MH|S=%S&l$ ztXtT=J^yEM(-W^;O-)U|D=AIv7Tzn$` zwrcOQ8$hoHb1-4P!ACkeNpW$SPoE5*y#UxMroO%&bTAW{BD5!Jp~Iin`}c2_+0b%f zwfEd}1M~7-y4hbtF~1lPsG%Vt@a*~tArL&z$F3QYRAgB$qeWaWb%DN3D{gwe9rg#e z+|0kB4|^8Dk(e~A^CLa|Fu#KY2MY(=Jc-HJIoJ4s z^X%-T=2K-|lRLo$)KY#t<3R)^Z&C8QB&0qis>x$3<_JuOG4TwC)or9 z!uinutx^!=%@N4xHEeCmR0@o8R1`EdVbt({%^`gS>)-6TYm-clL5@mBjw;i`;^&H^ z3@nVpxiS{@!Z_>TM4UqsVX;H?AM~RKdOl>-hdXryHOG8o?NS>n_pYU~$aDrWZGKIn z!yAdcNEpOxf8lh+_^vKS-Iu}Wd*)ZpYr;3f^CjRVWloP zvd;Bc50P#gFUR;c{!qYVcwp`_Ze5@$d6oJhf7n{n_U~&}`)@5l)^-nB#G1DTAxJol2YAK(c`O?eWivDooE~Ty6GI7sYMJ^|m$9>Jc{Bz5U?htOn^(8SDd4;z6=n(}}og zg>U#<;YYF!>oKgVFI`c=>XB;_AzjRBQ-2gzjmHMA>gO7e$qf|V2c#|Wll#zKLW>YY zrMoeXX^|oz3Gt|c5WD^6Hu162iy!l+O{o}~JL8O^5H6>|PQF??OhIu8s0Y25=2rzF zY5_W+r}=FaV|8g!+^`(-mfqZ8ZiRe+Iy#{OGo-yC0Hf3BRpZjW&Ks7Ap#_SW;bA0y z(OKL_G49)d9>*Sg&Tqc=K4SOZ(0BEVJtN$AC;S!#40EZa_hwsn*8LQ0ErB#8wSu9ilSz`a9h zf5qb0eQOBc{hg2JBRVDleg!z>1*p_E`Q8PS;pv7*8n#-P-l+N_58Xw`85F&YV0*An zFvABmEXgHqWJQa@x4_oWGjKn)&FJbcTNi3CFcq+`IM& zOQ*w$_ckydf&<=12fk{`%{1TNi1w`%ZYhp!eV8%FtQ~8OED;}stDUK;8fKlbiNFL# z76m-GxxLqUE##sn9>WlvNVh9q5aqAWL$!yb8@_XcfCNEK$mE{D9Nz{FS>wBziOu`U}fvL3nbjP^l zCOXd{%v%R_o20A@){u*PQr97md zht7Wt03Gg4B57qYz`uak;NjsxKAA^-KW44?7BKT6TuCM)hwv@=d5<^ zxIu0WtO|}cpn8Sj>C|RC^Ye7^6D^>5hr4!>A8H-WaU3*JCAu0ee!BEc0Keu~g}(*!f3rKxV>9z$ zJx+=y-olAxnvw~JFxVc>-PF%R;nJAIAHCK|4_9eSA3pM&65n~8Im-PlT&Q)L?Lu&S zE1?C?C%6M~x0L;NpQmD-b6Hgc5$fPW2T80Su^Y2d7?P$sb z2$HC3yMUUaqu--Z`okNIH7SI(*0b>>MZ~ockda~A3VY}yVRe2ZZcH`6{cO8+t-X*; z2m)o!INFu@f6JS|q9mSi{4hFjO$$5QQFtZtuCUsUzimAW0@xaYnb z?%qIgmC`KLt#muBqUbKc7J@ij3rhL>9mfw-U0`p}(ha8LaW>D5k7~NC-gQc*zsdKfZW8lS$J`Zg3ti>H*1w%hjl z-UyY-6FYb+wSk#*CQ{>m9}mne}6Vlpsk5V~WScrVxml; z`M&fXy;XZn?o5P=MZ84ZzTwZ3RBb|ZVkBs{=i&_ao@$8jpa-!Pak?GNwZY8%hcWN@ zmS#l`tJFNF#DIYn@yz|YvWW@i@{$%`;>wM^M-2)PVY{*KCmI4yoOg6_Q~O2qd5Hbs zN1{Dt^}-o$wRNuz$Tkka)#C7EkQwy$a7k50Dk1}ED7_a)ag={HFyXZNULpwoA8U|u+l7TGcw+X!`Qj}h=6Wlgv!SJ z_YoDZnNP~L9CY@;M~PoDAERAw;RWeRB8WZeIBE`?Ks$vU*Gs>HVzs>thP;JTHPPY` zoRtc_6Mn6xz3{60^kHN;pJ_`;N`kIT(xn5D44gAnRJ3VVmy|@ng8-1m^%oW5&(coO zamJ^d^U{>$n6)}NRSL!2IU)cotzEO7w+?%Qs9bf`#KhX{y`r8i#0F93M`QDE#1H_h z8+sDl+(T&vBrnurDt4%tre_W_B=kg%MCZ&Bt3fHVKmz#=L`6lF;B=fZW$weTlaM|! z-_z(??|kv%h(zbfQc2%sIv@`l+ z&(=+iIHxp^0i)LKcd$LvWO`%^qE)5s|IGwH+SN0@u_+U6!5dVWQWa%?D+>Rnjk@2v z(AjaOuXGS-f8Tof?9{ClIsD1APW#BlMN&;n@snr}Zb5R!Lna{t9U1sY-{>T;c>P&C z%tZqZ_;IGZo6r?-`=`hf4;aB&=1E9TE)5`DdA$c^@ebw14r<5QgOS4 z(!`9r;Rb}=nHoI*AS#YYbH;RNJW(V}ts%P{)ZmdM;{(qE=ESuZn{$eH>$Ljcaqozi ztrKI_p*}>nS4vj=u7`%@9ZXJu*QJo_mdASW#>+4Ibg!s;&ek^$5@Ub6-#|CV#uQX= z0y@gd%?{U8>@j2i7;ftihe|dP7o0$8gMtR(@cE7=Ba+hP;&J)J_`&zWVRdIbO*&Bod?C@jj*d36T zYOoPsotgY}s-Vt1T^5BpZ8PMInuoZ+lmZ5 zs(W%9Rf}2A2P@GdktvEf!w#t;*$#fd;=(qZqkpG`m3#wH*MF6?)_K9j5rPpH)(Uz{1=z=$3feX+?DRl7nfmEJz@>c^xZ=Y7w#-1 z&(`Y4PxXvf3}~2860BYG0&XDf62FQch7tg>V^1l9LnIsw$=oG=E*hrYdVCE*sGHRP zXLLgW=nOO&{tzqs$mwB=;KP{QoilODKe3iDtpsNylt^rUwvQ_=k*uH??p%xoA$hrpyFJDk z4!m`_NIg%q%r5t3Wwb|?q{a>Zor5;ZwrS(MRWy?)Ei+=Y;`J9In>LKee z`~_)%)3vuSs^qK1HJ5`sqkwG{8``DamT1?Zy2*Qf6PuobX$pp~7Bd?MSNRQ&`pIno zi>QexA@Ad21`5LTLf5FZSPK;@>Hb1S{(-CiWmElXPx>!OhV=&m5Gy?)-wWo*hGu>h zixp@mF#^(^DqaiqF59EXSqJry&ac`(%r-ar;c3i1w=QY`8+|8xt#!`CJKX9*>EC`m znh_~a6BK6qH1>@StL?Gq@iVPtquK4|6}zqgq-qE`Mus*O;jM@$_2Q>cW`jj{TH$G<;5K&W?yLb z&|rwe#lb0O5i9ycPrtaZ!0oWp`k$)FHtNj(kEmXxI`)4D^}PRKarcLbPGXgs3^1%P zEk6Ctr%#^<2?;msxc(ys7!FtLqCxNq6_v*L2P-UyxVP|iFKc{vZGGJy1~E!VsC_5I z5dHA>=K7imt)uTh$W{a_q->TZ9jIC5YOj=`f=WL;#N%+=F5U(@5SDekS_>rnu0uix z;`VBoZ#Vvd`$g(^84HR_UT0TVVtoAnfNW)DWwQO0&(g}v**eTp8eIH^w?2i9riqK^ z_?ecLR^NL#+izW^({#2o_0P)K<>4vUfl?-DyEy2@JXZ0dw z$oB#&M77059CjM!k0>-wlL>i7>P^94v~jtB)E+Ky$U06|vv8V1?6bw#R-#r`LI0wz@sv z&HNUce_y6RMRoxL2@5Bua9nY5aVw%=SST!zuv1sfj+~qr=7CF}roDA$A#`#6JF|JOos%C)tb|g}w2^(AWl5pw_2TE5d0?qL}hJ zp7%xih{`T{cs^y3J=JCKvFwMsfYTKCUO#NEAa*C^fr_>#;d+AjU9<*e+>7-PfQf50 z*3B{L2GS=G&>H39)IONR1?X-c9=-xps;ha6s-cU`F)7Lt*X`otIkGyhQ#0s4=HkDs zMd~R8TJuw4R0O>`j*`(4uNrCe*|!vdeu9z|$UeS&b1%*;p`@h!hi!uVq3m zkCtlAP)C;-tNAId$j~!F(U)yidSxtehA21=*w%K%SfoCa93$KF&C4v*6K^y3$1lxH6RHX z$i9R$(Qaq{8uU2ys;IcHsW_8&)S17~!pC#xI9kh=j6@Y_A*tnZUkGMF%E)N*PQ>pC z{t7t-ulDilEix2aX9OHMx;aAwo*v@cu!9SE)p7R$VD5mR0Hi67jO*(2v2+;zI7GIY zF1d;GF9IfJ;r%Z1=}3nGVgIX=;qS4RLkk#SO9`6&pybMSUgdOB=aD|r{%(7QFuvDy zG(!FHc&x^kBw@SnKK4>i$5N#Ka)`!wzBf z!FF@VFXWBKvaR5vGIhAj@t3YrYMk_P(N%XH!&cWIgXq5VjZfiM-4a&!ky(vVz9W<7 z0o4LLjE2-_R&FT@MfI6)LpAH&)3Wr*>P880Ekh@nd5glH`l7kUd4D%++d{+kx+bj4 z?iH7L8sgkN6gmykjJU&7?t1qx=jPv_;vUMs`tVlV?HjUur~4iS2e$+^XESVX(vtoL zI5l@>%lrVAh6#a$+Y%zlDTo{#w|3kW?%-kOBGaw?r;zwPxRrrI4)R;Vr4f$ffgnna zVspGynQqMZ%gu&8YYr{3>BR(wTZ@a=2j9ydeS@gI@QL3&@ohW0U8L_GKaD=3H`8h* zWMPFmw`f2+>As7L*L!{4|KqTlS5gsPayxQ<^;CMLtTPSU1lu8k&+TCh6!NH9#k8iF zW5R`wLN@#bmAC_FWT2p`i97jnEQ2#c7Y z&A8+s)WM`qRMLMJ{O6Ke3t^_4@g4nx>?M>P4wOO_9QGR+%Dhuy) zDO`D}ZFy-nD)~XIe_x?ja_wM+$rq41E^}{-;?Sj}6Lnp+4?8n$>Ne3_7#|H_z?z0A zXH(Ofuf@Xya8Z-5SE-Yz)aBbTSOrgD5aJRp3{khTXAd7GA+CoMy2(4WWU5e6G@{yH>JZRx|=mfW0dL2 zU(t)S9UWNW<2eL<=joo9&>s%-j2-&D8WQ?BzBlj!KqYclBbjD5_^99*&Dg@2y_UNc}bzB z!<5s5EX9HMLQjIhbh5iqvDJf$)=V)3IWPj7nd{s_S~W38kwzIlu=L)iM?6bH4i1Z5 zX+(Rra_7tTMZ=PlKXha*rn?0BLLV3ID0#uI^C8#+;s95k@#LmOdB9;Lc8$Kdz1(zc zYh<+ZGRN9eebPIi@K^7@x*UPD`i}EJwXO6}?ax0Rd$o~O>2Y%}W$~K?KtaeAfgbLv z$Uy%590%z56;>&(X5ik{e>6}qTgmhWo*1~ZY6C_nXK;3)wZuC=E8c_$^Iv2zef!?D z1-f%lXTP!y@k`s=Co9 zN7*vKCHQmAeP|Ht881-!e)Z{8k@oxgVu1JLps_>667_5q4mIxYaOxY-*emrS%bome z{#LEaN?`8B%^Y_KrQ@gH`rKgR8`ts4q4ePyJP(}WB%-4xFRj|2DFq#ivr)n=>!;4@ zGhs=S+h2q51P{?RIx}TBEAm>wM!M!Z5ZRWOfZU%==AorSxYn_0jh+v1w|8Z;MF@s4 z>e$xK{L$)agUUKzr2sWHW|^2G&s|f@o2ZBa#zxTbx~H|(B6NK;Q}piYSitk%8DV)$ z0aB6|Z@=eJ>+2j3=k>Qk-hrEfh$yAdnS&fNm395}MDC_Xp{T?ZF>yF$W#}2mP+qSS-=Z zvfp6?jF^(jn~k)^BN{H&MmlbHHDb!Z1FXE?5@NC&DWHd+;DI}a)Wd{7rYdCLzH?Zm zNs^cV5oot|^j?(}h2&lzbR&KYWr*juuB>RcSzlCaubw)`6%ufaY(`=50;R`mG;=QN z81O(>W(6{kD)upg(**@ML4;5F7F?KR){P6qV|X`Lb)o^~RwJf@J!Ch6FZQN1CXdbD zgz?)KtexXm>M=WL;ZGCmrcTU9OTW)|LO6qYbB@CJx8kO#7W<_)L#vqYXlY-yLSU@N zQBe}p3#4^j|ofeTaDr|-M8Zq%+)TGrv11j7^-XWl|i`ix&73((U)zhprSVE;0tgLPELx2;T* zRwQZ;&avZOugBDW3l)HsWD^_j`Wkc`47MkO9OZMftD>z7Lob|LtJ7g8IdefzY}quA}zwL%Sv> zDzmaG3k%PCleOkZ*|@|pfxav>Wgby#kFu@E?5G(+riGh*mCtDfwuq@I-M`9+%a+|Q zmgl<&T$B&0zq3q3l+EUm9ptoFn-#^Auu}e>os^b*){;Kbtj$33;^8Rn$Q0=u@xN@= zn!uI)UfS^%j!}U;<3k-17oi9y7b|fXAsTW@la<$X`DbxRr4dgDeh3(jaGpQn>P&P2zcklsP3;Z2Jn}~oG=M>GZ@NHCqk9zjcFXZrPVf@5JV`UIxCN_TA z+;y%^7CT2r<&Rhx7#Oe<9uIgG3jR?_q+m-G5E7ZPi;Ig^i{}G$vp+jq)+#!blQ68R zstR_#B;7;j-!o53 zuH#*+)w)*L<8=r6Rd_*3Yef{AdQ;$Rt?8(nKmi=nZ>wVlErD_t%yPs7xQvxtwg&Wlux__a2p$eDOME6koQq{B-FUsihA#*MkeuZe$Ny6-qd z)CRK`6E+Z_VRCmFthMln_^Mv>;CgrstH^3kIQ4@0QwIzx)&HDjF#6D4(c}unnRVA( zLb1PC^Nv3+i|jIn!uP#h&$UX*wo1NDXgk~$^is4jjhuc^+`17?b9Z-)hkDk0FX)o7 zdn*p#{^vYUyTZ<6Wu43(Al)66uK6)#IJm$zUe9L=W}+EmUr9OoZ*G%1Z0CA9O3Kb_ z(ufI2c6N3_fq8cr(JY?hY~A*VTSsV9wb=SYIS2INjn7QpMP?(!+CWQkxb>UsT#anb zI5rLrJ{tC-dH#wGr#nAHPkSioCyX!W)0Q^+!@|O1$@9+AV9mPa;m`PP2%Ha$2?e_X zpRbp|`V+n4d1FLV6Grjj^tlPnGf8OgHi&G05j^vD4tnd%Zf%a>6-LCvzP1$iT0s`A zgVjapHRrCmO5Z^#zsS$}^0zut^EKAt!NCN~`o0hdBrnfYTs%;_WZQ-l`&2{{gBT^R zCF|jgBSlVm*SOUgP3PRS)N=EKaF6}=>C|g?Hv4?5A^*sfS(ni4Fl`oVQM*Y--j?YJ zWxZi0hgYo^L@d*y0tx07HS7`FA?gH)Ur@~~uaWZ?;PSGvzGRM~__YU3A!SY#X&@sa ze*OB@&(H5-e|i|krK+ri%}Kufn+pFhC01cr2{7iaBJ(#?N=iyVN=hmuB|0B-4>&nl z?GOpTfSai@pB_x&c)C9uhIt2=_^ds;Oz$a>FJJrvOO(%=#RGZ4MMc+`#8cK{gf2nI zn3J$?2TD+QrmmN;$ct);_F|>!_-aQ048bu2cUTAswUL1D`!LEoZ04G9^Bt7Qp&v~Zqv*jrIRx_4Ra>-ZT&(o2c{ zjJ_T1eb^T)Y4&&%6BDz0;mQzqw;89y@Vz{%w)Ps<(*8Kcr;`rM*{=m}Uil&Uz!sy= zEU~Wi(pAb2`zyjuO&i&UgoF1m3BhRWU}!Hjok}4SJJCJtnS+c;nC$UIg`NSgEdC!B z2xM7COt5q-*nt`>EG!%xj2}OqoSyDZmyk4!jL*)@z_O0z{;|ZeY@hMN%J(ptX)?gD zqlNZ%az;k$fq3TX>I)C#Cb18+^z_*XwK4yE#?bW>R%6OmyP_xvKX(;m>MwA*d=R ztj_*F&{xgRv%5zQEAi`EY=LkMr#&fRo`yP8hI{LoAtlh>ctU)<4JRSYM=Z+Nn79%s ziL|fNWC-Yhsaz3wU}OY4H&n*ftRorooA0CfmmMAoD)%zVZ@mnoV!Nw~OY@{AIrzI9 zIYTrvfs-`t)J-kS-YM$1uuvAF!IHC+wC0V;O>u(3l3UCDGLOd{J-4bn>)pg_HAijx8?GPf87lKqReq93``W`E5Y#k zyyfuIKV{~i2;D!qGIQH%q4`P-l_k>WY`=}4sPL7{F*p80S|bqfhV!QRbCw2y)m|Np z9;kvpVM@FIbo3e*!)rhQ!&26HVy@t70(R1`b@Jnu#ZZ(2aL_Qglh~9#SJ@oYqw_Wh z&dXqGPUQf1XMJ1uGz-Pcb>OCg%xX*dH;T*6?uM<~gjGK-2&aQI{N7PJYwhAH`#_j6 z)vPHTHfu_SJUw`nhcjFo;)46iQ|MCO3r5u*7x-1Mf4Z^F59wx@&Dsd4PB~g?FtI0O z>nw)R1Kn=xdg+Qytum*M-W%Ps+|}&r7@?if4a+@NZ>4?H~MP5UV?#oT70ObEB)7WCvotA z6=qE+1#l?{8!q-a5)@C-I*>bXKi~IVcrD|)5vyiO7dNXSOW!~KYRn@`Ro>q)#vrJ4 z!u-;e#e^Z$@Z=m-sf1(IF4ZP2+Vi_EDRzCmy>k5GXv;xQkb`N9&LRHe*_~4{+w(84coFUzl6>C87gQ9;YUBc(ppvWOiR!Es zkVSj1hAJ=1ld&dyf&5$}D?%7s;zfa8rBieFLw7Dv=i7M}2Js4?&XJOi+A10h2j`(bx)xHcK5|xCT@A4#T!lIajuwHzMeolO=1;Sy zeVY(ncEh1(#NRJ>?v%rWCa1JRc~3j&i42TKY&ws_(L9w=22*B~@1o8IYezbmKN?m; zq@OXrjW-P&p5vFkoUoIvnk{BpYW$gmiPN}iY)>zpi6Eo9*PaI3QqXs_SF#C^ox?#x z6S|FAD+qnYll^$m2-M+Rl`(UIa5&2@D z<&m6@WYf90+)?|Pl-fr)IdqVn&akC+g(@HDcn(<3sSU2dwuta&+}LMz;YPu$`i7iN zK@ups-q}Pg0VlXnQRA==Ijvvf3w>9knOJ)gvkVzRfK|59C@bQiK{e2wtV2}~cMThh zK4fon0yZ9Q4*M(vyC}ATv(9RerFywlzNiG z>I=!~i8VnD2s@9|3G0vTcl10{kv=hGeR;56z{Ty>4$-%k&M1Bw^Lv0KQ*DlQP!9|z zo%Jj2R-_>LMwp}_bT9!F1l&Tj#=h3FE5Q}AMY*}iS;)(L=X0qsq1MTRDGM7A9FPPWlMihn)7tpo?$oIoasJ=+qO*Ra*fBA#}Cw{2b_2-*jr z|1WgSMqVpZqr;66e^k!zc?O%)N;hABAhuRIY6L3A@VJrQ$>h&zZc$3q{b`I{r>L&5 zEr0Rq%muJGOeXvUyq{o`(m?StSeg=FdlgvV^L2G-XU4oQZRt1lyk&`Y>E9}3y05)pCN6uzy^>>`^O*(Wt*ygIq zOY2iLbVJ&MK1pAvjI1=K?_O~cX6*)HA#WEK)tW>=rvE(sT;g5e;;@qa*(iDizCYK94U3Y;-#z7j6A%oFNCHr z>3oDw<9ZmZfljkq5>ff9G+(SEYCJd%y+H`FNHR*I5@XE~06VQ`XE)&bG52b8ed4Dg z;f;hVcPx(yrh-N`fyXwA!2X{;fz`6OYCL^1p5{WE`~)u_#aW#G9^M-+$jz3;3+c!n z=7s81+-puxCizPMlVw~a)|`hAc}I7L^?Cvphm5|^8rg4r|a;#6gZKZv&X94N0`hwjA__QxC|!*3PS)YlcBGr!S(JVSAdtbdx2lWISD}RMxXP zHU9>QWtgx0o8k>?2mg}IoLe4AM2@cZ)8?|(TzpJN3-{SvDrNAs3$lp}=X-&+(Ahrz zX2}OH-nyd;67b187{(~Rv}?ixL%Bm^<5F_g&+ve^$Eg76J`FrC$uvSLr_+h;XpS~k zdwIe1J^v)FiSodaLHkQL)tl1@+$#+!;(OX+jFAs!S?T@!hcwmT zVgo#N@~lq1EBS+O2MO4DVXm9r7wj6SW&@}h1iT6%LHB3oJlml_DFn-7)mX&I-1ni^orsZL{F4dwBE@Q{m(IOeVsQF7+6w^Bf1G zlO6%h3)U5uS(WOJ6MxIc&+w>aX@JVTxlaE`gxiIJtHOFG3q-*9Qj2J!n+5T>!R)H1 z%I6c7pG>m{i-GkPoSp^9Ng$lp_LSD2`S^HrW>SYJap2@exOt*G6pj=N z)zQx2N+GW$1QXEb;Ml4qC)kXsTeH(o)hyHP<9|jGho;ijX5~Qo`qkvNryH;o3iJ*` z6O&~{l!iWEfHbl1e-QuI= zsjZSvCsmH6Q&OcK%6nv_d=DI{f!9}%hPQ&ZQIW*qfe*K+xD1el?dh}0Y1igijRDdI zUTPlZH{~=ib17!{S?^jJ@gC@s-a_)C#)5W+S-Au5{5m?-jQ@g8UwAk z&@=Mp1dn9BH2EC|VFOAz(ZkV3J)g)nxp6xz=4E#h1c0gL3cA1EDn#og8b@)d!;Z7U ziAJ!gj5S2E-&OrEG{ir)2KHrZ3xnr1STYzVLQ9Ap#dSPUB%-88K(I z<>F6WPOa&W`9*JJmTNWOJl-)_o+JlF z@v25G<-3X9h|%t&UoZQ(o4W)JB+H& z|6#s1C{T2GbMrJ#iW})i`5AQ0q)4~f{mzVc+#@;~jx?f)cHA;_x{-Ecdvgi>ZC&`we8g!KubR8ehGH-0f$LYAAVR8*B3uk1to3P<8+a39o14ovHvGyp* zVP@=E&iHsZOb52z@2dYeA$K+{c)tY(T`Ey^btm()g5Cb+R?*ST2`G0@xkp{^Jr#Lq zz<;oKe>S*&K4%_&+pL;p`^B<|lUv!<>PA%L@{nRQNORq<&a(ST*e(17+g5jODtmBU z!`=S7*l}5UQ@8)+Bhy58AnJx;7QdH@r{`uD!jt6qx{$HHr^~2WzO+UH`yGh?lcfc1 zB0m0S6Jc%5si`Tu8%2_k{!KgceQFaA4N$##Kh&V|Q6pL` z;A96{D6`bUONb3iaM{+GmNww6(1ykZwz-)s(tHD}I?R)G5l z9JMvxJ1~_D0diY^TCVCrA(AC`?^lp*KY%^|itk`NZj^KFM>FC;YylXIt z-RiM2M~>a@V&Qe*jB>IQ+vv=71by88UxoC-8mG%qgIDxk2jimHOHEDY4VqOb`Uz;K zaZ!!{RK|mCbN@XNg(0g8K0T1aE0c}@be0WvZ-h)VT#d+Xp=0;0hg!3Z?uJBB<5LHG z=4Y0js=BldW+Pm7HG`!VzE;50=U|3H|1Y}UDlCqm?G_y%0fGmD1ShzAa0n#0yK9i( z?l1$v5 z&g+jG6u+*C1zkt!3ZXF@0}#>JM5IbBBU!0!xpk2)%z6btqYlDE8K%%If=#9|FPt_2)Je1$%QEuJ$on^O z-mhkA05YNKNw+SU0d>S8E+Z=gQVasOs zqv^FWa-WQ~`ThLF(!2M7lAKsccOML6gehvHi|y=74Z3dlV$FrQKgfQN%q)MNTjFFl z|Byd1b*+!V{D5dT{8R&L57)Z)YvitS;DpI+i{tvGaNV)_G{q8K{Epx6UGzfcvzPD9 zVd2K^(v_;)s)+dM^20}ke79$xq3eJH#wml%l`qf7sIGrTc?gAp2}l5}+*0c_nS z(dF{4*UKIlonZ!vr2h(L(S4}H$s8D+dJ|OJiY#@vW1*_rmL#-IN5)TL_|bjT8ZDsE z+2GM?Afyi<;8y@!1ZiWA##(0gQH~T`#!gLLsL@~lkSC( zMn_qBeA&}k4-5PD9@G}5k(u(r#GSJ@sQoiAF_JVD45xML*? z+-4n?d5?kAt#Qy6TC;F{0q@z()hReYuq`J?-mR)2|7&tf&8^7l+<$$wEIn93DC^B)`t`?>L@r%n1zd&aCCm7${dU4hG~8+p&=mC=)LtD)U=bcXUf zZVyj-vjCjG2SV}HZ062(Yl#+`Zx>n?T7oU^6|bMmJ|C9*Dyl}G4zc%pp0F>lT0&(mw$1zhL~|C&RlTxs0ZB}qfrnUGDG z{wKzQOgSKtHUIzGi}06V1|vMaR;nC>!Onxf2EJ|mmtu$m;~ZWr6{zN8i2TzzZzW|) z%ls=Hh(-Iq%t~HS7{vH*Yxf(kI{)ZhqCUqrZ{FOVEDsF~teZ79HOWxLtgRUZ8+&N~ zD`s|KAA%lSZJkKk%8LEw;@RBrJ=TP_f$3Y7$dmNtyY2Z$za9^f#R%L+RKMV5nj6cQ z)#t5y9DIDuT$%XsaU~!kfE5HS(JBx1U5Ehn6pY^s`4l4YYCjf?$s~i} z8rpbv3T%A75Ik`$U7oJAdS_*2H8wUv(Exts<)`VYLUm zZ3AT(Kf8mMAD#J^jBxt}u1@B^*a(6hzgCrGEj~ShUTke2B&Hq*W=~e1h?o)4(Thh| zf5b`5TxU09&|1KN#&w7UOZN&~+toUW>_9x>+>sf|85vH@cMy-iZ@)q5rXEWfe? z5w)%mi7?4sJ>G^?cLqmbMiGbrF5nlbr&*1pL`dObfu`{tL~p-IeLVXm?Q%-)kN|GB}&=Y{mt<@kJbQAjwoW=GG{ zS9^I$_~^-O0IEjhd=Vv*e}QwHdqS|}eUA&Y8W`pQN4;NawtrdieN?<(t&RDhq2krc zDAKdMNvrWArMVByK(%I3P@0D>V2YFfi_Z&{i2A+U$Lsl8pL;%@;=WZxMDN`h220vsT6U z&1%eXVmLram8JX*`ICg#u>`ufC;iEOG8pdD7BxNsR%3IR!38#)gS&gZxi%^am6_3W zj_%g80XzWS^Yi=@(Y_*EHx+9tk;NZ{H+{ndjk}jwoQF#~E^9O(I2E0RF4bO}N%y4N zW6V`D=z4zIuaVfVy)3dNnNuBK2UczQ(|Z+}@b_26?R)!l!Sk)|eJ%q$Q#|-M_0b&c zea8#WVF?*J6oglX^+KH)89MYrVe-Dg%!WXnF=5{N?C1=cbjn#EAM5){JNXy94{y7E zkegD67dY6L^y}*_R0o_-o(O>t?+fFNVq%u7(cR(HMpoGfyM=Y*Ge1YmWCBx|IhUv) zfQEqs&E1$1^UUvU9Vnh2K12Sjc8${1q|fQ|#DMk^S-qMk6~ZN>N*Nt6H|O3=p!)la zQM=u!kX7cTCh>*C{GXmAwT_1wFWaRJusGwX*jlr{KNqst>u;ew_QBOFRtoV*??XrBu zoJwqMWo#(lK9VzxAQGpQ|AUo{we-V@aV&NUw?)lDO`OY%=x5WPBDB`3vFFblxUD|G zq!~M;si}}D!s|jW>6gaK=0OzUt(C^wiIh!ViEle|cp0!w1Wyo#iFoFFY6Q3F-Wjqq#KZl|mV$kMQ0FLh4DMi;(@;DlF*CGr;fH zSN*`#prrHLWA{jjxgYIwoZ+h>4+;(oiy89w@$=F z{B9bGn^mshT*tyqs#rX5h|u4IQN`IhL0cBT?7iM&MiE_AD4kxw1?M)I?6AzbuLA8{3zF9Li<&oQL)x)bUJPLesPHIW{ii!I6@N4nX}73O?~TYi>W!`%W6NL%?v z>0b2(N2cLE7X=!kKAQL$=G8u)Lv>v zYQ1%T{#yth%(|Xqw2DANLKx(&zm~b@;5NHi9q@7*g&9&$<11Vcw0BN1-_&Xe(j(mQ zVMuN&(9BwEb&A4nCG=WWY%)f(W$1h&nk_Z3Z+-Rc4)s?)MaSZiy-b+VGr5E zgNh|R0^cLXm$DHDK?O|Et?uq?17K6iK*6c+rMZ(3c+JYLFKbrTyW6EGlqmnf7Mu!w zDE6eL&4`r7VojYNH3S?Fl!t)4Yv=cRA0$0|KdrK$7mI-`?>griX3|o4=lt@`

CY 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 tfLmi=xX|{Wg9rfW(&2q_<>N2`_ method for CSV generation, so the file will be saved by postgresql daemon. - -.. figure:: cdr-export-download.png - - CDR export download link - -Yeti Web interface uses Nginx `X-Accel-Redirect `_ mechanism to provide file download. -Web interface responds on download request with 200Ok with header **X-Accel-Redirect: /x-redirect/cdr_export/4.csv**. Nginx should be configured to handle this redirection properly. - - -CDR database and yeti-web on the same server --------------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **/x-redirect/cdr_export** with the following content: - -.. code-block:: nginx - - location /x-redirect/cdr_export { - internal; - alias /tmp; - } - -Where **/tmp** is the storage directory defined in **/opt/yeti-web/config/yeti_web.yml**: - -.. code-block:: yaml - - cdr_export: - dir_path: "/tmp" - -.. warning:: You can use any directory as **cdr_export dir_path** but this directory should be writable by **postgres** system user and readable by **www-data** system user. - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -CDR database and yeti-web located on different servers ------------------------------------------------------- - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **/x-redirect/cdr_export** with the following content: - -.. code-block:: nginx - - location /x-redirect/cdr_export { - internal; - proxy_pass http://:8080; - } - -Where **** is IP address of remote CDR database server. - -Configure nginx on CDR database server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Install **nginx** package and add the next server block to **/etc/nginx/nginx.conf**: - -.. code-block:: nginx - - server { - listen 8080; - server_name _; - root /tmp; - - allow /32; - deny all; - - location /x-redirect/cdr_export { - alias /tmp; - } - } - -Where **/tmp** is **cdr_export dir_path** from **/opt/yeti-web/config/yeti_web.yml** config file and **** is IP address of your web interface server. - -.. warning:: Make sure you configure **allow/deny** ACL properly. Wrong nginx configuration will cause data leak especially if CDR server uses public IP address(we recommend using private IP for CDR db server). - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - diff --git a/en/installation/installation-1.11/release-notes.rst b/en/installation/installation-1.11/release-notes.rst deleted file mode 100644 index 40389cb..0000000 --- a/en/installation/installation-1.11/release-notes.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. :maxdepth: 2 - -============= -Release notes -============= - - -Changes in 1.11 version -~~~~~~~~~~~~~~~~~~~~~~~ - - * Yeti web refactoring and more tests - * Migration to Postgresql 13 - * Export active calls metrics to prometheus - - diff --git a/en/installation/installation-1.11/repositories.rst b/en/installation/installation-1.11/repositories.rst deleted file mode 100644 index 532ab39..0000000 --- a/en/installation/installation-1.11/repositories.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. :maxdepth: 2 - - -========================== -Repositories configuration -========================== - -Most of servers may use same repositories set:: - - deb http://ftp.us.debian.org/debian/ buster main contrib non-free - deb http://ftp.us.debian.org/debian/ buster-updates main - deb http://security.debian.org/ buster/updates main - deb http://pkg.yeti-switch.org/debian/buster 1.11 main - deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main - -System repositories can be changed by editing of file: /etc/apt/sources.list. Since we use our own package repository you have add our key to trusted. - -.. code-block:: console - - # wget http://pkg.yeti-switch.org/key.gpg -O - | apt-key add - - - -PGDG repository key also should be added to trusted list - -.. code-block:: console - - # wget https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - diff --git a/en/installation/installation-1.11/upgrade-from-1.10.rst b/en/installation/installation-1.11/upgrade-from-1.10.rst deleted file mode 100644 index 52fb3ec..0000000 --- a/en/installation/installation-1.11/upgrade-from-1.10.rst +++ /dev/null @@ -1,130 +0,0 @@ -.. :maxdepth: 2 - -==================== -Upgrade instructions -==================== - -This instuctions describe how to upgrade Yeti system from version 1.10.13 to version 1.11.0. If you have any other Yeti version you should previously upgrade it to 1.10.3 - - -Get know your postgresql cluster epoch -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -PGQ components of CDR database require cluster epoch increment. To get know your cluster epoch, connect to CDR postgresql database using **psql** and run: - -.. code-block:: console - - cdr=# SELECT (txid_current() >> 32) as epoch; - epoch - ------- - 0 - (1 row) - -See https://github.com/markokr/skytools/blob/master/doc/faq.txt#L50 for details - - -Shutdown CDR billing process and other pgq-processor consumers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: console - - # systemctl stop yeti-cdr-billing@cdr_billing - # systemctl stop yeti-delayed-job - - -Upgrade yeti-web package to 1.11.0 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# apt update - root@yeti:/# apt install yeti-web=1.11.0 - - -Postgresql 13 installation -~~~~~~~~~~~~~~~~~~~~~~~~~~ -You should install postgresql-13 packages, as described at :doc:`routing-database` and :doc:`cdr-database` and create appropriate databases. - - -Run new instances of Postgresql(version 13) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -New postgresql instances should run on different ports: - -.. code-block:: console - - root@yeti-postgresql-9:~# pg_lsclusters - Ver Cluster Port Status Owner Data directory Log file - 11 cdr 5435 online postgres /var/lib/postgresql/9.4/cdr /var/log/postgresql/postgresql-9.4-cdr.log <<< OLD CDR database - 11 routing 5434 online postgres /var/lib/postgresql/9.4/routing /var/log/postgresql/postgresql-9.4-routing.log <<< OLD routing database - 13 cdr 5437 online postgres /var/lib/postgresql/11/cdr /var/log/postgresql/postgresql-11-cdr.log <<< NEW CDR database - 13 routing 5436 online postgres /var/lib/postgresql/11/routing /var/log/postgresql/postgresql-11-routing.log <<< NEW routing database - - -Stop CDR writing to old Postgresql CDR instances -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To stop CDR writing change **listen_address** to '127.0.0.1'(if your CDR db locaated not on same node as SEMS) at postgresql.conf Configuration for old postgresql instances and restart postgresql - - -Change epoch of new postgresql CDR instance -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Shutdown new postgresql CDR cluster and change epoch: - -.. code-block:: console - - # su - postgres - # /usr/lib/postgresql/13/bin/pg_resetwal -e 1 /var/lib/postgresql/13/cdr - - -Where **1** is increased epoch - it should be greater then epoch of old intance - -See https://github.com/markokr/skytools/blob/master/doc/faq.txt#L50 for details - -Start new postgresql CDD instance. - - -Copy data from old databases to new instances -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You should dump your databases using pg_dump and then restore data to new instances: - -.. code-block:: console - - root@yeti-postgresql:~# pg_dump -h 127.0.0.1 -p 5434 -U yeti -O -x -F c -f yeti.dmp yeti - root@yeti-postgresql:~# pg_restore -h 127.0.0.1 -p 5436 -U yeti -d yeti -e yeti.dmp - root@yeti-postgresql:~# pg_dump -h 127.0.0.1 -p 5435 -U cdr -O -x -F c -f yeti.dmp yeti - root@yeti-postgresql:~# pg_restore -h 127.0.0.1 -p 5437 -U cdr -d yeti -e yeti.dmp - - -Shutdown old databases and move new instances to their ports -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Change **port** at postgresql.conf of each postgresql cluster to move new instances to old ports. Restart postgresql. - - -Apply migrations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# cd /opt/yeti-web - root@yeti:/# su -s /bin/bash yeti-web - root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - root@yeti:/opt/yeti-web# - - -Restart all components of yeti-web -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# systemctl restart yeti-web yeti-cdr-billing@cdr_billing yeti-delayed-job - - -Upgrade SEMS -~~~~~~~~~~~~ - -Upgrade your SEMS nodes to new version. Configuration files format was changed, See :ref:`sems.conf ` for details. - - - - diff --git a/en/installation/installation-1.11/cdr-database.rst b/en/installation/installation-1.13/cdr-database.rst similarity index 86% rename from en/installation/installation-1.11/cdr-database.rst rename to en/installation/installation-1.13/cdr-database.rst index 9facdb6..0881f7d 100644 --- a/en/installation/installation-1.11/cdr-database.rst +++ b/en/installation/installation-1.13/cdr-database.rst @@ -14,7 +14,7 @@ CDRs databases require similar set of packages as routing database .. code-block:: console - # apt update && apt install postgresql-13 postgresql-contrib-13 postgresql-13-prefix postgresql-13-pgq3 postgresql-13-pgq-ext postgresql-13-yeti postgresql-13-pllua pgqd + # apt update && apt install postgresql-16 postgresql-contrib-16 postgresql-16-prefix postgresql-16-pgq3 postgresql-16-pgq-ext postgresql-16-yeti postgresql-16-pllua pgqd .. warning:: It is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details @@ -58,11 +58,7 @@ Create configuration file /etc/pgqd.ini base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=somepassword initial_database = cdr database_list = cdr - script = /usr/bin/pgqd pidfile = /var/run/postgresql/pgqd.pid - ticker_max_count=1 - ticker_max_lag=3 - ticker_idle_period=360 Then you should start ticker: @@ -87,7 +83,7 @@ Check if databases were successfully created and are accessible: cdr=# \q root@cdr-server:/# -Don't forget to make changes in /etc/postgresql/13/main/pg_hba.conf +Don't forget to make changes in /etc/postgresql/16/main/pg_hba.conf and apply them if you plan to access this databases from other hosts and/or set up database replication diff --git a/en/installation/installation-1.11/index.rst b/en/installation/installation-1.13/index.rst similarity index 55% rename from en/installation/installation-1.11/index.rst rename to en/installation/installation-1.13/index.rst index 9dc6043..48d3693 100644 --- a/en/installation/installation-1.11/index.rst +++ b/en/installation/installation-1.13/index.rst @@ -1,9 +1,9 @@ -.. _install_1.11: +.. _install_1.13: -Version 1.11 +Version 1.13 ============ -Supported Operating system is Debian GNU/Linux 10 the only supported architecture is amd64 +Supported Operating system is Debian GNU/Linux 12 the only supported architecture is amd64 Components: @@ -16,8 +16,6 @@ Components: web redis sems - call-trace - cdr-export release-notes - upgrade-from-1.10 + upgrade-from-1.12 diff --git a/en/installation/installation-1.11/redis.rst b/en/installation/installation-1.13/redis.rst similarity index 74% rename from en/installation/installation-1.11/redis.rst rename to en/installation/installation-1.13/redis.rst index 8aa6cd6..47eac25 100644 --- a/en/installation/installation-1.11/redis.rst +++ b/en/installation/installation-1.13/redis.rst @@ -5,7 +5,7 @@ Redis installation ================== -Redis is used to synchronize data between traffic switch instances. It stores information about used resources (e.g gateways capacity limits) to provide correct limitation among all nodes for distributed installations. +Redis is used to synchronize data between switch instances. It stores information about used resources (e.g gateways capacity limits) to provide correct limitation among all nodes for distributed installations. Install packages ================ diff --git a/en/installation/installation-1.13/release-notes.rst b/en/installation/installation-1.13/release-notes.rst new file mode 100644 index 0000000..ca6063c --- /dev/null +++ b/en/installation/installation-1.13/release-notes.rst @@ -0,0 +1,18 @@ +.. :maxdepth: 2 + +============= +Release notes +============= + + * Debian 12 support + * Postgresql 16 support + * Migration to new debian repo + * Ruby upgraded to 3.3.5 + * Improved privacy processing + * Registrar scalability improvements + * Recurrent billing services support + * ptime transcoding support + * Per routing plan numberlist processing + * STIR/SHAKEN signing performance improvements + * Lot of internal changes + diff --git a/en/installation/installation-1.13/repositories.rst b/en/installation/installation-1.13/repositories.rst new file mode 100644 index 0000000..f96f38e --- /dev/null +++ b/en/installation/installation-1.13/repositories.rst @@ -0,0 +1,29 @@ +.. :maxdepth: 2 + + +========================== +Repositories configuration +========================== + +Most of servers may use same repositories set:: + + deb http://deb.debian.org/debian/ bookworm main contrib non-free non-free-firmware + deb http://deb.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware + deb http://deb.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware + deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware + + deb http://deb.yeti-switch.org/debian/1.13 bookworm main + deb http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main + +System repositories can be changed in **/etc/apt/sources.list**. Since we use our own package repository you have add our key to trusted. + +.. code-block:: console + + # wget http://deb.yeti-switch.org/yeti.gpg -O /etc/apt/trusted.gpg.d/yeti-key.asc + +PGDG repository key also should be added to trusted list + +.. code-block:: console + + # wget https://www.postgresql.org/media/keys/ACCC4CF8.asc -O /etc/apt/trusted.gpg.d/pgdg-key.asc + diff --git a/en/installation/installation-1.11/routing-database.rst b/en/installation/installation-1.13/routing-database.rst similarity index 83% rename from en/installation/installation-1.11/routing-database.rst rename to en/installation/installation-1.13/routing-database.rst index 7eca4a5..5e57c1b 100644 --- a/en/installation/installation-1.11/routing-database.rst +++ b/en/installation/installation-1.13/routing-database.rst @@ -11,7 +11,7 @@ Routing database installation Supported versions ------------------ -The only supported postgresql version is 13. +The only supported postgresql version is 16. Packages installation @@ -19,7 +19,7 @@ Packages installation .. code-block:: console - # apt update && apt install postgresql-13 postgresql-contrib-13 postgresql-13-prefix postgresql-13-pgq3 postgresql-13-pgq-ext postgresql-13-yeti postgresql-13-pllua pgqd + # apt update && apt install postgresql-16 postgresql-contrib-16 postgresql-16-prefix postgresql-16-pgq3 postgresql-16-pgq-ext postgresql-16-yeti postgresql-16-pllua pgqd Databases creation @@ -60,7 +60,7 @@ Check if databases were successfully created and are accessible:: root@evial:/# -Don't forget to make changes in /etc/postgresql/13/main/pg_hba.conf +Don't forget to make changes in /etc/postgresql/16/main/pg_hba.conf and apply them if you plan to access this databases from other hosts and/or set up database replication .. seealso:: :ref:`Database tuning ` diff --git a/en/installation/installation-1.11/sems.rst b/en/installation/installation-1.13/sems.rst similarity index 72% rename from en/installation/installation-1.11/sems.rst rename to en/installation/installation-1.13/sems.rst index 78f7f63..bbe13b4 100644 --- a/en/installation/installation-1.11/sems.rst +++ b/en/installation/installation-1.13/sems.rst @@ -15,7 +15,7 @@ Install packages Configuration files ------------------- -.. _sems_conf_1.11: +.. _sems_conf_1.13: /etc/sems/sems.conf ~~~~~~~~~~~~~~~~~~~ @@ -29,7 +29,6 @@ Replace , with correct values for your server : .. code-block:: general { - daemon = yes stderr = no syslog_loglevel = 2 syslog_facility = LOCAL0 @@ -42,24 +41,23 @@ Replace , with correct values for your server : allow_uac = true } - media_processor_threads = 4 rtp_receiver_threads = 4 session_processor_threads = 20 sip_udp_server_threads = 2 sip_tcp_server_threads = 2 - dead_rtp_time=30 + dead_rtp_time = 30 - default_bl_ttl=0 + default_bl_ttl = 0 symmetric_rtp_mode = packets symmetric_rtp_packets = 20 } signaling-interfaces { - interface internal { - default-media-interface = internal + interface primary { + default-media-interface = primary ip4 { sip-udp { address = @@ -79,12 +77,12 @@ Replace , with correct values for your server : } media-interfaces { - interface internal { + interface primary { ip4 { rtp { address = low-port = 16384 - high-port = 32768 + high-port = 32769 dscp = 46 use-raw-sockets = off } @@ -94,6 +92,7 @@ Replace , with correct values for your server : modules { module "di_log" {} + module "mp3" {} module "opus" {} module "wav" {} @@ -102,17 +101,17 @@ Replace , with correct values for your server : module "adpcm" {} module "l16" {} module "g722" {} - module "g729bcg" {} module "registrar_client" {} - module "sctp_bus" {} + module "postgresql" {} + module "session_timer" {} module "jsonrpc" { listen{ address = 127.0.0.1 port = 7080 } - server_threads=1 + server_threads = 1 } module "http_client" {} @@ -122,23 +121,44 @@ Replace , with correct values for your server : module "radius_client" {} + module "redis" { + max_batch_size = 10 + batch_timeout = 100 + max_queue_size = 1000 + } + + module "registrar" { + redis { + use_functions = no + write { + hosts = { 127.0.0.1:6379 } + } + read { + hosts = { 127.0.0.1:6379 } + } + } + } + module "yeti" { - pop_id = 4 + pop_id = lega_cdr_headers { header(p-charge-info, string) header(diversion, array) } auth { - realm = 127.0.0.1 + realm = yeti-switch } msg_logger_dir = /var/spool/sems/dump - log_dir = /var/spool/sems/logdump audio_recorder_dir = /var/spool/sems/records - audio_recorder_compress = true + audio_recorder_compress = false + + db_refresh_interval = 5 + ip_auth_reject_if_no_matched = true + routing { - schema = switch19 + schema = switch21 function = route_release init = init master_pool { @@ -150,7 +170,7 @@ Replace , with correct values for your server : size = 4 check_interval = 10 max_exceptions = 0 - statement_timeout=3000 + statement_timeout = 3000 } failover_to_slave = false slave_pool { @@ -162,18 +182,14 @@ Replace , with correct values for your server : size = 4 check_interval = 10 max_exceptions = 0 - statement_timeout=3000 - } - cache { - enabled = false - check_interval = 60 - buckets = 100000 + statement_timeout = 3000 } } cdr { dir = /var/spool/sems/cdrs completed_dir = /var/spool/sems/cdrs/completed pool_size = 2 + auth_pool_size = 2 schema = switch function = writecdr master { @@ -196,32 +212,24 @@ Replace , with correct values for your server : serialize_dynamic_fields = true batch_size = 1 batch_timeout = 5000 + auth_batch_size = 1 + auth_batch_timeout = 20000 } resources { reject_on_error = false + reduce_operations = true write { - host = 127.0.0.1 - port = 6379 - size = 2 + hosts = { 127.0.0.1:6379 } timeout = 500 } read { - host = 127.0.0.1 - port = 6379 - size = 2 + hosts = { 127.0.0.1:6379 } timeout = 1000 } } registrations { check_interval = 5000 } - registrar { - enabled = true - redis { - host = 127.0.0.1 - port = 6379 - } - } rpc { calls_show_limit = 10000 } @@ -234,7 +242,7 @@ Replace , with correct values for your server : } -.. warning:: RPC allows shutdown SEMS node or make it non-operational. RPC interface should be secured by firewall to prevent connections from not trusted hosts. In YETI systems only two components should have ability to connect to RPC - WEB interface and yeti-cli console +.. warning:: JRPC interface allows shutdown SEMS node or make it non-operational. JRPC interface should be secured by firewall to prevent connections from not trusted hosts. In YETI systems only two components should have ability to connect to RPC - WEB interface and yeti-cli console Launch traffic switch --------------------- @@ -243,7 +251,7 @@ Launch configured traffic switch instance: .. code-block:: console - # service sems start + # systemctl sems start In case of errors it's useful to use **sems -E -D3** command which will launch daemon in foreground with debug logging level @@ -255,6 +263,17 @@ Check if **sems** process exists and signaling/media/rpc sockets are opened: .. code-block:: console + # systemctl status sems + ● sems.service - SEMS for YETI project + Loaded: loaded (/lib/systemd/system/sems.service; enabled; preset: enabled) + Active: active (running) since Thu 2024-12-05 20:21:52 UTC; 5 days ago + Docs: https://yeti-switch.org/docs/ + Main PID: 68166 (sems) + Tasks: 84 (limit: 154132) + Memory: 3.3G + CPU: 2d 18h 15min 51.113s + CGroup: /system.slice/sems.service + └─68166 /usr/bin/sems -f /etc/sems/sems.conf # pgrep sems 29749 # netstat -lpn | grep sems @@ -262,4 +281,11 @@ Check if **sems** process exists and signaling/media/rpc sockets are opened: udp 0 0 127.0.0.1:5061 0.0.0.0:* 29749/sems raw 2688 0 0.0.0.0:17 0.0.0.0:* 7 29749/sems -Check logfile /var/log/sems/sems-main.log for possible errors +Check logs using for possible errors: + +.. code-block:: console + + # journalctls -u sems + + + diff --git a/en/installation/installation-1.13/upgrade-from-1.12.rst b/en/installation/installation-1.13/upgrade-from-1.12.rst new file mode 100644 index 0000000..afb7f66 --- /dev/null +++ b/en/installation/installation-1.13/upgrade-from-1.12.rst @@ -0,0 +1,61 @@ +.. :maxdepth: 2 + +==================== +Upgrade instructions +==================== + +This instructions describe how to upgrade Yeti system from version 1.12 to version 1.13 + +Reconfigure repositories +------------------------ + +Before start upgrade you have to reconfigure Debian repositories according to documentation + + +Upgrade OS +---------- + +Upgrade Debian GNU/Linux to version 12. + + +Upgrade Postgresql instances +---------------------------- + +Upgrade routing and CDR databases instances from Postgresql 13 to Postgresql 16. + + +Upgrade yeti-web package +------------------------ + +Upgrade and reconfigure yeti-web: + +.. code-block:: console + + root@yeti:/# apt update + root@yeti:/# apt install yeti-web + + +Apply database migrations +------------------------- + +.. code-block:: console + + root@yeti:/# cd /opt/yeti-web + root@yeti:/# su -s /bin/bash yeti-web + root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate + root@yeti:/opt/yeti-web# + + +Restart all components of yeti-web +---------------------------------- + +.. code-block:: console + + root@yeti:/# systemctl restart yeti-web yeti-cdr-billing@cdr_billing yeti-cdr-billing@cdr_stats yeti-delayed-job yeti-scheduler + +Upgrade SEMS +------------ + +Upgrade your SEMS nodes to new version. Configuration files format was changed, See :ref:`sems.conf ` for details. + + diff --git a/en/installation/installation-1.11/web.rst b/en/installation/installation-1.13/web.rst similarity index 52% rename from en/installation/installation-1.11/web.rst rename to en/installation/installation-1.13/web.rst index 9b33757..ee8e6d4 100644 --- a/en/installation/installation-1.11/web.rst +++ b/en/installation/installation-1.13/web.rst @@ -8,7 +8,7 @@ WEB interface installation Server requirements: - amd64 architecture -- Debian 10 Buster distibution +- Debian 12 Bookworm distibution - at least 4GB of RAM Packages installation @@ -17,40 +17,56 @@ Packages installation .. code-block:: console # apt update && apt install yeti-web nginx - -Databases connection configuration ----------------------------------- + + +Yeti-web configuration +---------------------- To configure databases connection parameters create /opt/yeti-web/config/database.yml file with the following content: .. code-block:: yaml - production: - adapter: postgresql - encoding: unicode - database: yeti - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import' - port: 5432 - min_messages: notice + production: + primary: + adapter: postgresql + encoding: unicode + database: yeti + username: yeti + password: somepassword + host: 127.0.0.1 + port: 5432 + schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import' + min_messages: notice + pool: 5 - secondbase: - production: + cdr: adapter: postgresql encoding: unicode database: cdr - pool: 5 username: yeti password: somepassword host: 127.0.0.1 - schema_search_path: 'cdr, reports, billing' port: 5432 + schema_search_path: 'cdr, reports, billing' min_messages: notice + pool: 5 + migrations_paths: db/cdr_migrate + +.. warning:: You should specify correct addresses and credentials that were used in previous section + + +Configure security keys seed by creating /opt/yeti-web/config/secrets.yml with the following content: + +.. code-block:: yaml + + production: + secret_key_base: + +.. warning:: Replace **** with randomly generated value. You can use **pwgen -s 128** to generate it. + + +Copy configuration file example **/opt/yeti-web/config/yeti_web.yml.distr** to **/opt/yeti-web/config/yeti_web.yml** -Warning: you should specify correct addresses and credentials that were used in previous section Databases data initialization ----------------------------- @@ -61,8 +77,7 @@ To initialize empty databases during initial installation: # cd /opt/yeti-web # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:structure:load db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:structure:load db:second_base:migrate + $ RAILS_ENV=production ./bin/bundle.sh exec rake db:schema:load db:migrate $ RAILS_ENV=production ./bin/bundle.sh exec rake db:seed @@ -73,8 +88,15 @@ To upgrade databases to the latest version: # cd /opt/yeti-web # su -s /bin/bash yeti-web $ RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - + +To load countries and networks information to database: + +.. code-block:: console + + # cd /opt/yeti-web + # su -s /bin/bash yeti-web + $ RAILS_ENV=production ./bin/bundle.sh exec rake custom_seeds[network_prefixes] + Nginx configuration ------------------- @@ -100,6 +122,7 @@ After successful configuration of databases you finally can run software using f # service yeti-web start # service yeti-cdr-billing@cdr_billing start + # service yeti-cdr-billing@cdr_stats # service yeti-delayed-job start # service yeti-scheduler start @@ -123,12 +146,12 @@ check if nginx listens on correct TCP/IP addresses and ports: tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 23627/nginx tcp 0 0 127.0.0.1:6666 0.0.0.0:* LISTEN 23627/nginx -Log files to check for possible warnings/errors: +Log files to check for possible warnings/errors using systemctl and journalctl: -- /var/log/yeti/yeti-web.log -- /var/log/yeti/yeti-cdr-billing.log -- /opt/yeti-web/log/puma.stdout.log -- /opt/yeti-web/log/puma.stderr.log +.. code-block:: console + + # systemctl status yeti-web + # jounrnalctl -u yeti-web Try to open management interface in your favorite browser and login with default credentials: @@ -136,66 +159,3 @@ Try to open management interface in your favorite browser and login with default :password: 111111 -Invoice PDF generation ----------------------- - -If you need to generate invoices in PDF format, you have to install additional LibreOffice packages. - -.. code-block:: console - - # apt install unoconv libreoffice-core - -Service **yeti-libreoffice-headless** is disabled by default, you have to enable it. - -.. code-block:: console - - # systemctl enable yeti-libreoffice-headless - -Run it - -.. code-block:: console - - # systemctl start yeti-libreoffice-headless - - -LDAP Authentication -------------------- -Yeti's web-interface may use LDAP in order to authnticate users. - -Copy configuration from example file - -.. code-block:: console - - # cp /opt/yeti-web/config/ldap.yml.dist /opt/yeti-web/config/ldap.yml - -and edit it - -.. code-block:: console - - production: - host: yeti-host.com - port: 389 - ssl: false - attribute: uid - base: ou=employees,dc=yeti,dc=com - group_base: ou=groups,dc=yeti,dc=com - required_groups: - - ["member", "cn=yeti,ou=groups,dc=yeti,dc=com"] - -* **host** - address of LDAP server -* **port** - port of LDAP server -* **ssl** - enable/disable SSL -* **attribute** - name of attribute which contains user login -* **base** - base DN where YETI will try find users -* **group_base** - base DN where YETI will try find groups -* **required_groups** - array of groups where user must present -* **member** - attribute where group stored -* **cn=yeti,ou=groups,dc=yeti,dc=com** - group - - -After editing file, restart YETI web interface - -.. code-block:: console - - # systemctl restart yeti-web - diff --git a/en/installation/installation-1.7/call-trace.rst b/en/installation/installation-1.7/call-trace.rst deleted file mode 100644 index ea3c91d..0000000 --- a/en/installation/installation-1.7/call-trace.rst +++ /dev/null @@ -1,104 +0,0 @@ -.. :maxdepth: 2 - - -================================ -Call trace storage configuration -================================ - - -SEMS and Web are running on same server ---------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content:: - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/spool/sems; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -SEMS and Web located on different servers ------------------------------------------ - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create directory **/var/www/dump** with owner **www-data** to store PCAP files. - -Edit **/etc/nginx/sites-enabled/yeti-web** and add such server block:: - - server { - listen :8081; - server_name _; - access_log /var/log/nginx/pcap-upload.access.log; - error_log /var/log/nginx/pcap-upload.error.log; - - root /var/www/dump; - - location /upload { - allow /32; - deny all; - - alias /var/www/dump; - dav_methods PUT; - dav_access group:rw all:r; - create_full_put_path on; - client_max_body_size 10000M; - } - } - - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content:: - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/www; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -Configure SEMS to upload traces to WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add directive **pcap_upload_queue=pcap** to **/etc/sems/sems.conf** -Add module **http_client** to **load_plugins** at **/etc/sems/sems.conf** - -Create configuration file **/etc/sems/etc/http_client.conf** with following content:: - - resend_interval=5000 - resend_queue_max=10000 - - destinations=pcap - - pcap_mode=put - pcap_url=http://:8081/upload - pcap_succ_action=remove - pcap_fail_action=requeue - - - -Restart SEMS: - -.. code-block:: console - - # systemctl restart sems - - - - - diff --git a/en/installation/installation-1.7/cdr-database.rst b/en/installation/installation-1.7/cdr-database.rst deleted file mode 100644 index 4c556c5..0000000 --- a/en/installation/installation-1.7/cdr-database.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. :maxdepth: 2 - - -========================== -CDR databases installation -========================== - -.. note:: System requires two databases: one for routing and one for CDRs. Setting up different PostgreSQL instances is highly recommended to make replication possible. - -Packages installation -===================== - -CDRs databases require similar set of packages as routing database - -.. code-block:: console - - # apt update && apt install postgresql-9.4 postgresql-contrib-9.4 postgresql-9.4-prefix postgresql-9.4-pgq3 postgresql-9.4-pgq-ext postgresql-9.4-yeti pgqd - -or for Debian 9 and Postgresql 10: - -.. code-block:: console - - # apt update && apt install postgresql-10 postgresql-10-prefix postgresql-10-pgq3 postgresql-10-pgq-ext postgresql-10-yeti pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - - -Databases creation -================== - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user cdr encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database cdr owner cdr; - CREATE DATABASE - postgres=# \q - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - - -PGQd ticker -=========== - -After initialization of CDR database you should run pgq ticker daemon(**pgqd**) on server with CDR database. - -Create configuration file /etc/pgqd.ini - -.. code-block:: ini - - [pgqd] - base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=somepassword - initial_database = cdr - database_list = cdr - script = /usr/bin/pgqd - pidfile = /var/run/postgresql/pgqd.pid - ticker_max_count=1 - ticker_max_lag=3 - ticker_idle_period=360 - - -Then you should start ticker: - -.. code-block:: console - - # service pgqd start - - -Checks -====== - -Check if databases were successfully created and are accessible: - -.. code-block:: psql - - root@cdr-server:/# psql -h 127.0.0.1 -U cdr -d cdr - Password for user cdr: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - cdr=# \q - root@cdr-server:/# - -Don't forget to make changes in /etc/postgresql/9.4/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.7/cli-utility.rst b/en/installation/installation-1.7/cli-utility.rst deleted file mode 100644 index d4a3f9d..0000000 --- a/en/installation/installation-1.7/cli-utility.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. :maxdepth: 2 - - -========================== -CLI utility installation -========================== - -Server requirements: - -- OS Debian 8 or Debian 9 with amd64 architecture -- Python 2.7 - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-cli - -Configuration ----------------------------------- - -To configure yeti-cli parameters edit /etc/yeti/yeti-cli.yml file - -Create yeti-cli.yml file with the following content: - -.. code-block:: yaml - - nodes_url: 'http://localhost:6666/api/rest/system/nodes.json' - authentificator_url: 'http://localhost:6666/api/rest/system/admin_users.json?q[ssh_key_present]=1' - timeout: 5 - default_node: 8 - prompt_system_name: 'YETI' - - -* **nodes_url** - url for getting nodes list on initial startup -* **authentificator_url** - url for getting public keys via yeti-cli-authentificator -* **timeout** - result waiting timeout -* **default_node** - default node, to which we connect on start -* **prompt_system_name** - Promt string - -You can override default config location via enviroment variable YETI_CMD_CFG_PATH - -Shell mode -------------- - -Also you can configure yeti-cli to work as shell. -You openssh-server must support AuthorizedKeysCommand. -Add next lines to sshd_config - -.. code-block::yaml - - AuthorizedKeysCommand /usr/sbin/yeti-cli-authentificator - AuthorizedKeysCommandUser console - PermitUserEnvironment yes - - -Reload ssh daemon - -.. code-block:: console - - # systemctl sshd reload diff --git a/en/installation/installation-1.7/database-tuning.rst b/en/installation/installation-1.7/database-tuning.rst deleted file mode 100644 index f39724e..0000000 --- a/en/installation/installation-1.7/database-tuning.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. :maxdepth: 2 - -============================ -Databases performance tuning -============================ - -By default Postgresql RDBMS configured to consume minimal system resources. This approach allows Postgresql to start on any server after installation. YETI as well as any other system uses Postgresql requires changing default configuration in order to archive best performance. - -We recommends to change next configuration variables at /etc/postgresql/9.4/yeti/postgresql.conf - -.. code-block:: ini - - shared_buffers = 10GB - work_mem = 8MB - fsync = on - checkpoint_segments = 30 - checkpoint_timeout = 50min - - -Set **shared_buffers** variable to 1/3 of total RAM installed to server if you share this server with some another application. For example we recommends install yeti-web on same server as routing database. -If your server is dedicated for postgresql set **shared_buffers** to 2/3 of your RAM. - -When configuration changed you should restart your postgresql instance using `service postgresql restart` - -.. seealso:: Read Postgresql manual https://www.postgresql.org/docs/9.4/ to understand postgresql architecture and features - - - - - - - - diff --git a/en/installation/installation-1.7/index.rst b/en/installation/installation-1.7/index.rst deleted file mode 100644 index 94ce1fa..0000000 --- a/en/installation/installation-1.7/index.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _install: - -Version 1.7 -=========== - -Supported Operating systems is Debian GNU/Linux 8 and 9, the only supported architecture is amd64 - -Components: - -.. toctree:: - :maxdepth: 2 - - repositories - routing-database - cdr-database - web - redis - management - sems - call-trace - cli-utility - database-tuning - diff --git a/en/installation/installation-1.7/management.rst b/en/installation/installation-1.7/management.rst deleted file mode 100644 index 842da54..0000000 --- a/en/installation/installation-1.7/management.rst +++ /dev/null @@ -1,194 +0,0 @@ -.. :maxdepth: 2 - - -============================== -Management server installation -============================== - -Since version 1.6.3-175 we started to use central configuration server -to store yeti module configuration for all nodes in cluster. - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-management - -Configuration files -------------------- - -/etc/yeti/management.cfg -~~~~~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for management daemon. - -Set desired logging level and address to listen. - -You can set multiple addresses separated by comma to listen on multiple interfaces. - -Possible log_level values are: (1 - error, 2 - info, 3 - debug) - -.. code-block:: c - - daemon { - listen = { - "tcp://0.0.0.0:4444" - } - - sctp { - address = "127.0.0.1" - port = 4444 - } - - http { - address = "127.0.0.1" - port = 3000 - } - log_level = 2 - } - -/etc/yeti/system.cfg -~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for all nodes. -Each top-level section defines configuration for node of certain type -(signaling is for traffic switch nodes). -All top-level sections contains mandatory section globals -which must have all possible values common for all nodes. -Then there is named sections for each node_id which may contain -values overriding ones set in global section. - -Note: even if your node does not have -any specific values you have to define empty section -for this node anyway, otherwise management node -will not provide configuration for node with this id. - -Example of minimal configuration file for node with id 8 - -.. code-block:: c - - signalling { - globals { - yeti { - pop_id = 4 - msg_logger_dir = /var/spool/sems/dump - log_dir = /var/spool/sems/logdump - routing { - schema = switch16 - function = route_release - init = init - master_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - failover_to_slave = false - slave_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - cache { - enabled = false - check_interval = 60 - buckets = 100000 - } - } - cdr { - dir = /var/spool/sems/cdrs - completed_dir = /var/spool/sems/cdrs/completed - pool_size = 2 - schema = switch - function = writecdr - master { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_to_slave = false - slave { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_requeue = true - failover_to_file = false - serialize_dynamic_fields = true - batch_size = 1 - batch_timeout = 5000 - } - resources { - reject_on_error = false - write { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 500 - } - read { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 1000 - } - } - registrations { - check_interval = 5000 - } - rpc { - calls_show_limit = 10000 - } - } - } - node 8 { } - } - -.. warning:: You should define all Nodes that has been created at web interface by their IDs. See :ref:`System->Nodes ` menu. SEMS node will refuse to start if corresponding node is not defined at system.cfg - - -Management server launch ------------------------- - -Launch configured management server instance: - -.. code-block:: console - - # service yeti-management start - -Checks ------- - -Check file /var/log/yeti/yeti-management.log for daemon logs: - -.. code-block:: console - - # tail -2 /var/log/yeti/yeti-management.log - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/yeti_mgmt_server.cpp:148: starting version 1.0.5 - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/mgmt_server.cpp:123: listen on tcp://0.0.0.0:4444 - -Check listening port: - -.. code-block:: console - - # netstat -lpn | grep yeti_management - 4444 tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN 25376/yeti_manageme - diff --git a/en/installation/installation-1.7/redis.rst b/en/installation/installation-1.7/redis.rst deleted file mode 100644 index 2c8b4a7..0000000 --- a/en/installation/installation-1.7/redis.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. :maxdepth: 2 - - -================== -Redis installation -================== - -Redis is used to synchronize data between traffic switch instances. -It stores information about used resources (e.g gateways capacity limits) -to provide correct limitation among all nodes for distributed installations. - -Install packages -================ - -.. code-block:: console - - # apt update && apt install redis-server - -Checks -====== - -Try to enter redis console from traffic switch host -(redis installed at the same host -with traffic switch in this example): - -.. code-block:: console - - # redis-cli - 127.0.0.1:6379> ping - PONG - 127.0.0.1:6379> quit diff --git a/en/installation/installation-1.7/repositories.rst b/en/installation/installation-1.7/repositories.rst deleted file mode 100644 index d2c69d5..0000000 --- a/en/installation/installation-1.7/repositories.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. :maxdepth: 2 - - -========================== -Repositories configuration -========================== - -Most of servers you can use same repositories set, for Debian 8:: - - deb http://ftp.us.debian.org/debian/ jessie main contrib non-free - deb http://ftp.us.debian.org/debian/ jessie-updates main - deb http://security.debian.org/ jessie/updates main - deb http://pkg.yeti-switch.org/debian/jessie 1.7 main - -And for Debian 9:: - - deb http://ftp.us.debian.org/debian/ stretch main contrib non-free - deb http://ftp.us.debian.org/debian/ stretch-updates main - deb http://security.debian.org/ stretch/updates main - deb http://pkg.yeti-switch.org/debian/stretch 1.7 main - - -System repositories can be changed by editing of file: /etc/apt/sources.list. Since we use our own package repository you have add our key to trusted. -There is two ways to do it: - -.. code-block:: console - - # apt-key adv --keyserver keys.gnupg.net --recv-key 9CEBFFC569A832B6 - -or - -.. code-block:: console - - # wget http://pkg.yeti-switch.org/key.gpg -O - | apt-key add - - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. - -On your datadabase hosts(routing and CDR) you should add additional PGDG repository:: - - deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main - -Or for Debian 9:: - - deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main - -You can add PGDG repository key to trusted using command: - -.. code-block:: console - - # wget https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - diff --git a/en/installation/installation-1.7/routing-database.rst b/en/installation/installation-1.7/routing-database.rst deleted file mode 100644 index e6797a1..0000000 --- a/en/installation/installation-1.7/routing-database.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. :maxdepth: 2 - - -============================= -Routing database installation -============================= - -.. note:: We recommend placing routing database on the same host with management WEB interface for best performance and web interface responsiveness. - - -Supported versions ------------------- - -For Debian 8 you should install Postgresql version 9.4. For Debian 9 we supports Postgresql 10 as well. - - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install postgresql-9.4 postgresql-contrib-9.4 postgresql-9.4-prefix postgresql-9.4-pgq3 postgresql-9.4-pgq-ext postgresql-9.4-yeti pgqd - -or for Debian 9 and Postgresql 10: - -.. code-block:: console - - # apt update && apt install postgresql-10 postgresql-10-prefix postgresql-10-pgq3 postgresql-10-pgq-ext postgresql-10-yeti pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - -Databases creation ------------------- - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user yeti encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database yeti owner yeti; - CREATE DATABASE - postgres=# \q - - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - -Checks ------- - -Check if databases were successfully created and are accessible:: - - root@evial:/# psql -h 127.0.0.1 -U yeti -d yeti - Password for user yeti: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - yeti=# \q - root@evial:/# - - -Don't forget to make changes in /etc/postgresql/9.4/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.7/sems.rst b/en/installation/installation-1.7/sems.rst deleted file mode 100644 index 9ef64a8..0000000 --- a/en/installation/installation-1.7/sems.rst +++ /dev/null @@ -1,129 +0,0 @@ -.. :maxdepth: 2 - - -====================== -SEMS node installation -====================== - -Install packages ----------------- - -.. code-block:: console - - # apt update && apt install sems sems-modules-yeti - -Configuration files -------------------- - -.. _sems_conf: - -/etc/sems/sems.conf -~~~~~~~~~~~~~~~~~~~ - -Add new node to the routing database using web interface -[ System -> Nodes -> New Node ]. -Use id of newly created node as value for **node_id** parameter - -node_id - unique signaling node id. - -.. warning:: You should create Node at web interface and use ID from web interface at **node_id** variable. See :ref:`System->Nodes ` menu. - -Replace , with correct values for your server : - -.. code-block:: ini - - node_id = - - interfaces=intern - sip_ip_intern= - sip_port_intern=5061 - media_ip_intern= - rtp_low_port_intern=20000 - rtp_high_port_intern=50000 - plugin_path=/usr/lib/sems/plug-in/ - load_plugins=wav;ilbc;speex;gsm;adpcm;l16;g722;sctp_bus;yeti;session_timer;uac_auth;di_log;registrar_client;jsonrpc - application = yeti - plugin_config_path=/etc/sems/etc/ - fork=yes - stderr=no - syslog_loglevel=2 - max_shutdown_time = 10 - - session_processor_threads=20 - media_processor_threads=2 - session_limit="4000;509;Node overloaded" - shutdown_mode_reply="508 Node in shutdown mode" - options_session_limit="900;503;Warning, server soon overloaded" - # cps_limit="100;503;Server overload" - use_raw_sockets=yes - sip_timer_B = 8000 - default_bl_ttl=0 - registrations_enabled=no - -.. _yeti_conf: - -/etc/sems/etc/yeti.conf -~~~~~~~~~~~~~~~~~~~~~~~ - - - -cfg_timeout - timeout of waiting response from management node -cfg_host - IP address of management node -cfg_port - SCTP port of management node - -.. code-block:: ini - - cfg_timeout = 1000 - cfg_host = 127.0.0.1 - cfg_port = 4444 - core_options_handling=yes - - -.. _jsonrpc: - -/etc/sems/etc/jsonrpc.conf -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Such file used for RPC configuration - -.. code-block:: ini - - jsonrpc_listen=127.0.0.1 - jsonrpc_port=7080 - server_threads=1 - -RPC socket should be available from WEB interface server. You should place your real IP address if you run SEMS node on dedicated server. - -.. warning:: RPC allows shutdown SEMS node or make it non-operational. RPC interface should be secured by firewall to prevent connections from not trusted hosts. In YETI systems only two components should have ability to connect to RPC - WEB interface and yeti-cli console - -Launch traffic switch ---------------------- - -Launch configured traffic switch instance: - -.. code-block:: console - - # service sems start - -In case of errors it's useful to use **sems -E -D3** command -which will launch daemon in foreground with debug logging level - -Checks ------- - -Check if **sems** process exists and signaling/media/rpc sockets are opened: - -.. code-block:: console - - # pgrep sems - 29749 - # netstat -lpn | grep sems - tcp 0 0 127.0.0.1:8090 0.0.0.0:* LISTEN 29749/sems - udp 0 0 127.0.0.1:5061 0.0.0.0:* 29749/sems - raw 2688 0 0.0.0.0:17 0.0.0.0:* 7 29749/sems - -Check logfile /var/log/sems/sems-main.log for possible errors diff --git a/en/installation/installation-1.7/web.rst b/en/installation/installation-1.7/web.rst deleted file mode 100644 index 85735f6..0000000 --- a/en/installation/installation-1.7/web.rst +++ /dev/null @@ -1,205 +0,0 @@ -.. :maxdepth: 2 - - -========================== -WEB interface installation -========================== - -Server requirements: - -- amd64 architecture -- Debian 8 Jessie or Debian 9 Stretch distibution -- at least 4GB of RAM - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-web nginx - -Databases connection configuration ----------------------------------- - -To configure databases connection parameters edit /home/yeti-web/config/database.yml file - -Create database.yml file with the following content: - -.. code-block:: yaml - - production: - adapter: postgresql - encoding: unicode - database: yeti - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import' - port: 5432 - min_messages: notice - - secondbase: - production: - adapter: postgresql - encoding: unicode - database: cdr - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'cdr, reports, billing' - port: 5432 - min_messages: notice - -Warning: you should specify correct addresses and credentials that were used in previous section - -Databases data initialization ------------------------------ - -To simplify work with databases use utility yeti-db -To initialize empty databases: - -.. code-block:: console - - # cd /home/yeti-web - # RAILS_ENV=production ./bin/bundle.sh exec rake db:structure:load db:migrate - # RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:structure:load db:second_base:migrate - # RAILS_ENV=production ./bin/bundle.sh exec rake db:seed - - -To upgrade databases to the latest version: - -.. code-block:: console - - # cd /home/yeti-web - # RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - # RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - - -Nginx configuration -------------------- - -For basic configuration remove default config and copy yeti-web.dist.nginx: - -.. code-block:: console - - # rm /etc/nginx/sites-enabled/default - # cp /home/yeti-web/config/yeti-web.dist.nginx /etc/nginx/sites-enabled/yeti - # nginx -t - nginx: the configuration file /etc/nginx/nginx.conf syntax is ok - nginx: configuration file /etc/nginx/nginx.conf test is successful - # service nginx restart - - -Launch ------- - -After successful configuration of databases you finally can run software using following commands: - -.. code-block:: console - - # service yeti-web start - # service yeti-cdr-billing@cdr_billing start - # service yeti-delayed-job start - -This will run web-interface and CDR processing workers - -Checks ------- - -check if unicorn listens on local socket: - -.. code-block:: console - - # netstat -lpn | grep unicorn - unix 2 [ ACC ] STREAM LISTENING 2535145 24728/unicorn.rb -E /tmp/yeti-unicorn.sock - -check if nginx listens on correct TCP/IP addresses and ports: - -.. code-block:: console - - # netstat -lpn | grep nginx - tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 23627/nginx - tcp 0 0 127.0.0.1:6666 0.0.0.0:* LISTEN 23627/nginx - -Log files to check for possible warnings/errors: - -- /var/log/yeti-admin.log -- /var/log/yeti-cdr-billing.log -- /home/yeti-web/log/unicorn.stdout.log -- /home/yeti-web/log/unicorn.stderr.log - -Try to open management interface in your favorite browser and login with default credentials: - -:user: admin -:password: 111111 - - -Invoice PDF generation ----------------------- - -If you need to generate invoices in PDF format, you have to install additional packages. -It is accomplished via LibreOffice software, so our package just a wrapper for a LibreOffice installation. - -.. warning:: - This operation will install a lot of packages in your system! - -.. code-block:: console - - # apt install yeti-libreoffice-headless - -Make sure, that service is enabled for autostart - -.. code-block:: console - - # systemctl enable yeti-libreoffice-headless - -Run it - -.. code-block:: console - - # systemctl start yeti-libreoffice-headless - - -LDAP Authentication -------------------- -Yeti's web-interface may use LDAP in order to authnticate users. - -Copy configuration from example file - -.. code-block:: console - - # cp /home/yeti-web/config/ldap.yml.dist /home/yeti-web/config/ldap.yml - -and edit it - -.. code-block:: console - - production: - host: yeti-host.com - port: 389 - ssl: false - attribute: uid - base: ou=employees,dc=yeti,dc=com - group_base: ou=groups,dc=yeti,dc=com - required_groups: - - ["member", "cn=yeti,ou=groups,dc=yeti,dc=com"] - -* **host** - address of LDAP server -* **port** - port of LDAP server -* **ssl** - enable/disable SSL -* **attribute** - name of attribute which contains user login -* **base** - base DN where YETI will try find users -* **group_base** - base DN where YETI will try find groups -* **required_groups** - array of groups where user must present -* **member** - attribute where group stored -* **cn=yeti,ou=groups,dc=yeti,dc=com** - group - - -After editing file, restart YETI web interface - -.. code-block:: console - - # systemctl restart yeti-web - diff --git a/en/installation/installation-1.8/call-trace.rst b/en/installation/installation-1.8/call-trace.rst deleted file mode 100644 index d07e0e8..0000000 --- a/en/installation/installation-1.8/call-trace.rst +++ /dev/null @@ -1,120 +0,0 @@ -.. :maxdepth: 2 - - -================================ -Call trace storage configuration -================================ - - -SEMS and Web are running on same server ---------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content:: - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/spool/sems; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -SEMS and Web located on different servers ------------------------------------------ - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create directory **/var/www/dump** with owner **www-data** to store PCAP files. - -Edit **/etc/nginx/sites-enabled/yeti-web** and add such server block:: - - server { - listen :8081; - server_name _; - access_log /var/log/nginx/pcap-upload.access.log; - error_log /var/log/nginx/pcap-upload.error.log; - - root /var/www/dump; - - location /upload { - allow /32; - deny all; - - alias /var/www/dump; - dav_methods PUT; - dav_access group:rw all:r; - create_full_put_path on; - client_max_body_size 10000M; - } - } - - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content:: - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/www; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -Configure SEMS to upload traces to WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add **http_client** module configuration to **modules** section of **/etc/sems/sems.conf**:: - - modules { - path = /usr/lib/sems/plug-in - config_path=/etc/sems/etc/ - ... - module "http_client" { - resend_interval=5000 - resend_queue_max=10000 - - destination "pcap" { - mode=put - urls={ http://:8081/upload } - on_success { - action = remove - } - on_failure { - action = requeue - } - } - } - ... - } - -Add **pcap_upload_queue=pcap** directive to section **general** of **/etc/sems/sems.conf**:: - - general { - ... - pcap_upload_queue=pcap - ... - } - - -Restart SEMS: - -.. code-block:: console - - # systemctl restart sems - - - - - diff --git a/en/installation/installation-1.8/cdr-database.rst b/en/installation/installation-1.8/cdr-database.rst deleted file mode 100644 index 77b3907..0000000 --- a/en/installation/installation-1.8/cdr-database.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. :maxdepth: 2 - - -========================== -CDR databases installation -========================== - -.. note:: System requires two databases: one for routing and one for CDRs. Setting up different PostgreSQL instances is highly recommended to make replication possible. - -Packages installation -===================== - -CDRs databases require similar set of packages as routing database - -.. code-block:: console - - # apt update && apt install postgresql-11 postgresql-contrib-11 postgresql-11-prefix postgresql-11-pgq3 postgresql-11-pgq-ext postgresql-11-yeti pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - - -Databases creation -================== - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user cdr encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database cdr owner cdr; - CREATE DATABASE - postgres=# \q - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - - -PGQd ticker -=========== - -After initialization of CDR database you should run pgq ticker daemon(**pgqd**) on server with CDR database. - -Create configuration file /etc/pgqd.ini - -.. code-block:: ini - - [pgqd] - base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=somepassword - initial_database = cdr - database_list = cdr - script = /usr/bin/pgqd - pidfile = /var/run/postgresql/pgqd.pid - ticker_max_count=1 - ticker_max_lag=3 - ticker_idle_period=360 - - -Then you should start ticker: - -.. code-block:: console - - # service pgqd start - - -Checks -====== - -Check if databases were successfully created and are accessible: - -.. code-block:: psql - - root@cdr-server:/# psql -h 127.0.0.1 -U cdr -d cdr - Password for user cdr: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - cdr=# \q - root@cdr-server:/# - -Don't forget to make changes in /etc/postgresql/11/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.8/cli-utility.rst b/en/installation/installation-1.8/cli-utility.rst deleted file mode 100644 index d4a3f9d..0000000 --- a/en/installation/installation-1.8/cli-utility.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. :maxdepth: 2 - - -========================== -CLI utility installation -========================== - -Server requirements: - -- OS Debian 8 or Debian 9 with amd64 architecture -- Python 2.7 - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-cli - -Configuration ----------------------------------- - -To configure yeti-cli parameters edit /etc/yeti/yeti-cli.yml file - -Create yeti-cli.yml file with the following content: - -.. code-block:: yaml - - nodes_url: 'http://localhost:6666/api/rest/system/nodes.json' - authentificator_url: 'http://localhost:6666/api/rest/system/admin_users.json?q[ssh_key_present]=1' - timeout: 5 - default_node: 8 - prompt_system_name: 'YETI' - - -* **nodes_url** - url for getting nodes list on initial startup -* **authentificator_url** - url for getting public keys via yeti-cli-authentificator -* **timeout** - result waiting timeout -* **default_node** - default node, to which we connect on start -* **prompt_system_name** - Promt string - -You can override default config location via enviroment variable YETI_CMD_CFG_PATH - -Shell mode -------------- - -Also you can configure yeti-cli to work as shell. -You openssh-server must support AuthorizedKeysCommand. -Add next lines to sshd_config - -.. code-block::yaml - - AuthorizedKeysCommand /usr/sbin/yeti-cli-authentificator - AuthorizedKeysCommandUser console - PermitUserEnvironment yes - - -Reload ssh daemon - -.. code-block:: console - - # systemctl sshd reload diff --git a/en/installation/installation-1.8/database-tuning.rst b/en/installation/installation-1.8/database-tuning.rst deleted file mode 100644 index de6c7d4..0000000 --- a/en/installation/installation-1.8/database-tuning.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. :maxdepth: 2 - -============================ -Databases performance tuning -============================ - -By default Postgresql RDBMS configured to consume minimal system resources. This approach allows Postgresql to start on any server after installation. YETI as well as any other system uses Postgresql requires changing default configuration in order to archive best performance. - -We recommends to change next configuration variables at /etc/postgresql/11/yeti/postgresql.conf - -.. code-block:: ini - - shared_buffers = 10GB - work_mem = 32MB - fsync = on - max_wal_size = 8GB - checkpoint_timeout = 50min - - -Set **shared_buffers** variable to 1/3 of total RAM installed to server if you share this server with some another application. For example we recommends install yeti-web on same server as routing database. -If your server is dedicated for postgresql set **shared_buffers** to 2/3 of your RAM. - -When configuration changed you should restart your postgresql instance using `service postgresql restart` - -.. seealso:: Read Postgresql manual https://www.postgresql.org/docs/11/ to understand postgresql architecture and features - - - - - - - - diff --git a/en/installation/installation-1.8/index.rst b/en/installation/installation-1.8/index.rst deleted file mode 100644 index caafda5..0000000 --- a/en/installation/installation-1.8/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. _install_1.8: - -Version 1.8 -=========== - -Supported Operating systems is Debian GNU/Linux 8 and 9, the only supported architecture is amd64 - -Components: - -.. toctree:: - :maxdepth: 2 - - repositories - routing-database - cdr-database - web - redis - management - sems - call-trace - cli-utility - database-tuning - release-notes - upgrade-from-1.7 - diff --git a/en/installation/installation-1.8/management.rst b/en/installation/installation-1.8/management.rst deleted file mode 100644 index 9d9f3bd..0000000 --- a/en/installation/installation-1.8/management.rst +++ /dev/null @@ -1,194 +0,0 @@ -.. :maxdepth: 2 - - -============================== -Management server installation -============================== - -Since version 1.6.3-175 we started to use central configuration server -to store yeti module configuration for all nodes in cluster. - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-management - -Configuration files -------------------- - -/etc/yeti/management.cfg -~~~~~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for management daemon. - -Set desired logging level and address to listen. - -You can set multiple addresses separated by comma to listen on multiple interfaces. - -Possible log_level values are: (1 - error, 2 - info, 3 - debug) - -.. code-block:: c - - daemon { - listen = { - "tcp://0.0.0.0:4444" - } - - sctp { - address = "127.0.0.1" - port = 4444 - } - - http { - address = "127.0.0.1" - port = 3000 - } - log_level = 2 - } - -/etc/yeti/system.cfg -~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for all nodes. -Each top-level section defines configuration for node of certain type -(signaling is for traffic switch nodes). -All top-level sections contains mandatory section globals -which must have all possible values common for all nodes. -Then there is named sections for each node_id which may contain -values overriding ones set in global section. - -Note: even if your node does not have -any specific values you have to define empty section -for this node anyway, otherwise management node -will not provide configuration for node with this id. - -Example of minimal configuration file for node with id 8 - -.. code-block:: c - - signalling { - globals { - yeti { - pop_id = 4 - msg_logger_dir = /var/spool/sems/dump - log_dir = /var/spool/sems/logdump - routing { - schema = switch17 - function = route_release - init = init - master_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - failover_to_slave = false - slave_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - cache { - enabled = false - check_interval = 60 - buckets = 100000 - } - } - cdr { - dir = /var/spool/sems/cdrs - completed_dir = /var/spool/sems/cdrs/completed - pool_size = 2 - schema = switch - function = writecdr - master { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_to_slave = false - slave { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_requeue = true - failover_to_file = false - serialize_dynamic_fields = true - batch_size = 1 - batch_timeout = 5000 - } - resources { - reject_on_error = false - write { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 500 - } - read { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 1000 - } - } - registrations { - check_interval = 5000 - } - rpc { - calls_show_limit = 10000 - } - } - } - node 8 { } - } - -.. warning:: You should define all Nodes that has been created at web interface by their IDs. See :ref:`System->Nodes ` menu. SEMS node will refuse to start if corresponding node is not defined at system.cfg - - -Management server launch ------------------------- - -Launch configured management server instance: - -.. code-block:: console - - # service yeti-management start - -Checks ------- - -Check file /var/log/yeti/yeti-management.log for daemon logs: - -.. code-block:: console - - # tail -2 /var/log/yeti/yeti-management.log - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/yeti_mgmt_server.cpp:148: starting version 1.0.5 - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/mgmt_server.cpp:123: listen on tcp://0.0.0.0:4444 - -Check listening port: - -.. code-block:: console - - # netstat -lpn | grep yeti_management - 4444 tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN 25376/yeti_manageme - diff --git a/en/installation/installation-1.8/redis.rst b/en/installation/installation-1.8/redis.rst deleted file mode 100644 index 2c8b4a7..0000000 --- a/en/installation/installation-1.8/redis.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. :maxdepth: 2 - - -================== -Redis installation -================== - -Redis is used to synchronize data between traffic switch instances. -It stores information about used resources (e.g gateways capacity limits) -to provide correct limitation among all nodes for distributed installations. - -Install packages -================ - -.. code-block:: console - - # apt update && apt install redis-server - -Checks -====== - -Try to enter redis console from traffic switch host -(redis installed at the same host -with traffic switch in this example): - -.. code-block:: console - - # redis-cli - 127.0.0.1:6379> ping - PONG - 127.0.0.1:6379> quit diff --git a/en/installation/installation-1.8/release-notes.rst b/en/installation/installation-1.8/release-notes.rst deleted file mode 100644 index 5495e3a..0000000 --- a/en/installation/installation-1.8/release-notes.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. :maxdepth: 2 - -============= -Release notes -============= - - -Routing logic changes in 1.8 version -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - * Ability to limit Account capacity in both direction - see **total capacity** attribute of Account - * Ability to define maximum destination rate allowed for account. This feature useful to prevent traffic termination to fraudulent destinations - * Now it is possible to define VAT for account and calculate call price for call originator with VAT - * Per Account maximum call duration limitation. - * **Routeset Discriminators** allows to have few routeset from same vendor. Yeti will try to use few routes from same vendor if such routes have different Routeset Discriminator. Previously it was not possible to have two different routeset of same vendor in same Routing Plan. - * Ability to define maximum rerouting attempts per routing plan. Previously maximum rerouting attempts was hardcoded to 10 - * New balancing modes for Gateway Group - * Numberlist processing at termination gateway(after routing). Now it is possible configure massive number rewrite before call termination to specific gateway. - -SEMS changes in 1.8 version -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - * Completely new SEMS configuration format and configuration validation - * TLS transport protocol - * IPv6 support and flexible protocol priority configuration - * **sips** SIP schema support - * SRTP with DTLS and SDES mechanisms - * RTCP processing - * RTCP/RTP statistics saving to database. It is possible to analyze calls quality using statistics data. - -Admin UI changes -~~~~~~~~~~~~~~~~ - * Rails was upgraded to 5.2 - * ActiveAdmin was upgraded - * Role Based Access Control. It is possible to limit access level of system operator - diff --git a/en/installation/installation-1.8/repositories.rst b/en/installation/installation-1.8/repositories.rst deleted file mode 100644 index b797f04..0000000 --- a/en/installation/installation-1.8/repositories.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. :maxdepth: 2 - - -========================== -Repositories configuration -========================== - -Most of servers you can use same repositories set, for Debian 8:: - - deb http://ftp.us.debian.org/debian/ jessie main contrib non-free - deb http://ftp.us.debian.org/debian/ jessie-updates main - deb http://security.debian.org/ jessie/updates main - deb http://pkg.yeti-switch.org/debian/jessie 1.8 main - -And for Debian 9:: - - deb http://ftp.us.debian.org/debian/ stretch main contrib non-free - deb http://ftp.us.debian.org/debian/ stretch-updates main - deb http://security.debian.org/ stretch/updates main - deb http://pkg.yeti-switch.org/debian/stretch 1.8 main - - -System repositories can be changed by editing of file: /etc/apt/sources.list. Since we use our own package repository you have add our key to trusted. -There is two ways to do it: - -.. code-block:: console - - # apt-key adv --keyserver keys.gnupg.net --recv-key 9CEBFFC569A832B6 - -or - -.. code-block:: console - - # wget http://pkg.yeti-switch.org/key.gpg -O - | apt-key add - - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. - -On your datadabase hosts(routing and CDR) you should add additional PGDG repository:: - - deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main - -Or for Debian 9:: - - deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main - -You can add PGDG repository key to trusted using command: - -.. code-block:: console - - # wget https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - diff --git a/en/installation/installation-1.8/routing-database.rst b/en/installation/installation-1.8/routing-database.rst deleted file mode 100644 index 405f02f..0000000 --- a/en/installation/installation-1.8/routing-database.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. :maxdepth: 2 - - -============================= -Routing database installation -============================= - -.. note:: We recommend placing routing database on the same host with management WEB interface for best performance and web interface responsiveness. - - -Supported versions ------------------- - -The only supported postgresql version is 11. - - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install postgresql-11 postgresql-contrib-11 postgresql-11-prefix postgresql-11-pgq3 postgresql-11-pgq-ext postgresql-11-yeti pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - -Databases creation ------------------- - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user yeti encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database yeti owner yeti; - CREATE DATABASE - postgres=# \q - - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - -Checks ------- - -Check if databases were successfully created and are accessible:: - - root@evial:/# psql -h 127.0.0.1 -U yeti -d yeti - Password for user yeti: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - yeti=# \q - root@evial:/# - - -Don't forget to make changes in /etc/postgresql/11/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.8/sems.rst b/en/installation/installation-1.8/sems.rst deleted file mode 100644 index e7322e8..0000000 --- a/en/installation/installation-1.8/sems.rst +++ /dev/null @@ -1,168 +0,0 @@ -.. :maxdepth: 2 - - -====================== -SEMS node installation -====================== - -Install packages ----------------- - -.. code-block:: console - - # apt update && apt install sems sems-modules-yeti - -Configuration files -------------------- - -.. _sems_conf_1.8: - -/etc/sems/sems.conf -~~~~~~~~~~~~~~~~~~~ - -Add new node to the routing database using web interface -[ System -> Nodes -> New Node ]. -Use id of newly created node as value for **node_id** parameter - -node_id - unique signaling node id. - -.. warning:: You should create Node at web interface and use ID from web interface at **node_id** variable. See :ref:`System->Nodes ` menu. - -Replace , with correct values for your server : - -.. code-block:: c - - general { - daemon = yes - stderr = no - syslog_loglevel = 2 - syslog_facility = LOCAL0 - - node_id = 8 - - shutdown_mode { - code = 508 - reason = "Yeti node in shutdown mode" - allow_uac = true - } - - #pcap_upload_queue = pcap - - media_processor_threads = 2 - rtp_receiver_threads = 2 - session_processor_threads = 10 - sip_udp_server_threads = 2 - sip_tcp_server_threads = 2 - - dead_rtp_time=30 - } - - - signaling-interfaces { - interface input { - default-media-interface = input - ip4 { - sip-udp { - address = - port = 5061 - use-raw-sockets = off - } - sip-tcp { - address = - port = 5061 - connect-timeout = 2000 - static-client-port = on - idle-timeout=900000 - use-raw-sockets = off - } - } - } - } - - media-interfaces { - interface input { - ip4 { - rtp { - address = - low-port = 16384 - high-port = 32767 - dscp = 46 - use-raw-sockets = off - } - } - } - } - - modules { - module "di_log"{} - module "mp3"{} - module "opus"{} - module "wav"{} - module "gsm"{} - module "ilbc"{} - module "adpcm"{} - module "l16"{} - module "g722"{} - - module "registrar_client" {} - module "sctp_bus"{} - module "http_client"{} - module "session_timer"{} - module "jsonrpc"{ - listen{ - address = 127.0.0.1 - port = 7080 - } - server_threads=1 - } - - module-global "uac_auth" { } - - module "yeti" { - management { - address = 127.0.0.1 - port = 4444 - timeout = 60000 - } - core_options_handling = yes - registrations_enabled = yes - } - } - - routing { - application = yeti - } - - - - -.. warning:: RPC allows shutdown SEMS node or make it non-operational. RPC interface should be secured by firewall to prevent connections from not trusted hosts. In YETI systems only two components should have ability to connect to RPC - WEB interface and yeti-cli console - -Launch traffic switch ---------------------- - -Launch configured traffic switch instance: - -.. code-block:: console - - # service sems start - -In case of errors it's useful to use **sems -E -D3** command -which will launch daemon in foreground with debug logging level - -Checks ------- - -Check if **sems** process exists and signaling/media/rpc sockets are opened: - -.. code-block:: console - - # pgrep sems - 29749 - # netstat -lpn | grep sems - tcp 0 0 127.0.0.1:8090 0.0.0.0:* LISTEN 29749/sems - udp 0 0 127.0.0.1:5061 0.0.0.0:* 29749/sems - raw 2688 0 0.0.0.0:17 0.0.0.0:* 7 29749/sems - -Check logfile /var/log/sems/sems-main.log for possible errors diff --git a/en/installation/installation-1.8/upgrade-from-1.7.rst b/en/installation/installation-1.8/upgrade-from-1.7.rst deleted file mode 100644 index aab1ceb..0000000 --- a/en/installation/installation-1.8/upgrade-from-1.7.rst +++ /dev/null @@ -1,143 +0,0 @@ -.. :maxdepth: 2 - -==================== -Upgrade instructions -==================== - -This instuctions describe how to upgrade Yeti system from version 1.7.15 to version 1.8. If you have any other Yeti version you should previously upgrade it to 1.7.15 - - -Get know your postgresql cluster epoch -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -PGQ components of CDR database require cluster epoch increment. To get know your cluster epoch, connect to CDR postgresql database using **psql** and run: - -.. code-block:: console - - cdr=# SELECT (txid_current() >> 32) as epoch; - epoch - ------- - 0 - (1 row) - -See https://github.com/markokr/skytools/blob/master/doc/faq.txt#L50 for details - - -Upgrade yeti-web package to 1.8.0 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# apt update - root@yeti:/# apt install yeti-web=1.8.0 - - -Postgresql 11 installation -~~~~~~~~~~~~~~~~~~~~~~~~~~ -You should install postgresql-11 packages, as described at :doc:`routing-database` and :doc:`cdr-database` and create appropriate databases. - - -Run new instances of Postgresql(version 11) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -New postgresql instances should run on different ports: - -.. code-block:: console - - root@yeti-postgresql-9:~# pg_lsclusters - Ver Cluster Port Status Owner Data directory Log file - 9.4 cdr 5435 online postgres /var/lib/postgresql/9.4/cdr /var/log/postgresql/postgresql-9.4-cdr.log <<< OLD CDR database - 9.4 routing 5434 online postgres /var/lib/postgresql/9.4/routing /var/log/postgresql/postgresql-9.4-routing.log <<< OLD routing database - 11 cdr 5437 online postgres /var/lib/postgresql/11/cdr /var/log/postgresql/postgresql-11-cdr.log <<< NEW CDR database - 11 routing 5436 online postgres /var/lib/postgresql/11/routing /var/log/postgresql/postgresql-11-routing.log <<< NEW routing database - - - -Shutdown CDR billing process and other pgq-processor consumers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: console - - # systemctl stop yeti-cdr-billing@cdr_billing - # systemctl stop yeti-delayed-job - - -Stop CDR writing to old Postgresql CDR instances -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To stop CDR writing change **listen_address** to '127.0.0.1' at postgresql.conf Configuration for old postgresql instances and restart postgresql - - -Change epoch of new postgresql CDR instance -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Shutdown new postgresql CDR cluster and change epoch: - -.. code-block:: console - - # su - postgres - # /usr/lib/postgresql/11/bin/pg_resetwal -e 1 /var/lib/postgresql/11/cdr - - -Where **1** is increased epoch - it should be greater then epoch of old intance - -See https://github.com/markokr/skytools/blob/master/doc/faq.txt#L50 for details - -Start new postgresql CDD instance. - - -Copy data from old databases to new instances -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You should dump your databases using pg_dump and then restore data to new instances: - -.. code-block:: console - - root@yeti-postgresql-9:~# pg_dump -h 127.0.0.1 -p 5434 -U yeti -O -x -F c -f yeti.dmp yeti - root@yeti-postgresql-9:~# pg_restore -h 127.0.0.1 -p 5436 -U yeti -d yeti -e yeti.dmp - root@yeti-postgresql-9:~# pg_dump -h 127.0.0.1 -p 5435 -U cdr -O -x -F c -f yeti.dmp yeti - root@yeti-postgresql-9:~# pg_restore -h 127.0.0.1 -p 5437 -U cdr -d yeti -e yeti.dmp - - -Shutdown old databases and move new instances to their ports -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Change **port** at postgresql.conf of each postgresql cluster to move new instances to old ports. Restart postgresql. - - -Apply first stage of migrations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# cd /home/yeti-web - root@yeti:/# su -s /bin/bash yeti-web - yeti-web@demo-yeti:~$ RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - yeti-web@demo-yeti:~$ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - ....SKIPPED... - == 20180212105355 MultipleMatchingConditions: migrated (2.0862s) ============== - - IMPORTANT: Now update and restart your servers. And after that run `rake db:migrate` again. - root@yeti:/home/yeti-web# - - -Restart all components of yeti-web -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# systemctl restart yeti-web - root@yeti:/# systemctl restart yeti-cdr-billing@cdr_billing - root@yeti:/# systemctl restart yeti-delayed-job - - - -Switch to new routing schema -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Change at /etc/yeti/system.cfg switch routing schema to **switch17** from **switch16** on your yeti-management server and restart yeti-management server - - -SEMS servers -~~~~~~~~~~~~ - -Upgrade your SEMS nodes to new version. Configuration files format was changed, See :ref:`sems.conf ` for details. - - - diff --git a/en/installation/installation-1.8/web.rst b/en/installation/installation-1.8/web.rst deleted file mode 100644 index 61d651d..0000000 --- a/en/installation/installation-1.8/web.rst +++ /dev/null @@ -1,207 +0,0 @@ -.. :maxdepth: 2 - - -========================== -WEB interface installation -========================== - -Server requirements: - -- amd64 architecture -- Debian 8 Jessie or Debian 9 Stretch distibution -- at least 4GB of RAM - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-web nginx - -Databases connection configuration ----------------------------------- - -To configure databases connection parameters edit /home/yeti-web/config/database.yml file - -Create database.yml file with the following content: - -.. code-block:: yaml - - production: - adapter: postgresql - encoding: unicode - database: yeti - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import' - port: 5432 - min_messages: notice - - secondbase: - production: - adapter: postgresql - encoding: unicode - database: cdr - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'cdr, reports, billing' - port: 5432 - min_messages: notice - -Warning: you should specify correct addresses and credentials that were used in previous section - -Databases data initialization ------------------------------ - -To simplify work with databases use utility yeti-db -To initialize empty databases: - -.. code-block:: console - - # cd /home/yeti-web - # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:structure:load db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:structure:load db:second_base:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:seed - - -To upgrade databases to the latest version: - -.. code-block:: console - - # cd /home/yeti-web - # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - - -Nginx configuration -------------------- - -For basic configuration remove default config and copy yeti-web.dist.nginx: - -.. code-block:: console - - # rm /etc/nginx/sites-enabled/default - # cp /home/yeti-web/config/yeti-web.dist.nginx /etc/nginx/sites-enabled/yeti - # nginx -t - nginx: the configuration file /etc/nginx/nginx.conf syntax is ok - nginx: configuration file /etc/nginx/nginx.conf test is successful - # service nginx restart - - -Launch ------- - -After successful configuration of databases you finally can run software using following commands: - -.. code-block:: console - - # service yeti-web start - # service yeti-cdr-billing@cdr_billing start - # service yeti-delayed-job start - -This will run web-interface and CDR processing workers - -Checks ------- - -check if unicorn listens on local socket: - -.. code-block:: console - - # netstat -lpn | grep unicorn - unix 2 [ ACC ] STREAM LISTENING 2535145 24728/unicorn.rb -E /tmp/yeti-unicorn.sock - -check if nginx listens on correct TCP/IP addresses and ports: - -.. code-block:: console - - # netstat -lpn | grep nginx - tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 23627/nginx - tcp 0 0 127.0.0.1:6666 0.0.0.0:* LISTEN 23627/nginx - -Log files to check for possible warnings/errors: - -- /var/log/yeti-admin.log -- /var/log/yeti-cdr-billing.log -- /home/yeti-web/log/unicorn.stdout.log -- /home/yeti-web/log/unicorn.stderr.log - -Try to open management interface in your favorite browser and login with default credentials: - -:user: admin -:password: 111111 - - -Invoice PDF generation ----------------------- - -If you need to generate invoices in PDF format, you have to install additional packages. -It is accomplished via LibreOffice software, so our package just a wrapper for a LibreOffice installation. - -.. warning:: - This operation will install a lot of packages in your system! - -.. code-block:: console - - # apt install yeti-libreoffice-headless - -Make sure, that service is enabled for autostart - -.. code-block:: console - - # systemctl enable yeti-libreoffice-headless - -Run it - -.. code-block:: console - - # systemctl start yeti-libreoffice-headless - - -LDAP Authentication -------------------- -Yeti's web-interface may use LDAP in order to authnticate users. - -Copy configuration from example file - -.. code-block:: console - - # cp /home/yeti-web/config/ldap.yml.dist /home/yeti-web/config/ldap.yml - -and edit it - -.. code-block:: console - - production: - host: yeti-host.com - port: 389 - ssl: false - attribute: uid - base: ou=employees,dc=yeti,dc=com - group_base: ou=groups,dc=yeti,dc=com - required_groups: - - ["member", "cn=yeti,ou=groups,dc=yeti,dc=com"] - -* **host** - address of LDAP server -* **port** - port of LDAP server -* **ssl** - enable/disable SSL -* **attribute** - name of attribute which contains user login -* **base** - base DN where YETI will try find users -* **group_base** - base DN where YETI will try find groups -* **required_groups** - array of groups where user must present -* **member** - attribute where group stored -* **cn=yeti,ou=groups,dc=yeti,dc=com** - group - - -After editing file, restart YETI web interface - -.. code-block:: console - - # systemctl restart yeti-web - diff --git a/en/installation/installation-1.9/call-trace.rst b/en/installation/installation-1.9/call-trace.rst deleted file mode 100644 index 6a01fe2..0000000 --- a/en/installation/installation-1.9/call-trace.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. :maxdepth: 2 - - -================================ -Call trace storage configuration -================================ - - -SEMS and Web are running on same server ---------------------------------------- - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content: - -.. code-block:: nginx - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/spool/sems; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -SEMS and Web located on different servers ------------------------------------------ - -Configure nginx on WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Create directory **/var/www/dump** with owner **www-data** to store PCAP files. - -Edit **/etc/nginx/sites-enabled/yeti-web** and add such server block: - -.. code-block:: nginx - - server { - listen :8081; - server_name _; - access_log /var/log/nginx/pcap-upload.access.log; - error_log /var/log/nginx/pcap-upload.error.log; - - root /var/www/dump; - - location /upload { - allow /32; - deny all; - - alias /var/www/dump; - dav_methods PUT; - dav_access group:rw all:r; - create_full_put_path on; - client_max_body_size 10000M; - } - } - - -Edit **/etc/nginx/sites-enabled/yeti-web** and replace **location ~ ^/dump/(.*)$** with following content: - -.. code-block:: nginx - - location ~ ^/dump/(.*)$ { - internal; - set $filename $1; - proxy_hide_header Content-Disposition; - add_header Content-Disposition 'attachment; filename="$filename"'; - root /var/www; - } - -Restart nginx service: - -.. code-block:: console - - # systemctl restart nginx - -Configure SEMS to upload traces to WEB interface server -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Add **http_client** module configuration to **modules** section of **/etc/sems/sems.conf**:: - - modules { - path = /usr/lib/sems/plug-in - config_path=/etc/sems/etc/ - ... - module "http_client" { - resend_interval=5000 - resend_queue_max=10000 - - destination "pcap" { - mode=put - urls={ http://:8081/upload } - on_success { - action = remove - } - on_failure { - action = requeue - } - } - } - ... - } - -Add **pcap_upload_queue=pcap** directive to section **general** of **/etc/sems/sems.conf**:: - - general { - ... - pcap_upload_queue=pcap - ... - } - - -Restart SEMS: - -.. code-block:: console - - # systemctl restart sems - - - - - diff --git a/en/installation/installation-1.9/cdr-database.rst b/en/installation/installation-1.9/cdr-database.rst deleted file mode 100644 index 5935f28..0000000 --- a/en/installation/installation-1.9/cdr-database.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. :maxdepth: 2 - - -========================== -CDR databases installation -========================== - -.. note:: System requires two databases: one for routing and one for CDRs. Setting up different PostgreSQL instances is highly recommended to make replication possible. - -Packages installation -===================== - -CDRs databases require similar set of packages as routing database - -.. code-block:: console - - # apt update && apt install postgresql-11 postgresql-contrib-11 postgresql-11-prefix postgresql-11-pgq3 postgresql-11-pgq-ext postgresql-11-yeti postgresql-11-pllua pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - - -Databases creation -================== - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user cdr encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database cdr owner cdr; - CREATE DATABASE - postgres=# \q - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - - -PGQd ticker -=========== - -After initialization of CDR database you should run pgq ticker daemon(**pgqd**) on server with CDR database. - -Create configuration file /etc/pgqd.ini - -.. code-block:: ini - - [pgqd] - base_connstr = host=127.0.0.1 port=5432 dbname=cdr user=cdr password=somepassword - initial_database = cdr - database_list = cdr - script = /usr/bin/pgqd - pidfile = /var/run/postgresql/pgqd.pid - ticker_max_count=1 - ticker_max_lag=3 - ticker_idle_period=360 - - -Then you should start ticker: - -.. code-block:: console - - # service pgqd start - - -Checks -====== - -Check if databases were successfully created and are accessible: - -.. code-block:: psql - - root@cdr-server:/# psql -h 127.0.0.1 -U cdr -d cdr - Password for user cdr: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - cdr=# \q - root@cdr-server:/# - -Don't forget to make changes in /etc/postgresql/11/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.9/database-tuning.rst b/en/installation/installation-1.9/database-tuning.rst deleted file mode 100644 index de6c7d4..0000000 --- a/en/installation/installation-1.9/database-tuning.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. :maxdepth: 2 - -============================ -Databases performance tuning -============================ - -By default Postgresql RDBMS configured to consume minimal system resources. This approach allows Postgresql to start on any server after installation. YETI as well as any other system uses Postgresql requires changing default configuration in order to archive best performance. - -We recommends to change next configuration variables at /etc/postgresql/11/yeti/postgresql.conf - -.. code-block:: ini - - shared_buffers = 10GB - work_mem = 32MB - fsync = on - max_wal_size = 8GB - checkpoint_timeout = 50min - - -Set **shared_buffers** variable to 1/3 of total RAM installed to server if you share this server with some another application. For example we recommends install yeti-web on same server as routing database. -If your server is dedicated for postgresql set **shared_buffers** to 2/3 of your RAM. - -When configuration changed you should restart your postgresql instance using `service postgresql restart` - -.. seealso:: Read Postgresql manual https://www.postgresql.org/docs/11/ to understand postgresql architecture and features - - - - - - - - diff --git a/en/installation/installation-1.9/index.rst b/en/installation/installation-1.9/index.rst deleted file mode 100644 index f0d35ab..0000000 --- a/en/installation/installation-1.9/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. _install_1.9: - -Version 1.9 -=========== - -Supported Operating systems is Debian GNU/Linux 9, the only supported architecture is amd64 - -Components: - -.. toctree:: - :maxdepth: 2 - - repositories - routing-database - cdr-database - web - redis - management - sems - call-trace - database-tuning - release-notes - upgrade-from-1.8 - diff --git a/en/installation/installation-1.9/management.rst b/en/installation/installation-1.9/management.rst deleted file mode 100644 index 2f4855c..0000000 --- a/en/installation/installation-1.9/management.rst +++ /dev/null @@ -1,200 +0,0 @@ -.. :maxdepth: 2 - - -============================== -Management server installation -============================== - -Since version 1.6.3-175 we started to use central configuration server -to store yeti module configuration for all nodes in cluster. - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-management - -Configuration files -------------------- - -/etc/yeti/management.cfg -~~~~~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for management daemon. - -Set desired logging level and address to listen. - -You can set multiple addresses separated by comma to listen on multiple interfaces. - -Possible log_level values are: (1 - error, 2 - info, 3 - debug) - -.. code-block:: c - - daemon { - listen = { - "tcp://0.0.0.0:4444" - } - - sctp { - address = "127.0.0.1" - port = 4444 - } - - http { - address = "127.0.0.1" - port = 3000 - } - log_level = 2 - } - -/etc/yeti/system.cfg -~~~~~~~~~~~~~~~~~~~~ - -This file contains configuration for all nodes. -Each top-level section defines configuration for node of certain type -(signaling is for traffic switch nodes). -All top-level sections contains mandatory section globals -which must have all possible values common for all nodes. -Then there is named sections for each node_id which may contain -values overriding ones set in global section. - -.. note:: Even if your node does not have any specific values you have to define empty section for this node anyway, otherwise management node will not provide configuration for node with this id. - -Example of minimal configuration file for node with id 8 - -.. code-block:: c - - signalling { - globals { - yeti { - pop_id = 4 - msg_logger_dir = /var/spool/sems/dump - log_dir = /var/spool/sems/logdump - audio_recorder_dir = /var/spool/sems/records - audio_recorder_compress = true - routing { - schema = switch18 - function = route_release - init = init - master_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - failover_to_slave = false - slave_pool { - host = 127.0.0.1 - port = 5432 - name = yeti - user = yeti - pass = yeti - size = 4 - check_interval = 10 - max_exceptions = 0 - statement_timeout=3000 - } - cache { - enabled = false - check_interval = 60 - buckets = 100000 - } - } - cdr { - dir = /var/spool/sems/cdrs - completed_dir = /var/spool/sems/cdrs/completed - pool_size = 2 - schema = switch - function = writecdr - master { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_to_slave = false - slave { - host = 127.0.0.1 - port = 5432 - name = cdr - user = cdr - pass = cdr - } - failover_requeue = true - failover_to_file = false - serialize_dynamic_fields = true - batch_size = 1 - batch_timeout = 5000 - } - resources { - reject_on_error = false - write { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 500 - } - read { - host = 127.0.0.1 - port = 6379 - size = 2 - timeout = 1000 - } - } - registrations { - check_interval = 5000 - } - registrar { - enabled = true - redis { - host = 127.0.0.1 - port = 6379 - } - } - rpc { - calls_show_limit = 10000 - } - } - } - node 8 { } - } - -.. warning:: You should define all Nodes that has been created at web interface by their IDs. See :ref:`System->Nodes ` menu. SEMS node will refuse to start if corresponding node is not defined at system.cfg - - -Management server launch ------------------------- - -Launch configured management server instance: - -.. code-block:: console - - # service yeti-management start - -Checks ------- - -Check file /var/log/yeti/yeti-management.log for daemon logs: - -.. code-block:: console - - # tail -2 /var/log/yeti/yeti-management.log - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/yeti_mgmt_server.cpp:148: starting version 1.0.5 - Sep 12 12:54:47 evial yeti-management[25376]: [25376] - info: server/src/mgmt_server.cpp:123: listen on tcp://0.0.0.0:4444 - -Check listening port: - -.. code-block:: console - - # netstat -lpn | grep yeti_management - 4444 tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN 25376/yeti_manageme - diff --git a/en/installation/installation-1.9/redis.rst b/en/installation/installation-1.9/redis.rst deleted file mode 100644 index 2c8b4a7..0000000 --- a/en/installation/installation-1.9/redis.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. :maxdepth: 2 - - -================== -Redis installation -================== - -Redis is used to synchronize data between traffic switch instances. -It stores information about used resources (e.g gateways capacity limits) -to provide correct limitation among all nodes for distributed installations. - -Install packages -================ - -.. code-block:: console - - # apt update && apt install redis-server - -Checks -====== - -Try to enter redis console from traffic switch host -(redis installed at the same host -with traffic switch in this example): - -.. code-block:: console - - # redis-cli - 127.0.0.1:6379> ping - PONG - 127.0.0.1:6379> quit diff --git a/en/installation/installation-1.9/release-notes.rst b/en/installation/installation-1.9/release-notes.rst deleted file mode 100644 index 9e9df6b..0000000 --- a/en/installation/installation-1.9/release-notes.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. :maxdepth: 2 - -============= -Release notes -============= - - -Changes in 1.9 version -~~~~~~~~~~~~~~~~~~~~~~ - - * Yeti now can act as Registrar server and terminate calls to remote gateways with dynamic IP address - * Table partitioning mechanism was changed to native Postgresql partitioning(New partitioning mechanism was implemented in Postgresql 10) - * Admin API for Active Calls - * New numberlist matching mode - Random - * Additional CDR fields - *legb_ruri* and *legb_outbound_proxy* - * Support of Debian 8 Jessie was removed - diff --git a/en/installation/installation-1.9/repositories.rst b/en/installation/installation-1.9/repositories.rst deleted file mode 100644 index 445dd79..0000000 --- a/en/installation/installation-1.9/repositories.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. :maxdepth: 2 - - -========================== -Repositories configuration -========================== - -Most of servers you can use same repositories set:: - - deb http://ftp.us.debian.org/debian/ stretch main contrib non-free - deb http://ftp.us.debian.org/debian/ stretch-updates main - deb http://security.debian.org/ stretch/updates main - deb http://pkg.yeti-switch.org/debian/stretch 1.9 main - - -System repositories can be changed by editing of file: /etc/apt/sources.list. Since we use our own package repository you have add our key to trusted. -There is two ways to do it: - -.. code-block:: console - - # apt-key adv --keyserver keys.gnupg.net --recv-key 9CEBFFC569A832B6 - -or - -.. code-block:: console - - # wget http://pkg.yeti-switch.org/key.gpg -O - | apt-key add - - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. - -On your datadabase hosts(routing and CDR) you should add additional PGDG repository:: - - deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main - -You can add PGDG repository key to trusted using command: - -.. code-block:: console - - # wget https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - diff --git a/en/installation/installation-1.9/routing-database.rst b/en/installation/installation-1.9/routing-database.rst deleted file mode 100644 index 2d6e29a..0000000 --- a/en/installation/installation-1.9/routing-database.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. :maxdepth: 2 - - -============================= -Routing database installation -============================= - -.. note:: We recommend placing routing database on the same host with management WEB interface for best performance and web interface responsiveness. - - -Supported versions ------------------- - -The only supported postgresql version is 11. - - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install postgresql-11 postgresql-contrib-11 postgresql-11-prefix postgresql-11-pgq3 postgresql-11-pgq-ext postgresql-11-yeti postgresql-11-pllua pgqd - - -.. warning:: Since yeti-web version 1.6.0 it is important to install Postgresql from `PGDG `_ repository. See :doc:`repositories` for details - - -Databases creation ------------------- - -Create routing database - -.. code-block:: console - - # su - postgres - $ psql - - -.. code-block:: psql - - postgres=# create user yeti encrypted password 'somepassword' superuser; - CREATE ROLE - postgres=# create database yeti owner yeti; - CREATE DATABASE - postgres=# \q - - -.. warning:: It's recommended to choose databases names, usernames and passwords different from specified in this manual for security reasons. - -For large installations it's recommended to place CDR database on dedicated server. - -Checks ------- - -Check if databases were successfully created and are accessible:: - - root@evial:/# psql -h 127.0.0.1 -U yeti -d yeti - Password for user yeti: psql (9.4.5) SSL connection - (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256) - Type "help" for help. - - yeti=# \q - root@evial:/# - - -Don't forget to make changes in /etc/postgresql/11/main/pg_hba.conf -and apply them if you plan to access this databases from other hosts and/or set up database replication - -.. seealso:: :doc:`database-tuning` diff --git a/en/installation/installation-1.9/sems.rst b/en/installation/installation-1.9/sems.rst deleted file mode 100644 index eaac885..0000000 --- a/en/installation/installation-1.9/sems.rst +++ /dev/null @@ -1,167 +0,0 @@ -.. :maxdepth: 2 - - -====================== -SEMS node installation -====================== - -Install packages ----------------- - -.. code-block:: console - - # apt update && apt install sems sems-modules-yeti - -Configuration files -------------------- - -.. _sems_conf_1.9: - -/etc/sems/sems.conf -~~~~~~~~~~~~~~~~~~~ - -Add new node to the routing database using web interface -[ System -> Nodes -> New Node ]. -Use id of newly created node as value for **node_id** parameter - -node_id - unique signaling node id. - -.. warning:: You should create Node at web interface and use ID from web interface at **node_id** variable. See :ref:`System->Nodes ` menu. - -Replace , with correct values for your server : - -.. code-block:: c - - general { - daemon = yes - stderr = no - syslog_loglevel = 2 - syslog_facility = LOCAL0 - - node_id = 8 - - shutdown_mode { - code = 508 - reason = "Yeti node in shutdown mode" - allow_uac = true - } - - #pcap_upload_queue = pcap - - media_processor_threads = 2 - rtp_receiver_threads = 2 - session_processor_threads = 10 - sip_udp_server_threads = 2 - sip_tcp_server_threads = 2 - - dead_rtp_time=30 - } - - - signaling-interfaces { - interface input { - default-media-interface = input - ip4 { - sip-udp { - address = - port = 5061 - use-raw-sockets = off - } - sip-tcp { - address = - port = 5061 - connect-timeout = 2000 - static-client-port = on - idle-timeout=900000 - use-raw-sockets = off - } - } - } - } - - media-interfaces { - interface input { - ip4 { - rtp { - address = - low-port = 16384 - high-port = 32767 - dscp = 46 - use-raw-sockets = off - } - } - } - } - - modules { - module "di_log"{} - module "mp3"{} - module "opus"{} - module "wav"{} - module "gsm"{} - module "ilbc"{} - module "adpcm"{} - module "l16"{} - module "g722"{} - - module "registrar_client" {} - module "sctp_bus"{} - module "http_client"{} - module "session_timer"{} - module "jsonrpc"{ - listen{ - address = 127.0.0.1 - port = 7080 - } - server_threads=1 - } - - module-global "uac_auth" { } - - module "yeti" { - management { - address = 127.0.0.1 - port = 4444 - timeout = 60000 - } - core_options_handling = yes - } - } - - routing { - application = yeti - } - - - - -.. warning:: RPC allows shutdown SEMS node or make it non-operational. RPC interface should be secured by firewall to prevent connections from not trusted hosts. In YETI systems only two components should have ability to connect to RPC - WEB interface and yeti-cli console - -Launch traffic switch ---------------------- - -Launch configured traffic switch instance: - -.. code-block:: console - - # service sems start - -In case of errors it's useful to use **sems -E -D3** command -which will launch daemon in foreground with debug logging level - -Checks ------- - -Check if **sems** process exists and signaling/media/rpc sockets are opened: - -.. code-block:: console - - # pgrep sems - 29749 - # netstat -lpn | grep sems - tcp 0 0 127.0.0.1:8090 0.0.0.0:* LISTEN 29749/sems - udp 0 0 127.0.0.1:5061 0.0.0.0:* 29749/sems - raw 2688 0 0.0.0.0:17 0.0.0.0:* 7 29749/sems - -Check logfile /var/log/sems/sems-main.log for possible errors diff --git a/en/installation/installation-1.9/upgrade-from-1.8.rst b/en/installation/installation-1.9/upgrade-from-1.8.rst deleted file mode 100644 index 783844d..0000000 --- a/en/installation/installation-1.9/upgrade-from-1.8.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. :maxdepth: 2 - -==================== -Upgrade instructions -==================== - -This instuctions describe how to upgrade Yeti system from version 1.8.8 to version 1.9. If you have any other Yeti version you should previously upgrade it to 1.8.8 - - -Shutdown CDR billing process and other pgq-processor consumers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: console - - # systemctl stop yeti-cdr-billing@cdr_billing - # systemctl stop yeti-delayed-job - - - -Upgrade yeti-web package to 1.9.0 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# apt update - root@yeti:/# apt install yeti-web=1.9.0 - - -Postgresql 11 installation -~~~~~~~~~~~~~~~~~~~~~~~~~~ -You should install postgresql-11 packages, as described at :doc:`routing-database` and :doc:`cdr-database` and create appropriate databases. - - - -Apply migrations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# cd /opt/yeti-web - root@yeti:/# su -s /bin/bash yeti-web - root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - root@yeti:/opt/yeti-web# RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - root@yeti:/opt/yeti-web# - - -Restart all components of yeti-web -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: console - - root@yeti:/# systemctl restart yeti-web - root@yeti:/# systemctl restart yeti-cdr-billing@cdr_billing - root@yeti:/# systemctl restart yeti-delayed-job - - - -Switch to new routing schema -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Change at /etc/yeti/system.cfg switch routing schema to **switch18** from **switch17** on your yeti-management server:: - - signalling { - globals { - yeti { - pop_id = 4 - msg_logger_dir = /var/spool/sems/dump - log_dir = /var/spool/sems/logdump - routing { - schema = switch18 - ... - - -Restart yeti-management service to apply changes - - -SEMS servers -~~~~~~~~~~~~ - -Upgrade your SEMS nodes to new version. Configuration files format was changed, See :ref:`sems.conf ` for details. - - - diff --git a/en/installation/installation-1.9/web.rst b/en/installation/installation-1.9/web.rst deleted file mode 100644 index 87acf8d..0000000 --- a/en/installation/installation-1.9/web.rst +++ /dev/null @@ -1,204 +0,0 @@ -.. :maxdepth: 2 - - -========================== -WEB interface installation -========================== - -Server requirements: - -- amd64 architecture -- Debian 9 Stretch distibution -- at least 4GB of RAM - -Packages installation ---------------------- - -.. code-block:: console - - # apt update && apt install yeti-web nginx - -Databases connection configuration ----------------------------------- - -To configure databases connection parameters create /opt/yeti-web/config/database.yml file with the following content: - -.. code-block:: yaml - - production: - adapter: postgresql - encoding: unicode - database: yeti - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import' - port: 5432 - min_messages: notice - - secondbase: - production: - adapter: postgresql - encoding: unicode - database: cdr - pool: 5 - username: yeti - password: somepassword - host: 127.0.0.1 - schema_search_path: 'cdr, reports, billing' - port: 5432 - min_messages: notice - -Warning: you should specify correct addresses and credentials that were used in previous section - -Databases data initialization ------------------------------ - -To initialize empty databases during initial installation: - -.. code-block:: console - - # cd /opt/yeti-web - # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:structure:load db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:structure:load db:second_base:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:seed - - -To upgrade databases to the latest version: - -.. code-block:: console - - # cd /opt/yeti-web - # su -s /bin/bash yeti-web - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:migrate - $ RAILS_ENV=production ./bin/bundle.sh exec rake db:second_base:migrate - - -Nginx configuration -------------------- - -For basic configuration remove default config and copy yeti-web.dist.nginx: - -.. code-block:: console - - # rm /etc/nginx/sites-enabled/default - # cp /opt/yeti-web/config/yeti-web.dist.nginx /etc/nginx/sites-enabled/yeti - # nginx -t - nginx: the configuration file /etc/nginx/nginx.conf syntax is ok - nginx: configuration file /etc/nginx/nginx.conf test is successful - # service nginx restart - - -Launch ------- - -After successful configuration of databases you finally can run software using following commands: - -.. code-block:: console - - # service yeti-web start - # service yeti-cdr-billing@cdr_billing start - # service yeti-delayed-job start - -This will run web-interface and CDR processing workers - -Checks ------- - -check if unicorn listens on local socket: - -.. code-block:: console - - # netstat -lpn | grep unicorn - unix 2 [ ACC ] STREAM LISTENING 2535145 24728/unicorn.rb -E /tmp/yeti-unicorn.sock - -check if nginx listens on correct TCP/IP addresses and ports: - -.. code-block:: console - - # netstat -lpn | grep nginx - tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 23627/nginx - tcp 0 0 127.0.0.1:6666 0.0.0.0:* LISTEN 23627/nginx - -Log files to check for possible warnings/errors: - -- /var/log/yeti-admin.log -- /var/log/yeti-cdr-billing.log -- /opt/yeti-web/log/unicorn.stdout.log -- /opt/yeti-web/log/unicorn.stderr.log - -Try to open management interface in your favorite browser and login with default credentials: - -:user: admin -:password: 111111 - - -Invoice PDF generation ----------------------- - -If you need to generate invoices in PDF format, you have to install additional packages. -It is accomplished via LibreOffice software, so our package just a wrapper for a LibreOffice installation. - -.. warning:: - This operation will install a lot of packages in your system! - -.. code-block:: console - - # apt install yeti-libreoffice-headless - -Make sure, that service is enabled for autostart - -.. code-block:: console - - # systemctl enable yeti-libreoffice-headless - -Run it - -.. code-block:: console - - # systemctl start yeti-libreoffice-headless - - -LDAP Authentication -------------------- -Yeti's web-interface may use LDAP in order to authnticate users. - -Copy configuration from example file - -.. code-block:: console - - # cp /opt/yeti-web/config/ldap.yml.dist /opt/yeti-web/config/ldap.yml - -and edit it - -.. code-block:: console - - production: - host: yeti-host.com - port: 389 - ssl: false - attribute: uid - base: ou=employees,dc=yeti,dc=com - group_base: ou=groups,dc=yeti,dc=com - required_groups: - - ["member", "cn=yeti,ou=groups,dc=yeti,dc=com"] - -* **host** - address of LDAP server -* **port** - port of LDAP server -* **ssl** - enable/disable SSL -* **attribute** - name of attribute which contains user login -* **base** - base DN where YETI will try find users -* **group_base** - base DN where YETI will try find groups -* **required_groups** - array of groups where user must present -* **member** - attribute where group stored -* **cn=yeti,ou=groups,dc=yeti,dc=com** - group - - -After editing file, restart YETI web interface - -.. code-block:: console - - # systemctl restart yeti-web - diff --git a/en/quick-start/quick_start.rst b/en/quick-start/quick_start.rst index d8970c8..b8edef7 100644 --- a/en/quick-start/quick_start.rst +++ b/en/quick-start/quick_start.rst @@ -13,7 +13,7 @@ Yeti is user-friendly application and it very easy for configuration. You can se dependencies -This Guideline contains step-by-step description of Yeti's configuration that will help to start it quickly just after finishing of the :ref:`installation process `. +This Guideline contains step-by-step description of Yeti's configuration that will help to start it quickly just after finishing of the :ref:`installation process `. For configuration purposes :ref:`Yeti Web interface ` could be used. .. _quick_start_chapter1: diff --git a/en/web-interface/system/nodes.rst b/en/web-interface/system/nodes.rst index 3a2714b..07be102 100644 --- a/en/web-interface/system/nodes.rst +++ b/en/web-interface/system/nodes.rst @@ -16,7 +16,7 @@ Every node represents independent installation of YETI-SEMS, which communicate t Pop Point of presence. Might be useful for logic grupping of nodes (different data-centers, as example). Rpc endpoint - IP address and port on which YETI-SEMS is waiting for RPC connections. Value of this field should have format IP:PORT, for example 127.0.0.1:7080. See :ref:`SEMS jsonrpc.conf ` for defails + IP address and port on which YETI-SEMS is waiting for RPC connections. Value of this field should have format IP:PORT, for example 127.0.0.1:7080. See :ref:`SEMS sems.conf ` for defails   In view mode user can use next tabs: