From 8e2c20029219e7e01f42268f45425ee58cbe0c80 Mon Sep 17 00:00:00 2001 From: drono Date: Mon, 20 May 2024 17:22:34 +0300 Subject: [PATCH 01/46] Add initial package and configuration files for FHIR info Gateway --- config.yaml | 4 +- fhir-info-gateway/docker-compose.dev.yml | 8 ++ fhir-info-gateway/docker-compose.yml | 33 ++++++++ fhir-info-gateway/package-metadata.json | 23 ++++++ fhir-info-gateway/swarm.sh | 81 +++++++++++++++++++ .../docker-compose.yml | 4 + 6 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 fhir-info-gateway/docker-compose.dev.yml create mode 100644 fhir-info-gateway/docker-compose.yml create mode 100644 fhir-info-gateway/package-metadata.json create mode 100644 fhir-info-gateway/swarm.sh diff --git a/config.yaml b/config.yaml index 54977b16..39b1c622 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ projectName: platform -image: jembi/platform:3.0.0-beta +image: jembi/platform:latest logPath: /tmp/logs packages: @@ -26,6 +26,7 @@ packages: - database-postgres - reprocess-mediator - fhir-ig-importer + - fhir-info-gateway profiles: - name: cdr-dw @@ -75,4 +76,3 @@ profiles: - openhim-mapping-mediator envFiles: - mpi.env - diff --git a/fhir-info-gateway/docker-compose.dev.yml b/fhir-info-gateway/docker-compose.dev.yml new file mode 100644 index 00000000..7b96e520 --- /dev/null +++ b/fhir-info-gateway/docker-compose.dev.yml @@ -0,0 +1,8 @@ +version: '3.9' + +services: + fhir-info-gateway: + ports: + - target: 8080 + published: 8880 + mode: host diff --git a/fhir-info-gateway/docker-compose.yml b/fhir-info-gateway/docker-compose.yml new file mode 100644 index 00000000..195ddcd9 --- /dev/null +++ b/fhir-info-gateway/docker-compose.yml @@ -0,0 +1,33 @@ +version: "3.9" +services: + fhir-info-gateway: + image: ${FHIR_INFO_GATEWAY_IMAGE} + networks: + openhim: + keycloak: + default: + environment: + TOKEN_ISSUER: ${KC_API_URL}/realms/${KC_REALM_NAME} + ACCESS_CHECKER: ${ACCESS_CHECKER} + PROXY_TO: ${MPI_PROXY_URL} + BACKEND_TYPE: ${BACKEND_TYPE} + RUN_MODE: ${RUN_MODE} + deploy: + replicas: ${FHIR_INFO_GATEWAY_INSTANCES} + placement: + max_replicas_per_node: ${FHIR_INFO_GATEWAY_MAX_REPLICAS_PER_NODE} + resources: + limits: + cpus: ${FHIR_INFO_GATEWAY_CPU_LIMIT} + memory: ${FHIR_INFO_GATEWAY_MEMORY_LIMIT} + reservations: + cpus: ${FHIR_INFO_GATEWAY_CPU_RESERVE} + memory: ${FHIR_INFO_GATEWAY_MEMORY_RESERVE} +networks: + openhim: + name: openhim_public + external: true + keycloak: + name: keycloak_public + external: true + default: diff --git a/fhir-info-gateway/package-metadata.json b/fhir-info-gateway/package-metadata.json new file mode 100644 index 00000000..bfb968be --- /dev/null +++ b/fhir-info-gateway/package-metadata.json @@ -0,0 +1,23 @@ +{ + "id": "fhir-info-gateway", + "name": "FHIR Info Gateway", + "description": "Implement the FHIR Info Gateway as a platform package which sits between the OpenHIM and MPI Mediator and any other direct FHIR access", + "type": "infrastructure", + "version": "0.0.1", + "dependencies": ["mpi-mediator"], + "environmentVariables": { + "MPI_PROXY_URL": "http://localhost:5001", + "ACCESS_CHECKER": "patient", + "RUN_MODE": "DEV", + "FHIR_INFO_GATEWAY_IMAGE": "jembi/fhir-info-gateway:v0.0.1", + "BACKEND_TYPE": "HAPI", + "KC_API_URL": "http://identity-access-manager-keycloak:9088", + "KC_REALM_NAME": "platform-realm", + "FHIR_INFO_GATEWAY_INSTANCES": "1", + "FHIR_INFO_GATEWAY_MAX_REPLICAS_PER_NODE": "1", + "FHIR_INFO_GATEWAY_CPU_LIMIT": "0", + "FHIR_INFO_GATEWAY_MEMORY_LIMIT": "2G", + "FHIR_INFO_GATEWAY_CPU_RESERVE": "0.05", + "FHIR_INFO_GATEWAY_MEMORY_RESERVE": "500M" + } +} diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh new file mode 100644 index 00000000..2f89da06 --- /dev/null +++ b/fhir-info-gateway/swarm.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +declare ACTION="" +declare MODE="" +declare COMPOSE_FILE_PATH="" +declare UTILS_PATH="" +declare SERVICE_NAMES=() +declare STACK="fhir-info-gateway" + +function init_vars() { + ACTION=$1 + MODE=$2 + + COMPOSE_FILE_PATH=$( + cd "$(dirname "${BASH_SOURCE[0]}")" || exit + pwd -P + ) + + UTILS_PATH="${COMPOSE_FILE_PATH}/../utils" + + SERVICE_NAMES=( + "fhir-info-gateway" + ) + + readonly ACTION + readonly MODE + readonly COMPOSE_FILE_PATH + readonly UTILS_PATH + readonly SERVICE_NAMES + readonly STACK +} + +# shellcheck disable=SC1091 +function import_sources() { + source "${UTILS_PATH}/docker-utils.sh" + source "${UTILS_PATH}/log.sh" +} + +function initialize_package() { + local package_dev_compose_filename="" + if [[ "${MODE}" == "dev" ]]; then + log info "Running package in DEV mode" + package_dev_compose_filename="docker-compose.dev.yml" + else + log info "Running package in PROD mode" + fi + + ( + docker::deploy_service $STACK "${COMPOSE_FILE_PATH}" "docker-compose.yml" "$package_dev_compose_filename" + ) || { + log error "Failed to deploy package" + exit 1 + } +} + +function destroy_package() { + docker::stack_destroy "$STACK" +} + +main() { + init_vars "$@" + import_sources + + if [[ "${ACTION}" == "init" ]] || [[ "${ACTION}" == "up" ]]; then + log info "Running package in Single node mode" + + initialize_package + elif [[ "${ACTION}" == "down" ]]; then + log info "Scaling down package" + + docker::scale_services "$STACK" 0 + elif [[ "${ACTION}" == "destroy" ]]; then + log info "Destroying package" + + destroy_package + else + log error "Valid options are: init, up, down, or destroy" + fi +} + +main "$@" diff --git a/interoperability-layer-openhim/docker-compose.yml b/interoperability-layer-openhim/docker-compose.yml index 518d93dc..1a3ba685 100644 --- a/interoperability-layer-openhim/docker-compose.yml +++ b/interoperability-layer-openhim/docker-compose.yml @@ -24,6 +24,10 @@ services: - api_openid_clientId=${KC_OPENHIM_CLIENT_ID} - api_openid_clientSecret=${KC_OPENHIM_CLIENT_SECRET} - openhimConsoleBaseUrl=${OPENHIM_CONSOLE_BASE_URL} + - authentication_enableJWTAuthentication=true + - authentication_jwt_jwksUri=${KC_API_URL}/realms/${KC_REALM_NAME}/protocol/openid-connect/certs + - authentication_jwt_algorithms=RS256 + - authentication_jwt_issuer=${KC_FRONTEND_URL}/realms/${KC_REALM_NAME} deploy: replicas: ${OPENHIM_CORE_INSTANCES} placement: From b0a333c2b1b1c37b6119b80ed5ff2ba7b4fe63e6 Mon Sep 17 00:00:00 2001 From: drono Date: Fri, 24 May 2024 17:01:33 +0300 Subject: [PATCH 02/46] Add SMART on fhir realms creator --- .../docker-compose-smart_keyclock.yml | 15 + fhir-info-gateway/keycloak-config.json | 732 ++++++++++++++++++ fhir-info-gateway/package-metadata.json | 6 +- 3 files changed, 751 insertions(+), 2 deletions(-) create mode 100644 fhir-info-gateway/docker-compose-smart_keyclock.yml create mode 100644 fhir-info-gateway/keycloak-config.json diff --git a/fhir-info-gateway/docker-compose-smart_keyclock.yml b/fhir-info-gateway/docker-compose-smart_keyclock.yml new file mode 100644 index 00000000..04cd3548 --- /dev/null +++ b/fhir-info-gateway/docker-compose-smart_keyclock.yml @@ -0,0 +1,15 @@ +version: "3.9" + +services: + smart-config: + image: jembi/keycloak-config + networks: + - fhir-info-gateway_default + environment: + KEYCLOAK_BASE_URL: ${KC_API_URL} + KEYCLOAK_USER: ${KC_ADMIN_USER} + KEYCLOAK_PASSWORD: ${KC_ADMIN_PASSWORD} + KEYCLOAK_REALM: ${KC_REALM_NAME} +networks: + fhir-info-gateway_default: + diff --git a/fhir-info-gateway/keycloak-config.json b/fhir-info-gateway/keycloak-config.json new file mode 100644 index 00000000..36e154bb --- /dev/null +++ b/fhir-info-gateway/keycloak-config.json @@ -0,0 +1,732 @@ +{ + "keycloak": { + "serverUrl": "${KEYCLOAK_BASE_URL}", + "adminUser": "${KEYCLOAK_USER}", + "adminPassword": "${KEYCLOAK_PASSWORD}", + "adminClientId": "admin-cli", + "realms": { + "${KEYCLOAK_REALM}": { + "enabled": true, + "clientScopes": { + "fhirUser": { + "protocol": "openid-connect", + "description": "Permission to retrieve current logged-in user", + "attributes": { + "consent.screen.text": "Permission to retrieve current logged-in user" + }, + "mappers": { + "fhirUser Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-patient-prefix-usermodel-attribute-mapper", + "config": { + "user.attribute": "resourceId", + "claim.name": "fhirUser", + "jsonType.label": "String", + "id.token.claim": "true", + "access.token.claim": "false", + "userinfo.token.claim": "true" + } + } + } + }, + "launch/patient": { + "protocol": "openid-connect", + "description": "Used by clients to request a patient-scoped access token", + "attributes": { + "display.on.consent.screen": "false" + }, + "mappers": { + "Patient ID Claim Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-usermodel-attribute-mapper", + "config": { + "user.attribute": "resourceId", + "claim.name": "patient_id", + "jsonType.label": "String", + "id.token.claim": "false", + "access.token.claim": "true", + "userinfo.token.claim": "false" + } + }, + "Patient ID Token Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-usersessionmodel-note-mapper", + "config": { + "user.session.note": "patient_id", + "claim.name": "patient", + "jsonType.label": "String", + "id.token.claim": "false", + "access.token.claim": "false", + "access.tokenResponse.claim": "true" + } + }, + "Group Membership Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-group-membership-mapper", + "config": { + "claim.name": "group", + "full.path": "false", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + } + }, + "online_access": { + "protocol": "openid-connect", + "description": "Request a refresh_token that can be used to obtain a new access token to replace an expired one, and that will be usable for as long as the end-user remains online.", + "attributes": { + "consent.screen.text": "Retain access while you are online" + } + }, + "patient/*.read": { + "protocol": "openid-connect", + "description": "Read access to all data", + "attributes": { + "consent.screen.text": "Read access to all data for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/AllergyIntolerance.read": { + "protocol": "openid-connect", + "description": "Read access to AllergyIntolerance", + "attributes": { + "consent.screen.text": "Read access to AllergyIntolerance for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/CarePlan.read": { + "protocol": "openid-connect", + "description": "Read access to CarePlan", + "attributes": { + "consent.screen.text": "Read access to CarePlan for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/CareTeam.read": { + "protocol": "openid-connect", + "description": "Read access to CareTeam", + "attributes": { + "consent.screen.text": "Read access to CareTeam for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Condition.read": { + "protocol": "openid-connect", + "description": "Read access to Condition", + "attributes": { + "consent.screen.text": "Read access to Condition for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Device.read": { + "protocol": "openid-connect", + "description": "Read access to Device", + "attributes": { + "consent.screen.text": "Read access to Device for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/DiagnosticReport.read": { + "protocol": "openid-connect", + "description": "Read access to DiagnosticReport", + "attributes": { + "consent.screen.text": "Read access to DiagnosticReport for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/DocumentReference.read": { + "protocol": "openid-connect", + "description": "Read access to DocumentReference", + "attributes": { + "consent.screen.text": "Read access to DocumentReference for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Encounter.read": { + "protocol": "openid-connect", + "description": "Read access to Encounter", + "attributes": { + "consent.screen.text": "Read access to Encounter for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/ExplanationOfBenefit.read": { + "protocol": "openid-connect", + "description": "Read access to ExplanationOfBenefit", + "attributes": { + "consent.screen.text": "Read access to ExplanationOfBenefit for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Goal.read": { + "protocol": "openid-connect", + "description": "Read access to Goal", + "attributes": { + "consent.screen.text": "Read access to Goal for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Immunization.read": { + "protocol": "openid-connect", + "description": "Read access to Immunization", + "attributes": { + "consent.screen.text": "Read access to Immunization for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Location.read": { + "protocol": "openid-connect", + "description": "Read access to Location", + "attributes": { + "consent.screen.text": "Read access to Location for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Medication.read": { + "protocol": "openid-connect", + "description": "Read access to Medication", + "attributes": { + "consent.screen.text": "Read access to Medication for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/MedicationDispense.read": { + "protocol": "openid-connect", + "description": "Read access to MedicationDispense", + "attributes": { + "consent.screen.text": "Read access to MedicationDispense for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/MedicationRequest.read": { + "protocol": "openid-connect", + "description": "Read access to MedicationRequest", + "attributes": { + "consent.screen.text": "Read access to MedicationRequest for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Observation.read": { + "protocol": "openid-connect", + "description": "Read access to Observation", + "attributes": { + "consent.screen.text": "Read access to Observation for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Organization.read": { + "protocol": "openid-connect", + "description": "Read access to Organization", + "attributes": { + "consent.screen.text": "Read access to Organization for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Patient.read": { + "protocol": "openid-connect", + "description": "Read access to Patient", + "attributes": { + "consent.screen.text": "Read access to Patient for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Practitioner.read": { + "protocol": "openid-connect", + "description": "Read access to Practitioner", + "attributes": { + "consent.screen.text": "Read access to Practitioner for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/PractitionerRole.read": { + "protocol": "openid-connect", + "description": "Read access to PractitionerRole", + "attributes": { + "consent.screen.text": "Read access to PractitionerRole for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Procedure.read": { + "protocol": "openid-connect", + "description": "Read access to Procedure", + "attributes": { + "consent.screen.text": "Read access to Procedure for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/Provenance.read": { + "protocol": "openid-connect", + "description": "Read access to Provenance", + "attributes": { + "consent.screen.text": "Read access to Provenance for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/RelatedPerson.read": { + "protocol": "openid-connect", + "description": "Read access to RelatedPerson", + "attributes": { + "consent.screen.text": "Read access to RelatedPerson for the patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "user/Device.read": { + "protocol": "openid-connect", + "description": "Read access to Device", + "attributes": { + "consent.screen.text": "Read access to all Device" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "user/Organization.read": { + "protocol": "openid-connect", + "description": "Read access to Organization", + "attributes": { + "consent.screen.text": "Read access to all Organization" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "user/Practitioner.read": { + "protocol": "openid-connect", + "description": "Read access to Practitioner", + "attributes": { + "consent.screen.text": "Read access to all Practitioner" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "user/PractitionerRole.read": { + "protocol": "openid-connect", + "description": "Read access to PractitionerRole", + "attributes": { + "consent.screen.text": "Read access to all PractitionerRole" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + } + }, + "defaultDefaultClientScopes": [], + "defaultOptionalClientScopes": [ + "fhirUser", + "launch/patient", + "offline_access", + "online_access", + "profile", + "patient/*.read", + "patient/AllergyIntolerance.read", + "patient/CarePlan.read", + "patient/CareTeam.read", + "patient/Condition.read", + "patient/Device.read", + "patient/DiagnosticReport.read", + "patient/DocumentReference.read", + "patient/Encounter.read", + "patient/ExplanationOfBenefit.read", + "patient/Goal.read", + "patient/Immunization.read", + "patient/Location.read", + "patient/Medication.read", + "patient/MedicationDispense.read", + "patient/MedicationRequest.read", + "patient/Observation.read", + "patient/Organization.read", + "patient/Patient.read", + "patient/Practitioner.read", + "patient/PractitionerRole.read", + "patient/Procedure.read", + "patient/Provenance.read", + "patient/RelatedPerson.read", + "user/Device.read", + "user/Organization.read", + "user/Practitioner.read", + "user/PractitionerRole.read" + ], + "clients": { + "inferno": { + "consentRequired": true, + "publicClient": true, + "bearerOnly": false, + "enableDirectAccess": false, + "rootURL": "http://localhost:4567/inferno", + "redirectURIs": [ + "http://localhost:4567/inferno/*", + "http://localhost:4567/inferno2/*" + ], + "adminURL": "http://localhost:4567/inferno", + "webOrigins": ["http://localhost:4567"], + "defaultClientScopes": ["launch/patient"], + "optionalClientScopes": [ + "fhirUser", + "offline_access", + "online_access", + "profile", + "patient/*.read", + "patient/AllergyIntolerance.read", + "patient/CarePlan.read", + "patient/CareTeam.read", + "patient/Condition.read", + "patient/Device.read", + "patient/DiagnosticReport.read", + "patient/DocumentReference.read", + "patient/Encounter.read", + "patient/ExplanationOfBenefit.read", + "patient/Goal.read", + "patient/Immunization.read", + "patient/Location.read", + "patient/Medication.read", + "patient/MedicationDispense.read", + "patient/MedicationRequest.read", + "patient/Observation.read", + "patient/Organization.read", + "patient/Patient.read", + "patient/Practitioner.read", + "patient/PractitionerRole.read", + "patient/Procedure.read", + "patient/Provenance.read", + "patient/RelatedPerson.read", + "user/Device.read", + "user/Organization.read", + "user/Practitioner.read", + "user/PractitionerRole.read" + ] + } + }, + "authenticationFlows": { + "SMART App Launch": { + "description": "browser based authentication", + "providerId": "basic-flow", + "builtIn": false, + "authenticationExecutions": { + "SMART Login": { + "requirement": "ALTERNATIVE", + "userSetupAllowed": false, + "authenticatorFlow": true, + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "authenticationExecutions": { + "Audience Validation": { + "authenticator": "audience-validator", + "requirement": "DISABLED", + "priority": 10, + "authenticatorFlow": false, + "configAlias": "localhost", + "config": { + "audiences": "${FHIR_BASE_URL}" + } + }, + "Username Password Form": { + "authenticator": "auth-username-password-form", + "requirement": "REQUIRED", + "priority": 20, + "authenticatorFlow": false + }, + "Patient Selection Authenticator": { + "authenticator": "auth-select-patient", + "requirement": "REQUIRED", + "priority": 30, + "authenticatorFlow": false, + "configAlias": "host.docker", + "config": { + "internalFhirUrl": "${FHIR_BASE_URL}" + } + } + } + } + } + } + }, + "browserFlow": "SMART App Launch", + "groups": { + "fhirUser": {} + }, + "defaultGroups": ["fhirUser"], + "users": { + "fhiruser": { + "enabled": true, + "password": "change-password", + "passwordTemporary": false, + "attributes": { + "resourceId": ["Patient1"] + }, + "groups": ["fhirUser"] + } + }, + "eventsConfig": { + "saveLoginEvents": true, + "expiration": 23328000, + "types": [ + "FEDERATED_IDENTITY_LINK", + "LOGOUT", + "LOGIN_ERROR", + "IDENTITY_PROVIDER_LINK_ACCOUNT", + "REFRESH_TOKEN", + "FEDERATED_IDENTITY_LINK_ERROR", + "IDENTITY_PROVIDER_POST_LOGIN", + "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", + "CODE_TO_TOKEN_ERROR", + "IDENTITY_PROVIDER_FIRST_LOGIN", + "REFRESH_TOKEN_ERROR", + "IDENTITY_PROVIDER_POST_LOGIN_ERROR", + "LOGOUT_ERROR", + "CODE_TO_TOKEN", + "LOGIN", + "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" + ], + "saveAdminEvents": true + } + } + } + } +} diff --git a/fhir-info-gateway/package-metadata.json b/fhir-info-gateway/package-metadata.json index bfb968be..b2fcda0b 100644 --- a/fhir-info-gateway/package-metadata.json +++ b/fhir-info-gateway/package-metadata.json @@ -6,13 +6,15 @@ "version": "0.0.1", "dependencies": ["mpi-mediator"], "environmentVariables": { - "MPI_PROXY_URL": "http://localhost:5001", + "MPI_PROXY_URL": "http://mpi-mediator:3000/fhir", "ACCESS_CHECKER": "patient", "RUN_MODE": "DEV", - "FHIR_INFO_GATEWAY_IMAGE": "jembi/fhir-info-gateway:v0.0.1", + "FHIR_INFO_GATEWAY_IMAGE": "jembi/fhir-info-gateway:v0.0.2", "BACKEND_TYPE": "HAPI", "KC_API_URL": "http://identity-access-manager-keycloak:9088", "KC_REALM_NAME": "platform-realm", + "KC_ADMIN_PASSWORD": "dev_password_only", + "KC_ADMIN_USEERNAME": "admin", "FHIR_INFO_GATEWAY_INSTANCES": "1", "FHIR_INFO_GATEWAY_MAX_REPLICAS_PER_NODE": "1", "FHIR_INFO_GATEWAY_CPU_LIMIT": "0", From f6cec06cf905577fb7c37ecd1cd660a0c3130bc9 Mon Sep 17 00:00:00 2001 From: drono Date: Wed, 15 May 2024 17:19:41 +0300 Subject: [PATCH 03/46] Platform beta release --- config.yaml | 2 + fhir-ig-importer/docker-compose.dev.yml | 2 +- .../importer/volume/ig-importer-app.json | 2 +- fhir-ig-importer/package-metadata.json | 4 +- .../package-metadata.json | 4 +- kafka-mapper-consumer/package-metadata.json | 4 +- mpi-mediator/docker-compose.yml | 2 +- .../importer/volume/openhim-import.json | 31 ++---- reprocess-mediator/docker-compose.dev.yml | 2 +- reprocess-mediator/package-metadata.json | 32 +++--- test/cucumber/features/steps/recipesSteps.js | 105 +++++++++++------- 11 files changed, 103 insertions(+), 87 deletions(-) diff --git a/config.yaml b/config.yaml index 39b1c622..38c02aca 100644 --- a/config.yaml +++ b/config.yaml @@ -45,6 +45,8 @@ profiles: - openhim-mapping-mediator - kafka-mapper-consumer - kafka-unbundler-consumer + - fhir-ig-importer + - reprocess-mediator envFiles: - cdr-dw.env diff --git a/fhir-ig-importer/docker-compose.dev.yml b/fhir-ig-importer/docker-compose.dev.yml index 25714fbd..c33a9169 100644 --- a/fhir-ig-importer/docker-compose.dev.yml +++ b/fhir-ig-importer/docker-compose.dev.yml @@ -10,5 +10,5 @@ services: fhir-ig-importer-ui: ports: - target: 8080 - published: 3000 + published: 3334 mode: host diff --git a/fhir-ig-importer/importer/volume/ig-importer-app.json b/fhir-ig-importer/importer/volume/ig-importer-app.json index a86b0cc8..102b6eac 100644 --- a/fhir-ig-importer/importer/volume/ig-importer-app.json +++ b/fhir-ig-importer/importer/volume/ig-importer-app.json @@ -3,7 +3,7 @@ "description": "FHIR IG microfrontend app", "category": "HIE Configuration", "type": "esmodule", - "url": "http://localhost:3000/jembi-fhir-ig-importer.js", + "url": "http://localhost:3334/jembi-fhir-ig-importer.js", "showInPortal": true, "showInSideBar": true, "access_roles": ["admin"], diff --git a/fhir-ig-importer/package-metadata.json b/fhir-ig-importer/package-metadata.json index 1db85f0a..27f4de82 100644 --- a/fhir-ig-importer/package-metadata.json +++ b/fhir-ig-importer/package-metadata.json @@ -14,7 +14,7 @@ "FHIR_IG_IMPORTER_CORE_PORT": 3001, "FHIR_IG_IMPORTER_CORE_HOST": "0.0.0.0", "FHIR_IG_IMPORTER_CORE_URL": "http://0.0.0.0:3001/fhir/ig/v1.0", - "FHIR_IG_IMPORTER_UI_VERSION": "0.1.0", - "FHIR_IG_IMPORTER_CORE_VERSION": "1.0.0" + "FHIR_IG_IMPORTER_UI_VERSION": "v1.0.0", + "FHIR_IG_IMPORTER_CORE_VERSION": "v1.0.0" } } diff --git a/interoperability-layer-openhim/package-metadata.json b/interoperability-layer-openhim/package-metadata.json index a866f05c..82272031 100644 --- a/interoperability-layer-openhim/package-metadata.json +++ b/interoperability-layer-openhim/package-metadata.json @@ -6,8 +6,8 @@ "type": "infrastructure", "dependencies": [], "environmentVariables": { - "OPENHIM_CORE_IMAGE": "jembi/openhim-core:microfrontends-3.0.0-beta", - "OPENHIM_CONSOLE_IMAGE": "jembi/openhim-console:v1.18.2", + "OPENHIM_CORE_IMAGE": "jembi/openhim-core:v8.4.3", + "OPENHIM_CONSOLE_IMAGE": "jembi/openhim-console:poc-microfrontend", "MONGO_IMAGE": "mongo:4.2", "AWAIT_HELPER_IMAGE": "jembi/await-helper:1.0.1", "MONGO_1_PLACEMENT": "node-1", diff --git a/kafka-mapper-consumer/package-metadata.json b/kafka-mapper-consumer/package-metadata.json index a28cd5da..0c0b17a9 100644 --- a/kafka-mapper-consumer/package-metadata.json +++ b/kafka-mapper-consumer/package-metadata.json @@ -17,7 +17,7 @@ "REGISTER_MEDIATOR": "true", "CLICKHOUSE_HOST": "analytics-datastore-clickhouse", "CLICKHOUSE_PORT": "8123", - "KAFKA_CONSUMER_MAPPER_MEDIATOR_VERSION": "jembi/kafka-mapper-consumer:0.1.0", - "KAFKA_CONSUMER_MAPPER_UI_VERSION": "jembi/kafka-mapper-consumer-ui:0.1.1-alpha" + "KAFKA_CONSUMER_MAPPER_MEDIATOR_VERSION": "jembi/kafka-mapper-consumer:v0.0.1", + "KAFKA_CONSUMER_MAPPER_UI_VERSION": "jembi/kafka-mapper-consumer-ui:v0.0.1" } } diff --git a/mpi-mediator/docker-compose.yml b/mpi-mediator/docker-compose.yml index 084d7e39..8f39f082 100644 --- a/mpi-mediator/docker-compose.yml +++ b/mpi-mediator/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.9' services: mpi-mediator: - image: jembi/mpi-mediator:v2.1.1 + image: jembi/mpi-mediator:v2.2.0 networks: openhim: kafka: diff --git a/mpi-mediator/importer/volume/openhim-import.json b/mpi-mediator/importer/volume/openhim-import.json index 5a1b11b9..cb40af5d 100644 --- a/mpi-mediator/importer/volume/openhim-import.json +++ b/mpi-mediator/importer/volume/openhim-import.json @@ -5,9 +5,7 @@ "surname": "User", "email": "root@openhim.org", "provider": "token", - "groups": [ - "admin" - ], + "groups": ["admin"], "passwordAlgorithm": "sha512", "passwordHash": "ea3824f17cf1379eb118a36bc7c8cf0f45712e2af7748567fca5313dec6fa66d61064e82a5e5cb88e998486ee3c7d0dac235bbeda8c341d6edc1c77406be2ab6", "passwordSalt": "d4f622c0404f09bd959bfb263efa3452", @@ -21,9 +19,7 @@ { "clientID": "test", "name": "Test Client", - "roles": [ - "instant" - ], + "roles": ["instant"], "customTokenID": "test" } ], @@ -98,7 +94,7 @@ "urlPattern": "^/fhir.*$", "methods": ["GET", "POST"], "type": "http", - "priority": null, + "priority": 2, "tcpPort": null, "tcpHost": null, "pollingSchedule": null, @@ -147,9 +143,7 @@ { "name": "MPI Orchestration for fhir bundles - Asynchronous flow", "urlPattern": "^/async/fhir/?$", - "methods": [ - "POST" - ], + "methods": ["POST"], "type": "http", "priority": null, "tcpPort": null, @@ -157,9 +151,7 @@ "pollingSchedule": null, "requestBody": true, "responseBody": true, - "allow": [ - "instant" - ], + "allow": ["instant"], "whitelist": [], "authType": "private", "routes": [ @@ -240,9 +232,7 @@ "pollingSchedule": null, "requestBody": true, "responseBody": true, - "allow": [ - "instant" - ], + "allow": ["instant"], "whitelist": [], "authType": "private", "routes": [ @@ -328,14 +318,9 @@ { "name": "MPI mediator", "urlPattern": "^(/async)?/fhir.*$", - "methods": [ - "POST", - "GET" - ], + "methods": ["POST", "GET"], "type": "http", - "allow": [ - "instant" - ], + "allow": ["instant"], "whitelist": [], "authType": "private", "routes": [ diff --git a/reprocess-mediator/docker-compose.dev.yml b/reprocess-mediator/docker-compose.dev.yml index ee40381a..e376b2f1 100644 --- a/reprocess-mediator/docker-compose.dev.yml +++ b/reprocess-mediator/docker-compose.dev.yml @@ -4,7 +4,7 @@ services: reprocess-mediator: ports: - target: 3000 - published: 3000 + published: 3335 mode: host reprocess-mediator-ui: diff --git a/reprocess-mediator/package-metadata.json b/reprocess-mediator/package-metadata.json index 4393bc6e..97ca4643 100644 --- a/reprocess-mediator/package-metadata.json +++ b/reprocess-mediator/package-metadata.json @@ -1,18 +1,18 @@ { - "id": "reprocess-mediator", - "name": "Reprocess Mediator", - "description": "A mediator that allows for configuring and reprocessing of transactions", - "type": "use-case", - "version": "1.4.2", - "dependencies": ["interoperability-layer-openhim"], - "environmentVariables": { - "TRUST_SELF_SIGNED": "true", - "OPENHIM_MEDIATOR_URL": "https://openhim-core:8080", - "OPENHIM_USERNAME": "root@openhim.org", - "OPENHIM_PASSWORD": "instant101", - "REGISTER_MEDIATOR": "true", - "REPROCESSOR_API_BASE_URL": "http://reprocess-mediator:3000", - "REPROCESS_CORE_VERSION": "latest", - "REPROCESS_UI_VERSION": "latest" - } + "id": "reprocess-mediator", + "name": "Reprocess Mediator", + "description": "A mediator that allows for configuring and reprocessing of transactions", + "type": "use-case", + "version": "1.4.2", + "dependencies": ["interoperability-layer-openhim"], + "environmentVariables": { + "TRUST_SELF_SIGNED": "true", + "OPENHIM_MEDIATOR_URL": "https://openhim-core:8080", + "OPENHIM_USERNAME": "root@openhim.org", + "OPENHIM_PASSWORD": "instant101", + "REGISTER_MEDIATOR": "true", + "REPROCESSOR_API_BASE_URL": "http://reprocess-mediator:3000", + "REPROCESS_CORE_VERSION": "v0.1.0", + "REPROCESS_UI_VERSION": "v0.1.0" } +} diff --git a/test/cucumber/features/steps/recipesSteps.js b/test/cucumber/features/steps/recipesSteps.js index 9c119150..8d24c0b3 100644 --- a/test/cucumber/features/steps/recipesSteps.js +++ b/test/cucumber/features/steps/recipesSteps.js @@ -1,16 +1,15 @@ -"use strict" +"use strict"; const axios = require("axios"); const fs = require("fs"); -const path = require('path'); +const path = require("path"); const chai = require("chai"); -const { ClickHouse } = require('clickhouse'); +const { ClickHouse } = require("clickhouse"); const { Given, When, Then, setDefaultTimeout } = require("@cucumber/cucumber"); setDefaultTimeout(30 * 60 * 1000); -const HOST = - process.env.HOST || 'localhost'; -const CLICKHOUSE_PORT = parseInt(process.env.CLICKHOUSE_PORT || '8124'); +const HOST = process.env.HOST || "localhost"; +const CLICKHOUSE_PORT = parseInt(process.env.CLICKHOUSE_PORT || "8124"); const CLICKHOUSE_DEBUG = Boolean(process.env.CLICKHOUSE_DEBUG || false); const { expect } = chai; @@ -22,69 +21,99 @@ const clickhouse = new ClickHouse({ raw: true, }); -const query = table => `SELECT * FROM ${table}`; +const query = (table) => `SELECT * FROM ${table}`; -const sendRequest = (url, method='POST', data={}) => { +const sendRequest = (url, method = "POST", data = {}) => { return axios({ url, headers: { - 'Content-Type': 'application/fhir+json', - Authorization: `Custom test` + "Content-Type": "application/fhir+json", + Authorization: `Custom test`, }, data, - method - }) + method, + }); }; let PatientID; Given("I have configured the cdr", async function () { await new Promise((resolve) => { - setTimeout(() => resolve(), 300000) + setTimeout(() => resolve(), 300000); }); const organization = JSON.parse( - fs.readFileSync(path.resolve(__dirname, '..' , 'resources', 'organization.json')) + fs.readFileSync( + path.resolve(__dirname, "..", "resources", "organization.json") + ) ); - this.cdrConfigResult = await sendRequest(`http://${HOST}:5001/fhir`, 'POST', organization); + this.cdrConfigResult = await sendRequest( + `http://${HOST}:5001/fhir`, + "POST", + organization + ); }); When("I send a fhir patient bundle", async function () { const fhirBundle = JSON.parse( - fs.readFileSync(path.resolve(__dirname, '..' , 'resources', 'fhirBundle.json')) + fs.readFileSync( + path.resolve(__dirname, "..", "resources", "fhirBundle.json") + ) ); - this.fhirBundleSentResult = await sendRequest(`http://${HOST}:5001/fhir`, 'POST', fhirBundle); + this.fhirBundleSentResult = await sendRequest( + `http://${HOST}:5001/fhir`, + "POST", + fhirBundle + ); }); When("I then send a fhir patient summary request", async function () { - this.IPSResult = await sendRequest(`http://${HOST}:5001/fhir/Patient/${PatientID}/$summary`, 'GET'); -}); - -When("I then send a request for all the patient's clinical data", async function () { - this.EverythingResult = await sendRequest(`http://${HOST}:5001/fhir/Patient/${PatientID}/$everything?_mdm=true`, 'GET'); + this.IPSResult = await sendRequest( + `http://${HOST}:5001/fhir/Patient/${PatientID}/$summary`, + "GET" + ); }); -When("I wait for the services to start up", async function() { +When( + "I then send a request for all the patient's clinical data", + async function () { + this.EverythingResult = await sendRequest( + `http://${HOST}:5001/fhir/Patient/${PatientID}/$everything?_mdm=true`, + "GET" + ); + } +); + +When("I wait for the services to start up", async function () { await new Promise((resolve) => { setTimeout(() => resolve(), 1500000); }); }); Then("the clinical data should be stored in hapi fhir", async function () { - this.fhirBundleSentResult.data.entry.forEach(rec => { + this.fhirBundleSentResult.data.entry.forEach((rec) => { expect(rec.response.status).to.match(/201|200/); }); }); Then("the patient data in the Jempi client registry", async function () { - const patientResource = this.fhirBundleSentResult.data.entry.filter(rec => rec.response.location.match('Patient'))[0]; + const patientResource = this.fhirBundleSentResult.data.entry.filter((rec) => + rec.response.location.match("Patient") + )[0]; - PatientID = patientResource.response.location.split('/')[1]; + PatientID = patientResource.response.location.split("/")[1]; - const patient = await sendRequest(`http://${HOST}:5001/fhir/links/Patient/${PatientID}`, 'GET'); + const patient = await sendRequest( + `http://${HOST}:5001/fhir/Patient/${PatientID}`, + "GET" + ); - expect(patient.data.link.filter(pat => pat.other.reference.match(`Patient/${PatientID}`)).length).to.equal(1); + expect( + patient.data.link.filter((pat) => + pat.other.reference.match(`Patient/${PatientID}`) + ).length + ).to.equal(1); }); Then("I should get a successful summary response", function () { @@ -96,22 +125,22 @@ Then("I should get a successful everything response", function () { }); Then("a request to fetch data from the cdr should fail", async function () { - await sendRequest(`http://${HOST}:5001/fhir/links/Patient/${PatientID}`).catch(err => { - expect(err.message).to.match(/ECONNREFUSED|socket hang up|ETIMEDOUT/); - }); + await sendRequest(`http://${HOST}:5001/fhir/Patient/${PatientID}`).catch( + (err) => { + expect(err.message).to.match(/ECONNREFUSED|socket hang up|ETIMEDOUT/); + } + ); }); Then("the data should be stored in clickhouse", async function () { await new Promise((resolve) => { - setTimeout(() => resolve(), 20000) + setTimeout(() => resolve(), 20000); }); - const patient = await clickhouse.query( - query("patient_example"), - ).toPromise(); - const observation = await clickhouse.query( - query("observation_example") - ).toPromise(); + const patient = await clickhouse.query(query("patient_example")).toPromise(); + const observation = await clickhouse + .query(query("observation_example")) + .toPromise(); expect(JSON.parse(patient).rows).to.be.greaterThan(0); expect(JSON.parse(observation).rows).to.be.greaterThan(0); From e9979d65de68a88f79acb5e16f9f08cb6772bdce Mon Sep 17 00:00:00 2001 From: drono Date: Thu, 16 May 2024 06:34:15 +0300 Subject: [PATCH 04/46] Fix failing tests --- fhir-ig-importer/docker-compose.yml | 2 ++ fhir-ig-importer/importer/docker-compose.config.yml | 1 + kafka-mapper-consumer/docker-compose.config.yml | 1 + kafka-mapper-consumer/docker-compose.yml | 7 ++++++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fhir-ig-importer/docker-compose.yml b/fhir-ig-importer/docker-compose.yml index 43c0be1a..1faf0253 100644 --- a/fhir-ig-importer/docker-compose.yml +++ b/fhir-ig-importer/docker-compose.yml @@ -6,6 +6,7 @@ services: networks: hapi-fhir: openhim: + default: environment: HAPI_FHIR_BASE_URL: ${HAPI_FHIR_BASE_URL} HAPI_FHIR_INSTANCES: ${HAPI_FHIR_INSTANCES} @@ -27,4 +28,5 @@ networks: openhim: name: openhim_public external: true + default: diff --git a/fhir-ig-importer/importer/docker-compose.config.yml b/fhir-ig-importer/importer/docker-compose.config.yml index c6398016..0d11921a 100644 --- a/fhir-ig-importer/importer/docker-compose.config.yml +++ b/fhir-ig-importer/importer/docker-compose.config.yml @@ -46,3 +46,4 @@ networks: openhim: name: openhim_public external: true + default: diff --git a/kafka-mapper-consumer/docker-compose.config.yml b/kafka-mapper-consumer/docker-compose.config.yml index 168dd4b8..2e1b4db5 100644 --- a/kafka-mapper-consumer/docker-compose.config.yml +++ b/kafka-mapper-consumer/docker-compose.config.yml @@ -39,3 +39,4 @@ networks: openhim: name: openhim_public external: true + default: diff --git a/kafka-mapper-consumer/docker-compose.yml b/kafka-mapper-consumer/docker-compose.yml index c146a75c..cc031e00 100644 --- a/kafka-mapper-consumer/docker-compose.yml +++ b/kafka-mapper-consumer/docker-compose.yml @@ -21,7 +21,8 @@ services: networks: clickhouse: kafka: - + openhim: + default: kafka-mapper-consumer-ui: image: ${KAFKA_CONSUMER_MAPPER_UI_VERSION} networks: @@ -41,3 +42,7 @@ networks: kafka: name: kafka_public external: true + openhim: + name: openhim_public + external: true + default: From d6f8cb640e501c426883234a84ce6bcb9a776701 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Thu, 16 May 2024 09:27:55 +0200 Subject: [PATCH 05/46] Add correct assertion THe mpi mediator has been modified and the returned response has a different structure --- test/cucumber/features/steps/recipesSteps.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/cucumber/features/steps/recipesSteps.js b/test/cucumber/features/steps/recipesSteps.js index 8d24c0b3..5785eaf4 100644 --- a/test/cucumber/features/steps/recipesSteps.js +++ b/test/cucumber/features/steps/recipesSteps.js @@ -109,11 +109,7 @@ Then("the patient data in the Jempi client registry", async function () { "GET" ); - expect( - patient.data.link.filter((pat) => - pat.other.reference.match(`Patient/${PatientID}`) - ).length - ).to.equal(1); + expect(patient.data.id).to.be.equal(PatientID); }); Then("I should get a successful summary response", function () { From 5a7c3689f6d008b22cf572add20b098cb4920557 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Thu, 16 May 2024 09:29:39 +0200 Subject: [PATCH 06/46] Ensure that the entry property in the bundle is always an array --- client-registry-jempi/importer/mapping-mediator/searchAll.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-registry-jempi/importer/mapping-mediator/searchAll.json b/client-registry-jempi/importer/mapping-mediator/searchAll.json index 49134fca..c555e89f 100644 --- a/client-registry-jempi/importer/mapping-mediator/searchAll.json +++ b/client-registry-jempi/importer/mapping-mediator/searchAll.json @@ -9,7 +9,7 @@ }, "inputTransforms": { "total": "$count(lookupRequests.jempiSearchAll.data.goldenRecords)", - "entry": "$map(lookupRequests.jempiSearchAll.data.goldenRecords, function($v) {{'fullUrl': 'Patient/' & $v.goldenId, 'resource': {'resourceType': 'Patient','id': $v.goldenId,'name': {'given': [$v.demographicData.givenName],'family': $v.demographicData.familyName},'address': [{'city': $v.demographicData.city}],'birthDate': $v.demographicData.dob,'telecom': [{'value': $v.demographicData.phoneNumber,'system': 'phone'}],'identifier': [{'system': $v.sourceId.facility,'value': $v.sourceId.patient},{'system': 'NationalID','value': $v.demographicData.nationalId}],'gender': $v.demographicData.gender}}})" + "entry": "$append([], $map(lookupRequests.jempiSearchAll.data.goldenRecords, function($v) {{'fullUrl': 'Patient/' & $v.goldenId, 'resource': {'resourceType': 'Patient','id': $v.goldenId,'name': {'given': [$v.demographicData.givenName],'family': $v.demographicData.familyName},'address': [{'city': $v.demographicData.city}],'birthDate': $v.demographicData.dob,'telecom': [{'value': $v.demographicData.phoneNumber,'system': 'phone'}],'identifier': [{'system': $v.sourceId.facility,'value': $v.sourceId.patient},{'system': 'NationalID','value': $v.demographicData.nationalId}],'gender': $v.demographicData.gender}}}))" }, "inputMapping": { "constants.resourceType": "resourceType", From feccb35d5457ae28d2076725bc687a29e7d7f8fe Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Fri, 17 May 2024 11:42:48 +0200 Subject: [PATCH 07/46] Add jempi network for the services to communicate This also adds bootstrapper node placement. Has to be on the leader where the commands are run as we run a command in the bootstrapper docker container --- client-registry-jempi/docker-compose.api.yml | 5 +++++ .../docker-compose.combined-cluster.yml | 17 ++++++++++++++++- .../docker-compose.combined.yml | 12 +++++++++++- .../docker-compose.dgraph-zero-cluster.yml | 13 ++++++++++++- .../docker-compose.dgraph-zero.yml | 7 +++++++ client-registry-jempi/docker-compose.dgraph.yml | 13 +++++++++++++ client-registry-jempi/swarm.sh | 11 +++++------ 7 files changed, 69 insertions(+), 9 deletions(-) diff --git a/client-registry-jempi/docker-compose.api.yml b/client-registry-jempi/docker-compose.api.yml index 4cf156de..7d218748 100644 --- a/client-registry-jempi/docker-compose.api.yml +++ b/client-registry-jempi/docker-compose.api.yml @@ -33,6 +33,7 @@ services: reverse-proxy: kafka: default: + jempi: jempi-api-kc: @@ -77,6 +78,7 @@ services: reverse-proxy: kafka: default: + jempi: volumes: @@ -87,6 +89,9 @@ networks: reverse-proxy: name: reverse-proxy_public external: true + jempi: + name: jempi_public + external: true kafka: name: kafka_public external: true diff --git a/client-registry-jempi/docker-compose.combined-cluster.yml b/client-registry-jempi/docker-compose.combined-cluster.yml index ea3bd37d..2781e809 100644 --- a/client-registry-jempi/docker-compose.combined-cluster.yml +++ b/client-registry-jempi/docker-compose.combined-cluster.yml @@ -6,7 +6,13 @@ services: placement: constraints: - "node.labels.name==node-1" - + + jempi-bootstrapper: + deploy: + placement: + constraints: + - "node.labels.name==node-1" + jempi-postgresql-02: image: bitnami/postgresql-repmgr:15.2.0 environment: @@ -36,6 +42,8 @@ services: configs: - target: /docker-entrypoint-initdb.d/jempi_psql_init_db.sql source: jempi_psql_init_db.sql + networks: + jempi: jempi-postgresql-03: image: bitnami/postgresql-repmgr:15.2.0 @@ -66,7 +74,14 @@ services: configs: - target: /docker-entrypoint-initdb.d/jempi_psql_init_db.sql source: jempi_psql_init_db.sql + networks: + jempi: volumes: jempi-psql-02-data: jempi-psql-03-data: + +networks: + jempi: + name: jempi_public + external: true diff --git a/client-registry-jempi/docker-compose.combined.yml b/client-registry-jempi/docker-compose.combined.yml index 3bca3f1e..0e6a1a2b 100644 --- a/client-registry-jempi/docker-compose.combined.yml +++ b/client-registry-jempi/docker-compose.combined.yml @@ -19,6 +19,7 @@ services: networks: kafka: default: + jempi: jempi-etl: @@ -37,6 +38,7 @@ services: networks: kafka: default: + jempi: jempi-controller: @@ -70,6 +72,7 @@ services: networks: kafka: default: + jempi: jempi-linker: @@ -104,6 +107,7 @@ services: networks: kafka: default: + jempi: jempi-bootstrapper: image: jembi/jempi-bootstrapper:${JEMPI_BOOTSTRAPPER_IMAGE_TAG} @@ -124,6 +128,7 @@ services: networks: kafka: default: + jempi: jempi-postgresql-01: image: bitnami/postgresql-repmgr:15.2.0 @@ -151,6 +156,8 @@ services: configs: - target: /docker-entrypoint-initdb.d/jempi_psql_init_db.sql source: jempi_psql_init_db.sql + networks: + jempi: volumes: jempi-psql-01-data: @@ -161,7 +168,10 @@ networks: kafka: name: kafka_public external: true - defualt: + default: + jempi: + name: jempi_public + external: true configs: diff --git a/client-registry-jempi/docker-compose.dgraph-zero-cluster.yml b/client-registry-jempi/docker-compose.dgraph-zero-cluster.yml index 853f7c7f..fe7e61f8 100644 --- a/client-registry-jempi/docker-compose.dgraph-zero-cluster.yml +++ b/client-registry-jempi/docker-compose.dgraph-zero-cluster.yml @@ -7,7 +7,9 @@ services: constraints: - node.labels.name == node-1 command: dgraph zero --my=jempi-zero-01:5080 --replicas 3 --bindall --raft "idx=1" - + networks: + jempi: + jempi-zero-02: image: dgraph/dgraph:v22.0.0 volumes: @@ -25,6 +27,8 @@ services: restart_policy: condition: on-failure command: dgraph zero --my=jempi-zero-02:5080 --replicas 3 --peer=jempi-zero-01:5080 --raft "idx=2" + networks: + jempi: jempi-zero-03: image: dgraph/dgraph:v22.0.0 @@ -43,7 +47,14 @@ services: restart_policy: condition: on-failure command: dgraph zero --my=jempi-zero-03:5080 --replicas 3 --peer=jempi-zero-01:5080 --raft "idx=3" + networks: + jempi: volumes: jempi-zero-02-data: jempi-zero-03-data: + +networks: + jempi: + name: jempi_public + external: true diff --git a/client-registry-jempi/docker-compose.dgraph-zero.yml b/client-registry-jempi/docker-compose.dgraph-zero.yml index ac1974e3..8b8da6d0 100644 --- a/client-registry-jempi/docker-compose.dgraph-zero.yml +++ b/client-registry-jempi/docker-compose.dgraph-zero.yml @@ -15,6 +15,13 @@ services: restart_policy: condition: on-failure command: dgraph zero --my=jempi-zero-01:5080 --replicas 1 + networks: + jempi: volumes: jempi-zero-01-data: + +networks: + jempi: + name: jempi_public + external: true diff --git a/client-registry-jempi/docker-compose.dgraph.yml b/client-registry-jempi/docker-compose.dgraph.yml index 296aff7d..93ada3f7 100644 --- a/client-registry-jempi/docker-compose.dgraph.yml +++ b/client-registry-jempi/docker-compose.dgraph.yml @@ -16,6 +16,8 @@ services: restart_policy: condition: on-failure command: dgraph alpha --my=jempi-alpha-01:7080 --zero=jempi-zero-01:5080 --security whitelist=0.0.0.0/0 --telemetry "sentry=false;" + networks: + jempi: jempi-alpha-02: image: dgraph/dgraph:v22.0.0 @@ -32,6 +34,8 @@ services: restart_policy: condition: on-failure command: dgraph alpha --my=jempi-alpha-02:7081 --zero=jempi-zero-01:5080 --security whitelist=0.0.0.0/0 -o 1 --telemetry "sentry=false;" + networks: + jempi: jempi-alpha-03: image: dgraph/dgraph:v22.0.0 @@ -48,6 +52,8 @@ services: restart_policy: condition: on-failure command: dgraph alpha --my=jempi-alpha-03:7082 --zero=jempi-zero-01:5080 --security whitelist=0.0.0.0/0 -o 2 --telemetry "sentry=false;" + networks: + jempi: jempi-ratel: image: dgraph/ratel:v21.03.2 @@ -61,8 +67,15 @@ services: restart_policy: condition: on-failure command: dgraph-ratel + networks: + jempi: volumes: jempi-alpha-01-data: jempi-alpha-02-data: jempi-alpha-03-data: + +networks: + jempi: + name: jempi_public + external: true diff --git a/client-registry-jempi/swarm.sh b/client-registry-jempi/swarm.sh index 92e57aa2..d1323691 100644 --- a/client-registry-jempi/swarm.sh +++ b/client-registry-jempi/swarm.sh @@ -52,12 +52,11 @@ function initialize_package() { log info "Running package in PROD mode" fi - # Jempi not working in clustered mode, temporarily disable - # if [[ "$CLUSTERED_MODE" == "true" ]]; then - # dgraph_cluster_compose_param="docker-compose.dgraph-cluster.yml" - # dgraph_zero_cluster_compose_param="docker-compose.dgraph-zero-cluster.yml" - # combined_cluster_compose_param="docker-compose.combined-cluster.yml" - # fi + if [[ "$CLUSTERED_MODE" == "true" ]]; then + dgraph_cluster_compose_param="docker-compose.dgraph-cluster.yml" + dgraph_zero_cluster_compose_param="docker-compose.dgraph-zero-cluster.yml" + combined_cluster_compose_param="docker-compose.combined-cluster.yml" + fi ( log info "Importing JeMPI Kafka topics" From fb5eb07dc04b27c622125cfc7e4595b6a6d86f67 Mon Sep 17 00:00:00 2001 From: drono Date: Thu, 16 May 2024 10:56:50 +0300 Subject: [PATCH 08/46] Fix kafka consumer failing test --- test/cucumber/features/single-mode/kafka-packages.feature | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/cucumber/features/single-mode/kafka-packages.feature b/test/cucumber/features/single-mode/kafka-packages.feature index c37b8f08..6b398d79 100644 --- a/test/cucumber/features/single-mode/kafka-packages.feature +++ b/test/cucumber/features/single-mode/kafka-packages.feature @@ -18,11 +18,11 @@ Feature: Kafka and its dependent packages? And There should be 1 volumes Scenario: Init Kafka Mapper Consumer - Given I use parameters "package init -n=kafka-mapper-consumer --only --dev --env-file=.env.local" + Given I use parameters "package init -n=interoperability-layer-openhim,kafka-mapper-consumer --only --dev --env-file=.env.local" When I launch the platform with params Then The service "kafka-mapper-consumer" should be started with 1 replica And The service "kafka-mapper-consumer" should be connected to the networks - | clickhouse_public | kafka_public | + | clickhouse_public | kafka_public | openhim_public | Scenario: Init Message Bus Kafka Given I use parameters "package init -n=kafka-unbundler-consumer --only --dev --env-file=.env.local" @@ -32,7 +32,7 @@ Feature: Kafka and its dependent packages? | kafka_public | Scenario: Destroy Kafka and its dependent packages - Given I use parameters "package destroy -n=kafka-mapper-consumer,kafka-unbundler-consumer --dev --env-file=.env.local" + Given I use parameters "package destroy -n=kafka-mapper-consumer,kafka-unbundler-consumer,interoperability-layer-openhim --dev --env-file=.env.local" When I launch the platform with params And The service "kafka-01" should be removed And The service "kafdrop" should be removed @@ -43,4 +43,4 @@ Feature: Kafka and its dependent packages? And There should be 0 volume And There should be 0 config And There should not be network - | kafka_public | clickhouse_public | prometheus_public | + | kafka_public | clickhouse_public | prometheus_public | openhim_public | From c7ec43520a7f6edf358ef3cd3918f6b36ebb1c8b Mon Sep 17 00:00:00 2001 From: Ryan Crichton Date: Thu, 16 May 2024 15:33:52 +0200 Subject: [PATCH 09/46] Bump instant version to latest --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 87777566..8667516a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openhie/package-base:2.3.1 +FROM openhie/package-base:2.3.2 # Install yq RUN curl -L https://github.com/mikefarah/yq/releases/download/v4.23.1/yq_linux_amd64 -o /usr/bin/yq From 399a4073144541cb52684ceeb33d07921a7044b8 Mon Sep 17 00:00:00 2001 From: drono Date: Mon, 20 May 2024 08:02:51 +0300 Subject: [PATCH 10/46] fix version and disable cert verification in console. --- interoperability-layer-openhim/docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interoperability-layer-openhim/docker-compose.yml b/interoperability-layer-openhim/docker-compose.yml index 1a3ba685..5467cae6 100644 --- a/interoperability-layer-openhim/docker-compose.yml +++ b/interoperability-layer-openhim/docker-compose.yml @@ -54,6 +54,8 @@ services: KC_REALM_NAME: ${KC_REALM_NAME} KC_FRONTEND_URL: ${KC_FRONTEND_URL} OPENHIM_CONSOLE_SHOW_LOGIN: ${OPENHIM_CONSOLE_SHOW_LOGIN} + REACT_APP_OPENHIM_API_BASE_URL: ${OPENHIM_API_BASE_URL} + NODE_TLS_REJECT_UNAUTHORIZED: 0 networks: reverse-proxy: keycloak: From be327074a33c6f5396bee2a8cb479b83c7d06641 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Tue, 21 May 2024 12:08:13 +0200 Subject: [PATCH 11/46] Update version for mpi mediator --- mpi-mediator/docker-compose.yml | 2 +- mpi-mediator/package-metadata.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mpi-mediator/docker-compose.yml b/mpi-mediator/docker-compose.yml index 8f39f082..9497ecf8 100644 --- a/mpi-mediator/docker-compose.yml +++ b/mpi-mediator/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.9' services: mpi-mediator: - image: jembi/mpi-mediator:v2.2.0 + image: jembi/mpi-mediator:${MPI_MEDIATOR_VERSION} networks: openhim: kafka: diff --git a/mpi-mediator/package-metadata.json b/mpi-mediator/package-metadata.json index 85c1f07e..ce30f0a9 100644 --- a/mpi-mediator/package-metadata.json +++ b/mpi-mediator/package-metadata.json @@ -7,6 +7,7 @@ "dependencies": ["fhir-datastore-hapi-fhir", "client-registry-jempi"], "environmentVariables": { "MPI_MEDIATOR_INSTANCES": 1, + "MPI_MEDIATOR_VERSION": "v2.3.0", "OPENHIM_MEDIATOR_URL": "https://openhim-core:8080", "TRUST_SELF_SIGNED": "true", "OPENHIM_USERNAME": "root@openhim.org", From 57fb197fa08c41c9100b819fcb8418d2141734b6 Mon Sep 17 00:00:00 2001 From: ItsMurumba Date: Wed, 22 May 2024 10:26:30 +0300 Subject: [PATCH 12/46] Adds reprocess config files --- reprocess-mediator/docker-compose.config.yml | 42 ++++++++++++ reprocess-mediator/openhimConfig.js | 72 ++++++++++++++++++++ reprocess-mediator/reprocessor-ui-app.json | 12 ++++ reprocess-mediator/swarm.sh | 1 + 4 files changed, 127 insertions(+) create mode 100644 reprocess-mediator/docker-compose.config.yml create mode 100644 reprocess-mediator/openhimConfig.js create mode 100644 reprocess-mediator/reprocessor-ui-app.json diff --git a/reprocess-mediator/docker-compose.config.yml b/reprocess-mediator/docker-compose.config.yml new file mode 100644 index 00000000..d6f51e73 --- /dev/null +++ b/reprocess-mediator/docker-compose.config.yml @@ -0,0 +1,42 @@ +version: '3.9' + +services: + # container for executing config import scripts for creating the OpenHIM channels used by the Mediator + reprocess-config-importer: + image: node:erbium-alpine + networks: + openhim: + default: + environment: + OPENHIM_API_USERNAME: ${OPENHIM_USERNAME} + OPENHIM_API_PASSWORD: ${OPENHIM_PASSWORD} + # Reject unauthorised is only needed if the OpenHIM's SSL is not setup + NODE_TLS_REJECT_UNAUTHORIZED: 0 + command: sh -c "node openhimConfig.js" + configs: + - source: reprocess-openhimConfig.js + target: /openhimConfig.js + - source: reprocess-ui-app.json + target: /reprocess-ui-app.json + deploy: + replicas: 1 + restart_policy: + condition: none + +configs: + reprocess-openhimConfig.js: + file: ./openhimConfig.js + name: reprocess-openhimConfig.js-${reprocess_openhimConfig_js_DIGEST:?err} + labels: + name: reprocess + reprocess-ui-app.json: + file: ./reprocess-ui-app.json + name: reprocess-ui-app.json-${reprocess_ui_json_DIGEST:?err} + labels: + name: reprocess + +networks: + openhim: + name: openhim_public + external: true + default: diff --git a/reprocess-mediator/openhimConfig.js b/reprocess-mediator/openhimConfig.js new file mode 100644 index 00000000..b6066636 --- /dev/null +++ b/reprocess-mediator/openhimConfig.js @@ -0,0 +1,72 @@ +const fs = require("fs"); +const https = require("https"); +const path = require("path"); + +("use strict"); + +const OPENHIM_CORE_SERVICE_NAME = "openhim-core"; +const OPENHIM_MEDIATOR_API_PORT = 8080; +const OPENHIM_API_PASSWORD = process.env.OPENHIM_API_PASSWORD || "instant101"; +const OPENHIM_API_USERNAME = + process.env.OPENHIM_API_USERNAME || "root@openhim.org"; + +const authHeader = Buffer.from( + `${OPENHIM_API_USERNAME}:${OPENHIM_API_PASSWORD}` +).toString("base64"); +function makeRequest(options, data) { + const req = https.request(options, (res) => { + if (res.statusCode == 401) { + throw new Error(`Incorrect OpenHIM API credentials`); + } + + if (![201, 200].includes(res.statusCode)) { + throw new Error(`Failed to import OpenHIM config: ${res.statusCode}`); + } + + console.log("Successfully Imported OpenHIM Config"); + }); + + req.on("error", (error) => { + throw new Error(`Failed to import OpenHIM config: ${error}`); + }); + + req.write(data); + req.end(); +} + +const appJsonData = JSON.parse( + fs.readFileSync(path.resolve(__dirname, "reprocessor-ui-app.json")) +); +const appData = JSON.stringify(appJsonData); + +const options = { + protocol: "https:", + hostname: OPENHIM_CORE_SERVICE_NAME, + port: OPENHIM_MEDIATOR_API_PORT, + headers: { + "Content-Type": "application/json", + Authorization: `Basic ${authHeader}`, + }, +}; + +const appReqOptions = { + ...options, + path: "/apps", + method: "POST", + headers: { + ...options.headers, + "Content-Length": appData.length, + }, +}; + +const importMapRebuildOptions = { + ...options, + path: "/apps", + method: "GET", + headers: { + ...options.headers, + }, +}; + +makeRequest(appReqOptions, appData); +makeRequest(importMapRebuildOptions, ""); diff --git a/reprocess-mediator/reprocessor-ui-app.json b/reprocess-mediator/reprocessor-ui-app.json new file mode 100644 index 00000000..a453c344 --- /dev/null +++ b/reprocess-mediator/reprocessor-ui-app.json @@ -0,0 +1,12 @@ +{ + "name": "Reprocess", + "description": "Reprocess microfrontends app", + "category": "HIE Configuration", + "type": "esmodule", + "url": "http://localhost:3030/jembi-reprocessor-mediator-microfrontend.js", + "showInPortal": true, + "showInSideBar": false, + "access_roles": ["admin"], + "icon": "https://fonts.gstatic.com/s/i/materialicons/apps/v12/24px.svg" + } + \ No newline at end of file diff --git a/reprocess-mediator/swarm.sh b/reprocess-mediator/swarm.sh index dcb182eb..bfb6d8da 100644 --- a/reprocess-mediator/swarm.sh +++ b/reprocess-mediator/swarm.sh @@ -46,6 +46,7 @@ function initialize_package() { log error "Failed to deploy package" exit 1 } + docker::deploy_config_importer $STACK "$COMPOSE_FILE_PATH/docker-compose.config.yml" "reprocess-config-importer" "reprocess" } function destroy_package() { From 76c250c0f70b09e282a77d945c26b22de0e6fa67 Mon Sep 17 00:00:00 2001 From: ItsMurumba Date: Wed, 22 May 2024 19:04:06 +0300 Subject: [PATCH 13/46] Cleanup Reprocess package --- reprocess-mediator/docker-compose.config.yml | 4 ++-- reprocess-mediator/openhimConfig.js | 2 +- .../{reprocessor-ui-app.json => reprocess-ui-app.json} | 0 reprocess-mediator/swarm.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename reprocess-mediator/{reprocessor-ui-app.json => reprocess-ui-app.json} (100%) diff --git a/reprocess-mediator/docker-compose.config.yml b/reprocess-mediator/docker-compose.config.yml index d6f51e73..1135b51e 100644 --- a/reprocess-mediator/docker-compose.config.yml +++ b/reprocess-mediator/docker-compose.config.yml @@ -28,12 +28,12 @@ configs: file: ./openhimConfig.js name: reprocess-openhimConfig.js-${reprocess_openhimConfig_js_DIGEST:?err} labels: - name: reprocess + name: reprocess-mediator reprocess-ui-app.json: file: ./reprocess-ui-app.json name: reprocess-ui-app.json-${reprocess_ui_json_DIGEST:?err} labels: - name: reprocess + name: reprocess-mediator networks: openhim: diff --git a/reprocess-mediator/openhimConfig.js b/reprocess-mediator/openhimConfig.js index b6066636..3f645ab4 100644 --- a/reprocess-mediator/openhimConfig.js +++ b/reprocess-mediator/openhimConfig.js @@ -35,7 +35,7 @@ function makeRequest(options, data) { } const appJsonData = JSON.parse( - fs.readFileSync(path.resolve(__dirname, "reprocessor-ui-app.json")) + fs.readFileSync(path.resolve(__dirname, "reprocess-ui-app.json")) ); const appData = JSON.stringify(appJsonData); diff --git a/reprocess-mediator/reprocessor-ui-app.json b/reprocess-mediator/reprocess-ui-app.json similarity index 100% rename from reprocess-mediator/reprocessor-ui-app.json rename to reprocess-mediator/reprocess-ui-app.json diff --git a/reprocess-mediator/swarm.sh b/reprocess-mediator/swarm.sh index bfb6d8da..045e8d9b 100644 --- a/reprocess-mediator/swarm.sh +++ b/reprocess-mediator/swarm.sh @@ -46,7 +46,7 @@ function initialize_package() { log error "Failed to deploy package" exit 1 } - docker::deploy_config_importer $STACK "$COMPOSE_FILE_PATH/docker-compose.config.yml" "reprocess-config-importer" "reprocess" + docker::deploy_config_importer $STACK "$COMPOSE_FILE_PATH/docker-compose.config.yml" "reprocess-config-importer" "reprocess-mediator" } function destroy_package() { From 4601f8f52e5821bcb478c0ea15a90c0a0c670b3f Mon Sep 17 00:00:00 2001 From: ItsMurumba Date: Fri, 24 May 2024 12:54:49 +0300 Subject: [PATCH 14/46] Change docker images to be configurable env variables --- reprocess-mediator/docker-compose.yml | 4 ++-- reprocess-mediator/openhimConfig.js | 2 +- reprocess-mediator/package-metadata.json | 4 ++-- reprocess-mediator/swarm.sh | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/reprocess-mediator/docker-compose.yml b/reprocess-mediator/docker-compose.yml index e1efc59a..8cbb2ed7 100644 --- a/reprocess-mediator/docker-compose.yml +++ b/reprocess-mediator/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.9' services: reprocess-mediator: - image: jembi/reprocess-mediator:${REPROCESS_CORE_VERSION} + image: ${REPROCESS_MEDIATOR_VERSION} networks: openhim: reprocess: @@ -14,7 +14,7 @@ services: REGISTER_MEDIATOR: ${REGISTER_MEDIATOR} reprocess-mediator-ui: - image: jembi/reprocess-mediator-ui:${REPROCESS_UI_VERSION} + image: ${REPROCESS_MEDIATOR_UI_VERSION} networks: openhim: reprocess: diff --git a/reprocess-mediator/openhimConfig.js b/reprocess-mediator/openhimConfig.js index 3f645ab4..e5268dd9 100644 --- a/reprocess-mediator/openhimConfig.js +++ b/reprocess-mediator/openhimConfig.js @@ -16,7 +16,7 @@ const authHeader = Buffer.from( function makeRequest(options, data) { const req = https.request(options, (res) => { if (res.statusCode == 401) { - throw new Error(`Incorrect OpenHIM API credentials`); + throw new Error("Incorrect OpenHIM API credentials"); } if (![201, 200].includes(res.statusCode)) { diff --git a/reprocess-mediator/package-metadata.json b/reprocess-mediator/package-metadata.json index 97ca4643..493fd70c 100644 --- a/reprocess-mediator/package-metadata.json +++ b/reprocess-mediator/package-metadata.json @@ -12,7 +12,7 @@ "OPENHIM_PASSWORD": "instant101", "REGISTER_MEDIATOR": "true", "REPROCESSOR_API_BASE_URL": "http://reprocess-mediator:3000", - "REPROCESS_CORE_VERSION": "v0.1.0", - "REPROCESS_UI_VERSION": "v0.1.0" + "REPROCESS_MEDIATOR_VERSION": "jembi/reprocess-mediator:v0.1.0", + "REPROCESS_MEDIATOR_UI_VERSION": "jembi/reprocess-mediator-ui:v0.1.0" } } diff --git a/reprocess-mediator/swarm.sh b/reprocess-mediator/swarm.sh index 045e8d9b..1a176658 100644 --- a/reprocess-mediator/swarm.sh +++ b/reprocess-mediator/swarm.sh @@ -3,7 +3,7 @@ declare ACTION="" declare COMPOSE_FILE_PATH="" declare UTILS_PATH="" -declare STACK="reprocess-mediator" +declare STACK="reprocess" declare MODE="" function init_vars() { From ec18ae14ecb31476cc83d4cfd255a1a19132018a Mon Sep 17 00:00:00 2001 From: ItsMurumba Date: Fri, 24 May 2024 13:58:09 +0300 Subject: [PATCH 15/46] Format json files --- .vscode/settings.json | 6 ++++-- reprocess-mediator/package-metadata.json | 4 +++- reprocess-mediator/reprocess-ui-app.json | 23 ++++++++++++----------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8d187f9c..346e0173 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,14 +3,16 @@ "files.insertFinalNewline": true, "editor.formatOnSave": true, "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "vscode.json-language-features" }, "editor.codeActionsOnSave": { "source.fixAll": "explicit" }, "json.schemas": [ { - "fileMatch": ["package-metadata.json"], + "fileMatch": [ + "package-metadata.json" + ], "url": "https://raw.githubusercontent.com/openhie/package-starter-kit/main/schema/package-metadata.schema.json" } ], diff --git a/reprocess-mediator/package-metadata.json b/reprocess-mediator/package-metadata.json index 493fd70c..2c944f90 100644 --- a/reprocess-mediator/package-metadata.json +++ b/reprocess-mediator/package-metadata.json @@ -4,7 +4,9 @@ "description": "A mediator that allows for configuring and reprocessing of transactions", "type": "use-case", "version": "1.4.2", - "dependencies": ["interoperability-layer-openhim"], + "dependencies": [ + "interoperability-layer-openhim" + ], "environmentVariables": { "TRUST_SELF_SIGNED": "true", "OPENHIM_MEDIATOR_URL": "https://openhim-core:8080", diff --git a/reprocess-mediator/reprocess-ui-app.json b/reprocess-mediator/reprocess-ui-app.json index a453c344..354c1945 100644 --- a/reprocess-mediator/reprocess-ui-app.json +++ b/reprocess-mediator/reprocess-ui-app.json @@ -1,12 +1,13 @@ { - "name": "Reprocess", - "description": "Reprocess microfrontends app", - "category": "HIE Configuration", - "type": "esmodule", - "url": "http://localhost:3030/jembi-reprocessor-mediator-microfrontend.js", - "showInPortal": true, - "showInSideBar": false, - "access_roles": ["admin"], - "icon": "https://fonts.gstatic.com/s/i/materialicons/apps/v12/24px.svg" - } - \ No newline at end of file + "name": "Reprocess", + "description": "Reprocess microfrontends app", + "category": "HIE Configuration", + "type": "esmodule", + "url": "http://localhost:3030/jembi-reprocessor-mediator-microfrontend.js", + "showInPortal": true, + "showInSideBar": false, + "access_roles": [ + "admin" + ], + "icon": "https://fonts.gstatic.com/s/i/materialicons/apps/v12/24px.svg" +} From 069145fc9c115910c0da06672026759c14aadd6a Mon Sep 17 00:00:00 2001 From: ItsMurumba Date: Fri, 24 May 2024 14:22:01 +0300 Subject: [PATCH 16/46] Format json files --- reprocess-mediator/package-metadata.json | 4 +--- reprocess-mediator/reprocess-ui-app.json | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/reprocess-mediator/package-metadata.json b/reprocess-mediator/package-metadata.json index 2c944f90..493fd70c 100644 --- a/reprocess-mediator/package-metadata.json +++ b/reprocess-mediator/package-metadata.json @@ -4,9 +4,7 @@ "description": "A mediator that allows for configuring and reprocessing of transactions", "type": "use-case", "version": "1.4.2", - "dependencies": [ - "interoperability-layer-openhim" - ], + "dependencies": ["interoperability-layer-openhim"], "environmentVariables": { "TRUST_SELF_SIGNED": "true", "OPENHIM_MEDIATOR_URL": "https://openhim-core:8080", diff --git a/reprocess-mediator/reprocess-ui-app.json b/reprocess-mediator/reprocess-ui-app.json index 354c1945..840b037b 100644 --- a/reprocess-mediator/reprocess-ui-app.json +++ b/reprocess-mediator/reprocess-ui-app.json @@ -6,8 +6,6 @@ "url": "http://localhost:3030/jembi-reprocessor-mediator-microfrontend.js", "showInPortal": true, "showInSideBar": false, - "access_roles": [ - "admin" - ], + "access_roles": ["admin"], "icon": "https://fonts.gstatic.com/s/i/materialicons/apps/v12/24px.svg" } From 541a05632661304dcee530ac3b83fdbfcadeec6b Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Tue, 16 Apr 2024 07:29:24 +0200 Subject: [PATCH 17/46] adding image variable to metadata.json and docker-compose files --- .../docker-compose.cluster.yml | 60 +++++++++---------- .../docker-compose.yml | 14 ++--- .../package-metadata.json | 3 +- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/analytics-datastore-clickhouse/docker-compose.cluster.yml b/analytics-datastore-clickhouse/docker-compose.cluster.yml index f2c6b61b..af2f3e82 100644 --- a/analytics-datastore-clickhouse/docker-compose.cluster.yml +++ b/analytics-datastore-clickhouse/docker-compose.cluster.yml @@ -1,16 +1,16 @@ -version: '3.9' +version: "3.9" services: analytics-datastore-clickhouse-01: - image: clickhouse/clickhouse-server + image: ${CLICKHOUSE_IMAGE} ulimits: noFile: 262144 volumes: - clickhouse-data-01:/var/lib/clickhouse/ hostname: analytics-datastore-clickhouse-01 - deploy: - placement: - constraints: + deploy: + placement: + constraints: - "node.labels.name==node-1" configs: - target: /etc/clickhouse-server/config.d/docker_related_config.xml @@ -36,11 +36,11 @@ services: default: analytics-datastore-clickhouse-02: - image: clickhouse/clickhouse-server + image: ${CLICKHOUSE_IMAGE} hostname: analytics-datastore-clickhouse-02 - deploy: - placement: - constraints: + deploy: + placement: + constraints: - "node.labels.name==node-2" ulimits: noFile: 262144 @@ -70,16 +70,16 @@ services: default: analytics-datastore-clickhouse-03: - image: clickhouse/clickhouse-server + image: ${CLICKHOUSE_IMAGE} hostname: analytics-datastore-clickhouse-03 - deploy: - placement: - constraints: + deploy: + placement: + constraints: - "node.labels.name==node-3" ulimits: noFile: 262144 volumes: - - clickhouse-data-03:/var/lib/clickhouse/ + - clickhouse-data-03:/var/lib/clickhouse/ configs: - target: /etc/clickhouse-server/config.d/docker_related_config.xml source: docker_related_config.xml @@ -109,7 +109,7 @@ services: ulimits: noFile: 262144 volumes: - - clickhouse-data-04:/var/lib/clickhouse/ + - clickhouse-data-04:/var/lib/clickhouse/ configs: - target: /etc/clickhouse-server/config.d/docker_related_config.xml source: docker_related_config.xml @@ -136,77 +136,77 @@ volumes: clickhouse-data-02: clickhouse-data-03: clickhouse-data-04: - + configs: docker_related_config.xml: file: ./cluster_configs/docker_related_config.xml name: docker_related_config.xml-${docker_related_config_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_enable_keeper_01.xml: file: ./cluster_configs/enable_keeper_01.xml name: enable_keeper_01.xml-${enable_keeper_01_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_enable_keeper_02.xml: file: ./cluster_configs/enable_keeper_02.xml name: enable_keeper_02.xml-${enable_keeper_02_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_enable_keeper_03.xml: file: ./cluster_configs/enable_keeper_03.xml name: enable_keeper_03.xml-${enable_keeper_03_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_macros_01.xml: file: ./cluster_configs/macros_01.xml name: macros_01.xml-${macros_01_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_macros_02.xml: file: ./cluster_configs/macros_02.xml name: macros_02.xml-${macros_02_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_macros_03.xml: file: ./cluster_configs/macros_03.xml name: macros_03.xml-${macros_03_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_macros_04.xml: file: ./cluster_configs/macros_04.xml name: macros_04.xml-${macros_04_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_remote_servers.xml: file: ./cluster_configs/remote_servers.xml name: remote_servers.xml-${remote_servers_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_use_keeper.xml: file: ./cluster_configs/use_keeper.xml name: use_keeper.xml-${use_keeper_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_metric_log.xml: file: ./general_configs/metric_log.xml name: metric_log.xml.xml-${metric_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_part_log.xml: file: ./general_configs/part_log.xml name: part_log.xml.xml-${part_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_query_log.xml: file: ./general_configs/query_log.xml name: query_log.xml.xml-${query_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_trace_log.xml: file: ./general_configs/trace_log.xml name: trace_log.xml.xml-${trace_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse networks: diff --git a/analytics-datastore-clickhouse/docker-compose.yml b/analytics-datastore-clickhouse/docker-compose.yml index ce6363a8..3f175532 100644 --- a/analytics-datastore-clickhouse/docker-compose.yml +++ b/analytics-datastore-clickhouse/docker-compose.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: analytics-datastore-clickhouse: - image: clickhouse/clickhouse-server + image: ${CLICKHOUSE_IMAGE} ulimits: noFile: 262144 volumes: @@ -15,7 +15,7 @@ services: - target: /etc/clickhouse-server/config.d/query_log.xml source: clickhouse_query_log.xml - target: /etc/clickhouse-server/config.d/trace_log.xml - source: clickhouse_trace_log.xml + source: clickhouse_trace_log.xml networks: public: default: @@ -27,22 +27,22 @@ configs: clickhouse_metric_log.xml: file: ./general_configs/metric_log.xml name: metric_log.xml.xml-${metric_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_part_log.xml: file: ./general_configs/part_log.xml name: part_log.xml.xml-${part_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_query_log.xml: file: ./general_configs/query_log.xml name: query_log.xml.xml-${query_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse clickhouse_trace_log.xml: file: ./general_configs/trace_log.xml name: trace_log.xml.xml-${trace_log_xml_DIGEST:?err} - labels: + labels: name: clickhouse networks: diff --git a/analytics-datastore-clickhouse/package-metadata.json b/analytics-datastore-clickhouse/package-metadata.json index 680a3bb7..3dadee9a 100644 --- a/analytics-datastore-clickhouse/package-metadata.json +++ b/analytics-datastore-clickhouse/package-metadata.json @@ -7,6 +7,7 @@ "dependencies": [], "environmentVariables": { "CLICKHOUSE_HOST": "analytics-datastore-clickhouse", - "CLICKHOUSE_PORT": "8123" + "CLICKHOUSE_PORT": "8123", + "CLICKHOUSE_IMAGE": "clickhouse/clickhouse-server" } } From e51e5163ab956bc229ee1a24d7109b764dbb63f1 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Thu, 25 Apr 2024 07:33:45 +0200 Subject: [PATCH 18/46] adding deployment placement --- analytics-datastore-clickhouse/docker-compose.cluster.yml | 6 +++--- analytics-datastore-clickhouse/package-metadata.json | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/analytics-datastore-clickhouse/docker-compose.cluster.yml b/analytics-datastore-clickhouse/docker-compose.cluster.yml index af2f3e82..4e970066 100644 --- a/analytics-datastore-clickhouse/docker-compose.cluster.yml +++ b/analytics-datastore-clickhouse/docker-compose.cluster.yml @@ -11,7 +11,7 @@ services: deploy: placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${ANALYTICS_DATASTORE_CLICKHOUSE_01_PLACEMENT}" configs: - target: /etc/clickhouse-server/config.d/docker_related_config.xml source: docker_related_config.xml @@ -41,7 +41,7 @@ services: deploy: placement: constraints: - - "node.labels.name==node-2" + - "node.labels.name==${ANALYTICS_DATASTORE_CLICKHOUSE_02_PLACEMENT}" ulimits: noFile: 262144 volumes: @@ -75,7 +75,7 @@ services: deploy: placement: constraints: - - "node.labels.name==node-3" + - "node.labels.name==${ANALYTICS_DATASTORE_CLICKHOUSE_03_PLACEMENT}" ulimits: noFile: 262144 volumes: diff --git a/analytics-datastore-clickhouse/package-metadata.json b/analytics-datastore-clickhouse/package-metadata.json index 3dadee9a..4bc99cef 100644 --- a/analytics-datastore-clickhouse/package-metadata.json +++ b/analytics-datastore-clickhouse/package-metadata.json @@ -8,6 +8,9 @@ "environmentVariables": { "CLICKHOUSE_HOST": "analytics-datastore-clickhouse", "CLICKHOUSE_PORT": "8123", - "CLICKHOUSE_IMAGE": "clickhouse/clickhouse-server" + "CLICKHOUSE_IMAGE": "clickhouse/clickhouse-server", + "ANALYTICS_DATASTORE_CLICKHOUSE_01_PLACEMENT": "node-1", + "ANALYTICS_DATASTORE_CLICKHOUSE_02_PLACEMENT": "node-2", + "ANALYTICS_DATASTORE_CLICKHOUSE_03_PLACEMENT": "node-3" } } From e7b84adf3fc4a75b0e50174ebee52b0076345540 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Tue, 16 Apr 2024 08:05:26 +0200 Subject: [PATCH 19/46] adding image definition to metadata.json file --- .../docker-compose.certs.yml | 2 +- .../docker-compose.cluster.yml | 32 +++++++++---------- .../docker-compose.yml | 10 +++--- .../package-metadata.json | 3 +- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/analytics-datastore-elastic-search/docker-compose.certs.yml b/analytics-datastore-elastic-search/docker-compose.certs.yml index 699bc390..3798771f 100644 --- a/analytics-datastore-elastic-search/docker-compose.certs.yml +++ b/analytics-datastore-elastic-search/docker-compose.certs.yml @@ -2,7 +2,7 @@ version: "3.9" services: create_certs: - image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0 + image: ${ES_IMAGE} deploy: placement: constraints: diff --git a/analytics-datastore-elastic-search/docker-compose.cluster.yml b/analytics-datastore-elastic-search/docker-compose.cluster.yml index 7b802498..e6163a85 100644 --- a/analytics-datastore-elastic-search/docker-compose.cluster.yml +++ b/analytics-datastore-elastic-search/docker-compose.cluster.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: analytics-datastore-elastic-search-01: - image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0 + image: ${ES_IMAGE} ulimits: memlock: soft: -1 @@ -23,13 +23,13 @@ services: discovery.seed_hosts: analytics-datastore-elastic-search-02,analytics-datastore-elastic-search-03 cluster.initial_master_nodes: es01 xpack.license.self_generated.type: basic - bootstrap.memory_lock: 'true' - xpack.security.enabled: 'true' - xpack.security.http.ssl.enabled: 'false' + bootstrap.memory_lock: "true" + xpack.security.enabled: "true" + xpack.security.http.ssl.enabled: "false" xpack.security.http.ssl.key: certs/es01/es01.key xpack.security.http.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.http.ssl.certificate: certs/es01/es01.crt - xpack.security.transport.ssl.enabled: 'true' + xpack.security.transport.ssl.enabled: "true" xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.transport.ssl.certificate: certs/es01/es01.crt @@ -52,7 +52,7 @@ services: public: analytics-datastore-elastic-search-02: - image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0 + image: ${ES_IMAGE} ulimits: memlock: soft: -1 @@ -72,14 +72,14 @@ services: cluster.name: es-cluster discovery.seed_hosts: analytics-datastore-elastic-search-01,analytics-datastore-elastic-search-03 cluster.initial_master_nodes: es01 - bootstrap.memory_lock: 'true' - xpack.security.enabled: 'true' + bootstrap.memory_lock: "true" + xpack.security.enabled: "true" xpack.license.self_generated.type: basic - xpack.security.http.ssl.enabled: 'false' + xpack.security.http.ssl.enabled: "false" xpack.security.http.ssl.key: certs/es02/es02.key xpack.security.http.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.http.ssl.certificate: certs/es02/es02.crt - xpack.security.transport.ssl.enabled: 'true' + xpack.security.transport.ssl.enabled: "true" xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.transport.ssl.certificate: certs/es02/es02.crt @@ -102,7 +102,7 @@ services: public: analytics-datastore-elastic-search-03: - image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0 + image: ${ES_IMAGE} ulimits: memlock: soft: -1 @@ -122,14 +122,14 @@ services: cluster.name: es-cluster discovery.seed_hosts: analytics-datastore-elastic-search-01,analytics-datastore-elastic-search-02 cluster.initial_master_nodes: es01 - bootstrap.memory_lock: 'true' - xpack.security.enabled: 'true' + bootstrap.memory_lock: "true" + xpack.security.enabled: "true" xpack.license.self_generated.type: basic - xpack.security.http.ssl.enabled: 'false' + xpack.security.http.ssl.enabled: "false" xpack.security.http.ssl.key: certs/es03/es03.key xpack.security.http.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.http.ssl.certificate: certs/es03/es03.crt - xpack.security.transport.ssl.enabled: 'true' + xpack.security.transport.ssl.enabled: "true" xpack.security.transport.ssl.verification_mode: certificate xpack.security.transport.ssl.certificate_authorities: certs/ca/ca.crt xpack.security.transport.ssl.certificate: certs/es03/es03.crt diff --git a/analytics-datastore-elastic-search/docker-compose.yml b/analytics-datastore-elastic-search/docker-compose.yml index f6b86b78..e49b2916 100644 --- a/analytics-datastore-elastic-search/docker-compose.yml +++ b/analytics-datastore-elastic-search/docker-compose.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: analytics-datastore-elastic-search: - image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0 + image: ${ES_IMAGE} ulimits: memlock: soft: -1 @@ -16,9 +16,9 @@ services: environment: node.name: es01 discovery.type: single-node - bootstrap.memory_lock: 'true' - xpack.security.enabled: 'true' - xpack.monitoring.collection.enabled: 'true' + bootstrap.memory_lock: "true" + xpack.security.enabled: "true" + xpack.monitoring.collection.enabled: "true" ES_JAVA_OPTS: ${ES_HEAP_SIZE} search.max_buckets: 1000000 search.default_search_timeout: -1 diff --git a/analytics-datastore-elastic-search/package-metadata.json b/analytics-datastore-elastic-search/package-metadata.json index 0f305edb..48ac5da5 100644 --- a/analytics-datastore-elastic-search/package-metadata.json +++ b/analytics-datastore-elastic-search/package-metadata.json @@ -17,6 +17,7 @@ "ES_HEAP_SIZE": "-Xms2048m -Xmx2048m", "ES_SSL": "false", "ES_MEMORY_LIMIT": "3G", - "ES_MEMORY_RESERVE": "500M" + "ES_MEMORY_RESERVE": "500M", + "ES_IMAGE": "docker.elastic.co/elasticsearch/elasticsearch:7.13.0" } } From 417530e219d9dce5cfcce0c92a64cc7230b8e291 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Wed, 17 Apr 2024 08:40:13 +0200 Subject: [PATCH 20/46] adding placement and image version for pg in metadata file --- .../docker-compose.postgres.cluster.yml | 10 +++++----- .../docker-compose.postgres.yml | 2 +- dashboard-visualiser-superset/package-metadata.json | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dashboard-visualiser-superset/docker-compose.postgres.cluster.yml b/dashboard-visualiser-superset/docker-compose.postgres.cluster.yml index e4c6ff84..b6e31cbd 100644 --- a/dashboard-visualiser-superset/docker-compose.postgres.cluster.yml +++ b/dashboard-visualiser-superset/docker-compose.postgres.cluster.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: postgres-metastore: - deploy: - placement: - constraints: - - "node.labels.name==node-2" + deploy: + placement: + constraints: + - "node.labels.name==${POSTGRES_METASTORE}" diff --git a/dashboard-visualiser-superset/docker-compose.postgres.yml b/dashboard-visualiser-superset/docker-compose.postgres.yml index cc4cceae..10c0a68a 100644 --- a/dashboard-visualiser-superset/docker-compose.postgres.yml +++ b/dashboard-visualiser-superset/docker-compose.postgres.yml @@ -2,7 +2,7 @@ version: "3.9" services: postgres-metastore: - image: postgres:16.2 + image: ${POSTGRES_IMAGE} environment: POSTGRES_USER: ${SUPERSET_POSTGRESQL_USERNAME} POSTGRES_PASSWORD: ${SUPERSET_POSTGRESQL_PASSWORD} diff --git a/dashboard-visualiser-superset/package-metadata.json b/dashboard-visualiser-superset/package-metadata.json index a5068d95..69867d91 100644 --- a/dashboard-visualiser-superset/package-metadata.json +++ b/dashboard-visualiser-superset/package-metadata.json @@ -7,6 +7,8 @@ "dependencies": ["analytics-datastore-clickhouse"], "environmentVariables": { "SUPERSET_IMAGE": "apache/superset:3.1.1", + "POSTGRES_IMAGE": "postgres:16.2", + "POSTGRES_METASTORE": "node-2", "SUPERSET_ENABLED_FEATURE_FLAGS": "DASHBOARD_RBAC", "SUPERSET_USERNAME": "admin", "SUPERSET_FIRSTNAME": "SUPERSET", From 97695906ae5bdb1ed21491bd9fca1667865ce759 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Tue, 16 Apr 2024 15:42:10 +0200 Subject: [PATCH 21/46] Update Kibana image and add KIBANA_IMAGE environment variable --- dashboard-visualiser-kibana/docker-compose.yml | 6 +++--- dashboard-visualiser-kibana/package-metadata.json | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dashboard-visualiser-kibana/docker-compose.yml b/dashboard-visualiser-kibana/docker-compose.yml index 6064821d..30e3634f 100644 --- a/dashboard-visualiser-kibana/docker-compose.yml +++ b/dashboard-visualiser-kibana/docker-compose.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: dashboard-visualiser-kibana: - image: docker.elastic.co/kibana/kibana:7.13.0 + image: ${KIBANA_IMAGE} healthcheck: test: curl --fail http://localhost:5601 || exit 1 interval: 10s @@ -33,7 +33,7 @@ configs: kibana-kibana-cluster.yml: file: ./kibana.cluster.yml name: kibana-kibana-cluster.yml-${kibana_kibana_cluster_yml_DIGEST:?err} - labels: + labels: name: kibana networks: diff --git a/dashboard-visualiser-kibana/package-metadata.json b/dashboard-visualiser-kibana/package-metadata.json index 7a3bb05d..95d8b144 100644 --- a/dashboard-visualiser-kibana/package-metadata.json +++ b/dashboard-visualiser-kibana/package-metadata.json @@ -9,6 +9,7 @@ "KIBANA_INSTANCES": 1, "ES_LEADER_NODE": "analytics-datastore-elastic-search", "ES_KIBANA_SYSTEM": "dev_password_only", + "KIBANA_IMAGE": "docker.elastic.co/kibana/kibana:7.13.0", "KIBANA_PASSWORD": "dev_password_only", "KIBANA_USERNAME": "elastic", "KIBANA_YML_CONFIG": "kibana-kibana.yml", From 060ca81e4faa3a375c4f52bf54ba0a6f2e8cd539 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Tue, 16 Apr 2024 15:37:50 +0200 Subject: [PATCH 22/46] add image and max replicas to metadata file --- .../docker-compose.yml | 18 +++++++++--------- .../package-metadata.json | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/dashboard-visualiser-jsreport/docker-compose.yml b/dashboard-visualiser-jsreport/docker-compose.yml index 3d87f3c7..1d145e0f 100644 --- a/dashboard-visualiser-jsreport/docker-compose.yml +++ b/dashboard-visualiser-jsreport/docker-compose.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: dashboard-visualiser-jsreport: - image: jsreport/jsreport:3.2.0 + image: ${JS_REPORT_IMAGE} healthcheck: test: wget --no-verbose --tries=1 --spider -q http://localhost:5488/api/ping || exit 1 interval: 10s @@ -11,7 +11,7 @@ services: start_period: 10s deploy: placement: - max_replicas_per_node: 1 + max_replicas_per_node: ${JS_REPORT_MAX_REPLICAS_PER_NODE} replicas: ${JS_REPORT_INSTANCES} resources: limits: @@ -21,14 +21,14 @@ services: cpus: ${JS_REPORT_CPU_RESERVE} memory: ${JS_REPORT_MEMORY_RESERVE} labels: - co.elastic.metrics/module: 'docker' - co.elastic.metrics/metricsets: 'cpu,memory,diskio,info,healthcheck,container' + co.elastic.metrics/module: "docker" + co.elastic.metrics/metricsets: "cpu,memory,diskio,info,healthcheck,container" environment: - allowLocalFilesAccess: 'true' - extensions_fsStore_dataDirectory: 'jsreport/data' - extensions_fsStore_externalModificationsSync: 'true' + allowLocalFilesAccess: "true" + extensions_fsStore_dataDirectory: "jsreport/data" + extensions_fsStore_externalModificationsSync: "true" extensions_authentication_cookieSession_secret: ${JS_REPORT_SECRET} - extensions_authentication_admin_username: 'admin' + extensions_authentication_admin_username: "admin" extensions_authentication_admin_password: ${JS_REPORT} ES_PASSWORD: ${ES_ELASTIC} licenseKey: ${JS_REPORT_LICENSE_KEY} diff --git a/dashboard-visualiser-jsreport/package-metadata.json b/dashboard-visualiser-jsreport/package-metadata.json index 20e1ad78..a06074c6 100644 --- a/dashboard-visualiser-jsreport/package-metadata.json +++ b/dashboard-visualiser-jsreport/package-metadata.json @@ -6,7 +6,9 @@ "version": "0.0.1", "dependencies": ["analytics-datastore-elastic-search"], "environmentVariables": { + "JS_REPORT_IMAGE": "jsreport/jsreport:3.2.0", "JS_REPORT_INSTANCES": "1", + "JS_REPORT_MAX_REPLICAS_PER_NODE": "1", "JS_REPORT_USERNAME": "admin", "JS_REPORT_SECRET": "dev_secret_only", "JS_REPORT": "dev_password_only", From 9ca3ad835f5c0e67535a4bf0dcca32605414511d Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Thu, 18 Apr 2024 09:24:44 +0200 Subject: [PATCH 23/46] Update docker-compose files and package metadata --- monitoring/docker-compose.cluster.yml | 56 +++++++++------------------ monitoring/docker-compose.yml | 20 ++++------ monitoring/package-metadata.json | 11 ++++++ 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/monitoring/docker-compose.cluster.yml b/monitoring/docker-compose.cluster.yml index e627fa1c..87eb7d62 100644 --- a/monitoring/docker-compose.cluster.yml +++ b/monitoring/docker-compose.cluster.yml @@ -1,20 +1,20 @@ -version: '3.9' +version: "3.9" services: prometheus: deploy: placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${PROMETHEUS_PLACEMENT}" replicas: 1 prometheus_backup: - image: prom/prometheus:v2.38.0 + image: ${PROMETHEUS_BACKUP_IMAGE} user: root deploy: placement: constraints: - - "node.labels.name!=node-1" + - "node.labels.name!=${PROMETHEUS_BACKUP_PLACEMENT}" replicas: 1 volumes: - prometheus_data_backup:/prometheus @@ -23,11 +23,11 @@ services: - target: /etc/prometheus/prometheus.yml source: prometheus.yml command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--web.console.libraries=/etc/prometheus/console_libraries' - - '--web.console.templates=/etc/prometheus/consoles' - - '--web.enable-lifecycle' + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus" + - "--web.console.libraries=/etc/prometheus/console_libraries" + - "--web.console.templates=/etc/prometheus/consoles" + - "--web.enable-lifecycle" networks: public: default: @@ -36,23 +36,17 @@ services: deploy: placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${MINIO_01_PLACEMENT}" minio-02: - image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z + image: ${MINIO_IMAGE} entrypoint: sh command: -c 'mkdir -p /data1/loki /data2/loki && minio server --console-address ":9001" http://minio-0{1...4}/data{1...2}' environment: MINIO_ROOT_USER: ${MO_SECURITY_ADMIN_USER} MINIO_ROOT_PASSWORD: ${MO_SECURITY_ADMIN_PASSWORD} healthcheck: - test: - [ - "CMD", - "curl", - "-f", - "http://localhost:9000/minio/health/live" - ] + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 @@ -63,24 +57,18 @@ services: deploy: placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${MINIO_02_PLACEMENT}" replicas: 1 minio-03: - image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z + image: ${MINIO_IMAGE} entrypoint: sh command: -c 'mkdir -p /data1/loki /data2/loki && minio server --console-address ":9001" http://minio-0{1...4}/data{1...2}' environment: MINIO_ROOT_USER: ${MO_SECURITY_ADMIN_USER} MINIO_ROOT_PASSWORD: ${MO_SECURITY_ADMIN_PASSWORD} healthcheck: - test: - [ - "CMD", - "curl", - "-f", - "http://localhost:9000/minio/health/live" - ] + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 @@ -91,24 +79,18 @@ services: deploy: placement: constraints: - - "node.labels.name==node-2" + - "node.labels.name==${MINIO_03_PLACEMENT}" replicas: 1 minio-04: - image: quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z + image: ${MINIO_IMAGE} entrypoint: sh command: -c 'mkdir -p /data1/loki /data2/loki && minio server --console-address ":9001" http://minio-0{1...4}/data{1...2}' environment: MINIO_ROOT_USER: ${MO_SECURITY_ADMIN_USER} MINIO_ROOT_PASSWORD: ${MO_SECURITY_ADMIN_PASSWORD} healthcheck: - test: - [ - "CMD", - "curl", - "-f", - "http://localhost:9000/minio/health/live" - ] + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 @@ -119,7 +101,7 @@ services: deploy: placement: constraints: - - "node.labels.name==node-3" + - "node.labels.name==${MINIO_04_PLACEMENT}" replicas: 1 volumes: diff --git a/monitoring/docker-compose.yml b/monitoring/docker-compose.yml index 0e1b34e0..7f2b06cd 100644 --- a/monitoring/docker-compose.yml +++ b/monitoring/docker-compose.yml @@ -1,8 +1,8 @@ -version: '3.9' +version: "3.9" services: grafana: - image: grafana/grafana-oss:9.2.3 + image: ${GRAFANA_IMAGE} volumes: - grafana-data:/var/lib/grafana environment: @@ -97,14 +97,14 @@ services: image: quay.io/prometheus/node-exporter:v1.3.1 hostname: "{{.Node.ID}}" command: - - '--path.rootfs=/host' + - "--path.rootfs=/host" volumes: - - '/:/host:ro,rslave' + - "/:/host:ro,rslave" deploy: mode: global loki: - image: grafana/loki:2.6.1 + image: ${LOKI_IMAGE} volumes: - loki-data:/tmp/loki environment: @@ -120,7 +120,7 @@ services: - prometheus-address=loki:3100 promtail: - image: grafana/promtail:2.6.1 + image: ${PROMTAIL_IMAGE} volumes: - /var/lib/docker/containers:/host/containers - /var/log:/var/log:ro @@ -139,13 +139,7 @@ services: MINIO_ROOT_USER: ${MO_SECURITY_ADMIN_USER} MINIO_ROOT_PASSWORD: ${MO_SECURITY_ADMIN_PASSWORD} healthcheck: - test: - [ - "CMD", - "curl", - "-f", - "http://localhost:9000/minio/health/live" - ] + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 diff --git a/monitoring/package-metadata.json b/monitoring/package-metadata.json index fd3b14e6..8d081fcd 100644 --- a/monitoring/package-metadata.json +++ b/monitoring/package-metadata.json @@ -6,6 +6,17 @@ "version": "0.0.1", "dependencies": [], "environmentVariables": { + "GRAFANA_IMAGE": "grafana/grafana-oss:9.2.3", + "LOKI_IMAGE": "grafana/loki:2.6.1", + "PROMTAIL_IMAGE": "grafana/promtail:2.6.1", + "PROMETHEUS_BACKUP_IMAGE": "prom/prometheus:v2.38.0", + "MINIO_IMAGE": "quay.io/minio/minio:RELEASE.2022-10-24T18-35-07Z", + "PROMETHEUS_PLACEMENT": "node-1", + "PROMETHEUS_BACKUP_PLACEMENT": "node-1", + "MINIO_01_PLACEMENT": "node-1", + "MINIO_02_PLACEMENT": "node-1", + "MINIO_03_PLACEMENT": "node-2", + "MINIO_04_PLACEMENT": "node-3", "GF_SECURITY_ADMIN_USER": "admin", "GF_SECURITY_ADMIN_PASSWORD": "dev_password_only", "GF_SMTP_ENABLED": "false", From 7d09a73394145cddc8d458318ee77d51823fefe7 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Thu, 25 Apr 2024 08:12:54 +0200 Subject: [PATCH 24/46] Update Elasticsearch cluster placement --- .../docker-compose.cluster.yml | 6 +++--- analytics-datastore-elastic-search/package-metadata.json | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/analytics-datastore-elastic-search/docker-compose.cluster.yml b/analytics-datastore-elastic-search/docker-compose.cluster.yml index e6163a85..a35aa21b 100644 --- a/analytics-datastore-elastic-search/docker-compose.cluster.yml +++ b/analytics-datastore-elastic-search/docker-compose.cluster.yml @@ -16,7 +16,7 @@ services: memory: ${ES_MEMORY_RESERVE} placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${ES_01_PLACEMENT}" environment: node.name: es01 cluster.name: es-cluster @@ -66,7 +66,7 @@ services: memory: ${ES_MEMORY_RESERVE} placement: constraints: - - "node.labels.name==node-2" + - "node.labels.name==${ES_02_PLACEMENT}" environment: node.name: es02 cluster.name: es-cluster @@ -116,7 +116,7 @@ services: memory: ${ES_MEMORY_RESERVE} placement: constraints: - - "node.labels.name==node-3" + - "node.labels.name==${ES_03_PLACEMENT}" environment: node.name: es03 cluster.name: es-cluster diff --git a/analytics-datastore-elastic-search/package-metadata.json b/analytics-datastore-elastic-search/package-metadata.json index 48ac5da5..facad20b 100644 --- a/analytics-datastore-elastic-search/package-metadata.json +++ b/analytics-datastore-elastic-search/package-metadata.json @@ -18,6 +18,9 @@ "ES_SSL": "false", "ES_MEMORY_LIMIT": "3G", "ES_MEMORY_RESERVE": "500M", - "ES_IMAGE": "docker.elastic.co/elasticsearch/elasticsearch:7.13.0" + "ES_IMAGE": "docker.elastic.co/elasticsearch/elasticsearch:7.13.0", + "ES_01_PLACEMENT": "node-1", + "ES_02_PLACEMENT": "node-2", + "ES_03_PLACEMENT": "node-3" } } From 08c356c17f9decb4b466df9bb2cd9370c375a33c Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Thu, 25 Apr 2024 15:14:08 +0200 Subject: [PATCH 25/46] Update Docker Compose files for PostgreSQL and Pgpool --- .../docker-compose-pgpool.cluster.yml | 14 +++++++------- .../docker-compose-postgres.cluster.yml | 12 ++++++------ database-postgres/docker-compose-postgres.yml | 2 +- database-postgres/package-metadata.json | 8 ++++++++ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/database-postgres/docker-compose-pgpool.cluster.yml b/database-postgres/docker-compose-pgpool.cluster.yml index 0addf043..2a23b101 100644 --- a/database-postgres/docker-compose-pgpool.cluster.yml +++ b/database-postgres/docker-compose-pgpool.cluster.yml @@ -1,12 +1,12 @@ -version: '3.9' +version: "3.9" services: pgpool-1: - image: bitnami/pgpool:4.4.3 + image: ${PG_POOL_IMAGE} deploy: placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${PGPOOL_1_PLACEMENT}" replicas: 1 resources: limits: @@ -39,11 +39,11 @@ services: PGPOOL_USER_CONF_FILE: "/config/custom_pgpool.conf" pgpool-2: - image: bitnami/pgpool:4.4.3 + image: ${PG_POOL_IMAGE} deploy: placement: constraints: - - "node.labels.name==node-2" + - "node.labels.name==${PGPOOL_2_PLACEMENT}" replicas: 1 resources: limits: @@ -76,11 +76,11 @@ services: PGPOOL_USER_CONF_FILE: "/config/custom_pgpool.conf" pgpool-3: - image: bitnami/pgpool:4.4.3 + image: ${PG_POOL_IMAGE} deploy: placement: constraints: - - "node.labels.name==node-3" + - "node.labels.name==${PGPOOL_3_PLACEMENT}" replicas: 1 resources: limits: diff --git a/database-postgres/docker-compose-postgres.cluster.yml b/database-postgres/docker-compose-postgres.cluster.yml index 88fab559..b7660c98 100644 --- a/database-postgres/docker-compose-postgres.cluster.yml +++ b/database-postgres/docker-compose-postgres.cluster.yml @@ -1,4 +1,4 @@ -version: '3.9' +version: "3.9" services: postgres-1: @@ -7,7 +7,7 @@ services: deploy: placement: constraints: - - "node.labels.name==node-1" + - "node.labels.name==${POSTGRES_1_PLACEMENT}" postgres-2: image: bitnami/postgresql-repmgr:14 @@ -23,14 +23,14 @@ services: REPMGR_FAILOVER: ${POSTGRES_FAILOVER} REPMGR_DEGRADED_MONITORING_TIMEOUT: ${POSTGRES_DEGRADED_MONITORING_TIMEOUT} volumes: - - 'hapi-postgres-2-data:/bitnami/postgresql' + - "hapi-postgres-2-data:/bitnami/postgresql" configs: - target: /bitnami/postgresql/conf/conf.d/custom_postgresql.conf source: postgresql.conf deploy: placement: constraints: - - "node.labels.name==node-2" + - "node.labels.name==${POSTGRES_2_PLACEMENT}" replicas: 1 resources: limits: @@ -58,14 +58,14 @@ services: REPMGR_FAILOVER: ${POSTGRES_FAILOVER} REPMGR_DEGRADED_MONITORING_TIMEOUT: ${POSTGRES_DEGRADED_MONITORING_TIMEOUT} volumes: - - 'hapi-postgres-3-data:/bitnami/postgresql' + - "hapi-postgres-3-data:/bitnami/postgresql" configs: - target: /bitnami/postgresql/conf/conf.d/custom_postgresql.conf source: postgresql.conf deploy: placement: constraints: - - "node.labels.name==node-3" + - "node.labels.name==${POSTGRES_3_PLACEMENT}" replicas: 1 resources: limits: diff --git a/database-postgres/docker-compose-postgres.yml b/database-postgres/docker-compose-postgres.yml index 2a24c1ea..b5165127 100644 --- a/database-postgres/docker-compose-postgres.yml +++ b/database-postgres/docker-compose-postgres.yml @@ -2,7 +2,7 @@ version: "3.9" services: postgres-1: - image: bitnami/postgresql-repmgr:14 + image: ${POSTGRES_IMAGE} environment: POSTGRESQL_PASSWORD: ${POSTGRESQL_PASSWORD} REPMGR_NODE_NETWORK_NAME: postgres-1 diff --git a/database-postgres/package-metadata.json b/database-postgres/package-metadata.json index bc6c441b..c7240670 100644 --- a/database-postgres/package-metadata.json +++ b/database-postgres/package-metadata.json @@ -9,6 +9,14 @@ "REPMGR_PRIMARY_HOST": "postgres-1", "REPMGR_PARTNER_NODES": "postgres-1", "REPMGR_PASSWORD": "instant101", + "POSTGRES_IMAGE": "bitnami/postgresql-repmgr:14", + "POSTGRES_1_PLACEMENT": "node-1", + "POSTGRES_2_PLACEMENT": "node-2", + "POSTGRES_3_PLACEMENT": "node-3", + "PG_POOL_IMAGE": "bitnami/pgpool:4.4.3", + "PGPOOL_1_PLACEMENT": "node-1", + "PGPOOL_2_PLACEMENT": "node-2", + "PGPOOL_3_PLACEMENT": "node-3", "POSTGRES_REPLICA_SET": "postgres-1:5432", "POSTGRES_CPU_LIMIT": "0", "POSTGRES_CPU_RESERVE": "0.05", From b6963e1f3bf6b0e632306eb459777b887b82d130 Mon Sep 17 00:00:00 2001 From: Brett Onions Date: Tue, 21 May 2024 11:45:00 +0200 Subject: [PATCH 26/46] chore: update CLICKHOUSE_IMAGE to version 23.8.14.6 --- analytics-datastore-clickhouse/package-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analytics-datastore-clickhouse/package-metadata.json b/analytics-datastore-clickhouse/package-metadata.json index 4bc99cef..a7b0efb7 100644 --- a/analytics-datastore-clickhouse/package-metadata.json +++ b/analytics-datastore-clickhouse/package-metadata.json @@ -8,7 +8,7 @@ "environmentVariables": { "CLICKHOUSE_HOST": "analytics-datastore-clickhouse", "CLICKHOUSE_PORT": "8123", - "CLICKHOUSE_IMAGE": "clickhouse/clickhouse-server", + "CLICKHOUSE_IMAGE": "clickhouse/clickhouse-server:23.8.14.6", "ANALYTICS_DATASTORE_CLICKHOUSE_01_PLACEMENT": "node-1", "ANALYTICS_DATASTORE_CLICKHOUSE_02_PLACEMENT": "node-2", "ANALYTICS_DATASTORE_CLICKHOUSE_03_PLACEMENT": "node-3" From d624b1546638d571cf6557bf8d0313b81891ae2e Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Fri, 24 May 2024 16:22:13 +0200 Subject: [PATCH 27/46] Change the name of the postgres image variable This is so the value is not overidden --- dashboard-visualiser-superset/docker-compose.postgres.yml | 2 +- dashboard-visualiser-superset/package-metadata.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dashboard-visualiser-superset/docker-compose.postgres.yml b/dashboard-visualiser-superset/docker-compose.postgres.yml index 10c0a68a..912914cd 100644 --- a/dashboard-visualiser-superset/docker-compose.postgres.yml +++ b/dashboard-visualiser-superset/docker-compose.postgres.yml @@ -2,7 +2,7 @@ version: "3.9" services: postgres-metastore: - image: ${POSTGRES_IMAGE} + image: ${SS_POSTGRES_IMAGE} environment: POSTGRES_USER: ${SUPERSET_POSTGRESQL_USERNAME} POSTGRES_PASSWORD: ${SUPERSET_POSTGRESQL_PASSWORD} diff --git a/dashboard-visualiser-superset/package-metadata.json b/dashboard-visualiser-superset/package-metadata.json index 69867d91..0d63ff8b 100644 --- a/dashboard-visualiser-superset/package-metadata.json +++ b/dashboard-visualiser-superset/package-metadata.json @@ -7,7 +7,7 @@ "dependencies": ["analytics-datastore-clickhouse"], "environmentVariables": { "SUPERSET_IMAGE": "apache/superset:3.1.1", - "POSTGRES_IMAGE": "postgres:16.2", + "SS_POSTGRES_IMAGE": "postgres:16.2", "POSTGRES_METASTORE": "node-2", "SUPERSET_ENABLED_FEATURE_FLAGS": "DASHBOARD_RBAC", "SUPERSET_USERNAME": "admin", From 3f2538267305b3bf0317eb449dd8944637983108 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Mon, 27 May 2024 15:36:01 +0200 Subject: [PATCH 28/46] Disable the clickhouse test case (temporarily) To debug --- .github/workflows/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index d1f9a7d7..b2797f19 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -33,7 +33,7 @@ else echo "$folder_name was changed" if [[ $folder_name == *"clickhouse"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse + # DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse elif [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":elk elif [[ $folder_name == *"kafka"* ]] || [[ $folder_name == *"monitoring"* ]]; then From ec74acd22612811883bc6162201c945728f92e01 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Mon, 27 May 2024 15:57:09 +0200 Subject: [PATCH 29/46] Fix syntax error --- .github/workflows/run-tests.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index b2797f19..9af62903 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -32,9 +32,10 @@ else for folder_name in "${!changed_packages[@]}"; do echo "$folder_name was changed" - if [[ $folder_name == *"clickhouse"* ]]; then - # DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse - elif [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then + # if [[ $folder_name == *"clickhouse"* ]]; then + # # DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse + # el + if [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":elk elif [[ $folder_name == *"kafka"* ]] || [[ $folder_name == *"monitoring"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":kafka From ffbe6a987e96556b25b7d6aa7251a4b6481fd54d Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Mon, 27 May 2024 19:36:43 +0200 Subject: [PATCH 30/46] Run the recipe tests first --- .github/workflows/run-tests.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index 9af62903..c564d063 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -25,6 +25,9 @@ for package in "${CHANGED_FILES[@]}"; do fi done +# Run the basic funtional end to end tests for the CDR recipe +DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud HOST=$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":recipe + if [[ ${#changed_packages[@]} -eq 0 ]] || [[ "${!changed_packages[*]}" == *"utils"* ]] || [[ "${!changed_packages[*]}" == *"features/steps"* ]] || [[ "${!changed_packages[*]}" == *"infrastructure"* ]] ; then openhim_ran="true" DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":openhim @@ -32,9 +35,9 @@ else for folder_name in "${!changed_packages[@]}"; do echo "$folder_name was changed" - # if [[ $folder_name == *"clickhouse"* ]]; then - # # DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse - # el + if [[ $folder_name == *"clickhouse"* ]]; then + DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse + el if [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":elk elif [[ $folder_name == *"kafka"* ]] || [[ $folder_name == *"monitoring"* ]]; then @@ -63,6 +66,3 @@ else fi done fi - -# Run the basic funtional end to end tests for the CDR recipe -DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud HOST=$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":recipe From fc583cf8a050f849633c6344b56ffcbd8704fca7 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Mon, 27 May 2024 19:51:58 +0200 Subject: [PATCH 31/46] Fix typo --- .github/workflows/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index c564d063..1b4cfab8 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -37,7 +37,7 @@ else if [[ $folder_name == *"clickhouse"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse - el + elif if [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":elk elif [[ $folder_name == *"kafka"* ]] || [[ $folder_name == *"monitoring"* ]]; then From 0474393fddee9081958da4d5b1b20f6b1c0149f6 Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Mon, 27 May 2024 22:17:59 +0200 Subject: [PATCH 32/46] Fix if statement --- .github/workflows/run-tests.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index 1b4cfab8..754f830d 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -37,8 +37,7 @@ else if [[ $folder_name == *"clickhouse"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse - elif - if [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then + elif [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":elk elif [[ $folder_name == *"kafka"* ]] || [[ $folder_name == *"monitoring"* ]]; then DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":kafka From 65797ea8aa0cf5f4b007ab89457c592163f65c2c Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Tue, 28 May 2024 09:12:34 +0200 Subject: [PATCH 33/46] Fix typo in variable name --- .github/workflows/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index 754f830d..870c44c8 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -29,7 +29,7 @@ done DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud HOST=$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":recipe if [[ ${#changed_packages[@]} -eq 0 ]] || [[ "${!changed_packages[*]}" == *"utils"* ]] || [[ "${!changed_packages[*]}" == *"features/steps"* ]] || [[ "${!changed_packages[*]}" == *"infrastructure"* ]] ; then - openhim_ran="true" + openhimRan="true" DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":openhim else for folder_name in "${!changed_packages[@]}"; do From 5e7b67a97b2d963f726588f42f85e9f65d72ebba Mon Sep 17 00:00:00 2001 From: bradsawadye Date: Tue, 28 May 2024 12:30:28 +0200 Subject: [PATCH 34/46] Refactor --- .github/workflows/run-tests.sh | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.github/workflows/run-tests.sh b/.github/workflows/run-tests.sh index 870c44c8..71d1447e 100755 --- a/.github/workflows/run-tests.sh +++ b/.github/workflows/run-tests.sh @@ -25,43 +25,47 @@ for package in "${CHANGED_FILES[@]}"; do fi done +function run_test() { + DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud HOST=$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":$1 +} + # Run the basic funtional end to end tests for the CDR recipe -DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud HOST=$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":recipe +run_test "recipe" if [[ ${#changed_packages[@]} -eq 0 ]] || [[ "${!changed_packages[*]}" == *"utils"* ]] || [[ "${!changed_packages[*]}" == *"features/steps"* ]] || [[ "${!changed_packages[*]}" == *"infrastructure"* ]] ; then openhimRan="true" - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":openhim + run_test "openhim" else for folder_name in "${!changed_packages[@]}"; do echo "$folder_name was changed" if [[ $folder_name == *"clickhouse"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":clickhouse + run_test "clickhouse" elif [[ $folder_name == *"elastic"* ]] || [[ $folder_name == *"kibana"* ]] || [[ $folder_name == *"logstash"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":elk + run_test "elk" elif [[ $folder_name == *"kafka"* ]] || [[ $folder_name == *"monitoring"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":kafka + run_test "kafka" elif [[ $folder_name == *"openhim"* ]] && [[ $openhimRan == "false" ]]; then openhimRan="true" - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":openhim + run_test "openhim" elif [[ $folder_name == *"reverse-proxy"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":nginx + run_test "nginx" elif [[ $folder_name == *"hapi"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":hapi + run_test "hapi" elif [[ $folder_name == *"santempi"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":sante + run_test "sante" elif [[ $folder_name == *"monitoring"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":monitoring + run_test "monitoring" elif [[ $folder_name == *"keycloak"* ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":keycloak + run_test "keycloak" elif [[ $folder_name == *"superset"* ]] && [[ $NODE_MODE == "single" ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":superset + run_test "superset" elif [[ $folder_name == *"jsreport"* ]] && [[ $NODE_MODE == "single" ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":jsreport + run_test "jsreport" elif [[ $folder_name == *"mpi-mediator"* ]] && [[ $NODE_MODE == "single" ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":mpi-mediator + run_test "mpi-mediator" elif [[ $folder_name == *"jempi"* ]] && [[ $NODE_MODE == "single" ]]; then - DOCKER_HOST=ssh://ubuntu@$GITHUB_RUN_ID.jembi.cloud yarn test:"$NODE_MODE":jempi + run_test "jempi" fi done fi From f449d8e8eaff3be876efcf22c91b9849378004b5 Mon Sep 17 00:00:00 2001 From: Drizzentic Date: Wed, 29 May 2024 11:06:22 +0300 Subject: [PATCH 35/46] Update .vscode/settings.json --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 346e0173..308cd2aa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "files.insertFinalNewline": true, "editor.formatOnSave": true, "[json]": { - "editor.defaultFormatter": "vscode.json-language-features" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "editor.codeActionsOnSave": { "source.fixAll": "explicit" From 9daa76bee795846afeb642c10d1b842888f4291e Mon Sep 17 00:00:00 2001 From: drono Date: Thu, 30 May 2024 11:05:42 +0300 Subject: [PATCH 36/46] Fix failure in client scopes creation on keycloak --- ..._keyclock.yml => docker-compose-smart_keycloak.yml} | 10 +++++++--- fhir-info-gateway/docker-compose.yml | 2 +- fhir-info-gateway/package-metadata.json | 4 ++-- fhir-info-gateway/swarm.sh | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) rename fhir-info-gateway/{docker-compose-smart_keyclock.yml => docker-compose-smart_keycloak.yml} (53%) diff --git a/fhir-info-gateway/docker-compose-smart_keyclock.yml b/fhir-info-gateway/docker-compose-smart_keycloak.yml similarity index 53% rename from fhir-info-gateway/docker-compose-smart_keyclock.yml rename to fhir-info-gateway/docker-compose-smart_keycloak.yml index 04cd3548..988b66d2 100644 --- a/fhir-info-gateway/docker-compose-smart_keyclock.yml +++ b/fhir-info-gateway/docker-compose-smart_keycloak.yml @@ -4,12 +4,16 @@ services: smart-config: image: jembi/keycloak-config networks: - - fhir-info-gateway_default + keycloak: environment: KEYCLOAK_BASE_URL: ${KC_API_URL} - KEYCLOAK_USER: ${KC_ADMIN_USER} + KEYCLOAK_USER: ${KC_ADMIN_USERNAME} KEYCLOAK_PASSWORD: ${KC_ADMIN_PASSWORD} KEYCLOAK_REALM: ${KC_REALM_NAME} + restart: on-failure + command: ["-configFile", "config/backend-services-config.json"] networks: - fhir-info-gateway_default: + keycloak: + name: keycloak_public + external: true diff --git a/fhir-info-gateway/docker-compose.yml b/fhir-info-gateway/docker-compose.yml index 195ddcd9..27658a50 100644 --- a/fhir-info-gateway/docker-compose.yml +++ b/fhir-info-gateway/docker-compose.yml @@ -9,7 +9,7 @@ services: environment: TOKEN_ISSUER: ${KC_API_URL}/realms/${KC_REALM_NAME} ACCESS_CHECKER: ${ACCESS_CHECKER} - PROXY_TO: ${MPI_PROXY_URL} + PROXY_TO: ${GATEWAY_MPI_PROXY_URL} BACKEND_TYPE: ${BACKEND_TYPE} RUN_MODE: ${RUN_MODE} deploy: diff --git a/fhir-info-gateway/package-metadata.json b/fhir-info-gateway/package-metadata.json index b2fcda0b..4eed15d0 100644 --- a/fhir-info-gateway/package-metadata.json +++ b/fhir-info-gateway/package-metadata.json @@ -6,7 +6,7 @@ "version": "0.0.1", "dependencies": ["mpi-mediator"], "environmentVariables": { - "MPI_PROXY_URL": "http://mpi-mediator:3000/fhir", + "GATEWAY_MPI_PROXY_URL": "http://mpi-mediator:3000/fhir", "ACCESS_CHECKER": "patient", "RUN_MODE": "DEV", "FHIR_INFO_GATEWAY_IMAGE": "jembi/fhir-info-gateway:v0.0.2", @@ -14,7 +14,7 @@ "KC_API_URL": "http://identity-access-manager-keycloak:9088", "KC_REALM_NAME": "platform-realm", "KC_ADMIN_PASSWORD": "dev_password_only", - "KC_ADMIN_USEERNAME": "admin", + "KC_ADMIN_USERNAME": "admin", "FHIR_INFO_GATEWAY_INSTANCES": "1", "FHIR_INFO_GATEWAY_MAX_REPLICAS_PER_NODE": "1", "FHIR_INFO_GATEWAY_CPU_LIMIT": "0", diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh index 2f89da06..4a0af934 100644 --- a/fhir-info-gateway/swarm.sh +++ b/fhir-info-gateway/swarm.sh @@ -46,7 +46,7 @@ function initialize_package() { fi ( - docker::deploy_service $STACK "${COMPOSE_FILE_PATH}" "docker-compose.yml" "$package_dev_compose_filename" + docker::deploy_service $STACK "${COMPOSE_FILE_PATH}" "docker-compose.yml" "$package_dev_compose_filename" "docker-compose-smart_keycloak.yml" ) || { log error "Failed to deploy package" exit 1 From 0e3aacc164f193f8ac7a9b794590882724a83ec9 Mon Sep 17 00:00:00 2001 From: drono Date: Fri, 24 May 2024 17:01:33 +0300 Subject: [PATCH 37/46] parent cbd8b688d9f1973fbeb17415fe1ae55ad3102461 author drono 1716559293 +0300 committer drono 1717058217 +0300 Add SMART on fhir realms creator Fix failing tests Add correct assertion THe mpi mediator has been modified and the returned response has a different structure Ensure that the entry property in the bundle is always an array Add jempi network for the services to communicate This also adds bootstrapper node placement. Has to be on the leader where the commands are run as we run a command in the bootstrapper docker container Fix kafka consumer failing test Bump instant version to latest fix version and disable cert verification in console. Update version for mpi mediator Adds reprocess config files Cleanup Reprocess package Change docker images to be configurable env variables Format json files Format json files adding placement and image version for pg in metadata file Update Kibana image and add KIBANA_IMAGE environment variable add image and max replicas to metadata file Update docker-compose files and package metadata Update Elasticsearch cluster placement Update Docker Compose files for PostgreSQL and Pgpool chore: update CLICKHOUSE_IMAGE to version 23.8.14.6 Change the name of the postgres image variable This is so the value is not overidden Disable the clickhouse test case (temporarily) To debug Fix syntax error Run the recipe tests first Fix typo Fix if statement Fix typo in variable name Refactor Update .vscode/settings.json --- .../package-metadata.json | 4 +++- .../docker-compose-smart_keyclock.yml | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 fhir-info-gateway/docker-compose-smart_keyclock.yml diff --git a/dashboard-visualiser-superset/package-metadata.json b/dashboard-visualiser-superset/package-metadata.json index 0d63ff8b..f0bfc702 100644 --- a/dashboard-visualiser-superset/package-metadata.json +++ b/dashboard-visualiser-superset/package-metadata.json @@ -4,7 +4,9 @@ "description": "A dashboard to interpret the data from the Clickhouse data store", "type": "infrastructure", "version": "0.0.1", - "dependencies": ["analytics-datastore-clickhouse"], + "dependencies": [ + "analytics-datastore-clickhouse" + ], "environmentVariables": { "SUPERSET_IMAGE": "apache/superset:3.1.1", "SS_POSTGRES_IMAGE": "postgres:16.2", diff --git a/fhir-info-gateway/docker-compose-smart_keyclock.yml b/fhir-info-gateway/docker-compose-smart_keyclock.yml new file mode 100644 index 00000000..04cd3548 --- /dev/null +++ b/fhir-info-gateway/docker-compose-smart_keyclock.yml @@ -0,0 +1,15 @@ +version: "3.9" + +services: + smart-config: + image: jembi/keycloak-config + networks: + - fhir-info-gateway_default + environment: + KEYCLOAK_BASE_URL: ${KC_API_URL} + KEYCLOAK_USER: ${KC_ADMIN_USER} + KEYCLOAK_PASSWORD: ${KC_ADMIN_PASSWORD} + KEYCLOAK_REALM: ${KC_REALM_NAME} +networks: + fhir-info-gateway_default: + From 1b68f57ff1f616be2b5e784f09f9955bfd5174b9 Mon Sep 17 00:00:00 2001 From: drono Date: Tue, 9 Jul 2024 17:59:27 +0300 Subject: [PATCH 38/46] PR feedback --- config.yaml | 4 ++++ .../docker-compose-smart_keyclock.yml | 15 --------------- fhir-info-gateway/swarm.sh | 5 ++++- 3 files changed, 8 insertions(+), 16 deletions(-) delete mode 100644 fhir-info-gateway/docker-compose-smart_keyclock.yml diff --git a/config.yaml b/config.yaml index 38c02aca..aff5940f 100644 --- a/config.yaml +++ b/config.yaml @@ -47,6 +47,8 @@ profiles: - kafka-unbundler-consumer - fhir-ig-importer - reprocess-mediator + - fhir-ig-importer + - fhir-info-gateway envFiles: - cdr-dw.env @@ -63,6 +65,8 @@ profiles: - client-registry-jempi - identity-access-manager-keycloak - openhim-mapping-mediator + - fhir-ig-importer + - fhir-info-gateway envFiles: - cdr.env diff --git a/fhir-info-gateway/docker-compose-smart_keyclock.yml b/fhir-info-gateway/docker-compose-smart_keyclock.yml deleted file mode 100644 index 04cd3548..00000000 --- a/fhir-info-gateway/docker-compose-smart_keyclock.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: "3.9" - -services: - smart-config: - image: jembi/keycloak-config - networks: - - fhir-info-gateway_default - environment: - KEYCLOAK_BASE_URL: ${KC_API_URL} - KEYCLOAK_USER: ${KC_ADMIN_USER} - KEYCLOAK_PASSWORD: ${KC_ADMIN_PASSWORD} - KEYCLOAK_REALM: ${KC_REALM_NAME} -networks: - fhir-info-gateway_default: - diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh index 4a0af934..7bf41846 100644 --- a/fhir-info-gateway/swarm.sh +++ b/fhir-info-gateway/swarm.sh @@ -12,7 +12,10 @@ function init_vars() { MODE=$2 COMPOSE_FILE_PATH=$( - cd "$(dirname "${BASH_SOURCE[0]}")" || exit + cd "$(dirname "${BASH_SOURCE[0]}")" || { + echo "Failed to change directory" + exit 1 + } pwd -P ) From ac4d67f744ee3b9fcfd48bdabb2cc33ee9bfc77d Mon Sep 17 00:00:00 2001 From: Drizzentic Date: Wed, 10 Jul 2024 09:09:31 +0300 Subject: [PATCH 39/46] Update fhir-info-gateway/swarm.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- fhir-info-gateway/swarm.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh index 7bf41846..6adc9e15 100644 --- a/fhir-info-gateway/swarm.sh +++ b/fhir-info-gateway/swarm.sh @@ -4,7 +4,6 @@ declare ACTION="" declare MODE="" declare COMPOSE_FILE_PATH="" declare UTILS_PATH="" -declare SERVICE_NAMES=() declare STACK="fhir-info-gateway" function init_vars() { From 892c5c6fabc9291fb59d29d77ac83e156c964e7e Mon Sep 17 00:00:00 2001 From: Drizzentic Date: Wed, 10 Jul 2024 09:12:39 +0300 Subject: [PATCH 40/46] Update fhir-info-gateway/swarm.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- fhir-info-gateway/swarm.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh index 6adc9e15..8961ac69 100644 --- a/fhir-info-gateway/swarm.sh +++ b/fhir-info-gateway/swarm.sh @@ -20,9 +20,6 @@ function init_vars() { UTILS_PATH="${COMPOSE_FILE_PATH}/../utils" - SERVICE_NAMES=( - "fhir-info-gateway" - ) readonly ACTION readonly MODE From 5f2a64c04a7d6d5099834851134583b0c831d685 Mon Sep 17 00:00:00 2001 From: Drizzentic Date: Wed, 10 Jul 2024 09:12:53 +0300 Subject: [PATCH 41/46] Update fhir-info-gateway/swarm.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- fhir-info-gateway/swarm.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh index 8961ac69..156fa535 100644 --- a/fhir-info-gateway/swarm.sh +++ b/fhir-info-gateway/swarm.sh @@ -25,7 +25,6 @@ function init_vars() { readonly MODE readonly COMPOSE_FILE_PATH readonly UTILS_PATH - readonly SERVICE_NAMES readonly STACK } From e4e6edffe85e0d43754358af53c5013f96fec8d5 Mon Sep 17 00:00:00 2001 From: Drizzentic Date: Fri, 26 Jul 2024 10:10:02 +0300 Subject: [PATCH 42/46] Update config.yaml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/config.yaml b/config.yaml index 905a1219..c44ed3f8 100644 --- a/config.yaml +++ b/config.yaml @@ -48,7 +48,6 @@ profiles: - kafka-unbundler-consumer - fhir-ig-importer - reprocess-mediator - - fhir-ig-importer - fhir-info-gateway envFiles: - cdr-dw.env From 2b94455ec4271de01d9ef1da2848226a39dece58 Mon Sep 17 00:00:00 2001 From: drono Date: Wed, 14 Aug 2024 11:10:51 +0300 Subject: [PATCH 43/46] PR feedback --- .../docker-compose-smart_keycloak.yml | 10 +- fhir-info-gateway/keycloak-config.json | 477 ++++++++++++++++++ fhir-info-gateway/package-metadata.json | 2 +- 3 files changed, 482 insertions(+), 7 deletions(-) diff --git a/fhir-info-gateway/docker-compose-smart_keycloak.yml b/fhir-info-gateway/docker-compose-smart_keycloak.yml index 988b66d2..7cf41431 100644 --- a/fhir-info-gateway/docker-compose-smart_keycloak.yml +++ b/fhir-info-gateway/docker-compose-smart_keycloak.yml @@ -2,7 +2,7 @@ version: "3.9" services: smart-config: - image: jembi/keycloak-config + image: jembi/keycloak-config:v0.0.1 networks: keycloak: environment: @@ -10,10 +10,8 @@ services: KEYCLOAK_USER: ${KC_ADMIN_USERNAME} KEYCLOAK_PASSWORD: ${KC_ADMIN_PASSWORD} KEYCLOAK_REALM: ${KC_REALM_NAME} - restart: on-failure - command: ["-configFile", "config/backend-services-config.json"] + command: [ "-configFile", "config/backend-services-config.json" ] networks: keycloak: - name: keycloak_public - external: true - + name: keycloak_public + external: true diff --git a/fhir-info-gateway/keycloak-config.json b/fhir-info-gateway/keycloak-config.json index 36e154bb..3306a916 100644 --- a/fhir-info-gateway/keycloak-config.json +++ b/fhir-info-gateway/keycloak-config.json @@ -80,6 +80,483 @@ "consent.screen.text": "Retain access while you are online" } }, + "system/*.rs": { + "protocol": "openid-connect", + "description": "Read access and search to all data", + "attributes": { + "consent.screen.text": "Read access to all data" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Observation.rs": { + "protocol": "openid-connect", + "description": "Read access to Observation", + "attributes": { + "consent.screen.text": "Read access to Observation" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Encounter.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Encounter", + "attributes": { + "consent.screen.text": "Create, update and delete access to Encounter" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Encounter.rs": { + "protocol": "openid-connect", + "description": "Read access to Encounter", + "attributes": { + "consent.screen.text": "Read access to Encounter" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Patient.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Patient", + "attributes": { + "consent.screen.text": "Create, update and delete access to Patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Patient.rs": { + "protocol": "openid-connect", + "description": "Read access to Patient", + "attributes": { + "consent.screen.text": "Read access to Patient" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Practitioner.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Practitioner", + "attributes": { + "consent.screen.text": "Create, update and delete access to Practitioner" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Practitioner.rs": { + "protocol": "openid-connect", + "description": "Read access to Practitioner", + "attributes": { + "consent.screen.text": "Read access to Practitioner" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/PractitionerRole.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to PractitionerRole", + "attributes": { + "consent.screen.text": "Create, update and delete access to PractitionerRole" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/PractitionerRole.rs": { + "protocol": "openid-connect", + "description": "Read access to PractitionerRole", + "attributes": { + "consent.screen.text": "Read access to PractitionerRole" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Organization.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Organization", + "attributes": { + "consent.screen.text": "Create, update and delete access to Organization" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Organization.rs": { + "protocol": "openid-connect", + "description": "Read access to Organization", + "attributes": { + "consent.screen.text": "Read access to Organization" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Device.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Device", + "attributes": { + "consent.screen.text": "Create, update and delete access to Device" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Device.rs": { + "protocol": "openid-connect", + "description": "Read access to Device", + "attributes": { + "consent.screen.text": "Read access to Device" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/AllergyIntolerance.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to AllergyIntolerance", + "attributes": { + "consent.screen.text": "Create, update and delete access to AllergyIntolerance" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/AllergyIntolerance.rs": { + "protocol": "openid-connect", + "description": "Read access to AllergyIntolerance", + "attributes": { + "consent.screen.text": "Read access to AllergyIntolerance" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/CarePlan.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to CarePlan", + "attributes": { + "consent.screen.text": "Create, update and delete access to CarePlan" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/CarePlan.rs": { + "protocol": "openid-connect", + "description": "Read access to CarePlan", + "attributes": { + "consent.screen.text": "Read access to CarePlan" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/CareTeam.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to CareTeam", + "attributes": { + "consent.screen.text": "Create, update and delete access to CareTeam" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/CareTeam.rs": { + "protocol": "openid-connect", + "description": "Read access to CareTeam", + "attributes": { + "consent.screen.text": "Read access to CareTeam" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Condition.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Condition", + "attributes": { + "consent.screen.text": "Create, update and delete access to Condition" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Condition.rs": { + "protocol": "openid-connect", + "description": "Read access to Condition", + "attributes": { + "consent.screen.text": "Read access to Condition" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/DiagnosticReport.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to DiagnosticReport", + "attributes": { + "consent.screen.text": "Create, update and delete access to DiagnosticReport" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/DiagnosticReport.rs": { + "protocol": "openid-connect", + "description": "Read access to DiagnosticReport", + "attributes": { + "consent.screen.text": "Read access to DiagnosticReport" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/DocumentReference.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to DocumentReference", + "attributes": { + "consent.screen.text": "Create, update and delete access to DocumentReference" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/DocumentReference.rs": { + "protocol": "openid-connect", + "description": "Read access to DocumentReference", + "attributes": { + "consent.screen.text": "Read access to DocumentReference" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Bundle.cud": { + "protocol": "openid-connect", + "description": "Create, update and delete access to Bundle", + "attributes": { + "consent.screen.text": "Create, update and delete access to Bundle" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "system/Bundle.rs": { + "protocol": "openid-connect", + "description": "Read access to Bundle", + "attributes": { + "consent.screen.text": "Read access to Bundle" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "included.custom.audience": "${FHIR_BASE_URL}", + "access.token.claim": "true" + } + } + } + }, + "patient/*.read": { "protocol": "openid-connect", "description": "Read access to all data", diff --git a/fhir-info-gateway/package-metadata.json b/fhir-info-gateway/package-metadata.json index 4eed15d0..4e11abc3 100644 --- a/fhir-info-gateway/package-metadata.json +++ b/fhir-info-gateway/package-metadata.json @@ -9,7 +9,7 @@ "GATEWAY_MPI_PROXY_URL": "http://mpi-mediator:3000/fhir", "ACCESS_CHECKER": "patient", "RUN_MODE": "DEV", - "FHIR_INFO_GATEWAY_IMAGE": "jembi/fhir-info-gateway:v0.0.2", + "FHIR_INFO_GATEWAY_IMAGE": "jembi/fhir-info-gateway:scope-checker", "BACKEND_TYPE": "HAPI", "KC_API_URL": "http://identity-access-manager-keycloak:9088", "KC_REALM_NAME": "platform-realm", From bb0b7ef5dc7023397ae659c74d42be67d2bd7dec Mon Sep 17 00:00:00 2001 From: drono Date: Tue, 17 Sep 2024 13:12:37 +0300 Subject: [PATCH 44/46] Add the update script to create default clients,roles and mappings --- .../importer/keycloak-config.json | 231 +++++++++ .../importer/update-keycloak-config.js | 476 ++++++++++++++++++ 2 files changed, 707 insertions(+) create mode 100644 fhir-info-gateway/importer/keycloak-config.json create mode 100644 fhir-info-gateway/importer/update-keycloak-config.js diff --git a/fhir-info-gateway/importer/keycloak-config.json b/fhir-info-gateway/importer/keycloak-config.json new file mode 100644 index 00000000..95ea4dce --- /dev/null +++ b/fhir-info-gateway/importer/keycloak-config.json @@ -0,0 +1,231 @@ +{ + "clientScopes": { + "system/*.rs": { + "protocol": "openid-connect", + "description": "Read access to all resources", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "admin", + "name": "administrator", + "description": "Has full access to all resources" + } + }, + + "system/Patient.cruds": { + "protocol": "openid-connect", + "description": "Read access to all data", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "admin", + "name": "administrator", + "description": "Has full access to all resources" + } + }, + "system/Patient.cud": { + "protocol": "openid-connect", + "description": "Read and write access to all Patient", + "attributes": { + "include.in.token.scope": "false" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "manager", + "name": "manager", + "description": "Has limited access to all resources" + } + }, + "system/Patient.rs": { + "protocol": "openid-connect", + "description": "Read access to all Patient", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "user", + "name": "user", + "description": "Has read access to all resources" + } + }, + "system/Encounter.rs": { + "protocol": "openid-connect", + "description": "Read access to all Encounter data", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "user", + "name": "user", + "description": "Has read access to all resources" + } + }, + "system/Observation.rs": { + "protocol": "openid-connect", + "description": "Read access to all Observation data", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "user", + "name": "user", + "description": "Has read access to all resources" + } + }, + "system/Encounter.cruds": { + "protocol": "openid-connect", + "description": "Read, write and search access to all Encounter data", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "admin", + "name": "administrator", + "description": "Has full access to all resources" + } + }, + "system/Encounter.cud": { + "protocol": "openid-connect", + "description": "Read and write access to all Encounter data", + "attributes": { + "include.in.token.scope": "false" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "manager", + "name": "manager", + "description": "Has limited access to all resources" + } + }, + "system/Observation.cruds": { + "protocol": "openid-connect", + "description": "Read access to all Observation data", + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "admin", + "name": "administrator", + "description": "Has full access to all resources" + } + }, + "system/Observation.cud": { + "protocol": "openid-connect", + "description": "Read and write access to all Observation data", + "attributes": { + "include.in.token.scope": "false" + }, + "mappers": { + "Audience Mapper": { + "protocol": "openid-connect", + "protocolmapper": "oidc-audience-mapper", + "config": { + "access.token.claim": "true" + } + } + }, + "role": { + "id": "manager", + "name": "manager", + "description": "Has limited access to all resources" + } + } + }, + + "client": { + "protocol": "openid-connect", + "clientId": "emr", + "name": "EMR user", + "description": "", + "publicClient": false, + "authorizationServicesEnabled": false, + "serviceAccountsEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "standardFlowEnabled": true, + "frontchannelLogout": true, + "alwaysDisplayInConsole": false, + "attributes": { + "oauth2.device.authorization.grant.enabled": false, + "oidc.ciba.grant.enabled": false + } + }, + "groups": { + "fhirUser": {} + }, + "defaultGroup": "fhir-user-group", + "defaultUser": { + "username": "fhirUser", + "firstName": "FHIR", + "lastName": "User", + "email": "fhir@jembi.org", + "emailVerified": false, + "enabled": true, + "groups": ["fhirUser"] + }, + "resetPassword": { + "temporary": false, + "type": "password", + "value": "dev_password_only" + } +} diff --git a/fhir-info-gateway/importer/update-keycloak-config.js b/fhir-info-gateway/importer/update-keycloak-config.js new file mode 100644 index 00000000..709acedc --- /dev/null +++ b/fhir-info-gateway/importer/update-keycloak-config.js @@ -0,0 +1,476 @@ +const axios = require("axios"); + +// Load the JSON payload +const payload = require("./keycloak-config.json"); + +const serverUrl = + process.env.KEYCLOAK_SERVER_URL || "http://192.168.15.250:9088"; +const adminUser = process.env.KEYCLOAK_ADMIN_USER || "admin"; +const adminPassword = + process.env.KEYCLOAK_ADMIN_PASSWORD || "dev_password_only"; +const adminClientId = process.env.KEYCLOAK_ADMIN_CLIENT_ID || "admin-cli"; +const realm = process.env.KEYCLOAK_REALM || "platform-realm"; + +// Function definitions +async function getAdminToken( + keycloakBaseUrl, + realm, + clientId, + adminUser, + adminPassword +) { + try { + const tokenResponse = await axios.post( + `${keycloakBaseUrl}/realms/master/protocol/openid-connect/token`, + new URLSearchParams({ + grant_type: "password", + client_id: clientId, + username: adminUser, + password: adminPassword, + }), + { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + } + ); + + return tokenResponse.data.access_token; + } catch (error) { + console.error( + "Error fetching admin token:", + error.response ? error.response.data : error.message + ); + throw error; + } +} + +async function getRoleByName(roleName, keycloakBaseUrl, realm, adminToken) { + try { + const response = await axios.get( + `${keycloakBaseUrl}/admin/realms/${realm}/roles`, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + + const role = response.data.find((r) => r.name === roleName); + return role ? role.id : null; + } catch (error) { + console.error( + "Error fetching role by name:", + error.response ? error.response.data : error.message + ); + throw error; + } +} + +async function getOrCreateClient(client, keycloakBaseUrl, realm, adminToken) { + try { + const clientResponse = await axios.get( + `${keycloakBaseUrl}/admin/realms/${realm}/clients?clientId=${client.clientId}`, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + + if (clientResponse.data.length > 0) { + // Client exists, update it + const clientId = clientResponse.data[0].id; + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/clients/${clientId}`, + client, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Updated client: ${client.clientId}`); + } else { + // Client does not exist, create a new one + const newClientResponse = await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/clients`, + client, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Created client: ${client.clientId}`); + return newClientResponse.data; + } + } catch (error) { + console.error( + "Error creating or updating client:", + error.response ? error.response.data : error.message + ); + //throw error; + } +} + +async function processKeycloakPayload( + payload, + keycloakBaseUrl, + realm, + adminToken +) { + const { clientScopes, defaultUser, client, defaultGroup, resetPassword } = + payload; + + if (!clientScopes) { + throw new Error("clientScopes is not defined in the payload"); + } + + await Promise.all( + Object.entries(clientScopes).map(async ([scopeName, scope]) => { + if (!scope) { + console.error(`Scope is undefined for scopeName: ${scopeName}`); + return; + } + + console.log(`Processing scope: ${scopeName}`); + + const { role } = scope; + + const { name, description } = role; + + let roleId; + + try { + // Create or update client + + // Step 1: Create or update a role for each client scope + roleId = await getRoleByName(name, keycloakBaseUrl, realm, adminToken); + if (roleId) { + // Role exists, update it + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/roles-by-id/${roleId}`, + role, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Updated role: ${name}`); + } else { + // Role does not exist, create a new one + const roleResponse = await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/roles`, + role, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + roleId = roleResponse.data.id; + console.log(`Created role: ${name}`); + } + + // Step 2: Create or update the client scope + const clientScopeResponse = await axios.get( + `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes`, + { + headers: { + Authorization: `Bearer ${adminToken}`, + }, + } + ); + + let clientScope = clientScopeResponse.data.find( + (cs) => cs.name === scopeName + ); + + if (!clientScope) { + // Client scope does not exist, create a new one + const newClientScopeResponse = await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes`, + scope, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + clientScope = newClientScopeResponse.data; + } + + if (!clientScope || !clientScope.id) { + throw new Error(`Client scope ${scopeName} does not have a valid ID`); + } else { + // Map scopes to the client + const clientResponse = await getOrCreateClient( + client, + keycloakBaseUrl, + realm, + adminToken + ); + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/clients/${clientResponse[0].id}/default-client-scopes/${clientScope.id}`, + {}, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + } + + // Step 3: Map the created role to the client scope + await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes/${clientScope.id}/scope-mappings/realm`, + [{ id: roleId, name }], + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Mapped role ${name} to client scope ${scopeName}`); + } catch (error) { + console.error("Error processing scope:", error); + } + }) + ); + + // Step 4: Create or update the service-account user + try { + const groupResponse = await axios.get( + `${keycloakBaseUrl}/admin/realms/${realm}/groups?search=${defaultGroup}`, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + + let groupId = ""; + if (groupResponse.data.length > 0) { + // Group exists, update it + groupId = groupResponse.data[0].id; + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/groups/${groupId}`, + { + name: defaultGroup, + }, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + } else { + // Group does not exist, create a new one + const createdGroupResponse = await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/groups`, + { + name: defaultGroup, + }, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + groupId = createdGroupResponse.data.id; + console.log(`Created group: ${defaultGroup}`); + } + + const usersResponse = await axios.get( + `${keycloakBaseUrl}/admin/realms/${realm}/users`, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + + const users = usersResponse.data; + const user = users.find( + (u) => u.username === defaultUser.username.toLowerCase() + ); + + if (user) { + // User exists, update it + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/users/${user.id}`, + defaultUser, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Updated user: ${defaultUser.username}`); + } else { + // User does not exist, create a new one + const userResponse = await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/users`, + defaultUser, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Created user: ${defaultUser.username}`); + } + + // Reset the password + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/users/${user.id}/reset-password`, + resetPassword, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Reset password for user ${defaultUser.username}`); + + // Add service-account user to the group + await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/users/${user.id}/groups/${groupId}`, + {}, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Added user ${defaultUser.username} to group ${defaultGroup}`); + + const uniqueRolesArray = await getUniqueRolesArray(payload); + for (const role of uniqueRolesArray) { + const roleId = await getRoleByName( + role.name, + keycloakBaseUrl, + realm, + adminToken + ); + + await axios.post( + `${keycloakBaseUrl}/admin/realms/${realm}/groups/${groupId}/role-mappings/realm`, + [ + { + id: roleId, + clientRole: false, + composite: false, + containerId: realm, + name: role.name, + description: role.description, + }, + ], + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Added role mapping to group: ${role.name}`); + } + } catch (error) { + console.error( + "Error creating or updating user:", + error.response ? error.response.data : error.message + ); + throw error; + } +} + +async function getUniqueRolesArray(payload) { + const rolesSet = new Set(); + const { clientScopes } = payload; + + for (const key in clientScopes) { + if (clientScopes[key].role) { + rolesSet.add(JSON.stringify(clientScopes[key].role)); + } + } + + // Convert Set to Array and parse back to objects + const uniqueRolesArray = Array.from(rolesSet).map((role) => JSON.parse(role)); + return uniqueRolesArray; +} + +// Call the function and handle the result +async function main() { + try { + const adminToken = await getAdminToken( + serverUrl, + realm, + adminClientId, + adminUser, + adminPassword + ); + + const client = payload.client; + await getOrCreateClient(client, serverUrl, realm, adminToken); + + const uniqueRolesArray = await getUniqueRolesArray(payload); + for (const role of uniqueRolesArray) { + const { name } = role; + const roleId = await getRoleByName(name, serverUrl, realm, adminToken); + + if (roleId) { + // Role exists, update it + await axios.put( + `${serverUrl}/admin/realms/${realm}/roles-by-id/${roleId}`, + role, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Updated role: ${name}`); + } else { + // Role does not exist, create a new one + const roleResponse = await axios.post( + `${serverUrl}/admin/realms/${realm}/roles`, + role, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Created role: ${name}`); + } + } + + await processKeycloakPayload(payload, serverUrl, realm, adminToken); + console.log("Keycloak payload processed successfully"); + } catch (error) { + console.error("Error processing Keycloak payload:", error); + } +} + +main(); From f965914f1623039fcf75a58d67cfd3725f45193b Mon Sep 17 00:00:00 2001 From: drono Date: Tue, 17 Sep 2024 19:36:03 +0300 Subject: [PATCH 45/46] add config importer to update keycloak --- .../docker-compose-smart_keycloak.yml | 1 + .../importer/docker-compose.config.yml | 36 +++++ .../importer/update-keycloak-config.js | 145 ++++++++++-------- fhir-info-gateway/swarm.sh | 8 +- 4 files changed, 121 insertions(+), 69 deletions(-) rename fhir-info-gateway/{ => importer}/docker-compose-smart_keycloak.yml (99%) create mode 100644 fhir-info-gateway/importer/docker-compose.config.yml diff --git a/fhir-info-gateway/docker-compose-smart_keycloak.yml b/fhir-info-gateway/importer/docker-compose-smart_keycloak.yml similarity index 99% rename from fhir-info-gateway/docker-compose-smart_keycloak.yml rename to fhir-info-gateway/importer/docker-compose-smart_keycloak.yml index 7cf41431..b60c6bcd 100644 --- a/fhir-info-gateway/docker-compose-smart_keycloak.yml +++ b/fhir-info-gateway/importer/docker-compose-smart_keycloak.yml @@ -11,6 +11,7 @@ services: KEYCLOAK_PASSWORD: ${KC_ADMIN_PASSWORD} KEYCLOAK_REALM: ${KC_REALM_NAME} command: [ "-configFile", "config/backend-services-config.json" ] + networks: keycloak: name: keycloak_public diff --git a/fhir-info-gateway/importer/docker-compose.config.yml b/fhir-info-gateway/importer/docker-compose.config.yml new file mode 100644 index 00000000..b2e4ff32 --- /dev/null +++ b/fhir-info-gateway/importer/docker-compose.config.yml @@ -0,0 +1,36 @@ +version: "3.9" +services: + update-keycloak-config: + image: node:erbium-alpine + environment: + KEYCLOAK_SERVER_URL: ${KC_API_URL} + KEYCLOAK_REALM: ${KC_REALM_NAME} + KEYCLOAK_ADMIN_USER: ${KC_ADMIN_USERNAME} + KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD} + command: sh -c "cd / && npm i axios && node keycloakConfig.js" + configs: + - source: keycloak-config-importer-updateConfig.js + target: /keycloakConfig.js + - source: keycloak-config-importer-updateConfig.json + target: /keycloak-config.json + deploy: + replicas: 1 + restart_policy: + condition: none + networks: + keycloak: +configs: + keycloak-config-importer-updateConfig.js: + file: ./update-keycloak-config.js + name: keycloak-config-importer-updateConfig.js-${keycloak_config_importer_updateConfig_js_DIGEST:?err} + labels: + name: keycloakConfig + keycloak-config-importer-updateConfig.json: + file: ./keycloak-config.json + name: keycloak-config-importer-updateConfig.json-${keycloak_config_importer_updateConfig_json_DIGEST:?err} + labels: + name: keycloakConfigJson +networks: + keycloak: + name: keycloak_public + external: true diff --git a/fhir-info-gateway/importer/update-keycloak-config.js b/fhir-info-gateway/importer/update-keycloak-config.js index 709acedc..c9f71dfe 100644 --- a/fhir-info-gateway/importer/update-keycloak-config.js +++ b/fhir-info-gateway/importer/update-keycloak-config.js @@ -1,15 +1,19 @@ const axios = require("axios"); +const fs = require("fs"); // Load the JSON payload const payload = require("./keycloak-config.json"); +const { get } = require("http"); const serverUrl = - process.env.KEYCLOAK_SERVER_URL || "http://192.168.15.250:9088"; + process.env.KEYCLOAK_SERVER_URL || "http://192.168.100.57:9088"; const adminUser = process.env.KEYCLOAK_ADMIN_USER || "admin"; const adminPassword = process.env.KEYCLOAK_ADMIN_PASSWORD || "dev_password_only"; const adminClientId = process.env.KEYCLOAK_ADMIN_CLIENT_ID || "admin-cli"; const realm = process.env.KEYCLOAK_REALM || "platform-realm"; +const serviceAccountUser = + process.env.KEYCLOAK_SERVICE_ACCOUNT_USER || "service-account"; // Add service account user // Function definitions async function getAdminToken( @@ -70,7 +74,7 @@ async function getRoleByName(roleName, keycloakBaseUrl, realm, adminToken) { async function getOrCreateClient(client, keycloakBaseUrl, realm, adminToken) { try { - const clientResponse = await axios.get( + let clientResponse = await axios.get( `${keycloakBaseUrl}/admin/realms/${realm}/clients?clientId=${client.clientId}`, { headers: { @@ -96,7 +100,7 @@ async function getOrCreateClient(client, keycloakBaseUrl, realm, adminToken) { console.log(`Updated client: ${client.clientId}`); } else { // Client does not exist, create a new one - const newClientResponse = await axios.post( + clientResponse = await axios.post( `${keycloakBaseUrl}/admin/realms/${realm}/clients`, client, { @@ -107,8 +111,8 @@ async function getOrCreateClient(client, keycloakBaseUrl, realm, adminToken) { } ); console.log(`Created client: ${client.clientId}`); - return newClientResponse.data; } + return clientResponse.data; } catch (error) { console.error( "Error creating or updating client:", @@ -147,40 +151,12 @@ async function processKeycloakPayload( let roleId; try { - // Create or update client + // Create of update client // Step 1: Create or update a role for each client scope - roleId = await getRoleByName(name, keycloakBaseUrl, realm, adminToken); - if (roleId) { - // Role exists, update it - await axios.put( - `${keycloakBaseUrl}/admin/realms/${realm}/roles-by-id/${roleId}`, - role, - { - headers: { - Authorization: `Bearer ${adminToken}`, - "Content-Type": "application/json", - }, - } - ); - console.log(`Updated role: ${name}`); - } else { - // Role does not exist, create a new one - const roleResponse = await axios.post( - `${keycloakBaseUrl}/admin/realms/${realm}/roles`, - role, - { - headers: { - Authorization: `Bearer ${adminToken}`, - "Content-Type": "application/json", - }, - } - ); - roleId = roleResponse.data.id; - console.log(`Created role: ${name}`); - } // Step 2: Create or update the client scope + const clientScopeResponse = await axios.get( `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes`, { @@ -230,10 +206,11 @@ async function processKeycloakPayload( } ); } - + roleId = await getRoleByName(name, keycloakBaseUrl, realm, adminToken); // Step 3: Map the created role to the client scope await axios.post( `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes/${clientScope.id}/scope-mappings/realm`, + [{ id: roleId, name }], { headers: { @@ -249,9 +226,10 @@ async function processKeycloakPayload( }) ); - // Step 4: Create or update the service-account user + // Step 5: Create or update the service-account user + let userResponse, user, createdgroupResponse; try { - const groupResponse = await axios.get( + let groupResponse = await axios.get( `${keycloakBaseUrl}/admin/realms/${realm}/groups?search=${defaultGroup}`, { headers: { @@ -260,12 +238,11 @@ async function processKeycloakPayload( }, } ); - let groupId = ""; if (groupResponse.data.length > 0) { // Group exists, update it groupId = groupResponse.data[0].id; - await axios.put( + createdgroupResponse = await axios.put( `${keycloakBaseUrl}/admin/realms/${realm}/groups/${groupId}`, { name: defaultGroup, @@ -279,7 +256,7 @@ async function processKeycloakPayload( ); } else { // Group does not exist, create a new one - const createdGroupResponse = await axios.post( + createdgroupResponse = await axios.post( `${keycloakBaseUrl}/admin/realms/${realm}/groups`, { name: defaultGroup, @@ -291,10 +268,20 @@ async function processKeycloakPayload( }, } ); - groupId = createdGroupResponse.data.id; - console.log(`Created group: ${defaultGroup}`); + let createdGroup = await axios.get( + `${keycloakBaseUrl}/admin/realms/${realm}/groups?search=${defaultGroup}`, + { + headers: { + Authorization: `Bearer ${adminToken}`, + "Content-Type": "application/json", + }, + } + ); + console.log(`Created group: `, createdGroup); + groupId = createdGroup.data[0].id; } + const createdGroup = createdgroupResponse.data[0]; const usersResponse = await axios.get( `${keycloakBaseUrl}/admin/realms/${realm}/users`, { @@ -306,14 +293,13 @@ async function processKeycloakPayload( ); const users = usersResponse.data; - const user = users.find( - (u) => u.username === defaultUser.username.toLowerCase() - ); + user = users.find((u) => u.username === defaultUser.username.toLowerCase()); if (user) { // User exists, update it - await axios.put( - `${keycloakBaseUrl}/admin/realms/${realm}/users/${user.id}`, + const userId = user.id; + userResponse = await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/users/${userId}`, defaultUser, { headers: { @@ -325,7 +311,7 @@ async function processKeycloakPayload( console.log(`Updated user: ${defaultUser.username}`); } else { // User does not exist, create a new one - const userResponse = await axios.post( + userResponse = await axios.post( `${keycloakBaseUrl}/admin/realms/${realm}/users`, defaultUser, { @@ -338,9 +324,13 @@ async function processKeycloakPayload( console.log(`Created user: ${defaultUser.username}`); } + const createdUser = userResponse.data; + console.log("here", user); // Reset the password - await axios.put( - `${keycloakBaseUrl}/admin/realms/${realm}/users/${user.id}/reset-password`, + const newPass = await axios.put( + `${keycloakBaseUrl}/admin/realms/${realm}/users/${ + userResponse.id ? userResponse.id : user.id + }/reset-password`, resetPassword, { headers: { @@ -349,11 +339,12 @@ async function processKeycloakPayload( }, } ); - console.log(`Reset password for user ${defaultUser.username}`); - - // Add service-account user to the group + console.log(`Reset password for user ${createdUser}`, newPass.data); + // Step 5: Add service-account user to the group await axios.put( - `${keycloakBaseUrl}/admin/realms/${realm}/users/${user.id}/groups/${groupId}`, + `${keycloakBaseUrl}/admin/realms/${realm}/users/${ + createdUser.id ? createdUser.id : user.id + }/groups/${groupId}`, {}, { headers: { @@ -362,22 +353,21 @@ async function processKeycloakPayload( }, } ); - console.log(`Added user ${defaultUser.username} to group ${defaultGroup}`); - + console.log(`Added ${createdUser} to group ${createdgroupResponse}`); const uniqueRolesArray = await getUniqueRolesArray(payload); for (const role of uniqueRolesArray) { - const roleId = await getRoleByName( + const roleID = await getRoleByName( role.name, keycloakBaseUrl, realm, adminToken ); - - await axios.post( + console.log(roleID); + const roleMapping = await axios.post( `${keycloakBaseUrl}/admin/realms/${realm}/groups/${groupId}/role-mappings/realm`, [ { - id: roleId, + id: roleID, clientRole: false, composite: false, containerId: realm, @@ -392,7 +382,7 @@ async function processKeycloakPayload( }, } ); - console.log(`Added role mapping to group: ${role.name}`); + console.log(`Added role mapping to group ${roleMapping}`, role); } } catch (error) { console.error( @@ -401,8 +391,23 @@ async function processKeycloakPayload( ); throw error; } -} + // Step 6: Add role mapping to the group + // Extract unique roles + + // const rolesToBeMapped = []; + // uniqueRolesArray.forEach(async (role) => { + // const rolesToBeMappedPayload = await getRoleByName( + // role.name, + // keycloakBaseUrl, + // realm, + // adminToken + // ); + // console.log(rolesToBeMappedPayload); + // rolesToBeMapped.push(rolesToBeMappedPayload); + // }); + // console.log("sdsdsd", rolesToBeMapped); +} async function getUniqueRolesArray(payload) { const rolesSet = new Set(); const { clientScopes } = payload; @@ -417,7 +422,6 @@ async function getUniqueRolesArray(payload) { const uniqueRolesArray = Array.from(rolesSet).map((role) => JSON.parse(role)); return uniqueRolesArray; } - // Call the function and handle the result async function main() { try { @@ -428,14 +432,19 @@ async function main() { adminUser, adminPassword ); - const client = payload.client; - await getOrCreateClient(client, serverUrl, realm, adminToken); - + const createorupdateClient = await getOrCreateClient( + client, + serverUrl, + realm, + adminToken + ); + console.log(createorupdateClient); const uniqueRolesArray = await getUniqueRolesArray(payload); + for (const role of uniqueRolesArray) { const { name } = role; - const roleId = await getRoleByName(name, serverUrl, realm, adminToken); + let roleId = await getRoleByName(name, serverUrl, realm, adminToken); if (roleId) { // Role exists, update it @@ -462,10 +471,10 @@ async function main() { }, } ); + roleId = roleResponse.data.id; console.log(`Created role: ${name}`); } } - await processKeycloakPayload(payload, serverUrl, realm, adminToken); console.log("Keycloak payload processed successfully"); } catch (error) { diff --git a/fhir-info-gateway/swarm.sh b/fhir-info-gateway/swarm.sh index 156fa535..9dee3de1 100644 --- a/fhir-info-gateway/swarm.sh +++ b/fhir-info-gateway/swarm.sh @@ -44,11 +44,17 @@ function initialize_package() { fi ( - docker::deploy_service $STACK "${COMPOSE_FILE_PATH}" "docker-compose.yml" "$package_dev_compose_filename" "docker-compose-smart_keycloak.yml" + docker::deploy_service $STACK "${COMPOSE_FILE_PATH}" "docker-compose.yml" "$package_dev_compose_filename" "importer/docker-compose-smart_keycloak.yml" + + if [[ "${ACTION}" == "init" ]]; then + docker::deploy_config_importer $STACK "$COMPOSE_FILE_PATH/importer/docker-compose.config.yml" "update-keycloak-config" "fhirinfo" + fi + docker service rm fhir-info-gateway_smart-config >> /dev/null 2>&1 ) || { log error "Failed to deploy package" exit 1 } + } function destroy_package() { From abfd8514dfb01d0728af279562cdeb1a89266105 Mon Sep 17 00:00:00 2001 From: drono Date: Wed, 18 Sep 2024 09:48:26 +0300 Subject: [PATCH 46/46] cleanup --- .../importer/update-keycloak-config.js | 26 +- fhir-info-gateway/keycloak-config.json | 1209 ----------------- 2 files changed, 2 insertions(+), 1233 deletions(-) delete mode 100644 fhir-info-gateway/keycloak-config.json diff --git a/fhir-info-gateway/importer/update-keycloak-config.js b/fhir-info-gateway/importer/update-keycloak-config.js index c9f71dfe..6c84bc18 100644 --- a/fhir-info-gateway/importer/update-keycloak-config.js +++ b/fhir-info-gateway/importer/update-keycloak-config.js @@ -151,12 +151,6 @@ async function processKeycloakPayload( let roleId; try { - // Create of update client - - // Step 1: Create or update a role for each client scope - - // Step 2: Create or update the client scope - const clientScopeResponse = await axios.get( `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes`, { @@ -207,7 +201,7 @@ async function processKeycloakPayload( ); } roleId = await getRoleByName(name, keycloakBaseUrl, realm, adminToken); - // Step 3: Map the created role to the client scope + // Map the created role to the client scope await axios.post( `${keycloakBaseUrl}/admin/realms/${realm}/client-scopes/${clientScope.id}/scope-mappings/realm`, @@ -226,7 +220,7 @@ async function processKeycloakPayload( }) ); - // Step 5: Create or update the service-account user + // Create or update the service-account user let userResponse, user, createdgroupResponse; try { let groupResponse = await axios.get( @@ -391,22 +385,6 @@ async function processKeycloakPayload( ); throw error; } - - // Step 6: Add role mapping to the group - // Extract unique roles - - // const rolesToBeMapped = []; - // uniqueRolesArray.forEach(async (role) => { - // const rolesToBeMappedPayload = await getRoleByName( - // role.name, - // keycloakBaseUrl, - // realm, - // adminToken - // ); - // console.log(rolesToBeMappedPayload); - // rolesToBeMapped.push(rolesToBeMappedPayload); - // }); - // console.log("sdsdsd", rolesToBeMapped); } async function getUniqueRolesArray(payload) { const rolesSet = new Set(); diff --git a/fhir-info-gateway/keycloak-config.json b/fhir-info-gateway/keycloak-config.json deleted file mode 100644 index 3306a916..00000000 --- a/fhir-info-gateway/keycloak-config.json +++ /dev/null @@ -1,1209 +0,0 @@ -{ - "keycloak": { - "serverUrl": "${KEYCLOAK_BASE_URL}", - "adminUser": "${KEYCLOAK_USER}", - "adminPassword": "${KEYCLOAK_PASSWORD}", - "adminClientId": "admin-cli", - "realms": { - "${KEYCLOAK_REALM}": { - "enabled": true, - "clientScopes": { - "fhirUser": { - "protocol": "openid-connect", - "description": "Permission to retrieve current logged-in user", - "attributes": { - "consent.screen.text": "Permission to retrieve current logged-in user" - }, - "mappers": { - "fhirUser Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-patient-prefix-usermodel-attribute-mapper", - "config": { - "user.attribute": "resourceId", - "claim.name": "fhirUser", - "jsonType.label": "String", - "id.token.claim": "true", - "access.token.claim": "false", - "userinfo.token.claim": "true" - } - } - } - }, - "launch/patient": { - "protocol": "openid-connect", - "description": "Used by clients to request a patient-scoped access token", - "attributes": { - "display.on.consent.screen": "false" - }, - "mappers": { - "Patient ID Claim Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-usermodel-attribute-mapper", - "config": { - "user.attribute": "resourceId", - "claim.name": "patient_id", - "jsonType.label": "String", - "id.token.claim": "false", - "access.token.claim": "true", - "userinfo.token.claim": "false" - } - }, - "Patient ID Token Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-usersessionmodel-note-mapper", - "config": { - "user.session.note": "patient_id", - "claim.name": "patient", - "jsonType.label": "String", - "id.token.claim": "false", - "access.token.claim": "false", - "access.tokenResponse.claim": "true" - } - }, - "Group Membership Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-group-membership-mapper", - "config": { - "claim.name": "group", - "full.path": "false", - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - } - } - }, - "online_access": { - "protocol": "openid-connect", - "description": "Request a refresh_token that can be used to obtain a new access token to replace an expired one, and that will be usable for as long as the end-user remains online.", - "attributes": { - "consent.screen.text": "Retain access while you are online" - } - }, - "system/*.rs": { - "protocol": "openid-connect", - "description": "Read access and search to all data", - "attributes": { - "consent.screen.text": "Read access to all data" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Observation.rs": { - "protocol": "openid-connect", - "description": "Read access to Observation", - "attributes": { - "consent.screen.text": "Read access to Observation" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Encounter.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Encounter", - "attributes": { - "consent.screen.text": "Create, update and delete access to Encounter" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Encounter.rs": { - "protocol": "openid-connect", - "description": "Read access to Encounter", - "attributes": { - "consent.screen.text": "Read access to Encounter" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Patient.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Patient", - "attributes": { - "consent.screen.text": "Create, update and delete access to Patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Patient.rs": { - "protocol": "openid-connect", - "description": "Read access to Patient", - "attributes": { - "consent.screen.text": "Read access to Patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Practitioner.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Practitioner", - "attributes": { - "consent.screen.text": "Create, update and delete access to Practitioner" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Practitioner.rs": { - "protocol": "openid-connect", - "description": "Read access to Practitioner", - "attributes": { - "consent.screen.text": "Read access to Practitioner" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/PractitionerRole.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to PractitionerRole", - "attributes": { - "consent.screen.text": "Create, update and delete access to PractitionerRole" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/PractitionerRole.rs": { - "protocol": "openid-connect", - "description": "Read access to PractitionerRole", - "attributes": { - "consent.screen.text": "Read access to PractitionerRole" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Organization.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Organization", - "attributes": { - "consent.screen.text": "Create, update and delete access to Organization" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Organization.rs": { - "protocol": "openid-connect", - "description": "Read access to Organization", - "attributes": { - "consent.screen.text": "Read access to Organization" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Device.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Device", - "attributes": { - "consent.screen.text": "Create, update and delete access to Device" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Device.rs": { - "protocol": "openid-connect", - "description": "Read access to Device", - "attributes": { - "consent.screen.text": "Read access to Device" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/AllergyIntolerance.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to AllergyIntolerance", - "attributes": { - "consent.screen.text": "Create, update and delete access to AllergyIntolerance" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/AllergyIntolerance.rs": { - "protocol": "openid-connect", - "description": "Read access to AllergyIntolerance", - "attributes": { - "consent.screen.text": "Read access to AllergyIntolerance" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/CarePlan.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to CarePlan", - "attributes": { - "consent.screen.text": "Create, update and delete access to CarePlan" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/CarePlan.rs": { - "protocol": "openid-connect", - "description": "Read access to CarePlan", - "attributes": { - "consent.screen.text": "Read access to CarePlan" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/CareTeam.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to CareTeam", - "attributes": { - "consent.screen.text": "Create, update and delete access to CareTeam" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/CareTeam.rs": { - "protocol": "openid-connect", - "description": "Read access to CareTeam", - "attributes": { - "consent.screen.text": "Read access to CareTeam" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Condition.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Condition", - "attributes": { - "consent.screen.text": "Create, update and delete access to Condition" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Condition.rs": { - "protocol": "openid-connect", - "description": "Read access to Condition", - "attributes": { - "consent.screen.text": "Read access to Condition" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/DiagnosticReport.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to DiagnosticReport", - "attributes": { - "consent.screen.text": "Create, update and delete access to DiagnosticReport" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/DiagnosticReport.rs": { - "protocol": "openid-connect", - "description": "Read access to DiagnosticReport", - "attributes": { - "consent.screen.text": "Read access to DiagnosticReport" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/DocumentReference.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to DocumentReference", - "attributes": { - "consent.screen.text": "Create, update and delete access to DocumentReference" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/DocumentReference.rs": { - "protocol": "openid-connect", - "description": "Read access to DocumentReference", - "attributes": { - "consent.screen.text": "Read access to DocumentReference" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Bundle.cud": { - "protocol": "openid-connect", - "description": "Create, update and delete access to Bundle", - "attributes": { - "consent.screen.text": "Create, update and delete access to Bundle" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "system/Bundle.rs": { - "protocol": "openid-connect", - "description": "Read access to Bundle", - "attributes": { - "consent.screen.text": "Read access to Bundle" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - - "patient/*.read": { - "protocol": "openid-connect", - "description": "Read access to all data", - "attributes": { - "consent.screen.text": "Read access to all data for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/AllergyIntolerance.read": { - "protocol": "openid-connect", - "description": "Read access to AllergyIntolerance", - "attributes": { - "consent.screen.text": "Read access to AllergyIntolerance for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/CarePlan.read": { - "protocol": "openid-connect", - "description": "Read access to CarePlan", - "attributes": { - "consent.screen.text": "Read access to CarePlan for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/CareTeam.read": { - "protocol": "openid-connect", - "description": "Read access to CareTeam", - "attributes": { - "consent.screen.text": "Read access to CareTeam for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Condition.read": { - "protocol": "openid-connect", - "description": "Read access to Condition", - "attributes": { - "consent.screen.text": "Read access to Condition for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Device.read": { - "protocol": "openid-connect", - "description": "Read access to Device", - "attributes": { - "consent.screen.text": "Read access to Device for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/DiagnosticReport.read": { - "protocol": "openid-connect", - "description": "Read access to DiagnosticReport", - "attributes": { - "consent.screen.text": "Read access to DiagnosticReport for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/DocumentReference.read": { - "protocol": "openid-connect", - "description": "Read access to DocumentReference", - "attributes": { - "consent.screen.text": "Read access to DocumentReference for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Encounter.read": { - "protocol": "openid-connect", - "description": "Read access to Encounter", - "attributes": { - "consent.screen.text": "Read access to Encounter for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/ExplanationOfBenefit.read": { - "protocol": "openid-connect", - "description": "Read access to ExplanationOfBenefit", - "attributes": { - "consent.screen.text": "Read access to ExplanationOfBenefit for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Goal.read": { - "protocol": "openid-connect", - "description": "Read access to Goal", - "attributes": { - "consent.screen.text": "Read access to Goal for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Immunization.read": { - "protocol": "openid-connect", - "description": "Read access to Immunization", - "attributes": { - "consent.screen.text": "Read access to Immunization for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Location.read": { - "protocol": "openid-connect", - "description": "Read access to Location", - "attributes": { - "consent.screen.text": "Read access to Location for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Medication.read": { - "protocol": "openid-connect", - "description": "Read access to Medication", - "attributes": { - "consent.screen.text": "Read access to Medication for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/MedicationDispense.read": { - "protocol": "openid-connect", - "description": "Read access to MedicationDispense", - "attributes": { - "consent.screen.text": "Read access to MedicationDispense for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/MedicationRequest.read": { - "protocol": "openid-connect", - "description": "Read access to MedicationRequest", - "attributes": { - "consent.screen.text": "Read access to MedicationRequest for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Observation.read": { - "protocol": "openid-connect", - "description": "Read access to Observation", - "attributes": { - "consent.screen.text": "Read access to Observation for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Organization.read": { - "protocol": "openid-connect", - "description": "Read access to Organization", - "attributes": { - "consent.screen.text": "Read access to Organization for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Patient.read": { - "protocol": "openid-connect", - "description": "Read access to Patient", - "attributes": { - "consent.screen.text": "Read access to Patient for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Practitioner.read": { - "protocol": "openid-connect", - "description": "Read access to Practitioner", - "attributes": { - "consent.screen.text": "Read access to Practitioner for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/PractitionerRole.read": { - "protocol": "openid-connect", - "description": "Read access to PractitionerRole", - "attributes": { - "consent.screen.text": "Read access to PractitionerRole for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Procedure.read": { - "protocol": "openid-connect", - "description": "Read access to Procedure", - "attributes": { - "consent.screen.text": "Read access to Procedure for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/Provenance.read": { - "protocol": "openid-connect", - "description": "Read access to Provenance", - "attributes": { - "consent.screen.text": "Read access to Provenance for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "patient/RelatedPerson.read": { - "protocol": "openid-connect", - "description": "Read access to RelatedPerson", - "attributes": { - "consent.screen.text": "Read access to RelatedPerson for the patient" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "user/Device.read": { - "protocol": "openid-connect", - "description": "Read access to Device", - "attributes": { - "consent.screen.text": "Read access to all Device" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "user/Organization.read": { - "protocol": "openid-connect", - "description": "Read access to Organization", - "attributes": { - "consent.screen.text": "Read access to all Organization" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "user/Practitioner.read": { - "protocol": "openid-connect", - "description": "Read access to Practitioner", - "attributes": { - "consent.screen.text": "Read access to all Practitioner" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - }, - "user/PractitionerRole.read": { - "protocol": "openid-connect", - "description": "Read access to PractitionerRole", - "attributes": { - "consent.screen.text": "Read access to all PractitionerRole" - }, - "mappers": { - "Audience Mapper": { - "protocol": "openid-connect", - "protocolmapper": "oidc-audience-mapper", - "config": { - "included.custom.audience": "${FHIR_BASE_URL}", - "access.token.claim": "true" - } - } - } - } - }, - "defaultDefaultClientScopes": [], - "defaultOptionalClientScopes": [ - "fhirUser", - "launch/patient", - "offline_access", - "online_access", - "profile", - "patient/*.read", - "patient/AllergyIntolerance.read", - "patient/CarePlan.read", - "patient/CareTeam.read", - "patient/Condition.read", - "patient/Device.read", - "patient/DiagnosticReport.read", - "patient/DocumentReference.read", - "patient/Encounter.read", - "patient/ExplanationOfBenefit.read", - "patient/Goal.read", - "patient/Immunization.read", - "patient/Location.read", - "patient/Medication.read", - "patient/MedicationDispense.read", - "patient/MedicationRequest.read", - "patient/Observation.read", - "patient/Organization.read", - "patient/Patient.read", - "patient/Practitioner.read", - "patient/PractitionerRole.read", - "patient/Procedure.read", - "patient/Provenance.read", - "patient/RelatedPerson.read", - "user/Device.read", - "user/Organization.read", - "user/Practitioner.read", - "user/PractitionerRole.read" - ], - "clients": { - "inferno": { - "consentRequired": true, - "publicClient": true, - "bearerOnly": false, - "enableDirectAccess": false, - "rootURL": "http://localhost:4567/inferno", - "redirectURIs": [ - "http://localhost:4567/inferno/*", - "http://localhost:4567/inferno2/*" - ], - "adminURL": "http://localhost:4567/inferno", - "webOrigins": ["http://localhost:4567"], - "defaultClientScopes": ["launch/patient"], - "optionalClientScopes": [ - "fhirUser", - "offline_access", - "online_access", - "profile", - "patient/*.read", - "patient/AllergyIntolerance.read", - "patient/CarePlan.read", - "patient/CareTeam.read", - "patient/Condition.read", - "patient/Device.read", - "patient/DiagnosticReport.read", - "patient/DocumentReference.read", - "patient/Encounter.read", - "patient/ExplanationOfBenefit.read", - "patient/Goal.read", - "patient/Immunization.read", - "patient/Location.read", - "patient/Medication.read", - "patient/MedicationDispense.read", - "patient/MedicationRequest.read", - "patient/Observation.read", - "patient/Organization.read", - "patient/Patient.read", - "patient/Practitioner.read", - "patient/PractitionerRole.read", - "patient/Procedure.read", - "patient/Provenance.read", - "patient/RelatedPerson.read", - "user/Device.read", - "user/Organization.read", - "user/Practitioner.read", - "user/PractitionerRole.read" - ] - } - }, - "authenticationFlows": { - "SMART App Launch": { - "description": "browser based authentication", - "providerId": "basic-flow", - "builtIn": false, - "authenticationExecutions": { - "SMART Login": { - "requirement": "ALTERNATIVE", - "userSetupAllowed": false, - "authenticatorFlow": true, - "description": "Username, password, otp and other auth forms.", - "providerId": "basic-flow", - "authenticationExecutions": { - "Audience Validation": { - "authenticator": "audience-validator", - "requirement": "DISABLED", - "priority": 10, - "authenticatorFlow": false, - "configAlias": "localhost", - "config": { - "audiences": "${FHIR_BASE_URL}" - } - }, - "Username Password Form": { - "authenticator": "auth-username-password-form", - "requirement": "REQUIRED", - "priority": 20, - "authenticatorFlow": false - }, - "Patient Selection Authenticator": { - "authenticator": "auth-select-patient", - "requirement": "REQUIRED", - "priority": 30, - "authenticatorFlow": false, - "configAlias": "host.docker", - "config": { - "internalFhirUrl": "${FHIR_BASE_URL}" - } - } - } - } - } - } - }, - "browserFlow": "SMART App Launch", - "groups": { - "fhirUser": {} - }, - "defaultGroups": ["fhirUser"], - "users": { - "fhiruser": { - "enabled": true, - "password": "change-password", - "passwordTemporary": false, - "attributes": { - "resourceId": ["Patient1"] - }, - "groups": ["fhirUser"] - } - }, - "eventsConfig": { - "saveLoginEvents": true, - "expiration": 23328000, - "types": [ - "FEDERATED_IDENTITY_LINK", - "LOGOUT", - "LOGIN_ERROR", - "IDENTITY_PROVIDER_LINK_ACCOUNT", - "REFRESH_TOKEN", - "FEDERATED_IDENTITY_LINK_ERROR", - "IDENTITY_PROVIDER_POST_LOGIN", - "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", - "CODE_TO_TOKEN_ERROR", - "IDENTITY_PROVIDER_FIRST_LOGIN", - "REFRESH_TOKEN_ERROR", - "IDENTITY_PROVIDER_POST_LOGIN_ERROR", - "LOGOUT_ERROR", - "CODE_TO_TOKEN", - "LOGIN", - "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" - ], - "saveAdminEvents": true - } - } - } - } -}