diff --git a/README.md b/README.md index 82586a7c..df57750a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ The full documentation on Amido Stacks can be found [here](https://amido.github. ### Customised solution -To customise the namespaces and create an application for your company please visit the full [documentation](https://stacks.amido.com/docs/) +To customise the namespaces and create an application for your company please visit the +full [documentation](https://stacks.amido.com/docs/) ### Running the application locally @@ -12,19 +13,26 @@ To customise the namespaces and create an application for your company please vi --- 1. Simple web API: [stacks-java repository](https://github.com/amido/stacks-java) 2. Web API with CQRS: [stacks-java-cqrs repository](https://github.com/amido/stacks-java-cqrs) - 3. Web API with CQRS and events: [stacks-java-cqrs-events repository](https://github.com/amido/stacks-java-cqrs-events) + 3. Web API with CQRS and + events: [stacks-java-cqrs-events repository](https://github.com/amido/stacks-java-cqrs-events) 2. Configure required environment variables --- The application is currently configured to work with the Azure environment. - It uses an Azure **CosmosDB** database to store the example application data. So you should have access to an instance to use with the application. - Note: For running on a local Windows environment you can use the [Cosmos DB emulator](docs/workloads/azure/backend/java/setting_up_cosmos_db_locally_java.md) (CosmosDB Emulator has a known fixed key). There is no need for CosmosDB for the simple web API implementation (1.i above) as there is no persistence layer in it. - For further info please follow the [link](https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator?tabs=ssl-netstd21). + It uses an Azure **CosmosDB** database to store the example application data. So you should have + access to an instance to use with the application. Note: For running on a local Windows + environment you can use + the [Cosmos DB emulator](docs/workloads/azure/backend/java/setting_up_cosmos_db_locally_java.md) ( + CosmosDB Emulator has a known fixed key). There is no need for CosmosDB for the simple web API + implementation (1.i above) as there is no persistence layer in it. For further info please follow + the [link](https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator?tabs=ssl-netstd21). --- - In addition, Azure **ApplicationInsights** is used for logging purposes. If this is unavailable, modify the application so that it doesn't fail to startup if it can't access ApplicationInsights, and simply log to the terminal instead. + In addition, Azure **ApplicationInsights** is used for logging purposes. If this is unavailable, + modify the application so that it doesn't fail to startup if it can't access ApplicationInsights, + and simply log to the terminal instead. ```yaml application-insights: @@ -32,7 +40,8 @@ To customise the namespaces and create an application for your company please vi enabled: false ``` - There are two corresponding environment variables that need to be set to interact with these systems: + There are two corresponding environment variables that need to be set to interact with these + systems: ```text AZURE_COSMOSDB_KEY @@ -65,19 +74,22 @@ To customise the namespaces and create an application for your company please vi mvnw.cmd spring-boot:run ``` - For instructions on how to customise the project for your company please look in the [Scaffolding](docs/workloads/azure/backend/java/scaffolding_java.md) section + For instructions on how to customise the project for your company please look in + the [Scaffolding](docs/workloads/azure/backend/java/scaffolding_java.md) section 4. Build and run the application using Cosmos DB Emulator --- - Please refer to section "Determine which root certificates have been installed" in [Setting Up CosmosDB Emulator](docs/workloads/azure/backend/java/setting_up_cosmos_db_locally_java.md) + Please refer to section "Determine which root certificates have been installed" + in [Setting Up CosmosDB Emulator](docs/workloads/azure/backend/java/setting_up_cosmos_db_locally_java.md) - Move to the `/java` folder, then - go to `application.yml` either comment out the `application-insights` block or set `enabled` property to `false`. - In `logback-spring.xml` comment out the application-insight section. + Move to the `/java` folder, then go to `application.yml` either comment out + the `application-insights` block or set `enabled` property to `false`. In `logback-spring.xml` + comment out the application-insight section. ![logback](/img/logback_xml.png) - Set `AZURE_COSMOSDB_KEY` as an environment variable and set the value to be the primary key value on the emulator. + Set `AZURE_COSMOSDB_KEY` as an environment variable and set the value to be the primary key value + on the emulator.
For UNIX systems do: @@ -94,38 +106,45 @@ To customise the namespaces and create an application for your company please vi 5. Verify that the application has started --- - Browse to [http://localhost:9000/v1/menu](http://localhost:9000/v1/menu). This should return a valid JSON response. + Browse to [http://localhost:9000/v1/menu](http://localhost:9000/v1/menu). This should return a + valid JSON response. - The application configuration uses Swagger/OAS3 to represent the API endpoints. The Swagger UI can be viewed by directing your - browser to [http://localhost:9000/swagger/index.html](http://localhost:9000/swagger/index.html). + The application configuration uses Swagger/OAS3 to represent the API endpoints. The Swagger UI + can be viewed by directing your browser + to [http://localhost:9000/swagger/index.html](http://localhost:9000/swagger/index.html). ### Authorization -All API endpoints are (optionally) protected using **Auth0**. There is an `auth.properties` file within the project codebase. -If the following property within this file is set: +All API endpoints are (optionally) protected using **Auth0**. There is an `auth.properties` file +within the project codebase. If the following property within this file is set: ```text auth.isEnabled=true + ``` -then clients will need to pass an `Authorization` header containing the Bearer token generated from Auth0 as part of the endpoint request. If the value -is set to `false` then no authorization is required. +then clients will need to pass an `Authorization` header containing the Bearer token generated from +Auth0 as part of the endpoint request. If the value is set to `false` then no authorization is +required. #### Auth0 configuration properties -If using Auth0 for authorization, Auth0 itself will need to be configured with both an API definition and an associated Application. -There are corresponding configuration values required for the Stacks application, within the `auth.properties` file, e.g. +If using Auth0 for authorization, Auth0 itself will need to be configured with both an API +definition and an associated Application. There are corresponding configuration values required for +the Stacks application, within the `auth.properties` file, e.g. ```text auth0.issuer=https://amidostacks.eu.auth0.com/ auth0.apiAudience=https://amidostacks.eu.auth0.com/api/v2/ ``` -These parameters are used to verify that the JWT supplied in the Authorization header of a request is valid. +These parameters are used to verify that the JWT supplied in the Authorization header of a request +is valid. #### Swagger/OAS -- Automatically generated for the project. Go to [Swagger Index](http://localhost:9000/swagger/index.html) to view. +- Automatically generated for the project. Go + to [Swagger Index](http://localhost:9000/swagger/index.html) to view. - Swagger Json is here: [Swagger Json](http://localhost:9000/swagger/oas.json) #### Health check @@ -145,7 +164,8 @@ From the `/java` folder, build a Docker image using e.g. the comma This uses the `Dockerfile` in this folder to generate the Docker image. -If you have an `.m2` directory in the `java/` folder, the Docker build will attempt to copy the files inside the container and use the cached versions. +If you have an `.m2` directory in the `java/` folder, the Docker build will attempt to copy the +files inside the container and use the cached versions. Once the Docker image is created, you can then run a Docker container based on this image using e.g. diff --git a/java/deploy_scenario.sh b/java/deploy_scenario.sh new file mode 100644 index 00000000..5a6fc179 --- /dev/null +++ b/java/deploy_scenario.sh @@ -0,0 +1,280 @@ +#!/bin/bash +# from SO: https://stackoverflow.com/a/54261882/317605 (by https://stackoverflow.com/users/8207842/dols3m) +function prompt_for_multiselect { + + # little helpers for terminal print control and key input + ESC=$( printf "\033") + + cursor_blink_on() { printf "$ESC[?25h"; } + cursor_blink_off() { printf "$ESC[?25l"; } + cursor_to() { printf "$ESC[$1;${2:-1}H"; } + print_inactive() { printf "$2 $1 "; } + print_active() { printf "$2 $ESC[7m $1 $ESC[27m"; } + get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } + + key_input() { + local key + IFS= read -rsn1 key 2>/dev/null >&2 + if [[ $key = "" ]]; then echo enter; fi; + if [[ $key = $'\x20' ]]; then echo space; fi; + if [[ $key = $'\x1b' ]]; then + read -rsn2 key + if [[ $key = [A ]]; then echo up; fi; + if [[ $key = [B ]]; then echo down; fi; + fi + } + + toggle_option() { + local arr_name=$1 + eval "local arr=(\"\${${arr_name}[@]}\")" + local option=$2 + if [[ ${arr[option]} == true ]]; then + arr[option]= + else + arr[option]=true + fi + eval $arr_name='("${arr[@]}")' + } + + local retval=$1 + local options + local defaults + + IFS=';' read -r -a options <<< "$2" + if [[ -z $3 ]]; then + defaults=() + else + IFS=';' read -r -a defaults <<< "$3" + fi + local selected=() + + for ((i=0; i<${#options[@]}; i++)); do + selected+=("${defaults[i]:-false}") + printf "\n" + done + + # determine current screen position for overwriting the options + local lastrow=`get_cursor_row` + local startrow=$(($lastrow - ${#options[@]})) + + # ensure cursor and input echoing back on upon a ctrl+c during read -s + trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 + cursor_blink_off + + local active=0 + while true; do + # print options by overwriting the last lines + local idx=0 + for option in "${options[@]}"; do + local prefix=" [ ]" + if [[ ${selected[idx]} == true ]]; then + prefix=" [x]" + fi + + cursor_to $(($startrow + $idx)) + if [ $idx -eq $active ]; then + print_active "$option" "$prefix" + else + print_inactive "$option" "$prefix" + fi + ((idx++)) + done + + # user key control + case `key_input` in + space) toggle_option selected $active;; + enter) break;; + up) ((active--)); + if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;; + down) ((active++)); + if [ $active -ge ${#options[@]} ]; then active=0; fi;; + esac + done + + # cursor position back to normal + cursor_to $lastrow + printf "\n" + cursor_blink_on + + eval $retval='("${selected[@]}")' +} + +function delete_from_array { + + local retval=$1 + delete="$2" + array=("${@:3}") + + for target in "${delete[@]}"; do + for i in "${!array[@]}"; do + if [[ ${array[i]} = $target ]]; then + unset 'array[i]' + fi + done + done + + eval $retval='("${array[@]}")' + +} + +function array_contains_element { + local e match="$1" + shift + for e; do [[ "$e" == "$match" ]] && return 0; done + return 1 +} + +function check_environment { + + if ! command -v xmlstarlet &> /dev/null + then + printf "\n ERROR: Utility 'xmlstarlet' could not be found, please install from : http://xmlstar.sourceforge.net/doc/UG/index.html\n\n" + exit 1 + fi + +} + +##################### +##################### + +check_environment + +declare -a ALL_SPRING_PROFILES=(aws azure cosmosdb dynamodb servicebus kafka sqs) + +BASE_FOLDER="." + +printf "\n" + +##################### + +unset OPTIONS_STRING OPTIONS_SELECTED_STRING + +printf "1. Please select the Cloud required:\n\n" + +OPTIONS_VALUES=("azure" "aws") +OPTIONS_LABELS=("Azure Cloud" "AWS Cloud") +OPTIONS_SELECTED=("true" "true") + +for i in "${!OPTIONS_VALUES[@]}"; do + OPTIONS_STRING+="${OPTIONS_VALUES[$i]} (${OPTIONS_LABELS[$i]});" + OPTIONS_SELECTED_STRING+="${OPTIONS_SELECTED[$i]};" +done + +prompt_for_multiselect SELECTED "$OPTIONS_STRING" "$OPTIONS_SELECTED_STRING" + +for i in "${!SELECTED[@]}"; do + if [ "${SELECTED[$i]}" == "true" ]; then + CHECKED+=("${OPTIONS_VALUES[$i]}") + delete_from_array ALL_SPRING_PROFILES "${OPTIONS_VALUES[$i]}" "${ALL_SPRING_PROFILES[@]}" + fi +done +# echo "${CHECKED[@]}" + +##################### + +unset OPTIONS_STRING OPTIONS_SELECTED_STRING + +printf "2. Please select the Persistence required:\n\n" + +OPTIONS_VALUES=("cosmosdb" "dynamodb") +OPTIONS_LABELS=("CosmosDB" "DynamoDB") +OPTIONS_SELECTED=("true" "") + +for i in "${!OPTIONS_VALUES[@]}"; do + OPTIONS_STRING+="${OPTIONS_VALUES[$i]} (${OPTIONS_LABELS[$i]});" + OPTIONS_SELECTED_STRING+="${OPTIONS_SELECTED[$i]};" +done + +prompt_for_multiselect SELECTED "$OPTIONS_STRING" "$OPTIONS_SELECTED_STRING" + +for i in "${!SELECTED[@]}"; do + if [ "${SELECTED[$i]}" == "true" ]; then + CHECKED+=("${OPTIONS_VALUES[$i]}") + delete_from_array ALL_SPRING_PROFILES "${OPTIONS_VALUES[$i]}" "${ALL_SPRING_PROFILES[@]}" + fi +done + +##################### + +unset OPTIONS_STRING OPTIONS_SELECTED_STRING + +printf "3. Please select the Message Handler required:\n\n" + +OPTIONS_VALUES=("servicebus" "kafka" "sqs") +OPTIONS_LABELS=("Azure ServiceBus" "AWS Kafka" "AWS SQS") +OPTIONS_SELECTED=("true" "" "") + +for i in "${!OPTIONS_VALUES[@]}"; do + OPTIONS_STRING+="${OPTIONS_VALUES[$i]} (${OPTIONS_LABELS[$i]});" + OPTIONS_SELECTED_STRING+="${OPTIONS_SELECTED[$i]};" +done + +prompt_for_multiselect SELECTED "$OPTIONS_STRING" "$OPTIONS_SELECTED_STRING" + +for i in "${!SELECTED[@]}"; do + if [ "${SELECTED[$i]}" == "true" ]; then + CHECKED+=("${OPTIONS_VALUES[$i]}") + delete_from_array ALL_SPRING_PROFILES "${OPTIONS_VALUES[$i]}" "${ALL_SPRING_PROFILES[@]}" + fi +done + +##################### + +printf "You have selected these options for your project:\n\n" +for i in "${CHECKED[@]}"; +do + printf " * %s\n" "${i}" + MAVEN_SPECIFIC_PROFILES+="${i}," +done + +printf "\nPress ENTER to accept or CTRL-C to quit" +read -r + +##################### + +cp ${BASE_FOLDER}/pom.xml ${BASE_FOLDER}/pom.template.xml + +printf "" +#echo "DELETE THESE..." +for i in "${ALL_SPRING_PROFILES[@]}"; +do + #echo "$i" + + xmlstarlet edit -N ns='http://maven.apache.org/POM/4.0.0' \ + --delete ".//ns:project/ns:properties/ns:${i}.profile.name" \ + --delete ".//ns:project/ns:profiles/ns:profile[ns:id=\"${i}\"]" \ + ${BASE_FOLDER}/pom.template.xml > ${BASE_FOLDER}/pom.template.xml.work + + mv ${BASE_FOLDER}/pom.template.xml.work ${BASE_FOLDER}/pom.template.xml + + sed -i "" "/- \"@${i}.profile.name@\"/d" ${BASE_FOLDER}/src/main/resources/application.yml + + rm -f "${BASE_FOLDER}/src/main/resources/application-${i}.yml" + rm -f "${BASE_FOLDER}/src/main/resources/local/application-${i}.yml" + +done + +#echo "KEEP THESE..." +for i in "${CHECKED[@]}"; +do + #echo "$i" + + xmlstarlet edit -N ns='http://maven.apache.org/POM/4.0.0' \ + --move ".//ns:project/ns:profiles/ns:profile[ns:id=\"${i}\"]/ns:dependencies/*" ".//ns:project/ns:dependencies" \ + ${BASE_FOLDER}/pom.template.xml > ${BASE_FOLDER}/pom.template.xml.work + + mv ${BASE_FOLDER}/pom.template.xml.work ${BASE_FOLDER}/pom.template.xml + + xmlstarlet edit -N ns='http://maven.apache.org/POM/4.0.0' \ + --delete ".//ns:project/ns:properties/ns:${i}.profile.name" \ + --delete ".//ns:project/ns:profiles/ns:profile[ns:id=\"${i}\"]" \ + ${BASE_FOLDER}/pom.template.xml > ${BASE_FOLDER}/pom.template.xml.work + + mv ${BASE_FOLDER}/pom.template.xml.work ${BASE_FOLDER}/pom.template.xml + + sed -i "" "s/- \"@${i}.profile.name@\"/- ${i}/g" ${BASE_FOLDER}/src/main/resources/application.yml + +done + +cp ${BASE_FOLDER}/pom.template.xml ${BASE_FOLDER}/pom.xml +rm -f ${BASE_FOLDER}/pom.template.xml diff --git a/java/pom.xml b/java/pom.xml index e37fbd2f..12bf173e 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -20,8 +20,14 @@ + + no-aws + no-azure + no-cosmosdb + no-dynamodb + 1.0.3 - 1.0.2.2-RELEASE + 1.0.3.2-RELEASE 1.0.0 1.0.0 @@ -31,10 +37,9 @@ 2.6.3 3.6.0 3.6.0 - 7.3.0 2.12.3 3.11.2 - 1.18.20 + 1.18.24 2.2 1.6.7 0.8.7 @@ -56,14 +61,6 @@ 4.5.2 3.0.0 - - - - - - - - 4.0.10 4.3.2 @@ -94,11 +91,7 @@ stacks-core-commons ${stacks.core.commons.version} - - com.amido.stacks.modules - stacks-azure-cosmos - ${stacks.azure.cosmos.version} - + com.amido.stacks.modules stacks-core-api @@ -252,36 +245,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - com.coveo @@ -378,6 +341,64 @@ + + + aws + + + . + + + + aws + + + + + + + azure + + + . + + + + azure + + + + + + + cosmosdb + + + . + + + + cosmosdb + + + + com.amido.stacks.modules + stacks-azure-cosmos + ${stacks.azure.cosmos.version} + + + + + + dynamodb + + dynamodb + + + + + + owasp-dependency-check diff --git a/java/run_scenario.sh b/java/run_scenario.sh new file mode 100644 index 00000000..24df168d --- /dev/null +++ b/java/run_scenario.sh @@ -0,0 +1,261 @@ +#!/bin/bash +# from SO: https://stackoverflow.com/a/54261882/317605 (by https://stackoverflow.com/users/8207842/dols3m) +function prompt_for_multiselect { + + # little helpers for terminal print control and key input + ESC=$( printf "\033") + + cursor_blink_on() { printf "$ESC[?25h"; } + cursor_blink_off() { printf "$ESC[?25l"; } + cursor_to() { printf "$ESC[$1;${2:-1}H"; } + print_inactive() { printf "$2 $1 "; } + print_active() { printf "$2 $ESC[7m $1 $ESC[27m"; } + get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } + + key_input() { + local key + IFS= read -rsn1 key 2>/dev/null >&2 + if [[ $key = "" ]]; then echo enter; fi; + if [[ $key = $'\x20' ]]; then echo space; fi; + if [[ $key = $'\x1b' ]]; then + read -rsn2 key + if [[ $key = [A ]]; then echo up; fi; + if [[ $key = [B ]]; then echo down; fi; + fi + } + + toggle_option() { + local arr_name=$1 + eval "local arr=(\"\${${arr_name}[@]}\")" + local option=$2 + if [[ ${arr[option]} == true ]]; then + arr[option]= + else + arr[option]=true + fi + eval $arr_name='("${arr[@]}")' + } + + local retval=$1 + local options + local defaults + + IFS=';' read -r -a options <<< "$2" + if [[ -z $3 ]]; then + defaults=() + else + IFS=';' read -r -a defaults <<< "$3" + fi + local selected=() + + for ((i=0; i<${#options[@]}; i++)); do + selected+=("${defaults[i]:-false}") + printf "\n" + done + + # determine current screen position for overwriting the options + local lastrow=`get_cursor_row` + local startrow=$(($lastrow - ${#options[@]})) + + # ensure cursor and input echoing back on upon a ctrl+c during read -s + trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 + cursor_blink_off + + local active=0 + while true; do + # print options by overwriting the last lines + local idx=0 + for option in "${options[@]}"; do + local prefix=" [ ]" + if [[ ${selected[idx]} == true ]]; then + prefix=" [x]" + fi + + cursor_to $(($startrow + $idx)) + if [ $idx -eq $active ]; then + print_active "$option" "$prefix" + else + print_inactive "$option" "$prefix" + fi + ((idx++)) + done + + # user key control + case `key_input` in + space) toggle_option selected $active;; + enter) break;; + up) ((active--)); + if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;; + down) ((active++)); + if [ $active -ge ${#options[@]} ]; then active=0; fi;; + esac + done + + # cursor position back to normal + cursor_to $lastrow + printf "\n" + cursor_blink_on + + eval $retval='("${selected[@]}")' +} + +function delete_from_array { + + local retval=$1 + delete="$2" + array=("${@:3}") + + for target in "${delete[@]}"; do + for i in "${!array[@]}"; do + if [[ ${array[i]} = $target ]]; then + unset 'array[i]' + fi + done + done + + eval $retval='("${array[@]}")' + +} + +function array_contains_element { + local e match="$1" + shift + for e; do [[ "$e" == "$match" ]] && return 0; done + return 1 +} + +function check_environment { + + if ! command -v xmlstarlet &> /dev/null + then + printf "\n ERROR: Utility 'xmlstarlet' could not be found, please install from : http://xmlstar.sourceforge.net/doc/UG/index.html\n\n" + exit 1 + fi + +} + +##################### +##################### + +check_environment + +declare -a ALL_SPRING_PROFILES=(aws azure cosmosdb dynamodb servicebus kafka sqs) + +BASE_FOLDER="." + +printf "\n" + +##################### + +# shellcheck disable=SC2207 +DEFAULT_POM_PROFILES=($(xmlstarlet sel -N ns='http://maven.apache.org/POM/4.0.0' \ + -t -m ".//ns:project/ns:profiles/ns:profile[ns:activation]" -v "concat(ns:id,',')" pom.xml | tr ',' '\n')) + +##################### + +unset OPTIONS_STRING OPTIONS_SELECTED_STRING + +printf "1. Please select the Cloud required:\n\n" + +OPTIONS_VALUES=("azure" "aws") +OPTIONS_LABELS=("Azure Cloud" "AWS Cloud") +OPTIONS_SELECTED=("true" "true") + +for i in "${!OPTIONS_VALUES[@]}"; do + OPTIONS_STRING+="${OPTIONS_VALUES[$i]} (${OPTIONS_LABELS[$i]});" + OPTIONS_SELECTED_STRING+="${OPTIONS_SELECTED[$i]};" +done + +prompt_for_multiselect SELECTED "$OPTIONS_STRING" "$OPTIONS_SELECTED_STRING" + +for i in "${!SELECTED[@]}"; do + if [ "${SELECTED[$i]}" == "true" ]; then + CHECKED+=("${OPTIONS_VALUES[$i]}") + delete_from_array ALL_SPRING_PROFILES "${OPTIONS_VALUES[$i]}" "${ALL_SPRING_PROFILES[@]}" + fi +done +# echo "${CHECKED[@]}" + +##################### + +unset OPTIONS_STRING OPTIONS_SELECTED_STRING + +printf "2. Please select the Persistence required:\n\n" + +OPTIONS_VALUES=("cosmosdb" "dynamodb") +OPTIONS_LABELS=("CosmosDB" "DynamoDB") +OPTIONS_SELECTED=("true" "") + +for i in "${!OPTIONS_VALUES[@]}"; do + OPTIONS_STRING+="${OPTIONS_VALUES[$i]} (${OPTIONS_LABELS[$i]});" + OPTIONS_SELECTED_STRING+="${OPTIONS_SELECTED[$i]};" +done + +prompt_for_multiselect SELECTED "$OPTIONS_STRING" "$OPTIONS_SELECTED_STRING" + +for i in "${!SELECTED[@]}"; do + if [ "${SELECTED[$i]}" == "true" ]; then + CHECKED+=("${OPTIONS_VALUES[$i]}") + delete_from_array ALL_SPRING_PROFILES "${OPTIONS_VALUES[$i]}" "${ALL_SPRING_PROFILES[@]}" + fi +done + +##################### + +unset OPTIONS_STRING OPTIONS_SELECTED_STRING + +printf "3. Please select the Message Handler required:\n\n" + +OPTIONS_VALUES=("servicebus" "kafka" "sqs") +OPTIONS_LABELS=("Azure ServiceBus" "AWS Kafka" "AWS SQS") +OPTIONS_SELECTED=("true" "" "") + +for i in "${!OPTIONS_VALUES[@]}"; do + OPTIONS_STRING+="${OPTIONS_VALUES[$i]} (${OPTIONS_LABELS[$i]});" + OPTIONS_SELECTED_STRING+="${OPTIONS_SELECTED[$i]};" +done + +prompt_for_multiselect SELECTED "$OPTIONS_STRING" "$OPTIONS_SELECTED_STRING" + +for i in "${!SELECTED[@]}"; do + if [ "${SELECTED[$i]}" == "true" ]; then + CHECKED+=("${OPTIONS_VALUES[$i]}") + delete_from_array ALL_SPRING_PROFILES "${OPTIONS_VALUES[$i]}" "${ALL_SPRING_PROFILES[@]}" + fi +done + +##################### + +MAVEN_SPECIFIC_PROFILES="" + +##################### + +printf "You have selected these options for your project:\n\n" +for i in "${CHECKED[@]}"; +do + printf " * %s\n" "${i}" + MAVEN_SPECIFIC_PROFILES+="${i}," +done + +##################### + +## If any of the POM PROFILES are not checked and in the ones that are left then we need to switch +## them off else they'll be added by default + +for i in "${ALL_SPRING_PROFILES[@]}"; +do + if array_contains_element "${i}" "${DEFAULT_POM_PROFILES[@]}"; then + MAVEN_SPECIFIC_PROFILES+="-${i}," + fi +done + +# shellcheck disable=SC2001 +MAVEN_SPECIFIC_PROFILES_FIXED="$(echo "${MAVEN_SPECIFIC_PROFILES}" | sed 's/,$//g')" + +printf "\nAbout to execute:\n" +printf "\n mvn clean spring-boot:run -P%s\n" "${MAVEN_SPECIFIC_PROFILES_FIXED}" + +printf "\n\nPress ENTER to accept or CTRL-C to quit" +read -r + +mvn clean spring-boot:run -P"${MAVEN_SPECIFIC_PROFILES_FIXED}" \ No newline at end of file diff --git a/java/src/main/java/com/amido/stacks/workloads/menu/api/v1/SecretsController.java b/java/src/main/java/com/amido/stacks/workloads/menu/api/v1/SecretsController.java new file mode 100644 index 00000000..46643dd2 --- /dev/null +++ b/java/src/main/java/com/amido/stacks/workloads/menu/api/v1/SecretsController.java @@ -0,0 +1,25 @@ +package com.amido.stacks.workloads.menu.api.v1; + +import com.amido.stacks.workloads.menu.service.v1.SecretsService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping( + path = "/v1/secrets", + produces = MediaType.APPLICATION_JSON_VALUE + "; charset=utf-8") +@RequiredArgsConstructor +public class SecretsController { + + private final SecretsService secretsService; + + @GetMapping + public ResponseEntity getSecrets() { + + return ResponseEntity.ok(secretsService.getSecrets()); + } +} diff --git a/java/src/main/java/com/amido/stacks/workloads/menu/repository/MenuRepository.java b/java/src/main/java/com/amido/stacks/workloads/menu/repository/MenuRepository.java index aabd549d..225d4a2f 100644 --- a/java/src/main/java/com/amido/stacks/workloads/menu/repository/MenuRepository.java +++ b/java/src/main/java/com/amido/stacks/workloads/menu/repository/MenuRepository.java @@ -1,13 +1,13 @@ package com.amido.stacks.workloads.menu.repository; +import com.amido.stacks.cosmosdb.repository.StacksCosmosRepository; import com.amido.stacks.workloads.menu.domain.Menu; -import com.azure.spring.data.cosmos.repository.CosmosRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @Repository -public interface MenuRepository extends CosmosRepository { +public interface MenuRepository extends StacksCosmosRepository { @Override Menu save(Menu menu); diff --git a/java/src/main/java/com/amido/stacks/workloads/menu/service/v1/SecretsService.java b/java/src/main/java/com/amido/stacks/workloads/menu/service/v1/SecretsService.java new file mode 100644 index 00000000..931e9b5e --- /dev/null +++ b/java/src/main/java/com/amido/stacks/workloads/menu/service/v1/SecretsService.java @@ -0,0 +1,33 @@ +package com.amido.stacks.workloads.menu.service.v1; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class SecretsService { + + @Value(value = "${stacks-secret-1:secret-not-available}") + private String secret1; + + @Value(value = "${stacks-secret-2:secret-not-available}") + private String secret2; + + @Value(value = "${stacks-secret-3:secret-not-available}") + private String secret3; + + @Value(value = "${stacks-secret-4:secret-not-available}") + private String secret4; + + public String getSecrets() { + + log.info("Getting some secrets..."); + + return showSecrets(); + } + + private String showSecrets() { + return "Secrets -> " + secret1 + ", " + secret2 + ", " + secret3 + ", " + secret4; + } +} diff --git a/java/src/main/resources/application-aws.yml b/java/src/main/resources/application-aws.yml new file mode 100644 index 00000000..22d8e757 --- /dev/null +++ b/java/src/main/resources/application-aws.yml @@ -0,0 +1,10 @@ +aws: + xray: + enabled: ${AWS_XRAY_ENABLED:false} + secretsmanager: + enabled: ${AWS_SECRETS_ENABLED:false} + +# AWS Secrets Manager imports +spring.config.import: + - optional:aws-secretsmanager:/stacks-secret/example-1/ + - optional:aws-secretsmanager:/stacks-secret/example-2/ diff --git a/java/src/main/resources/application-azure.yml b/java/src/main/resources/application-azure.yml new file mode 100644 index 00000000..1d2be838 --- /dev/null +++ b/java/src/main/resources/application-azure.yml @@ -0,0 +1,10 @@ +azure: + application-insights: + instrumentation-key: xxxxxx + enabled: false + keyvault: + enabled: false + uri: https://amido-stacks-tmp.vault.azure.net/ + client-id: xxxxxx + client-key: xxxxxx + tenant-id: xxxxxx diff --git a/java/src/main/resources/application-cosmosdb.yml b/java/src/main/resources/application-cosmosdb.yml new file mode 100644 index 00000000..2db32bbb --- /dev/null +++ b/java/src/main/resources/application-cosmosdb.yml @@ -0,0 +1,5 @@ +azure: + cosmos: + uri: https://localhost:8081 + database: Stacks + key: ${COSMOSDB_KEY} diff --git a/java/src/main/resources/application-dynamodb.yml b/java/src/main/resources/application-dynamodb.yml new file mode 100644 index 00000000..e69de29b diff --git a/java/src/main/resources/application.yml b/java/src/main/resources/application.yml index 3d231594..7b37bb4d 100644 --- a/java/src/main/resources/application.yml +++ b/java/src/main/resources/application.yml @@ -1,4 +1,11 @@ spring: + profiles: + include: + - "@aws.profile.name@" + - "@azure.profile.name@" + - "@cosmosdb.profile.name@" + - "@dynamodb.profile.name@" + application: name: stacks-api-cqrs data: @@ -31,18 +38,3 @@ springdoc: enabled: true enabled: true path: /swagger/oas-json - -azure: - cosmos: - uri: https://localhost:8081 - database: Stacks - key: ${COSMOSDB_KEY} - application-insights: - instrumentation-key: xxxxxx - enabled: false - keyvault: - enabled: false - uri: https://amido-stacks-tmp.vault.azure.net/ - client-id: xxxxxx - client-key: xxxxxx - tenant-id: xxxxxx diff --git a/java/src/main/resources/local/application-aws.yml b/java/src/main/resources/local/application-aws.yml new file mode 100644 index 00000000..22d8e757 --- /dev/null +++ b/java/src/main/resources/local/application-aws.yml @@ -0,0 +1,10 @@ +aws: + xray: + enabled: ${AWS_XRAY_ENABLED:false} + secretsmanager: + enabled: ${AWS_SECRETS_ENABLED:false} + +# AWS Secrets Manager imports +spring.config.import: + - optional:aws-secretsmanager:/stacks-secret/example-1/ + - optional:aws-secretsmanager:/stacks-secret/example-2/ diff --git a/java/src/main/resources/local/application-azure.yml b/java/src/main/resources/local/application-azure.yml new file mode 100644 index 00000000..1d2be838 --- /dev/null +++ b/java/src/main/resources/local/application-azure.yml @@ -0,0 +1,10 @@ +azure: + application-insights: + instrumentation-key: xxxxxx + enabled: false + keyvault: + enabled: false + uri: https://amido-stacks-tmp.vault.azure.net/ + client-id: xxxxxx + client-key: xxxxxx + tenant-id: xxxxxx diff --git a/java/src/main/resources/local/application-cosmosdb.yml b/java/src/main/resources/local/application-cosmosdb.yml new file mode 100644 index 00000000..2db32bbb --- /dev/null +++ b/java/src/main/resources/local/application-cosmosdb.yml @@ -0,0 +1,5 @@ +azure: + cosmos: + uri: https://localhost:8081 + database: Stacks + key: ${COSMOSDB_KEY} diff --git a/java/src/main/resources/local/application-dynamodb.yml b/java/src/main/resources/local/application-dynamodb.yml new file mode 100644 index 00000000..e69de29b diff --git a/java/src/main/resources/local/application.yml b/java/src/main/resources/local/application.yml index a83400e3..bb7bdd9d 100644 --- a/java/src/main/resources/local/application.yml +++ b/java/src/main/resources/local/application.yml @@ -1,4 +1,11 @@ spring: + profiles: + include: + - aws + - azure + - cosmodb + - servicebus + application: name: stacks-api-cqrs data: @@ -31,18 +38,3 @@ springdoc: enabled: true enabled: true path: /swagger/oas-json - -azure: - cosmos: - uri: http://192.168.50.169:8081/ - database: Stacks - key: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== - application-insights: - instrumentation-key: xxxxxx - enabled: false - keyvault: - enabled: false - uri: https://amido-stacks-tmp.vault.azure.net/ - client-id: xxxxxx - client-key: xxxxxx - tenant-id: xxxxxx diff --git a/java/src/test/java/com/amido/stacks/workloads/menu/api/v1/SecretsControllerTest.java b/java/src/test/java/com/amido/stacks/workloads/menu/api/v1/SecretsControllerTest.java new file mode 100644 index 00000000..4e6a17fa --- /dev/null +++ b/java/src/test/java/com/amido/stacks/workloads/menu/api/v1/SecretsControllerTest.java @@ -0,0 +1,62 @@ +package com.amido.stacks.workloads.menu.api.v1; + +import static org.assertj.core.api.BDDAssertions.then; + +import com.amido.stacks.workloads.Application; +import com.amido.stacks.workloads.menu.repository.MenuRepository; +import com.amido.stacks.workloads.util.TestHelper; +import com.azure.spring.autoconfigure.cosmos.CosmosAutoConfiguration; +import com.azure.spring.autoconfigure.cosmos.CosmosHealthConfiguration; +import com.azure.spring.autoconfigure.cosmos.CosmosRepositoriesAutoConfiguration; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = Application.class, + properties = { + "stacks-secret-1=SEC1", + "stacks-secret-2=SEC2", + "stacks-secret-3=SEC3", + "stacks-secret-4=SEC4" + }) +@EnableAutoConfiguration( + exclude = { + CosmosRepositoriesAutoConfiguration.class, + CosmosAutoConfiguration.class, + CosmosHealthConfiguration.class + }) +@Tag("Integration") +@ActiveProfiles("test") +class SecretsControllerTest { + + public static final String GET_SECRETS = "/v1/secrets"; + + @LocalServerPort private int port; + + @Autowired private TestRestTemplate testRestTemplate; + + @MockBean private MenuRepository menuRepository; + + @Test + void shouldReturnValidSecrets() { + // Given + + // When + var response = + this.testRestTemplate.getForEntity( + String.format("%s/v1/secrets", TestHelper.getBaseURL(port)), String.class); + + // Then + then(response.getStatusCode()).isEqualTo(HttpStatus.OK); + then(response.getBody()).isEqualTo("Secrets -> SEC1, SEC2, SEC3, SEC4"); + } +} diff --git a/java/src/test/java/com/amido/stacks/workloads/profile/ProfileTest.java b/java/src/test/java/com/amido/stacks/workloads/profile/ProfileTest.java new file mode 100644 index 00000000..8a9c966b --- /dev/null +++ b/java/src/test/java/com/amido/stacks/workloads/profile/ProfileTest.java @@ -0,0 +1,43 @@ +package com.amido.stacks.workloads.profile; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.amido.stacks.workloads.menu.repository.MenuRepository; +import com.azure.spring.autoconfigure.cosmos.CosmosAutoConfiguration; +import com.azure.spring.autoconfigure.cosmos.CosmosHealthConfiguration; +import com.azure.spring.autoconfigure.cosmos.CosmosRepositoriesAutoConfiguration; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.core.env.Environment; +import org.springframework.test.context.TestPropertySource; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = {"management.port=0"}) +@EnableAutoConfiguration( + exclude = { + CosmosRepositoriesAutoConfiguration.class, + CosmosAutoConfiguration.class, + CosmosHealthConfiguration.class + }) +@Tag("Integration") +class ProfileTest { + + /* + @Value("${spring.profiles.active:}") + private String activeProfiles; + */ + @Autowired private Environment env; + + @MockBean private MenuRepository menuRepository; + + @Test + void shouldReturnprofiles() { + + String[] activeProfile = env.getActiveProfiles(); + assertEquals(99, activeProfile.length); + } +}