Add files via upload

This commit is contained in:
Joshua Hare 2025-04-17 17:31:43 +10:00 committed by GitHub
parent 6fd4bd3171
commit dc21d202c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 1208 additions and 0 deletions

View File

@ -0,0 +1,9 @@
dependencies:
- name: postgresql
repository: oci://registry-1.docker.io/bitnamicharts
version: 16.5.5
- name: common
repository: oci://registry-1.docker.io/bitnamicharts
version: 2.30.0
digest: sha256:c114b296b53007a7973260de8bad61917fe741c0ad9de15fdbeea5743c8f4910
generated: "2025-03-21T21:44:22.334197366+01:00"

View File

@ -0,0 +1,34 @@
apiVersion: v2
name: hapi-fhir-jpaserver
description: A Helm chart for deploying the HAPI FHIR JPA server starter on Kubernetes.
type: application
home: https://github.com/hapifhir/hapi-fhir-jpaserver-starter
sources:
- https://github.com/hapifhir/hapi-fhir-jpaserver-starter
dependencies:
- name: postgresql
version: 16.5.5
repository: oci://registry-1.docker.io/bitnamicharts
condition: postgresql.enabled
- name: common
repository: oci://registry-1.docker.io/bitnamicharts
version: 2.30.0
appVersion: 8.0.0
version: 0.19.0
annotations:
artifacthub.io/license: Apache-2.0
artifacthub.io/containsSecurityUpdates: "false"
artifacthub.io/operator: "false"
artifacthub.io/prerelease: "false"
artifacthub.io/recommendations: |
- url: https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack
- url: https://artifacthub.io/packages/helm/bitnami/postgresql
artifacthub.io/changes: |
# When using the list of objects option the valid supported kinds are
# added, changed, deprecated, removed, fixed, and security.
- kind: changed
description: "updated postgresql sub-chart to 16.5.5"
- kind: changed
description: "updated curlimages/curl to 8.12.1"
- kind: changed
description: "updated hapiproject/hapi to v8.0.0-1"

View File

