Skip to content

Commit

Permalink
Google Cloud Functions http bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
loicmathieu committed Jun 8, 2020
1 parent 26e8edb commit a34a753
Show file tree
Hide file tree
Showing 18 changed files with 807 additions and 2 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ci-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ jobs:
java :
- { name: Java8,
java-version: 8,
maven_args: "-pl !integration-tests/vault-app,!integration-tests/vault-agroal,!integration-tests/vault"
maven_args: "-pl !integration-tests/vault-app,!integration-tests/vault-agroal,!integration-tests/vault,!integration-tests/google-cloud-functions-http"
}
- {
name: "Java 8 - 242",
java-version: 8,
release: "jdk8u242-b08"
release: "jdk8u242-b08",
maven_args: "-pl !integration-tests/vault-app,!integration-tests/vault-agroal,!integration-tests/vault,!integration-tests/google-cloud-functions-http"
}
- {
name: Java 11,
Expand Down
6 changes: 6 additions & 0 deletions bom/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-google-cloud-functions-http-deployment</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Quarkus extension dependencies -->
<dependency>
<groupId>org.webjars</groupId>
Expand Down
11 changes: 11 additions & 0 deletions bom/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@

<picocli.version>4.3.2</picocli.version>
<org.eclipse.sisu.inject.version>0.3.4</org.eclipse.sisu.inject.version>
<google-cloud-functions.version>1.0.1</google-cloud-functions.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -1040,6 +1041,11 @@
<artifactId>quarkus-cache</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-google-cloud-functions-http</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Quarkus test dependencies -->
<dependency>
Expand Down Expand Up @@ -1193,6 +1199,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>${google-cloud-functions.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down
214 changes: 214 additions & 0 deletions docs/src/main/asciidoc/gcp-functions-http.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
////
This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc
////
= Quarkus - Google Cloud Functions (Serverless) with RESTEasy, Undertow, or Vert.x Web
:extension-status: preview

include::./attributes.adoc[]

The `quarkus-google-cloud-functions-http` extension allows you to write microservices with RESTEasy (JAX-RS),
Undertow (servlet) or Vert.x Web, and make these microservices deployable to the Google Cloud Functions runtime.

One Google Cloud Functions deployment can represent any number of JAX-RS, servlet, or Vert.x Web endpoints.

include::./status-include.adoc[]

== Prerequisites

To complete this guide, you need:

* less than 15 minutes
* JDK 11 (Google Cloud Functions requires JDK 11)
* Apache Maven {maven-version}
* https://cloud.google.com/[A Google Cloud Account]. Free accounts work.
* https://cloud.google.com/sdk[Cloud SDK CLI Installed]

== Solution

This guide walks you through running a Maven Archetype to generate a sample project then creating three http endpoints
written with JAX-RS APIs, Servlet APIs or Vert.x Web APIs. After building, you will then be able to deploy
to Google Cloud.

== Creating the Maven Deployment Project

Create an application with the `quarkus-google-cloud-functions-http` extension.
You can use the following Maven command to create it:

[source,shell,subs=attributes+]
----
mvn io.quarkus:quarkus-maven-plugin:{quarkus-version}:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=google-cloud-functions-http \
-DclassName="org.acme.quickstart.GreetingResource" \
-Dpath="/hello" \
-Dextensions="google-cloud-functions-http,resteasy-json,undertow,vertx-web"
----

== Login to Google Cloud

If you don't login to Google Cloud you won't be able to deploy.

[source, subs=attributes+]
----
gcloud auth login
----

At the time writing this guide, Cloud Functions are still in beta so make sure to install the `beta` command group.

[source, subs=attributes+]
----
gcloud components install beta
----

== Creating the endpoints

For this example project, we will create three endpoints, one for RESTEasy (JAX-RS), one for Undertow (Servlet)
and one for Vert.x Web (reactive routes).

If you don't want endpoints to all these technologies, you can remove the unnecessary extensions from your `pom.xml`.

=== The JAX-RS endpoint

[source,java]
----
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
----

=== The Servlet endpoint

[source,java]
----
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "ServletGreeting", urlPatterns = "/servlet/hello")
public class GreetingServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(200);
resp.addHeader("Content-Type", "text/plain");
resp.getWriter().write("hello");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getReader().readLine();
resp.setStatus(200);
resp.addHeader("Content-Type", "text/plain");
resp.getWriter().write("hello " + name);
}
}
----

