Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edburns msft rh 205 quarkus learn path public #33

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### YamlMime:AchievementDetail
achievementUid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.badge
metadata:
title: >-
Microsoft Badge: Deploy a Quarkus application to Azure Red Hat OpenShift was
issued by Microsoft
socialImageUrl: /training/achievements/generic-badge-social.png
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.1-introduction
title: Introduction
metadata:
title: Introduction
description: Introduction
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: edburns
durationInMinutes: 3
content: |
[!include[](includes/1-introduction.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.10-summary
title: Summary
metadata:
title: Summary
description: Summary
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: edburns
durationInMinutes: 2
content: |
[!include[](includes/10-summary.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.2-create-quarkus-todo-app
title: Create a new ToDo application using Quarkus
metadata:
title: Create a new ToDo application using Quarkus
description: Create a new ToDo application using Quarkus
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: edburns
durationInMinutes: 5
content: |
[!include[](includes/2-create-quarkus-todo-app.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.3-exercise-create-quarkus-todo-app
title: Exercise - Create a new ToDo application using Quarkus
metadata:
title: Exercise - Create a new ToDo application using Quarkus
description: In this exercise, follow the steps to create a new ToDo application using Quarkus
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: edburns
durationInMinutes: 10
content: |
[!include[](includes/3-exercise-create-quarkus-todo-app.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.4-package-run-locally
title: Package and Run Locally
metadata:
title: Package and Run Locally
description: Package and Run the Todo Application with PostgreSQL locally
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: danieloh
durationInMinutes: 3
content: |
[!include[](includes/4-package-run-locally.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.5-exercise-package-run-locally
title: Exercise - Package and Run Locally
metadata:
title: Exercise - Package and Run Locally
description: In this exercise, follow the steps to package and run the Todo Application with PostgreSQL locally
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: danieloh
durationInMinutes: 3
content: |
[!include[](includes/5-exercise-package-run-locally.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.6-deploy-aro-postgresql
title: Deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL
metadata:
title: Deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL
description: Deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: edburns
durationInMinutes: 8
content: |
[!include[](includes/6-deploy-aro-postgresql.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.7-exercise-deploy-aro-postgresql
title: Exercise - Deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL
metadata:
title: Exercise - Deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL
description: In this exercise, follow the steps to deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom:
- team=devdiv
- devx-track-extended-java
ms.contributors: edburns
durationInMinutes: 10
content: |
[!include[](includes/7-exercise-deploy-aro-postgresql.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.8-evolve-openshift-serverless
title: Evolve the ToDo application to OpenShift Serverless
metadata:
title: Evolve the ToDo application to OpenShift Serverless
description: Evolve the ToDo application to OpenShift Serverless
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom: team=devdiv, devx-track-extended-java, devx-track-azurecli
ms.contributors: edburns
durationInMinutes: 7
content: |
[!include[](includes/8-evolve-openshift-serverless.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### YamlMime:ModuleUnit
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.9-exercise-evolve-openshift-serverless
title: Exercise - Evolve the ToDo application to OpenShift Serverless
metadata:
title: Exercise - Evolve the ToDo application to OpenShift Serverless
description: In this exercise, follow the steps to evolve the ToDo application to OpenShift Serverless
ms.date: 10/18/2024
author: danieloh
ms.author: edburns
ms.topic: unit
ms.custom: team=devdiv, devx-track-extended-java, devx-track-azurecli
ms.contributors: edburns
durationInMinutes: 7
content: |
[!include[](includes/9-exercise-evolve-openshift-serverless.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
As a Java developer working for a company seeking to expand its Azure cloud services, you're tasked with creating a new web-based ToDo list application. The application's data will be stored in a relational Azure database.

Your company has a history of successfully deploying business services on Red Hat OpenShift, leveraging its scalability, elasticity, resilience, and rapid time-to-market benefits.

To align with this established architecture, your team has chosen [Quarkus, a Kubernetes-native Java framework](https://quarkus.io/), for developing the ToDo service since Quarkus focuses on developer productivity, containerization, and seamless OpenShift integration makes it an ideal fit for this project.

This module guides you through creating a new Java project using the Quarkus CLI. The generated project includes sample code, a Maven wrapper, Dockerfile, and unit tests.

Next, you'll develop the business logic to store ToDo items in a relational database, such as PostgreSQL. This will involve implementing methods to retrieve specific ToDo items (entities) from the database.

Once you've thoroughly tested your ToDo list application locally, we'll move on to the deployment phase on the [Azure Red Hat OpenShift (ARO)](hhttps://azure.microsoft.com/en-us/products/openshift) platform.

As an optional challenge, we can explore the possibility of transforming your ToDo application into a serverless function. Serverless functions offer several advantages, including cost-efficiency, reliability, flexibility, and enhanced security. If you're interested in this option, we'll guide you through the process of deploying your application on [Red Hat OpenShift Serverless](https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless).

By the end of this module, you'll not only have a well-functioning ToDo application deployed on ARO with [Azure Database for PostgreSQL](https://azure.microsoft.com/en-us/products/postgresql), but you'll also gain the knowledge and skills to potentially evolve it into a serverless function on Red Hat OpenShift Serverless.

This module requires you to deploy resources to your Azure subscription. If you haven't already, create a free Azure account using the following link: [Free Azure Account](https://azure.microsoft.com/free/java/?azure-portal=true).

> ⚠️ **IMPORTANT**:
> To avoid incurring unnecessary charges in your Azure subscription, remember to deprovision (clean up) the resources you create once you've finished working with them in this module.

## Learning objectives

By the end of this module, you'll be able to:

- Create a new ToDo application using Quarkus.
- Package and Run Locally to verify the functionalities.
- Deploy the Todo application to Azure Red Hat OpenShift with Azure Database for PostgreSQL.
- Evolve the ToDo application to OpenShift Serverless.

## Prerequisites

As a Java developer, you're already familiar with the fundamentals of Java applications. We'll guide you through Quarkus as we progress. For the exercises in this module, you'll need a personal Azure account. Ensure you have the following resources ready:

- An Azure subscription
- JDK 17+ installed with JAVA_HOME configured appropriately
- Apache Maven 3.9.8
- Azure CLI 2.64.0+
- Podman or Docker
- Quarkus CLI
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Congratulations! You've deployed a Quarkus application to Azure Red Hat OpenShift.

Your company wanted to learn how to deploy a Quarkus application to the Azure Red Hat OpenShift with Azure PostgreSQL. You followed these steps:

1. Create a sample Quarkus application, execute and test it locally using Quarkus Dev Services and Dev mode.

1. Build and package the Quarkus application to create a JAR file. Run it locally with a standload PostgreSQL database locally.

1. Create an Azure for PostgreSQL database, and create a TODO table in the database.

1. Install a new Azure Red Hat OpenShift cluster and Configure the Quarkus application to connect to the Azure PostgreSQL database.

1. Deploy the Quarkus application container.

1. Install OpenShift serverless and configure the native serverless function deployment with Quarkus.

You're now confident that you can recommend executing your Quarkus application to Azure Red Hat OpenShift.

## Clean up resources

If you don't need these resources later, delete the resources from the Azure portal.

### Delete Azure Red Hat OpenShift cluster

* [Tutorial: Delete an Azure Red Hat OpenShift 4 cluster](https://docs.microsoft.com/en-us/azure/openshift/tutorial-delete-cluster)

### Delete resource group

```shell
az group delete --name YOUR_RESOURCE_GROUP --yes
```

This command might take a minute to run.

## Additional resources

For more information about Quarkus, see [Quarkus guides](https://quarkus.io/guides).

For more information about[Azure Red Hat OpenShift](https://azure.microsoft.com/en-us/products/openshift).

For more information about PostgreSQL servers on Azure, see [Azure Database for PostgreSQL documentation](/azure/postgresql/).

For more information about Hibernate ORM with Panache, see [Hibernate ORM with Panache](https://quarkus.io/guides/hibernate-orm-panache).

For more information about using Azure with Java, see [Azure for Java developers](/azure/developer/java).

For more information about Quarkus Azure extensions, see [Quarkus Azure extensions](https://quarkus.io/extensions/?search-regex=azure).
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
In this module, you'll embark on a new learning journey to scaffold a new Todo application using Quarkus. You'll also seamlessly implement the entitiy class to map Java beans with the relational database. In the end, you'll create REST services to retrieve the Todo items from the database and store a new Todo item to the database.

Here is a summary of the key developer tools you'll learn in this module.

## Quarkus, Supersonic Subatomic Java

[Quarkus](https://quarkus.io) is a modern Java framework designed to build fast, efficient, and container-native applications. It is optimized for GraalVM, a high-performance Java virtual machine, which can compile Java code into native executables. This results in significantly reduced startup times and memory consumption compared to traditional Java applications.

Key features of Quarkus include:

* **Fast startup**: Quarkus applications start up in milliseconds, making them ideal for microservices architectures and serverless environments.
* **Low memory footprint**: Quarkus is designed to have a small memory footprint, allowing you to run more applications on a given hardware configuration.
* **Developer-friendly**: Quarkus provides a familiar development experience for Java developers, with support for popular frameworks and tools.
* **Container-native**: Quarkus is optimized for deployment in containers, making it easy to build and deploy cloud-native applications.
* **Extensible**: Quarkus is highly extensible, allowing you to add new features and functionality using extensions.

## Quarkus CLI

Quarkus offers multiple options for project creation, including _Maven_, _Gradle_, the [online project generator](https://code.quarkus.io/), and the _Quarkus CLI_. In this lab, we'll focus on the **Quarkus CLI**, a convenient tool easily installable as a JAR using [JBang](https://jbang.dev/). JBang allows us to execute the CLI directly without prior installation.

Run the following commands based on your operation system.

* On Linux, macOS, and Windows (using WSL or bash compatible shell like Cygwin or MinGW)

```bash
curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/
curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio
```

* On Windows using Powershell:

```bash
iex "& { $(iwr https://ps.jbang.dev) } trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/"
iex "& { $(iwr https://ps.jbang.dev) } app install --fresh --force quarkus@quarkusio"
```

If JBang has already been installed, you can directly use it:

```bash
jbang app install --fresh --force quarkus@quarkusio
```

Once installed *quarkus* will be in your *$PATH* and if you run *quarkus --version* it will print the installed version:

```bash
quarkus --version
3.14.4
```

The version might be different when you run the command.

Let's see all these developer tools in action by creating the Todo application using Quarkus CLI.
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
Dive into Quarkus with a hands-on lab! In this module, you'll create a basic Quarkus application using Quarkus CLI and your preferred IDE. Then, you will keep adding new features to your Todo application.

For consistent environment from developer's local to production using Quarkus Dev Services, you need to install a container runtime (e.g., _Docker_ or _Podman_) to stand up external services (e.g. PostgreSQL) with your application locally.

## Generate a new Quarkus application

Use Quarkus CLI to scaffold a new Quarkus project to implement a Todo application. Run the following command in your local Terminal.

```bash
quarkus create app quarkus-todo-app-aro
```

The output should look likt this.

```bash
Looking for the newly published extensions in registry.quarkus.io
-----------

applying codestarts...
📚 java
🔨 maven
📦 quarkus
📝 config-properties
🔧 tooling-dockerfiles
🔧 tooling-maven-wrapper
🚀 rest-codestart

-----------
[SUCCESS] ✅ quarkus project has been successfully generated in:
--> /Users/danieloh/azure-learn-path/quarkus-todo-app-aro
-----------
Navigate into this directory and get started: quarkus dev
```
## Get started with live coding
Quarkus Dev Mode is a powerful feature that significantly speeds up the development lifecycle by providing hot reload capabilities as known as _Live Coding_. This means that changes made to your application code are automatically recompiled and reloaded without requiring a full restart.
Run the Quarkus Dev Mode using the following Quarkus CLI.
```bash
cd quarkus-todo-app-aro
quarkus dev
```
The output should look likt this.
```bash
....
Listening for transport dt_socket at address: 5005
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
INFO [io.quarkus] (Quarkus Main Thread) quarkus-todo-app-aro 1.0.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx) started in 1.306s. Listening on: http://localhost:8080

INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, rest, smallrye-context-propagation, vertx]

--
Tests paused
Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options
```
Press `d` to open the Quarkus DEV UI. It will open a new web browser or tab automatically. You can also access the [DEV UI](http://localhost:8080/q/dev-ui) directly.
![Quarkus Dev UI](../media/quarkus-dev-ui.png)
Take some time to familiarize yourself with the Dev UI menus, including Extensions and Continuous Testing. We'll cover these topics in depth later.
Find more information about Quarkus DEV UI [here](https://quarkus.io/guides/dev-ui).
Test the sample REST service by sending a request using `curl` in your terminal. This will help ensure it's working as expected.
```bash
curl localhost:8080/hello
```
The output should look like this.
```bash
Hello from Quarkus REST
```
Keep running the Quarkus dev mode!
## Develop new features in the Todo application
We’ll be creating a simple data-driven application that manages a set of Todo items, who have title, completed, order, and url. In this lab we'll add the **quarkus-panache** extension for the JPA implementation to our project, but we will need a few more for connecting to databases. Add these extensions with the following command:
```bash
quarkus ext add jdbc-postgresql hibernate-orm-panache hibernate-validator rest-jackson
```
The output should look like this.
```bash
Looking for the newly published extensions in registry.quarkus.io
[SUCCESS] ✅ Extension io.quarkus:quarkus-jdbc-postgresql has been installed
[SUCCESS] ✅ Extension io.quarkus:quarkus-hibernate-orm-panache has been installed
[SUCCESS] ✅ Extension io.quarkus:quarkus-hibernate-validator has been installed
[SUCCESS] ✅ Extension io.quarkus:quarkus-rest-jackson has been installed
```
When you take a look at the terminal where you started the Quarkus Dev Mode, you should see the following logs.
```bash
Dev Services for the default datasource (postgresql) started
```
**Quarkus Dev Services** provide a convenient way to manage and configure external dependencies for your Quarkus applications. This can significantly simplify development and testing processes. Find more information about Quarkus Dev Services [here](https://quarkus.io/guides/dev-services).
Then, execute `podman ps` or `docker ps` locally in another terminal. You will see that a PostgreSQL container is running automatically.
```bash
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f36fef6abd46 docker.io/library/postgres:14 postgres -c fsync... 9 seconds ago Up 9 seconds 0.0.0.0:41493->5432/tcp, 5432/tcp festive_ramanujan
```
### Create the new Todo entity
Now, let's create a new class representing a `Todo` entity. We'll leverage the Java Persistence API (JPA) to manage data interaction with our PostgreSQL database. For simplified persistence logic, we'll utilize [Hibernate ORM with Panache](https://quarkus.io/guides/hibernate-orm-panache) by extending the `io.quarkus.hibernate.orm.panache.PanacheEntity` class.
To establish a direct connection between your Java Todo object and the PostgreSQL `Todo` table, you employ a JPA entity (`@Entity`). The `TodoResource` REST endpoint serves as a gateway, creating a new `Todo` entity class and subsequently persisting it. This entity class acts as a domain model, aligning with the Todo table. JPA will automatically generate this table.
By extending `PanacheEntity`, you gain access to a comprehensive set of generic create, read, update, and delete (CRUD) methods tailored to your specific type. This streamlines the process of saving and deleting `Todo` objects, condensing these operations into a single line of Java code.
Create a new `Todo.java` file in the `src/main/java/java/org/acme/` directory. Copy the following code to the Java file.
```java
package org.acme;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import java.util.List;

@Entity
public class Todo extends PanacheEntity {

@Column(unique = true)
public String title;

public boolean completed;

@Column(name = "ordering")
public int order;

public String url;

public static List<Todo> findNotCompleted() {
return list("completed", false);
}

public static List<Todo> findCompleted() {
return list("completed", true);
}

public static long deleteCompleted() {
return delete("completed", true);
}

}
```
### Create Jakarta REST services
To manage that class, update the `TodoResource` so that it can publish REST interfaces to store and retrieve data by using HTTP. Open the `TodoResource` class and replace the code with the following:
To effectively manage the Todo class, you'll create a new `TodoResource.java` file in the `src/main/java/java/org/acme/` directory to expose REST interfaces that facilitate data storage and retrieval through HTTP requests.
Copy the following code to the Java file:
```java
package org.acme;
import io.quarkus.panache.common.Sort;
import jakarta.transaction.Transactional;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import java.util.List;
@Path("/api")
public class TodoResource {
@OPTIONS
public Response opt() {
return Response.ok().build();
}
@GET
public List<Todo> getAll() {
return Todo.listAll(Sort.by("order"));
}
@GET
@Path("/{id}")
public Todo getOne(@PathParam("id") Long id) {
Todo entity = Todo.findById(id);
if (entity == null) {
throw new WebApplicationException("Todo with id of " + id + " does not exist.", Status.NOT_FOUND);
}
return entity;
}
@POST
@Transactional
public Response create(@Valid Todo item) {
item.persist();
return Response.status(Status.CREATED).entity(item).build();
}
@PATCH
@Path("/{id}")
@Transactional
public Response update(@Valid Todo todo, @PathParam("id") Long id) {
Todo entity = Todo.findById(id);
entity.id = id;
entity.completed = todo.completed;
entity.order = todo.order;
entity.title = todo.title;
entity.url = todo.url;
return Response.ok(entity).build();
}
@DELETE
@Transactional
public Response deleteCompleted() {
Todo.deleteCompleted();
return Response.noContent().build();
}
@DELETE
@Transactional
@Path("/{id}")
public Response deleteOne(@PathParam("id") Long id) {
Todo entity = Todo.findById(id);
if (entity == null) {
throw new WebApplicationException("Todo with id of " + id + " does not exist.", Status.NOT_FOUND);
}
entity.delete();
return Response.noContent().build();
}
}
```
## Insert sample data to the Todo database
In the reality scenario, you would insert data into the database since the business data in production should be stored in a relational database.
Create a new `import.sql` file in the `src/main/resources/` directory. Copy the following SQL code to the SQL file.
```sql
INSERT INTO todo(id, title, completed, ordering, url) VALUES (1, 'Introduction to Quarkus', false, 0, null);
INSERT INTO todo(id, title, completed, ordering, url) VALUES (2, 'Hibernate with Panache', false, 1, null);
INSERT INTO todo(id, title, completed, ordering, url) VALUES (3, 'Visit Quarkus web site', false, 2, 'https://quarkus.io');
INSERT INTO todo(id, title, completed, ordering, url) VALUES (4, 'Visit Azure Red Hat OpenShift', false, 3, 'https://azure.microsoft.com/en-us/products/openshift');
ALTER SEQUENCE todo_seq RESTART WITH 5;
```
## Verify the application
Let's verify the application using `curl` command.
Open a new lcoal terminal. Retrieve all Todo items by running the following `curl` command:
```bash
curl http://localhost:8080/api
```
The output should look like this:
```json
[
{
"id": 1,
"title": "Introduction to Quarkus",
"completed": false,
"order": 0,
"url": null
},
{
"id": 2,
"title": "Hibernate with Panache",
"completed": false,
"order": 1,
"url": null
},
{
"id": 3,
"title": "Visit Quarkus web site",
"completed": false,
"order": 2,
"url": "https://quarkus.io"
},
{
"id": 4,
"title": "Visit Azure Red Hat OpenShift",
"completed": false,
"order": 3,
"url": "https://azure.microsoft.com/en-us/products/openshift"
}
]
```
Great job! You have successfully developed your Todo application on Quarkus.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Within this module, you'll thoroughly test the Todo application's functionality locally by leveraging Quarkus's continuous testing capabilities. Instead of relying on an external database, we'll utilize Quarkus Dev Services to streamline this process. Before deploying the application to Azure Red Hat OpenShift, we'll also package and execute it locally once more.

## Quarkus Continuous Testing

**Quarkus Continuous Testing** is a powerful feature that allows developers to automatically test their applications as they make changes to the code. This helps to ensure that the application remains functional and bug-free throughout the development process.

Key Features of Quarkus Continuous Testing:

* **Automatic test execution**: Quarkus automatically executes tests whenever changes are made to the code.
* **Fast feedback**: Tests are run quickly, providing developers with immediate feedback on the impact of their changes.
* **Integration with Quarkus Dev Services**: Quarkus Continuous Testing can be easily integrated with Quarkus Dev Services, allowing you to test your application against real external dependencies.
* **Support for various testing frameworks**: Quarkus supports a wide range of testing frameworks, including JUnit, TestNG, and Mockito.

Continuous Testing also offers a multitude of benefits for developers. By automatically executing tests whenever code changes are made, it helps to ensure that applications remain functional and bug-free throughout the development process. This not only improves code quality but also boosts productivity by eliminating the need for manual testing. Additionally, Quarkus Continuous Testing reduces the risk of introducing new bugs and accelerates the development and testing cycle, ultimately leading to faster time-to-market.

## How to Set Up Quarkus Continuous Testing

1. **Create a test class**: Write a test class using your preferred testing framework.
2. **Annotate the test class**: Annotate the test class with @QuarkusTest to enable Quarkus Continuous Testing.
3. **Run the application**: Start your Quarkus application in development mode.
4. **Make changes to your code**: As you make changes to your code, Quarkus will automatically recompile and rerun your tests.

Here is an example of a test class:

```java
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class TodoResourceTest {
// Your test methods here
}
```

Next, you'll dive into the process of applying continuous testing to the Todo application. Following that, we'll package and execute the application using the Quarkus CLI and Java command.
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
To further strengthen the Todo application's testing, we'll introduce new test cases that leverage Quarkus Continuous Testing as the testing framework and align with Test-Driven Development principles. We'll also package and run the application locally using a standalone PostgreSQL database.

## Resume the continuous testing

To resume the continuous testing in Quakrus, you can press `r` in the terminal where the Quarkus dev mode is running.

```bash
--
Tests paused
Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
```

Otherwise, you can start it in Quarkus Dev UI.

![Quarkus Continuous Testing in Dev Ui - Paused](../media/quarkus-devui-ct.png)

When you resume the continuous testing, the existing test (`testHelloEndpoint()`) will be re-run.

The output in the terminal should look like this (**All 1 test is passing**).

```bash
--
All 1 test is passing (0 skipped), 1 test was run in 2984ms. Tests completed at 22:02:31.
Press [e] to edit command line args (currently ''), [r] to re-run, [o] Toggle test output, [:] for the terminal, [h] for more options>
```

When you run it in Dev UI, you will see the test result like this.

![Quarkus Continuous Testing Result in Dev UI - 1 tested](../media/quarkus-devui-ct-result.png)

## Create following 5 test cases for Todo application

You'll add new 5 test cases to verify the Todo application.

* **testInitialItems()** - verify that the initial list of items is correct.
* **testAddingAnItem()** - verify that you can add an item to the list.
* **testUpdatingAnItem()** - verify that you can update an item in the list.
** **testDeletingAnItem()** - verify that you can delete an item from the list.
* **testDeleteCompleted()** - verify that you can delete all completed items from the list.

Create a new `TodoResourceTest.java` file in the `src/test/java/io/quarkus/sample/` directory. Copy the following code to the Java file.

```java
package io.quarkus.sample;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.common.mapper.TypeRef;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import java.util.List;

import static io.restassured.RestAssured.*;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.assertEquals;

@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class TodoResourceTest {

@Test
@Order(1)
void testInitialItems() {
List<Todo> todos = get("/api").then()
.statusCode(HttpStatus.SC_OK)
.contentType(MediaType.APPLICATION_JSON)
.extract().body().as(getTodoTypeRef());
assertEquals(4, todos.size());

get("/api/1").then()
.statusCode(HttpStatus.SC_OK)
.contentType(MediaType.APPLICATION_JSON)
.body("title", is("Introduction to Quarkus - Imperative"))
.body("completed", is(false));
}

@Test
@Order(2)
void testAddingAnItem() {
Todo todo = new Todo();
todo.title = "testing the application";
given()
.body(todo)
.contentType(MediaType.APPLICATION_JSON)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
.when()
.post("/api")
.then()
.statusCode(HttpStatus.SC_CREATED)
.contentType(MediaType.APPLICATION_JSON)
.body("title", is(todo.title))
.body("completed", is(false))
.body("id", is(5));

List<Todo> todos = get("/api").then()
.statusCode(HttpStatus.SC_OK)
.contentType(MediaType.APPLICATION_JSON)
.extract().body().as(getTodoTypeRef());
assertEquals(5, todos.size());
}

@Test
@Order(3)
void testUpdatingAnItem() {
Todo todo = new Todo();
todo.title = "testing the application (updated)";
todo.completed = true;
given()
.body(todo)
.contentType(MediaType.APPLICATION_JSON)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
.pathParam("id", 5)
.when()
.patch("/api/{id}")
.then()
.statusCode(HttpStatus.SC_OK)
.contentType(MediaType.APPLICATION_JSON)
.body("title", is(todo.title))
.body("completed", is(true))
.body("id", is(5));
}

@Test
@Order(4)
void testDeletingAnItem() {
given()
.contentType(MediaType.APPLICATION_JSON)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
.pathParam("id", 5)
.when()
.delete("/api/{id}")
.then()
.statusCode(HttpStatus.SC_NO_CONTENT);

List<Todo> todos = get("/api").then()
.statusCode(HttpStatus.SC_OK)
.contentType(MediaType.APPLICATION_JSON)
.extract().body().as(getTodoTypeRef());
assertEquals(4, todos.size());
}

@Test
@Order(5)
void testDeleteCompleted() {
delete("/api")
.then()
.statusCode(HttpStatus.SC_NO_CONTENT);

List<Todo> todos = get("/api").then()
.statusCode(HttpStatus.SC_OK)
.contentType(MediaType.APPLICATION_JSON)
.extract().body().as(getTodoTypeRef());
assertEquals(4, todos.size());
}

private TypeRef<List<Todo>> getTodoTypeRef() {
return new TypeRef<List<Todo>>() {
// Kept empty on purpose
};
}

}
```

`Save` the file. Then, the continuous testing is running automatically and instantly in the Quarkus Dev UI.

The output in the terminal should look like this (**All 6 tests are passing**).

```bash
--
All 6 tests are passing (0 skipped), 5 tests were run in 2968ms. Tests completed at 22:06:45 due to changes to TodoResourceTest$1.class and 1 other files.
Press [e] to edit command line args (currently ''), [r] to re-run, [o] Toggle test output, [:] for the terminal, [h] for more options>
```

Dev UI should now show the following.

![Quarkus Continuous Testing Result in Dev UI - 6 tested](../media/quarkus-continuous-testing.png)

`Stop` the Quarkus dev mode by pressing `CTRL + c`.

## Package your application

Before you package your application, you need to append the actual database connection details (e.g., _JDBC url_, _database credentials_) to the `application.properties` file in the `src/main/resources` directory.

```properties
%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/todo
%prod.quarkus.datasource.jdbc.driver=org.postgresql.Driver
%prod.quarkus.hibernate-orm.sql-load-script=import.sql
%prod.quarkus.datasource.username=user
%prod.quarkus.datasource.password=superSecret
%prod.quarkus.hibernate-orm.database.generation=drop-and-create
```

Quarkus supports the notion of configuration profiles. These allows you to have multiple configurations in the same file and select between then via a profile name.

By default Quarkus has three profiles, although it is possible to use as many as you like. The default profiles are:

* *dev* - Activated when in development mode (e.g., quarkus:dev)
* *test* - Activated when running tests
* *prod* - The default profile when not running in development or test mode

During the build process, Quarkus will automatically validate the database connection using the above specified details. Therefore, it's necessary to run a standalone PostgreSQL database instead of relying on the PostgreSQL dev service.

Run a standalone PostgreSQL database with the following command.

```bash
podman run -it --rm=true --name todo -e POSTGRES_USER=user \
-e POSTGRES_PASSWORD=superSecret -e POSTGRES_DB=todo \
-p 5432:5432 postgres:14
```

You can also run the above command using `docker run` command.

Next, compile your application to create a JAR file. You can do this using the `quarkus build` command.

```bash
quarkus build
```

While building the applicaiton, you will see the following test result in the terminal.

```bash
[INFO] Results:
[INFO]
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
```

The output should end with `BUILD SUCCESS`.

You should now see a JAR file (`quarkus-run.jar `) in the `target/quarkus-app/` directory.

## Run your application

You might wonder why the Jar file isn't generated right under the _target_ directory. The reason is that Quarkus generates a **Fast-JAR** file for you when you build your application.

**Quarkus Fast-Jar** offers several advantages for Quarkus applications. By generating smaller JAR files compared to traditional Java applications, it improves deployment and startup times. Additionally, Quarkus Fast-Jar enhances application performance by minimizing classloader lookups. Its simplified deployment process, involving a single JAR file, streamlines management and distribution. Moreover, Quarkus Fast-Jar is compatible with various deployment environments, including cloud platforms, Kubernetes, and traditional servers.

Run your application by executing the following command.

```bash
java -jar target/quarkus-run.jar
```

The output should look like this.

```bash
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
INFO [io.quarkus] (main) quarkus-todo-app-aro 1.0.0-SNAPSHOT on JVM (powered by Quarkus xx.xx.xx) started in 1.558s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profile prod activated.
INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, rest, rest-jackson, smallrye-context-propagation, vertx]
```

Open a new lcoal terminal. Retrieve a specific Todo item by running the following `curl` command:

```bash
curl http://localhost:8080/api/3
```

The output should look like this.

```json
{
"id": 3,
"title": "Visit Quarkus web site",
"completed": false,
"order": 2,
"url": "https://quarkus.io"
}
```

Stop the application by pressing `CTRL + c`.

Great job! You have successfully packaged your Todo application with the PosgreSQL database configuration. You can now deploy your application to Azure Red Hat OpenShift.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
In this module, you'll delve into deploying the Todo application to a scalable Azure Red Hat OpenShift cluster. Upon completion, you'll have successfully established an Azure Database for PostgreSQL server and a fully functional Todo application developed in Quarkus and deployed in a cloud-native environment.

Explore the underlying technologies in more detail here:

## Azure Red Hat OpenShift

[Azure Red Hat OpenShift (ARO)](hhttps://azure.microsoft.com/en-us/products/openshift) is a fully managed Kubernetes platform as a service (PaaS) that combines the power of Red Hat OpenShift with the scale and reliability of Microsoft Azure. It provides a comprehensive environment for building, deploying, and managing containerized applications.

Key features and benefits of Azure Red Hat OpenShift include:

* **Fully managed**: Microsoft and Red Hat jointly manage the infrastructure, control plane, and application nodes, reducing operational overhead for customers.
* **Enterprise-grade**: Built on a stable and secure foundation, Azure Red Hat OpenShift offers enterprise-grade features like high availability, disaster recovery, and security.  
* **Hybrid flexibility**: Deploy OpenShift clusters on-premises or in the cloud using Azure Red Hat OpenShift Dedicated or Azure Red Hat OpenShift, respectively.  
* **Developer-friendly**: Provides a rich set of tools and features to simplify application development, deployment, and management.  
* **Integrated ecosystem**: Benefits from a vast ecosystem of tools, technologies, and partners, enabling seamless integration with existing applications and infrastructure.

## Azure Database for PostgreSQL

[Azure Database for PostgreSQL](https://azure.microsoft.com/en-us/products/postgresql) is a fully managed relational database service offered by Microsoft Azure. It provides a highly available, scalable, and secure PostgreSQL environment that is ideal for a wide range of applications.

Key features and benefits include:

* **Fully managed**: Microsoft handles the infrastructure, maintenance, and updates, allowing you to focus on your application.
* **High availability**: Built-in redundancy and automatic failover ensure your database remains accessible.
**Scalability**: Easily scale your database up or down to meet changing demands.
* **Security**: Robust security features, including encryption, authentication, and authorization, protect your data.
* **Compatibility**: Compatible with the open-source PostgreSQL ecosystem, enabling you to leverage existing tools and skills.
* **Integration**: Seamless integration with other Azure services, such as Azure Functions, Logic Apps, and Azure Data Factory.

## Azure CLI

Azure CLI is a powerful command-line interface (CLI) tool that allows you to manage and interact with Azure resources directly from your terminal. It provides a flexible and efficient way to automate tasks, create and configure resources, and execute complex operations within the Azure cloud platform.

For example, to get the details of a subscription, you can use the following command:

```bash
az account show
```

In this module, you use the Azure CLI to spin up the Azure Red Hat Openshift cluster. Access the Azure CLI from a terminal or through Visual Studio Code. Or you can access it from [Azure Cloud Shell](https://azure.microsoft.com/get-started/azure-portal/cloud-shell). This browser-based shell experience is hosted in the cloud. In Cloud Shell, the Azure CLI is configured for use with your Azure subscription.

Find more information about using [Azure CLI to Create Azure Red Hat OpenShift](https://learn.microsoft.com/en-us/azure/openshift/create-cluster?tabs=azure-cli).

Let's see all these technologies in action by deploying the Todo application to an Azure Red Hat OpenShift cluster with Azure Database for PostgreSQL.
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
In this exercise, you'll establish a new Azure Red Hat OpenShift cluster, which will serve as the deployment environment for the Todo application. Subsequently, you'll create a new Azure PostgreSQL database server and configure your Quarkus application to access it.

## Create a new Azure Red Hat OpenShift cluster

To create a new Azure Red Hat OpenShift cluster, you can follow these steps:

1. Log in to the [Azure Portal](https://portal.azure.com) and sign in with your Azure credentials.

2. Create a resource group: A resource group is a logical container for related Azure resources. Click on `Create a resource` and search for `Resource group`. Choose a name and location for your resource group and click `Create`.

3. Create an OpenShift cluster: Search for `OpenShift` in the Azure marketplace and select `OpenShift`. Click `Create` to start the deployment process.

4. Configure your cluster: In the deployment wizard, you'll need to specify the following:

* **Subscription**: Choose your available Azure subscription.
* **Resource group**: Select the resource group you created in step 2.
* **Region**: Choose a region for your cluster.
* **OpenShift cluster name**: Choose a unique name for your cluster (e.g., `todo-aro-cluster`).
* **Domain name**: Specify the domain name for your cluster. You can use the randomly generated domain name.
* **OpenShift cluster version**: Select the OpenShift version for your cluster (e.g., `4.15.27 (latest)`).
* **Master VM size**: Choose the size of the virtual machines for your master nodes.
* **Worker VM size**: Choose the size of the virtual machines for your worker nodes.
* **Worker node count**: Choose the number of worker nodes for your cluster.

> [!NOTE]
> You can leave the default values in _Authentication_, _Network_, and _Tags_ settings section.
5. Review and create: Review your cluster configuration and click `Create` to start the deployment process.

6. Monitor the deployment: The deployment process may take more than 60 minutes to complete. You can monitor the progress in the Azure portal.

Once your cluster is deployed, you can access it using the OpenShift web console. You can find the URL for the web console in the cluster's overview page.

![ARO Deployment is complete](../media/aro-deployment-complete.png)

> 💡 **Tip:**:
> If you're not sure which region to choose, you can select a region that is closest to your users to reduce latency.
More resources for Azure Red Hat OpenShift deployments:

* [Azure CLI to Create Azure Red Hat OpenShift](https://learn.microsoft.com/en-us/azure/openshift/create-cluster?tabs=azure-cli)
* [Deploying an Azure Red Hat OpenShift cluster in the Azure portal](https://youtu.be/iY66MONBfVQ?si=m1HH3SWPOokGVXSY)

## Create an instance of Azure Database for PostgreSQL

To create an instance of Azure Database for PostgreSQL, follow these steps:

1. Log in to the [Azure Portal](https://portal.azure.com) and sign in with your Azure credentials.

2. Create a resource group or choose an existing one.

3. Create an Azure Database for PostgreSQL: In the Azure Portal, click `Create a resource` and search for `Azure Database for PostgreSQL`. Then, select `Flexible server` and fill in the required details:

* **Subscription**: Select your Azure subscription.
* **Resource group**: Choose the resource group you created earlier.
* **Server name**: Give your PostgreSQL server a unique name (e.g., `todo-postgres-server`).
* **Region**: Choose a region for your cluster.
* **PostgreSQL version**: Select the version of your PostgreSQL server (e.g., `16`).
* **Workload type**: Choose the type of workload for your PostgreSQL server (e.g., `Development`).
* **Authentication method**: Choose the authentication method for your PostgreSQL server (e.g., `PostgreSQL authentication only`).
* **Admin username**: Specify the name of the administrator user (e.g., `admin`).
* **Password**: Specify the password for the administrator user.
* **Public access**: Check the `Allow public access to this resource through the internet using a public IP address`.
* **Firewall rules**: Check the `Allow public access from any Azure service within Azure to this server`.

4. Review and create: Review your cluster configuration and click `Create` to start the deployment process.

> [!NOTE]
> You can leave the default values in other settings section.
Wait for deployment! The deployment process may take a few minutes to complete. You can monitor its progress in the Azure Portal.

Once the deployment is finished, you can connect to your PostgreSQL server using tools like pgAdmin or the Azure Data Studio. You'll need the server name, administrator login, and password.

![Azure PostgreSQL Database Deployment is complete](../media/azure-postgres-deployment-complete.png)

More Resources for creating Azure Database for PostgreSQL:

* [Quickstart: Create an Azure Database for PostgreSQL - Flexible Server instance in the Azure portal](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/quickstart-create-server-portal)

## Create a Todo database in the Azure PostgreSQL server

The PostgreSQL server that you created earlier is empty. It doesn't have any database that you can use with the Quarkus application.

Export your resource group using the following command:

> [!NOTE]
> You can run the following shell command using your local terminal or [Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/overview).
Create a new database called `Todo` by using the following command:

```shell
az postgres flexible-server db create \
--resource-group YOUR_RESOURCE_GROUP \
--database-name todo \
--server-name todo-postgres-server
```

The output should look like this:

```shell
Creating database with utf8 charset and en_US.utf8 collation
{
"charset": "UTF8",
"collation": "en_US.utf8",
"id": "/subscriptions/xxxx-xxxx-xxxx-xxxx-xxxx-xxxx/resourceGroups/my-resource-group/providers/Microsoft.DBforPostgreSQL/flexibleServers/todo-postgres-server/databases/todo",
"name": "todo",
"resourceGroup": "my-resource-group",
"systemData": null,
"type": "Microsoft.DBforPostgreSQL/flexibleServers/databases"
}
```

## Update the configuration in the Quarkus application to access the PostgreSQL database

Now let's connect the Quarkus application to the PostgreSQL database. To do so, you first need to obtain the connection string for the database.

Copy the server name on the overview page to clipboard.

![Azure PostgreSQL Database Server Name](../media/azure-postgresql-server-name.png)

`Replace` the following values in the `application.properties` file.

```properties
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://<YOUR POSTGRESQL SERVER NAME>:5432/todo
%prod.quarkus.datasource.password=<YOUR POSTGRESQL SERVER PASSWORD>
```

## Deploy the Quarkus Todo application

Quarkus also offers the ability to automatically generate OpenShift resources based on sane default and user supplied configuration. The OpenShift extension is actually a wrapper extension that brings together the [kubernetes](https://quarkus.io/guides/deploying-to-kubernetes) and [container-image-s2i](https://quarkus.io/guides/container-image#s2i) extensions with defaults so that it’s easier for the user to get started with **Quarkus on OpenShift**.

Add `quarkus-openshift` extension in Terminal:

```shell
quarkus ext add openshift
```

The output should look like this.

```shell
[SUCCESS] ✅ Extension io.quarkus:quarkus-openshift has been installed
```

Next, append the OpenShift deployment configuration to the `application.properties` file in the `src/main/resources` directory.

```properties
# OpenShift configurations
%prod.quarkus.container-image.group=quarkus-todo-postgres
%prod.quarkus.kubernetes-client.trust-certs=true
%prod.quarkus.kubernetes.deployment-target=openshift
%prod.quarkus.openshift.build-strategy=docker
%prod.quarkus.openshift.deploy=true
%prod.quarkus.openshift.route.expose=true
```

Before deploying the Todo application to ARO, be sure to log in to the OpenShift cluster via `oc` command-line tool.

* [Installing the OpenShift CLI](https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/getting-started-cli.html)

Get the token from OpenShift web consol. Then, paste the `oc login` command-line with the _token_ in Terminal.

![How to get the token in OpenShift](../media/ocp-token-login.png)

The output should look like:

```shell
Logged into "https://api.fm2aj9iw54373388db.eastus.aroapp.io:6443" as "kube:admin" using the token provided.

You have access to 72 projects, the list has been suppressed. You can list all projects with 'oc projects'

Using project "default".
```

Now let’s create a new project (Kubernetes namespace) for the Todo application deployment.

```shell
oc new-project quarkus-todo-postgres
```

The output should look like:

```shell
Now using project "quarkus-todo-postgres" on server "https://api.fm2aj9iw54373388db.eastus.aroapp.io:6443".

You can add applications to this project with the 'new-app' command. For example, try:

oc new-app rails-postgresql-example

to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:

kubectl create deployment hello-node --image=registry.k8s.io/e2e-test-images/agnhost:2.43 -- /agnhost serve-hostname
```

Next, deploy the application itself. Run the following Quarkus CLI which will build and deploy using the OpenShift extension:

```shell
quarkus build --no-tests
```

The output should end with `BUILD SUCCESS`.

Finally, make sure it’s actually done rolling out:

```shell
oc rollout status -w deployment/quarkus-todo-app-aro
```

Wait for that command to report `deployment "quarkus-todo-app-aro" successfully rolled out` before continuing.

Go to the `Topology View` in _OpenShift Dev Perspective_, make sure it’s done deploying (dark blue circle):

![OpenShift Topology](../media/topology-openshift.png)

Copy the `Route URL` to clipboard.

Access the REST API (_/api/_) to get all Todo items that store in the **Azure PostgreSQL database**. You need to replace `ROUTE-URL` with your url in the OpenShift cluster.

```shell
curl http://ROUTE-URL/api/3 ; echo
```

The output should look like:

```json
{
"completed": false,
"id": 3,
"order": 2,
"title": "Visit Quarkus web site",
"url": "https://quarkus.io"
}
```

## Connect to the Azure PostgreSQL server using Azure Cloud Shell

Open Azure Cloud Shell in the Azure portal by selecting the icon on the upper-left side:

![azure-cli](../media/azure-cli.png)

Run the following command in the Azure Cloud Shell terminal. Replace values with `your server name` and admin user login name:

```shell
psql --host=YOUR-POSTGRESQL-SERVER-NAME --port=5432 --username=quarkus --dbname=todo
```

Key the `admin password` in the prompt. Then, execute the following query to get all Todo items:

```shell
select * from todo;
```
The output should look like:
![azure-cli-psql](../media/azure-cli-psql.png)
Great job! You have successfully deployed your Todo application to ARO with Azure PostgreSQL.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
In this module, you'll explore the possibility of transforming your ToDo list application into a serverless function. Serverless functions offer several advantages, including cost-efficiency, reliability, flexibility, and enhanced security. We'll guide you through the process of deploying your application on [Red Hat OpenShift Serverless](https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless).

By the end of this module, you'll not only have a well-functioning ToDo list application deployed on ARO, but you'll also gain the knowledge and skills to potentially evolve it into a serverless function on Red Hat OpenShift Serverless.

## Red Hat OpenShift Serverless

[Red Hat OpenShift Serverless](https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless) is a platform-as-a-service (PaaS) offering from Red Hat that allows developers to build, deploy, and manage serverless functions on top of the OpenShift Kubernetes platform. It provides a simplified and managed environment for running event-driven, stateless applications without the need to provision or manage underlying infrastructure.

Key features and benefits of OpenShift Serverless:

* **Serverless architecture**: Enables developers to focus on writing code without worrying about infrastructure management.
* **Event-driven**: Functions are triggered by events, such as HTTP requests, message queue messages, or timers.
* **Scalability**: Automatically scales functions up or down based on demand, ensuring optimal resource utilization.
* **Managed environment**: Red Hat manages the underlying infrastructure, including Kubernetes, serverless runtime, and networking.
* **Integration with OpenShift**: Seamlessly integrates with other OpenShift services, such as OpenShift Pipelines for CI/CD and OpenShift Service Mesh for service-to-service communication.

Let's see all these concepts in action by creating the Todo application using OpenShift Serverless.
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
In this unit, you will deploy the exsisting Todo application as a serverless function to the Azure Red Hat OpenShift environment.

Quarkus offers Funqy extensions, enabling you to create a portable Java API for deploying functions on various serverless platforms like OpenShift Serverless (Knative), AWS Lambda, Azure Functions, and Google Cloud Functions. Unlike direct Azure Functions, Quarkus functions on OpenShift Serverless on ARO can be compiled into **native executables**, resulting in faster cold starts and significantly reduced memory footprints.

## Install OpenShift Serverless

Install the OpenShift Serverless ane Knative Serving Custom Resource (CR) with the following documents:

* [Installing the OpenShift Serverless Operator](https://docs.openshift.com/container-platform/latest/serverless/install/install-serverless-operator.html)
* [Installing Knative Serving](https://docs.openshift.com/container-platform/latest/serverless/install/installing-knative-serving.html)

You should see the deployed pods when you have successfully installed the OpenShift Serverless:

![Screenshot](../media/openshift-serverless-operator.png)

## Configure the serverless function deployment with Quarkus

**Update** the following values in `src/main/resources/application.properties` to keep the existing Todo data and deploy the application as the serverless function:

```yaml
%prod.quarkus.kubernetes.deployment-target=knative
```

**Append** the following variables in `src/main/resources/application.properties`:

```yaml
%prod.quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000
```

_Note_ that if you want to build a native executables on `macOS`, add the following configuration to use Linux binary file format:

```yaml
%prod.quarkus.native.container-build=true
```

Before the build, delete existing `todo` application by the following `oc` command:

> [!NOTE]
> If you haven't installed the OpenShift CL yet, you can install it by following this [link](https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/getting-started-cli.html).
```shell
oc delete all --all
```

## Build and deploy the serverless function

Build the native executables then deploy it to ARO. Run the following Quarkus CLI which will build and deploy using the OpenShift extension:

```shell
quarkus build --no-tests --native
```

The output should end with `BUILD SUCCESS`.

Edit the label of the serverless function pod to use the Quarkus icon.

```shell
oc label rev/quarkus-todo-app-aro-00001 app.openshift.io/runtime=quarkus --overwrite
```

If your application name is not "quarkus-todo-app-aro", you need to change it in the above `oc` command.

The output should look like:

```shell
revision.serving.knative.dev/quarkus-todo-app-aro-00001 labeled
```

## Access the serverless function

Go back to the _Topology_ view, you should see the serverless function pods running. The pod will scale down to `zero` if you didn't send traffic in `30` seconds.

Copy the `Route URL` to clipboard.

![Todo serverless pod](../media/todo-serverless-up.png)

Access the REST API (_/api/_) to get all Todo items in the **Azure PostgreSQL database**. You need to replace `ROUTE-URL` with your serverless function url in the OpenShift cluster.

```shell
curl http://ROUTE-URL/api ; echo
```

The output should look like:

```shell
[
{
"completed": false,
"id": 1,
"order": 0,
"title": "Introduction to Quarkus",
"url": null
},
{
"completed": false,
"id": 2,
"order": 1,
"title": "Hibernate with Panache",
"url": null
},
{
"completed": false,
"id": 3,
"order": 2,
"title": "Visit Quarkus web site",
"url": "https://quarkus.io"
},
{
"completed": false,
"id": 4,
"order": 3,
"title": "Visit Azure Red Hat OpenShift",
"url": "https://azure.microsoft.com/en-us/products/openshift"
}
]
```

You can also see that the servereless function pod has **scaled up** again in the _Topology view_.

![Todo scale up](../media/todo-scale-up.png)

Great! You have successfully deployed the serverless function to ARO.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
### YamlMime:Module
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres
metadata:
title: Deploy a Quarkus application to Azure Red Hat OpenShift
description: Create a Quarkus application, connect it to a PostgreSQL database, and then deploy to Azure Red Hat OpenShift.
ms.date: 10/14/2024
author: danieloh
ms.author: edburns
ms.topic: module
ms.custom: team=devdiv
ms.contributors: edburns
ms.service: azure-openshift
title: Deploy a Quarkus application to Azure Red Hat OpenShift
summary: Create a Quarkus application, connect it to a PostgreSQL database, deploy to Azure Red Hat OpenShift, and evolve to serverless functions.
abstract: |
In this module, you:
- Create a new ToDo application using Quarkus.
- Package and Run Locally.
- Deploy the Todo Application to Azure Red Hat OpenShift with Azure Database for PostgreSQL.
- Evolve the ToDo application to OpenShift Serverless.
prerequisites: |
- An Azure subscription
- JDK 17+ installed with JAVA_HOME configured appropriately
- Apache Maven 3.9.8
- Azure CLI 2.64.0+
- Podman or Docker
- Quarkus CLI
iconUrl: /training/achievements/generic-badge.svg
levels:
- intermediate
roles:
- developer
products:
- azure
- azure-openshift
- azure-database-postgresql
- quarkus
subjects:
- custom-app-development
units:
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.1-introduction
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.2-create-quarkus-todo-app
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.3-exercise-create-quarkus-todo-app
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.4-package-run-locally
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.5-exercise-package-run-locally
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.6-deploy-aro-postgresql
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.7-exercise-deploy-aro-postgresql
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.8-evolve-openshift-serverless
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.9-exercise-evolve-openshift-serverless
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.10-summary
badge:
uid: learn.azure.deploy-java-quarkus-red-hat-openshift-postgres.badge
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions learn-pr/paths/get-started-java-azure/index.yml
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@ modules:
- learn.java-target-destinations
- learn.azure.deploy-java-spring-boot-app-service-mysql
- learn.azure.deploy-java-quarkus-azure-container-app-postgres
- learn.azure.deploy-java-quarkus-red-hat-openshift-postgres
- learn.azure.build-webapp-java-tomcat
- learn.azure-spring-cloud-workshop
- learn.azure.deploy-event-driven-real-time