@ -0,0 +1,150 @@
# HAPI FHIR JPA Server Starter Helm Chart
![Version: 0.19.0](https://img.shields.io/badge/Version-0.19.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 8.0.0](https://img.shields.io/badge/AppVersion-8.0.0-informational?style=flat-square)
This helm chart will help you install the HAPI FHIR JPA Server in a Kubernetes environment.
## Sample usage
```sh
helm repo add hapifhir https://hapifhir.github.io/hapi-fhir-jpaserver-starter/
helm install hapi-fhir-jpaserver hapifhir/hapi-fhir-jpaserver
```
## Requirements
| Repository | Name | Version |
|------------|------|---------|
| oci://registry-1.docker.io/bitnamicharts | common | 2.30.0 |
| oci://registry-1.docker.io/bitnamicharts | postgresql | 16.5.5 |
## Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | pod affinity |
| deploymentAnnotations | object | `{}` | annotations applied to the server deployment |
| externalDatabase.database | string | `"fhir"` | database name |
| externalDatabase.existingSecret | string | `""` | name of an existing secret resource containing the DB password in the `existingSecretKey` key |
| externalDatabase.existingSecretKey | string | `"postgresql-password"` | name of the key inside the `existingSecret` |
| externalDatabase.host | string | `"localhost"` | external database host used with `postgresql.enabled=false` |
| externalDatabase.password | string | `""` | database password |
| externalDatabase.port | int | `5432` | database port number |
| externalDatabase.user | string | `"fhir"` | username for the external database |
| extraConfig | string | `""` | additional Spring Boot application config. Mounted as a file and automatically loaded by the application. |
| extraEnv | list | `[]` | extra environment variables to set on the server container |
| extraVolumeMounts | list | `[]` | Optionally specify extra list of additional volumeMounts |
| extraVolumes | list | `[]` | Optionally specify extra list of additional volumes |
| fullnameOverride | string | `""` | override the chart fullname |
| image.pullPolicy | string | `"IfNotPresent"` | image pullPolicy to use |
| image.registry | string | `"docker.io"` | registry where the HAPI FHIR server image is hosted |
| image.repository | string | `"hapiproject/hapi"` | the path inside the repository |
| image.tag | string | `"v8.0.0-1@sha256:9fbac7b012b4be91ba481e7008f1353ede4598bc99a36f3902b8abf873e70ed8"` | the image tag. As of v5.7.0, this is the `distroless` flavor by default, add `-tomcat` to use the Tomcat-based image. |
| imagePullSecrets | list | `[]` | image pull secrets to use when pulling the image |
| ingress.annotations | object | `{}` | provide any additional annotations which may be required. Evaluated as a template. |
| ingress.enabled | bool | `false` | whether to create an Ingress to expose the FHIR server HTTP endpoint |
| ingress.hosts[0].host | string | `"fhir-server.127.0.0.1.nip.io"` | |
| ingress.hosts[0].pathType | string | `"ImplementationSpecific"` | |
| ingress.hosts[0].paths[0] | string | `"/"` | |
| ingress.tls | list | `[]` | ingress TLS config |
| initContainers.resources | object | `{}` | configure the init containers pods resource requests and limits |
| initContainers.resourcesPreset | string | `"nano"` | set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if `resources` is set (`resources` is recommended for production). More information: <https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15> |
| metrics.service.port | int | `8081` | |
| metrics.serviceMonitor.additionalLabels | object | `{}` | additional labels to apply to the ServiceMonitor object, e.g. `release: prometheus` |
| metrics.serviceMonitor.enabled | bool | `false` | if enabled, creates a ServiceMonitor instance for Prometheus Operator-based monitoring |
| nameOverride | string | `""` | override the chart name |
| nodeSelector | object | `{}` | node selector for the pod |
| podAnnotations | object | `{}` | annotations applied to the server pod |
| podDisruptionBudget.enabled | bool | `false` | Enable PodDisruptionBudget for the server pods. uses policy/v1/PodDisruptionBudget thus requiring k8s 1.21+ |
| podDisruptionBudget.maxUnavailable | string | `""` | maximum unavailable instances |
| podDisruptionBudget.minAvailable | int | `1` | minimum available instances |
| podSecurityContext | object | `{"fsGroup":65532,"fsGroupChangePolicy":"OnRootMismatch","runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | pod security context |
| postgresql.auth.database | string | `"fhir"` | name for a custom database to create |
| postgresql.auth.existingSecret | string | `""` | Name of existing secret to use for PostgreSQL credentials `auth.postgresPassword`, `auth.password`, and `auth.replicationPassword` will be ignored and picked up from this secret The secret must contain the keys `postgres-password` (which is the password for "postgres" admin user), `password` (which is the password for the custom user to create when `auth.username` is set), and `replication-password` (which is the password for replication user). The secret might also contains the key `ldap-password` if LDAP is enabled. `ldap.bind_password` will be ignored and picked from this secret in this case. The value is evaluated as a template. |
| postgresql.enabled | bool | `true` | enable an included PostgreSQL DB. see <https://github.com/bitnami/charts/tree/master/bitnami/postgresql> for details if set to `false`, the values under `externalDatabase` are used |
| replicaCount | int | `1` | number of replicas to deploy |
| resources | object | `{}` | configure the FHIR server's resource requests and limits |
| resourcesPreset | string | `"medium"` | set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if `resources` is set (`resources` is recommended for production). More information: <https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15> |
| securityContext.allowPrivilegeEscalation | bool | `false` | |
| securityContext.capabilities.drop[0] | string | `"ALL"` | |
| securityContext.privileged | bool | `false` | |
| securityContext.readOnlyRootFilesystem | bool | `true` | |
| securityContext.runAsGroup | int | `65532` | |
| securityContext.runAsNonRoot | bool | `true` | |
| securityContext.runAsUser | int | `65532` | |
| securityContext.seccompProfile.type | string | `"RuntimeDefault"` | |
| service.port | int | `8080` | port where the server will be exposed at |
| service.type | string | `"ClusterIP"` | service type |
| serviceAccount.annotations | object | `{}` | Annotations to add to the service account |
| serviceAccount.automount | bool | `true` | Automatically mount a ServiceAccount's API credentials? |
| serviceAccount.create | bool | `false` | Specifies whether a service account should be created. |
| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template |
| tests.automountServiceAccountToken | bool | `false` | whether the service account token should be auto-mounted for the test pods |
| tests.resources | object | `{}` | configure the test pods resource requests and limits |
| tests.resourcesPreset | string | `"nano"` | set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if `resources` is set (`resources` is recommended for production). More information: <https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15> |
| tolerations | list | `[]` | pod tolerations |
| topologySpreadConstraints | list | `[]` | pod topology spread configuration see: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#api |
## Development
To update the Helm chart when a new version of the `hapiproject/hapi` image is released, [values.yaml](values.yaml) `image.tag` and the [Chart.yaml](Chart.yaml)'s
`version` and optionally the `appVersion` field need to be updated. Afterwards, re-generate the [README.md](README.md)
by running:
```sh
$ helm-docs
INFO[2021-11-20T12:38:04Z] Found Chart directories [charts/hapi-fhir-jpaserver]
INFO[2021-11-20T12:38:04Z] Generating README Documentation for chart /usr/src/app/charts/hapi-fhir-jpaserver
```
## Enable Distributed Tracing based on the OpenTelemtry Java Agent
The container image includes the [OpenTelemetry Java agent JAR](https://github.com/open-telemetry/opentelemetry-java-instrumentation)
which can be used to enable distributed tracing. It can be configured entirely using environment variables,
see <https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/> for details.
Here's an example setup deploying [Jaeger](https://www.jaegertracing.io/) as a tracing backend:
```sh
# required by the Jaeger Operator
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
kubectl create namespace observability
kubectl create -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.37.0/jaeger-operator.yaml -n observability
cat <<EOF | kubectl apply -n observability -f -
# simple, all-in-one Jaeger installation. Not suitable for production use.
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: simplest
EOF
```
Use this chart's `extraEnv` value to set the required environment variables:
```yaml
extraEnv:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/app/opentelemetry-javaagent.jar"
- name: OTEL_METRICS_EXPORTER
value: "none"
- name: OTEL_LOGS_EXPORTER
value: "none"
- name: OTEL_TRACES_EXPORTER
value: "jaeger"
- name: OTEL_SERVICE_NAME
value: "hapi-fhir-jpaserver"
- name: OTEL_EXPORTER_JAEGER_ENDPOINT
value: "http://simplest-collector.observability.svc:14250"
```
Finally, you can open the Jaeger query UI by running:
```sh
kubectl port-forward -n observability service/simplest-query 16686:16686
```
and opening <http://localhost:16686/> in your browser.
----------------------------------------------
Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2)

View File

@ -0,0 +1,79 @@
# HAPI FHIR JPA Server Starter Helm Chart
{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }}
This helm chart will help you install the HAPI FHIR JPA Server in a Kubernetes environment.
## Sample usage
```sh
helm repo add hapifhir https://hapifhir.github.io/hapi-fhir-jpaserver-starter/
helm install hapi-fhir-jpaserver hapifhir/hapi-fhir-jpaserver
```
{{ template "chart.requirementsSection" . }}
{{ template "chart.valuesSection" . }}
## Development
To update the Helm chart when a new version of the `hapiproject/hapi` image is released, [values.yaml](values.yaml) `image.tag` and the [Chart.yaml](Chart.yaml)'s
`version` and optionally the `appVersion` field need to be updated. Afterwards, re-generate the [README.md](README.md)
by running:
```sh
$ helm-docs
INFO[2021-11-20T12:38:04Z] Found Chart directories [charts/hapi-fhir-jpaserver]
INFO[2021-11-20T12:38:04Z] Generating README Documentation for chart /usr/src/app/charts/hapi-fhir-jpaserver
```
## Enable Distributed Tracing based on the OpenTelemtry Java Agent
The container image includes the [OpenTelemetry Java agent JAR](https://github.com/open-telemetry/opentelemetry-java-instrumentation)
which can be used to enable distributed tracing. It can be configured entirely using environment variables,
see <https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/> for details.
Here's an example setup deploying [Jaeger](https://www.jaegertracing.io/) as a tracing backend:
```sh
# required by the Jaeger Operator
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
kubectl create namespace observability
kubectl create -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.37.0/jaeger-operator.yaml -n observability
cat <<EOF | kubectl apply -n observability -f -
# simple, all-in-one Jaeger installation. Not suitable for production use.
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: simplest
EOF
```
Use this chart's `extraEnv` value to set the required environment variables:
```yaml
extraEnv:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/app/opentelemetry-javaagent.jar"
- name: OTEL_METRICS_EXPORTER
value: "none"
- name: OTEL_LOGS_EXPORTER
value: "none"
- name: OTEL_TRACES_EXPORTER
value: "jaeger"
- name: OTEL_SERVICE_NAME
value: "hapi-fhir-jpaserver"
- name: OTEL_EXPORTER_JAEGER_ENDPOINT
value: "http://simplest-collector.observability.svc:14250"
```
Finally, you can open the Jaeger query UI by running:
```sh
kubectl port-forward -n observability service/simplest-query 16686:16686
```
and opening <http://localhost:16686/> in your browser.
{{ template "helm-docs.versionFooter" . }}

View File

@ -0,0 +1,7 @@
postgresql:
enabled: true
auth:
username: hapi_fhir_jpaserver_starter_user
database: hapi_fhir_jpaserver_starter
password: secret_user_password
postgresPassword: secret_postgres_password

View File

@ -0,0 +1,6 @@
ingress:
enabled: true
postgresql:
auth:
postgresPassword: secretpassword

View File

@ -0,0 +1,17 @@
extraConfig: |
hapi:
fhir:
cr_enabled: true
tester:
home:
name: Hello HAPI FHIR
server_address: "http://fhir-server.127.0.0.1.nip.io/fhir"
refuse_to_fetch_third_party_urls: true
fhir_version: R4
ingress:
enabled: true
hosts:
- host: fhir-server.127.0.0.1.nip.io
pathType: ImplementationSpecific
paths: ["/"]

View File

@ -0,0 +1,11 @@
extraVolumes:
- name: config-kube-root-ca
configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
extraVolumeMounts:
- name: config-kube-root-ca
mountPath: /etc/test

View File

@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "hapi-fhir-jpaserver.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "hapi-fhir-jpaserver.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "hapi-fhir-jpaserver.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "hapi-fhir-jpaserver.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

View File

@ -0,0 +1,152 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "hapi-fhir-jpaserver.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "hapi-fhir-jpaserver.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "hapi-fhir-jpaserver.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "hapi-fhir-jpaserver.labels" -}}
helm.sh/chart: {{ include "hapi-fhir-jpaserver.chart" . }}
{{ include "hapi-fhir-jpaserver.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "hapi-fhir-jpaserver.selectorLabels" -}}
app.kubernetes.io/name: {{ include "hapi-fhir-jpaserver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "hapi-fhir-jpaserver.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "hapi-fhir-jpaserver.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Create a default fully qualified postgresql name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "hapi-fhir-jpaserver.postgresql.fullname" -}}
{{- $name := default "postgresql" .Values.postgresql.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Get the Postgresql credentials secret name.
*/}}
{{- define "hapi-fhir-jpaserver.postgresql.secretName" -}}
{{- if .Values.postgresql.enabled -}}
{{- if .Values.postgresql.auth.existingSecret -}}
{{- printf "%s" .Values.postgresql.auth.existingSecret -}}
{{- else -}}
{{- printf "%s" (include "hapi-fhir-jpaserver.postgresql.fullname" .) -}}
{{- end -}}
{{- else }}
{{- if .Values.externalDatabase.existingSecret -}}
{{- printf "%s" .Values.externalDatabase.existingSecret -}}
{{- else -}}
{{ printf "%s-%s" (include "hapi-fhir-jpaserver.fullname" .) "external-db" }}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Get the Postgresql credentials secret key.
*/}}
{{- define "hapi-fhir-jpaserver.postgresql.secretKey" -}}
{{- if .Values.postgresql.enabled -}}
{{- if .Values.postgresql.auth.username -}}
{{- printf "%s" .Values.postgresql.auth.secretKeys.userPasswordKey -}}
{{- else -}}
{{- printf "%s" .Values.postgresql.auth.secretKeys.adminPasswordKey -}}
{{- end -}}
{{- else }}
{{- if .Values.externalDatabase.existingSecret -}}
{{- printf "%s" .Values.externalDatabase.existingSecretKey -}}
{{- else -}}
{{- printf "postgres-password" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Add environment variables to configure database values
*/}}
{{- define "hapi-fhir-jpaserver.database.host" -}}
{{- ternary (include "hapi-fhir-jpaserver.postgresql.fullname" .) .Values.externalDatabase.host .Values.postgresql.enabled -}}
{{- end -}}
{{/*
Add environment variables to configure database values
*/}}
{{- define "hapi-fhir-jpaserver.database.user" -}}
{{- if .Values.postgresql.enabled -}}
{{- printf "%s" .Values.postgresql.auth.username | default "postgres" -}}
{{- else -}}
{{- printf "%s" .Values.externalDatabase.user -}}
{{- end -}}
{{- end -}}
{{/*
Add environment variables to configure database values
*/}}
{{- define "hapi-fhir-jpaserver.database.name" -}}
{{- ternary .Values.postgresql.auth.database .Values.externalDatabase.database .Values.postgresql.enabled -}}
{{- end -}}
{{/*
Add environment variables to configure database values
*/}}
{{- define "hapi-fhir-jpaserver.database.port" -}}
{{- ternary "5432" .Values.externalDatabase.port .Values.postgresql.enabled -}}
{{- end -}}
{{/*
Create the JDBC URL from the host, port and database name.
*/}}
{{- define "hapi-fhir-jpaserver.database.jdbcUrl" -}}
{{- $host := (include "hapi-fhir-jpaserver.database.host" .) -}}
{{- $port := (include "hapi-fhir-jpaserver.database.port" .) -}}
{{- $name := (include "hapi-fhir-jpaserver.database.name" .) -}}
{{- $appName := .Release.Name -}}
{{ printf "jdbc:postgresql://%s:%d/%s?ApplicationName=%s" $host (int $port) $name $appName }}
{{- end -}}

View File

@ -0,0 +1,11 @@
{{- if .Values.extraConfig -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}-application-config
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
data:
application-extra.yaml: |-
{{ .Values.extraConfig | nindent 4 }}
{{- end }}

View File

@ -0,0 +1,160 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
{{- with .Values.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "hapi-fhir-jpaserver.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "hapi-fhir-jpaserver.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "hapi-fhir-jpaserver.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
initContainers:
- name: wait-for-db-to-be-ready
image: docker.io/bitnami/postgresql:17.4.0-debian-12-r10@sha256:7b9af9dd759055265998bbf12368e6d7d6326e6fd23f8157be841fad0915c1a1
imagePullPolicy: IfNotPresent
{{- with .Values.restrictedContainerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.initContainers.resources }}
resources: {{- toYaml .Values.initContainers.resources | nindent 12 }}
{{- else if ne .Values.initContainers.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.initContainers.resourcesPreset) | nindent 12 }}
{{- end }}
env:
- name: PGHOST
value: "{{ include "hapi-fhir-jpaserver.database.host" . }}"
- name: PGPORT
value: "{{ include "hapi-fhir-jpaserver.database.port" . }}"
- name: PGUSER
value: "{{ include "hapi-fhir-jpaserver.database.user" . }}"
command: ["/bin/sh", "-c"]
args:
- |
until pg_isready; do
echo "Waiting for DB ${PGUSER}@${PGHOST}:${PGPORT} to be up";
sleep 15;
done;
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: {{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 8080
protocol: TCP
- name: http-metrics
containerPort: 8081
protocol: TCP
{{- with .Values.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.resources }}
resources: {{- toYaml .Values.resources | nindent 12 }}
{{- else if ne .Values.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.resourcesPreset) | nindent 12 }}
{{- end }}
env:
- name: SPRING_DATASOURCE_URL
value: {{ include "hapi-fhir-jpaserver.database.jdbcUrl" $ }}
- name: SPRING_DATASOURCE_USERNAME
value: {{ include "hapi-fhir-jpaserver.database.user" $ }}
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "hapi-fhir-jpaserver.postgresql.secretName" . }}
key: {{ include "hapi-fhir-jpaserver.postgresql.secretKey" . }}
- name: SPRING_DATASOURCE_DRIVERCLASSNAME
value: org.postgresql.Driver
- name: spring.jpa.properties.hibernate.dialect
value: ca.uhn.fhir.jpa.model.dialect.HapiFhirPostgres94Dialect
- name: HAPI_FHIR_USE_APACHE_ADDRESS_STRATEGY
value: "true"
- name: MANAGEMENT_ENDPOINT_HEALTH_PROBES_ADD_ADDITIONAL_PATHS
value: "true"
- name: MANAGEMENT_SERVER_PORT
value: "8081"
- name: MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE
value: "health,prometheus"
{{- if .Values.extraConfig }}
- name: SPRING_CONFIG_IMPORT
value: "/app/config/application-extra.yaml"
{{- end }}
{{- if .Values.extraEnv }}
{{ toYaml .Values.extraEnv | nindent 12 }}
{{- end }}
volumeMounts:
- mountPath: /tmp
name: tmp-volume
- mountPath: /app/target
name: lucenefiles-volume
{{- if .Values.extraConfig }}
- name: application-extra-config
mountPath: /app/config/application-extra.yaml
readOnly: true
subPath: application-extra.yaml
{{- end }}
{{- if .Values.extraVolumeMounts }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: tmp-volume
emptyDir: {}
- name: lucenefiles-volume
emptyDir: {}
{{- if .Values.extraConfig }}
- name: application-extra-config
configMap:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}-application-config
{{- end }}
{{- if .Values.extraVolumes }}
{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,11 @@
{{- if and (not .Values.postgresql.enabled) (not .Values.externalDatabase.existingSecret) (not .Values.postgresql.auth.existingSecret) }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}-external-db
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
type: Opaque
data:
postgres-password: {{ .Values.externalDatabase.password | b64enc | quote }}
{{- end }}

View File

@ -0,0 +1,53 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "hapi-fhir-jpaserver.fullname" . -}}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }}
apiVersion: networking.k8s.io/v1beta1
{{ else }}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
{{- $pathType := .pathType }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
pathType: {{ $pathType | default "ImplementationSpecific" }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
name: http
{{ else }}
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,18 @@
{{- if .Values.podDisruptionBudget.enabled }}
kind: PodDisruptionBudget
apiVersion: policy/v1
metadata:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
spec:
{{- if .Values.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
{{- end }}
{{- if .Values.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
{{- end }}
selector:
matchLabels:
{{- include "hapi-fhir-jpaserver.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
- port: {{ .Values.metrics.service.port }}
targetPort: http-metrics
protocol: TCP
name: http-metrics
selector:
{{- include "hapi-fhir-jpaserver.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "hapi-fhir-jpaserver.serviceAccountName" . }}
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}

View File

@ -0,0 +1,30 @@
{{- if .Values.metrics.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "hapi-fhir-jpaserver.fullname" . }}
{{- if .Values.metrics.serviceMonitor.namespace }}
namespace: {{ .Values.metrics.serviceMonitor.namespace }}
{{- end }}
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
{{- if .Values.metrics.serviceMonitor.additionalLabels }}
{{- toYaml .Values.metrics.serviceMonitor.additionalLabels | nindent 4 }}
{{- end }}
spec:
endpoints:
- port: http-metrics
path: /actuator/prometheus
{{- if .Values.metrics.serviceMonitor.interval }}
interval: {{ .Values.metrics.serviceMonitor.interval }}
{{- end }}
{{- if .Values.metrics.serviceMonitor.scrapeTimeout }}
scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }}
{{- end }}
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
selector:
matchLabels:
{{- include "hapi-fhir-jpaserver.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@ -0,0 +1,73 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "hapi-fhir-jpaserver.fullname" . }}-test-endpoints"
labels:
{{- include "hapi-fhir-jpaserver.labels" . | nindent 4 }}
{{ include "hapi-fhir-jpaserver.fullname" . }}-client: "true"
app.kubernetes.io/component: tests
annotations:
"helm.sh/hook": test
spec:
restartPolicy: Never
automountServiceAccountToken: {{ .Values.tests.automountServiceAccountToken }}
securityContext:
{{- toYaml .Values.tests.podSecurityContext | nindent 4 }}
containers:
- name: test-metadata-endpoint
image: "{{ .Values.curl.image.registry }}/{{ .Values.curl.image.repository }}:{{ .Values.curl.image.tag }}"
command: ["curl", "--fail-with-body"]
args: ["http://{{ include "hapi-fhir-jpaserver.fullname" . }}:{{ .Values.service.port }}/fhir/metadata?_summary=true"]
{{- with .Values.restrictedContainerSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.tests.resources }}
resources: {{- toYaml .Values.tests.resources | nindent 10 }}
{{- else if ne .Values.tests.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.tests.resourcesPreset) | nindent 10 }}
{{- end }}
livenessProbe:
exec:
command: ["true"]
readinessProbe:
exec:
command: ["true"]
- name: test-patient-endpoint
image: "{{ .Values.curl.image.registry }}/{{ .Values.curl.image.repository }}:{{ .Values.curl.image.tag }}"
command: ["curl", "--fail-with-body"]
args: ["http://{{ include "hapi-fhir-jpaserver.fullname" . }}:{{ .Values.service.port }}/fhir/Patient?_count=1&_summary=true"]
{{- with .Values.restrictedContainerSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.tests.resources }}
resources: {{- toYaml .Values.tests.resources | nindent 10 }}
{{- else if ne .Values.tests.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.tests.resourcesPreset) | nindent 10 }}
{{- end }}
livenessProbe:
exec:
command: ["true"]
readinessProbe:
exec:
command: ["true"]
- name: test-metrics-endpoint
image: "{{ .Values.curl.image.registry }}/{{ .Values.curl.image.repository }}:{{ .Values.curl.image.tag }}"
command: ["curl", "--fail-with-body"]
args: ["http://{{ include "hapi-fhir-jpaserver.fullname" . }}:{{ .Values.metrics.service.port }}/actuator/prometheus"]
{{- with .Values.restrictedContainerSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.tests.resources }}
resources: {{- toYaml .Values.tests.resources | nindent 10 }}
{{- else if ne .Values.tests.resourcesPreset "none" }}
resources: {{- include "common.resources.preset" (dict "type" .Values.tests.resourcesPreset) | nindent 10 }}
{{- end }}
livenessProbe:
exec:
command: ["true"]
readinessProbe:
exec:
command: ["true"]

View File

@ -0,0 +1,302 @@
# -- number of replicas to deploy
replicaCount: 1
image:
# -- registry where the HAPI FHIR server image is hosted
registry: docker.io
# -- the path inside the repository
repository: hapiproject/hapi
# -- the image tag. As of v5.7.0, this is the `distroless` flavor by default, add `-tomcat` to use the Tomcat-based image.
tag: "v8.0.0-1@sha256:9fbac7b012b4be91ba481e7008f1353ede4598bc99a36f3902b8abf873e70ed8"
# -- image pullPolicy to use
pullPolicy: IfNotPresent
# -- image pull secrets to use when pulling the image
imagePullSecrets: []
# -- override the chart name
nameOverride: ""
# -- override the chart fullname
fullnameOverride: ""
# -- annotations applied to the server deployment
deploymentAnnotations: {}
# -- annotations applied to the server pod
podAnnotations: {}
# -- pod security context
podSecurityContext:
fsGroupChangePolicy: OnRootMismatch
runAsNonRoot: true
runAsGroup: 65532
runAsUser: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
privileged: false
seccompProfile:
type: RuntimeDefault
# service to expose the server
service:
# -- service type
type: ClusterIP
# -- port where the server will be exposed at
port: 8080
ingress:
# -- whether to create an Ingress to expose the FHIR server HTTP endpoint
enabled: false
# -- provide any additional annotations which may be required. Evaluated as a template.
annotations:
{}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: fhir-server.127.0.0.1.nip.io
pathType: ImplementationSpecific
paths: ["/"]
# -- ingress TLS config
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
# -- set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge).
# This is ignored if `resources` is set (`resources` is recommended for production).
# More information: <https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15>
resourcesPreset: "medium"
# -- configure the FHIR server's resource requests and limits
resources:
{}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# -- node selector for the pod
nodeSelector: {}
# -- pod tolerations
tolerations: []
# -- pod affinity
affinity: {}
# -- pod topology spread configuration
# see: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#api
topologySpreadConstraints:
[]
# - maxSkew: 1
# topologyKey: topology.kubernetes.io/zone
# whenUnsatisfiable: ScheduleAnyway
# labelSelector:
# matchLabels:
# app.kubernetes.io/instance: hapi-fhir-jpaserver
# app.kubernetes.io/name: hapi-fhir-jpaserver
postgresql:
# -- enable an included PostgreSQL DB.
# see <https://github.com/bitnami/charts/tree/master/bitnami/postgresql> for details
# if set to `false`, the values under `externalDatabase` are used
enabled: true
auth:
# -- name for a custom database to create
database: "fhir"
# -- Name of existing secret to use for PostgreSQL credentials
# `auth.postgresPassword`, `auth.password`, and `auth.replicationPassword` will be ignored and picked up from this secret
# The secret must contain the keys `postgres-password` (which is the password for "postgres" admin user),
# `password` (which is the password for the custom user to create when `auth.username` is set),
# and `replication-password` (which is the password for replication user).
# The secret might also contains the key `ldap-password` if LDAP is enabled. `ldap.bind_password` will be ignored and
# picked from this secret in this case.
# The value is evaluated as a template.
existingSecret: ""
# -- readiness probe
# @ignored
readinessProbe:
httpGet:
path: /readyz
port: http
failureThreshold: 5
initialDelaySeconds: 30
periodSeconds: 20
successThreshold: 1
timeoutSeconds: 20
# -- liveness probe
# @ignored
livenessProbe:
httpGet:
path: /livez
port: http
failureThreshold: 5
initialDelaySeconds: 30
periodSeconds: 20
successThreshold: 1
timeoutSeconds: 30
# -- startup probe
# @ignored
startupProbe:
httpGet:
path: /readyz
port: http
failureThreshold: 10
initialDelaySeconds: 30
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 30
externalDatabase:
# -- external database host used with `postgresql.enabled=false`
host: localhost
# -- database port number
port: 5432
# -- username for the external database
user: fhir
# -- database password
password: ""
# -- name of an existing secret resource containing the DB password in the `existingSecretKey` key
existingSecret: ""
# -- name of the key inside the `existingSecret`
existingSecretKey: "postgresql-password"
# -- database name
database: fhir
# -- extra environment variables to set on the server container
extraEnv:
[]
# - name: SPRING_FLYWAY_BASELINE_ON_MIGRATE
# value: "true"
podDisruptionBudget:
# -- Enable PodDisruptionBudget for the server pods.
# uses policy/v1/PodDisruptionBudget thus requiring k8s 1.21+
enabled: false
# -- minimum available instances
minAvailable: 1
# -- maximum unavailable instances
maxUnavailable: ""
serviceAccount:
# -- Specifies whether a service account should be created.
create: false
# -- Annotations to add to the service account
annotations: {}
# -- The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
# -- Automatically mount a ServiceAccount's API credentials?
automount: true
metrics:
serviceMonitor:
# -- if enabled, creates a ServiceMonitor instance for Prometheus Operator-based monitoring
enabled: false
# -- additional labels to apply to the ServiceMonitor object, e.g. `release: prometheus`
additionalLabels: {}
# namespace: monitoring
# interval: 30s
# scrapeTimeout: 10s
service:
port: 8081
# @ignore
restrictedContainerSecurityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
privileged: false
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
seccompProfile:
type: RuntimeDefault
# @ignored
curl:
image:
registry: docker.io
repository: curlimages/curl
tag: 8.12.1@sha256:94e9e444bcba979c2ea12e27ae39bee4cd10bc7041a472c4727a558e213744e6
tests:
# -- whether the service account token should be auto-mounted for the test pods
automountServiceAccountToken: false
# -- set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge).
# This is ignored if `resources` is set (`resources` is recommended for production).
# More information: <https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15>
resourcesPreset: "nano"
# -- configure the test pods resource requests and limits
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# @ignored
podSecurityContext:
fsGroupChangePolicy: OnRootMismatch
runAsNonRoot: true
runAsGroup: 65532
runAsUser: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
initContainers:
# -- set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge).
# This is ignored if `resources` is set (`resources` is recommended for production).
# More information: <https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15>
resourcesPreset: "nano"
# -- configure the init containers pods resource requests and limits
resources: {}
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# -- additional Spring Boot application config. Mounted as a file and automatically loaded by the application.
extraConfig:
""
# # For example:
# |
# hapi:
# fhir:
# implementationguides:
# gh_0_1_0:
# url: https://build.fhir.org/ig/hl7-eu/gravitate-health/package.tgz
# name: hl7.eu.fhir.gh
# version: 0.1.0
# -- Optionally specify extra list of additional volumes
extraVolumes: []
# -- Optionally specify extra list of additional volumeMounts
extraVolumeMounts: []

View File

@ -0,0 +1,3 @@
<p>
Greetings from the custom web app page!
</p>

View File

@ -0,0 +1,14 @@
<p>
<b>This is a custom about page! It means you have configured 'custom_content_path: ./custom' in the application.yaml</b>
</p>
<p>
This server provides a complete implementation of the FHIR Specification
using a 100% open source software stack.
</p>
<p>
This server is built
from a number of modules of the
<a href="https://github.com/hapifhir/hapi-fhir/">HAPI FHIR</a>
project, which is a 100% open-source (Apache 2.0 Licensed) Java based
implementation of the FHIR specification.
</p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -0,0 +1,14 @@
<p>
<b>This is a custom welcome page! It means you have configured 'custom_content_path: ./custom' in the application.yaml</b>
</p>
<p>
This server provides a complete implementation of the FHIR Specification
using a 100% open source software stack.
</p>
<p>
This server is built
from a number of modules of the
<a href="https://github.com/hapifhir/hapi-fhir/">HAPI FHIR</a>
project, which is a 100% open-source (Apache 2.0 Licensed) Java based
implementation of the FHIR specification.
</p>