From 456712ea65ef32972e4cf4d70d9a31f3e69e26bf Mon Sep 17 00:00:00 2001 From: Brian Stansberry Date: Mon, 7 Oct 2024 15:45:08 -0500 Subject: [PATCH] [WFLY-21081] Add a quickstart showing Jakarta Data --- .../quickstart_todo-jakarta-data_ci.yml | 17 + .../quickstart_todo-jakarta-data_ci_before.sh | 2 + .../qs-overrides/todo-jakarta-data/ci.yaml | 16 + .../overridable-functions.sh | 39 + pom.xml | 1 + todo-jakarta-data/README-source.adoc | 282 +++ todo-jakarta-data/README.adoc | 1662 +++++++++++++++++ .../additional-readme-cloud.adoc | 70 + .../additional-readme-kubernetes.adoc | 4 + .../additional-readme-openshift.adoc | 4 + todo-jakarta-data/charts/.helmignore | 23 + todo-jakarta-data/charts/Chart.yaml | 9 + .../charts/templates/postgres-configmap.yaml | 11 + .../charts/templates/postgres.yaml | 40 + todo-jakarta-data/charts/values.yaml | 50 + .../helm-install-prerequisites.adoc | 19 + todo-jakarta-data/pom.xml | 289 +++ .../org/wildfly/quickstarts/todos/ToDo.java | 143 ++ .../todos/ToDoBackendApplication.java | 29 + .../quickstarts/todos/ToDoController.java | 104 ++ .../quickstarts/todos/ToDoRepository.java | 58 + .../main/resources/META-INF/persistence.xml | 31 + .../src/main/scripts/cors_filters.cli | 16 + .../src/main/webapp/WEB-INF/beans.xml | 10 + .../quickstarts/todos/RemoteToDoIT.java | 91 + 25 files changed, 3020 insertions(+) create mode 100644 .github/workflows/quickstart_todo-jakarta-data_ci.yml create mode 100644 .github/workflows/quickstart_todo-jakarta-data_ci_before.sh create mode 100644 .github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/ci.yaml create mode 100644 .github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/overridable-functions.sh create mode 100644 todo-jakarta-data/README-source.adoc create mode 100644 todo-jakarta-data/README.adoc create mode 100644 todo-jakarta-data/additional-readme-cloud.adoc create mode 100644 todo-jakarta-data/additional-readme-kubernetes.adoc create mode 100644 todo-jakarta-data/additional-readme-openshift.adoc create mode 100644 todo-jakarta-data/charts/.helmignore create mode 100644 todo-jakarta-data/charts/Chart.yaml create mode 100644 todo-jakarta-data/charts/templates/postgres-configmap.yaml create mode 100644 todo-jakarta-data/charts/templates/postgres.yaml create mode 100644 todo-jakarta-data/charts/values.yaml create mode 100644 todo-jakarta-data/helm-install-prerequisites.adoc create mode 100644 todo-jakarta-data/pom.xml create mode 100644 todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDo.java create mode 100644 todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java create mode 100644 todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java create mode 100644 todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoRepository.java create mode 100644 todo-jakarta-data/src/main/resources/META-INF/persistence.xml create mode 100644 todo-jakarta-data/src/main/scripts/cors_filters.cli create mode 100644 todo-jakarta-data/src/main/webapp/WEB-INF/beans.xml create mode 100644 todo-jakarta-data/src/test/java/org/wildfly/quickstarts/todos/RemoteToDoIT.java diff --git a/.github/workflows/quickstart_todo-jakarta-data_ci.yml b/.github/workflows/quickstart_todo-jakarta-data_ci.yml new file mode 100644 index 0000000000..7a158b3d2e --- /dev/null +++ b/.github/workflows/quickstart_todo-jakarta-data_ci.yml @@ -0,0 +1,17 @@ +name: WildFly todo-jakarta-data Quickstart CI + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + paths: + - 'todo-jakarta-data/**' + - '.github/workflows/quickstart_ci.yml' +jobs: + call-quickstart_ci: + uses: ./.github/workflows/quickstart_ci.yml + with: + QUICKSTART_PATH: todo-jakarta-data + TEST_PROVISIONED_SERVER: true + TEST_OPENSHIFT: true + MATRIX_OS: '"ubuntu-latest"' + EXTRA_RUN_ARGS: '-DPOSTGRESQL_DATABASE=todos -DPOSTGRESQL_SERVICE_HOST=localhost -DPOSTGRESQL_SERVICE_PORT=5432 -DPOSTGRESQL_USER=todos -DPOSTGRESQL_PASSWORD=mysecretpassword -DPOSTGRESQL_DATASOURCE=ToDos' diff --git a/.github/workflows/quickstart_todo-jakarta-data_ci_before.sh b/.github/workflows/quickstart_todo-jakarta-data_ci_before.sh new file mode 100644 index 0000000000..8fdfa0aeb6 --- /dev/null +++ b/.github/workflows/quickstart_todo-jakarta-data_ci_before.sh @@ -0,0 +1,2 @@ +#!/bin/sh +docker run --name todo-jakarta-data-db -e POSTGRES_USER=todos -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres diff --git a/.github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/ci.yaml b/.github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/ci.yaml new file mode 100644 index 0000000000..533c91fde1 --- /dev/null +++ b/.github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/ci.yaml @@ -0,0 +1,16 @@ +postgresql: + primary: + podSecurityContext: + enabled: true + fsGroup: 1001 + containerSecurityContext: + enabled: true + runAsUser: 1001 + runAsGroup: 0 + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL \ No newline at end of file diff --git a/.github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/overridable-functions.sh b/.github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/overridable-functions.sh new file mode 100644 index 0000000000..855e2ee216 --- /dev/null +++ b/.github/workflows/scripts/kubernetes/qs-overrides/todo-jakarta-data/overridable-functions.sh @@ -0,0 +1,39 @@ +function installPrerequisites() +{ + echo "Adding bitnami repository" + helm repo add bitnami https://charts.bitnami.com/bitnami + + helm dependency update charts/ +} + +function helmInstall() { + application="${1}" + helm_set_arguments="$2" + + # TODO https://issues.redhat.com/browse/WFLY-18574 remove this when persistence is working + helm_set_arguments="${helm_set_arguments} -f ../.ci/openshift-ci/build-root/scripts/qs-overrides/todo-jakarta-data/ci.yaml" + + helm install "${application}" charts/ --wait --timeout="${helm_install_timeout}" ${helm_set_arguments} + echo $? +} + + + +function cleanPrerequisites() +{ + helm uninstall "${application}" + helm repo remove bitnami +} + +function getHelmSetVariablePrefix() { + echo "wildfly." +} + +function helmInstallFailed() { + echo "----> Getting status of all pods" + kubectl get pods + echo "----> Checking logs for postgres pod" + kubectl logs todo-jakarta-data-postgresql-0 + echo "----> Checking events" + kubectl get events +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 71e8226f91..fd4fa8495b 100644 --- a/pom.xml +++ b/pom.xml @@ -287,6 +287,7 @@ tasks-jsf temperature-converter todo-backend + todo-jakarta-data thread-racing websocket-endpoint websocket-hello diff --git a/todo-jakarta-data/README-source.adoc b/todo-jakarta-data/README-source.adoc new file mode 100644 index 0000000000..4526ff37b5 --- /dev/null +++ b/todo-jakarta-data/README-source.adoc @@ -0,0 +1,282 @@ +include::../shared-doc/attributes.adoc[] + += todo-jakata-data: quickstart for backend deployment on OpenShift +:toc: left +:icons: font +:idprefix: +:idseparator: - +:keywords: openshift,galleon,helm +:level: Intermediate +:technologies: Jakarta Data, Jakarta REST, OpenShift, Galleon +:openshift: true +:archiveType: war +:useHelmChartDir: true +:helm-install-prerequisites-openshift: ../todo-backend/helm-install-prerequisites.adoc +:helm-install-prerequisites-kubernetes: ../todo-backend/helm-install-prerequisites.adoc +:helmSetWildFlyArgumentPrefix: wildfly. + +[abstract] +The `todo-jakarta-data` quickstart demonstrates how to implement a backend that exposes a HTTP API with Jakarta REST +to manage a list of ToDo which are persisted in a database with Jakarta Data. +It is very similar to the `todo-backend` quickstart but uses Jakarta Data instead of Jakarta Persistence to handle +interaction with the backend database. + +ifndef::ProductRelease[] +This quickstart shows how to set up a local deployment of this backend as well as a deployment on OpenShift to connect +to a PostgreSQL database also hosted on OpenShift. +endif::[] +ifdef::ProductRelease[] +This quickstart shows how to deploy a {productName} application on OpenShift that connects +to a PostgreSQL database also hosted on OpenShift. +endif::[] + + +== What is it? + +The `todo-jakarta-data` quickstart demonstrates how to implement a backend that exposes a HTTP API with `Jakarta REST` +to manage a list of ToDo which are persisted in a database with `Jakarta Data`. + +* The backend exposes a HTTP API to manage a list of todos that complies with the specs defined at https://todobackend.com/specs/index.html[todobackend.com]. +* It requires a connection to a PostgreSQL database to persist the todos. +ifndef::ProductRelease[] +* It uses the Server Provisioning for local and cloud deployment +endif::[] +* It can be build with {productName} S2I images for cloud deployment +ifndef::ProductRelease[] +* It is deployed on OpenShift using the https://docs.wildfly.org/wildfly-charts/[Helm Chart for {productName}]. +endif::[] +ifdef::ProductRelease[] +* It is deployed on OpenShift using the https://jbossas.github.io/eap-charts//[Helm Chart for {productName}]. +endif::[] + +This quickstart is the same as the `todo-backend` quickstart, but uses `Jakarta Data` for its persistence layer, +instead of `Jakarta Persistence`. +To see the differences, compare this quickstart's `ToDoRepository` interface with the `ToDoDAO` interface +and `ToDoDAOImpl` class in `todo-backend`. + +// Link to the quickstart source +include::../shared-doc/view-the-source.adoc[leveloffset=+1] +// System Requirements +include::../shared-doc/system-requirements.adoc[leveloffset=+1] + +== Architecture + +=== Architecture with S2I + +This backend is built using {productName} S2I Builder and Runtime images. + +ifndef::ProductRelease[] +When the image is built, `org.wildfly.plugins:wildfly-maven-plugin` plugin provisions the {productName} application server and all the feature packs it needs for its features. +The layers are defined in the `pom.xml` file in the `` section of the `org.wildfly.plugins:wildfly-maven-plugin` plugin: + +[source,xml] +---- + + cloud-server + jakarta-data + postgresql-datasource + +---- +endif::[] + +ifdef::ProductRelease[] +When the image is built, `org.jboss.eap.plugins:eap-maven-plugin` plugin provisions the {productName} application server and all the feature packs it needs for its features. +The layers are defined in the `pom.xml` file in the `` section of the `org.jboss.eap.plugins:eap-maven-plugin` plugin: + +[source,xml] +---- + + cloud-server + jakarta-data + postgresql-datasource + +---- +endif::[] + +The `cloud-server` layer provides everything needed to run the backend on OpenShift. This also includes access to +Jakarta EE APIs such as CDI, Jakarta REST, etc, along with the Hibernate support used by Jakarta Data. +The `jakarta-data` layer provides the Jakarta Data API. +These two layers come from the {productName} feature pack provided in the +{productName} S2I builder image. + +ifndef::ProductRelease[] +The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is also provided by +`org.wildfly:wildfly-datasources-galleon-pack` which is included in the WildFly S2I image. + +The Git repository for this feature pack is hosted at https://github.com/wildfly-extras/wildfly-datasources-galleon-pack. +It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`. +endif::[] + +ifdef::ProductRelease[] +The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is also provided by +the `org.jboss.eap:eap-datasources-galleon-pack` feature pack. + +The Git repository for this feature pack is hosted at https://github.com/jbossas/eap-datasources-galleon-pack. +It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`. +endif::[] + +=== Generation of the Jakarta Data Repository implementation + +A key feature of Jakarta Data is it does not require application developers to write detailed code to write from and write to the backend database. +Developers just need declare their entities (using Jakarta Persistence annotations like `@Entity`) and then write an repository interface that describes the desired persistence operations, using the Jakarta Data annotations. +It is then up to the Jakarta Data implementation to generate an implementation of that interface. + +WildFly's implementation of Jakarta Data, Hibernate Data Repositories, generates that implementation at application build time using an annotation processor run as part of compilation of the application. + +This is handled in the project `pom.xml` by configuring the `maven-compiler-plugin`: + +[source,xml] +---- + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.hibernate.orm + hibernate-jpamodelgen + ${version.org.hibernate.jpamodelgen} + + + + +---- + +=== Connection to the PostgreSQL database + +ifndef::ProductRelease[] +As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database +is provided by the `org.wildfly:wildfly-datasources-galleon-pack` feature pack. +endif::[] +ifdef::ProductRelease[] +As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database +is provided by the `org.jboss.eap:eap-datasources-galleon-pack` feature pack. +endif::[] + +By default, it exposes a single datasource. +In the backend, the name of this datasource is `ToDos` and is specified in the `persistence.xml` to configure Hibernate: + +[source,xml] +---- + + java:jboss/datasources/ToDos + +---- + +At runtime, we only need a few environment variables to establish the connection from {productName} to the external PostgreSQL database: + +* `POSTGRESQL_DATABASE` - the name of the database (that will be called `todos`) +* `POSTGRESQL_SERVICE_HOST` - the host to connect to the database +* `POSTGRESQL_SERVICE_PORT` - The port to connect to the database +* `POSTGRESQL_USER` & `POSTGRESQL_PASSWORD` - the credentials to connect to the database +* `POSTGRESQL_DATASOURCE` - The name of the datasource (as mentioned above, it will be `ToDos`) + +=== Filters for Cross-Origin Resource Sharing (CORS) + +The Web frontend for this quickstart uses JavaScript calls to query the backend's HTTP API. +We must enable Cross-Origin Resource Sharing (CORS) filters in the `undertow` subsystem of {productName} to allow +these HTTP requests to succeed. + +ifdef::ProductRelease[] +==== Configuration with {productName} S2I + +As we use S2I to provision the server and build the application, we provide a CLI script that contains all the commands to create and configure the CORS filters in Undertow. This script is located in the `src/scripts/cors_filters.cli`. +endif::[] + +This script is executed at build time and will provide the following HTTP headers to enabled CORS: + +* `Access-Control-Allow-Origin: *` +* `Access-Control-Allow-Methods: GET, POST, OPTION, PUT, DELETE, PATCH` +* `Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with` +* `Access-Control-Allow-Credentials: true` +* `Access-Control-Max-Age: 1` + +By default, the backend accepts requests from any origin (`*`). This is only simplicity. It is possible to restrict +the allowed origin using the environment variable `CORS_ORIGIN` at runtime. + +== Run the Backend Locally + +=== Package the Backend + +The backend is packaged and deployed on a provisioned server: + +[source,options="nowrap"] +---- +$ mvn clean package +---- + +=== Run a Local PostgreSQL Database + +Before running the backend locally, we need to have a local PostgreSQL database that we can connect to. +We use the `postgresql` docker image to create one: + +[source,options="nowrap"] +---- +$ docker run --name todo-backend-db -e POSTGRES_USER=todos -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 postgres +---- + +This will create a database named `todos` that we can connect to on `localhost:5432` with the credentials `todos / mysecretpassword`. + +=== Run the Application + +With the PostgreSQL database running, we can start the backend by passing the required environment variables to connect to the database: + +[source,options="nowrap"] +---- +$ ./target/server/bin/standalone.sh -Denv.POSTGRESQL_DATABASE=todos -Denv.POSTGRESQL_DATASOURCE=ToDos -Denv.POSTGRESQL_SERVICE_HOST=localhost -Denv.POSTGRESQL_SERVICE_PORT=5432 -Denv.POSTGRESQL_USER=todos -Denv.POSTGRESQL_PASSWORD=mysecretpassword +---- + +The backend is running, and we can use the HTTP API to manage a list of todos: + +[source,options="nowrap"] +---- +# get a list of todos +$ curl http://localhost:8080/todo-jakarta-data +[] + +# create a todo with the title "This is my first todo item!" +$ curl -X POST -H "Content-Type: application/json" -d '{"title": "This is my first todo item!"}' http://localhost:8080 +{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}% + +# get a list of todos with the one that was just created +$ curl http://localhost:8080/todo-jakarta-data +[{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}] +---- + +Please note that the quickstart includes integration tests, which may be executed using the following command: + +[source,subs="attributes+",options="nowrap"] +---- +$ mvn verify -Pintegration-testing +---- + +//=========================================================== +// Openshift - START +== Run the Backend on OpenShift + +// OpenShift +include::../shared-doc/build-and-run-the-quickstart-with-openshift.adoc[leveloffset=+1] +include::../todo-backend/additional-readme-openshift.adoc[leveloffset=+1] +// OpenShift - END +//=========================================================== + +//=========================================================== +// Kubernetes - START +ifndef::ProductRelease,EAPXPRelease[] +== Run the Backend on Kubernetes + +//Kubernetes +include::../shared-doc/build-and-run-the-quickstart-with-kubernetes.adoc[leveloffset=+1] +include::../todo-backend/additional-readme-kubernetes.adoc[leveloffset=+1] +endif::[] +// Kubernetes - END +//=========================================================== + + +== Conclusion + +This quickstart shows how the datasource feature pack provided by {productName} simplifies the deployment +of a {productName} Jakarta EE backend on OpenShift to connect to an external database and exposes an HTTP API. + +The use of a Server Provisioned deployment makes it seamless to move from a local deployment for development to a +deployment on cloud platforms such as OpenShift and Kubernetes. \ No newline at end of file diff --git a/todo-jakarta-data/README.adoc b/todo-jakarta-data/README.adoc new file mode 100644 index 0000000000..a8e01ae711 --- /dev/null +++ b/todo-jakarta-data/README.adoc @@ -0,0 +1,1662 @@ +ifdef::env-github[] +:artifactId: todo-backend +endif::[] + +//*********************************************************************************** +// Enable the following flag to build README.html files for JBoss EAP product builds. +// Comment it out for WildFly builds. +//*********************************************************************************** +//:ProductRelease: + +//*********************************************************************************** +// Enable the following flag to build README.html files for EAP XP product builds. +// Comment it out for WildFly or JBoss EAP product builds. +//*********************************************************************************** +//:EAPXPRelease: + +// This is a universal name for all releases +:ProductShortName: JBoss EAP +// Product names and links are dependent on whether it is a product release (CD or JBoss) +// or the WildFly project. +// The "DocInfo*" attributes are used to build the book links to the product documentation + +ifdef::ProductRelease[] +// JBoss EAP release +:productName: JBoss EAP +:productNameFull: Red Hat JBoss Enterprise Application Platform +:productVersion: 8.0 +:DocInfoProductNumber: {productVersion} +:WildFlyQuickStartRepoTag: 8.0.x +:productImageVersion: 8.0.0 +:helmChartName: jboss-eap/eap8 +endif::[] + +ifdef::EAPXPRelease[] +// JBoss EAP XP release +:productName: JBoss EAP XP +:productNameFull: Red Hat JBoss Enterprise Application Platform expansion pack +:productVersion: 3.0 +:DocInfoProductNumber: 7.4 +:WildFlyQuickStartRepoTag: XP_3.0.0.GA +:productImageVersion: 3.0 +:helmChartName: jboss-eap/eap-xp3 +endif::[] + +ifdef::ProductRelease,EAPXPRelease[] +:githubRepoUrl: https://github.com/jboss-developer/jboss-eap-quickstarts/ +:githubRepoCodeUrl: https://github.com/jboss-developer/jboss-eap-quickstarts.git +:jbossHomeName: EAP_HOME +:DocInfoProductName: Red Hat JBoss Enterprise Application Platform +:DocInfoProductNameURL: red_hat_jboss_enterprise_application_platform +:DocInfoPreviousProductName: jboss-enterprise-application-platform +:quickstartDownloadName: {productNameFull} {productVersion} Quickstarts +:quickstartDownloadUrl: https://access.redhat.com/jbossnetwork/restricted/listSoftware.html?product=appplatform&downloadType=distributions +:helmRepoName: jboss-eap +:helmRepoUrl: https://jbossas.github.io/eap-charts/ +// END ifdef::ProductRelease,EAPXPRelease[] +endif::[] + +ifndef::ProductRelease,EAPXPRelease[] +// WildFly project +:productName: WildFly +:productNameFull: WildFly Application Server +:ProductShortName: {productName} +:jbossHomeName: WILDFLY_HOME +:productVersion: 34 +:productImageVersion: 34.0 +:githubRepoUrl: https://github.com/wildfly/quickstart/ +:githubRepoCodeUrl: https://github.com/wildfly/quickstart.git +:WildFlyQuickStartRepoTag: 34.0.0.Beta1 +:DocInfoProductName: Red Hat JBoss Enterprise Application Platform +:DocInfoProductNameURL: red_hat_jboss_enterprise_application_platform +:DocInfoProductNumber: 8.0 +:DocInfoPreviousProductName: jboss-enterprise-application-platform +:helmRepoName: wildfly +:helmRepoUrl: http://docs.wildfly.org/wildfly-charts/ +:helmChartName: wildfly/wildfly +// END ifndef::ProductRelease,EAPCDRelease,EAPXPRelease[] +endif::[] + +:source: {githubRepoUrl} + +// Values for Openshift S2i sections attributes +:CDProductName: {productNameFull} for OpenShift +:CDProductShortName: {ProductShortName} for OpenShift +:CDProductTitle: {CDProductName} +:CDProductNameSentence: Openshift release for {ProductShortName} +:CDProductAcronym: {CDProductShortName} +:CDProductVersion: {productVersion} +:EapForOpenshiftBookName: {productNameFull} for OpenShift +:EapForOpenshiftOnlineBookName: {EapForOpenshiftBookName} Online +:xpaasproduct: {productNameFull} for OpenShift +:xpaasproductOpenShiftOnline: {xpaasproduct} Online +:xpaasproduct-shortname: {CDProductShortName} +:xpaasproductOpenShiftOnline-shortname: {xpaasproduct-shortname} Online +:ContainerRegistryName: Red Hat Container Registry +:EapForOpenshiftBookName: Getting Started with {ProductShortName} for OpenShift Container Platform +:EapForOpenshiftOnlineBookName: Getting Started with {ProductShortName} for OpenShift Online +:OpenShiftOnlinePlatformName: Red Hat OpenShift Container Platform +:OpenShiftOnlineName: Red Hat OpenShift Online +:ImagePrefixVersion: eap80 +:ImageandTemplateImportBaseURL: https://raw.githubusercontent.com/jboss-container-images/jboss-eap-openshift-templates +:ImageandTemplateImportURL: {ImageandTemplateImportBaseURL}/{ImagePrefixVersion}/ +:BuildImageStream: jboss-{ImagePrefixVersion}-openjdk11-openshift +:RuntimeImageStream: jboss-{ImagePrefixVersion}-openjdk11-runtime-openshift + +// OpenShift repository and reference for quickstarts +:EAPQuickStartRepo: https://github.com/jboss-developer/jboss-eap-quickstarts +:EAPQuickStartRepoRef: 8.0.x +:EAPQuickStartRepoTag: EAP_8.0.0.GA +// Links to the OpenShift documentation +:LinkOpenShiftGuide: https://access.redhat.com/documentation/en-us/{DocInfoProductNameURL}/{DocInfoProductNumber}/html-single/getting_started_with_jboss_eap_for_openshift_container_platform/ +:LinkOpenShiftOnlineGuide: https://access.redhat.com/documentation/en-us/{DocInfoProductNameURL}/{DocInfoProductNumber}/html-single/getting_started_with_jboss_eap_for_openshift_online/ + +ifdef::EAPXPRelease[] +// Attributes for XP releases +:EapForOpenshiftBookName: {productNameFull} for OpenShift +:EapForOpenshiftOnlineBookName: {productNameFull} for OpenShift Online +:xpaasproduct: {productNameFull} for OpenShift +:xpaasproductOpenShiftOnline: {productNameFull} for OpenShift Online +:xpaasproduct-shortname: {ProductShortName} for OpenShift +:xpaasproductOpenShiftOnline-shortname: {ProductShortName} for OpenShift Online +:ContainerRegistryName: Red Hat Container Registry +:EapForOpenshiftBookName: {productNameFull} for OpenShift +:EapForOpenshiftOnlineBookName: {productNameFull} for OpenShift Online +:ImagePrefixVersion: eap-xp3 +:ImageandTemplateImportURL: {ImageandTemplateImportBaseURL}/{ImagePrefixVersion}/ +:BuildImageStream: jboss-{ImagePrefixVersion}-openjdk11-openshift +:RuntimeImageStream: jboss-{ImagePrefixVersion}-openjdk11-runtime-openshift +// OpenShift repository and reference for quickstarts +:EAPQuickStartRepoRef: xp-3.0.x +// Links to the OpenShift documentation +:LinkOpenShiftGuide: https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/{DocInfoProductNumber}/html/using_eclipse_microprofile_in_jboss_eap/using-the-openshift-image-for-jboss-eap-xp_default +:LinkOpenShiftOnlineGuide: https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/{DocInfoProductNumber}/html/using_eclipse_microprofile_in_jboss_eap/using-the-openshift-image-for-jboss-eap-xp_default +endif::[] + +ifndef::ProductRelease,EAPCDRelease,EAPXPRelease[] +:ImageandTemplateImportURL: https://raw.githubusercontent.com/wildfly/wildfly-s2i/v{productVersion}.0/ +endif::[] + +//************************* +// Other values +//************************* +:buildRequirements: Java 11.0 (Java SDK 11) or later and Maven 3.6.0 or later +:jbdsEapServerName: Red Hat JBoss Enterprise Application Platform 7.3 +:javaVersion: Jakarta EE 10 +ifdef::EAPXPRelease[] +:javaVersion: Eclipse MicroProfile +endif::[] +:githubRepoBranch: master +:guidesBaseUrl: https://github.com/jboss-developer/jboss-developer-shared-resources/blob/master/guides/ +:useEclipseUrl: {guidesBaseUrl}USE_JBDS.adoc#use_red_hat_jboss_developer_studio_or_eclipse_to_run_the_quickstarts +:useEclipseDeployJavaClientDocUrl: {guidesBaseUrl}USE_JBDS.adoc#deploy_and_undeploy_a_quickstart_containing_server_and_java_client_projects +:useEclipseDeployEARDocUrl: {guidesBaseUrl}USE_JBDS.adoc#deploy_and_undeploy_a_quickstart_ear_project +:useProductHomeDocUrl: {guidesBaseUrl}USE_OF_{jbossHomeName}.adoc#use_of_product_home_and_jboss_home_variables +:configureMavenDocUrl: {guidesBaseUrl}CONFIGURE_MAVEN_JBOSS_EAP.adoc#configure_maven_to_build_and_deploy_the_quickstarts +:addUserDocUrl: {guidesBaseUrl}CREATE_USERS.adoc#create_users_required_by_the_quickstarts +:addApplicationUserDocUrl: {guidesBaseUrl}CREATE_USERS.adoc#add_an_application_user +:addManagementUserDocUrl: {guidesBaseUrl}CREATE_USERS.adoc#add_an_management_user +:startServerDocUrl: {guidesBaseUrl}START_JBOSS_EAP.adoc#start_the_jboss_eap_server +:configurePostgresDocUrl: {guidesBaseUrl}CONFIGURE_POSTGRESQL_JBOSS_EAP.adoc#configure_the_postgresql_database_for_use_with_the_quickstarts +:configurePostgresDownloadDocUrl: {guidesBaseUrl}CONFIGURE_POSTGRESQL_JBOSS_EAP.adoc#download_and_install_postgresql +:configurePostgresCreateUserDocUrl: {guidesBaseUrl}CONFIGURE_POSTGRESQL_JBOSS_EAP.adoc#create_a_database_user +:configurePostgresAddModuleDocUrl: {guidesBaseUrl}CONFIGURE_POSTGRESQL_JBOSS_EAP.adoc#add_the_postgres_module_to_the_jboss_eap_server +:configurePostgresDriverDocUrl: {guidesBaseUrl}CONFIGURE_POSTGRESQL_JBOSS_EAP.adoc#configure_the_postgresql_driver_in_the_jboss_eap_server +:configureBytemanDownloadDocUrl: {guidesBaseUrl}CONFIGURE_BYTEMAN.adoc#download_and_configure_byteman +:configureBytemanDisableDocUrl: {guidesBaseUrl}CONFIGURE_BYTEMAN.adoc#disable_the_byteman_script +:configureBytemanClearDocUrl: {guidesBaseUrl}CONFIGURE_BYTEMAN.adoc#clear_the_transaction_object_store +:configureBytemanQuickstartDocUrl: {guidesBaseUrl}CONFIGURE_BYTEMAN.adoc#configure_byteman_for_use_with_the_quickstarts +:configureBytemanHaltDocUrl: {guidesBaseUrl}CONFIGURE_BYTEMAN.adoc#use_byteman_to_halt_the_application[ +:configureBytemanQuickstartsDocUrl: {guidesBaseUrl}CONFIGURE_BYTEMAN.adoc#configure_byteman_for_use_with_the_quickstarts + +:EESubsystemNamespace: urn:jboss:domain:ee:4.0 +:IiopOpenJdkSubsystemNamespace: urn:jboss:domain:iiop-openjdk:2.0 +:MailSubsystemNamespace: urn:jboss:domain:mail:3.0 +:SingletonSubsystemNamespace: urn:jboss:domain:singleton:1.0 +:TransactionsSubsystemNamespace: urn:jboss:domain:transactions:4.0 + +// LinkProductDocHome: https://access.redhat.com/documentation/en/red-hat-jboss-enterprise-application-platform/ +:LinkProductDocHome: https://access.redhat.com/documentation/en/jboss-enterprise-application-platform-continuous-delivery +:LinkConfigGuide: https://access.redhat.com/documentation/en-us/{DocInfoProductNameURL}/{DocInfoProductNumber}/html-single/configuration_guide/ +:LinkDevelopmentGuide: https://access.redhat.com/documentation/en-us/{DocInfoProductNameURL}/{DocInfoProductNumber}/html-single/development_guide/ +:LinkGettingStartedGuide: https://access.redhat.com/documentation/en-us/{DocInfoProductNameURL}/{DocInfoProductNumber}/html-single/getting_started_guide/ +:LinkOpenShiftWelcome: https://docs.openshift.com/online/welcome/index.html +:LinkOpenShiftSignup: https://docs.openshift.com/online/getting_started/choose_a_plan.html +:OpenShiftTemplateName: JBoss EAP CD (no https) + +:ConfigBookName: Configuration Guide +:DevelopmentBookName: Development Guide +:GettingStartedBookName: Getting Started Guide + +:JBDSProductName: Red Hat CodeReady Studio +:JBDSVersion: 12.15 +:LinkJBDSInstall: https://access.redhat.com/documentation/en-us/red_hat_codeready_studio/{JBDSVersion}/html-single/installation_guide/ +:JBDSInstallBookName: Installation Guide +:LinkJBDSGettingStarted: https://access.redhat.com/documentation/en-us/red_hat_codeready_studio/{JBDSVersion}/html-single/getting_started_with_codeready_studio_tools/ +:JBDSGettingStartedBookName: Getting Started with CodeReady Studio Tools + +// Enable Rendering of Glow configuration in plugin examples +:portedToGlow: true + += todo-backend: quickstart for backend deployment on OpenShift +:toc: left +:icons: font +:idprefix: +:idseparator: - +:keywords: openshift,galleon,helm +:level: Intermediate +:technologies: JPA, JAX-RS, OpenShift, Galleon +:openshift: true +:archiveType: war +:useHelmChartDir: true +:helm-install-prerequisites-openshift: ../todo-backend/helm-install-prerequisites.adoc +:helm-install-prerequisites-kubernetes: ../todo-backend/helm-install-prerequisites.adoc +:portedToGlow: true +:helmSetWildFlyArgumentPrefix: wildfly. + +[abstract] +The `todo-backend` quickstart demonstrates how to implement a backend that exposes a HTTP API with JAX-RS +to manage a list of ToDo which are persisted in a database with JPA. + +ifndef::ProductRelease[] +This quickstart shows how to setup a local deployment of this backend as well as a deployment on OpenShift to connect +to a PostgreSQL database also hosted on OpenShift. +endif::[] +ifdef::ProductRelease[] +This quickstart shows how to deploy a {productName} application on OpenShift that connects +to a PostgreSQL database also hosted on OpenShift. +endif::[] + + +== What is it? + +The `todo-backend` quickstart demonstrates how to implement a backend that exposes a HTTP API with `JAX-RS` +to manage a list of ToDo which are persisted in a database with `JPA`. + +* The backend exposes a HTTP API to manage a list of todos that complies with the specs defined at https://todobackend.com/specs/index.html[todobackend.com]. +* It requires a connection to a PostgreSQL database to persist the todos. +ifndef::ProductRelease[] +* It uses the Server Provisioning for local and cloud deployment +endif::[] +* It can be build with {productName} S2I images for cloud deployment +ifndef::ProductRelease[] +* It is deployed on OpenShift using the https://docs.wildfly.org/wildfly-charts/[Helm Chart for {productName}]. +endif::[] +ifdef::ProductRelease[] +* It is deployed on OpenShift using the https://jbossas.github.io/eap-charts//[Helm Chart for {productName}]. +endif::[] + +// Link to the quickstart source +:leveloffset: +1 + +ifndef::ProductRelease,EAPXPRelease[] +link:https://github.com/wildfly/quickstart/tree/{WildFlyQuickStartRepoTag}/{artifactId}[Browse the source] +endif::[] + +:leveloffset!: +// System Requirements +:leveloffset: +1 + +[[system_requirements]] += System Requirements +//****************************************************************************** +// Include this template to describe the standard system requirements for +// running the quickstarts. +// +// The Forge quickstarts define a `forge-from-scratch` attribute because they +// run entirely in CodeReady Studio and have different requirements . +//****************************************************************************** + +The application this project produces is designed to be run on {productNameFull} {productVersion} or later. + +All you need to build this project is {buildRequirements}. See link:{configureMavenDocUrl}[Configure Maven to Build and Deploy the Quickstarts] to make sure you are configured correctly for testing the quickstarts. + +:leveloffset!: + +== Architecture + +=== Architecture with S2I + +This backend is built using {productName} S2I Builder and Runtime images. + +ifndef::ProductRelease[] +When the image is built, `org.wildfly.plugins:wildfly-maven-plugin` plugin provisions the {productName} application server and all the feature packs it needs for its features. +The layers are defined in the `pom.xml` file in the `` section of the `org.wildfly.plugins:wildfly-maven-plugin` plugin: + +[source,xml] +---- + + cloud-server + postgresql-datasource + +---- +endif::[] + +ifdef::ProductRelease[] +When the image is built, `org.jboss.eap.plugins:eap-maven-plugin` plugin provisions the {productName} application server and all the feature packs it needs for its features. +The layers are defined in the `pom.xml` file in the `` section of the `org.jboss.eap.plugins:eap-maven-plugin` plugin: + +[source,xml] +---- + + cloud-server + postgresql-datasource + +---- +endif::[] + +The `cloud-server` layer provides everything needed to run the backend on OpenShift. This also includes access to +Jakarta EE APIs such as CDI, JAX-RS, JPA, etc. These two layers comes from the {productName} feature pack provided in the +{productName} S2I builder image. + +ifndef::ProductRelease[] +The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is also provided by +`org.wildfly:wildfly-datasources-galleon-pack` which is included in the WildFly S2I image. + +The Git repository for this feature pack is hosted at https://github.com/wildfly-extras/wildfly-datasources-galleon-pack. +It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`. +endif::[] + +ifdef::ProductRelease[] +The `postgresql-datasource` layer provides a JDBC driver and DataSource to connect to a PostgreSQL database. It is also provided by +the `org.jboss.eap:eap-datasources-galleon-pack` feature pack. + +The Git repository for this feature pack is hosted at https://github.com/jbossas/eap-datasources-galleon-pack. +It provides JDBC drivers and datasources for different databases but for this quickstart, we will only need the `postgresql-datasource`. +endif::[] + +=== Connection to the PostgreSQL database + +ifndef::ProductRelease[] +As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database +is provided by the `org.wildfly:wildfly-datasources-galleon-pack` feature pack. +endif::[] +ifdef::ProductRelease[] +As mentioned, the JDBC drivers and datasource configuration that the backend uses to connect to the PostgreSQL database +is provided by the `org.jboss.eap:eap-datasources-galleon-pack` feature pack. +endif::[] + +By default, it exposes a single datasource. +In the backend, the name of this datasource is `ToDos` and is specified in the `persistence.xml` to configure JPA: + +[source,xml] +---- + + java:jboss/datasources/ToDos + +---- + +At runtime, we only need a few environment variables to establish the connection from {productName} to the external PostgreSQL database: + +* `POSTGRESQL_DATABASE` - the name of the database (that will be called `todos`) +* `POSTGRESQL_SERVICE_HOST` - the host to connect to the database +* `POSTGRESQL_SERVICE_PORT` - The port to connect to the database +* `POSTGRESQL_USER` & `POSTGRESQL_PASSWORD` - the credentials to connect to the database +* `POSTGRESQL_DATASOURCE` - The name of the datasource (as mentioned above, it will be `ToDos`) + +=== Filters for Cross-Origin Resource Sharing (CORS) + +The Web frontend for this quickstart uses JavaScript calls to query the backend's HTTP API. +We must enable Cross-Origin Resource Sharing (CORS) filters in the `undertow` subsystem of {productName} to allow +these HTTP requests to succeed. + +ifdef::ProductRelease[] +==== Configuration with {productName} S2I + +As we use S2I to provision the server and build the application, we provide a CLI script that contains all the commands to create and configure the CORS filters in Undertow. This script is located in the `src/scripts/cors_filters.cli`. +endif::[] + +This script is executed at build time and will provide the following HTTP headers to enabled CORS: + +* `Access-Control-Allow-Origin: *` +* `Access-Control-Allow-Methods: GET, POST, OPTION, PUT, DELETE, PATCH` +* `Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with` +* `Access-Control-Allow-Credentials: true` +* `Access-Control-Max-Age: 1` + +By default, the backend accepts requests from any origin (`*`). This is only simplicity. It is possible to restrict +the allowed origin using the environment variable `CORS_ORIGIN` at runtime. + +ifndef::ProductRelease[] + +== Run the Backend Locally + +=== Package the Backend + +The backend is packaged and deployed on a provisioned server: + +[source,options="nowrap"] +---- +$ mvn clean package -Pprovisioned-server +---- + +=== Run a Local PostgreSQL Database + +Before running the backend locally, we need to have a local PostgreSQL database that we can connect to. +We use the `postgresql` docker image to create one: + +[source,options="nowrap"] +---- +$ docker run --name todo-backend-db -e POSTGRES_USER=todos -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 postgres +---- + +This will create a database named `todos` that we can connect to on `localhost:5432` with the credentials `todos / mysecretpassword`. + +=== Run the Application + +With the PostgreSQL database running, we can start the backend by passing the required environment variables to connect to the database: + +[source,options="nowrap"] +---- +$ ./target/server/bin/standalone.sh -Denv.POSTGRESQL_DATABASE=todos -Denv.POSTGRESQL_DATASOURCE=ToDos -Denv.POSTGRESQL_SERVICE_HOST=localhost -Denv.POSTGRESQL_SERVICE_PORT=5432 -Denv.POSTGRESQL_USER=todos -Denv.POSTGRESQL_PASSWORD=mysecretpassword +---- + +The backend is running, and we can use the HTTP API to manage a list of todos: + +[source,options="nowrap"] +---- +# get a list of todos +$ curl http://localhost:8080 +[] + +# create a todo with the title "This is my first todo item!" +$ curl -X POST -H "Content-Type: application/json" -d '{"title": "This is my first todo item!"}' http://localhost:8080 +{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}% + +# get a list of todos with the one that was just created +$ curl http://localhost:8080 +[{"completed":false,"id":1,"order":0,"title":"This is my first todo item!","url":"https://localhost:8080/1"}] +---- + +:extraStartParams: -DPOSTGRESQL_DATABASE=todos -DPOSTGRESQL_SERVICE_HOST=localhost -DPOSTGRESQL_SERVICE_PORT=5432 -DPOSTGRESQL_USER=todos -DPOSTGRESQL_PASSWORD=mysecretpassword -DPOSTGRESQL_DATASOURCE=ToDos +:leveloffset: +1 + +[[run_the_integration_tests_with_provisioned_server_]] += Run the Integration Tests with a provisioned server + +//****************************************************************************** +// This template sets attributes for the different standalone server profiles. +// +// You must define the `standalone-server-type`. Supported values are: +// default +// full +// full-ha +// ha +// microprofile +// custom +//****************************************************************************** + +// Standalone server with the default profile. +ifeval::["{standalone-server-type}"=="default"] +:serverProfile: default profile +:configFileName: standalone/configuration/standalone.xml +:serverArguments: +endif::[] + +// Standalone server with the full profile. +ifeval::["{standalone-server-type}"=="full"] +:serverProfile: full profile +:configFileName: standalone/configuration/standalone-full.xml +:serverArguments: -c standalone-full.xml +endif::[] + +// Standalone server with the full HA profile. +ifeval::["{standalone-server-type}"=="full-ha"] +:serverProfile: full HA profile +:configFileName: standalone/configuration/standalone-full-ha.xml +:serverArguments: -c standalone-full-ha.xml +endif::[] + +// Start the standalone server with the HA profile. +ifeval::["{standalone-server-type}"=="ha"] +:serverProfile: HA profile +:configFileName: standalone/configuration/standalone-ha.xml +:serverArguments: -c standalone-ha.xml +endif::[] + +// Start the standalone server with the Eclipse MicroProfile profile. +ifeval::["{standalone-server-type}"=="microprofile"] +:serverProfile: MicroProfile profile +:configFileName: standalone/configuration/standalone-microprofile.xml +:serverArguments: -c standalone-microprofile.xml +endif::[] + +// Standalone server with the custom profile. +// NOTE: This profile requires that you define the `serverArguments` variable +// within the quickstart README.adoc file. For example: +// :serverArguments: --server-config=../../docs/examples/configs/standalone-xts.xml +ifeval::["{standalone-server-type}"=="custom"] +:serverProfile: custom profile +endif::[] + +// If there is no match, use the default profile. +ifndef::serverProfile[] +:standalone-server-type: default +:serverProfile: default profile +:configFileName: standalone/configuration/standalone.xml +:serverArguments: +endif::serverProfile[] + +ifndef::mavenServerProvisioningCommand[] +ifeval::["{archiveType}"=="ear"] +:mavenServerProvisioningCommand: clean install +endif::[] +ifeval::["{archiveType}"=="war"] +:mavenServerProvisioningCommand: clean package +endif::[] +ifeval::["{archiveType}"=="jar"] +:mavenServerProvisioningCommand: clean install +endif::[] +endif::mavenServerProvisioningCommand[] + +ifndef::deploymentTargetDir[] +ifndef::deploymentDir[:deploymentTargetDir: target] +ifdef::deploymentDir[:deploymentTargetDir: {deploymentDir}/target] +endif::deploymentTargetDir[] + +ifndef::server_provisioning_server_host[] +:server_provisioning_server_host: http://localhost:8080 +endif::server_provisioning_server_host[] + +ifndef::extraStartParams[:extraStartParams: ] +ifndef::extraProvisioningTestParams[:extraProvisioningTestParams: ] + +The integration tests included with this quickstart, which verify that the quickstart runs correctly, may also be run with a provisioned server. + +Follow these steps to run the integration tests. + +. Make sure the server is provisioned. ++ +[source,subs="attributes+",options="nowrap"] +---- +$ mvn {mavenServerProvisioningCommand} -Pprovisioned-server +---- + +ifdef::addQuickstartUser[] +. Add the quickstart user: ++ +[source,subs="+quotes,attributes+",options="nowrap"] +---- +$ {deploymentTargetDir}/server/bin/add-user.sh -a -u 'quickstartUser' -p 'quickstartPwd1!' {app-group-command} +---- +endif::[] + +ifdef::addQuickstartAdmin[] +. Add the quickstart admin: ++ +[source,subs="+quotes,attributes+",options="nowrap"] +---- +$ {deploymentTargetDir}/server/bin/add-user.sh -a -u 'quickstartAdmin' -p 'adminPwd1!' {admin-group-command} +---- +[NOTE] +==== +For Windows, use the `__{jbossHomeName}__\bin\add-user.bat` script. +==== +endif::[] + +. Start the {productName} provisioned server, this time using the {productName} Maven Plugin, which is recommended for testing due to simpler automation. The path to the provisioned server should be specified using the `jbossHome` system property. ++ +ifndef::deploymentDir[] +[source,subs="attributes+",options="nowrap"] +---- +$ mvn wildfly:start -DjbossHome=target/server {extraStartParams} +---- +endif::[] +ifdef::deploymentDir[] +[source,subs="attributes+",options="nowrap"] +---- +$ mvn -f {deploymentDir}/pom.xml wildfly:start -DjbossHome={deploymentDir}/target/server {extraStartParams} +---- +endif::[] + +. Type the following command to run the `verify` goal with the `integration-testing` profile activated, and specifying the quickstart's URL using the `server.host` system property, which for a provisioned server by default is `{server_provisioning_server_host}`. ++ +[source,subs="attributes+",options="nowrap"] +---- +$ mvn verify -Pintegration-testing -Dserver.host={server_provisioning_server_host} {extraProvisioningTestParams} +---- + +. Shutdown the {productName} provisioned server, this time using the {productName} Maven Plugin too. ++ +ifndef::deploymentDir[] +[source,subs="attributes+",options="nowrap"] +---- +$ mvn wildfly:shutdown +---- +endif::[] +ifdef::deploymentDir[] +[source,subs="attributes+",options="nowrap"] +---- +$ mvn -f {deploymentDir}/pom.xml wildfly:shutdown +---- +endif::[] + +:leveloffset!: + +//=========================================================== +// Openshift - START +== Run the Backend on OpenShift + +// OpenShift +:leveloffset: +1 + +:cloud-platform: OpenShift +:openshift: true +ifndef::helm-app-name[] +:helm-app-name: {artifactId} +endif::helm-app-name[] + +[[build_and_run_the_quickstart_on_openshift]] += Building and running the quickstart application with OpenShift +// The openshift profile +:leveloffset: +1 + +[[build-the-quickstart-for-openshift]] +== Build the {productName} Source-to-Image (S2I) Quickstart to {cloud-platform} with Helm Charts + +On OpenShift, the S2I build with Apache Maven uses an `openshift` Maven profile to provision a {productName} server, deploy and run the quickstart in OpenShift environment. + +ifndef::ProductRelease,EAPXPRelease[] +The server provisioning functionality is provided by the WildFly Maven Plugin, and you may find its configuration in the quickstart `pom.xml`: +endif::[] +ifdef::ProductRelease,EAPXPRelease[] +The server provisioning functionality is provided by the EAP Maven Plugin, and you may find its configuration in the quickstart `pom.xml`: +endif::[] + +ifndef::ProductRelease,EAPXPRelease[] + +[source,xml,subs="attributes+"] +---- + + openshift + + + + org.wildfly.plugins + wildfly-maven-plugin + + + ${version.server} + cloud + + + ROOT.war + ... + + + + + package + + + + + ... + + + +---- +You may note that unlike the `provisioned-server` profile it uses the cloud context which enables a configuration tuned for {cloud-platform} environment. + +The plugin uses https://github.com/wildfly/wildfly-glow[WildFly Glow] to discover the feature packs and layers required to run the application, and provisions a server containing those layers. + +If you get an error or the server is missing some functionality which cannot be auto-discovered, you can download the https://github.com/wildfly/wildfly-glow/releases[WildFly Glow CLI] and run the following command to see more information about what add-ons are available: +[source,shell] +---- +wildfly-glow show-add-ons +---- +endif::ProductRelease,EAPXPRelease[] + +ifdef::ProductRelease,EAPXPRelease[] +[source,xml,subs="attributes+"] +---- + + openshift + + + + org.jboss.eap.plugins + eap-maven-plugin + + ... + + + org.jboss.eap:wildfly-ee-galleon-pack + + + org.jboss.eap.cloud:eap-cloud-galleon-pack + + + ... + ROOT.war + + + + + package + + + + + ... + + + +---- +You may note that it uses the cloud feature pack which enables a configuration tuned for the {cloud-platform} environment. +endif::[] + +:leveloffset: 1 +// Getting Started with Helm +:leveloffset: +1 + +[[getting_started_with_helm]] += Getting Started with {xpaasproduct-shortname} and Helm Charts + +This section contains the basic instructions to build and deploy this quickstart to {xpaasproduct-shortname} or {xpaasproductOpenShiftOnline-shortname} using Helm Charts. + +[[prerequisites_helm_openshift]] +== Prerequisites + +ifndef::kubernetes[] +* You must be logged in OpenShift and have an `oc` client to connect to OpenShift +endif::[] +* https://helm.sh[Helm] must be installed to deploy the backend on {cloud-platform}. + +Once you have installed Helm, you need to add the repository that provides Helm Charts for {productName}. + +ifndef::ProductRelease,EAPXPRelease[] +[source,options="nowrap"] +---- +$ helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ +"wildfly" has been added to your repositories +$ helm search repo wildfly +NAME CHART VERSION APP VERSION DESCRIPTION +wildfly/wildfly ... ... Build and Deploy WildFly applications on OpenShift +wildfly/wildfly-common ... ... A library chart for WildFly-based applications +---- +endif::[] +ifdef::ProductRelease[] +[source,options="nowrap",subs="+attributes"] +---- +$ helm repo add jboss-eap https://jbossas.github.io/eap-charts/ +"jboss-eap" has been added to your repositories +$ helm search repo jboss-eap +NAME CHART VERSION APP VERSION DESCRIPTION +{helmChartName} ... ... A Helm chart to build and deploy EAP {productVersion} applications +---- +endif::[] +ifdef::EAPXPRelease[] +[source,options="nowrap",subs="+attributes"] +---- +$ helm repo add jboss-eap https://jbossas.github.io/eap-charts/ +"jboss-eap" has been added to your repositories +$ helm search repo jboss-eap +NAME CHART VERSION APP VERSION DESCRIPTION +{helmChartName} ... ... A Helm chart to build and deploy EAP XP {productVersion} applications +---- +endif::[] + +:leveloffset: 1 + +ifdef::helm-install-prerequisites-openshift[] +// Additional steps needed before deploying in Helm +[[deploy_helm_prerequisites]] +:leveloffset: +1 + +ifndef::ProductRelease[] +Add the bitnami repository which provides an helm chart for PostgreSQL: +[source,options="nowrap"] +---- +$ helm repo add bitnami https://charts.bitnami.com/bitnami +"bitnami" has been added to your repositories +---- + +The Helm Chart for this quickstart contains all the information to build an image from the source code using S2I and install it with the database: + +[source,options="nowrap"] +---- +dependencies: + - name: postgresql + repository: https://charts.bitnami.com/bitnami + version: ... + - name: wildfly + repository: http://docs.wildfly.org/wildfly-charts/ + version: ... +---- + +So we need to update the dependecies of our Helm Chart. + +[source,options="nowrap",subs="+attributes"] +---- +$ helm dependency update charts/ +---- +endif::[] + +:leveloffset: 1 +endif::helm-install-prerequisites-openshift[] + +//Prepare Helm for Quickstart Deployment +:leveloffset: +1 + +ifndef::helmSetWildFlyArgumentPrefix[] +// For use with nested Helm charts +:helmSetWildFlyArgumentPrefix: +endif::[] +ifeval::[{useHelmChartDir} == true] +:helm_chart_values: charts +endif::[] +ifndef::useHelmChartDir[] +:helm_chart_values: -f charts/helm.yaml {helmChartName} +endif::[] +ifdef::kubernetes[] +:helm-set-build-enabled: --set {helmSetWildFlyArgumentPrefix}build.enabled=false +:helm-set-deploy-route-enabled: --set {helmSetWildFlyArgumentPrefix}deploy.route.enabled=false +:helm-set-image-name: --set {helmSetWildFlyArgumentPrefix}image.name="localhost:5000/{artifactId}" +:helm-extra-arguments: {helm-set-build-enabled} {helm-set-deploy-route-enabled} {helm-set-image-name} +:cloud-cli: kubectl +endif::[] +ifndef::kubernetes[] +:helm-extra-arguments: +:cloud-cli: oc +endif::[] +[[deploy_helm]] +== Deploy the {ProductShortName} Source-to-Image (S2I) Quickstart to {cloud-platform} with Helm Charts + +ifndef::kubernetes[] +Log in to your OpenShift instance using the `oc login` command. +endif::[] +The backend will be built and deployed on {cloud-platform} with a Helm Chart for {productName}. + + +ifndef::kubernetes[] +Navigate to the root directory of this quickstart and run the following command: +endif::[] +ifdef::kubernetes[] +Navigate to the root directory of this quickstart and run the following commands: + +[source,options="nowrap",subs="+attributes"] +---- +mvn -Popenshift package wildfly:image +---- +This will use the `openshift` Maven profile we saw earlier to build the application, and create a Docker image containing the {productName} server with the application deployed. The name of the image will be `{artifactId}`. + +Next we need to tag the image and make it available to Kubernetes. You can push it to a registry like `quay.io`. In this case we tag as `localhost:5000/{artifactId}:latest` and push it to the internal registry in our Kubernetes instance: + +[source,options="nowrap",subs="+attributes"] +---- +# Tag the image +docker tag {artifactId} localhost:5000/{artifactId}:latest +# Push the image to the registry +docker push localhost:5000/{artifactId}:latest +---- + +In the below call to `helm install` which deploys our application to Kubernetes, we are passing in some extra arguments to tweak the Helm build: + +* `{helm-set-build-enabled}` - This turns off the s2i build for the Helm chart since Kubernetes, unlike OpenShift, does not have s2i. Instead, we are providing the image to use. +* `{helm-set-deploy-route-enabled}` - This disables route creation normally performed by the Helm chart. On Kubernetes we will use port-forwards instead to access our application, since routes are an OpenShift specific concept and thus not available on Kubernetes. +* `{helm-set-image-name}` - This tells the Helm chart to use the image we built, tagged and pushed to Kubernetes' internal registry above. + +endif::[] +[source,options="nowrap",subs="+attributes"] +---- +$ helm install {helm-app-name} {helm_chart_values} --wait --timeout=10m0s {helm-extra-arguments} +NAME: {helm-app-name} +... +STATUS: deployed +REVISION: 1 +---- + +This command will return once the application has successfully deployed. In case of a timeout, you can check the status of the application with the following command in another terminal: + +[source,options="nowrap",subs="+attributes"] +---- +{cloud-cli} get deployment {helm-app-name} +---- + +The Helm Chart for this quickstart contains all the information to build an image from the source code using S2I on Java 17: + + +ifndef::requires-http-route[] +ifdef::useHelmChartDir[] +[source,yaml] +---- +apiVersion: v2 +name: todo-backend-chart +description: A Helm chart to deploy a WildFly todo-backend application and its Postgresql database +type: application +version: 1.0.0 +appVersion: 31.0.0.Final +dependencies: + - name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 13.1.5 + - name: wildfly + repository: http://docs.wildfly.org/wildfly-charts/ + version: 2.3.2 +---- +endif::useHelmChartDir[] +ifndef::useHelmChartDir[] +[source,yaml] +---- +include::{docdir}/charts/helm.yaml[] +---- +endif::useHelmChartDir[] +endif::requires-http-route[] + +ifdef::requires-http-route[] +[source,options="nowrap",subs="+attributes"] +---- +build: + uri: {githubRepoCodeUrl} + ref: {WildFlyQuickStartRepoTag} + contextDir: {artifactId} +deploy: + replicas: 1 + route: + tls: + enabled: false +---- +endif::requires-http-route[] + +This will create a new deployment on {cloud-platform} and deploy the application. + +If you want to see all the configuration elements to customize your deployment you can use the following command: +[source,options="nowrap",subs="+attributes"] +---- +$ helm show readme {helmChartName} +---- + +ifdef::openshift[] +Get the URL of the route to the deployment. + +[source,options="nowrap",subs="+attributes"] +---- +$ oc get route {helm-app-name} -o jsonpath="{.spec.host}" +---- +Access the application in your web browser using the displayed URL. +endif::[] +ifdef::kubernetes[] +To be able to connect to our application running in Kubernetes from outside, we need to set up a port-forward to the `{helm-app-name}` service created for us by the Helm chart. + +This service will run on port `8080`, and we set up the port forward to also run on port `8080`: + +[source,options="nowrap",subs="+attributes"] +---- +kubectl port-forward service/{helm-app-name} 8080:8080 +---- +The server can now be accessed via `http://localhost:8080` from outside Kubernetes. Note that the command to create the port-forward will not return, so it is easiest to run this in a separate terminal. + +endif::[] +[NOTE] +==== +The Maven profile named `openshift` is used by the Helm chart to provision the server with the quickstart deployed on the root web context, and thus the application should be accessed with the URL without the `/{artifactId}` path segment after `HOST:PORT`. +==== + +ifdef::openshift+post-helm-install-actions-openshift[] +include::{post-helm-install-actions-openshift}[leveloffset=+1] +endif::openshift+post-helm-install-actions-openshift[] +ifdef::kubernetes+post-helm-install-actions-kubernetes[] +include::{post-helm-install-actions-kubernetes}[leveloffset=+1] +endif::kubernetes+post-helm-install-actions-kubernetes[] + +:leveloffset: 1 + +// Testing on Openshift +:leveloffset: +1 + +[[run_the_integration_tests_with_openshift]] += Run the Integration Tests with OpenShift +The integration tests included with this quickstart, which verify that the quickstart runs correctly, may also be run with the quickstart running on OpenShift. +[NOTE] +==== +The integration tests expect a deployed application, so make sure you have deployed the quickstart on OpenShift before you begin. +==== + +ifdef::extra-testing-actions-openshift[] +include::{extra-testing-actions-openshift}[leveloffset=+1] +endif::extra-testing-actions-openshift[] + +ifndef::extra-test-arguments-openshift[:extra-test-arguments-openshift:] + +Run the integration tests using the following command to run the `verify` goal with the `integration-testing` profile activated and the proper URL: +ifndef::requires-http-route[] +[source,options="nowrap",subs="+attributes"] +---- +$ mvn verify -Pintegration-testing -Dserver.host=https://$(oc get route {helm-app-name} --template='{{ .spec.host }}') {extra-test-arguments-openshift} +---- +endif::requires-http-route[] +ifdef::requires-http-route[] +[source,options="nowrap",subs="+attributes"] +---- +$ mvn verify -Pintegration-testing -Dserver.host=http://$(oc get route {helm-app-name} --template='{{ .spec.host }}') {extra-test-arguments-openshift} +---- +endif::requires-http-route[] + +[NOTE] +==== +The tests are using SSL to connect to the quickstart running on OpenShift. So you need the certificates to be trusted by the machine the tests are run from. +==== + +:leveloffset: 1 + +//Prepare Helm for Quickstart Deployment +:leveloffset: +1 + +[[undeploy_helm]] +== Undeploy the {ProductShortName} Source-to-Image (S2I) Quickstart from {cloud-platform} with Helm Charts + +[source,options="nowrap",subs="+attributes"] +---- +$ helm uninstall {helm-app-name} +---- +ifdef::kubernetes[] +To stop the port forward you created earlier use: +[source,options="nowrap",subs="+attributes"] +---- +$ kubectl port-forward service/{helm-app-name} 8080:8080 +---- +endif::[] + +:leveloffset: 1 + +// Unset the attribute +:!openshift: + +:leveloffset!: +:leveloffset: +1 + +:additional-readme-openshift: true +ifdef::additional-readme-openshift[] +:additional-readme-cloud-platform: OpenShift +endif::[] +ifdef::additional-readme-kubernetes[] +:additional-readme-cloud-platform: Kubernetes +endif::[] + +=== Environment variables for PostgreSQL + +The Helm Chart also contains the environment variables required to connect to the PostgreSQL database. + +ifndef::ProductRelease[] +In local deployment the credentials were passed directly as the values of the environment variables. +endif::[] + +For {additional-readme-cloud-platform}, we rely on secrets so that the credentials are never copied outside {additional-readme-cloud-platform}: + +[source,options="nowrap"] +---- +deploy: + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + key: database-password + name: todo-backend-db +---- + +When the application is deployed, the value for the `POSTGRESQL_PASSWORD` will be taken from the key `database-password` +in the secret `todo-backend-db`. + +ifdef::additional-readme-openshift[] +== Use the todobackend Web Frontend + +Once the backend is deployed on {additional-readme-cloud-platform}, it can be accessed from the route `todo-backend`. +Let's find the host that we can use to connect to this backend: + +[source,options="nowrap"] +---- +$ oc get route todo-backend -o jsonpath="{.spec.host}" +todo-backend-jmesnil1-dev.apps.sandbox.x8i5.p1.openshiftapps.com +---- + +This value will be different for every installation of the backend. + +[WARNING] +==== +Make sure to prepend the host with `https://` to be able to connect to the backend from the ToDo Backend Specs or Client. +The host must also be publicly accessible. +==== + +We can verify that this application is properly working as a ToDo Backend by running its https://todobackend.com/specs/index.html[specs] on it. + + +Once all tests passed, we can use the https://todobackend.com/client/index.html[todobackend client] to have a Web application connected to the backend. + +[NOTE] +==== +https://todobackend.com/[todobackend.com] is an external service used to showcase this quickstart. +It might not always be functional but does not impact the availability of this backend. +==== +endif::[] + +== Clean Up + +=== Remove the Backend + +The backend can be deleted from {additional-readme-cloud-platform} by running the command: + +[source,options="nowrap"] +---- +$ helm uninstall todo-backend +release "todo-backend" uninstalled +---- +// Unset the attribute +:!additional-readme-openshift: + +:leveloffset!: +// OpenShift - END +//=========================================================== + +//=========================================================== +// Kubernetes - START +ifndef::ProductRelease,EAPXPRelease[] +== Run the Backend on Kubernetes + +//Kubernetes +:leveloffset: +1 + +:cloud-platform: Kubernetes +:kubernetes: true +ifndef::helm-app-name[] +:helm-app-name: {artifactId} +endif::helm-app-name[] + +[[build_and_run_the_quickstart_on_kubernetes]] += Building and running the quickstart application with Kubernetes +// The openshift profile +:leveloffset: +1 + +[[build-the-quickstart-for-kubernetes]] +== Build the {productName} Quickstart to Kubernetes with Helm Charts + +For Kubernetes, the build with Apache Maven uses an `openshift` Maven profile to provision a {productName} server, suitable for running on Kubernetes. + +ifndef::ProductRelease,EAPXPRelease[] +The server provisioning functionality is provided by the WildFly Maven Plugin, and you may find its configuration in the quickstart `pom.xml`: +endif::[] +ifdef::ProductRelease,EAPXPRelease[] +The server provisioning functionality is provided by the EAP Maven Plugin, and you may find its configuration in the quickstart `pom.xml`: +endif::[] + +ifndef::ProductRelease,EAPXPRelease[] + +[source,xml,subs="attributes+"] +---- + + openshift + + + + org.wildfly.plugins + wildfly-maven-plugin + + + ${version.server} + cloud + + + ROOT.war + ... + + + + + package + + + + + ... + + + +---- +You may note that unlike the `provisioned-server` profile it uses the cloud context which enables a configuration tuned for {cloud-platform} environment. + +The plugin uses https://github.com/wildfly/wildfly-glow[WildFly Glow] to discover the feature packs and layers required to run the application, and provisions a server containing those layers. + +If you get an error or the server is missing some functionality which cannot be auto-discovered, you can download the https://github.com/wildfly/wildfly-glow/releases[WildFly Glow CLI] and run the following command to see more information about what add-ons are available: +[source,shell] +---- +wildfly-glow show-add-ons +---- +endif::ProductRelease,EAPXPRelease[] + +ifdef::ProductRelease,EAPXPRelease[] +[source,xml,subs="attributes+"] +---- + + openshift + + + + org.jboss.eap.plugins + eap-maven-plugin + + ... + + + org.jboss.eap:wildfly-ee-galleon-pack + + + org.jboss.eap.cloud:eap-cloud-galleon-pack + + + ... + ROOT.war + + + + + package + + + + + ... + + + +---- +You may note that it uses the cloud feature pack which enables a configuration tuned for the {cloud-platform} environment. +endif::[] + +:leveloffset: 1 +// Getting Started with Helm +:leveloffset: +1 + +[[getting_started_with_helm]] += Getting Started with Kubernetes and Helm Charts + +This section contains the basic instructions to build and deploy this quickstart to Kubernetes using Helm Charts. + +== Install Kubernetes +In this example we are using https://github.com/kubernetes/minikube[Minikube] as our Kubernetes provider. See the https://minikube.sigs.k8s.io/docs/start/[Minikube Getting Started guide] for how to install it. After installing it, we start it with 4GB of memory. + +[source,options="nowrap",subs="+attributes"] +---- +minikube start --memory='4gb' +---- +The above command should work if you have Docker installed on your machine. If, you are using https://podman-desktop.io[Podman] instead of Docker, you will also need to pass in `--driver=podman`, as covered in the https://minikube.sigs.k8s.io/docs/handbook/config/[Minikube documentation]. + +Once Minikube has started, we need to enable its https://minikube.sigs.k8s.io/docs/handbook/registry/[registry] since that is where we will push the image needed to deploy the quickstart, and where we will tell the Helm charts to download it from. + +[source,options="nowrap",subs="+attributes"] +---- +minikube addons enable registry +---- + +In order to be able to push images to the registry we need to make it accessible from outside Kubernetes. How we do this depends on your operating system. All the below examples will expose it at `localhost:5000` + +[source,options="nowrap",subs="+attributes"] +---- +# On Mac: +docker run --rm -it --network=host alpine ash -c "apk add socat && socat TCP-LISTEN:5000,reuseaddr,fork TCP:$(minikube ip):5000" + +# On Linux: +kubectl port-forward --namespace kube-system service/registry 5000:80 & + +# On Windows: +kubectl port-forward --namespace kube-system service/registry 5000:80 +docker run --rm -it --network=host alpine ash -c "apk add socat && socat TCP-LISTEN:5000,reuseaddr,fork TCP:host.docker.internal:5000" +---- + +[[prerequisites_helm_openshift]] +== Prerequisites + +ifndef::kubernetes[] +* You must be logged in OpenShift and have an `oc` client to connect to OpenShift +endif::[] +* https://helm.sh[Helm] must be installed to deploy the backend on {cloud-platform}. + +Once you have installed Helm, you need to add the repository that provides Helm Charts for {productName}. + +ifndef::ProductRelease,EAPXPRelease[] +[source,options="nowrap"] +---- +$ helm repo add wildfly https://docs.wildfly.org/wildfly-charts/ +"wildfly" has been added to your repositories +$ helm search repo wildfly +NAME CHART VERSION APP VERSION DESCRIPTION +wildfly/wildfly ... ... Build and Deploy WildFly applications on OpenShift +wildfly/wildfly-common ... ... A library chart for WildFly-based applications +---- +endif::[] +ifdef::ProductRelease[] +[source,options="nowrap",subs="+attributes"] +---- +$ helm repo add jboss-eap https://jbossas.github.io/eap-charts/ +"jboss-eap" has been added to your repositories +$ helm search repo jboss-eap +NAME CHART VERSION APP VERSION DESCRIPTION +{helmChartName} ... ... A Helm chart to build and deploy EAP {productVersion} applications +---- +endif::[] +ifdef::EAPXPRelease[] +[source,options="nowrap",subs="+attributes"] +---- +$ helm repo add jboss-eap https://jbossas.github.io/eap-charts/ +"jboss-eap" has been added to your repositories +$ helm search repo jboss-eap +NAME CHART VERSION APP VERSION DESCRIPTION +{helmChartName} ... ... A Helm chart to build and deploy EAP XP {productVersion} applications +---- +endif::[] + +:leveloffset: 1 + +ifdef::helm-install-prerequisites-kubernetes[] +// Additional steps needed before deploying in Helm +[[deploy_helm_prerequisites]] +:leveloffset: +1 + +ifndef::ProductRelease[] +Add the bitnami repository which provides an helm chart for PostgreSQL: +[source,options="nowrap"] +---- +$ helm repo add bitnami https://charts.bitnami.com/bitnami +"bitnami" has been added to your repositories +---- + +The Helm Chart for this quickstart contains all the information to build an image from the source code using S2I and install it with the database: + +[source,options="nowrap"] +---- +dependencies: + - name: postgresql + repository: https://charts.bitnami.com/bitnami + version: ... + - name: wildfly + repository: http://docs.wildfly.org/wildfly-charts/ + version: ... +---- + +So we need to update the dependecies of our Helm Chart. + +[source,options="nowrap",subs="+attributes"] +---- +$ helm dependency update charts/ +---- +endif::[] + +:leveloffset: 1 +endif::helm-install-prerequisites-kubernetes[] + +//Prepare Helm for Quickstart Deployment +:leveloffset: +1 + +ifndef::helmSetWildFlyArgumentPrefix[] +// For use with nested Helm charts +:helmSetWildFlyArgumentPrefix: +endif::[] +ifeval::[{useHelmChartDir} == true] +:helm_chart_values: charts +endif::[] +ifndef::useHelmChartDir[] +:helm_chart_values: -f charts/helm.yaml {helmChartName} +endif::[] +ifdef::kubernetes[] +:helm-set-build-enabled: --set {helmSetWildFlyArgumentPrefix}build.enabled=false +:helm-set-deploy-route-enabled: --set {helmSetWildFlyArgumentPrefix}deploy.route.enabled=false +:helm-set-image-name: --set {helmSetWildFlyArgumentPrefix}image.name="localhost:5000/{artifactId}" +:helm-extra-arguments: {helm-set-build-enabled} {helm-set-deploy-route-enabled} {helm-set-image-name} +:cloud-cli: kubectl +endif::[] +ifndef::kubernetes[] +:helm-extra-arguments: +:cloud-cli: oc +endif::[] +[[deploy_helm]] +== Deploy the {ProductShortName} Source-to-Image (S2I) Quickstart to {cloud-platform} with Helm Charts + +ifndef::kubernetes[] +Log in to your OpenShift instance using the `oc login` command. +endif::[] +The backend will be built and deployed on {cloud-platform} with a Helm Chart for {productName}. + + +ifndef::kubernetes[] +Navigate to the root directory of this quickstart and run the following command: +endif::[] +ifdef::kubernetes[] +Navigate to the root directory of this quickstart and run the following commands: + +[source,options="nowrap",subs="+attributes"] +---- +mvn -Popenshift package wildfly:image +---- +This will use the `openshift` Maven profile we saw earlier to build the application, and create a Docker image containing the {productName} server with the application deployed. The name of the image will be `{artifactId}`. + +Next we need to tag the image and make it available to Kubernetes. You can push it to a registry like `quay.io`. In this case we tag as `localhost:5000/{artifactId}:latest` and push it to the internal registry in our Kubernetes instance: + +[source,options="nowrap",subs="+attributes"] +---- +# Tag the image +docker tag {artifactId} localhost:5000/{artifactId}:latest +# Push the image to the registry +docker push localhost:5000/{artifactId}:latest +---- + +In the below call to `helm install` which deploys our application to Kubernetes, we are passing in some extra arguments to tweak the Helm build: + +* `{helm-set-build-enabled}` - This turns off the s2i build for the Helm chart since Kubernetes, unlike OpenShift, does not have s2i. Instead, we are providing the image to use. +* `{helm-set-deploy-route-enabled}` - This disables route creation normally performed by the Helm chart. On Kubernetes we will use port-forwards instead to access our application, since routes are an OpenShift specific concept and thus not available on Kubernetes. +* `{helm-set-image-name}` - This tells the Helm chart to use the image we built, tagged and pushed to Kubernetes' internal registry above. + +endif::[] +[source,options="nowrap",subs="+attributes"] +---- +$ helm install {helm-app-name} {helm_chart_values} --wait --timeout=10m0s {helm-extra-arguments} +NAME: {helm-app-name} +... +STATUS: deployed +REVISION: 1 +---- + +This command will return once the application has successfully deployed. In case of a timeout, you can check the status of the application with the following command in another terminal: + +[source,options="nowrap",subs="+attributes"] +---- +{cloud-cli} get deployment {helm-app-name} +---- + +The Helm Chart for this quickstart contains all the information to build an image from the source code using S2I on Java 17: + + +ifndef::requires-http-route[] +ifdef::useHelmChartDir[] +[source,yaml] +---- +apiVersion: v2 +name: todo-backend-chart +description: A Helm chart to deploy a WildFly todo-backend application and its Postgresql database +type: application +version: 1.0.0 +appVersion: 31.0.0.Final +dependencies: + - name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 13.1.5 + - name: wildfly + repository: http://docs.wildfly.org/wildfly-charts/ + version: 2.3.2 +---- +endif::useHelmChartDir[] +ifndef::useHelmChartDir[] +[source,yaml] +---- +include::{docdir}/charts/helm.yaml[] +---- +endif::useHelmChartDir[] +endif::requires-http-route[] + +ifdef::requires-http-route[] +[source,options="nowrap",subs="+attributes"] +---- +build: + uri: {githubRepoCodeUrl} + ref: {WildFlyQuickStartRepoTag} + contextDir: {artifactId} +deploy: + replicas: 1 + route: + tls: + enabled: false +---- +endif::requires-http-route[] + +This will create a new deployment on {cloud-platform} and deploy the application. + +If you want to see all the configuration elements to customize your deployment you can use the following command: +[source,options="nowrap",subs="+attributes"] +---- +$ helm show readme {helmChartName} +---- + +ifdef::openshift[] +Get the URL of the route to the deployment. + +[source,options="nowrap",subs="+attributes"] +---- +$ oc get route {helm-app-name} -o jsonpath="{.spec.host}" +---- +Access the application in your web browser using the displayed URL. +endif::[] +ifdef::kubernetes[] +To be able to connect to our application running in Kubernetes from outside, we need to set up a port-forward to the `{helm-app-name}` service created for us by the Helm chart. + +This service will run on port `8080`, and we set up the port forward to also run on port `8080`: + +[source,options="nowrap",subs="+attributes"] +---- +kubectl port-forward service/{helm-app-name} 8080:8080 +---- +The server can now be accessed via `http://localhost:8080` from outside Kubernetes. Note that the command to create the port-forward will not return, so it is easiest to run this in a separate terminal. + +endif::[] +[NOTE] +==== +The Maven profile named `openshift` is used by the Helm chart to provision the server with the quickstart deployed on the root web context, and thus the application should be accessed with the URL without the `/{artifactId}` path segment after `HOST:PORT`. +==== + +ifdef::openshift+post-helm-install-actions-openshift[] +include::{post-helm-install-actions-openshift}[leveloffset=+1] +endif::openshift+post-helm-install-actions-openshift[] +ifdef::kubernetes+post-helm-install-actions-kubernetes[] +include::{post-helm-install-actions-kubernetes}[leveloffset=+1] +endif::kubernetes+post-helm-install-actions-kubernetes[] + +:leveloffset: 1 + +// Testing on Openshift +:leveloffset: +1 + +[[run_the_integration_tests_with_kubernetes]] += Run the Integration Tests with Kubernetes +The integration tests included with this quickstart, which verify that the quickstart runs correctly, may also be run with the quickstart running on Kubernetes. +[NOTE] +==== +The integration tests expect a deployed application, so make sure you have deployed the quickstart on Kubernetes before you begin. +==== + +ifdef::extra-testing-actions-kubernetes[] +include::{extra-testing-actions-kubernetes}[leveloffset=+1] +endif::extra-testing-actions-kubernetes[] + +ifndef::extra-test-arguments-kubernetes[:extra-test-arguments-kubernetes:] + +Run the integration tests using the following command to run the `verify` goal with the `integration-testing` profile activated and the proper URL: +[source,options="nowrap",subs="+attributes"] +---- +$ mvn verify -Pintegration-testing -Dserver.host=http://localhost:8080 {extra-test-arguments-kubernetes} +---- + + +:leveloffset: 1 + +//Prepare Helm for Quickstart Deployment +:leveloffset: +1 + +[[undeploy_helm]] +== Undeploy the {ProductShortName} Source-to-Image (S2I) Quickstart from {cloud-platform} with Helm Charts + +[source,options="nowrap",subs="+attributes"] +---- +$ helm uninstall {helm-app-name} +---- +ifdef::kubernetes[] +To stop the port forward you created earlier use: +[source,options="nowrap",subs="+attributes"] +---- +$ kubectl port-forward service/{helm-app-name} 8080:8080 +---- +endif::[] + +:leveloffset: 1 + +// Unset the attribute +:!kubernetes: + +:leveloffset!: +:leveloffset: +1 + +:additional-readme-kubernetes: true +ifdef::additional-readme-openshift[] +:additional-readme-cloud-platform: OpenShift +endif::[] +ifdef::additional-readme-kubernetes[] +:additional-readme-cloud-platform: Kubernetes +endif::[] + +=== Environment variables for PostgreSQL + +The Helm Chart also contains the environment variables required to connect to the PostgreSQL database. + +ifndef::ProductRelease[] +In local deployment the credentials were passed directly as the values of the environment variables. +endif::[] + +For {additional-readme-cloud-platform}, we rely on secrets so that the credentials are never copied outside {additional-readme-cloud-platform}: + +[source,options="nowrap"] +---- +deploy: + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + key: database-password + name: todo-backend-db +---- + +When the application is deployed, the value for the `POSTGRESQL_PASSWORD` will be taken from the key `database-password` +in the secret `todo-backend-db`. + +ifdef::additional-readme-openshift[] +== Use the todobackend Web Frontend + +Once the backend is deployed on {additional-readme-cloud-platform}, it can be accessed from the route `todo-backend`. +Let's find the host that we can use to connect to this backend: + +[source,options="nowrap"] +---- +$ oc get route todo-backend -o jsonpath="{.spec.host}" +todo-backend-jmesnil1-dev.apps.sandbox.x8i5.p1.openshiftapps.com +---- + +This value will be different for every installation of the backend. + +[WARNING] +==== +Make sure to prepend the host with `https://` to be able to connect to the backend from the ToDo Backend Specs or Client. +The host must also be publicly accessible. +==== + +We can verify that this application is properly working as a ToDo Backend by running its https://todobackend.com/specs/index.html[specs] on it. + + +Once all tests passed, we can use the https://todobackend.com/client/index.html[todobackend client] to have a Web application connected to the backend. + +[NOTE] +==== +https://todobackend.com/[todobackend.com] is an external service used to showcase this quickstart. +It might not always be functional but does not impact the availability of this backend. +==== +endif::[] + +== Clean Up + +=== Remove the Backend + +The backend can be deleted from {additional-readme-cloud-platform} by running the command: + +[source,options="nowrap"] +---- +$ helm uninstall todo-backend +release "todo-backend" uninstalled +---- +// Unset the attribute +:!additional-readme-kubernetes: + +:leveloffset!: +endif::[] +// Kubernetes - END +//=========================================================== + + +== Conclusion + +This quickstart shows how the datasource feature pack provided by {productName} simplifies the deployment +of a {productName} Jakarta EE backend on OpenShift to connect to an external database and exposes an HTTP API. + +ifndef::ProductRelease[] +The use of a Server Provisioned deployment makes it seamless to move from a local deployment for development to a +deployment on cloud platforms such as OpenShift and Kubernetes. +endif::[] diff --git a/todo-jakarta-data/additional-readme-cloud.adoc b/todo-jakarta-data/additional-readme-cloud.adoc new file mode 100644 index 0000000000..6bdc0dfc34 --- /dev/null +++ b/todo-jakarta-data/additional-readme-cloud.adoc @@ -0,0 +1,70 @@ +ifdef::additional-readme-openshift[] +:additional-readme-cloud-platform: OpenShift +endif::[] +ifdef::additional-readme-kubernetes[] +:additional-readme-cloud-platform: Kubernetes +endif::[] + +=== Environment variables for PostgreSQL + +The Helm Chart also contains the environment variables required to connect to the PostgreSQL database. + +ifndef::ProductRelease[] +In local deployment the credentials were passed directly as the values of the environment variables. +endif::[] + +For {additional-readme-cloud-platform}, we rely on secrets so that the credentials are never copied outside {additional-readme-cloud-platform}: + +[source,options="nowrap"] +---- +deploy: + env: + - name: POSTGRESQL_PASSWORD + - name: POSTGRESQL_DATABASE + valueFrom: + configMapKeyRef: + name: postgres-configmap + key: POSTGRES_PASSWORD +---- + +When the application is deployed, the value for the `POSTGRESQL_PASSWORD` will be taken from the key `POSTGRES_PASSWORD` +in the secret `postgres-configmap`. + +ifdef::additional-readme-openshift[] +== Use the todobackend Web Frontend + +Once the backend is deployed on {additional-readme-cloud-platform}, it can be accessed from the route `todo-jakarta-data`. +Let's find the host that we can use to connect to this backend: + +[source,options="nowrap"] +---- +$ oc get route todo-jakarta-data -o jsonpath="{.spec.host}" +todo-jakarta-data-jmesnil1-dev.apps.sandbox.x8i5.p1.openshiftapps.com +---- + +This value will be different for every installation of the backend. + +To be able to connect to the backend from the ToDo Backend Specs or Client, then prepend the host with `https://`, and append the relative web context `/todo-jakarta-data`. For the previous example host this would be `https://todo-jakarta-data-jmesnil1-dev.apps.sandbox.x8i5.p1.openshiftapps.com/todo-jakarta-data`. + +We can verify that this application is properly working as a ToDo Backend by running its https://todobackend.com/specs/index.html[specs] on it. + +Once all tests passed, we can use the https://todobackend.com/client/index.html[todobackend client] to have a Web application connected to the backend. + +[NOTE] +==== +https://todobackend.com/[todobackend.com] is an external service used to showcase this quickstart. +It might not always be functional but does not impact the availability of this backend. +==== +endif::[] + +== Clean Up + +=== Remove the Backend + +The backend can be deleted from {additional-readme-cloud-platform} by running the command: + +[source,options="nowrap"] +---- +$ helm uninstall todo-backend +release "todo-backend" uninstalled +---- \ No newline at end of file diff --git a/todo-jakarta-data/additional-readme-kubernetes.adoc b/todo-jakarta-data/additional-readme-kubernetes.adoc new file mode 100644 index 0000000000..1894d7279b --- /dev/null +++ b/todo-jakarta-data/additional-readme-kubernetes.adoc @@ -0,0 +1,4 @@ +:additional-readme-kubernetes: true +include::../todo-backend/additional-readme-cloud.adoc[] +// Unset the attribute +:!additional-readme-kubernetes: \ No newline at end of file diff --git a/todo-jakarta-data/additional-readme-openshift.adoc b/todo-jakarta-data/additional-readme-openshift.adoc new file mode 100644 index 0000000000..144ab7f3fc --- /dev/null +++ b/todo-jakarta-data/additional-readme-openshift.adoc @@ -0,0 +1,4 @@ +:additional-readme-openshift: true +include::../todo-backend/additional-readme-cloud.adoc[] +// Unset the attribute +:!additional-readme-openshift: \ No newline at end of file diff --git a/todo-jakarta-data/charts/.helmignore b/todo-jakarta-data/charts/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/todo-jakarta-data/charts/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/todo-jakarta-data/charts/Chart.yaml b/todo-jakarta-data/charts/Chart.yaml new file mode 100644 index 0000000000..e7f2e36b11 --- /dev/null +++ b/todo-jakarta-data/charts/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: todo-jakarta-data-chart +description: A Helm chart to deploy a WildFly todo-jakarta-data application and its Postgresql database +type: application +version: 1.0.0 +dependencies: + - name: wildfly + repository: http://docs.wildfly.org/wildfly-charts/ + version: 2.3.2 diff --git a/todo-jakarta-data/charts/templates/postgres-configmap.yaml b/todo-jakarta-data/charts/templates/postgres-configmap.yaml new file mode 100644 index 0000000000..806c20d581 --- /dev/null +++ b/todo-jakarta-data/charts/templates/postgres-configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-configmap + labels: + app: postgres +data: + POSTGRES_DB: {{ .Values.db.database }} + POSTGRES_USER: {{ .Values.db.username }} + POSTGRES_PASSWORD: {{ .Values.db.password }} + PGDATA: /var/lib/postgresql/data/pgdata \ No newline at end of file diff --git a/todo-jakarta-data/charts/templates/postgres.yaml b/todo-jakarta-data/charts/templates/postgres.yaml new file mode 100644 index 0000000000..16662d9b04 --- /dev/null +++ b/todo-jakarta-data/charts/templates/postgres.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: todo-jakarta-data-postgresql +spec: + replicas: 1 + selector: + matchLabels: + app: todo-jakarta-data-postgresql + template: + metadata: + labels: + app: todo-jakarta-data-postgresql + spec: + containers: + - name: postgres + image: postgres:17 + ports: + - containerPort: 5432 + name: postgres + envFrom: + - configMapRef: + name: postgres-configmap + volumeMounts: + - name: pgdata + mountPath: /var/lib/postgresql/data + volumes: + - name: pgdata + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: todo-jakarta-data-postgresql +spec: + ports: + - port: 5432 + targetPort: postgres + selector: + app: todo-jakarta-data-postgresql diff --git a/todo-jakarta-data/charts/values.yaml b/todo-jakarta-data/charts/values.yaml new file mode 100644 index 0000000000..8a09d705c1 --- /dev/null +++ b/todo-jakarta-data/charts/values.yaml @@ -0,0 +1,50 @@ +# Default values for todo-backend-chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +db: + username: todos-db + password: todos-db + database: todos-db + +wildfly: + build: + uri: https://github.com/wildfly/quickstart.git + ref: main + contextDir: todo-backend + deploy: + replicas: 1 + env: + # Env vars to connect to PostgreSQL DB + - name: POSTGRESQL_DATABASE + valueFrom: + configMapKeyRef: + name: postgres-configmap + key: POSTGRES_DB + - name: POSTGRESQL_USER + valueFrom: + configMapKeyRef: + name: postgres-configmap + key: POSTGRES_USER + - name: POSTGRESQL_PASSWORD + valueFrom: + configMapKeyRef: + name: postgres-configmap + key: POSTGRES_PASSWORD + - name: POSTGRESQL_DATASOURCE + value: ToDos + - name: POSTGRESQL_SERVICE_HOST + value: todo-jakarta-data-postgresql + - name: POSTGRESQL_SERVICE_PORT + value: "5432" + # Env to avoid OOME + - name: GC_MAX_METASPACE_SIZE + value: "256" + - name: GC_METASPACE_SIZE + value: "96" + initContainers: + - name: check-db-ready + image: busybox:1.36 + command: ['sh', '-c', + 'until nc -z -v -w 2 todo-backend-postgresql 5432; + do echo "waiting for database"; sleep 2; done;'] diff --git a/todo-jakarta-data/helm-install-prerequisites.adoc b/todo-jakarta-data/helm-install-prerequisites.adoc new file mode 100644 index 0000000000..01b4331b3f --- /dev/null +++ b/todo-jakarta-data/helm-install-prerequisites.adoc @@ -0,0 +1,19 @@ +ifndef::ProductRelease[] +The Helm Chart for this quickstart contains all the information to build an image from the source code using S2I. +It also deploys the PostGreSQL database to store the data. + +[source,options="nowrap"] +---- +dependencies: + - name: wildfly + repository: http://docs.wildfly.org/wildfly-charts/ + version: ... +---- + +So we need to update the dependencies of our Helm Chart. + +[source,options="nowrap",subs="+attributes"] +---- +$ helm dependency update charts/ +---- +endif::[] \ No newline at end of file diff --git a/todo-jakarta-data/pom.xml b/todo-jakarta-data/pom.xml new file mode 100644 index 0000000000..8dc225993f --- /dev/null +++ b/todo-jakarta-data/pom.xml @@ -0,0 +1,289 @@ + + + + 4.0.0 + + org.wildfly.quickstarts + wildfly-quickstart-parent + + 10 + + + + todo-jakarta-data + 39.0.0.Beta1-SNAPSHOT + war + Quickstart: todo-jakarta-data + This project demonstrates how to implement use Jakarta Data to implement a Todo-Backend application to manage ToDos + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.html + repo + + + + + + 17 + + 38.0.1.Final + + ${version.server} + 5.1.5.Final + 7.1.2.Final + + + + + + + org.wildfly.bom + wildfly-ee-preview-with-tools + ${version.bom.ee} + pom + import + + + + + + ${project.artifactId} + + + + org.wildfly.plugins + wildfly-maven-plugin + ${version.plugin.wildfly} + + + + ${POSTGRESQL_DATABASE} + ${POSTGRESQL_SERVICE_HOST} + ${POSTGRESQL_SERVICE_PORT} + ${POSTGRESQL_USER} + ${POSTGRESQL_PASSWORD} + ${POSTGRESQL_DATASOURCE} + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.hibernate.orm + hibernate-jpamodelgen + ${version.org.hibernate.jpamodelgen} + + + + + + + + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + jakarta.data + jakarta.data-api + provided + + + jakarta.ejb + jakarta.ejb-api + provided + + + jakarta.persistence + jakarta.persistence-api + provided + + + jakarta.ws.rs + jakarta.ws.rs-api + provided + + + org.hibernate.orm + hibernate-core + provided + + + org.jboss.resteasy + resteasy-jackson2-provider + provided + + + org.junit.jupiter + junit-jupiter-engine + 5.9.3 + test + + + org.jboss.resteasy + resteasy-client + test + + + org.jboss.logging + commons-logging-jboss-logging + test + + + + + + provisioned-server + + true + + + + + org.wildfly.plugins + wildfly-maven-plugin + + + + + + wildfly-preview@maven(org.jboss.universe:community-universe)#${version.server} + + + org.wildfly + wildfly-datasources-preview-galleon-pack + 11.1.0.Final + + + + cloud-server + jakarta-data + postgresql-datasource + --> + + + + + + + false + + + + + + + package + + + + + + + + + openshift + + + + org.wildfly.plugins + wildfly-maven-plugin + + + ${version.server} + cloud + true + + postgresql + + + + + + + + + false + + + + + + + package + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + none + + + + + + + + integration-testing + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + + + + + + + jboss-public-maven-repository + JBoss Public Maven Repository + https://repository.jboss.org/nexus/content/groups/public/ + + + + + jboss-public-maven-repository + JBoss Public Maven Repository + https://repository.jboss.org/nexus/content/groups/public/ + + + diff --git a/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDo.java b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDo.java new file mode 100644 index 0000000000..9c7c0b2ebf --- /dev/null +++ b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDo.java @@ -0,0 +1,143 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import static java.util.Optional.ofNullable; +import static jakarta.persistence.GenerationType.IDENTITY; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Objects; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.ws.rs.core.UriBuilder; + +@Entity +public class ToDo { + + @Id + @GeneratedValue(strategy = IDENTITY) + private Long id; + private String title; + private Boolean completed = false; + @Column(name = "\"order\"") + private int order; + private URL url; + + public ToDo() { + + } + + public ToDo(String title) { + this.title = title; + } + + public ToDo(Long id, String title, Boolean completed, int order, URL url) { + this.id = id; + this.title = title; + this.completed = completed; + this.order = order; + this.url = url; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isCompleted() { + return completed; + } + + public void setCompleted(Boolean completed) { + this.completed = completed; + } + + public Boolean getCompleted(){ + return this.completed == null ? false : this.completed; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public URL getUrl() throws MalformedURLException, URISyntaxException { + if (this.id != null) { + return UriBuilder.fromUri(url.toURI()).scheme(url.getProtocol()).path(id.toString()).build().toURL(); + } + return this.url; + } + + public void setUrl(URL url) { + this.url = url; + } + + public void update(ToDo newTodo) { + this.title = ofNullable(newTodo.title).orElse(title); + this.completed = ofNullable(newTodo.completed).orElse(completed); + this.order = ofNullable(newTodo.order).orElse(order); + this.url = ofNullable(newTodo.url).orElse(url); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ToDo toDo = (ToDo) o; + return id == toDo.id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public String toString() { + return "ToDo{" + + "id=" + id + + ", title='" + title + '\'' + + ", completed=" + completed + + ", order=" + order + + ", url=" + url + + '}'; + } +} diff --git a/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java new file mode 100644 index 0000000000..2da5913ad6 --- /dev/null +++ b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoBackendApplication.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("") +public class ToDoBackendApplication extends Application{ +} diff --git a/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java new file mode 100644 index 0000000000..d7dfb98ea3 --- /dev/null +++ b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoController.java @@ -0,0 +1,104 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; + +import java.net.MalformedURLException; +import java.util.List; +import java.util.Optional; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; + +@Path("") +@RequestScoped +public class ToDoController { + + @Inject + private ToDoRepository toDoRepository; + + @Context + private UriInfo uriInfo; + + @GET + @Produces(APPLICATION_JSON) + public List getAllTodos(){ + return toDoRepository.findAll(); + } + + @GET + @Path("{id}") + @Produces(APPLICATION_JSON) + public ToDo getTodoFrom(@PathParam("id") long id) { + Optional todo = toDoRepository.find(id); + return todo.orElseThrow(() -> new NotFoundException("ToDo does not exist!")); + } + + @DELETE + @Transactional + public void deleteAllTodos(){ + toDoRepository.findAll().forEach(todo -> toDoRepository.remove(todo)); + } + + @DELETE + @Path("{id}") + @Transactional + public Response deleteTodoFrom(@PathParam("id") long id) { + Optional optional = toDoRepository.find(id); + ToDo todo = optional.orElseThrow(() -> new NotFoundException("ToDo does not exist!")); + toDoRepository.remove(todo); + return Response.ok().build(); + } + + @POST + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @Transactional + public ToDo addTodo(ToDo todo) throws MalformedURLException { + todo.setUrl(uriInfo.getAbsolutePathBuilder().scheme("https").build().toURL()); + toDoRepository.insert(todo); + return todo; + } + + @PATCH + @Path("{id}") + @Produces(APPLICATION_JSON) + @Consumes(APPLICATION_JSON) + @Transactional + public ToDo updateTodo(@PathParam("id") long id, ToDo update) { + return toDoRepository.update(id, update).orElseThrow(() -> new NotFoundException("ToDo does not exist!")); + } +} \ No newline at end of file diff --git a/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoRepository.java b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoRepository.java new file mode 100644 index 0000000000..16b389e747 --- /dev/null +++ b/todo-jakarta-data/src/main/java/org/wildfly/quickstarts/todos/ToDoRepository.java @@ -0,0 +1,58 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2020, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.quickstarts.todos; + +import java.util.List; +import java.util.Optional; + +import jakarta.data.repository.Delete; +import jakarta.data.repository.Find; +import jakarta.data.repository.Insert; +import jakarta.data.repository.Repository; +import jakarta.data.repository.Update; + +@Repository +public interface ToDoRepository { + + @Find + List findAll(); + + @Find + Optional find(Long id); + + @Delete + void remove(ToDo todo); + + @Insert + void insert(ToDo todo); + + @Update + ToDo update(ToDo todo); + + default Optional update(Long id, ToDo newTodo) { + Optional optional = find(id); + if (optional.isPresent()) { + return Optional.of(update(newTodo)); + } + return optional; + } +} \ No newline at end of file diff --git a/todo-jakarta-data/src/main/resources/META-INF/persistence.xml b/todo-jakarta-data/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000..c3de6c4d23 --- /dev/null +++ b/todo-jakarta-data/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,31 @@ + + + + + java:jboss/datasources/ToDos + + + + + + + diff --git a/todo-jakarta-data/src/main/scripts/cors_filters.cli b/todo-jakarta-data/src/main/scripts/cors_filters.cli new file mode 100644 index 0000000000..12b029fbba --- /dev/null +++ b/todo-jakarta-data/src/main/scripts/cors_filters.cli @@ -0,0 +1,16 @@ +echo Adding Undertow Filters for CORS +# Access-Control-Allow-Origin +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Origin":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Origin":add(header-name="Access-Control-Allow-Origin",header-value="${env.CORS_ORIGIN:*}") +# Access-Control-Allow-Methods +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Methods":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Methods":add(header-name="Access-Control-Allow-Methods",header-value="GET, POST, OPTION, PUT, DELETE, PATCH") +# Access-Control-Allow-Headers +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Headers":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Headers":add(header-name="Access-Control-Allow-Headers",header-value="accept, authorization, content-type, x-requested-with") +# Access-Control-Allow-Credentials +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Allow-Credentials":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Allow-Credentials":add(header-name="Access-Control-Allow-Credentials",header-value="true") +# Access-Control-Max-Age +/subsystem=undertow/server=default-server/host=default-host/filter-ref="Access-Control-Max-Age":add() +/subsystem=undertow/configuration=filter/response-header="Access-Control-Max-Age":add(header-name="Access-Control-Max-Age",header-value="1") \ No newline at end of file diff --git a/todo-jakarta-data/src/main/webapp/WEB-INF/beans.xml b/todo-jakarta-data/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000000..ab3c29d2e5 --- /dev/null +++ b/todo-jakarta-data/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/todo-jakarta-data/src/test/java/org/wildfly/quickstarts/todos/RemoteToDoIT.java b/todo-jakarta-data/src/test/java/org/wildfly/quickstarts/todos/RemoteToDoIT.java new file mode 100644 index 0000000000..e020619b94 --- /dev/null +++ b/todo-jakarta-data/src/test/java/org/wildfly/quickstarts/todos/RemoteToDoIT.java @@ -0,0 +1,91 @@ +/* + * Copyright 2022 Red Hat, Inc. + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.wildfly.quickstarts.todos; + +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test; + +/** + * + * @author Emmanuel Hugonnet (c) 2022 Red Hat, Inc. + */ +public class RemoteToDoIT { + + private static final String REST_TARGET_URL = "http://localhost:8080"; + + private String getServerHost() { + String host = System.getenv("SERVER_HOST"); + if (host == null) { + host = System.getProperty("server.host"); + } + return host; + } + + URL getRequestUrl() { + String host = getServerHost(); + if (host == null) { + host = REST_TARGET_URL; + } + try { + return new URI(host+"/todo-jakarta-data").toURL(); + } catch (URISyntaxException | MalformedURLException ex) { + throw new RuntimeException(ex); + } + } + + @Test + public void testCRUD() throws Exception { + WebTarget client = ((ResteasyClientBuilder) ClientBuilder.newBuilder()).setFollowRedirects(true).build().target(getRequestUrl().toURI()); + + GenericType> todosListType = new GenericType>() { + }; + List allTodos = client.request().get(todosListType); + int initialSize = allTodos.size(); + + ToDo toDo = new ToDo(); + toDo.setTitle("My First ToDo"); + toDo.setOrder(1); + ToDo persistedTodo = client.request().post(Entity.entity(toDo, MediaType.APPLICATION_JSON_TYPE), ToDo.class); + assertNotNull(persistedTodo.getId()); + + allTodos = client.request().get(todosListType); + assertEquals(initialSize+1, allTodos.size()); + ToDo fetchedToDo = allTodos.get(initialSize); + assertEquals(toDo.getTitle(), fetchedToDo.getTitle()); + + client.request().delete(); + + allTodos = client.request().get(todosListType); + assertEquals(0, allTodos.size()); + } +}