diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index e964943b5..81eb0a338 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -27,7 +27,8 @@ jobs: - name: Build and push Docker image uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc with: - context: ./docker/ + context: . + file: ./docker/Dockerfile push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/docker-compose.grafana.yml b/docker-compose.grafana.yml new file mode 100644 index 000000000..820b777ff --- /dev/null +++ b/docker-compose.grafana.yml @@ -0,0 +1,58 @@ +version: "3" + +services: + redis: + image: redis:alpine + + rabbit-mq: + image: rabbitmq:alpine + + prometheus: + image: prom/prometheus:latest + restart: unless-stopped + ports: + - '9090:9090' + volumes: + - ./misc/config/prometheus.yml:/etc/prometheus/prometheus.yml + - monitoring_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.console.libraries=/etc/prometheus/console_libraries' + - '--web.console.templates=/etc/prometheus/consoles' + - '--web.enable-lifecycle' + depends_on: + - jasmin + + grafana: + image: grafana/grafana + restart: unless-stopped + ports: + - 3000:3000 + environment: + GF_INSTALL_PLUGINS: "grafana-clock-panel,grafana-simple-json-datasource" + volumes: + - monitoring_data:/var/lib/grafana + depends_on: + - prometheus + + jasmin: + build: + context: ./ + dockerfile: ./docker/Dockerfile.dev + container_name: jasmin + volumes: + - ./jasmin:/usr/jasmin/jasmin + ports: + - 2775:2775 + - 8990:8990 + - 1401:1401 + depends_on: + - redis + - rabbit-mq + environment: + REDIS_CLIENT_HOST: redis + AMQP_BROKER_HOST: rabbit-mq + +volumes: + monitoring_data: { } diff --git a/jasmin/__init__.py b/jasmin/__init__.py index aa50613a4..645eeea9f 100644 --- a/jasmin/__init__.py +++ b/jasmin/__init__.py @@ -5,7 +5,7 @@ MAJOR = 0 MINOR = 10 -PATCH = 11 +PATCH = 12 META = '' diff --git a/jasmin/managers/content.py b/jasmin/managers/content.py index a20488835..ae6083810 100644 --- a/jasmin/managers/content.py +++ b/jasmin/managers/content.py @@ -150,7 +150,7 @@ def __init__(self, uid, body, replyto, submit_sm_bill, priority=1, expiration=No # RabbitMQ does not support priority (yet), anyway, we may use any other amqp broker that supports it if not isinstance(priority, int): raise InvalidParameterError("Invalid priority argument: %s" % priority) - if priority < 0 or priority > 3: + if not isinstance(priority, int) or priority < 0: raise InvalidParameterError("Priority must be set from 0 to 3, it is actually set to %s" % priority) if source_connector not in ['httpapi', 'smppsapi']: diff --git a/jasmin/protocols/http/endpoints/metrics.py b/jasmin/protocols/http/endpoints/metrics.py new file mode 100644 index 000000000..b6ca0402a --- /dev/null +++ b/jasmin/protocols/http/endpoints/metrics.py @@ -0,0 +1,116 @@ +from twisted.web.resource import Resource + +from jasmin.protocols.http.stats import HttpAPIStatsCollector +from jasmin.protocols.smpp.stats import SMPPClientStatsCollector, SMPPServerStatsCollector + +PROM_METRICS_HTTPAPI = { + 'request_count': {'type': b'counter', 'help': b'Http request count.'}, + 'interceptor_count': {'type': b'counter', 'help': b'Successful http request count.'}, + 'auth_error_count': {'type': b'counter', 'help': b'Authentication error count.'}, + 'route_error_count': {'type': b'counter', 'help': b'Routing error count.'}, + 'interceptor_error_count': {'type': b'counter', 'help': b'Interceptor error count.'}, + 'throughput_error_count': {'type': b'counter', 'help': b'Throughput exceeded error count.'}, + 'charging_error_count': {'type': b'counter', 'help': b'Charging error count.'}, + 'server_error_count': {'type': b'counter', 'help': b'Server error count.'}, + 'success_count': {'type': b'counter', 'help': b'Successful http request count.'}, +} +PROM_METRICS_SMPPC = { + 'connected_count': {'type': b'counter', 'help': b'Cumulated number of successful connections.'}, + 'disconnected_count': {'type': b'counter', 'help': b'Cumulated number of disconnections.'}, + 'bound_count': {'type': b'counter', 'help': b'Number of bound sessions.'}, + 'submit_sm_request_count': {'type': b'counter', 'help': b'SubmitSm pdu requests count.'}, + 'submit_sm_count': {'type': b'counter', 'help': b'Complete SubmitSm transactions count.'}, + 'deliver_sm_count': {'type': b'counter', 'help': b'DeliverSm pdu requests count.'}, + 'data_sm_count': {'type': b'counter', 'help': b'Complete DataSm transactions count.'}, + 'interceptor_count': {'type': b'counter', 'help': b'Interceptor calls count.'}, + 'elink_count': {'type': b'counter', 'help': b'EnquireLinks count.'}, + 'throttling_error_count': {'type': b'counter', 'help': b'Throttling errors count.'}, + 'interceptor_error_count': {'type': b'counter', 'help': b'Interception errors count.'}, + 'other_submit_error_count': {'type': b'counter', 'help': b'Other errors count.'}, +} +PROM_METRICS_SMPPS_API = { + 'connected_count': {'type': b'counter', 'help': b'Number of connected sessions.'}, + 'connect_count': {'type': b'counter', 'help': b'Cumulated number of connect requests.'}, + 'disconnect_count': {'type': b'counter', 'help': b'Cumulated number of disconnect requests.'}, + 'interceptor_count': {'type': b'counter', 'help': b'Interceptor calls count.'}, + 'bound_trx_count': {'type': b'counter', 'help': b'Number of bound sessions in transceiver mode.'}, + 'bound_rx_count': {'type': b'counter', 'help': b'Number of bound sessions in receiver mode.'}, + 'bound_tx_count': {'type': b'counter', 'help': b'Number of bound sessions in transmitter mode.'}, + 'bind_trx_count': {'type': b'counter', 'help': b'Number of bind requests in transceiver mode.'}, + 'bind_rx_count': {'type': b'counter', 'help': b'Number of bind requests in receiver mode.'}, + 'bind_tx_count': {'type': b'counter', 'help': b'Number of bind requests in transmitter mode.'}, + 'unbind_count': {'type': b'counter', 'help': b'Cumulated number of unbind requests.'}, + 'submit_sm_request_count': {'type': b'counter', 'help': b'SubmitSm pdu requests count.'}, + 'submit_sm_count': {'type': b'counter', 'help': b'Complete SubmitSm transactions count.'}, + 'deliver_sm_count': {'type': b'counter', 'help': b'DeliverSm pdu requests count.'}, + 'data_sm_count': {'type': b'counter', 'help': b'Complete DataSm transactions count.'}, + 'elink_count': {'type': b'counter', 'help': b'EnquireLinks count.'}, + 'throttling_error_count': {'type': b'counter', 'help': b'Throttling errors count.'}, + 'interceptor_error_count': {'type': b'counter', 'help': b'Interception errors count.'}, + 'other_submit_error_count': {'type': b'counter', 'help': b'Other errors count.'}, +} + + +class Metrics(Resource): + isleaf = True + + def __init__(self, SMPPClientManagerPB, log): + Resource.__init__(self) + + self.SMPPClientManagerPB = SMPPClientManagerPB + self.log = log + + def render_GET(self, request): + """ + /metrics request processing, used for exporting prometheus metrics + """ + + self.log.debug("Rendering /metrics response with args: %s from %s", + request.args, request.getClientIP()) + + request.responseHeaders.addRawHeader(b"content-type", b"text/plain") + request.setResponseCode(200) + + # Init response payload + response = [] + + # Fill httpapi stats + _s = HttpAPIStatsCollector().get() + for metric, descriptor in PROM_METRICS_HTTPAPI.items(): + response.extend([ + b'# TYPE httpapi_%s %s' % (metric.encode(), descriptor['type']), + b'# HELP httpapi_%s %s' % (metric.encode(), descriptor['help']), + ('httpapi_%s %s' % (metric, _s.get(metric))).encode(), + ]) + + # Fill smppcs stats + _connectors = self.SMPPClientManagerPB.perspective_connector_list() + _stats = {} + for metric, descriptor in PROM_METRICS_SMPPC.items(): + if len(_connectors) > 0: + response.extend([ + b'# TYPE smppc_%s %s' % (metric.encode(), descriptor['type']), + b'# HELP smppc_%s %s' % (metric.encode(), descriptor['help']), + ]) + + for _connector in _connectors: + _cid = _connector['id'] + _s = _stats.get(_cid, SMPPClientStatsCollector().get(_cid)) + + response.extend([ + ('smppc_%s{cid="%s"} %s' % (metric, _cid, _s.get(metric))).encode(), + ]) + + # Fill smpps stats + _s = SMPPServerStatsCollector().get('smpps_01').getStats() + for metric, descriptor in PROM_METRICS_SMPPS_API.items(): + response.extend([ + b'# TYPE smppsapi_%s %s' % (metric.encode(), descriptor['type']), + b'# HELP smppsapi_%s %s' % (metric.encode(), descriptor['help']), + ('smppsapi_%s %s' % (metric, _s.get(metric))).encode(), + ]) + + # Add padding + response.extend([b'', b'']) + + return b'\n'.join(response) diff --git a/jasmin/protocols/http/server.py b/jasmin/protocols/http/server.py index 42df7da33..cc254173d 100644 --- a/jasmin/protocols/http/server.py +++ b/jasmin/protocols/http/server.py @@ -10,6 +10,7 @@ from jasmin.protocols.http.endpoints.rate import Rate from jasmin.protocols.http.endpoints.ping import Ping from jasmin.protocols.http.endpoints.balance import Balance +from jasmin.protocols.http.endpoints.metrics import Metrics from jasmin.protocols.http.stats import HttpAPIStatsCollector LOG_CATEGORY = "jasmin-http-api" @@ -47,6 +48,8 @@ def __init__(self, RouterPB, SMPPClientManagerPB, config, interceptor=None): self.putChild(b'balance', Balance(RouterPB, stats, log)) log.debug("Setting http url routing for /ping") self.putChild(b'ping', Ping(log)) + log.debug("Setting http url routing for /metrics") + self.putChild(b'metrics', Metrics(SMPPClientManagerPB, log)) def getChild(self, name, request): self.log.debug("Getting child with name %s", name) diff --git a/kubernetes/README.rst b/kubernetes/README.rst new file mode 100644 index 000000000..848c6b306 --- /dev/null +++ b/kubernetes/README.rst @@ -0,0 +1,4 @@ +Kubernetes clustering for Jasmin +################################ + +Go to Jasmin docs to get `detailed Kubernetes how-to `_. diff --git a/kubernetes/simple-pods/jasmin.yml b/kubernetes/simple-pods/jasmin.yml new file mode 100644 index 000000000..44e52a39a --- /dev/null +++ b/kubernetes/simple-pods/jasmin.yml @@ -0,0 +1,76 @@ +apiVersion: v1 +kind: Pod +metadata: + name: jasmin + labels: + app: jasmin +spec: + hostname: jasmin + subdomain: app + containers: + - name: jasmin + image: jookies/jasmin:latest + ports: + - containerPort: 2775 + name: smpp-port + protocol: TCP + - containerPort: 1401 + name: http-port + protocol: TCP + - containerPort: 8990 + name: cli-port + protocol: TCP + lifecycle: + postStart: + exec: + command: [ "sh", "-c", "cp /tmp/jasminconfig/* /etc/jasmin/" ] + volumeMounts: + - name: jasminconfig + mountPath: /tmp/jasminconfig + volumes: + - name: jasminconfig + configMap: + name: etcjasmin +--- +apiVersion: v1 +kind: Service +metadata: + name: app +spec: + selector: + name: jasmin + clusterIP: None +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: etcjasmin +data: + jasmin.cfg: | + # This is a simplified config version taken from the /etc/jasmin/jasmin.cfg file + # Some parameters are slightly fine tuned for better performance, amqp and redis + # parameters are updated accordingly to kubernetes requirements. + + [sm-listener] + publish_submit_sm_resp = False + submit_max_age_smppc_not_ready = 300 + + [dlr] + dlr_lookup_retry_delay = 180 + + [amqp-broker] + host = rabbit.mq.farirat.svc.cluster.local + + [deliversm-thrower] + http_timeout = 10 + retry_delay = 90 + max_retries = 2 + + [dlr-thrower] + http_timeout = 10 + retry_delay = 90 + max_retries = 2 + + [redis-client] + host = redis.store.farirat.svc.cluster.local + poolsize = 30 diff --git a/kubernetes/simple-pods/observability.yml b/kubernetes/simple-pods/observability.yml new file mode 100644 index 000000000..5b86b5864 --- /dev/null +++ b/kubernetes/simple-pods/observability.yml @@ -0,0 +1,127 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: grafana-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + labels: + app: grafana +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + securityContext: + fsGroup: 472 + runAsUser: 0 + supplementalGroups: + - 0 + containers: + - name: grafana + image: grafana/grafana:latest + ports: + - containerPort: 3000 + name: http-grafana + protocol: TCP + volumeMounts: + - mountPath: /var/lib/grafana + name: grafana-data + volumes: + - name: grafana-data + persistentVolumeClaim: + claimName: grafana-pvc +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + labels: + app: prometheus +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + containers: + - name: prometheus + image: prom/prometheus:latest + args: + - --config.file=/etc/prometheus/prometheus.yml + ports: + - containerPort: 9090 + name: prometheus-port + protocol: TCP + volumeMounts: + - name: etcprom + mountPath: /etc/prometheus + volumes: + - name: etcprom + configMap: + name: promconf +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: promconf +data: + prometheus.yml: | + global: + scrape_interval: 30s + scrape_timeout: 10s + + scrape_configs: + - job_name: jasmin + static_configs: + - targets: + - 'jasmin.app.farirat.svc.cluster.local:1401' + - job_name: rabbitmq + static_configs: + - targets: + - 'rabbit.mq.farirat.svc.cluster.local:15692' +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus +spec: + ports: + - port: 9090 + protocol: TCP + targetPort: prometheus-port + selector: + app: prometheus + sessionAffinity: None + type: LoadBalancer +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana +spec: + ports: + - port: 3000 + protocol: TCP + targetPort: http-grafana + selector: + app: grafana + sessionAffinity: None + type: LoadBalancer diff --git a/kubernetes/simple-pods/rabbitmq.yml b/kubernetes/simple-pods/rabbitmq.yml new file mode 100644 index 000000000..9fba6949e --- /dev/null +++ b/kubernetes/simple-pods/rabbitmq.yml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Pod +metadata: + name: rabbit + labels: + name: rabbit +spec: + hostname: rabbit + subdomain: mq + containers: + - name: rabbit + image: rabbitmq:3.10-management-alpine +--- +apiVersion: v1 +kind: Service +metadata: + name: mq +spec: + selector: + name: rabbit + clusterIP: None + diff --git a/kubernetes/simple-pods/redis.yml b/kubernetes/simple-pods/redis.yml new file mode 100644 index 000000000..1f6a7d301 --- /dev/null +++ b/kubernetes/simple-pods/redis.yml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Pod +metadata: + name: redis + labels: + name: redis +spec: + hostname: redis + subdomain: store + containers: + - name: redis + image: redis:6-alpine + command: + - redis-server + - "/etc/redis/redis.conf" + env: + - name: MASTER + value: "true" + volumeMounts: + - mountPath: /etc/redis/ + name: redisconfig + volumes: + - name: redisconfig + configMap: + name: etcredis +--- +apiVersion: v1 +kind: Service +metadata: + name: store +spec: + selector: + name: redis + clusterIP: None +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: etcredis +data: + redis.conf: "" diff --git a/kubernetes/simple-pods/smppsimulator.yml b/kubernetes/simple-pods/smppsimulator.yml new file mode 100644 index 000000000..7ea83fc07 --- /dev/null +++ b/kubernetes/simple-pods/smppsimulator.yml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Pod +metadata: + name: smppsim + labels: + name: smppsim +spec: + hostname: smppsim + subdomain: test + containers: + - name: smppsim + image: jookies/smppsim:latest +--- +apiVersion: v1 +kind: Service +metadata: + name: test +spec: + selector: + name: smppsim + clusterIP: None diff --git a/misc/config/prometheus.yml b/misc/config/prometheus.yml new file mode 100644 index 000000000..c296f4a4f --- /dev/null +++ b/misc/config/prometheus.yml @@ -0,0 +1,16 @@ +# Simple configuration file for prometheus service +# This is used in the /docker-compose.yml file + +global: + scrape_interval: 30s + scrape_timeout: 10s + +scrape_configs: + - job_name: jasmin + static_configs: + - targets: + - 'jasmin:1401' + - job_name: rabbitmq + static_configs: + - targets: + - 'rabbit-mq:15692' diff --git a/misc/doc/sources/apis/ja-http/example_balance.py b/misc/doc/sources/apis/http/example_balance.py similarity index 100% rename from misc/doc/sources/apis/ja-http/example_balance.py rename to misc/doc/sources/apis/http/example_balance.py diff --git a/misc/doc/sources/apis/ja-http/example_rate.py b/misc/doc/sources/apis/http/example_rate.py similarity index 100% rename from misc/doc/sources/apis/ja-http/example_rate.py rename to misc/doc/sources/apis/http/example_rate.py diff --git a/misc/doc/sources/apis/ja-http/example_send_dlr2.py b/misc/doc/sources/apis/http/example_send_dlr2.py similarity index 100% rename from misc/doc/sources/apis/ja-http/example_send_dlr2.py rename to misc/doc/sources/apis/http/example_send_dlr2.py diff --git a/misc/doc/sources/apis/ja-http/example_send_gsm0338.php b/misc/doc/sources/apis/http/example_send_gsm0338.php similarity index 100% rename from misc/doc/sources/apis/ja-http/example_send_gsm0338.php rename to misc/doc/sources/apis/http/example_send_gsm0338.php diff --git a/misc/doc/sources/apis/ja-http/example_send_gsm0338.py b/misc/doc/sources/apis/http/example_send_gsm0338.py similarity index 100% rename from misc/doc/sources/apis/ja-http/example_send_gsm0338.py rename to misc/doc/sources/apis/http/example_send_gsm0338.py diff --git a/misc/doc/sources/apis/ja-http/example_send_gsm0338.rb b/misc/doc/sources/apis/http/example_send_gsm0338.rb similarity index 100% rename from misc/doc/sources/apis/ja-http/example_send_gsm0338.rb rename to misc/doc/sources/apis/http/example_send_gsm0338.rb diff --git a/misc/doc/sources/apis/ja-http/example_send_misc.py b/misc/doc/sources/apis/http/example_send_misc.py similarity index 100% rename from misc/doc/sources/apis/ja-http/example_send_misc.py rename to misc/doc/sources/apis/http/example_send_misc.py diff --git a/misc/doc/sources/apis/ja-http/index.rst b/misc/doc/sources/apis/http/index.rst similarity index 76% rename from misc/doc/sources/apis/ja-http/index.rst rename to misc/doc/sources/apis/http/index.rst index 7c75a82de..372286e2e 100644 --- a/misc/doc/sources/apis/ja-http/index.rst +++ b/misc/doc/sources/apis/http/index.rst @@ -19,11 +19,12 @@ SMS Messages can be transmitted using HTTP protocol, the following requirements Features ******** -The ja-http API allows you to: +The Http API allows you to: * Send and receive SMS through Jasmin's connectors, * Receive http callbacks for delivery notification (*receipts*) when SMS-MT is received (or not) on mobile station, * Send and receive long (more than 160 characters) SMS, unicode/binary content and receive http callbacks when a mobile station send you a SMS-MO. +* Get monitoring metrics * Check your balance status, * Check a message rate price before sending it. @@ -47,7 +48,7 @@ HTTP request parameters ======================= When calling Jasmin's URL from an application, the below parameters must be passed (at least mandatory ones), the api will return a message id on success, see :ref:`http_response`. -.. list-table:: ja-http sending SMS parameters +.. list-table:: Http sending SMS parameters :header-rows: 1 * - Parameter @@ -87,9 +88,9 @@ When calling Jasmin's URL from an application, the below parameters must be pass - Default is 0 (lowest priority) * - **sdt** - String - - 000000000100000R (send in 1 minute) + - 000000000100000R (send in 1 minute) - Optional - - Specifies the scheduled delivery time at which the message delivery should be first attempted, default is value is None (message will take SMSC's default). Supports Absolute and Relative Times per SMPP v3.4 Issue 1.2 + - Specifies the scheduled delivery time at which the message delivery should be first attempted, default is value is None (message will take SMSC's default). Supports Absolute and Relative Times per SMPP v3.4 Issue 1.2 * - **validity-period** - Integer - 1440 @@ -148,7 +149,7 @@ Otherwise, an error is returned: Error "No route found" -.. list-table:: HTTP response code details +.. list-table:: Http response code details :widths: 10 40 50 :header-rows: 1 @@ -225,7 +226,7 @@ In Ruby: jasmin.cfg / http-api ===================== -The **jasmin.cfg** file *(INI format, located in /etc/jasmin)* contain a section called **http-api** where all ja-http API related config elements are: +The **jasmin.cfg** file *(INI format, located in /etc/jasmin)* contain a section called **http-api** where all Http API related config elements are: .. code-block:: ini :linenos: @@ -294,7 +295,7 @@ HTTP Parameters for a level 1 DLR ================================= The following parameters are sent to the receiving end point (at dlr-url) when the DLR's dlr-level is set to 1 (SMS-C level only) -.. list-table:: ja-http parameters for a level 1 DLR +.. list-table:: Http parameters for a level 1 DLR :header-rows: 1 * - Parameter @@ -328,7 +329,7 @@ HTTP Parameters for a level 2 or 3 DLR ====================================== The following parameters are sent to the receiving end point (at dlr-url) when DLR's dlr-level is set to 2 or 3 (Terminal level or all levels) -.. list-table:: ja-http parameters for a level 2 or 3 DLR +.. list-table:: Http parameters for a level 2 or 3 DLR :header-rows: 1 * - Parameter @@ -398,7 +399,7 @@ Processing ========== The flowchart below describes how dlr delivery and retrying policy is done inside DLRThrower service: -.. figure:: /resources/ja-http/dlr-flowchart.png +.. figure:: /resources/http/dlr-flowchart.png :alt: DLR delivery flowchart as processed by DLRThrower service :align: Center @@ -470,7 +471,7 @@ HTTP Parameters =============== When receiving an URL call from Jasmin's *deliverSmHttpThrower service*, the below parameters are delivered (at least *Always* present ones). -.. list-table:: ja-http receiving SMS parameters +.. list-table:: Http receiving SMS parameters :header-rows: 1 * - Parameter @@ -533,7 +534,7 @@ Processing ========== The flowchart below describes how message delivery and retrying policy are done inside *deliverSmHttpThrower* service: -.. figure:: /resources/ja-http/sms-mo-flowchart.png +.. figure:: /resources/http/sms-mo-flowchart.png :alt: MO delivery flowchart as processed by deliverSmHttpThrower service :align: Center @@ -576,6 +577,149 @@ The **jasmin.cfg** file *(INI format, located in /etc/jasmin)* contain a section - - Python's logging module configuration. +.. _get_metrics: + +Monitoring metrics +****************** + +Jasmin provides a native exporter for `Prometheus `_ with extensive metrics obtained directly from the statistics collector. + +In order to get Jasmin's metrics, user may request a **HTTP GET** from the following URL: + +http://127.0.0.1:1401/metrics + +.. note:: Host ``127.0.0.1`` and port ``1401`` are default values and configurable in ``/etc/jasmin/jasmin.cfg``, see :ref:`configuration_http-api`. + +HTTP response +============= + +Self documented response: + +.. code-block:: text + + # TYPE httpapi_request_count counter + # HELP httpapi_request_count Http request count. + httpapi_request_count 0 + # TYPE httpapi_interceptor_count counter + # HELP httpapi_interceptor_count Successful http request count. + httpapi_interceptor_count 0 + # TYPE httpapi_auth_error_count counter + # HELP httpapi_auth_error_count Authentication error count. + httpapi_auth_error_count 0 + # TYPE httpapi_route_error_count counter + # HELP httpapi_route_error_count Routing error count. + httpapi_route_error_count 0 + # TYPE httpapi_interceptor_error_count counter + # HELP httpapi_interceptor_error_count Interceptor error count. + httpapi_interceptor_error_count 0 + # TYPE httpapi_throughput_error_count counter + # HELP httpapi_throughput_error_count Throughput exceeded error count. + httpapi_throughput_error_count 0 + # TYPE httpapi_charging_error_count counter + # HELP httpapi_charging_error_count Charging error count. + httpapi_charging_error_count 0 + # TYPE httpapi_server_error_count counter + # HELP httpapi_server_error_count Server error count. + httpapi_server_error_count 0 + # TYPE httpapi_success_count counter + # HELP httpapi_success_count Successful http request count. + httpapi_success_count 0 + # TYPE smppc_connected_count counter + # HELP smppc_connected_count Cumulated number of successful connections. + smppc_connected_count{cid=smppprovider} 0 + # TYPE smppc_disconnected_count counter + # HELP smppc_disconnected_count Cumulated number of disconnections. + smppc_disconnected_count{cid=smppprovider} 0 + # TYPE smppc_bound_count counter + # HELP smppc_bound_count Number of bound sessions. + smppc_bound_count{cid=smppprovider} 0 + # TYPE smppc_submit_sm_request_count counter + # HELP smppc_submit_sm_request_count SubmitSm pdu requests count. + smppc_submit_sm_request_count{cid=smppprovider} 0 + # TYPE smppc_submit_sm_count counter + # HELP smppc_submit_sm_count Complete SubmitSm transactions count. + smppc_submit_sm_count{cid=smppprovider} 0 + # TYPE smppc_deliver_sm_count counter + # HELP smppc_deliver_sm_count DeliverSm pdu requests count. + smppc_deliver_sm_count{cid=smppprovider} 0 + # TYPE smppc_data_sm_count counter + # HELP smppc_data_sm_count Complete DataSm transactions count. + smppc_data_sm_count{cid=smppprovider} 0 + # TYPE smppc_interceptor_count counter + # HELP smppc_interceptor_count Interceptor calls count. + smppc_interceptor_count{cid=smppprovider} 0 + # TYPE smppc_elink_count counter + # HELP smppc_elink_count EnquireLinks count. + smppc_elink_count{cid=smppprovider} 0 + # TYPE smppc_throttling_error_count counter + # HELP smppc_throttling_error_count Throttling errors count. + smppc_throttling_error_count{cid=smppprovider} 0 + # TYPE smppc_interceptor_error_count counter + # HELP smppc_interceptor_error_count Interception errors count. + smppc_interceptor_error_count{cid=smppprovider} 0 + # TYPE smppc_other_submit_error_count counter + # HELP smppc_other_submit_error_count Other errors count. + smppc_other_submit_error_count{cid=smppprovider} 0 + # TYPE smppsapi_connected_count counter + # HELP smppsapi_connected_count Number of connected sessions. + smppsapi_connected_count 0 + # TYPE smppsapi_connect_count counter + # HELP smppsapi_connect_count Cumulated number of connect requests. + smppsapi_connect_count 0 + # TYPE smppsapi_disconnect_count counter + # HELP smppsapi_disconnect_count Cumulated number of disconnect requests. + smppsapi_disconnect_count 0 + # TYPE smppsapi_interceptor_count counter + # HELP smppsapi_interceptor_count Interceptor calls count. + smppsapi_interceptor_count 0 + # TYPE smppsapi_bound_trx_count counter + # HELP smppsapi_bound_trx_count Number of bound sessions in transceiver mode. + smppsapi_bound_trx_count 0 + # TYPE smppsapi_bound_rx_count counter + # HELP smppsapi_bound_rx_count Number of bound sessions in receiver mode. + smppsapi_bound_rx_count 0 + # TYPE smppsapi_bound_tx_count counter + # HELP smppsapi_bound_tx_count Number of bound sessions in transmitter mode. + smppsapi_bound_tx_count 0 + # TYPE smppsapi_bind_trx_count counter + # HELP smppsapi_bind_trx_count Number of bind requests in transceiver mode. + smppsapi_bind_trx_count 0 + # TYPE smppsapi_bind_rx_count counter + # HELP smppsapi_bind_rx_count Number of bind requests in receiver mode. + smppsapi_bind_rx_count 0 + # TYPE smppsapi_bind_tx_count counter + # HELP smppsapi_bind_tx_count Number of bind requests in transmitter mode. + smppsapi_bind_tx_count 0 + # TYPE smppsapi_unbind_count counter + # HELP smppsapi_unbind_count Cumulated number of unbind requests. + smppsapi_unbind_count 0 + # TYPE smppsapi_submit_sm_request_count counter + # HELP smppsapi_submit_sm_request_count SubmitSm pdu requests count. + smppsapi_submit_sm_request_count 0 + # TYPE smppsapi_submit_sm_count counter + # HELP smppsapi_submit_sm_count Complete SubmitSm transactions count. + smppsapi_submit_sm_count 0 + # TYPE smppsapi_deliver_sm_count counter + # HELP smppsapi_deliver_sm_count DeliverSm pdu requests count. + smppsapi_deliver_sm_count 0 + # TYPE smppsapi_data_sm_count counter + # HELP smppsapi_data_sm_count Complete DataSm transactions count. + smppsapi_data_sm_count 0 + # TYPE smppsapi_elink_count counter + # HELP smppsapi_elink_count EnquireLinks count. + smppsapi_elink_count 0 + # TYPE smppsapi_throttling_error_count counter + # HELP smppsapi_throttling_error_count Throttling errors count. + smppsapi_throttling_error_count 0 + # TYPE smppsapi_interceptor_error_count counter + # HELP smppsapi_interceptor_error_count Interception errors count. + smppsapi_interceptor_error_count 0 + # TYPE smppsapi_other_submit_error_count counter + # HELP smppsapi_other_submit_error_count Other errors count. + smppsapi_other_submit_error_count 0 + +.. note:: The statistics exposed through this api are also exposed through jcli's :ref:`stats_manager` module. + .. _check_balance: Checking account balance @@ -592,7 +736,7 @@ http://127.0.0.1:1401/balance HTTP request parameters ======================= -.. list-table:: ja-http balance request parameters +.. list-table:: Http balance request parameters :header-rows: 1 * - Parameter @@ -652,7 +796,7 @@ http://127.0.0.1:1401/rate HTTP request parameters ======================= -.. list-table:: ja-http rate request parameters +.. list-table:: Http rate request parameters :header-rows: 1 * - Parameter diff --git a/misc/doc/sources/apis/smpp-server/index.rst b/misc/doc/sources/apis/smpp-server/index.rst index 2393f0e32..6683be130 100644 --- a/misc/doc/sources/apis/smpp-server/index.rst +++ b/misc/doc/sources/apis/smpp-server/index.rst @@ -2,7 +2,7 @@ SMPP Server API ############### -This document is targeted at software designers/programmers wishing to integrate SMS messaging through a stateful tcp protocol **SMPP v3.4**, if you feel this does not fit your needs and that you are more "web-service-guy" then you still can try :doc:`/apis/ja-http/index`. +This document is targeted at software designers/programmers wishing to integrate SMS messaging through a stateful tcp protocol **SMPP v3.4**, if you feel this does not fit your needs and that you are more "web-service-guy" then you still can try :doc:`/apis/http/index`. SMS Messages can be transmitted using SMPP protocol, the following requirements must be met to enable the service : @@ -27,18 +27,18 @@ The **jasmin.cfg** file *(INI format, located in /etc/jasmin)* contain a section .. code-block:: ini :linenos: - + [smpp-server] id = "smpps_01" bind = 0.0.0.0 port = 2775 - + sessionInitTimerSecs = 30 enquireLinkTimerSecs = 30 inactivityTimerSecs = 300 responseTimerSecs = 60 pduReadTimerSecs = 30 - + log_level = INFO log_file = /var/log/jasmin/default-smpps_01.log log_format = %(asctime)s %(levelname)-8s %(process)d %(message)s @@ -76,7 +76,7 @@ The **jasmin.cfg** file *(INI format, located in /etc/jasmin)* contain a section - 30 - Protocol tuning parameter: binary pdu ready timeout. * - log_* - - + - - Python's logging module configuration. .. _smpps_binding: @@ -121,4 +121,4 @@ Jamsin's SMPP Server is supporting the following PDUs: * enquire_link .. rubric:: Footnotes -.. [1] :doc:`/billing/index` \ No newline at end of file +.. [1] :doc:`/billing/index` diff --git a/misc/doc/sources/architecture/index.rst b/misc/doc/sources/architecture/index.rst index 07ca4e771..c5b497811 100644 --- a/misc/doc/sources/architecture/index.rst +++ b/misc/doc/sources/architecture/index.rst @@ -7,24 +7,24 @@ Architecture overview .. figure:: /resources/architecture/hld.png :alt: HLD Architecture :align: Center - + Jasmin SMS Gateway high level design #. **jCli**: Telnet management console, refer to :doc:`/management/jcli/index` for more details, -#. **SMPP Client Manager PB**: A `PerspectBroker `_ +#. **SMPP Client Manager PB**: A `PerspectBroker `_ providing facilities to manage (add, remove, list, start, stop ...) SMPP client connectors, -#. **Router**: A `PerspectBroker `_ +#. **Router**: A `PerspectBroker `_ providing facilities to manage message routes, groups, users, http connectors and filters, #. **DLR Thrower**: A service for delivering acknowledgement receipts back to third party applications - through HTTP, refer to :doc:`/apis/ja-http/index` for more details, + through HTTP, refer to :doc:`/apis/http/index` for more details, #. **DeliverSM Thrower**: A service for delivering MO SMS (Mobile originated) to third party applications - through HTTP, refer to :doc:`/apis/ja-http/index` for more details, + through HTTP, refer to :doc:`/apis/http/index` for more details, #. **Restful API**: A Restful API to be used by third party application to send MT SMS (Mobile Terminated) and launch batches, refer to :doc:`/apis/rest/index` for more details. #. **HTTP API**: A HTTP Server to be used by third party application to send MT SMS (Mobile Terminated), - refer to :doc:`/apis/ja-http/index` for more details. + refer to :doc:`/apis/http/index` for more details. #. **SMPP Server API**: A SMPP Server to be used by third party application to send and receive SMS through a stateful tcp protocol, refer to :doc:`/apis/smpp-server/index` for more details. -Jasmin core and its external connectors (used for AMQP, Redis, SMPP, HTTP, Telnet ...) are written in Python -and are mainly based on `Twisted matrix `_, a event-driven networking engine. \ No newline at end of file +Jasmin core and its external connectors (used for AMQP, Redis, SMPP, HTTP, Telnet ...) are written in Python +and are mainly based on `Twisted matrix `_, a event-driven networking engine. diff --git a/misc/doc/sources/conf.py b/misc/doc/sources/conf.py index 158e76e27..37956f35c 100644 --- a/misc/doc/sources/conf.py +++ b/misc/doc/sources/conf.py @@ -38,7 +38,7 @@ # The short X.Y version. version = "0.10" # The full version, including alpha/beta/rc tags. -release = "0.10.11s" +release = "0.10.12" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/misc/doc/sources/index.rst b/misc/doc/sources/index.rst index 7e02c671f..740b910f1 100644 --- a/misc/doc/sources/index.rst +++ b/misc/doc/sources/index.rst @@ -10,12 +10,14 @@ Jasmin is written in Python and Twisted framework for serving highly scalable ap Features ******** + * SMPP Client / Server * HTTP Client / Server * Based on AMQP broker for store&forward mechanisms * Advanced message routing : Simple & static, *Roundrobin*, *Failover*, *Leastcost* .. * Standard message filtering: *TransparentFilter*, *ConnectorFilter*, *UserFilter* .. * Advanced message filtering: *EvalPyFilter* +* Advanced messaging/routing mechanisms enabled by message *interceptor* * Flexible billing support * Supports Unicode (UTF-8 / 16) for sending out multilingual SMS * Supports easy creation and sending of specialized/binary SMS like mono Ringtones, WAP Push, Vcards @@ -29,6 +31,8 @@ Getting started :columns: 2 * :doc:`/installation/index` -- Install and run Jasmin SMS Gateway + * :ref:`monitoring_grafana` -- Install Grafana for monitoring + * :ref:`install_k8s` -- Kubernetes cluster *how-to* * :ref:`Examples_Receiving_SMS` -- Basic push/pull SMS application via HTTP * :doc:`/apis/rest/index` -- RESTful API technical specification * :doc:`/apis/smpp-server/index` -- SMPP Server API technical specification @@ -44,7 +48,7 @@ Full contents /support/index /installation/index /apis/rest/index - /apis/ja-http/index + /apis/http/index /apis/smpp-server/index /routing/index /interception/index diff --git a/misc/doc/sources/installation/docker-compose.yml b/misc/doc/sources/installation/docker-compose.yml index 4dd8120b9..f41f72285 100644 --- a/misc/doc/sources/installation/docker-compose.yml +++ b/misc/doc/sources/installation/docker-compose.yml @@ -10,7 +10,7 @@ services: restart: unless-stopped jasmin: - image: jookies/jasmin:0.10 + image: jookies/jasmin:latest restart: unless-stopped container_name: jasmin volumes: diff --git a/misc/doc/sources/installation/index.rst b/misc/doc/sources/installation/index.rst index dc6159d23..b64008999 100644 --- a/misc/doc/sources/installation/index.rst +++ b/misc/doc/sources/installation/index.rst @@ -2,7 +2,7 @@ Installation ############ -The Installation section is intended to get you up and running quickly with a simple SMS sending scenario through :doc:`/apis/ja-http/index` or :doc:`/apis/smpp-server/index`. +The Installation section is intended to get you up and running quickly with a simple SMS sending scenario through :doc:`/apis/http/index` or :doc:`/apis/smpp-server/index`. Jasmin installation is provided as rpm & deb Linux packages, docker image and pypi package. @@ -150,6 +150,142 @@ Jasmin is now up and running:: .. note:: You can play around with the docker-compose.yml to choose different versions, mounting the configs outside the container, etc ... +.. _monitoring_grafana: + +Monitoring using Grafana +************************ + +Through its native exporter for `Prometheus `_ you can collect and analyze detailed metrics within a production environment, we will be using the /metrics API (:ref:`get_metrics`) with `Prometheus `_ and `Grafana `_ in this guide. + +Spin the `docker-compose including prometheus and grafana `_ file:: + + docker-compose -f docker-compose.grafana.yml up -d + +You should have the following containers up and running:: + + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + cd7597137e9a grafana/grafana "/run.sh" 2 days ago Up About a minute 0.0.0.0:3000->3000/tcp jasmin-grafana-1 + bd3be30a5cd5 prom/prometheus:latest "/bin/prometheus --c…" 2 days ago Up About a minute 9090/tcp jasmin-prometheus-1 + 8209435c2f8d jasmin-jasmin "/docker-entrypoint.…" 2 days ago Up About a minute 0.0.0.0:1401->1401/tcp, 0.0.0.0:2775->2775/tcp, 0.0.0.0:8990->8990/tcp jasmin + 6c88fa5e47db rabbitmq:alpine "docker-entrypoint.s…" 2 days ago Up About a minute 4369/tcp, 5671-5672/tcp, 15691-15692/tcp, 25672/tcp jasmin-rabbit-mq-1 + a649abd164c8 redis:alpine "docker-entrypoint.s…" 2 days ago Up About a minute 6379/tcp jasmin-redis-1 + +Now open Grafana using default username (admin) and password (admin):: + + http://127.0.0.1:3000 + +First you'll need to add *Prometheus metrics* as a **Data Source**, go to **Configuration > Data sources** and click on **Add data source**: + +* Name: *Prometheus* +* URL: *http://prometheus:9090* + +Keep defaults the **Save & test**. + +Now you can start playing around with the collected metrics, go to **Explore** and play with the autocomplete feature in **Metrics browser** by typing **httapi**, **smpps** or **smppc**. + +You can also *explore* metrics of a defined SMPP client connector by setting the **cid** tag, example of getting number of bound session of a specific connector:: + + smppc_bound_count{cid="foo"} + +.. note:: The complete set of metrics exposed by Jasmin can be checked through the **/metrics** http api, these metrics are also exposed through jcli's :ref:`stats_manager` module. + +.. _install_k8s: + +Kubernetes cluster +****************** + +**@TODO: add link to documented stresstests** + +This part of the documentation covers clustering Jasmin SMS Gateway using `Kubernetes `_, it is also made as a reference setup for anyone looking to deploy Jasmin in complex/cloud architectures, this is a proof-of-concept model for deploying simple and advanced clusters, these were used for making stress tests and performance metering of the sms gateway, `documented here `_. + +Before you begin you need to have a Kubernetes cluster, and the **kubectl** command-line tool must be configured to communicate with your cluster. It is recommended to run this tutorial on a cluster with at least two nodes that are not acting as control plane hosts. If you do not already have a cluster, you can create one by using minikube or you can use one of these Kubernetes playgrounds: + +* `Okteto `_ +* `Killercoda `_ +* `Play with Kubernetes `_ + +Your Kubernetes server must be at or later than version v1.10. To check the version, enter *kubectl version*. + +Simple k8s architecture +======================= + +This is barely simple architecture with running pods and a SMPP simulator to allow simple functional or performance testing. + +.. note:: This section of the guide uses the provided Kubernetes objects located in this `directory `_. + +Start by adjusting the namespace in **configmaps.yml**: replace the rabbitmq and redis hosts to hostnames provided by your own Kubernetes cluster then deploy: + +1. kubectl apply -f redis.yml +2. kubectl apply -f rabbitmq.yml +3. kubectl apply -f jasmin.yml + +You should have the cluster up and running within seconds, your Jasmin pod must log to stdout the following messages: + +.. code-block:: bash + + INFO 1 Starting Jasmin Daemon ... + INFO 1 Interceptor client Started. + INFO 1 RedisClient Started. + INFO 1 AMQP Broker Started. + INFO 1 RouterPB Started. + INFO 1 SMPPClientManagerPB Started. + INFO 1 DLRLookup Started. + INFO 1 SMPPServer Started. + INFO 1 deliverSmThrower Started. + INFO 1 DLRThrower Started. + INFO 1 HTTPApi Started. + INFO 1 jCli Started. + +.. warning:: + + If you don't have the indicated above logged lines to Jasmin's pod stdout then you are having troubles somewhere, do not step forward before solving them. + +Now you can connect jcli by *first* running a port-forward and then connecting to the forwarded port: + +.. code-block:: bash + + kubectl port-forward jasmin 8990:8990 + +Then: + +.. code-block:: bash + + telnet 127.0.0.1 8990 + +.. note:: + + The **kubectl port-forward** command will not return unless you *ctrl-c* to stop the port-forward, the second command (telnet) needs to be run in another terminal session. + +You can now make the same steps to port-forward the smpp (2775) port or the http (1401) port and start using Jasmin. + +If you need to connect Jasmin to a *provided smpp simulator* then first deploy the simulator:: + + kubectl apply -f smppsimulator.yml + +And then add a new SMPP client connector by following these steps: + +.. code-block:: bash + + smppccm -a + > cid smpp_simulator + > host smppsim.test.farirat.svc.cluster.local + > username smppclient1 + > password password + > ok + smppccm -1 smpp_simulator + +You will also need to create a group, user and at least a mt route to make your first sms delivery test, `this guide is your friend ! `_ + +.. note:: + + You may adjust the **host** value in the example above to your own host (provided by your Kubernetes cluster). + +Advanced deployment architecture +================================ + +*[work in progress]* + + Sending your first SMS ********************** @@ -260,7 +396,7 @@ And then create the new user:: 5. Send SMS =========== -Sending outbound SMS (MT) is simply done through Jasmin's HTTP API (refer to :doc:`/apis/ja-http/index` for detailed information about sending and receiving SMS and receipts):: +Sending outbound SMS (MT) is simply done through Jasmin's HTTP API (refer to :doc:`/apis/http/index` for detailed information about sending and receiving SMS and receipts):: http://127.0.0.1:1401/send?username=foo&password=bar&to=06222172&content=hello diff --git a/misc/doc/sources/management/jcli/modules.rst b/misc/doc/sources/management/jcli/modules.rst index 47eea857d..f2cf19609 100644 --- a/misc/doc/sources/management/jcli/modules.rst +++ b/misc/doc/sources/management/jcli/modules.rst @@ -50,7 +50,7 @@ The User manager module is accessible through the **user** command and is provid A User object is required for: * :doc:`/apis/smpp-server/index` authentication to send a SMS (c.f. :ref:`sending_sms-mt`) - * :doc:`/apis/ja-http/index` authentication to send a SMS (c.f. :ref:`sending_sms-mt`) + * :doc:`/apis/http/index` authentication to send a SMS (c.f. :ref:`sending_sms-mt`) * Creating a **UserFilter** using the **filter** manager (c.f. :ref:`filter_manager`) Every User **must** be a member of a Group, so before adding a new User, there must be at least one Group diff --git a/misc/doc/sources/programming-examples/index.rst b/misc/doc/sources/programming-examples/index.rst index 6576401e1..747497041 100644 --- a/misc/doc/sources/programming-examples/index.rst +++ b/misc/doc/sources/programming-examples/index.rst @@ -2,10 +2,10 @@ Programming examples #################### -Subsequent chapters present how to send and receive messages through Jasmin :doc:`/apis/ja-http/index` and some more -advanced use cases, such as manipulating receipts and complex routings, will look like. +Subsequent chapters present how to send and receive messages through Jasmin :doc:`/apis/http/index` and some more +advanced use cases, such as manipulating receipts and complex routings, will look like. -It is assumed the reader has already installed Jasmin and at least read the :doc:`/apis/ja-http/index` +It is assumed the reader has already installed Jasmin and at least read the :doc:`/apis/http/index` and :doc:`/routing/index` chapters and knows enough about Jasmin's architecture/design concepts. .. _Examples_Sending_SMS: @@ -13,22 +13,22 @@ and :doc:`/routing/index` chapters and knows enough about Jasmin's architecture/ Sending SMS *********** -Sending a SMS is done through the :doc:`/apis/ja-http/index`: +Sending a SMS is done through the :doc:`/apis/http/index`: -.. literalinclude:: /apis/ja-http/example_send_gsm0338.py - :language: python +.. literalinclude:: /apis/http/example_send_gsm0338.py + :language: python In PHP: -.. literalinclude:: /apis/ja-http/example_send_gsm0338.php +.. literalinclude:: /apis/http/example_send_gsm0338.php :language: php -In Ruby: +In Ruby: -.. literalinclude:: /apis/ja-http/example_send_gsm0338.rb +.. literalinclude:: /apis/http/example_send_gsm0338.rb :language: ruby -c.f. :doc:`/apis/ja-http/index` for more details about sending SMS with receipt enquiry, long content +c.f. :doc:`/apis/http/index` for more details about sending SMS with receipt enquiry, long content etc ... .. _Examples_Receiving_SMS: @@ -36,15 +36,15 @@ etc ... Receiving SMS ************* -Receiving a SMS is done through the :doc:`/apis/ja-http/index`, this a PHP script pointed by Jasmin for every +Receiving a SMS is done through the :doc:`/apis/http/index`, this a PHP script pointed by Jasmin for every received SMS (using routing): .. literalinclude:: example_receive.php :language: php -In the above example, there's an error handling where the message is not ACKed if there's a database connection -problem, if it occurs, the script will return "**Error connecting to DB**" when Jasmin HTTP thrower is waiting for -a "**ACL/Jasmin**", this will lead to a message re-queue and later re-delivery to the same script, this behaviour is +In the above example, there's an error handling where the message is not ACKed if there's a database connection +problem, if it occurs, the script will return "**Error connecting to DB**" when Jasmin HTTP thrower is waiting for +a "**ACL/Jasmin**", this will lead to a message re-queue and later re-delivery to the same script, this behaviour is explained in :ref:`deliverSmHttpThrower_process`. Another example of an interactive SMS application: @@ -52,7 +52,7 @@ Another example of an interactive SMS application: .. literalinclude:: example_receive_send.php :language: php -c.f. :doc:`/apis/ja-http/index` for more details. +c.f. :doc:`/apis/http/index` for more details. .. _Examples_Routing: @@ -60,4 +60,4 @@ Routing ******* c.f. :ref:`morouter_manager` and :ref:`mtrouter_manager` for routing scenarios. -c.f. :doc:`/routing/index` for details about routing. \ No newline at end of file +c.f. :doc:`/routing/index` for details about routing. diff --git a/misc/doc/sources/resources/architecture/hld.graphml b/misc/doc/sources/resources/architecture/hld.graphml index c625792bc..772a3d8d8 100644 --- a/misc/doc/sources/resources/architecture/hld.graphml +++ b/misc/doc/sources/resources/architecture/hld.graphml @@ -1,6 +1,6 @@ - + @@ -13,14 +13,14 @@ - + - Jasmin SMS Gateway v0.9 + Jasmin SMS Gateway v0.10 @@ -30,13 +30,7 @@ - Router - - - - - - + Router @@ -46,14 +40,8 @@ - SMPP -Client - - - - - - + SMPP +Client @@ -63,13 +51,7 @@ Client - Redis - - - - - - + Redis @@ -79,13 +61,7 @@ Client - AMQP Broker - - - - - - + AMQP Broker @@ -96,14 +72,8 @@ Client - AMQP -client - - - - - - + AMQP +client @@ -113,14 +83,8 @@ client - Redis -client - - - - - - + Redis +client @@ -130,13 +94,7 @@ client - SMPP Client manager - - - - - - + SMPP Client manager @@ -146,13 +104,7 @@ client - DLR Thrower - - - - - - + DLR Thrower @@ -162,13 +114,7 @@ client - DeliverSM thrower - - - - - - + DeliverSM thrower @@ -178,13 +124,7 @@ client - HTTP API - - - - - - + HTTP API @@ -194,14 +134,8 @@ client - PB -server - - - - - - + PB +server @@ -211,14 +145,8 @@ server - PB -server - - - - - - + PB +server @@ -228,14 +156,8 @@ server - HTTP -server - - - - - - + HTTP +server @@ -245,14 +167,8 @@ server - Third party -Application - - - - - - + Third party +Application @@ -263,14 +179,8 @@ Application - Third party -Application - - - - - - + Third party +Application @@ -281,14 +191,8 @@ Application - Third party -Application - - - - - - + Third party +Application @@ -299,13 +203,7 @@ Application - MT SMS - - - - - - + MT SMS @@ -316,14 +214,8 @@ Application - HTTP -client - - - - - - + HTTP +client @@ -333,14 +225,8 @@ client - HTTP -client - - - - - - + HTTP +client @@ -350,13 +236,7 @@ client - Receipt - - - - - - + Receipt @@ -367,14 +247,8 @@ client - Third party -Application - - - - - - + Third party +Application @@ -385,14 +259,8 @@ Application - Third party -Application - - - - - - + Third party +Application @@ -403,14 +271,8 @@ Application - Third party -Application - - - - - - + Third party +Application @@ -421,14 +283,8 @@ Application - Telnet -server - - - - - - + Telnet +server @@ -438,13 +294,7 @@ server - jCli - Jasmin Console - - - - - - + jCli - Jasmin Console @@ -454,14 +304,8 @@ server - Third party -SMPP server - - - - - - + Third party +SMPP server @@ -472,14 +316,8 @@ SMPP server - Third party -SMPP server - - - - - - + Third party +SMPP server @@ -490,14 +328,8 @@ SMPP server - Third party -SMPP server - - - - - - + Third party +SMPP server @@ -508,13 +340,7 @@ SMPP server - MO SMS - - - - - - + MO SMS @@ -525,13 +351,7 @@ SMPP server - MT SMS - - - - - - + MT SMS @@ -542,13 +362,7 @@ SMPP server - MO SMS - - - - - - + MO SMS @@ -559,13 +373,7 @@ SMPP server - Receipt - - - - - - + Receipt @@ -576,7 +384,7 @@ SMPP server - + @@ -597,13 +405,7 @@ SMPP server - SMPP Server API - - - - - - + SMPP Server API @@ -613,14 +415,8 @@ SMPP server - SMPP -server - - - - - - + SMPP +server @@ -630,13 +426,7 @@ server - MO SMS - - - - - - + MO SMS @@ -647,14 +437,8 @@ server - Third party -SMPP client - - - - - - + Third party +SMPP client @@ -665,14 +449,8 @@ SMPP client - Third party -SMPP client - - - - - - + Third party +SMPP client @@ -683,14 +461,8 @@ SMPP client - Third party -SMPP client - - - - - - + Third party +SMPP client @@ -701,13 +473,7 @@ SMPP client - Receipt - - - - - - + Receipt @@ -718,13 +484,7 @@ SMPP client - MT SMS - - - - - - + MT SMS @@ -735,14 +495,8 @@ SMPP client - Restful -API - - - - - - + Restful +API @@ -752,13 +506,7 @@ API - MO/MT SMS & Bulks - - - - - - + MO/MT SMS & Bulks @@ -909,14 +657,7 @@ API - Management - - - - - - - + Management @@ -939,14 +680,7 @@ API - Management - - - - - - - + Management @@ -1015,14 +749,7 @@ API - Management - - - - - - - + Management @@ -1074,7 +801,6 @@ API - @@ -1085,7 +811,6 @@ API - @@ -1100,70 +825,78 @@ API - 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 -YII= - iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAE9ElEQVR42q2VCUxUVxSGEcGaasXU -oLYq1SpqlTaVpShttAIqCJVRgiirAgMiVUqIbGItyyBWTRUXQKlLNW0tamujUWKRZdKksQtWQbGB -inFjk3UQZ6j5e8+dNzPvjYj12Um+nHvOPf+Zf+bO3GdhIbwWLg0drQhfeyHsk3TIhfQ0x0LOy4+J -j5aoUXiqBJ8fPG6EajNmzTMya44Xh+riPtJRjebIMhCyPhWqwmOITc+VsjEXSVv3Im1HoRHKYzdu -eQJVwVHQHFkGgj9OwRo2xN0vRDakpzmyDKyMS8aatBzE7bwkmximpzmyDKxYswExqSocqOyRDelp -jiwDy2MSEZ2iwv4KDaPHDI2ornlKTcP02aA5sgwEKBOgTM5GQbkGhWWMchOSWpnZfpl+n1AmZ4Hm -yDLgHxEPZVIm8i92GykQkS+K+f3UiSimpzmyDChWrUPkhgzs+6lLoNtEabe+VmqoifdNa9LTHLkX -ESITP8NeNlBPtxldz1xHJG6mi0ieAd+gaKxK2IS8kk7OrnOd2GmkQ0Ccm9Z5JV2ccHYd+66MlmfA -OzAK4fHpUH3fhhxOO1Q/tHEoN9TF0UQ7Jyx+I2iOLAOLAlYjdH0ask4+QDYjy4xsUTTH0BO6Lg00 -R5aBBcvCEcKu0cziFkYrJ0OAr79rFe2Je1qMfcFxKaA5sgx4KkIRtDZZ8oR7XoJik+DpFyrPwPwl -wfwafRGUKdvhH5WMvPO33ztUdm96WU3z8P9sYJ7PCgRGJw5I6xFLdHxt8b8hMTDXOwABUQk4d+0q -jp89w6FcXGv+0gpo+VbP30nyEPTtxwZJDby/0J9fo2FRSjg6uXAoF9cai6zQnD8IfZfD0Fc5EzpG -nwH1DOgE+iTMFGrUN4NraMaDryylBtw8FVi2av2A3CsYgntHpuhNVAVBV/4WdBXT9ZGv9VFbYcq1 -hr3y6RzSNn9jj5ZDZgbmePhBERYnOQLKxbVbu4ei7cQUNOybhPt7mInfFNCVToXu4lRoiVIh9kfp -NDTuscTdQ2+i7aQ9mooGSw24fvgRloTESo6AcnGtbvvLeHRhCjpOTcbNvRNx5wtL6C75QFvpzL5a -AbUzzw3ohHhnpyXTvIHO05P5jLuF1lIDLnN94BsUMyA3cofj0flJ6GW0F0/Ezd12aNg2GH2/L0Xf -rz4Ci/GPca2nYZsVarfaoenoRK6lGbf3DJEacPzAGz4roiVHQLm4di1rBB6etcPDM3Y8Nh6ZgNot -41Gnssbj6gg8rnmS+hz25rnjcbdoAnqZrpfpKDbsesnMgNsiLF6ulBwB5eJaTeYI9Jwep+fHcWg6 -PAbVmWNRu8sVNzKsOX8JGNbXc8bxHuo16Ij6HUOlBt6dvQBeAZEDcnWzDXpOjYWG0XjQFnU7bNlf -MhC381/DNdXrRq6LuMP26Mdaz3qbmIb0xHXVMKmBd1w9sch/teQIKBfXrnxqA02xLe4XjWI/yFHQ -sfPtODwcjQdG41bemH6hPerR/ryAa0hLM2qyXpEaeNvFgz0NUyVHsHbTVo6h9uemkbi//1VUZ4yE -7pd5aD84rF86noJW7cG1NOPK5hFGA3aMafYOrhccnNzh4DzfhBPhblyTAUKrdkLPibGyeKR24yYu -p9tIvgFbxuxn4Edv/keaDarSDNG0FudVqSwnjHtCTegxRPrgz/vUtnV0dPR6Ecw+lO2/t0WFHz46 -b1IAAAAASUVORK5CYII= - <?xml version="1.0" encoding="utf-8"?> + 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 + <?xml version="1.0" encoding="utf-8"?> <svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="59px" height="59px" viewBox="0 0 59 59" enable-background="new 0 0 59 59" xml:space="preserve"> <g> diff --git a/misc/doc/sources/resources/architecture/hld.png b/misc/doc/sources/resources/architecture/hld.png index a2b8a83fa..83489b148 100644 Binary files a/misc/doc/sources/resources/architecture/hld.png and b/misc/doc/sources/resources/architecture/hld.png differ diff --git a/misc/doc/sources/resources/ja-http/dlr-flowchart.graphml b/misc/doc/sources/resources/http/dlr-flowchart.graphml similarity index 100% rename from misc/doc/sources/resources/ja-http/dlr-flowchart.graphml rename to misc/doc/sources/resources/http/dlr-flowchart.graphml diff --git a/misc/doc/sources/resources/ja-http/dlr-flowchart.png b/misc/doc/sources/resources/http/dlr-flowchart.png similarity index 100% rename from misc/doc/sources/resources/ja-http/dlr-flowchart.png rename to misc/doc/sources/resources/http/dlr-flowchart.png diff --git a/misc/doc/sources/resources/ja-http/sms-mo-flowchart.graphml b/misc/doc/sources/resources/http/sms-mo-flowchart.graphml similarity index 100% rename from misc/doc/sources/resources/ja-http/sms-mo-flowchart.graphml rename to misc/doc/sources/resources/http/sms-mo-flowchart.graphml diff --git a/misc/doc/sources/resources/ja-http/sms-mo-flowchart.png b/misc/doc/sources/resources/http/sms-mo-flowchart.png similarity index 100% rename from misc/doc/sources/resources/ja-http/sms-mo-flowchart.png rename to misc/doc/sources/resources/http/sms-mo-flowchart.png diff --git a/nfpm.yaml b/nfpm.yaml index 38be80b8d..f9bf5981e 100644 --- a/nfpm.yaml +++ b/nfpm.yaml @@ -1,7 +1,7 @@ name: "jasmin-sms-gateway" arch: "amd64" platform: "linux" -version: "v0.10.11" +version: "v0.10.12" section: "default" priority: "extra" maintainer: "Jookies LTD " @@ -32,10 +32,15 @@ replaces: - jasmin-sms-gateway provides: - jasmin-sms-gateway -empty_folders: - - /var/log/jasmin - - /etc/jasmin/store contents: + - dst: /var/log/jasmin + type: dir + file_info: + mode: 0700 + - dst: /etc/jasmin/store + type: dir + file_info: + mode: 0700 - src: ./misc/config/jasmin.cfg dst: "/etc/jasmin/jasmin.cfg" type: config diff --git a/requirements.txt b/requirements.txt index f00294ad3..e4e87ee62 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,10 @@ smpp.pdu3~=0.6 smpp.twisted3~=0.7 python-messaging~=0.5.13 +# Freezinng cryptography version because of a bug in >=38.0.0 +# https://github.com/pyca/cryptography/issues/7617 +cryptography~=37.0.4 + # Added in 0.9rc16: celery>=4.0.0 redis~=3.4.1 @@ -24,3 +28,6 @@ requests~=2.23.0 # For REST API python-mimeparse~=1.6.0 + +# For /metrics (prometheus exporter) +prometheus-client~=0.14.1 diff --git a/setup.py b/setup.py index 7cf5e537d..b176e27c2 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ def parse_requirements(filename): setup( name="jasmin", - version='0.10.11', + version='0.10.12', author="Jookies LTD", author_email="jasmin@jookies.net", url="https://www.jasminsms.com", diff --git a/tests/managers/test_contents.py b/tests/managers/test_contents.py index 858f64ddc..79b59958b 100644 --- a/tests/managers/test_contents.py +++ b/tests/managers/test_contents.py @@ -41,6 +41,23 @@ def test_minimal_arguments(self): self.assertEqual(c['priority'], 1) self.assertNotEqual(c['message-id'], None) + def test_priority_values(self): + """Refs #971""" + + # Assert standard values + for priority in [0, 1, 2, 3]: + c = SubmitSmContent(1, self.body, self.replyto, self.bill, priority=priority) + self.assertEqual(c['priority'], priority) + + # Assert non-standard values + for priority in [4, 10, 100]: + c = SubmitSmContent(1, self.body, self.replyto, self.bill, priority=priority) + self.assertEqual(c['priority'], priority) + + # Assert incorrect values + for priority in ['2', 'string', object]: + self.assertRaises(InvalidParameterError, SubmitSmContent, 1, self.body, self.replyto, self.bill, priority=priority) + def test_unique_messageid(self): counter = 0 maxCounter = 10000 diff --git a/tests/protocols/http/test_metrics.py b/tests/protocols/http/test_metrics.py new file mode 100644 index 000000000..be1f2f4c5 --- /dev/null +++ b/tests/protocols/http/test_metrics.py @@ -0,0 +1,66 @@ +from twisted.internet import defer + +from .test_server import HTTPApiTestCases + + +class MetricsTestCases(HTTPApiTestCases): + @defer.inlineCallbacks + def get_metric(self, key=None): + """ + Invoke /metrics, + if key is set: return key's value or None if not found + if not: return metrics in json format + """ + response = yield self.web.get(b'metrics') + + metric_map = {} + for _line in response.value().decode().split('\n'): + if len(_line) == 0 or _line[:1] == '#': + continue + _key, _value = _line.split(' ') + metric_map[_key] = _value + + if key is not None: + yield defer.returnValue(metric_map.get(_key, None)) + else: + yield defer.returnValue(metric_map) + + +class HttpapiTestCases(MetricsTestCases): + username = 'nathalie' + + @defer.inlineCallbacks + def test_send_auth_error(self): + _before = yield self.get_metric() + + response = yield self.web.post(b'send', {b'username': self.username, + b'password': 'incorrec', + b'to': b'06155423', + b'content': 'anycontent'}) + self.assertEqual(response.value(), + b'Error "Authentication failure for username:%s"' % self.username.encode()) + self.assertEqual(response.responseCode, 403) + + _after = yield self.get_metric() + self.assertEqual(int(_before['httpapi_request_count'].encode()) + 1, + int(_after['httpapi_request_count'].encode())) + self.assertEqual(int(_before['httpapi_auth_error_count'].encode()) + 1, + int(_after['httpapi_auth_error_count'].encode())) + + @defer.inlineCallbacks + def test_send_other_error(self): + _before = yield self.get_metric() + + response = yield self.web.post(b'send', {b'username': 'nathalie', + b'password': 'correct', + b'to': b'06155423', + b'content': 'anycontent'}) + self.assertEqual(response.value(), + b'Error "Cannot send submit_sm, check SMPPClientManagerPB log file for details"') + self.assertEqual(response.responseCode, 500) + + _after = yield self.get_metric() + self.assertEqual(int(_before['httpapi_request_count'].encode()) + 1, + int(_after['httpapi_request_count'].encode())) + self.assertEqual(int(_before['httpapi_server_error_count'].encode()) + 1, + int(_after['httpapi_server_error_count'].encode())) diff --git a/tests/protocols/http/test_server.py b/tests/protocols/http/test_server.py index f199a75cd..7e2737eba 100644 --- a/tests/protocols/http/test_server.py +++ b/tests/protocols/http/test_server.py @@ -1,4 +1,3 @@ -import base64 import json from datetime import datetime @@ -12,9 +11,9 @@ from jasmin.protocols.http.stats import HttpAPIStatsCollector from jasmin.routing.Filters import GroupFilter from jasmin.routing.Routes import DefaultRoute, StaticMTRoute +from jasmin.routing.router import RouterPB from jasmin.routing.configs import RouterPBConfig from jasmin.routing.jasminApi import User, Group, SmppClientConnector -from jasmin.routing.router import RouterPB from .twisted_web_test_utils import DummySite diff --git a/tests/protocols/smpp/test_smpp_client.py b/tests/protocols/smpp/test_smpp_client.py index 7b873cdcb..296a0eccc 100644 --- a/tests/protocols/smpp/test_smpp_client.py +++ b/tests/protocols/smpp/test_smpp_client.py @@ -4,11 +4,9 @@ """ import copy -import random from unittest.mock import Mock from testfixtures import LogCapture -from twisted.internet import defer from twisted.internet.protocol import Factory from twisted.python import log from twisted.trial.unittest import TestCase diff --git a/tests/protocols/smpp/test_smpp_server.py b/tests/protocols/smpp/test_smpp_server.py index 36ae1c1be..f4de70b42 100644 --- a/tests/protocols/smpp/test_smpp_server.py +++ b/tests/protocols/smpp/test_smpp_server.py @@ -23,14 +23,7 @@ from jasmin.tools.cred.portal import SmppsRealm from smpp.pdu.error import SMPPTransactionError from smpp.pdu.operations import DeliverSM, DataSM - - -@defer.inlineCallbacks -def waitFor(seconds): - # Wait seconds - waitDeferred = defer.Deferred() - reactor.callLater(seconds, waitDeferred.callback, None) - yield waitDeferred +from .test_smpp_client import waitFor class LastProtoSMPPServerFactory(SMPPServerFactory):