diff --git a/designer/additional-configuration.conf b/designer/application-customizations.conf similarity index 100% rename from designer/additional-configuration.conf rename to designer/application-customizations.conf diff --git a/docker-compose.yml b/docker-compose.yml index 0df07e6b..042a19d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,15 +4,16 @@ services: ### Quickstart setup container quickstart-setup: - build: - context: quickstart-setup/ - dockerfile: Dockerfile - no_cache: true + image: touk/nussknacker-example-scenarios-library:latest depends_on: nginx: condition: service_healthy designer: condition: service_healthy + kafka: + condition: service_healthy + schema-registry: + condition: service_healthy environment: NU_DESIGNER_ADDRESS: "nginx:8080" NU_REQUEST_RESPONSE_OPEN_API_SERVICE_ADDRESS: "nginx:8181" @@ -20,7 +21,6 @@ services: SCHEMA_REGISTRY_ADDRESS: "schema-registry:8081" volumes: - nussknacker_designer_shared_configuration:/opt/nussknacker/conf/ - - ./scenario-examples:/scenario-examples deploy: resources: limits: @@ -58,6 +58,7 @@ services: image: touk/nussknacker:${NUSSKNACKER_VERSION:?NUSSKNACKER_VERSION must be defined}_scala-2.12 restart: unless-stopped environment: + EXAMPLE_SCENARIOS_LIBRARY_SERVICE_NAME: quickstart-setup CONFIG_FILE: "/opt/nussknacker/conf/application.conf,/opt/nussknacker/conf/additional-configuration.conf,/opt/nussknacker/conf/application-customizations.conf" DB_URL: "jdbc:postgresql://postgres:5432/nu-db" DB_DRIVER: "org.postgresql.Driver" @@ -91,7 +92,7 @@ services: retries: 10 volumes: - nussknacker_designer_shared_configuration:/opt/nussknacker/conf - - ./designer/additional-configuration.conf:/opt/nussknacker/conf/additional-configuration.conf + - ./designer/application-customizations.conf:/opt/nussknacker/conf/application-customizations.conf volumes_from: - flink-jobmanager deploy: diff --git a/quickstart-setup/Dockerfile b/quickstart-setup/Dockerfile deleted file mode 100644 index 53e83403..00000000 --- a/quickstart-setup/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM holomekc/wiremock-gui:3.8.1 AS wiremock - -RUN apt-get update && \ - apt-get install -y wget && \ - wget -P /var/wiremock/extensions https://repo1.maven.org/maven2/org/wiremock/extensions/wiremock-faker-extension-standalone/0.2.0/wiremock-faker-extension-standalone-0.2.0.jar - -FROM phusion/baseimage:noble-1.0.0 - -# Use baseimage-docker's init system. -CMD ["/sbin/my_init"] - -WORKDIR /app - -COPY setup/ /app/setup/ -COPY mocks/ /app/mocks/ -COPY data/ /app/data/ -COPY utils/ /app/utils/ -COPY run-mocks-setup-data.sh /app/run-mocks-setup-data.sh - -COPY services/postgres.sh /etc/service/db/run -COPY services/wiremock.sh /etc/service/http-service/run -COPY services/setup.sh /etc/service/setup/run - -# WIREMOCK & POSTGRES -COPY --from=wiremock /var/wiremock /var/wiremock -COPY --from=wiremock /home/wiremock /home/wiremock - -USER root - -RUN apt update && \ - apt install -y --no-install-recommends curl ca-certificates jq less && \ - install -d /usr/share/postgresql-common/pgdg && \ - curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc && \ - echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \ - apt update -y && \ - apt -y install postgresql-16 && \ - apt -y install openjdk-11-jre-headless && \ - apt clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ - curl https://raw.githubusercontent.com/birdayz/kaf/master/godownloader.sh | BINDIR=/bin bash - -EXPOSE 8080 -EXPOSE 5432 - -HEALTHCHECK --interval=10s --timeout=1s --retries=12 --start-period=30s \ - CMD (/app/setup/is-setup-done.sh && /app/mocks/db/is-postgres-ready.sh && /app/mocks/http-service/is-wiremock-ready.sh) || exit 1 diff --git a/quickstart-setup/Readme.md b/quickstart-setup/Readme.md deleted file mode 100644 index ba9e7623..00000000 --- a/quickstart-setup/Readme.md +++ /dev/null @@ -1,11 +0,0 @@ -# MOCKS - -## Resources: -https://github.com/wiremock/wiremock-faker-extension/blob/main/docs/reference.md -https://docs.wiremock.io/response-templating/basics/ -https://docs.wiremock.io/response-templating/dates-and-times/ - -# todo: -- delete -- write about disabling examples (eg. LOAN_REQUEST_DISABLED: true) -- write about required envs: NU_REQUEST_RESPONSE_OPEN_API_SERVICE_ADDRESS, SCHEMA_REGISTRY_ADDRESS, KAFKA_ADDRESS, NU_DESIGNER_ADDRESS \ No newline at end of file diff --git a/quickstart-setup/data/http/continuously-send-http-generated-requests.sh b/quickstart-setup/data/http/continuously-send-http-generated-requests.sh deleted file mode 100755 index 78a5d433..00000000 --- a/quickstart-setup/data/http/continuously-send-http-generated-requests.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function run_request_sending() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) OpenAPI service slug, 2) request generator script\n" - exit 11 - fi - - set -e - - local OPENAPI_SERVICE_SLUG=$1 - local REQUEST_GENERATOR_SCRIPT=$2 - - echo -n "Starting to send to '$OPENAPI_SERVICE_SLUG' OpenAPI service, requests generated by '$REQUEST_GENERATOR_SCRIPT' generator script... " - - mkdir -p /var/log/continuously-send-http-requests - nohup ../../utils/http/continuously-send-http-requests.sh "$OPENAPI_SERVICE_SLUG" "$REQUEST_GENERATOR_SCRIPT" > /var/log/continuously-send-http-requests/output.log 2>&1 & - - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to send generated requests to Nu OpenAPI services..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/data/http/generated"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.sh ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.sh' and content with bash script\n" - exit 3 - fi - - OPENAPI_SERVICE_SLUG=$(basename "$ITEM" ".sh") - - run_request_sending "$OPENAPI_SERVICE_SLUG" "$ITEM" - -done - -echo -e "Generators are running!\n" diff --git a/quickstart-setup/data/http/send-http-static-requests.sh b/quickstart-setup/data/http/send-http-static-requests.sh deleted file mode 100755 index 35b7300d..00000000 --- a/quickstart-setup/data/http/send-http-static-requests.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function send_request() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) Request-Response OpenAPI service slug, 2) request body\n" - exit 11 - fi - - set -e - - local OPENAPI_SERVICE_SLUG=$1 - local REQUEST_BODY=$2 - - echo -n "Sending request '$REQUEST_BODY' to Request-Response '$OPENAPI_SERVICE_SLUG' OpenAPI service... " - ../../utils/http/send-request-to-nu-openapi-service.sh "$OPENAPI_SERVICE_SLUG" "$REQUEST_BODY" - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to send preconfigured Request-Response OpenAPI service requests..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/data/http/static"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.txt ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.txt' and content with JSON messages\n" - exit 3 - fi - - OPENAPI_SERVICE_SLUG=$(basename "$ITEM" ".txt") - - while IFS= read -r REQUEST_BODY; do - if [[ $REQUEST_BODY == "#"* ]]; then - continue - fi - - send_request "$OPENAPI_SERVICE_SLUG" "$REQUEST_BODY" - - done < "$ITEM" -done - -echo -e "Requests sent!\n" diff --git a/quickstart-setup/data/kafka/continuously-send-kafka-generated-messages.sh b/quickstart-setup/data/kafka/continuously-send-kafka-generated-messages.sh deleted file mode 100755 index 6d20e84e..00000000 --- a/quickstart-setup/data/kafka/continuously-send-kafka-generated-messages.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function run_message_sending() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) topic name, 2) message generator script\n" - exit 11 - fi - - set -e - - local TOPIC_NAME=$1 - local MSG_GENERATOR_SCRIPT=$2 - - echo -n "Starting to send to '$TOPIC_NAME' messages generated by '$MSG_GENERATOR_SCRIPT' generator script... " - - mkdir -p /var/log/continuously-send-to-topic - nohup ../../utils/kafka/continuously-send-to-topic.sh "$TOPIC_NAME" "$MSG_GENERATOR_SCRIPT" > /var/log/continuously-send-to-topic/output.log 2>&1 & - - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to send generated messages..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/data/kafka/generated"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.sh ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.sh' and content with bash script\n" - exit 3 - fi - - TOPIC_NAME=$(basename "$ITEM" ".sh" | sed 's/.*/\u&/') - - run_message_sending "$TOPIC_NAME" "$ITEM" - -done - -echo -e "Generators are running!\n" diff --git a/quickstart-setup/data/kafka/send-kafka-static-messages.sh b/quickstart-setup/data/kafka/send-kafka-static-messages.sh deleted file mode 100755 index b7644904..00000000 --- a/quickstart-setup/data/kafka/send-kafka-static-messages.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function send_message() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) topic name, 2) message\n" - exit 11 - fi - - set -e - - local TOPIC_NAME=$1 - local MSG=$2 - - echo -n "Sending message $MSG to '$TOPIC_NAME'" - ../../utils/kafka/send-to-topic.sh "$TOPIC_NAME" "$MSG" - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to send preconfigured messages..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/data/kafka/static"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.txt ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.txt' and content with JSON messages\n" - exit 3 - fi - - TOPIC_NAME=$(basename "$ITEM" ".sh" | sed 's/.*/\u&/') - - while IFS= read -r MSG; do - if [[ $MSG == "#"* ]]; then - continue - fi - - send_message "$TOPIC_NAME" "$MSG" - - done < "$ITEM" -done - -echo -e "Messages sent!\n" diff --git a/quickstart-setup/data/keep-sending.sh b/quickstart-setup/data/keep-sending.sh deleted file mode 100755 index 91b83450..00000000 --- a/quickstart-setup/data/keep-sending.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../utils/lib.sh - -magenta_echo "-------- DATA GENERATION ACTIVATION STAGE is starting... ------\n" - -shopt -s nullglob - -for FOLDER in /scenario-examples/*; do - if is_scenario_enabled "$FOLDER"; then - echo -e "Starting to send static and generated data for scenario from ${GREEN}$FOLDER directory...\n\n" - - ./http/send-http-static-requests.sh "$FOLDER" - ./kafka/send-kafka-static-messages.sh "$FOLDER" - ./http/continuously-send-http-generated-requests.sh "$FOLDER" - ./kafka/continuously-send-kafka-generated-messages.sh "$FOLDER" - - echo -e "Static data sent and generators from ${GREEN}$FOLDER directory are runnning!\n\n" - else - echo -e "Skipping sending static and generated data for scenario from ${GREEN}$FOLDER directory.\n" - fi -done - -magenta_echo "-------- DATA GENERATION ACTIVATION STAGE is finished! --------\n\n" \ No newline at end of file diff --git a/quickstart-setup/mocks/configure.sh b/quickstart-setup/mocks/configure.sh deleted file mode 100755 index 6b02ec38..00000000 --- a/quickstart-setup/mocks/configure.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../utils/lib.sh - -shopt -s nullglob - -magenta_echo "-------- MOCK CONFIGURATION STAGE is starting... ----\n" - -for FOLDER in /scenario-examples/*; do - if is_scenario_enabled "$SCENARIO_DIR"; then - echo -e "Starting to configure mocks for scenarios from ${GREEN}$FOLDER directory...\n\n" - - ./db/execute-ddls.sh "$FOLDER" - ./http-service/configure-mock-http-services.sh "$FOLDER" - - echo -e "Mocks for scenarios from ${GREEN}$FOLDER directory configured!\n\n" - else - echo "Skipping configuring mocks for scenario from ${GREEN}$FOLDER directory." - fi -done - -magenta_echo "-------- MOCK CONFIGURATION STAGE is finished! ------\n\n" \ No newline at end of file diff --git a/quickstart-setup/mocks/db/execute-ddls.sh b/quickstart-setup/mocks/db/execute-ddls.sh deleted file mode 100755 index 9fdf043a..00000000 --- a/quickstart-setup/mocks/db/execute-ddls.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source postgres-operations.sh -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function execute_ddl_script() { - if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) DDL file path\n" - exit 11 - fi - - set -e - - local DDL_FILE_NAME=$1 - - local SCHEMA_NAME - local DDL_CONTENT - - SCHEMA_NAME=$(basename "$(strip_extension "$DDL_FILE_NAME")") - echo -n "Creating schema: $SCHEMA_NAME... " - create_schema "$PG_USER" "$SCHEMA_NAME" > /dev/null - echo "OK" - - DDL_CONTENT=$(wrap_sql_with_current_schema "$SCHEMA_NAME" "$(cat "$DDL_FILE_NAME")") - echo -n "Executing DDL '$DDL_FILE_NAME'... " - echo "$DDL_CONTENT" | execute_sql "" "$PG_USER" "$PG_PASS" > /dev/null - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to import Postgres DDL scripts..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/mocks/db"/*; do - if [ -f "$ITEM" ]; then - execute_ddl_script "$ITEM" - fi -done - -echo -e "Postgres DDL scripts imported!\n" diff --git a/quickstart-setup/mocks/db/is-postgres-ready.sh b/quickstart-setup/mocks/db/is-postgres-ready.sh deleted file mode 100755 index 903d4607..00000000 --- a/quickstart-setup/mocks/db/is-postgres-ready.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -e - -pg_isready -d mocks -U mocks > /dev/null diff --git a/quickstart-setup/mocks/db/postgres-init.sh b/quickstart-setup/mocks/db/postgres-init.sh deleted file mode 100755 index d9a625c2..00000000 --- a/quickstart-setup/mocks/db/postgres-init.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source postgres-operations.sh -source ../../utils/lib.sh - -init_db() { - init_bg_log_file - init_data_dir - init_custom_conf_dir - configure_pg_config - configure_authentication -} - -configure_users() { - create_user - create_custom_database - grant_privileges - alter_pg_user_pass -} - -init_db -postgres_start_bg -wait_until_started -configure_users -postgres_stop \ No newline at end of file diff --git a/quickstart-setup/mocks/db/postgres-operations.sh b/quickstart-setup/mocks/db/postgres-operations.sh deleted file mode 100755 index 87b35d32..00000000 --- a/quickstart-setup/mocks/db/postgres-operations.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash -e - -PG_DB_NAME="mocks" -PG_USER="mocks" -PG_PASS="mocks_pass" - -PG_BIN_DIR="/usr/lib/postgresql/16/bin" -PG_BASE_DIR="/home/postgres" -PG_DATA_DIR="$PG_BASE_DIR/data" -PG_CUSTOM_CONF_DIR="$PG_BASE_DIR/conf" -PG_CONF_FILE="$PG_CUSTOM_CONF_DIR/postgresql.conf" -PG_HBA_FILE="$PG_CUSTOM_CONF_DIR/pg_hba.conf" - -source /app/utils/lib.sh - -init_data_dir() { - if [ ! -e "$PG_DATA_DIR" ]; then - mkdir -p "$PG_DATA_DIR" - chown postgres "$PG_DATA_DIR" - /sbin/setuser postgres "$PG_BIN_DIR"/initdb -D "$PG_DATA_DIR" - fi -} - -init_custom_conf_dir() { - if [ ! -e "$PG_CUSTOM_CONF_DIR" ]; then - mkdir -p "$PG_CUSTOM_CONF_DIR" - chown postgres "$PG_CUSTOM_CONF_DIR" - fi -} - -configure_authentication() { - if [ ! -f "$PG_HBA_FILE" ]; then - cp "$PG_DATA_DIR/pg_hba.conf" "$PG_HBA_FILE" - chown postgres "$PG_HBA_FILE" - echo "#" >> "$PG_HBA_FILE" - echo "host all all all md5" >> "$PG_HBA_FILE" - fi -} - -configure_pg_config() { - if [ ! -f "$PG_CONF_FILE" ]; then - cp "$PG_DATA_DIR/postgresql.conf" "$PG_CONF_FILE" - chown postgres "$PG_CONF_FILE" - echo "#" >> "$PG_CONF_FILE" - echo "listen_addresses = '*'" >> "$PG_CONF_FILE" - fi -} - -init_bg_log_file() { - local log_file - log_file="/var/log/postgres_bg.log" - if [ ! -f "$log_file" ]; then - touch "$log_file" - chown postgres "$log_file" - fi -} - -wait_until_started() { - local max_startup_timeout_in_s=${1:-10} - while ! pg_isready >/dev/null 2>&1; do - sleep 1 - max_startup_timeout_in_s=$((max_startup_timeout_in_s - 1)) - if ((max_startup_timeout_in_s <= 0)); then - red_echo "ERROR: Postgres is not started\n" - exit 1 - fi - done - echo "Postgres started" -} - -create_custom_database() { - local db_name="${1:-$PG_DB_NAME}" - DB_EXISTS=$(echo "SELECT 1 FROM pg_database WHERE datname='$db_name'" | execute_sql "" "postgres" "" "-tA") - if [ "$DB_EXISTS" != "1" ]; then - echo "CREATE DATABASE \"$db_name\"" | execute_sql "" "postgres" "" - else - echo "DB already exists - creation skipped" - fi -} - -create_user() { - ROLE_EXISTS=$(echo "SELECT 1 FROM pg_roles WHERE rolname='$PG_USER'" | execute_sql "" "postgres" "" "-tA") - if [ "$ROLE_EXISTS" != "1" ]; then - echo "CREATE ROLE \"${PG_USER}\" WITH LOGIN PASSWORD '${PG_PASS}';" | execute_sql "" "postgres" "" - else - echo "ROLE already exists - creation skipped" - fi -} - -grant_privileges() { - local user="${1:-$PG_USER}" - local db_name="${2:-$PG_DB_NAME}" - execute_sql "" "postgres" "" < /dev/null \ No newline at end of file diff --git a/quickstart-setup/mocks/http-service/run-wiremock.sh b/quickstart-setup/mocks/http-service/run-wiremock.sh deleted file mode 100755 index e74e961c..00000000 --- a/quickstart-setup/mocks/http-service/run-wiremock.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -e - -echo "RUNNING Wiremock service..." - -java $JAVA_OPTS -cp /var/wiremock/lib/*:/var/wiremock/extensions/* wiremock.Run \ - --port=8080 \ - --root-dir=/home/wiremock/mocks \ - --max-request-journal=1000 \ - --global-response-templating \ - --extensions=org.wiremock.RandomExtension \ - --async-response-enable=true \ - --async-response-threads=30 \ - --disable-banner \ No newline at end of file diff --git a/quickstart-setup/run-mocks-setup-data.sh b/quickstart-setup/run-mocks-setup-data.sh deleted file mode 100755 index 9e3d2ea6..00000000 --- a/quickstart-setup/run-mocks-setup-data.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source /app/utils/lib.sh - -rm -rf /app/healthy - -if /app/mocks/db/is-postgres-ready.sh && /app/mocks/http-service/is-wiremock-ready.sh; then - green_echo "------ Nu scenarios library is being prepared... ---------\n" - - /app/mocks/configure.sh - /app/setup/run-setup.sh - /app/data/keep-sending.sh - - green_echo "------ Nu scenarios library sucessfully bootstrapped! ----\n\n" - - touch /app/healthy - - # loop forever (you can use manually called utils scripts now) - tail -f /dev/null -else - echo -e "\nWaiting for Postgres and Wiremock to be up and ready...\n" - sleep 5 - exit 1 -fi diff --git a/quickstart-setup/services/postgres.sh b/quickstart-setup/services/postgres.sh deleted file mode 100755 index 74bce8ca..00000000 --- a/quickstart-setup/services/postgres.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec /app/mocks/db/run-postgres.sh \ No newline at end of file diff --git a/quickstart-setup/services/setup.sh b/quickstart-setup/services/setup.sh deleted file mode 100755 index 571e0b3f..00000000 --- a/quickstart-setup/services/setup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec /app/run-mocks-setup-data.sh \ No newline at end of file diff --git a/quickstart-setup/services/wiremock.sh b/quickstart-setup/services/wiremock.sh deleted file mode 100755 index d7089ba1..00000000 --- a/quickstart-setup/services/wiremock.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec /app/mocks/http-service/run-wiremock.sh \ No newline at end of file diff --git a/quickstart-setup/setup/is-setup-done.sh b/quickstart-setup/setup/is-setup-done.sh deleted file mode 100755 index b6cb932b..00000000 --- a/quickstart-setup/setup/is-setup-done.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -e - -test -f "/app/healthy" diff --git a/quickstart-setup/setup/kafka/setup-topics.sh b/quickstart-setup/setup/kafka/setup-topics.sh deleted file mode 100755 index 6924aa41..00000000 --- a/quickstart-setup/setup/kafka/setup-topics.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function create_topic() { - if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) topic name\n" - exit 11 - fi - - set -e - local TOPIC_NAME=$1 - - echo -n "Creating topic '$TOPIC_NAME'... " - ../../utils/kafka/create-topic-idempotently.sh "$TOPIC_NAME" - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to create preconfigured topics..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/setup/kafka"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.txt ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.txt' and content with topic names\n" - exit 2 - fi - - while IFS= read -r TOPIC_NAME; do - - if [[ $TOPIC_NAME == "#"* ]]; then - continue - fi - - create_topic "$TOPIC_NAME" - - done < "$ITEM" -done - -echo -e "Topics created!\n" diff --git a/quickstart-setup/setup/nu/customize-nu-configuration.sh b/quickstart-setup/setup/nu/customize-nu-configuration.sh deleted file mode 100755 index 5142798a..00000000 --- a/quickstart-setup/setup/nu/customize-nu-configuration.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} -CONFS_DIR=/opt/nussknacker/conf -APP_CUSTOMIZATION_FILE_PATH="$CONFS_DIR/application-customizations.conf" - -function customize_nu_configuration() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) configuration file path 2) example scenario id\n" - exit 11 - fi - - set -e - - local EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_PATH=$1 - local EXAMPLE_SCENARIO_ID=$2 - local EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_NAME="${EXAMPLE_SCENARIO_ID}-$(basename "$EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_PATH")" - - echo -n "Including $EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_PATH configuration... " - - cp -f "$EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_PATH" "$CONFS_DIR/$EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_NAME" - local INCLUDE_CONF_LINE="include \"$EXAMPLE_SCENARIO_RELATED_CONFIGURAION_FILE_NAME\"" - - if ! grep -qxF "$INCLUDE_CONF_LINE" "$APP_CUSTOMIZATION_FILE_PATH"; then - echo "$INCLUDE_CONF_LINE" >> "$APP_CUSTOMIZATION_FILE_PATH" - fi - echo "OK" -} - -echo "Starting to customize Nu configuration..." - -touch "$APP_CUSTOMIZATION_FILE_PATH" - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/setup/nu-designer"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.conf ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.conf' and content with HOCON Nu configuration\n" - exit 2 - fi - - SCENARIO_EXAMPLE_ID=$(basename "$SCENARIO_EXAMPLE_DIR_PATH") - customize_nu_configuration "$ITEM" "$SCENARIO_EXAMPLE_ID" -done - -../../utils/nu/reload-configuration.sh - -echo -e "Configuration customized!\n" \ No newline at end of file diff --git a/quickstart-setup/setup/nu/import-and-deploy-example-scenarios.sh b/quickstart-setup/setup/nu/import-and-deploy-example-scenarios.sh deleted file mode 100755 index 4f3fd828..00000000 --- a/quickstart-setup/setup/nu/import-and-deploy-example-scenarios.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -function import_and_deploy_scenario() { - if [ "$#" -ne 2 ]; then - red_echo "Error: Two parameters required: 1) scenario name, 2) example scenario file path\n" - exit 11 - fi - - set -e - - local EXAMPLE_SCENARIO_NAME=$1 - local EXAMPLE_SCENARIO_FILE=$2 - - ../../utils/nu/load-scenario-from-json-file.sh "$EXAMPLE_SCENARIO_NAME" "$EXAMPLE_SCENARIO_FILE" - ../../utils/nu/deploy-scenario-and-wait-for-running-state.sh "$EXAMPLE_SCENARIO_NAME" -} - -echo "Starting to import and deploy example scenarios..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.json ]]; then - red_echo "ERROR: Unrecognized file $ITEM. Required file with extension '.json' and content with Nu scenario JSON\n" - exit 2 - fi - - EXAMPLE_SCENARIO_NAME="$(basename "$ITEM" ".json")" - - import_and_deploy_scenario "$EXAMPLE_SCENARIO_NAME" "$ITEM" -done - -echo -e "Scenarios imported and deployed!\n" diff --git a/quickstart-setup/setup/run-setup.sh b/quickstart-setup/setup/run-setup.sh deleted file mode 100755 index 6f9d03e0..00000000 --- a/quickstart-setup/setup/run-setup.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../utils/lib.sh - -shopt -s nullglob - -magenta_echo "-------- SETUP STAGE is starting... -------\n" - -for FOLDER in /scenario-examples/*; do - if is_scenario_enabled "$FOLDER"; then - echo -e "Starting to configure and run example scenarios from ${GREEN}$FOLDER directory...\n\n" - - ./schema-registry/setup-schemas.sh "$FOLDER" - ./kafka/setup-topics.sh "$FOLDER" - ./nu/customize-nu-configuration.sh "$FOLDER" - ./nu/import-and-deploy-example-scenarios.sh "$FOLDER" - - echo -e "Scenarios from ${GREEN}$FOLDER directory configured and running!\n\n" - else - echo "Skipping configuring and running example scenario from ${GREEN}$FOLDER directory." - fi -done - -magenta_echo "-------- SETUP STAGE is finished! ---------\n\n" diff --git a/quickstart-setup/setup/schema-registry/setup-schemas.sh b/quickstart-setup/setup/schema-registry/setup-schemas.sh deleted file mode 100755 index 31e12362..00000000 --- a/quickstart-setup/setup/schema-registry/setup-schemas.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../../utils/lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario example folder path\n" - exit 1 -fi - -function create_json_schema() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) schema name, 2) schema file path\n" - exit 11 - fi - - set -e - - local SCHEMA_NAME=$1 - local SCHEMA_FILE_PATH=$2 - - echo -n "Creating schema '$SCHEMA_NAME'... " - ../../utils/schema-registry/add-json-schema-idempotently.sh "$SCHEMA_NAME" "$SCHEMA_FILE_PATH" - echo "OK" -} - -SCENARIO_EXAMPLE_DIR_PATH=${1%/} - -echo "Starting to add preconfigured schemas..." - -shopt -s nullglob - -for ITEM in "$SCENARIO_EXAMPLE_DIR_PATH/setup/schema-registry"/*; do - if [ ! -f "$ITEM" ]; then - continue - fi - - if [[ ! "$ITEM" == *.schema.json ]]; then - red_echo "ERROR: Unrecognized file '$ITEM'. Required file with extension '.schema.json' and content with JSON schema\n" - exit 2 - fi - - SCHEMA_NAME="$(basename "$ITEM" ".schema.json")-value" - create_json_schema "$SCHEMA_NAME" "$ITEM" -done - -echo -e "Schemas added!\n" diff --git a/quickstart-setup/utils/http/continuously-send-http-requests.sh b/quickstart-setup/utils/http/continuously-send-http-requests.sh deleted file mode 100755 index 468e5474..00000000 --- a/quickstart-setup/utils/http/continuously-send-http-requests.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) OpenAPI service slug, 2) request generator script path\n" - exit 1 -fi - -OPENAPI_SERVICE_SLUG=$1 -REQUEST_GENERATOR_SCRIPT=$2 - -verify_bash_script "$REQUEST_GENERATOR_SCRIPT" - -while true; do - sleep 0.1 - ./send-request-to-nu-openapi-service.sh "$OPENAPI_SERVICE_SLUG" "$($REQUEST_GENERATOR_SCRIPT)" > /dev/null || true -done diff --git a/quickstart-setup/utils/http/send-request-to-nu-openapi-service.sh b/quickstart-setup/utils/http/send-request-to-nu-openapi-service.sh deleted file mode 100755 index 08a30d83..00000000 --- a/quickstart-setup/utils/http/send-request-to-nu-openapi-service.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) Nu OpenAPI service slug, 2) request payload\n" - exit 1 -fi - -if ! [ -v NU_REQUEST_RESPONSE_OPEN_API_SERVICE_ADDRESS ] || [ -z "$NU_REQUEST_RESPONSE_OPEN_API_SERVICE_ADDRESS" ]; then - red_echo "ERROR: required variable NU_REQUEST_RESPONSE_OPEN_API_SERVICE_ADDRESS not set or empty\n" - exit 2 -fi - -OPENAPI_SERVICE_SLUG=$1 -REQUEST_BODY=$2 - -RESPONSE=$(curl -s -L -w "\n%{http_code}" \ - -X POST "http://$NU_REQUEST_RESPONSE_OPEN_API_SERVICE_ADDRESS/scenario/$OPENAPI_SERVICE_SLUG" \ - -H "Content-Type: application/json" -d "$REQUEST_BODY" -) - -HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) -RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - -if [[ "$HTTP_STATUS" != 200 ]] ; then - red_echo "ERROR: '$OPENAPI_SERVICE_SLUG' OpenAPI service unexpected response.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 3 -fi - -echo "$RESPONSE_BODY" \ No newline at end of file diff --git a/quickstart-setup/utils/kafka/continuously-send-to-topic.sh b/quickstart-setup/utils/kafka/continuously-send-to-topic.sh deleted file mode 100755 index b4e5b85a..00000000 --- a/quickstart-setup/utils/kafka/continuously-send-to-topic.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) topic name, 2) generator script path\n" - exit 1 -fi - -TOPIC=$1 -GENERATOR_SCRIPT=$2 - -verify_bash_script "$GENERATOR_SCRIPT" - -while true; do - sleep 0.1 - ./send-to-topic.sh "$TOPIC" "$($GENERATOR_SCRIPT)" || true -done diff --git a/quickstart-setup/utils/kafka/create-topic-idempotently.sh b/quickstart-setup/utils/kafka/create-topic-idempotently.sh deleted file mode 100755 index ea51cc65..00000000 --- a/quickstart-setup/utils/kafka/create-topic-idempotently.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) topic name\n" - exit 1 -fi - -if ! [ -v KAFKA_ADDRESS ] || [ -z "$KAFKA_ADDRESS" ]; then - red_echo "ERROR: required variable KAFKA_ADDRESS not set or empty\n" - exit 2 -fi - -TOPIC_NAME=$1 - -if ! kaf --brokers="$KAFKA_ADDRESS" topics ls | awk '{print $1}' | grep "^$TOPIC_NAME$" > /dev/null 2>&1; then - kaf --brokers="$KAFKA_ADDRESS" topic create "$TOPIC_NAME" > /dev/null -fi \ No newline at end of file diff --git a/quickstart-setup/utils/kafka/purge-topic.sh b/quickstart-setup/utils/kafka/purge-topic.sh deleted file mode 100755 index a2681fff..00000000 --- a/quickstart-setup/utils/kafka/purge-topic.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) topic name\n" - exit 1 -fi - -if ! [ -v KAFKA_ADDRESS ] || [ -z "$KAFKA_ADDRESS" ]; then - red_echo "ERROR: required variable KAFKA_ADDRESS not set or empty\n" - exit 2 -fi - -TOPIC_NAME=$1 - -kaf --brokers="$KAFKA_ADDRESS" topic delete "$TOPIC_NAME" > /dev/null -./create-topic-idempotently.sh diff --git a/quickstart-setup/utils/kafka/send-to-topic.sh b/quickstart-setup/utils/kafka/send-to-topic.sh deleted file mode 100755 index 65e8ecae..00000000 --- a/quickstart-setup/utils/kafka/send-to-topic.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) topic name, 2) message\n" - exit 1 -fi - -if ! [ -v KAFKA_ADDRESS ] || [ -z "$KAFKA_ADDRESS" ]; then - red_echo "ERROR: required variable KAFKA_ADDRESS not set or empty\n" - exit 2 -fi - -TOPIC_NAME=$1 -MESSAGE=$2 - -if kaf --brokers="$KAFKA_ADDRESS" topics ls | awk '{print $1}' | grep "^$TOPIC_NAME$" > /dev/null 2>&1; then - echo "$MESSAGE" | kaf --brokers="$KAFKA_ADDRESS" produce "$TOPIC_NAME" > /dev/null -else - red_echo "ERROR: Topic name '$TOPIC_NAME' not found\n" - exit 3 -fi \ No newline at end of file diff --git a/quickstart-setup/utils/lib.sh b/quickstart-setup/utils/lib.sh deleted file mode 100755 index af6cd3d7..00000000 --- a/quickstart-setup/utils/lib.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/bin/bash -e - -RED='\033[31m' -GREEN='\033[32m' -MAGENTA='\033[35m' -RESET='\033[0m' - -function red_echo() { - echo -e "${RED}$1${RESET}" -} - -function green_echo() { - echo -e "${GREEN}$1${RESET}" -} - -function magenta_echo() { - echo -e "${MAGENTA}$1${RESET}" -} - -function verify_bash_script() { - local FILE=$1 - - if [[ -f "$FILE" ]]; then - if [[ $(head -n 1 "$FILE") =~ ^#!/bin/bash ]]; then - return 0 - else - echo "File '$FILE' exists but is not a Bash script." - return 1 - fi - else - echo "File '$FILE' does not exist." - return 2 - fi -} - -function random_Ndigit_number() { - if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) number of digits\n" - return 1 - fi - - local LENGTH=$1 - local RESULT="" - - local FIRST_DIGIT=$((RANDOM % 9 + 1)) - RESULT+="$FIRST_DIGIT" - - while [ ${#RESULT} -lt $LENGTH ]; do - local REMAINING=$((LENGTH - ${#RESULT})) - local PART=$(printf "%05d" $((RANDOM % 100000))) - RESULT+=${PART:0:$REMAINING} - done - echo "$RESULT" -} - -function random_4digit_number() { - random_Ndigit_number 4 -} - -function random_3digit_number() { - random_Ndigit_number 3 -} - -function random_1digit_number() { - random_Ndigit_number 1 -} - -function now() { - echo "$(date +%s)$(random_3digit_number)" -} - -function pick_randomly() { - local OPTIONS=("$@") - local COUNT=${#OPTIONS[@]} - local RANDOM_INDEX=$((RANDOM % COUNT)) - echo "${OPTIONS[$RANDOM_INDEX]}" -} - -function strip_extension() { - local file="$1" - echo "${file%.*}" -} - -function is_scenario_enabled() { - if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario folder path\n" - return 1 - fi - - SCENARIO_DIR=$1 - SCENARIO_NAME=$(basename "$SCENARIO_DIR") - - IS_DISABLED=$(echo "${SCENARIO_NAME}_DISABLED" | tr '-' '_' | awk '{print toupper($0)}') - if [[ "${!IS_DISABLED,,}" == "true" ]]; then - return 2 - fi - - return 0 -} \ No newline at end of file diff --git a/quickstart-setup/utils/nu/deploy-scenario-and-wait-for-running-state.sh b/quickstart-setup/utils/nu/deploy-scenario-and-wait-for-running-state.sh deleted file mode 100755 index 02713c1f..00000000 --- a/quickstart-setup/utils/nu/deploy-scenario-and-wait-for-running-state.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -lt 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario name\n" - exit 1 -fi - -if ! [ -v NU_DESIGNER_ADDRESS ] || [ -z "$NU_DESIGNER_ADDRESS" ]; then - red_echo "ERROR: required variable NU_DESIGNER_ADDRESS not set or empty\n" - exit 2 -fi - -SCENARIO_NAME=$1 -TIMEOUT_SECONDS=${2:-60} -WAIT_INTERVAL=5 - -function deploy_scenario() { - if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario name\n" - exit 11 - fi - - set -e - - local SCENARIO_NAME=$1 - - local RESPONSE - RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X POST "http://${NU_DESIGNER_ADDRESS}/api/processManagement/deploy/$SCENARIO_NAME" - ) - - local HTTP_STATUS - HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - - if [ "$HTTP_STATUS" != "200" ]; then - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - red_echo "ERROR: Cannot run scenario $SCENARIO_NAME deployment.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 12 - fi - - echo "Scenario $SCENARIO_NAME deployment started..." -} - -function check_deployment_status() { - if [ "$#" -ne 1 ]; then - red_echo "ERROR: One parameter required: 1) scenario name\n" - exit 21 - fi - - set -e - - local SCENARIO_NAME=$1 - - local RESPONSE - RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X GET "http://${NU_DESIGNER_ADDRESS}/api/processes/$SCENARIO_NAME/status" - ) - - local HTTP_STATUS - HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - - if [ "$HTTP_STATUS" != "200" ]; then - red_echo "ERROR: Cannot check scenario $SCENARIO_NAME deployment status.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 22 - fi - - local SCENARIO_STATUS - SCENARIO_STATUS=$(echo "$RESPONSE_BODY" | jq -r '.status.name') - echo "$SCENARIO_STATUS" -} - -echo "Deploying scenario $SCENARIO_NAME..." - -START_TIME=$(date +%s) -END_TIME=$((START_TIME + TIMEOUT_SECONDS)) - -deploy_scenario "$SCENARIO_NAME" - -while true; do - DEPLOYMENT_STATUS=$(check_deployment_status "$SCENARIO_NAME") - - if [ "$DEPLOYMENT_STATUS" == "RUNNING" ]; then - break - fi - - CURRENT_TIME=$(date +%s) - if [ $CURRENT_TIME -gt $END_TIME ]; then - red_echo "ERROR: Timeout for waiting for the RUNNING state of $SCENARIO_NAME deployment reached!\n" - exit 3 - fi - - echo "$SCENARIO_NAME deployment state is $DEPLOYMENT_STATUS. Checking again in $WAIT_INTERVAL seconds..." - sleep $WAIT_INTERVAL -done - -echo "Scenario $SCENARIO_NAME is RUNNING!" diff --git a/quickstart-setup/utils/nu/load-scenario-from-json-file.sh b/quickstart-setup/utils/nu/load-scenario-from-json-file.sh deleted file mode 100755 index 2ba17770..00000000 --- a/quickstart-setup/utils/nu/load-scenario-from-json-file.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -lt 2 ]; then - red_echo "ERROR: Two parameters required: 1) scenario name, 2) scenario file path\n" - exit 1 -fi - -if ! [ -v NU_DESIGNER_ADDRESS ] || [ -z "$NU_DESIGNER_ADDRESS" ]; then - red_echo "ERROR: required variable NU_DESIGNER_ADDRESS not set or empty\n" - exit 2 -fi - -SCENARIO_NAME=$1 -SCENARIO_FILE_PATH=$2 -CATEGORY=${3:-"Default"} - -if [ ! -f "$SCENARIO_FILE_PATH" ]; then - red_echo "ERROR: Cannot find file $SCENARIO_FILE_PATH with scenario\n" - exit 3 -fi - -function create_empty_scenario() { - if [ "$#" -ne 4 ]; then - red_echo "ERROR: Four parameters required: 1) scenario name, 2) processing mode, 3) category, 4) engine\n" - exit 11 - fi - - set -e - - local SCENARIO_NAME=$1 - local PROCESSING_MODE=$2 - local CATEGORY=$3 - local ENGINE=$4 - - local REQUEST_BODY="{ - \"name\": \"$SCENARIO_NAME\", - \"processingMode\": \"$PROCESSING_MODE\", - \"category\": \"$CATEGORY\", - \"engineSetupName\": \"$ENGINE\", - \"isFragment\": false - }" - - local RESPONSE - RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X POST "http://${NU_DESIGNER_ADDRESS}/api/processes" \ - -H "Content-Type: application/json" -d "$REQUEST_BODY" - ) - - local HTTP_STATUS - HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - - if [ "$HTTP_STATUS" == "400" ]; then - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - - if [[ "$RESPONSE_BODY" == *"already exists"* ]]; then - echo "Scenario already exists." - exit 0 - else - red_echo "ERROR: Cannot create empty scenario $SCENARIO_NAME.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 12 - fi - elif [ "$HTTP_STATUS" != "201" ]; then - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - red_echo "ERROR: Cannot create empty scenario $SCENARIO_NAME.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 13 - fi - - echo "Empty scenario $SCENARIO_NAME created successfully." -} - -function import_scenario_from_file() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) scenario name, 2) scenario file path\n" - exit 21 - fi - - set -e - - local SCENARIO_NAME=$1 - local SCENARIO_FILE=$2 - - local RESPONSE - RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X POST "http://${NU_DESIGNER_ADDRESS}/api/processes/import/$SCENARIO_NAME" \ - -F "process=@$SCENARIO_FILE" - ) - - # Check response body and status code - local HTTP_STATUS - HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - - if [ "$HTTP_STATUS" == "200" ]; then - local SCENARIO_GRAPH - SCENARIO_GRAPH=$(echo "$RESPONSE_BODY" | jq '.scenarioGraph') - echo "$SCENARIO_GRAPH" - else - red_echo "ERROR: Cannot import scenario $SCENARIO_NAME.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 22 - fi -} - -function save_scenario() { - if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) scenario name, 2) scenario graph JSON representation\n" - exit 31 - fi - - set -e - - local SCENARIO_NAME=$1 - local SCENARIO_GRAPH_JSON=$2 - - local REQUEST_BODY="{ - \"scenarioGraph\": $SCENARIO_GRAPH_JSON, - \"comment\": \"\" - }" - - local RESPONSE - RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X PUT "http://${NU_DESIGNER_ADDRESS}/api/processes/$SCENARIO_NAME" \ - -H "Content-Type: application/json" -d "$REQUEST_BODY" - ) - - local HTTP_STATUS - HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - - if [ "$HTTP_STATUS" != "200" ]; then - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - red_echo "ERROR: Cannot save scenario $SCENARIO_NAME.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 32 - fi - - echo "Scenario $SCENARIO_NAME saved successfully." -} - -META_DATA_TYPE=$(jq -r .metaData.additionalFields.metaDataType < "$SCENARIO_FILE_PATH") -case "$META_DATA_TYPE" in - "StreamMetaData") - ENGINE="Flink" - PROCESSING_MODE="Unbounded-Stream" - ;; - "LiteStreamMetaData") - ENGINE="Lite Embedded" - PROCESSING_MODE="Unbounded-Stream" - ;; - "RequestResponseMetaData") - ENGINE="Lite Embedded" - PROCESSING_MODE="Request-Response" - ;; - *) - red_echo "ERROR: Cannot import scenario with metadata type: $META_DATA_TYPE\n" - exit 4 - ;; -esac - -create_empty_scenario "$SCENARIO_NAME" "$PROCESSING_MODE" "$CATEGORY" "$ENGINE" -SCENARIO_GRAPH=$(import_scenario_from_file "$SCENARIO_NAME" "$SCENARIO_FILE_PATH") -save_scenario "$SCENARIO_NAME" "$SCENARIO_GRAPH" diff --git a/quickstart-setup/utils/nu/load-scenario-from-json.sh b/quickstart-setup/utils/nu/load-scenario-from-json.sh deleted file mode 100755 index de1f51ee..00000000 --- a/quickstart-setup/utils/nu/load-scenario-from-json.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -lt 2 ]; then - red_echo "ERROR: Two parameters required: 1) scenario name, 2) scenario JSON\n" - exit 1 -fi - -SCENARIO_NAME=$1 -SCENARIO_JSON=$2 -SCENARIO_JSON_FILE="/tmp/scenario-$SCENARIO_NAME.json" - -echo "$SCENARIO_JSON" > "$SCENARIO_JSON_FILE" -trap 'rm "$SCENARIO_JSON_FILE"' EXIT - -./load-scenario-from-json-file.sh "$SCENARIO_NAME" "$SCENARIO_JSON_FILE" diff --git a/quickstart-setup/utils/nu/reload-configuration.sh b/quickstart-setup/utils/nu/reload-configuration.sh deleted file mode 100755 index de796767..00000000 --- a/quickstart-setup/utils/nu/reload-configuration.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if ! [ -v NU_DESIGNER_ADDRESS ] || [ -z "$NU_DESIGNER_ADDRESS" ]; then - red_echo "ERROR: required variable NU_DESIGNER_ADDRESS not set or empty\n" - exit 1 -fi - -function reload_configuration() { - set -e - - local RESPONSE - RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X POST "http://${NU_DESIGNER_ADDRESS}/api/app/processingtype/reload" - ) - - local HTTP_STATUS - HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - local RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - - if [ "$HTTP_STATUS" != "204" ]; then - red_echo "ERROR: Cannot reload Nu configuration.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 22 - fi -} - -echo -n "Reloading Nu configuration... " -reload_configuration -echo "OK" diff --git a/quickstart-setup/utils/schema-registry/add-json-schema-idempotently.sh b/quickstart-setup/utils/schema-registry/add-json-schema-idempotently.sh deleted file mode 100755 index dd5cdc9a..00000000 --- a/quickstart-setup/utils/schema-registry/add-json-schema-idempotently.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source ../lib.sh - -if [ "$#" -ne 2 ]; then - red_echo "ERROR: Two parameters required: 1) schema name, 2) schema file path\n" - exit 1 -fi - -if ! [ -v SCHEMA_REGISTRY_ADDRESS ] || [ -z "$SCHEMA_REGISTRY_ADDRESS" ]; then - red_echo "ERROR: required variable SCHEMA_REGISTRY_ADDRESS not set or empty\n" - exit 2 -fi - -SCHEMA_NAME=$1 -SCHEMA_FILE=$2 - -ESCAPED_JSON_SCHEMA=$(awk 'BEGIN{ORS="\\n"} {gsub(/"/, "\\\"")} 1' < "$SCHEMA_FILE") - -REQUEST_BODY="{ - \"schema\": \"$ESCAPED_JSON_SCHEMA\", - \"schemaType\": \"JSON\", - \"references\": [] -}" - -RESPONSE=$(curl -s -L -w "\n%{http_code}" -u admin:admin \ - -X POST "http://${SCHEMA_REGISTRY_ADDRESS}/subjects/${SCHEMA_NAME}/versions" \ - -H "Content-Type: application/vnd.schemaregistry.v1+json" -d "$REQUEST_BODY" -) - -HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1) - -if [[ "$HTTP_STATUS" != 200 ]] ; then - RESPONSE_BODY - RESPONSE_BODY=$(echo "$RESPONSE" | sed \$d) - red_echo "ERROR: Cannot create schema $SCHEMA_NAME.\nHTTP status: $HTTP_STATUS, response body: $RESPONSE_BODY\n" - exit 3 -fi \ No newline at end of file diff --git a/scenario-examples/detect-large-transactions/DetectLargeTransactions.json b/scenario-examples/detect-large-transactions/DetectLargeTransactions.json deleted file mode 100644 index 5523b1af..00000000 --- a/scenario-examples/detect-large-transactions/DetectLargeTransactions.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "metaData": { - "id": "DetectLargeTransactions", - "additionalFields": { - "description": null, - "properties": { - "parallelism": "1", - "spillStateToDisk": "true" - }, - "metaDataType": "StreamMetaData" - } - }, - "nodes": [ - { - "id": "transactions", - "ref": { - "typ": "kafka", - "parameters": [ - { - "name": "Topic", - "expression": { - "language": "spel", - "expression": "'Transactions'" - } - }, - { - "name": "Schema version", - "expression": { - "language": "spel", - "expression": "'latest'" - } - } - ] - }, - "additionalFields": { - "description": null, - "layoutData": { - "x": 0, - "y": 0 - } - }, - "type": "Source" - }, - { - "nextFalse": [ - ], - "id": "only large ones", - "expression": { - "language": "spel", - "expression": "#input.amount > 20" - }, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 0, - "y": 180 - } - }, - "type": "Filter" - }, - { - "id": "send for audit", - "ref": { - "typ": "kafka", - "parameters": [ - { - "name": "Topic", - "expression": { - "language": "spel", - "expression": "'ProcessedTransactions'" - } - }, - { - "name": "Schema version", - "expression": { - "language": "spel", - "expression": "'latest'" - } - }, - { - "name": "Key", - "expression": { - "language": "spel", - "expression": "" - } - }, - { - "name": "Raw editor", - "expression": { - "language": "spel", - "expression": "true" - } - }, - { - "name": "Value validation mode", - "expression": { - "language": "spel", - "expression": "'strict'" - } - }, - { - "name": "Value", - "expression": { - "language": "spel", - "expression": "#input" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 0, - "y": 360 - } - }, - "type": "Sink" - } - ], - "additionalBranches": [ - ] -} diff --git a/scenario-examples/detect-large-transactions/data/kafka/generated/transactions.sh b/scenario-examples/detect-large-transactions/data/kafka/generated/transactions.sh deleted file mode 100755 index f8004ec9..00000000 --- a/scenario-examples/detect-large-transactions/data/kafka/generated/transactions.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source /app/utils/lib.sh - -ID=$((1 + $(random_4digit_number) % 5)) -AMOUNT=$((1 + $(random_4digit_number) % 30)) -TIME=$(($(now) - $(random_4digit_number) % 20)) - -echo "{ \"clientId\": \"Client$ID\", \"amount\": $AMOUNT, \"eventDate\": $TIME}" \ No newline at end of file diff --git a/scenario-examples/detect-large-transactions/data/kafka/static/transactions.txt b/scenario-examples/detect-large-transactions/data/kafka/static/transactions.txt deleted file mode 100644 index 65a41522..00000000 --- a/scenario-examples/detect-large-transactions/data/kafka/static/transactions.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Example messages below (message per line) -#{ "clientId": "Client1", "amount": 100, "eventDate": 1720166429}" -#{ "clientId": "Client2", "amount": 1000, "eventDate": 1720166429}" diff --git a/scenario-examples/detect-large-transactions/setup/kafka/topics.txt b/scenario-examples/detect-large-transactions/setup/kafka/topics.txt deleted file mode 100644 index 8efc1cf5..00000000 --- a/scenario-examples/detect-large-transactions/setup/kafka/topics.txt +++ /dev/null @@ -1,2 +0,0 @@ -ProcessedTransactions -Transactions diff --git a/scenario-examples/detect-large-transactions/setup/schema-registry/ProcessedTransactions.schema.json b/scenario-examples/detect-large-transactions/setup/schema-registry/ProcessedTransactions.schema.json deleted file mode 100644 index ca3c0d02..00000000 --- a/scenario-examples/detect-large-transactions/setup/schema-registry/ProcessedTransactions.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema", - "type": "object", - "properties": { - "clientId": { "type": "string" }, - "amount": { "type": "integer" }, - "isLast": { "type": "boolean", "default": false }, - "eventDate": { "type": "integer" } - }, - "required": ["clientId", "amount"], - "additionalProperties": false -} diff --git a/scenario-examples/detect-large-transactions/setup/schema-registry/Transactions.schema.json b/scenario-examples/detect-large-transactions/setup/schema-registry/Transactions.schema.json deleted file mode 100644 index ca3c0d02..00000000 --- a/scenario-examples/detect-large-transactions/setup/schema-registry/Transactions.schema.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema", - "type": "object", - "properties": { - "clientId": { "type": "string" }, - "amount": { "type": "integer" }, - "isLast": { "type": "boolean", "default": false }, - "eventDate": { "type": "integer" } - }, - "required": ["clientId", "amount"], - "additionalProperties": false -} diff --git a/scenario-examples/loan-request/LoanRequest.json b/scenario-examples/loan-request/LoanRequest.json deleted file mode 100644 index a18e4079..00000000 --- a/scenario-examples/loan-request/LoanRequest.json +++ /dev/null @@ -1,239 +0,0 @@ -{ - "metaData": { - "id": "LoanRequest", - "additionalFields": { - "description": null, - "properties": { - "inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"customerId\": {\n \"type\": \"string\"\n },\n \"location\": {\n \"type\": \"object\",\n \"properties\": {\n \"city\": {\n \"type\": \"string\"\n },\n \"street\": {\n \"type\": \"string\"\n }\n }\n },\n \"requestType\": {\n \"type\": \"string\"\n },\n \"requestedAmount\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\"customerId\", \"location\", \"requestType\", \"requestedAmount\"],\n \"additionalProperties\": false\n}", - "outputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"acceptedAmount\": {\n \"type\": \"number\",\n \"description\": \"Accepted amount\"\n },\n \"message\": {\n \"type\": \"string\",\n \"description\": \"Additional message\"\n }\n },\n \"required\": [\"acceptedAmount\", \"message\"],\n \"additionalProperties\": false\n}", - "slug": "loan" - }, - "metaDataType": "RequestResponseMetaData" - } - }, - "nodes": [ - { - "id": "request", - "ref": { - "typ": "request", - "parameters": [ - ] - }, - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 0 - } - }, - "type": "Source" - }, - { - "defaultNext": [ - ], - "nexts": [ - { - "expression": { - "language": "spel", - "expression": "#input.requestType == 'loan'" - }, - "nodes": [ - { - "id": "loan response", - "ref": { - "typ": "response", - "parameters": [ - { - "name": "acceptedAmount", - "expression": { - "language": "spel", - "expression": "50" - } - }, - { - "name": "message", - "expression": { - "language": "spel", - "expression": "'only small amount available'" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 0, - "y": 360 - } - }, - "type": "Sink" - } - ] - }, - { - "expression": { - "language": "spel", - "expression": "#input.requestType == 'mortgage'" - }, - "nodes": [ - { - "defaultNext": [ - ], - "nexts": [ - { - "expression": { - "language": "spel", - "expression": "#input.location.city == 'Warszawa'" - }, - "nodes": [ - { - "id": "Warsaw mortgage", - "ref": { - "typ": "response", - "parameters": [ - { - "name": "acceptedAmount", - "expression": { - "language": "spel", - "expression": "1000" - } - }, - { - "name": "message", - "expression": { - "language": "spel", - "expression": "'Large sum for Warszawa'" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 180, - "y": 540 - } - }, - "type": "Sink" - } - ] - }, - { - "expression": { - "language": "spel", - "expression": "true" - }, - "nodes": [ - { - "id": "Other city mortgage", - "ref": { - "typ": "response", - "parameters": [ - { - "name": "Raw editor", - "expression": { - "language": "spel", - "expression": "false" - } - }, - { - "name": "acceptedAmount", - "expression": { - "language": "spel", - "expression": "100" - } - }, - { - "name": "message", - "expression": { - "language": "spel", - "expression": "'Large sum for other city'" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 540, - "y": 540 - } - }, - "type": "Sink" - } - ] - } - ], - "id": "switch", - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 360 - } - }, - "type": "Switch" - } - ] - }, - { - "expression": { - "language": "spel", - "expression": "true" - }, - "nodes": [ - { - "id": "unknown", - "ref": { - "typ": "response", - "parameters": [ - { - "name": "acceptedAmount", - "expression": { - "language": "spel", - "expression": "0" - } - }, - { - "name": "message", - "expression": { - "language": "spel", - "expression": "'Unknown loan type'" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 720, - "y": 360 - } - }, - "type": "Sink" - } - ] - } - ], - "id": "loan type", - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 180 - } - }, - "type": "Switch" - } - ], - "additionalBranches": [ - ] - } \ No newline at end of file diff --git a/scenario-examples/loan-request/data/http/generated/loan.sh b/scenario-examples/loan-request/data/http/generated/loan.sh deleted file mode 100755 index b46b7f78..00000000 --- a/scenario-examples/loan-request/data/http/generated/loan.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source /app/utils/lib.sh - -ID="$(random_4digit_number)" -AMOUNT="$(random_4digit_number)" -REQUEST_TYPE="$(pick_randomly "loan" "mortgage" "insurance")" -CITY="$(pick_randomly "Warszawa" "Berlin" "Gdańsk" "Kraków", "Poznań", "Praga")" - -echo "{\"customerId\": \"$ID\", \"requestedAmount\": $AMOUNT, \"requestType\": \"$REQUEST_TYPE\", \"location\": { \"city\": \"$CITY\", \"street\": \"\" }}" \ No newline at end of file diff --git a/scenario-examples/loan-request/data/http/static/loan.txt b/scenario-examples/loan-request/data/http/static/loan.txt deleted file mode 100644 index 9b667512..00000000 --- a/scenario-examples/loan-request/data/http/static/loan.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Example Request-Response OpenAPI service requests (request payload per line) -#{"customerId": "anon", "requestedAmount": 1555, "requestType": "mortgage", "location": { "city": "Warszawa", "street": "Marszałkowska" }} -#{"customerId": "anon", "requestedAmount": 86, "requestType": "loan", "location": { "city": "Lublin", "street": "Głęboka" }} -#{"customerId": "1", "requestedAmount": 1000, "requestType": "loan", "location": { "city": "Warszawa", "street": "Marszałkowska" }} -#{"customerId": "1", "requestedAmount": 500, "requestType": "savings", "location": { "city": "London", "street": "Kensington" }} -#{"customerId": "4", "requestedAmount": 2000, "requestType": "mortgage", "location": { "city": "Lublin", "street": "Lipowa" }} -#{"customerId": "3", "requestedAmount": 2000, "requestType": "loan", "location": { "city": "Lublin", "street": "Głęboka" }} diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/OfferCustomerProposalBasedOnActivityEvent.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/OfferCustomerProposalBasedOnActivityEvent.json deleted file mode 100644 index 9bf82cd8..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/OfferCustomerProposalBasedOnActivityEvent.json +++ /dev/null @@ -1,446 +0,0 @@ -{ - "metaData" : { - "id" : "OfferCustomerProposalBasedOnActivityEvent", - "additionalFields" : { - "description" : null, - "properties" : { - "parallelism" : "1", - "spillStateToDisk" : "true", - "useAsyncInterpretation" : "", - "checkpointIntervalInSeconds" : "" - }, - "metaDataType" : "StreamMetaData" - } - }, - "nodes" : [ - { - "id" : "Customers-related events", - "ref" : { - "typ" : "kafka", - "parameters" : [ - { - "name" : "Topic", - "expression" : { - "language" : "spel", - "expression" : "'CustomerEvents'" - } - }, - { - "name" : "Schema version", - "expression" : { - "language" : "spel", - "expression" : "'latest'" - } - } - ] - }, - "additionalFields" : { - "description" : null, - "layoutData" : { - "x" : 180, - "y" : 0 - } - }, - "type" : "Source" - }, - { - "nextFalse" : [ - ], - "id" : "May client be interested in the new offer?", - "expression" : { - "language" : "spel", - "expression" : "#input.eventType.toString == \"ClientBrowseOffers\" || \n#input.eventType.toString == \"ClientSentTerminationLetter\"" - }, - "isDisabled" : null, - "additionalFields" : { - "description" : "We are interested only in two types of events: \"ClientSentTerminationLetter\", \"ClientBrowseOffers\"", - "layoutData" : { - "x" : 180, - "y" : 180 - } - }, - "type" : "Filter" - }, - { - "id" : "Get Customer Profile from API", - "service" : { - "id" : "getCustomerProfile", - "parameters" : [ - { - "name" : "customerId", - "expression" : { - "language" : "spel", - "expression" : "#input.customerId" - } - } - ] - }, - "output" : "profile", - "additionalFields" : { - "description" : "HTTP service is called to get customer profile using the \"customerId\" value from the event", - "layoutData" : { - "x" : 180, - "y" : 360 - } - }, - "type" : "Enricher" - }, - { - "nextFalse" : [ - ], - "id" : "Is adult customer?", - "expression" : { - "language" : "spel", - "expression" : "#profile.customerAge > 18" - }, - "isDisabled" : null, - "additionalFields" : { - "description" : "We are not interested in non-adult customers", - "layoutData" : { - "x" : 180, - "y" : 540 - } - }, - "type" : "Filter" - }, - { - "id" : "Get Offers for a given Customer Type from API", - "service" : { - "id" : "getOffersForCustomerType", - "parameters" : [ - { - "name" : "customerType", - "expression" : { - "language" : "spel", - "expression" : "#profile.customerType" - } - } - ] - }, - "output" : "offers", - "additionalFields" : { - "description" : "HTTP service is called to get offers for a passed customer type (taken from the response from the previous HTTP service call)", - "layoutData" : { - "x" : 180, - "y" : 720 - } - }, - "type" : "Enricher" - }, - { - "nextFalse" : [ - ], - "id" : "At least one offer exists?", - "expression" : { - "language" : "spel", - "expression" : "#offers.size > 0" - }, - "isDisabled" : null, - "additionalFields" : { - "description" : "We can continue if at least one offer is returned", - "layoutData" : { - "x" : 180, - "y" : 900 - } - }, - "type" : "Filter" - }, - { - "id" : "Pick the best offer", - "varName" : "offer", - "value" : { - "language" : "spel", - "expression" : "#offers.?[price == #COLLECTION.min(#offers.![price])][0]" - }, - "additionalFields" : { - "description" : "The offer with the best price is taken", - "layoutData" : { - "x" : 180, - "y" : 1080 - } - }, - "type" : "Variable" - }, - { - "nextFalse" : [ - { - "id" : "Random 4% discount", - "varName" : "specialDiscountPercentage", - "value" : { - "language" : "spel", - "expression" : "#RANDOM.nextInt(0,1000) == 0 ? 4 : 0" - }, - "additionalFields" : { - "description" : "1/1000 events will receive a 4% discount", - "layoutData" : { - "x" : 0, - "y" : 1620 - } - }, - "type" : "Variable" - }, - { - "definition" : { - "id" : "Random 4% discount", - "joinId" : "Union" - }, - "type" : "BranchEndData" - } - ], - "id" : "Is premium customer?", - "expression" : { - "language" : "spel", - "expression" : "#profile.isPremiumCustomer" - }, - "isDisabled" : null, - "additionalFields" : { - "description" : "We will give premium customers different discounts than regular customers.", - "layoutData" : { - "x" : 180, - "y" : 1260 - } - }, - "type" : "Filter" - }, - { - "id" : "Special discount depending on day of week (decision table)", - "service" : { - "id" : "decision-table", - "parameters" : [ - { - "name" : "Decision Table", - "expression" : { - "language" : "tabularDataDefinition", - "expression" : "{\n \"rows\": [\n [\n \"MONDAY\",\n \"0\"\n ],\n [\n \"TUESDAY\",\n \"0\"\n ],\n [\n \"WEDNESDAY\",\n \"3\"\n ],\n [\n \"THURSDAY\",\n \"0\"\n ],\n [\n \"FRIDAY\",\n \"5\"\n ],\n [\n \"SATURDAY\",\n \"5\"\n ],\n [\n \"SUNDAY\",\n \"5\"\n ],\n [\n null,\n null\n ]\n ],\n \"columns\": [\n {\n \"name\": \"DayOfWeek\",\n \"type\": \"java.lang.String\"\n },\n {\n \"name\": \"DiscountPercentage\",\n \"type\": \"java.lang.Integer\"\n }\n ]\n}" - } - }, - { - "name" : "Match condition", - "expression" : { - "language" : "spel", - "expression" : "#ROW.DayOfWeek == #DATE.nowAtDefaultTimeZone.getDayOfWeek.toString.toUpperCase" - } - } - ] - }, - "output" : "specialDiscountPercentages", - "additionalFields" : { - "description" : "Customer receives 5% discount on weekends and 3% discount on Wednesdays", - "layoutData" : { - "x" : 360, - "y" : 1440 - } - }, - "type" : "Enricher" - }, - { - "id" : "Extract the special discount", - "varName" : "specialDiscountPercentage", - "value" : { - "language" : "spel", - "expression" : "#specialDiscountPercentages.isEmpty ? \n0 : #specialDiscountPercentages[0].DiscountPercentage" - }, - "additionalFields" : { - "description" : null, - "layoutData" : { - "x" : 360, - "y" : 1620 - } - }, - "type" : "Variable" - }, - { - "definition" : { - "id" : "Extract the special discount", - "joinId" : "Union" - }, - "type" : "BranchEndData" - } - ], - "additionalBranches" : [ - [ - { - "id" : "Union", - "outputVar" : "context", - "nodeType" : "union", - "parameters" : [ - ], - "branchParameters" : [ - { - "branchId" : "Random 4% discount", - "parameters" : [ - { - "name" : "Output expression", - "expression" : { - "language" : "spel", - "expression" : "{ specialDiscountPercentage: #specialDiscountPercentage, offer: #offer, profile: #profile }" - } - } - ] - }, - { - "branchId" : "Extract the special discount", - "parameters" : [ - { - "name" : "Output expression", - "expression" : { - "language" : "spel", - "expression" : "{ specialDiscountPercentage: #specialDiscountPercentage, offer: #offer, profile: #profile }" - } - } - ] - } - ], - "additionalFields" : { - "description" : "it's workaround to unify context after the split: \nhttps://nussknacker.io/documentation/docs/next/scenarios_authoring/DesignerTipsAndTricks/#passing-the-context-after-the-union-node", - "layoutData" : { - "x" : 180, - "y" : 1800 - } - }, - "type" : "Join" - }, - { - "id" : "Calculate final price of the offer", - "varName" : "finalPrice", - "value" : { - "language" : "spel", - "expression" : "#context.offer.price - #context.specialDiscountPercentage * #context.offer.price" - }, - "additionalFields" : { - "description" : "Final price of the offer is calculated here", - "layoutData" : { - "x" : 180, - "y" : 1980 - } - }, - "type" : "Variable" - }, - { - "id" : "Prepare full offer message", - "varName" : "offerMessage", - "value" : { - "language" : "spel", - "expression" : "'Hello ' + #context.profile.customerName + \"! \\n\" + #context.offer.name + \"\\n\\n\" + #context.offer.message + \"\\nValid to \" + #DATE_FORMAT.formatter('yyyy-MM-dd HH:mm').format(#context.offer.validity) + \". Don't miss it!\"" - }, - "additionalFields" : { - "description" : "Offer message is prepared here", - "layoutData" : { - "x" : 180, - "y" : 2160 - } - }, - "type" : "Variable" - }, - { - "id" : "Offer proposal to customer", - "ref" : { - "typ" : "kafka", - "parameters" : [ - { - "name" : "Topic", - "expression" : { - "language" : "spel", - "expression" : "'OfferProposalsBasedOnCustomerEvents'" - } - }, - { - "name" : "Schema version", - "expression" : { - "language" : "spel", - "expression" : "'latest'" - } - }, - { - "name" : "Key", - "expression" : { - "language" : "spel", - "expression" : "" - } - }, - { - "name" : "Raw editor", - "expression" : { - "language" : "spel", - "expression" : "false" - } - }, - { - "name" : "amount", - "expression" : { - "language" : "spel", - "expression" : "#context.offer.price" - } - }, - { - "name" : "offerName", - "expression" : { - "language" : "spel", - "expression" : "#context.offer.name" - } - }, - { - "name" : "clientName", - "expression" : { - "language" : "spel", - "expression" : "#context.profile.customerName" - } - }, - { - "name" : "profileId", - "expression" : { - "language" : "spel", - "expression" : "#context.profile.id" - } - }, - { - "name" : "offerDescription", - "expression" : { - "language" : "spel", - "expression" : "#context.offer.message" - } - }, - { - "name" : "dueDate", - "expression" : { - "language" : "spel", - "expression" : "#context.offer.validity" - } - }, - { - "name" : "customerId", - "expression" : { - "language" : "spel", - "expression" : "#context.profile.customerId" - } - }, - { - "name" : "clientMsisdn", - "expression" : { - "language" : "spel", - "expression" : "#context.profile.customerMsisdn" - } - }, - { - "name" : "preparedMessageReadyToSend", - "expression" : { - "language" : "spel", - "expression" : "#offerMessage" - } - } - ] - }, - "endResult" : null, - "isDisabled" : null, - "additionalFields" : { - "description" : "We put the offer in a Kafka topic. Some other system will take care of sending it.", - "layoutData" : { - "x" : 180, - "y" : 2340 - } - }, - "type" : "Sink" - } - ] - ] -} \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/data/kafka/generated/customerEvents.sh b/scenario-examples/offer-customer-proposal-based-on-activity-event/data/kafka/generated/customerEvents.sh deleted file mode 100755 index 476afdd9..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/data/kafka/generated/customerEvents.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source /app/utils/lib.sh - -ID=$(random_Ndigit_number 10) -EVENT_TYPE="$(pick_randomly "ClientCloseToShowroom" "ClientBrowseOffers" "ClientEndedCallWithCustomerService" "ClientSentTerminationLetter" "Other")" - -echo "{ \"customerId\": \"$ID\", \"eventType\": \"$EVENT_TYPE\" }" \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/openapi/CustomerApi.yaml b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/openapi/CustomerApi.yaml deleted file mode 100644 index 2dd082f2..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/openapi/CustomerApi.yaml +++ /dev/null @@ -1,106 +0,0 @@ -openapi: 3.0.0 -info: - title: Customer API - version: 1.0.0 - description: API for retrieving customer profiles and offers based on customer type. - -paths: - '/customer/{customerId}/profile': - get: - summary: Get customer profile by customer's ID - description: Retrieve detailed profile information for a customer using their unique customer ID. - operationId: getCustomerProfile - parameters: - - name: customerId - in: path - required: true - description: The unique identifier of the customer. - schema: - type: string - responses: - '200': - description: Customer profile found successfully. - content: - application/json: - schema: - $ref: '#/components/schemas/CustomerProfile' - '404': - description: No customer profile found for the given ID. - - '/customer/{customerType}/offers': - get: - summary: Get offers by customer type - description: Retrieve offers available for a specific type of customer. - operationId: getOffersForCustomerType - parameters: - - name: customerType - in: path - required: true - description: The type/category of the customer. - schema: - type: string - responses: - '200': - description: Offers found for the specified customer type. - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/CustomerTypeOffer' - '404': - description: No offer found for the specified customer type. - -components: - schemas: - CustomerProfile: - title: CustomerProfile - type: object - description: Schema representing a customer's profile information. - properties: - id: - type: string - description: The unique identifier of the customer profile. - customerId: - type: string - description: The identifier of customer - customerType: - type: string - description: The type or category of the customer. - customerName: - type: string - description: The customer's name - customerMsisdn: - type: string - description: The customer's phone number - customerAge: - type: integer - description: The customer's age - customerSex: - type: string - description: The customer's sex - isPremiumCustomer: - type: boolean - description: Indicates if the customer is a premium one - - CustomerTypeOffer: - title: CustomerTypeOffer - type: object - description: Schema representing an offer available for a specific type of customer. - properties: - id: - type: string - description: The unique identifier of the offer. - name: - type: string - description: The name or title of the offer. - message: - type: string - description: A human-readable offer description - price: - type: integer - description: Price of the offer - validity: - type: string - format: date-time - description: The validity date of the offer. diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerProfile.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerProfile.json deleted file mode 100644 index 4c43f806..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerProfile.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "{{randomValue length=10 type='NUMERIC'}}", - "customerId": "{{request.path.[1]}}", - "customerType": "{{{pickRandom 'Freemium' 'Regular' 'VIP'}}}", - "customerName": "{{random 'Name.fullName'}}", - "customerMsisdn": "{{random 'PhoneNumber.phoneNumber'}}", - "customerAge": {{randomInt lower=10 upper=99}}, - "customerSex": "{{{pickRandom 'Male' 'Female' 'N/A'}}}", - "isPremiumCustomer": {{random 'Bool.bool'}} -} \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers0.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers0.json deleted file mode 100644 index 0637a088..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers0.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers1.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers1.json deleted file mode 100644 index 704ceea2..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers1.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "id": "{{randomValue length=10 type='NUMERIC'}}", - "name": "{{random 'Commerce.productName'}} promotion", - "message": "{{random 'Lorem.sentence'}} {{random 'Lorem.sentence'}} {{random 'Lorem.sentence'}}", - "price": {{randomInt lower=10 upper=50}}, - "validity": "{{dateFormat (now offset='3 days') format='yyyy-MM-dd\'T\'HH:mm:ss\'Z\''}}" - } -] \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers2.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers2.json deleted file mode 100644 index af6af793..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/__files/customer-api/responses/CustomerTypeOffers2.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "id": "{{randomValue length=10 type='NUMERIC'}}", - "name": "{{random 'Commerce.productName'}} promotion", - "message": "{{random 'Lorem.sentence'}} {{random 'Lorem.sentence'}} {{random 'Lorem.sentence'}}", - "price": {{randomInt lower=10 upper=50}}, - "validity": "{{dateFormat (now offset='3 days') format='yyyy-MM-dd\'T\'HH:mm:ss\'Z\''}}" - }, - { - "id": "{{randomValue length=10 type='NUMERIC'}}", - "name": "{{random 'Commerce.productName'}} promotion", - "message": "{{random 'Lorem.sentence'}} {{random 'Lorem.sentence'}} {{random 'Lorem.sentence'}}", - "price": {{randomInt lower=10 upper=50}}, - "validity": "{{dateFormat (now offset='3 days') format='yyyy-MM-dd\'T\'HH:mm:ss\'Z\''}}" - } -] \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/mappings/customer-api/GetCustomerProfile.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/mappings/customer-api/GetCustomerProfile.json deleted file mode 100644 index 57153c01..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/mappings/customer-api/GetCustomerProfile.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "request": { - "urlPattern": "/customer/(.+)/profile", - "method": "GET" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "bodyFileName": "customer-api/responses/CustomerProfile.json" - } -} \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/mappings/customer-api/GetOffersForCusomerType.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/mappings/customer-api/GetOffersForCusomerType.json deleted file mode 100644 index d19260ae..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/mocks/http-service/customer-api/mappings/customer-api/GetOffersForCusomerType.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "mappings": [ - { - "request": { - "urlPattern": "/customer/(.+)/offers", - "method": "GET" - }, - "response": { - "status": 404 - } - }, - { - "request": { - "urlPattern": "/customer/(?i)(Freemium|Regular|VIP)/offers", - "method": "GET" - }, - "response": { - "status": 200, - "headers": { - "Content-Type": "application/json" - }, - "bodyFileName": "customer-api/responses/CustomerTypeOffers{{{pickRandom '0' '1' '2'}}}.json" - } - } - ] -} \ No newline at end of file diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/kafka/topics.txt b/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/kafka/topics.txt deleted file mode 100644 index 28e852c6..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/kafka/topics.txt +++ /dev/null @@ -1,2 +0,0 @@ -CustomerEvents -OfferProposalsBasedOnCustomerEvents diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/nu-designer/custom-configuration.conf b/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/nu-designer/custom-configuration.conf deleted file mode 100644 index b26d8dc7..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/nu-designer/custom-configuration.conf +++ /dev/null @@ -1,19 +0,0 @@ -## To customize Nu Designer configuration see https://nussknacker.io/documentation/docs/configuration/Common/#configuration-file - -scenarioTypes { - "streaming" { - # customize Flink streaming scenario type - modelConfig { - components { - # OpenAPI enrichers - "customerProfileOffers" { - providerType: "openAPI" - url: "http://quickstart-setup:8080/__admin/files/customer-api/openapi/CustomerApi.yaml" - rootUrl: "http://quickstart-setup:8080/" - namePattern: "get.*" - allowedMethods: ["GET"] - } - } - } - } -} diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/schema-registry/CustomerEvents.schema.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/schema-registry/CustomerEvents.schema.json deleted file mode 100644 index 933a3c20..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/schema-registry/CustomerEvents.schema.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "type": "object", - "title": "CustomerEvent", - "$schema": "http://json-schema.org/draft-07/schema#", - "required": [ - "customerId", - "eventType" - ], - "properties": { - "customerId": { - "description": "The customer unique identifier", - "type": "string" - }, - "eventType": { - "description": "Type of event", - "type": "string", - "enum": [ - "ClientCloseToShowroom", - "ClientBrowseOffers", - "ClientEndedCallWithCustomerService", - "ClientSentTerminationLetter", - "Other" - ] - } - } -} diff --git a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/schema-registry/OfferProposalsBasedOnCustomerEvents.schema.json b/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/schema-registry/OfferProposalsBasedOnCustomerEvents.schema.json deleted file mode 100644 index ddcec287..00000000 --- a/scenario-examples/offer-customer-proposal-based-on-activity-event/setup/schema-registry/OfferProposalsBasedOnCustomerEvents.schema.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "type": "object", - "title": "OfferProposal", - "$schema": "http://json-schema.org/draft-07/schema#", - "required": [ - "offerName", - "offerDescription", - "clientName", - "amount", - "dueDate" - ], - "properties": { - "customerId": { - "type": "string" - }, - "profileId": { - "type": "string" - }, - "clientName": { - "type": "string", - "description": "The person's full name" - }, - "clientMsisdn": { - "type": "string", - "description": "Client's phone number" - }, - "offerName": { - "type": "string", - "description": "The assigned offer for the person" - }, - "offerDescription": { - "type": "string", - "description": "The assigned offer human readable description" - }, - "amount": { - "type": "integer", - "description": "The offer price" - }, - "dueDate": { - "type": "string", - "format": "date-time", - "description": "The expiration date for the offer" - }, - "preparedMessageReadyToSend": { - "type": "string", - "description": "The human-readable message. It should be prepared to be sent without further modifications." - } - } -} diff --git a/scenario-examples/rtm-client-near-pos/RTMClientNearPOS.json b/scenario-examples/rtm-client-near-pos/RTMClientNearPOS.json deleted file mode 100644 index 8ec020bd..00000000 --- a/scenario-examples/rtm-client-near-pos/RTMClientNearPOS.json +++ /dev/null @@ -1,660 +0,0 @@ -{ - "metaData": { - "id": "RTMClientNearPOS", - "additionalFields": { - "description": null, - "properties": { - "parallelism": "1", - "spillStateToDisk": "true", - "useAsyncInterpretation": "", - "checkpointIntervalInSeconds": "" - }, - "metaDataType": "StreamMetaData" - } - }, - "nodes": [ - { - "id": "stream of given clients geo location", - "ref": { - "typ": "kafka", - "parameters": [ - { - "name": "Topic", - "expression": { - "language": "spel", - "expression": "'GeoLocations'" - } - }, - { - "name": "Schema version", - "expression": { - "language": "spel", - "expression": "'latest'" - } - } - ] - }, - "additionalFields": { - "description": "geo locations stream", - "layoutData": { - "x": 360, - "y": 0 - } - }, - "type": "Source" - }, - { - "id": "enrich with contact history data", - "service": { - "id": "customers-data-query-enricher", - "parameters": [ - { - "name": "Result strategy", - "expression": { - "language": "spel", - "expression": "'Result set'" - } - }, - { - "name": "Query", - "expression": { - "language": "spelTemplate", - "expression": "select 'x' from contact_history where client_id = ? and event_time > NOW() - INTERVAL '5 minutes'" - } - }, - { - "name": "Cache TTL", - "expression": { - "language": "spel", - "expression": "T(java.time.Duration).parse('PT1M')" - } - }, - { - "name": "arg1", - "expression": { - "language": "spel", - "expression": "#input.clientId" - } - } - ] - }, - "output": "contact_history_entry", - "additionalFields": { - "description": "Wer are fetching given client contact history from the last X days.\nFor the purpose of example we are fetching entries from the last 5 minutes instead of days or longer period.", - "layoutData": { - "x": 360, - "y": 180 - } - }, - "type": "Enricher" - }, - { - "nextFalse": [ - ], - "id": "client is not contacted in last X Days", - "expression": { - "language": "spel", - "expression": "#contact_history_entry.empty" - }, - "isDisabled": null, - "additionalFields": { - "description": "The main goal is not to send too many notifications to the given client.", - "layoutData": { - "x": 360, - "y": 360 - } - }, - "type": "Filter" - }, - { - "id": "enrich with data from list of blocked clients", - "service": { - "id": "customers-data-lookup-enricher", - "parameters": [ - { - "name": "Table", - "expression": { - "language": "spel", - "expression": "'blocked_list'" - } - }, - { - "name": "Cache TTL", - "expression": { - "language": "spel", - "expression": "T(java.time.Duration).parse('PT1M')" - } - }, - { - "name": "Key column", - "expression": { - "language": "spel", - "expression": "'client_id'" - } - }, - { - "name": "Key value", - "expression": { - "language": "spel", - "expression": "#input.clientId" - } - } - ] - }, - "output": "is_client_on_blocked_list", - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 540 - } - }, - "type": "Enricher" - }, - { - "nextFalse": [ - ], - "id": "client is not blocked", - "expression": { - "language": "spel", - "expression": "#is_client_on_blocked_list == null" - }, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 720 - } - }, - "type": "Filter" - }, - { - "id": "enrich with client data", - "service": { - "id": "customers-data-lookup-enricher", - "parameters": [ - { - "name": "Table", - "expression": { - "language": "spel", - "expression": "'client'" - } - }, - { - "name": "Cache TTL", - "expression": { - "language": "spel", - "expression": "T(java.time.Duration).parse('PT5M')" - } - }, - { - "name": "Key column", - "expression": { - "language": "spel", - "expression": "'id'" - } - }, - { - "name": "Key value", - "expression": { - "language": "spel", - "expression": "#input.clientId" - } - } - ] - }, - "output": "clientData", - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 900 - } - }, - "type": "Enricher" - }, - { - "id": "extract consents from client data", - "varName": "consents", - "value": { - "language": "spel", - "expression": "#UTIL.split(#clientData.consents, '_')" - }, - "additionalFields": { - "description": "We are transforming and then assigning consents to variable consents", - "layoutData": { - "x": 360, - "y": 1080 - } - }, - "type": "Variable" - }, - { - "nextFalse": [ - ], - "id": "client has marketing consents", - "expression": { - "language": "spel", - "expression": "NOT #consents.isEmpty" - }, - "isDisabled": false, - "additionalFields": { - "description": "#clientData?.consents?", - "layoutData": { - "x": 360, - "y": 1260 - } - }, - "type": "Filter" - }, - { - "id": "enrich with POS info", - "service": { - "id": "pos-data-lookup-enricher", - "parameters": [ - { - "name": "Table", - "expression": { - "language": "spel", - "expression": "'pos'" - } - }, - { - "name": "Cache TTL", - "expression": { - "language": "spel", - "expression": "T(java.time.Duration).parse('PT10M')" - } - }, - { - "name": "Key column", - "expression": { - "language": "spel", - "expression": "'id'" - } - }, - { - "name": "Key value", - "expression": { - "language": "spel", - "expression": "#clientData.pos_id" - } - } - ] - }, - "output": "pos_data", - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 1440 - } - }, - "type": "Enricher" - }, - { - "nextFalse": [ - ], - "id": "POS is currently opened", - "expression": { - "language": "spel", - "expression": "#pos_data != null AND #pos_data.open_hour != null AND #pos_data.close_hour != null AND #DATE.isBetween(#DATE.nowAtZone('Europe/Warsaw').toLocalTime, #pos_data.open_hour, #pos_data.close_hour)" - }, - "isDisabled": null, - "additionalFields": { - "description": "POS open weekdays should be checked too", - "layoutData": { - "x": 360, - "y": 1620 - } - }, - "type": "Filter" - }, - { - "id": "Count when distance to POS is lower than 1 km", - "outputVar": "agg_out", - "nodeType": "aggregate-session", - "parameters": [ - { - "name": "groupBy", - "expression": { - "language": "spel", - "expression": "#input.clientId + ''" - } - }, - { - "name": "aggregator", - "expression": { - "language": "spel", - "expression": "#AGG.countWhen" - } - }, - { - "name": "aggregateBy", - "expression": { - "language": "spel", - "expression": "#GEO.distanceInKm(#input.geo.lat, #input.geo.lon, #pos_data.location_lat, #pos_data.location_lon) <= 1" - } - }, - { - "name": "endSessionCondition", - "expression": { - "language": "spel", - "expression": "false" - } - }, - { - "name": "sessionTimeout", - "expression": { - "language": "spel", - "expression": "T(java.time.Duration).parse('PT10S')" - } - }, - { - "name": "emitWhen", - "expression": { - "language": "spel", - "expression": "T(pl.touk.nussknacker.engine.flink.util.transformer.aggregate.SessionWindowTrigger).OnEvent" - } - } - ], - "additionalFields": { - "description": "We are counting events when a customer is within one kilometre of the point of sale assigned to that customer. For the purpose of the example we set the timeout to 10 seconds, in the real scenario the value should be higher.", - "layoutData": { - "x": 360, - "y": 1800 - } - }, - "type": "CustomNode" - }, - { - "nextFalse": [ - ], - "id": "2 events received with location near POS from session of X time", - "expression": { - "language": "spel", - "expression": "#agg_out == 2" - }, - "isDisabled": null, - "additionalFields": { - "description": "If we receive at least 2 events where the customer location meets our requirements within 10 seconds, we process further.", - "layoutData": { - "x": 360, - "y": 1980 - } - }, - "type": "Filter" - }, - { - "id": "decisions priorities and notification content by consent and client type", - "service": { - "id": "decision-table", - "parameters": [ - { - "name": "Decision Table", - "expression": { - "language": "tabularDataDefinition", - "expression": "{\n \"rows\": [\n [\n \"SMS\",\n \"INDIVIDUAL\",\n \"3\",\n \"You are close to our shop come and see new offers!\"\n ],\n [\n \"EMAIL\",\n \"INDIVIDUAL\",\n \"1\",\n \"You are close to our shop come and see new offers!\"\n ],\n [\n \"PUSH\",\n \"INDIVIDUAL\",\n \"2\",\n \"You are close to our shop come and see new offers!\"\n ],\n [\n \"SMS\",\n \"BUSINESS\",\n \"2\",\n \"You are close to our shop come and see new business offers!\"\n ],\n [\n \"EMAIL\",\n \"BUSINESS\",\n \"3\",\n \"You are close to our shop come and see new business offers!\"\n ],\n [\n \"PUSH\",\n \"BUSINESS\",\n \"1\",\n \"You are close to our shop come and see new business offers!\"\n ]\n ],\n \"columns\": [\n {\n \"name\": \"Consent\",\n \"type\": \"java.lang.String\"\n },\n {\n \"name\": \"Client type\",\n \"type\": \"java.lang.String\"\n },\n {\n \"name\": \"Priority\",\n \"type\": \"java.lang.Integer\"\n },\n {\n \"name\": \"Notification content\",\n \"type\": \"java.lang.String\"\n }\n ]\n}" - } - }, - { - "name": "Match condition", - "expression": { - "language": "spel", - "expression": "#consents.^[#this == #ROW.Consent] != null AND #clientData.client_type == #ROW['Client type']" - } - } - ] - }, - "output": "decisionsWithPrioritiesAndNotificationContent", - "additionalFields": { - "description": "In the decision table, we define the business rules that we are trying to match with the 'matching condition' and then pass the matched decisions on.", - "layoutData": { - "x": 360, - "y": 2160 - } - }, - "type": "Enricher" - }, - { - "id": "choose best decision", - "varName": "decision", - "value": { - "language": "spel", - "expression": "#decisionsWithPrioritiesAndNotificationContent?.^[#this.Priority == 3] ?: (#decisionsWithPrioritiesAndNotificationContent?.^[#this.Priority == 2] ?: (#decisionsWithPrioritiesAndNotificationContent?.^[#this.Priority == 1]))" - }, - "additionalFields": { - "description": "We can apply various business rules to choose best decisions here", - "layoutData": { - "x": 360, - "y": 2340 - } - }, - "type": "Variable" - }, - { - "defaultNext": [ - ], - "nexts": [ - { - "expression": { - "language": "spel", - "expression": "#decision?.Consent == \"SMS\"" - }, - "nodes": [ - { - "id": "SMS", - "ref": { - "typ": "kafka", - "parameters": [ - { - "name": "Topic", - "expression": { - "language": "spel", - "expression": "'GeoLocationsOutputSms'" - } - }, - { - "name": "Schema version", - "expression": { - "language": "spel", - "expression": "'latest'" - } - }, - { - "name": "Key", - "expression": { - "language": "spel", - "expression": "" - } - }, - { - "name": "Raw editor", - "expression": { - "language": "spel", - "expression": "false" - } - }, - { - "name": "msisdn", - "expression": { - "language": "spel", - "expression": "#clientData.msisdn" - } - }, - { - "name": "content", - "expression": { - "language": "spel", - "expression": "#decision['Notification content']" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 0, - "y": 2700 - } - }, - "type": "Sink" - } - ] - }, - { - "expression": { - "language": "spel", - "expression": "#decision?.Consent == \"EMAIL\"" - }, - "nodes": [ - { - "id": "EMAIL", - "ref": { - "typ": "kafka", - "parameters": [ - { - "name": "Topic", - "expression": { - "language": "spel", - "expression": "'GeoLocationsOutputEmail'" - } - }, - { - "name": "Schema version", - "expression": { - "language": "spel", - "expression": "'latest'" - } - }, - { - "name": "Key", - "expression": { - "language": "spel", - "expression": "" - } - }, - { - "name": "Raw editor", - "expression": { - "language": "spel", - "expression": "false" - } - }, - { - "name": "email", - "expression": { - "language": "spel", - "expression": "#clientData.email" - } - }, - { - "name": "content", - "expression": { - "language": "spel", - "expression": "#decision['Notification content']" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 360, - "y": 2700 - } - }, - "type": "Sink" - } - ] - }, - { - "expression": { - "language": "spel", - "expression": "#decision?.Consent == 'PUSH'" - }, - "nodes": [ - { - "id": "PUSH", - "ref": { - "typ": "kafka", - "parameters": [ - { - "name": "Topic", - "expression": { - "language": "spel", - "expression": "'GeoLocationsOutputPush'" - } - }, - { - "name": "Schema version", - "expression": { - "language": "spel", - "expression": "'latest'" - } - }, - { - "name": "Key", - "expression": { - "language": "spel", - "expression": "" - } - }, - { - "name": "Raw editor", - "expression": { - "language": "spel", - "expression": "false" - } - }, - { - "name": "msisdn", - "expression": { - "language": "spel", - "expression": "#clientData.msisdn" - } - }, - { - "name": "content", - "expression": { - "language": "spel", - "expression": "#decision['Notification content']" - } - } - ] - }, - "endResult": null, - "isDisabled": null, - "additionalFields": { - "description": null, - "layoutData": { - "x": 720, - "y": 2700 - } - }, - "type": "Sink" - } - ] - } - ], - "id": "split by notification type", - "expression": null, - "exprVal": null, - "additionalFields": { - "description": "We direct the results to the appropriate topic", - "layoutData": { - "x": 360, - "y": 2520 - } - }, - "type": "Switch" - } - ], - "additionalBranches": [ - ] -} \ No newline at end of file diff --git a/scenario-examples/rtm-client-near-pos/data/kafka/generated/geoLocations.sh b/scenario-examples/rtm-client-near-pos/data/kafka/generated/geoLocations.sh deleted file mode 100755 index 3f247ee9..00000000 --- a/scenario-examples/rtm-client-near-pos/data/kafka/generated/geoLocations.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -e - -cd "$(dirname "$0")" - -source /app/utils/lib.sh - -case $(($(random_1digit_number) % 3)) in - 0) - LAT="52.23$(random_3digit_number)" - LON="21.01$(random_3digit_number)" - ;; - 1) - LAT="50.04$(random_3digit_number)" - LON="19.94$(random_3digit_number)" - ;; - *) - LAT="51.10$(random_3digit_number)" - LON="17.03$(random_3digit_number)" - ;; -esac - -CLIENT_ID=$(random_1digit_number) -TIME=$(date +%s) - -echo "{\"clientId\": $CLIENT_ID, \"geo\": { \"lat\": $LAT, \"lon\": $LON }, \"eventTime\": $TIME }" diff --git a/scenario-examples/rtm-client-near-pos/data/kafka/static/geoLocations.txt b/scenario-examples/rtm-client-near-pos/data/kafka/static/geoLocations.txt deleted file mode 100644 index 84c8efc8..00000000 --- a/scenario-examples/rtm-client-near-pos/data/kafka/static/geoLocations.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Example messages below (message per line) -# {"clientId": 1,"geo": {"lat": 52.237049, "lon": 21.017532},"eventTime": 1720166429} -# {"clientId": 9,"geo": {"lat": 51.107883, "lon": 17.038538},"eventTime": 1720166429} diff --git a/scenario-examples/rtm-client-near-pos/mocks/db/rtm_near_pos.sql b/scenario-examples/rtm-client-near-pos/mocks/db/rtm_near_pos.sql deleted file mode 100644 index 6079bbf0..00000000 --- a/scenario-examples/rtm-client-near-pos/mocks/db/rtm_near_pos.sql +++ /dev/null @@ -1,61 +0,0 @@ --- cleanup for the sake idempotent run -drop table if exists contact_history; -drop table if exists blocked_list; -drop table if exists client; -drop table if exists pos; -drop type if exists consent_enum; -drop type if exists client_type_enum; - -create table pos -( - id SERIAL PRIMARY KEY, - location_lat NUMERIC(10, 6) NOT NULL, - location_lon NUMERIC(10, 6) NOT NULL, - open_hour TIME NOT NULL, - close_hour TIME NOT NULL -); - -create type consent_enum AS ENUM ('SMS', 'EMAIL', 'PUSH', 'SMS_EMAIL', 'EMAIL_PUSH', 'SMS_PUSH', 'SMS_EMAIL_PUSH'); -create type client_type_enum AS ENUM ('INDIVIDUAL', 'BUSINESS'); - -create table client -( - id SERIAL PRIMARY KEY, - pos_id SERIAL REFERENCES pos(id) NOT NULL, - msisdn CHAR(11), - email VARCHAR(100), - consents consent_enum, - client_type client_type_enum NOT NULL -); - -create table blocked_list( - client_id INT PRIMARY KEY references client(id) -); - -create table contact_history( - id SERIAL PRIMARY KEY, - client_id INT NOT NULL references client(id), - event_time TIMESTAMP NOT NULL -); - ----- POS -insert into pos(id, location_lat, location_lon, open_hour, close_hour) VALUES (1, 52.237049, 21.017532, '00:00:00', '23:59:59'); -insert into pos(id, location_lat, location_lon, open_hour, close_hour) VALUES (2, 50.049683, 19.944544, '08:00:00', '15:00:00'); -insert into pos(id, location_lat, location_lon, open_hour, close_hour) VALUES (3, 51.107883, 17.038538, '00:00:00', '23:59:59'); - ----- Clients -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (1, 1, '48500500500', 'jan.kowalski@nussknacker.io', 'SMS', 'INDIVIDUAL'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (2, 1, '48500500501', 'zbigniew.paleta@nussknacker.io', 'SMS_EMAIL', 'BUSINESS'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (3, 1, '48500500502', 'genia.nowak@nussknacker.io', 'PUSH', 'INDIVIDUAL'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (4, 2, '48500500503', 'klaudia.wisniewska@nussknacker.io', 'SMS_EMAIL_PUSH', 'INDIVIDUAL'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (5, 2, '48500500504', 'teofil.benc@nussknacker.io', 'EMAIL', 'BUSINESS'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (6, 2, '48500500505', 'zdzislaw.lecina@nussknacker.io', null, 'BUSINESS'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (7, 2, '48500500506', 'ksenia.gorka@nussknacker.io', 'EMAIL_PUSH', 'INDIVIDUAL'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (8, 3, '48500500507', 'anna.milkowska@nussknacker.io', 'SMS_PUSH', 'BUSINESS'); -insert into client(id, pos_id, msisdn, email, consents, client_type) VALUES (9, 3, '48500500508', 'john.doe@nussknacker.io', 'EMAIL', 'INDIVIDUAL'); - ----- Blocked -insert into blocked_list(client_id) values (5); - --- Contact history -insert into contact_history(client_id, event_time) VALUES (9, NOW() - INTERVAL '1 minutes'); diff --git a/scenario-examples/rtm-client-near-pos/setup/kafka/topics.txt b/scenario-examples/rtm-client-near-pos/setup/kafka/topics.txt deleted file mode 100644 index 5d9d2ae1..00000000 --- a/scenario-examples/rtm-client-near-pos/setup/kafka/topics.txt +++ /dev/null @@ -1,4 +0,0 @@ -GeoLocations -GeoLocationsOutputEmail -GeoLocationsOutputSms -GeoLocationsOutputPush diff --git a/scenario-examples/rtm-client-near-pos/setup/nu-designer/custom-configuration.conf b/scenario-examples/rtm-client-near-pos/setup/nu-designer/custom-configuration.conf deleted file mode 100644 index 61b3869e..00000000 --- a/scenario-examples/rtm-client-near-pos/setup/nu-designer/custom-configuration.conf +++ /dev/null @@ -1,41 +0,0 @@ -scenarioTypes { - "streaming" { - # customize Flink streaming scenario type - modelConfig { - components { - # Database entichers - "customersDataEnricher" { - providerType: databaseEnricher - config: { - databaseQueryEnricher { - name: "customers-data-query-enricher" - dbPool: ${rtmNearPosExampleDatabasePool} #refers to your database pool definition - } - databaseLookupEnricher { - name: "customers-data-lookup-enricher" - dbPool: ${rtmNearPosExampleDatabasePool} - } - } - } - "posDataEnricher" { - providerType: databaseEnricher - config: { - databaseLookupEnricher { - name: "pos-data-lookup-enricher" - dbPool: ${rtmNearPosExampleDatabasePool} - } - } - } - } - } - } -} - -# Database definition -rtmNearPosExampleDatabasePool { - driverClassName: "org.postgresql.Driver" - url: "jdbc:postgresql://quickstart-setup:5432/mocks" - username: "mocks" - password: "mocks_pass" - schema: "rtm_near_pos" -} diff --git a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocations.schema.json b/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocations.schema.json deleted file mode 100644 index 6e2aaa34..00000000 --- a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocations.schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "$schema": "http://json-schema.org/draft-07/schema", - "required": [ - "clientId", - "geo", - "eventTime" - ], - "properties": { - "geo": { - "type": "object", - "description": "This property contains geographical coordinates (latitude and longitude).", - "required": [ - "lat", - "lon" - ], - "properties": { - "lon": { - "type": "number", - "description": "Longitude coordinate." - }, - "lat": { - "type": "number", - "description": "Latitude coordinate." - } - } - }, - "clientId": { - "type": "integer", - "description": "A unique identifier for the client." - }, - "eventTime": { - "type": "integer", - "description": "A timestamp indicating the time of the event." - } - } -} diff --git a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputEmail.schema.json b/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputEmail.schema.json deleted file mode 100644 index 2d550d39..00000000 --- a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputEmail.schema.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "description": "A schema for a topic used to send emails.", - "$schema": "http://json-schema.org/draft-07/schema", - "required": [ - "email", - "content" - ], - "properties": { - "email": { - "type": "string", - "description": "The email address of the client." - }, - "content": { - "type": "string", - "description": "The content or message to be associated with the email." - } - } -} diff --git a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputPush.schema.json b/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputPush.schema.json deleted file mode 100644 index d9d2d2e6..00000000 --- a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputPush.schema.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "description": "A schema for a topic used to send pushes.", - "$schema": "http://json-schema.org/draft-07/schema", - "required": [ - "msisdn", - "content" - ], - "properties": { - "msisdn": { - "type": "string", - "description": "The phone number of the client." - }, - "content": { - "type": "string", - "description": "The content or message to be associated with the email." - } - } -} diff --git a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputSms.schema.json b/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputSms.schema.json deleted file mode 100644 index c86f7635..00000000 --- a/scenario-examples/rtm-client-near-pos/setup/schema-registry/GeoLocationsOutputSms.schema.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "description": "A schema for a topic used to send smses.", - "$schema": "http://json-schema.org/draft-07/schema", - "required": [ - "msisdn", - "content" - ], - "properties": { - "msisdn": { - "type": "string", - "description": "The phone number of the client." - }, - "content": { - "type": "string", - "description": "The content or message to be associated with the email." - } - } -}