=== The Vert.x Web endpoint

[source,java]
----
import static io.vertx.core.http.HttpMethod.GET;
import io.quarkus.vertx.web.Route;
import io.vertx.ext.web.RoutingContext;
public class GreetingRoutes {
@Route(path = "/vertx/hello", methods = GET)
void hello(RoutingContext context) {
context.response().headers().set("Content-Type", "text/plain");
context.response().setStatusCode(200).end("hello");
}
}
----

== Build and Deploy to Google Cloud

To build your application, you first need to define a packaging of type `uber-jar` via your `application.properties`.

[source]
----
quarkus.package.uber-jar=true
----

Then you can package your application via `mvn clean package`.
You will have a single JAR inside the target repository that contains your classes and all your dependencies in it.

To deploy your JAR to Google Cloud, you need to pass a directory with only this JAR inside it, to the `gcloud` utility.

So first, create a `deployment` directory and copy the generated artifact inside it.

[source]
----
mkdir deployment
cp target/google-cloud-functions-http-1.0-SNAPSHOT-runner.jar deployment/
----

Then you will be able to use `gcloud` to deploy your function to Google Cloud.

[source]
----
gcloud beta functions deploy quarkus-example-http \
--entry-point=io.quarkus.gcp.functions.http.QuarkusHttpFunction \
--runtime=java11 --trigger-http --source=deployment
----

[WARNING]
----
The first time you launch this command, you can have the following error message:
```
ERROR: (gcloud.beta.functions.deploy) OperationError: code=7, message=Build Failed: Cloud Build has not been used in project <project_name> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=<my-project> then retry.
```
This means that Cloud Build is not activated yet, please go to the mentionned URL to activate it, wait a few minutes and retry the command.
----

The entry point always needs to be `io.quarkus.gcp.functions.http.QuarkusHttpFunction` as it will be this class
that bootstraps Quarkus.

This command will give you as output a `httpsTrigger.url` that point to your function.

You can then call your endpoints via:

- For JAX-RS: {httpsTrigger.url}/hello
- For servlet: {httpsTrigger.url}/servlet/hello
- For Vert.x Web: {httpsTrigger.url}/vertx/hello

== Testing locally

The easiest way to locally test your function is using the Cloud Function invoker JAR.

You can download it via Maven using the following command:

[source]
----
mvn dependency:copy \
-Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.0.0-beta1' \
-DoutputDirectory=.
----

Then you can use it to launch your function locally.

[source]
----
java -jar java-function-invoker-1.0.0-beta1.jar \
--classpath target/google-cloud-functions-http-1.0-SNAPSHOT-runner.jar \
--target io.quarkus.gcp.functions.http.QuarkusHttpFunction
----

Your endpoints will be available on http://localhost:8080.
47 changes: 47 additions & 0 deletions extensions/google-cloud-functions-http/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-google-cloud-functions-http-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-google-cloud-functions-http-deployment</artifactId>
<name>Quarkus - HTTP Google Cloud Functions - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-http-deployment</artifactId>
</dependency>
<dependency>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>svm</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.quarkus.gcp.functions.http.deployment;

import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.vertx.http.deployment.RequireVirtualHttpBuildItem;

public class GoogleCloudFunctionsHttpProcessor {
private static final String FEATURE_NAME = "google-cloud-functions-http";

@BuildStep
public FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE_NAME);
}

@BuildStep
public RunTimeConfigurationDefaultBuildItem disableBanner() {
// the banner is not displayed well inside the Google Cloud Function logs
return new RunTimeConfigurationDefaultBuildItem("quarkus.banner.enabled", "false");
}

@BuildStep
public RequireVirtualHttpBuildItem requestVirtualHttp(LaunchModeBuildItem launchMode) {
return launchMode.getLaunchMode() == LaunchMode.NORMAL ? RequireVirtualHttpBuildItem.MARKER : null;
}
}
22 changes: 22 additions & 0 deletions extensions/google-cloud-functions-http/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-build-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../../build-parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-google-cloud-functions-http-parent</artifactId>
<name>Quarkus - HTTP Google Cloud Functions</name>
<packaging>pom</packaging>

<modules>
<module>runtime</module>
<module>deployment</module>
</modules>

</project>
Loading

0 comments on commit a34a753

Please sign in to comment.