mirror of https://github.com/knative/docs.git
[release-1.0] Move community docs onto MkDocs site (#4559)
* Move community docs onto MkDocs site * Edit about community processes * Will this fix the tests? * Add redirects * Fix broken redirects * Change folder name and fix samples * lint * more lint * Fix code snippet * style tweak * Add signing the CLA as a prereq and update serving issue link * Capitalization * Clarify roles * lint Co-authored-by: snneji <snneji@vmware.com>
This commit is contained in:
parent
233dad36a9
commit
22ee342cf8
|
@ -0,0 +1,7 @@
|
|||
# Knative code samples
|
||||
|
||||
Find and use Knative code samples to help you get up and running with common use
|
||||
cases. Code samples include content from the Knative team and community members.
|
||||
|
||||
Browse all code samples to find other languages and use cases that might align
|
||||
closer with your goals.
|
|
@ -0,0 +1,42 @@
|
|||
# Community code samples
|
||||
|
||||
Get up and running with one of the community code samples. These samples are
|
||||
contributed and maintained by members of the Knative community.
|
||||
|
||||
!!! note
|
||||
These samples might become outdated or the original author might be unable
|
||||
to maintain their contribution. If you find that something isn't working,
|
||||
lend a helping hand and fix it in a PR.
|
||||
|
||||
[Learn more about the lifespan of samples](https://github.com/knative/docs/blob/main/contribute-to-docs/what-to-contribute/creating-code-samples.md#user-focused-content)
|
||||
|
||||
[**See all Knative code samples**](../README.md)
|
||||
|
||||
## Interactive Serving sample
|
||||
|
||||
Check out this [Katacoda tutorial](https://www.katacoda.com/swapb/scenarios/knative-intro)
|
||||
which guides you through installing Knative and the `kn` command line tool, deploying a
|
||||
sample container, updating your deployment, and performing a traffic split
|
||||
between the two versions.
|
||||
|
||||
## Serving samples
|
||||
|
||||
Knative Serving sample apps.
|
||||
|
||||
| Sample Name | Description | Language(s) |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| Hello World | A quick introduction to Knative Serving that highlights how to deploy an app. | [Clojure](serving/helloworld-clojure/), [Dart](serving/helloworld-dart/), [Elixir](serving/helloworld-elixir/), [Haskell](serving/helloworld-haskell/), [Java - Micronaut](serving/helloworld-java-micronaut/), [Java - Quarkus](serving/helloworld-java-quarkus/), [R - Go Server](serving/helloworld-r/), [Rust](serving/helloworld-rust/), [Swift](serving/helloworld-swift/), [Vertx](serving/helloworld-vertx/) |
|
||||
| Machine Learning | A quick introduction to using Knative Serving to serve machine learning models | [Python - BentoML](serving/machinelearning-python-bentoml)
|
||||
|
||||
### Eventing and Eventing Resources samples
|
||||
|
||||
_Be the first to contribute an Eventing or Eventing Sources code sample to the
|
||||
community collection._
|
||||
|
||||
## Client samples
|
||||
|
||||
Knative `kn` Client sample workflows and apps.
|
||||
|
||||
| Sample Name | Description |
|
||||
| ----------- | ----------- |
|
||||
| [knfun](https://github.com/maximilien/knfun) | Knative micro-functions (Twitter and Watson APIs) demo using the `kn` client. |
|
|
@ -0,0 +1,3 @@
|
|||
# Knative Serving code samples
|
||||
|
||||
Community contributed and maintained code samples for Knative Serving.
|
|
@ -0,0 +1,14 @@
|
|||
pom.xml
|
||||
pom.xml.asc
|
||||
*.jar
|
||||
*.class
|
||||
/lib/
|
||||
/classes/
|
||||
/target/
|
||||
/checkouts/
|
||||
.lein-deps-sum
|
||||
.lein-repl-history
|
||||
.lein-plugins/
|
||||
.lein-failures
|
||||
.nrepl-port
|
||||
.cpcache/
|
|
@ -0,0 +1,17 @@
|
|||
# Use the official Clojure image.
|
||||
# https://hub.docker.com/_/clojure
|
||||
FROM clojure
|
||||
|
||||
# Create the project and download dependencies.
|
||||
WORKDIR /usr/src/app
|
||||
COPY project.clj .
|
||||
RUN lein deps
|
||||
|
||||
# Copy local code to the container image.
|
||||
COPY . .
|
||||
|
||||
# Build an uberjar release artifact.
|
||||
RUN mv "$(lein uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar
|
||||
|
||||
# Run the web service on container startup.
|
||||
CMD ["java", "-jar", "app-standalone.jar"]
|
|
@ -0,0 +1,157 @@
|
|||
# Hello World - Clojure
|
||||
|
||||
A simple web app written in Clojure that you can use for testing. It reads in an
|
||||
env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
||||
specified, it will use "World" as the TARGET.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||
[Knative installation instructions](https://knative.dev/docs/install/) if you need to create
|
||||
one.
|
||||
- [Docker](https://www.docker.com) installed and running on your local machine,
|
||||
and a Docker Hub account configured (we'll use it for a container registry).
|
||||
|
||||
## Recreating the sample code
|
||||
|
||||
While you can clone all of the code from this directory, hello world apps are
|
||||
generally more useful if you build them step-by-step. The following instructions
|
||||
recreate the source files from this folder.
|
||||
|
||||
1. Create a new file named `src/helloworld/core.clj` and paste the following
|
||||
code. This code creates a basic web server which listens on port 8080:
|
||||
|
||||
```clojure
|
||||
(ns helloworld.core
|
||||
(:use ring.adapter.jetty)
|
||||
(:gen-class))
|
||||
|
||||
(defn handler [request]
|
||||
{:status 200
|
||||
:headers {"Content-Type" "text/html"}
|
||||
:body (str "Hello "
|
||||
(if-let [target (System/getenv "TARGET")]
|
||||
target
|
||||
"World")
|
||||
"!\n")})
|
||||
|
||||
(defn -main [& args]
|
||||
(run-jetty handler {:port (if-let [port (System/getenv "PORT")]
|
||||
(Integer/parseInt port)
|
||||
8080)}))
|
||||
```
|
||||
|
||||
1. In your project directory, create a file named `project.clj` and copy the
|
||||
code below into it. This code defines the project's dependencies and
|
||||
entrypoint.
|
||||
|
||||
```clojure
|
||||
(defproject helloworld "1.0.0-SNAPSHOT"
|
||||
:description "Hello World - Clojure sample"
|
||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||
[ring/ring-core "1.6.3"]
|
||||
[ring/ring-jetty-adapter "1.6.3"]]
|
||||
:main helloworld.core)
|
||||
```
|
||||
|
||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||
block below into it. For detailed instructions on dockerizing a Clojure app,
|
||||
see
|
||||
[the clojure image documentation](https://github.com/docker-library/docs/tree/master/clojure).
|
||||
|
||||
```docker
|
||||
# Use the official Clojure image.
|
||||
# https://hub.docker.com/_/clojure
|
||||
FROM clojure
|
||||
|
||||
# Create the project and download dependencies.
|
||||
WORKDIR /usr/src/app
|
||||
COPY project.clj .
|
||||
RUN lein deps
|
||||
|
||||
# Copy local code to the container image.
|
||||
COPY . .
|
||||
|
||||
# Build an uberjar release artifact.
|
||||
RUN mv "$(lein uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar
|
||||
|
||||
# Run the web service on container startup.
|
||||
CMD ["java", "-jar", "app-standalone.jar"]
|
||||
```
|
||||
|
||||
1. Create a new file, `service.yaml` and copy the following service definition
|
||||
into the file. Make sure to replace `{username}` with your Docker Hub
|
||||
username.
|
||||
|
||||
```yaml
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-clojure
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-clojure
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Clojure Sample v1"
|
||||
```
|
||||
|
||||
## Building and deploying the sample
|
||||
|
||||
Once you have recreated the sample code files (or used the files in the sample
|
||||
folder) you're ready to build and deploy the sample app.
|
||||
|
||||
1. Use Docker to build the sample code into a container. To build and push with
|
||||
Docker Hub, run these commands replacing `{username}` with your Docker Hub
|
||||
username:
|
||||
|
||||
```bash
|
||||
# Build the container on your local machine
|
||||
docker build -t {username}/helloworld-clojure .
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/helloworld-clojure
|
||||
```
|
||||
|
||||
1. After the build has completed and the container is pushed to docker hub, you
|
||||
can deploy the app into your cluster. Ensure that the container image value
|
||||
in `service.yaml` matches the container you built in the previous step. Apply
|
||||
the configuration using `kubectl`:
|
||||
|
||||
```bash
|
||||
kubectl apply --filename service.yaml
|
||||
```
|
||||
|
||||
1. Now that your service is created, Knative will perform the following steps:
|
||||
|
||||
- Create a new immutable revision for this version of the app.
|
||||
- Network programming to create a route, ingress, service, and load balance
|
||||
for your app.
|
||||
- Automatically scale your pods up and down (including to zero active pods).
|
||||
|
||||
1. To find the URL for your service, use
|
||||
|
||||
```
|
||||
kubectl get ksvc helloworld-clojure --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||
NAME URL
|
||||
helloworld-clojure http://helloworld-clojure.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
1. Now you can make a request to your app and see the result. Replace
|
||||
the URL below with the URL returned in the previous command.
|
||||
|
||||
```bash
|
||||
curl http://helloworld-clojure.default.1.2.3.4.sslip.io
|
||||
Hello World!
|
||||
```
|
||||
|
||||
## Removing the sample app deployment
|
||||
|
||||
To remove the sample app from your cluster, delete the service record:
|
||||
|
||||
```bash
|
||||
kubectl delete --filename service.yaml
|
||||
```
|
|
@ -0,0 +1,6 @@
|
|||
(defproject helloworld "1.0.0-SNAPSHOT"
|
||||
:description "Hello World - Clojure sample"
|
||||
:dependencies [[org.clojure/clojure "1.9.0"]
|
||||
[ring/ring-core "1.6.3"]
|
||||
[ring/ring-jetty-adapter "1.6.3"]]
|
||||
:main helloworld.core)
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-clojure
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-clojure
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Clojure Sample v1"
|
|
@ -0,0 +1,17 @@
|
|||
(ns helloworld.core
|
||||
(:use ring.adapter.jetty)
|
||||
(:gen-class))
|
||||
|
||||
(defn handler [request]
|
||||
{:status 200
|
||||
:headers {"Content-Type" "text/html"}
|
||||
:body (str "Hello "
|
||||
(if-let [target (System/getenv "TARGET")]
|
||||
target
|
||||
"World")
|
||||
"!\n")})
|
||||
|
||||
(defn -main [& args]
|
||||
(run-jetty handler {:port (if-let [port (System/getenv "PORT")]
|
||||
(Integer/parseInt port)
|
||||
8080)}))
|
|
@ -0,0 +1,4 @@
|
|||
# See https://www.dartlang.org/guides/libraries/private-files
|
||||
.dart_tool
|
||||
.packages
|
||||
pubspec.lock
|
|
@ -0,0 +1,7 @@
|
|||
# Use Google's official Dart image.
|
||||
# https://hub.docker.com/r/google/dart-runtime/
|
||||
FROM google/dart-runtime
|
||||
|
||||
# ONBUILD instructions for COPY and pub get is defined in the google/dart-runtime image,
|
||||
# allowing you to keep this file very simple, see:
|
||||
# https://github.com/dart-lang/dart_docker/blob/master/runtime/Dockerfile.template#L15-L18
|
|
@ -0,0 +1,155 @@
|
|||
# Hello World - Dart
|
||||
|
||||
A simple web app written in the [Dart](https://www.dart.dev) programming language
|
||||
that you can use for testing. It reads in the env variable `TARGET` and prints
|
||||
`"Hello $TARGET"`. If `TARGET` is not specified, it will use `"World"` as
|
||||
`TARGET`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||
[Knative installation instructions](https://knative.dev/docs/install/) if you need to create
|
||||
one.
|
||||
- [Docker](https://www.docker.com) installed and running on your local machine,
|
||||
and a Docker Hub account configured (we'll use it for a container registry).
|
||||
- [dart-sdk](https://www.dart.dev/tools/sdk#install) installed and
|
||||
configured if you want to run the program locally.
|
||||
|
||||
## Recreating the sample code
|
||||
|
||||
While you can clone all of the code from this directory, it is useful to know
|
||||
how to build a hello world Dart application step-by-step. This application can
|
||||
be created using the following instructions.
|
||||
|
||||
1. Create a new directory and write `pubspec.yaml` as follows:
|
||||
|
||||
```yaml
|
||||
name: hello_world_dart
|
||||
publish_to: none # let's not accidentally publish this to pub.dartlang.org
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
shelf: ^1.0.0
|
||||
```
|
||||
|
||||
2. If you want to run locally, install dependencies. If you only want to run in
|
||||
Docker or Knative, you can skip this step.
|
||||
|
||||
```bash
|
||||
> pub get
|
||||
```
|
||||
|
||||
3. Create a new file `bin/server.dart` and write the following code:
|
||||
|
||||
```dart
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf/shelf_io.dart';
|
||||
|
||||
Future main() async {
|
||||
// Find port to listen on from environment variable.
|
||||
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
||||
|
||||
// Read $TARGET from environment variable.
|
||||
final target = Platform.environment['TARGET'] ?? 'World';
|
||||
|
||||
Response handler(Request request) => Response.ok('Hello $target');
|
||||
|
||||
// Serve handler on given port.
|
||||
final server = await serve(
|
||||
const Pipeline().addMiddleware(logRequests()).addHandler(handler),
|
||||
InternetAddress.anyIPv4,
|
||||
port,
|
||||
);
|
||||
print('Serving at http://${server.address.host}:${server.port}');
|
||||
}
|
||||
```
|
||||
|
||||
4. Create a new file named `Dockerfile`, this file defines instructions for
|
||||
dockerizing your applications, for dart apps this can be done as follows:
|
||||
|
||||
```Dockerfile
|
||||
# Use Google's official Dart image.
|
||||
# https://hub.docker.com/r/google/dart-runtime/
|
||||
FROM google/dart-runtime
|
||||
```
|
||||
|
||||
5. Create a new file, `service.yaml` and copy the following service definition
|
||||
into the file. Make sure to replace `{username}` with your Docker Hub
|
||||
username.
|
||||
|
||||
```yaml
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-dart
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-dart
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Dart Sample v1"
|
||||
```
|
||||
|
||||
## Building and deploying the sample
|
||||
|
||||
Once you have recreated the sample code files (or used the files in the sample
|
||||
folder) you're ready to build and deploy the sample app.
|
||||
|
||||
1. Use Docker to build the sample code into a container. To build and push with
|
||||
Docker Hub, run these commands replacing `{username}` with your Docker Hub
|
||||
username:
|
||||
|
||||
```bash
|
||||
# Build the container on your local machine
|
||||
docker build -t {username}/helloworld-dart .
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/helloworld-dart
|
||||
```
|
||||
|
||||
1. After the build has completed and the container is pushed to docker hub, you
|
||||
can deploy the app into your cluster. Ensure that the container image value
|
||||
in `service.yaml` matches the container you built in the previous step. Apply
|
||||
the configuration using `kubectl`:
|
||||
|
||||
```bash
|
||||
kubectl apply --filename service.yaml
|
||||
```
|
||||
|
||||
1. Now that your service is created, Knative will perform the following steps:
|
||||
|
||||
- Create a new immutable revision for this version of the app.
|
||||
- Network programming to create a route, ingress, service, and load balance
|
||||
for your app.
|
||||
- Automatically scale your pods up and down (including to zero active pods).
|
||||
|
||||
1. To find the URL for your service, use
|
||||
|
||||
```
|
||||
kubectl get ksvc helloworld-dart --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||
NAME URL
|
||||
helloworld-dart http://helloworld-dart.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
1. Now you can make a request to your app and see the result. Replace
|
||||
the URL below with the URL returned in the previous command.
|
||||
|
||||
```bash
|
||||
curl http://helloworld-dart.default.1.2.3.4.sslip.io
|
||||
Hello Dart Sample v1
|
||||
```
|
||||
|
||||
## Removing the sample app deployment
|
||||
|
||||
To remove the sample app from your cluster, delete the service record:
|
||||
|
||||
```bash
|
||||
kubectl delete --filename service.yaml
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:shelf/shelf.dart';
|
||||
import 'package:shelf/shelf_io.dart';
|
||||
|
||||
Future main() async {
|
||||
// Find port to listen on from environment variable.
|
||||
final port = int.parse(Platform.environment['PORT'] ?? '8080');
|
||||
|
||||
// Read $TARGET from environment variable.
|
||||
final target = Platform.environment['TARGET'] ?? 'World';
|
||||
|
||||
Response handler(Request request) => Response.ok('Hello $target');
|
||||
|
||||
// Serve handler on given port.
|
||||
final server = await serve(
|
||||
const Pipeline().addMiddleware(logRequests()).addHandler(handler),
|
||||
InternetAddress.anyIPv4,
|
||||
port,
|
||||
);
|
||||
print('Serving at http://${server.address.host}:${server.port}');
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
name: hello_world_dart
|
||||
publish_to: none # let's not accidentally publish this to pub.dartlang.org
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
dependencies:
|
||||
shelf: ^1.0.0
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-dart
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-dart
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Dart Sample v1"
|
|
@ -0,0 +1,2 @@
|
|||
Dockerfile
|
||||
README.md
|
|
@ -0,0 +1,8 @@
|
|||
FROM hayd/alpine-deno:1.0.0-rc2
|
||||
WORKDIR /app
|
||||
|
||||
# These steps will be re-run upon each file change in your working directory:
|
||||
COPY . ./
|
||||
|
||||
# Added to ENTRYPOINT of base image.
|
||||
CMD ["run", "--allow-env", "--allow-net", "main.ts"]
|
|
@ -0,0 +1,144 @@
|
|||
# Hello World - Deno
|
||||
|
||||
A simple web app written in Deno.
|
||||
|
||||
Follow the steps below to create the sample code and then deploy the app to your
|
||||
cluster. You can also download a working copy of the sample, by running the
|
||||
following commands:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/knative/docs.git knative-docs
|
||||
cd knative-docs/code-samples/community/hello-world/helloworld-deno
|
||||
```
|
||||
|
||||
## Before you begin
|
||||
|
||||
- A Kubernetes cluster with Knative installed. Follow the
|
||||
[Knative installation instructions](https://knative.dev/docs/install/) if you need to
|
||||
create one.
|
||||
- [Docker](https://www.docker.com) installed and running on your local machine,
|
||||
and a Docker Hub account configured (we'll use it for a container registry).
|
||||
|
||||
## Recreating the sample code
|
||||
|
||||
1. Create a new file named `deps.ts` and paste the following script:
|
||||
|
||||
```ts
|
||||
export { serve } from "https://deno.land/std@std@0.50.0/http/server.ts";
|
||||
```
|
||||
|
||||
1. Create a new file named `main.ts` and paste the following script:
|
||||
|
||||
```ts
|
||||
import { serve } from "./deps.ts";
|
||||
import "https://deno.land/x/dotenv/mod.ts";
|
||||
|
||||
const PORT = Deno.env.get('PORT') || 8080;
|
||||
const s = serve(`0.0.0.0:${PORT}`);
|
||||
const body = new TextEncoder().encode("Hello Deno\n");
|
||||
|
||||
console.log(`Server started on port ${PORT}`);
|
||||
for await (const req of s) {
|
||||
req.respond({ body });
|
||||
}
|
||||
```
|
||||
|
||||
1. Create a new file named `Dockerfile` and copy the code block below into it.
|
||||
|
||||
```docker
|
||||
FROM hayd/alpine-deno:1.0.0-rc2
|
||||
WORKDIR /app
|
||||
|
||||
# These steps will be re-run upon each file change in your working directory:
|
||||
COPY . ./
|
||||
|
||||
# Added to ENTRYPOINT of base image.
|
||||
CMD ["run", "--allow-env", "--allow-net", "main.ts"]
|
||||
```
|
||||
|
||||
1. Create a new file, `service.yaml` and copy the following service definition
|
||||
into the file. Make sure to replace `{username}` with your Docker Hub
|
||||
username.
|
||||
|
||||
```yaml
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-deno
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-deno
|
||||
```
|
||||
|
||||
## Building and deploying the sample
|
||||
|
||||
Once you have recreated the sample code files (or used the files in the sample
|
||||
folder) you're ready to build and deploy the sample app.
|
||||
|
||||
1. Use Docker to build the sample code into a container. To build and push with
|
||||
Docker Hub, run these commands replacing `{username}` with your Docker Hub
|
||||
username:
|
||||
|
||||
```bash
|
||||
# Build the container on your local machine
|
||||
docker build -t {username}/helloworld-deno .
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/helloworld-deno
|
||||
```
|
||||
|
||||
1. After the build has completed and the container is pushed to docker hub, you
|
||||
can deploy the app into your cluster. Ensure that the container image value
|
||||
in `service.yaml` matches the container you built in the previous step. Apply
|
||||
the configuration using `kubectl`:
|
||||
|
||||
```bash
|
||||
kubectl apply --filename service.yaml
|
||||
```
|
||||
|
||||
1. Now that your service is created, Knative performs the following steps:
|
||||
|
||||
- Create a new immutable revision for this version of the app.
|
||||
- Network programming to create a route, ingress, service, and load balance
|
||||
for your app.
|
||||
- Automatically scale your pods up and down (including to zero active pods).
|
||||
|
||||
1. Run the following command to find the domain URL for your service:
|
||||
|
||||
```bash
|
||||
kubectl get ksvc helloworld-deno --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
NAME URL
|
||||
helloworld-deno http://helloworld-deno.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
1. Now you can make a request to your app and see the result. Replace
|
||||
the URL below with the URL returned in the previous command.
|
||||
|
||||
```bash
|
||||
curl http://helloworld-deno.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
curl http://helloworld-deno.default.1.2.3.4.sslip.io
|
||||
[1] "Hello R Sample v1!"
|
||||
```
|
||||
|
||||
> Note: Add `-v` option to get more detail if the `curl` command failed.
|
||||
|
||||
## Removing the sample app deployment
|
||||
|
||||
To remove the sample app from your cluster, delete the service record:
|
||||
|
||||
```bash
|
||||
kubectl delete --filename service.yaml
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
export { serve } from "https://deno.land/std@0.50.0/http/server.ts";
|
|
@ -0,0 +1,11 @@
|
|||
import { serve } from "./deps.ts";
|
||||
import "https://deno.land/x/dotenv/mod.ts";
|
||||
|
||||
const PORT = Deno.env.get('PORT') || 8080;
|
||||
const s = serve(`0.0.0.0:${PORT}`);
|
||||
const body = new TextEncoder().encode("Hello Deno\n");
|
||||
|
||||
console.log(`Server started on port ${PORT}`);
|
||||
for await (const req of s) {
|
||||
req.respond({ body });
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
# For building with Google Cloud Build using the gcloud command line tool.
|
||||
# Similar to .gitignore, except we want the /config/*.secrete.exs uploaded for the build.
|
||||
|
||||
# App artifacts
|
||||
/_build
|
||||
/db
|
||||
/deps
|
||||
/*.ez
|
||||
|
||||
# Generated on crash by the VM
|
||||
erl_crash.dump
|
||||
|
||||
# Generated on crash by NPM
|
||||
npm-debug.log
|
||||
/assets/package-lock.json
|
||||
|
||||
# Static artifacts
|
||||
/assets/node_modules
|
||||
|
||||
# Since we are building assets from assets/,
|
||||
# we ignore priv/static. You may want to comment
|
||||
# this depending on your deployment strategy.
|
||||
/priv/static/
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# App artifacts
|
||||
/_build
|
||||
/db
|
||||
/deps
|
||||
/*.ez
|
||||
|
||||
# Generated on crash by the VM
|
||||
erl_crash.dump
|
||||
|
||||
# Generated on crash by NPM
|
||||
npm-debug.log
|
||||
/assets/package-lock.json
|
||||
|
||||
# Static artifacts
|
||||
/assets/node_modules
|
||||
|
||||
# Since we are building assets from assets/,
|
||||
# we ignore priv/static. You may want to comment
|
||||
# this depending on your deployment strategy.
|
||||
/priv/static/
|
||||
|
||||
# Files matching config/*.secret.exs pattern contain sensitive
|
||||
# data and you should not commit them into version control.
|
||||
#
|
||||
# Alternatively, you may comment the line below and commit the
|
||||
# secrets files as long as you replace their contents by environment
|
||||
# variables.
|
||||
/config/*.secret.exs
|
|
@ -0,0 +1,38 @@
|
|||
FROM elixir:1.6.6-alpine
|
||||
|
||||
ARG APP_NAME=hello
|
||||
ARG PHOENIX_SUBDIR=.
|
||||
ENV MIX_ENV=prod REPLACE_OS_VARS=true TERM=xterm
|
||||
WORKDIR /opt/app
|
||||
RUN apk update \
|
||||
&& apk --no-cache --update add nodejs nodejs-npm \
|
||||
&& mix local.rebar --force \
|
||||
&& mix local.hex --force
|
||||
COPY . .
|
||||
|
||||
RUN mix do deps.get, deps.compile, compile
|
||||
RUN cd ${PHOENIX_SUBDIR}/assets \
|
||||
&& npm install \
|
||||
&& ./node_modules/brunch/bin/brunch build -p \
|
||||
&& cd .. \
|
||||
&& mix phx.digest
|
||||
RUN mix release --env=prod --verbose \
|
||||
&& mv _build/prod/rel/${APP_NAME} /opt/release \
|
||||
&& mv /opt/release/bin/${APP_NAME} /opt/release/bin/start_server
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk update && apk --no-cache --update add bash openssl-dev ca-certificates
|
||||
|
||||
RUN addgroup -g 1000 appuser && \
|
||||
adduser -S -u 1000 -G appuser appuser
|
||||
|
||||
RUN mkdir -p /opt/app/var
|
||||
RUN chown appuser /opt/app/var
|
||||
|
||||
USER appuser
|
||||
|
||||
ENV MIX_ENV=prod REPLACE_OS_VARS=true
|
||||
WORKDIR /opt/app
|
||||
COPY --from=0 /opt/release .
|
||||
ENV RUNNER_LOG_DIR /var/log
|
||||
CMD ["/opt/app/bin/start_server", "foreground", "boot_var=/tmp"]
|
|
@ -0,0 +1,293 @@
|
|||
# Hello World - Elixir
|
||||
|
||||
A simple web application written in [Elixir](https://elixir-lang.org/) using the
|
||||
[Phoenix Framework](https://phoenixframework.org/). The application prints all
|
||||
environment variables to the main page.
|
||||
|
||||
## Set up Elixir and Phoenix Locally
|
||||
|
||||
Following the
|
||||
[Phoenix Installation Guide](https://hexdocs.pm/phoenix/installation.html) is
|
||||
the best way to get your computer set up for developing, building, running, and
|
||||
packaging Elixir Web applications.
|
||||
|
||||
## Running Locally
|
||||
|
||||
To start your Phoenix server:
|
||||
|
||||
- Install dependencies with `mix deps.get`
|
||||
- Install Node.js dependencies with `cd assets && npm install`
|
||||
- Start Phoenix endpoint with `mix phx.server`
|
||||
|
||||
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
|
||||
|
||||
## Recreating the sample code
|
||||
|
||||
1. Generate a new project.
|
||||
|
||||
```bash
|
||||
mix phoenix.new helloelixir
|
||||
```
|
||||
|
||||
When asked, if you want to `Fetch and install dependencies? [Yn]` select `y`
|
||||
|
||||
1. Follow the direction in the output to change directories into start your
|
||||
local server with `mix phoenix.server`
|
||||
|
||||
1. In the new directory, create a new Dockerfile for packaging your application
|
||||
for deployment
|
||||
|
||||
```docker
|
||||
# Start from a base image for elixir
|
||||
# Phoenix works best on pre 1.7 at the moment.
|
||||
FROM elixir:1.6.6-alpine
|
||||
|
||||
# Set up Elixir and Phoenix
|
||||
ARG APP_NAME=hello
|
||||
ARG PHOENIX_SUBDIR=.
|
||||
ENV MIX_ENV=prod REPLACE_OS_VARS=true TERM=xterm
|
||||
WORKDIR /opt/app
|
||||
|
||||
# Update nodejs, rebar, and hex.
|
||||
RUN apk update \
|
||||
&& apk --no-cache --update add nodejs nodejs-npm \
|
||||
&& mix local.rebar --force \
|
||||
&& mix local.hex --force
|
||||
COPY . .
|
||||
|
||||
# Download and compile dependencies, then compile Web app.
|
||||
RUN mix do deps.get, deps.compile, compile
|
||||
RUN cd ${PHOENIX_SUBDIR}/assets \
|
||||
&& npm install \
|
||||
&& ./node_modules/brunch/bin/brunch build -p \
|
||||
&& cd .. \
|
||||
&& mix phx.digest
|
||||
|
||||
# Create a release version of the application
|
||||
RUN mix release --env=prod --verbose \
|
||||
&& mv _build/prod/rel/${APP_NAME} /opt/release \
|
||||
&& mv /opt/release/bin/${APP_NAME} /opt/release/bin/start_server
|
||||
|
||||
# Prepare final layer
|
||||
FROM alpine:latest
|
||||
RUN apk update && apk --no-cache --update add bash openssl-dev ca-certificates
|
||||
|
||||
# Add a user so the server will run as a non-root user.
|
||||
RUN addgroup -g 1000 appuser && \
|
||||
adduser -S -u 1000 -G appuser appuser
|
||||
# Pre-create necessary temp directory for erlang and set permissions.
|
||||
RUN mkdir -p /opt/app/var
|
||||
RUN chown appuser /opt/app/var
|
||||
# Run everything else as 'appuser'
|
||||
USER appuser
|
||||
|
||||
ENV MIX_ENV=prod REPLACE_OS_VARS=true
|
||||
WORKDIR /opt/app
|
||||
COPY --from=0 /opt/release .
|
||||
ENV RUNNER_LOG_DIR /var/log
|
||||
|
||||
# Command to execute the application.
|
||||
CMD ["/opt/app/bin/start_server", "foreground", "boot_var=/tmp"]
|
||||
```
|
||||
|
||||
1. Create a new file, `service.yaml` and copy the following Service definition
|
||||
into the file. Make sure to replace `{username}` with your Docker Hub
|
||||
username.
|
||||
|
||||
```yaml
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-elixir
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-elixir
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "elixir Sample v1"
|
||||
```
|
||||
|
||||
## Building and deploying the sample
|
||||
|
||||
The sample in this directory is ready to build and deploy without changes. You
|
||||
can deploy the sample as is, or use you created version following the directions
|
||||
above.
|
||||
|
||||
1. Generate a new `secret_key_base` in the `config/prod.secret.exs` file.
|
||||
Phoenix applications use a secrets file on production deployments and, by
|
||||
default, that file is not checked into source control. We have provides
|
||||
shell of an example on `config/prod.secret.exs.sample` and you can use the
|
||||
following command to generate a new prod secrets file.
|
||||
|
||||
```bash
|
||||
SECRET_KEY_BASE=$(elixir -e ":crypto.strong_rand_bytes(48) |> Base.encode64 |> IO.puts")
|
||||
sed "s|SECRET+KEY+BASE|$SECRET_KEY_BASE|" config/prod.secret.exs.sample >config/prod.secret.exs
|
||||
```
|
||||
|
||||
1. Use Docker to build the sample code into a container. To build and push with
|
||||
Docker Hub, run these commands replacing `{username}` with your Docker Hub
|
||||
username:
|
||||
|
||||
```bash
|
||||
# Build the container on your local machine
|
||||
docker build -t {username}/helloworld-elixir .
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/helloworld-elixir
|
||||
```
|
||||
|
||||
1. After the build has completed and the container is pushed to docker hub, you
|
||||
can deploy the app into your cluster. Ensure that the container image value
|
||||
in `service.yaml` matches the container you built in the previous step.
|
||||
Apply the configuration using `kubectl`:
|
||||
|
||||
```bash
|
||||
kubectl apply --filename service.yaml
|
||||
```
|
||||
|
||||
1. Now that your service is created, Knative will perform the following steps:
|
||||
|
||||
- Create a new immutable revision for this version of the app.
|
||||
- Network programming to create a route, ingress, service, and load balance
|
||||
for your app.
|
||||
- Automatically scale your pods up and down (including to zero active pods).
|
||||
|
||||
1. To find the URL for your service, use
|
||||
|
||||
```
|
||||
kubectl get ksvc helloworld-elixir --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||
|
||||
NAME URL
|
||||
helloworld-elixir http://helloworld-elixir.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
1. Now you can make a request to your app to see the results. Replace
|
||||
`{IP_ADDRESS}` with the address you see returned in the previous step.
|
||||
|
||||
```bash
|
||||
curl http://helloworld-elixir.default.1.2.3.4.sslip.io
|
||||
|
||||
...
|
||||
# HTML from your application is returned.
|
||||
```
|
||||
|
||||
Here is the HTML returned from our deployed sample application:
|
||||
|
||||
```HTML
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>Hello Knative</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/app-833cc7e8eeed7a7953c5a02e28130dbd.css?vsn=d">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<nav role="navigation">
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<p class="alert alert-info" role="alert"></p>
|
||||
<p class="alert alert-danger" role="alert"></p>
|
||||
|
||||
<main role="main">
|
||||
|
||||
<div class="jumbotron">
|
||||
<h2>Welcome to Knative and Elixir</h2>
|
||||
|
||||
<p>$TARGET = elixir Sample v1</p>
|
||||
</div>
|
||||
|
||||
<h3>Environment</h3>
|
||||
<ul>
|
||||
<li>BINDIR = /opt/app/erts-9.3.2/bin</li>
|
||||
<li>DEST_SYS_CONFIG_PATH = /opt/app/var/sys.config</li>
|
||||
<li>DEST_VMARGS_PATH = /opt/app/var/vm.args</li>
|
||||
<li>DISTILLERY_TASK = foreground</li>
|
||||
<li>EMU = beam</li>
|
||||
<li>ERL_LIBS = /opt/app/lib</li>
|
||||
<li>ERL_OPTS = </li>
|
||||
<li>ERTS_DIR = /opt/app/erts-9.3.2</li>
|
||||
<li>ERTS_LIB_DIR = /opt/app/erts-9.3.2/../lib</li>
|
||||
<li>ERTS_VSN = 9.3.2</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT = tcp://10.35.241.50:80</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP = tcp://10.35.241.50:80</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_ADDR = 10.35.241.50</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_PORT = 80</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_PORT_80_TCP_PROTO = tcp</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_HOST = 10.35.241.50</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_PORT = 80</li>
|
||||
<li>HELLOWORLD_ELIXIR_00001_SERVICE_SERVICE_PORT_HTTP = 80</li>
|
||||
<li>HELLOWORLD_ELIXIR_PORT = tcp://10.35.253.90:80</li>
|
||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP = tcp://10.35.253.90:80</li>
|
||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_ADDR = 10.35.253.90</li>
|
||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_PORT = 80</li>
|
||||
<li>HELLOWORLD_ELIXIR_PORT_80_TCP_PROTO = tcp</li>
|
||||
<li>HELLOWORLD_ELIXIR_SERVICE_HOST = 10.35.253.90</li>
|
||||
<li>HELLOWORLD_ELIXIR_SERVICE_PORT = 80</li>
|
||||
<li>HELLOWORLD_ELIXIR_SERVICE_PORT_HTTP = 80</li>
|
||||
<li>HOME = /root</li>
|
||||
<li>HOSTNAME = helloworld-elixir-00001-deployment-84f68946b4-76hcv</li>
|
||||
<li>KUBERNETES_PORT = tcp://10.35.240.1:443</li>
|
||||
<li>KUBERNETES_PORT_443_TCP = tcp://10.35.240.1:443</li>
|
||||
<li>KUBERNETES_PORT_443_TCP_ADDR = 10.35.240.1</li>
|
||||
<li>KUBERNETES_PORT_443_TCP_PORT = 443</li>
|
||||
<li>KUBERNETES_PORT_443_TCP_PROTO = tcp</li>
|
||||
<li>KUBERNETES_SERVICE_HOST = 10.35.240.1</li>
|
||||
<li>KUBERNETES_SERVICE_PORT = 443</li>
|
||||
<li>KUBERNETES_SERVICE_PORT_HTTPS = 443</li>
|
||||
<li>LD_LIBRARY_PATH = /opt/app/erts-9.3.2/lib:</li>
|
||||
<li>MIX_ENV = prod</li>
|
||||
<li>NAME = hello@127.0.0.1</li>
|
||||
<li>NAME_ARG = -name hello@127.0.0.1</li>
|
||||
<li>NAME_TYPE = -name</li>
|
||||
<li>OLDPWD = /opt/app</li>
|
||||
<li>OTP_VER = 20</li>
|
||||
<li>PATH = /opt/app/erts-9.3.2/bin:/opt/app/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</li>
|
||||
<li>PORT = 8080</li>
|
||||
<li>PROGNAME = opt/app/releases/0.0.1/hello.sh</li>
|
||||
<li>PWD = /opt/app</li>
|
||||
<li>RELEASES_DIR = /opt/app/releases</li>
|
||||
<li>RELEASE_CONFIG_DIR = /opt/app</li>
|
||||
<li>RELEASE_ROOT_DIR = /opt/app</li>
|
||||
<li>REL_NAME = hello</li>
|
||||
<li>REL_VSN = 0.0.1</li>
|
||||
<li>REPLACE_OS_VARS = true</li>
|
||||
<li>ROOTDIR = /opt/app</li>
|
||||
<li>RUNNER_LOG_DIR = /var/log</li>
|
||||
<li>RUN_ERL_ENV = </li>
|
||||
<li>SHLVL = 1</li>
|
||||
<li>SRC_SYS_CONFIG_PATH = /opt/app/releases/0.0.1/sys.config</li>
|
||||
<li>SRC_VMARGS_PATH = /opt/app/releases/0.0.1/vm.args</li>
|
||||
<li>SYS_CONFIG_PATH = /opt/app/var/sys.config</li>
|
||||
<li>TARGET = elixir Sample v1</li>
|
||||
<li>TERM = xterm</li>
|
||||
<li>VMARGS_PATH = /opt/app/var/vm.args</li>
|
||||
</ul>
|
||||
</main>
|
||||
|
||||
</div> <!-- /container -->
|
||||
<script src="/js/app-930ab1950e10d7b5ab5083423c28f06e.js?vsn=d"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Removing the sample app deployment
|
||||
|
||||
To remove the sample app from your cluster, delete the service record:
|
||||
|
||||
```bash
|
||||
kubectl delete --filename service.yaml
|
||||
```
|
|
@ -0,0 +1,62 @@
|
|||
exports.config = {
|
||||
// See http://brunch.io/#documentation for docs.
|
||||
files: {
|
||||
javascripts: {
|
||||
joinTo: "js/app.js"
|
||||
|
||||
// To use a separate vendor.js bundle, specify two files path
|
||||
// http://brunch.io/docs/config#-files-
|
||||
// joinTo: {
|
||||
// "js/app.js": /^js/,
|
||||
// "js/vendor.js": /^(?!js)/
|
||||
// }
|
||||
//
|
||||
// To change the order of concatenation of files, explicitly mention here
|
||||
// order: {
|
||||
// before: [
|
||||
// "vendor/js/jquery-2.1.1.js",
|
||||
// "vendor/js/bootstrap.min.js"
|
||||
// ]
|
||||
// }
|
||||
},
|
||||
stylesheets: {
|
||||
joinTo: "css/app.css"
|
||||
},
|
||||
templates: {
|
||||
joinTo: "js/app.js"
|
||||
}
|
||||
},
|
||||
|
||||
conventions: {
|
||||
// This option sets where we should place non-css and non-js assets in.
|
||||
// By default, we set this to "/assets/static". Files in this directory
|
||||
// will be copied to `paths.public`, which is "priv/static" by default.
|
||||
assets: /^(static)/
|
||||
},
|
||||
|
||||
// Phoenix paths configuration
|
||||
paths: {
|
||||
// Dependencies and current project directories to watch
|
||||
watched: ["static", "css", "js", "vendor"],
|
||||
// Where to compile files to
|
||||
public: "../priv/static"
|
||||
},
|
||||
|
||||
// Configure your plugins
|
||||
plugins: {
|
||||
babel: {
|
||||
// Do not use ES6 compiler in vendor code
|
||||
ignore: [/vendor/]
|
||||
}
|
||||
},
|
||||
|
||||
modules: {
|
||||
autoRequire: {
|
||||
"js/app.js": ["js/app"]
|
||||
}
|
||||
},
|
||||
|
||||
npm: {
|
||||
enabled: true
|
||||
}
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
/* This file is for your main application css. */
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,21 @@
|
|||
// Brunch automatically concatenates all files in your
|
||||
// watched paths. Those paths can be configured at
|
||||
// config.paths.watched in "brunch-config.js".
|
||||
//
|
||||
// However, those files will only be executed if
|
||||
// explicitly imported. The only exception are files
|
||||
// in vendor, which are never wrapped in imports and
|
||||
// therefore are always executed.
|
||||
|
||||
// Import dependencies
|
||||
//
|
||||
// If you no longer want to use a dependency, remember
|
||||
// to also remove its path from "config.paths.watched".
|
||||
import "phoenix_html"
|
||||
|
||||
// Import local files
|
||||
//
|
||||
// Local files can be imported directly using relative
|
||||
// paths "./socket" or full ones "web/static/js/socket".
|
||||
|
||||
// import socket from "./socket"
|
|
@ -0,0 +1,62 @@
|
|||
// NOTE: The contents of this file will only be executed if
|
||||
// you uncomment its entry in "assets/js/app.js".
|
||||
|
||||
// To use Phoenix channels, the first step is to import Socket
|
||||
// and connect at the socket path in "lib/web/endpoint.ex":
|
||||
import {Socket} from "phoenix"
|
||||
|
||||
let socket = new Socket("/socket", {params: {token: window.userToken}})
|
||||
|
||||
// When you connect, you'll often need to authenticate the client.
|
||||
// For example, imagine you have an authentication plug, `MyAuth`,
|
||||
// which authenticates the session and assigns a `:current_user`.
|
||||
// If the current user exists you can assign the user's token in
|
||||
// the connection for use in the layout.
|
||||
//
|
||||
// In your "lib/web/router.ex":
|
||||
//
|
||||
// pipeline :browser do
|
||||
// ...
|
||||
// plug MyAuth
|
||||
// plug :put_user_token
|
||||
// end
|
||||
//
|
||||
// defp put_user_token(conn, _) do
|
||||
// if current_user = conn.assigns[:current_user] do
|
||||
// token = Phoenix.Token.sign(conn, "user socket", current_user.id)
|
||||
// assign(conn, :user_token, token)
|
||||
// else
|
||||
// conn
|
||||
// end
|
||||
// end
|
||||
//
|
||||
// Now you need to pass this token to JavaScript. You can do so
|
||||
// inside a script tag in "lib/web/templates/layout/app.html.eex":
|
||||
//
|
||||
// <script>window.userToken = "<%= assigns[:user_token] %>";</script>
|
||||
//
|
||||
// You will need to verify the user token in the "connect/2" function
|
||||
// in "lib/web/channels/user_socket.ex":
|
||||
//
|
||||
// def connect(%{"token" => token}, socket) do
|
||||
// # max_age: 1209600 is equivalent to two weeks in seconds
|
||||
// case Phoenix.Token.verify(socket, "user socket", token, max_age: 1209600) do
|
||||
// {:ok, user_id} ->
|
||||
// {:ok, assign(socket, :user, user_id)}
|
||||
// {:error, reason} ->
|
||||
// :error
|
||||
// end
|
||||
// end
|
||||
//
|
||||
// Finally, pass the token on connect as below. Or remove it
|
||||
// from connect if you don't care about authentication.
|
||||
|
||||
socket.connect()
|
||||
|
||||
// Now that you are connected, you can join channels with a topic:
|
||||
let channel = socket.channel("topic:subtopic", {})
|
||||
channel.join()
|
||||
.receive("ok", resp => { console.log("Joined successfully", resp) })
|
||||
.receive("error", resp => { console.log("Unable to join", resp) })
|
||||
|
||||
export default socket
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"repository": {},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"deploy": "brunch build --production",
|
||||
"watch": "brunch watch --stdin"
|
||||
},
|
||||
"dependencies": {
|
||||
"phoenix": "file:../deps/phoenix",
|
||||
"phoenix_html": "file:../deps/phoenix_html"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-brunch": "6.1.1",
|
||||
"brunch": "2.10.9",
|
||||
"clean-css-brunch": "2.10.0",
|
||||
"uglify-js-brunch": "2.10.0"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,5 @@
|
|||
# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
|
||||
#
|
||||
# To ban all spiders from the entire site uncomment the next two lines:
|
||||
# User-agent: *
|
||||
# Disallow: /
|
|
@ -0,0 +1,23 @@
|
|||
# This file is responsible for configuring your application
|
||||
# and its dependencies with the aid of the Mix.Config module.
|
||||
#
|
||||
# This configuration file is loaded before any dependency and
|
||||
# is restricted to this project.
|
||||
use Mix.Config
|
||||
|
||||
# Configures the endpoint
|
||||
config :hello, HelloWeb.Endpoint,
|
||||
url: [host: "localhost"],
|
||||
secret_key_base: "P0fv0U47j6mdL40sn3f3BIuvEyIdbxUq+yKc8Mcbwig5105brf2Dzio5ANjTVRUo",
|
||||
render_errors: [view: HelloWeb.ErrorView, accepts: ~w(html json)]
|
||||
#pubsub: [name: Hello.PubSub,
|
||||
# adapter: Phoenix.PubSub.PG2]
|
||||
|
||||
# Configures Elixir's Logger
|
||||
config :logger, :console,
|
||||
format: "$time $metadata[$level] $message\n",
|
||||
metadata: [:user_id]
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
import_config "#{Mix.env}.exs"
|
|
@ -0,0 +1,49 @@
|
|||
use Mix.Config
|
||||
|
||||
# For development, we disable any cache and enable
|
||||
# debugging and code reloading.
|
||||
#
|
||||
# The watchers configuration can be used to run external
|
||||
# watchers to your application. For example, we use it
|
||||
# with brunch.io to recompile .js and .css sources.
|
||||
config :hello, HelloWeb.Endpoint,
|
||||
http: [port: 4000],
|
||||
debug_errors: true,
|
||||
code_reloader: true,
|
||||
check_origin: false,
|
||||
watchers: [node: ["node_modules/brunch/bin/brunch", "watch", "--stdin",
|
||||
cd: Path.expand("../assets", __DIR__)]]
|
||||
|
||||
# ## SSL Support
|
||||
#
|
||||
# In order to use HTTPS in development, a self-signed
|
||||
# certificate can be generated by running the following
|
||||
# command from your terminal:
|
||||
#
|
||||
# openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout priv/server.key -out priv/server.pem
|
||||
#
|
||||
# The `http:` config above can be replaced with:
|
||||
#
|
||||
# https: [port: 4000, keyfile: "priv/server.key", certfile: "priv/server.pem"],
|
||||
#
|
||||
# If desired, both `http:` and `https:` keys can be
|
||||
# configured to run both http and https servers on
|
||||
# different ports.
|
||||
|
||||
# Watch static and templates for browser reloading.
|
||||
config :hello, HelloWeb.Endpoint,
|
||||
live_reload: [
|
||||
patterns: [
|
||||
~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
|
||||
~r{priv/gettext/.*(po)$},
|
||||
~r{lib/hello_web/views/.*(ex)$},
|
||||
~r{lib/hello_web/templates/.*(eex)$}
|
||||
]
|
||||
]
|
||||
|
||||
# Do not include metadata nor timestamps in development logs
|
||||
config :logger, :console, format: "[$level] $message\n"
|
||||
|
||||
# Set a higher stacktrace during development. Avoid configuring such
|
||||
# in production as building large stacktraces may be expensive.
|
||||
config :phoenix, :stacktrace_depth, 20
|
|
@ -0,0 +1,67 @@
|
|||
use Mix.Config
|
||||
|
||||
# For production, we often load configuration from external
|
||||
# sources, such as your system environment. For this reason,
|
||||
# you won't find the :http configuration below, but set inside
|
||||
# HelloWeb.Endpoint.init/2 when load_from_system_env is
|
||||
# true. Any dynamic configuration should be done there.
|
||||
#
|
||||
# Don't forget to configure the url host to something meaningful,
|
||||
# Phoenix uses this information when generating URLs.
|
||||
#
|
||||
# Finally, we also include the path to a cache manifest
|
||||
# containing the digested version of static files. This
|
||||
# manifest is generated by the mix phx.digest task
|
||||
# which you typically run after static files are built.
|
||||
config :hello, HelloWeb.Endpoint,
|
||||
load_from_system_env: false,
|
||||
http: [port: 8080],
|
||||
check_origin: false,
|
||||
server: true,
|
||||
root: ".",
|
||||
cache_static_manifest: "priv/static/cache_manifest.json"
|
||||
|
||||
# Do not print debug messages in production
|
||||
config :logger, level: :info
|
||||
|
||||
# ## SSL Support
|
||||
#
|
||||
# To get SSL working, you will need to add the `https` key
|
||||
# to the previous section and set your `:url` port to 443:
|
||||
#
|
||||
# config :hello, HelloWeb.Endpoint,
|
||||
# ...
|
||||
# url: [host: "example.com", port: 443],
|
||||
# https: [:inet6,
|
||||
# port: 443,
|
||||
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
|
||||
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")]
|
||||
#
|
||||
# Where those two env variables return an absolute path to
|
||||
# the key and cert in disk or a relative path inside priv,
|
||||
# for example "priv/ssl/server.key".
|
||||
#
|
||||
# We also recommend setting `force_ssl`, ensuring no data is
|
||||
# ever sent via http, always redirecting to https:
|
||||
#
|
||||
# config :hello, HelloWeb.Endpoint,
|
||||
# force_ssl: [hsts: true]
|
||||
#
|
||||
# Check `Plug.SSL` for all available options in `force_ssl`.
|
||||
|
||||
# ## Using releases
|
||||
#
|
||||
# If you are doing OTP releases, you need to instruct Phoenix
|
||||
# to start the server for all endpoints:
|
||||
#
|
||||
# config :phoenix, :serve_endpoints, true
|
||||
#
|
||||
# Alternatively, you can configure exactly which server to
|
||||
# start per endpoint:
|
||||
#
|
||||
# config :hello, HelloWeb.Endpoint, server: true
|
||||
#
|
||||
|
||||
# Finally import the config/prod.secret.exs
|
||||
# which should be versioned separately.
|
||||
import_config "prod.secret.exs"
|
|
@ -0,0 +1,12 @@
|
|||
use Mix.Config
|
||||
|
||||
# In this file, we keep production configuration that
|
||||
# you'll likely want to automate and keep away from
|
||||
# your version control system.
|
||||
#
|
||||
# You should document the content of this
|
||||
# file or create a script for recreating it, since it's
|
||||
# kept out of version control and might be hard to recover
|
||||
# or recreate for your teammates (or yourself later on).
|
||||
config :hello, HelloWeb.Endpoint,
|
||||
secret_key_base: "SECRET+KEY+BASE"
|
|
@ -0,0 +1,10 @@
|
|||
use Mix.Config
|
||||
|
||||
# We don't run a server during test. If one is required,
|
||||
# you can enable the server option below.
|
||||
config :hello, HelloWeb.Endpoint,
|
||||
http: [port: 4001],
|
||||
server: false
|
||||
|
||||
# Print only warnings and errors during test
|
||||
config :logger, level: :warn
|
|
@ -0,0 +1,9 @@
|
|||
defmodule Hello do
|
||||
@moduledoc """
|
||||
Hello keeps the contexts that define your domain
|
||||
and business logic.
|
||||
|
||||
Contexts are also responsible for managing your data, regardless
|
||||
if it comes from the database, an external API or others.
|
||||
"""
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
defmodule Hello.Application do
|
||||
use Application
|
||||
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
def start(_type, _args) do
|
||||
IO.puts :stderr, "Application starting up"
|
||||
import Supervisor.Spec
|
||||
|
||||
# Define workers and child supervisors to be supervised
|
||||
children = [
|
||||
# Start the endpoint when the application starts
|
||||
supervisor(HelloWeb.Endpoint, []),
|
||||
# Start your own worker by calling: Hello.Worker.start_link(arg1, arg2, arg3)
|
||||
# worker(Hello.Worker, [arg1, arg2, arg3]),
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: Hello.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
|
||||
# Tell Phoenix to update the endpoint configuration
|
||||
# whenever the application is updated.
|
||||
def config_change(changed, _new, removed) do
|
||||
IO.puts :stderr, "Config changed"
|
||||
HelloWeb.Endpoint.config_change(changed, removed)
|
||||
:ok
|
||||
end
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
defmodule HelloWeb do
|
||||
@moduledoc """
|
||||
The entrypoint for defining your web interface, such
|
||||
as controllers, views, channels and so on.
|
||||
|
||||
This can be used in your application as:
|
||||
|
||||
use HelloWeb, :controller
|
||||
use HelloWeb, :view
|
||||
|
||||
The definitions below will be executed for every view,
|
||||
controller, etc, so keep them short and clean, focused
|
||||
on imports, uses and aliases.
|
||||
|
||||
Do NOT define functions inside the quoted expressions
|
||||
below. Instead, define any helper function in modules
|
||||
and import those modules here.
|
||||
"""
|
||||
|
||||
def controller do
|
||||
quote do
|
||||
use Phoenix.Controller, namespace: HelloWeb
|
||||
import Plug.Conn
|
||||
import HelloWeb.Router.Helpers
|
||||
import HelloWeb.Gettext
|
||||
end
|
||||
end
|
||||
|
||||
def view do
|
||||
quote do
|
||||
use Phoenix.View, root: "lib/hello_web/templates",
|
||||
namespace: HelloWeb
|
||||
|
||||
# Import convenience functions from controllers
|
||||
import Phoenix.Controller, only: [get_flash: 2, view_module: 1]
|
||||
|
||||
# Use all HTML functionality (forms, tags, etc)
|
||||
use Phoenix.HTML
|
||||
|
||||
import HelloWeb.Router.Helpers
|
||||
import HelloWeb.ErrorHelpers
|
||||
import HelloWeb.Gettext
|
||||
end
|
||||
end
|
||||
|
||||
def router do
|
||||
quote do
|
||||
use Phoenix.Router
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller
|
||||
end
|
||||
end
|
||||
|
||||
def channel do
|
||||
quote do
|
||||
use Phoenix.Channel
|
||||
import HelloWeb.Gettext
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
When used, dispatch to the appropriate controller/view/etc.
|
||||
"""
|
||||
defmacro __using__(which) when is_atom(which) do
|
||||
apply(__MODULE__, which, [])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
defmodule HelloWeb.UserSocket do
|
||||
use Phoenix.Socket
|
||||
|
||||
## Channels
|
||||
# channel "room:*", HelloWeb.RoomChannel
|
||||
|
||||
## Transports
|
||||
transport :longpoll, Phoenix.Transports.LongPoll
|
||||
# transport :longpoll, Phoenix.Transports.LongPoll
|
||||
|
||||
# Socket params are passed from the client and can
|
||||
# be used to verify and authenticate a user. After
|
||||
# verification, you can put default assigns into
|
||||
# the socket that will be set for all channels, ie
|
||||
#
|
||||
# {:ok, assign(socket, :user_id, verified_user_id)}
|
||||
#
|
||||
# To deny connection, return `:error`.
|
||||
#
|
||||
# See `Phoenix.Token` documentation for examples in
|
||||
# performing token verification on connect.
|
||||
def connect(_params, socket) do
|
||||
IO.puts :stderr, "UserSocket.connect called"
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
# Socket id's are topics that allow you to identify all sockets for a given user:
|
||||
#
|
||||
# def id(socket), do: "user_socket:#{socket.assigns.user_id}"
|
||||
#
|
||||
# Would allow you to broadcast a "disconnect" event and terminate
|
||||
# all active sockets and channels for a given user:
|
||||
#
|
||||
# HelloWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
|
||||
#
|
||||
# Returning `nil` makes this socket anonymous.
|
||||
def id(_socket), do: nil
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
defmodule HelloWeb.PageController do
|
||||
use HelloWeb, :controller
|
||||
|
||||
def index(conn, params) do
|
||||
env = System.get_env()
|
||||
target = Map.get(env, "TARGET")
|
||||
|
||||
render conn, "index.html",
|
||||
title: "Hello Knative",
|
||||
greeting: "Welcome to Knative and Elixir",
|
||||
target: target,
|
||||
env: env
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
defmodule HelloWeb.Endpoint do
|
||||
use Phoenix.Endpoint, otp_app: :hello
|
||||
|
||||
socket "/socket", HelloWeb.UserSocket
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
# You should set gzip to true if you are running phoenix.digest
|
||||
# when deploying your static files in production.
|
||||
plug Plug.Static,
|
||||
at: "/", from: :hello, gzip: false,
|
||||
only: ~w(css fonts images js favicon.ico robots.txt)
|
||||
|
||||
# Code reloading can be explicitly enabled under the
|
||||
# :code_reloader configuration of your endpoint.
|
||||
if code_reloading? do
|
||||
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
|
||||
plug Phoenix.LiveReloader
|
||||
plug Phoenix.CodeReloader
|
||||
end
|
||||
|
||||
plug Plug.Logger
|
||||
|
||||
plug Plug.Parsers,
|
||||
parsers: [:urlencoded, :multipart, :json],
|
||||
pass: ["*/*"],
|
||||
json_decoder: Poison
|
||||
|
||||
plug Plug.MethodOverride
|
||||
plug Plug.Head
|
||||
|
||||
# The session will be stored in the cookie and signed,
|
||||
# this means its contents can be read but not tampered with.
|
||||
# Set :encryption_salt if you would also like to encrypt it.
|
||||
plug Plug.Session,
|
||||
store: :cookie,
|
||||
key: "_hello_key",
|
||||
signing_salt: "M0cGJtXU"
|
||||
|
||||
plug HelloWeb.Router
|
||||
|
||||
@doc """
|
||||
Callback invoked for dynamically configuring the endpoint.
|
||||
|
||||
It receives the endpoint configuration and checks if
|
||||
configuration should be loaded from the system environment.
|
||||
"""
|
||||
def init(_key, config) do
|
||||
IO.puts :stderr, "called HelloWeb.Endpoint.init"
|
||||
if config[:load_from_system_env] do
|
||||
port = System.get_env("PORT") || raise "expected the PORT environment variable to be set"
|
||||
{:ok, Keyword.put(config, :http, [:inet6, port: port])}
|
||||
else
|
||||
{:ok, config}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
defmodule HelloWeb.Gettext do
|
||||
@moduledoc """
|
||||
A module providing Internationalization with a gettext-based API.
|
||||
|
||||
By using [Gettext](https://hexdocs.pm/gettext),
|
||||
your module gains a set of macros for translations, for example:
|
||||
|
||||
import HelloWeb.Gettext
|
||||
|
||||
# Simple translation
|
||||
gettext "Here is the string to translate"
|
||||
|
||||
# Plural translation
|
||||
ngettext "Here is the string to translate",
|
||||
"Here are the strings to translate",
|
||||
3
|
||||
|
||||
# Domain-based translation
|
||||
dgettext "errors", "Here is the error message to translate"
|
||||
|
||||
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
|
||||
"""
|
||||
use Gettext, otp_app: :hello
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
defmodule HelloWeb.Router do
|
||||
use HelloWeb, :router
|
||||
|
||||
pipeline :browser do
|
||||
plug :accepts, ["html"]
|
||||
plug :fetch_session
|
||||
plug :fetch_flash
|
||||
plug :protect_from_forgery
|
||||
plug :put_secure_browser_headers
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
plug :accepts, ["json"]
|
||||
end
|
||||
|
||||
scope "/", HelloWeb do
|
||||
pipe_through :browser # Use the default browser stack
|
||||
|
||||
get "/", PageController, :index
|
||||
get "/:name", PageController, :show
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
# scope "/api", HelloWeb do
|
||||
# pipe_through :api
|
||||
# end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title><%= @title %></title>
|
||||
<link rel="stylesheet" type="text/css" href="<%= static_path(@conn, "/css/app.css") %>">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<header class="header">
|
||||
<nav role="navigation">
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
|
||||
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
|
||||
|
||||
<main role="main">
|
||||
<%= render @view_module, @view_template, assigns %>
|
||||
</main>
|
||||
|
||||
</div> <!-- /container -->
|
||||
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
<div class="jumbotron">
|
||||
<h2><%= @greeting %></h2>
|
||||
|
||||
<p>$TARGET = <%= @target %></p>
|
||||
</div>
|
||||
|
||||
<h3>Environment</h3>
|
||||
<ul>
|
||||
<%= for key <- Enum.sort(Map.keys(@env)) do %>
|
||||
<li><%= key %> = <%= Map.get(@env, key) %></li>
|
||||
<% end %>
|
||||
</ul>
|
|
@ -0,0 +1,44 @@
|
|||
defmodule HelloWeb.ErrorHelpers do
|
||||
@moduledoc """
|
||||
Conveniences for translating and building error messages.
|
||||
"""
|
||||
|
||||
use Phoenix.HTML
|
||||
|
||||
@doc """
|
||||
Generates tag for inlined form input errors.
|
||||
"""
|
||||
def error_tag(form, field) do
|
||||
Enum.map(Keyword.get_values(form.errors, field), fn (error) ->
|
||||
content_tag :span, translate_error(error), class: "help-block"
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Translates an error message using gettext.
|
||||
"""
|
||||
def translate_error({msg, opts}) do
|
||||
# When using gettext, we typically pass the strings we want
|
||||
# to translate as a static argument:
|
||||
#
|
||||
# # Translate "is invalid" in the "errors" domain
|
||||
# dgettext "errors", "is invalid"
|
||||
#
|
||||
# # Translate the number of files with plural rules
|
||||
# dngettext "errors", "1 file", "%{count} files", count
|
||||
#
|
||||
# Because the error messages we show in our forms and APIs
|
||||
# are defined inside Ecto, we need to translate them dynamically.
|
||||
# This requires us to call the Gettext module passing our gettext
|
||||
# backend as first argument.
|
||||
#
|
||||
# Note we use the "errors" domain, which means translations
|
||||
# should be written to the errors.po file. The :count option is
|
||||
# set by Ecto and indicates we should also apply plural rules.
|
||||
if count = opts[:count] do
|
||||
Gettext.dngettext(HelloWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
else
|
||||
Gettext.dgettext(HelloWeb.Gettext, "errors", msg, opts)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
defmodule HelloWeb.ErrorView do
|
||||
use HelloWeb, :view
|
||||
|
||||
# If you want to customize a particular status code
|
||||
# for a certain format, you may uncomment below.
|
||||
# def render("500.html", _assigns) do
|
||||
# "Internal Server Error"
|
||||
# end
|
||||
|
||||
# By default, Phoenix returns the status message from
|
||||
# the template name. For example, "404.html" becomes
|
||||
# "Not Found".
|
||||
def template_not_found(template, _assigns) do
|
||||
Phoenix.Controller.status_message_from_template(template)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
defmodule HelloWeb.HelloView do
|
||||
use HelloWeb, :view
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
defmodule HelloWeb.LayoutView do
|
||||
use HelloWeb, :view
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
defmodule HelloWeb.PageView do
|
||||
use HelloWeb, :view
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
defmodule Hello.Mixfile do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :hello,
|
||||
version: "0.0.1",
|
||||
elixir: "~> 1.4",
|
||||
elixirc_paths: elixirc_paths(Mix.env),
|
||||
compilers: [:phoenix, :gettext] ++ Mix.compilers,
|
||||
start_permanent: Mix.env == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
# Configuration for the OTP application.
|
||||
#
|
||||
# Type `mix help compile.app` for more information.
|
||||
def application do
|
||||
[
|
||||
mod: {Hello.Application, []},
|
||||
extra_applications: [:logger, :runtime_tools]
|
||||
]
|
||||
end
|
||||
|
||||
# Specifies which paths to compile per environment.
|
||||
defp elixirc_paths(:test), do: ["lib", "test/support"]
|
||||
defp elixirc_paths(_), do: ["lib"]
|
||||
|
||||
# Specifies your project dependencies.
|
||||
#
|
||||
# Type `mix help deps` for examples and options.
|
||||
defp deps do
|
||||
[
|
||||
{:phoenix, "~> 1.3.2"},
|
||||
{:phoenix_pubsub, "~> 1.0"},
|
||||
{:phoenix_html, "~> 2.10"},
|
||||
{:phoenix_live_reload, "~> 1.0", only: :dev},
|
||||
{:gettext, "~> 0.11"},
|
||||
{:cowboy, "~> 1.0"},
|
||||
{:distillery, "~> 1.5"}
|
||||
]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
%{
|
||||
"cowboy": {:hex, :cowboy, "1.1.2", "61ac29ea970389a88eca5a65601460162d370a70018afe6f949a29dca91f3bb0", [:rebar3], [{:cowlib, "~> 1.0.2", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], [], "hexpm"},
|
||||
"distillery": {:hex, :distillery, "1.5.2", "eec18b2d37b55b0bcb670cf2bcf64228ed38ce8b046bb30a9b636a6f5a4c0080", [:mix], [], "hexpm"},
|
||||
"file_system": {:hex, :file_system, "0.2.5", "a3060f063b116daf56c044c273f65202e36f75ec42e678dc10653056d3366054", [:mix], [], "hexpm"},
|
||||
"gettext": {:hex, :gettext, "0.15.0", "40a2b8ce33a80ced7727e36768499fc9286881c43ebafccae6bab731e2b2b8ce", [:mix], [], "hexpm"},
|
||||
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"},
|
||||
"phoenix": {:hex, :phoenix, "1.3.2", "2a00d751f51670ea6bc3f2ba4e6eb27ecb8a2c71e7978d9cd3e5de5ccf7378bd", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "2.11.2", "86ebd768258ba60a27f5578bec83095bdb93485d646fc4111db8844c316602d6", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.1.5", "8d4c9b1ef9ca82deee6deb5a038d6d8d7b34b9bb909d99784a49332e0d15b3dc", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2 or ~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.2", "bfa7fd52788b5eaa09cb51ff9fcad1d9edfeb68251add458523f839392f034c1", [:mix], [], "hexpm"},
|
||||
"plug": {:hex, :plug, "1.5.1", "1ff35bdecfb616f1a2b1c935ab5e4c47303f866cb929d2a76f0541e553a58165", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.3", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
|
||||
"ranch": {:hex, :ranch, "1.3.2", "e4965a144dc9fbe70e5c077c65e73c57165416a901bd02ea899cfd95aa890986", [:rebar3], [], "hexpm"},
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
## `msgid`s in this file come from POT (.pot) files.
|
||||
##
|
||||
## Do not add, change, or remove `msgid`s manually here as
|
||||
## they're tied to the ones in the corresponding POT file
|
||||
## (with the same domain).
|
||||
##
|
||||
## Use `mix gettext.extract --merge` or `mix gettext.merge`
|
||||
## to merge POT files into PO files.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: en\n"
|
|
@ -0,0 +1,10 @@
|
|||
## This file is a PO Template file.
|
||||
##
|
||||
## `msgid`s here are often extracted from source code.
|
||||
## Add new translations manually only if they're dynamic
|
||||
## translations that can't be statically extracted.
|
||||
##
|
||||
## Run `mix gettext.extract` to bring this file up to
|
||||
## date. Leave `msgstr`s empty as changing them here as no
|
||||
## effect: edit them in PO (`.po`) files instead.
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# Import all plugins from `rel/plugins`
|
||||
# They can then be used by adding `plugin MyPlugin` to
|
||||
# either an environment, or release definition, where
|
||||
# `MyPlugin` is the name of the plugin module.
|
||||
Path.join(["rel", "plugins", "*.exs"])
|
||||
|> Path.wildcard()
|
||||
|> Enum.map(&Code.eval_file(&1))
|
||||
|
||||
use Mix.Releases.Config,
|
||||
# This sets the default release built by `mix release`
|
||||
default_release: :default,
|
||||
# This sets the default environment used by `mix release`
|
||||
default_environment: Mix.env()
|
||||
|
||||
# For a full list of config options for both releases
|
||||
# and environments, visit https://hexdocs.pm/distillery/configuration.html
|
||||
|
||||
|
||||
# You may define one or more environments in this file,
|
||||
# an environment's settings will override those of a release
|
||||
# when building in that environment, this combination of release
|
||||
# and environment configuration is called a profile
|
||||
|
||||
environment :dev do
|
||||
# If you are running Phoenix, you should make sure that
|
||||
# server: true is set and the code reloader is disabled,
|
||||
# even in dev mode.
|
||||
# It is recommended that you build with MIX_ENV=prod and pass
|
||||
# the --env flag to Distillery explicitly if you want to use
|
||||
# dev mode.
|
||||
set dev_mode: true
|
||||
set include_erts: false
|
||||
set cookie: :"Bps5@RVvPgL9c~C~D(<o2o>DCQ5*Iu!<h[wb{zngH1o&j?EtGh~U$nB9kBamX(LF"
|
||||
end
|
||||
|
||||
environment :prod do
|
||||
set include_erts: true
|
||||
set include_src: false
|
||||
set cookie: :"oj@tGtLJFd=:Qn]]9d;6mI^.K}*eJuMF(&@`(s}zCIgba<J:;c`aLvLjw@ZN!Z@3"
|
||||
end
|
||||
|
||||
# You may define one or more releases in this file.
|
||||
# If you have not set a default release, or selected one
|
||||
# when running `mix release`, the first release in the file
|
||||
# will be used by default
|
||||
|
||||
release :hello do
|
||||
set version: current_version(:hello)
|
||||
set applications: [
|
||||
:runtime_tools
|
||||
]
|
||||
end
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-elixir
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-elixir
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "elixir Sample v1"
|
|
@ -0,0 +1,8 @@
|
|||
defmodule HelloWeb.PageControllerTest do
|
||||
use HelloWeb.ConnCase
|
||||
|
||||
test "GET /", %{conn: conn} do
|
||||
conn = get conn, "/"
|
||||
assert html_response(conn, 200) =~ "Welcome to Knative and Elixir"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
defmodule HelloWeb.ErrorViewTest do
|
||||
use HelloWeb.ConnCase, async: true
|
||||
|
||||
# Bring render/3 and render_to_string/3 for testing custom views
|
||||
import Phoenix.View
|
||||
|
||||
test "renders 404.html" do
|
||||
assert render_to_string(HelloWeb.ErrorView, "404.html", []) ==
|
||||
"Not Found"
|
||||
end
|
||||
|
||||
test "renders 500.html" do
|
||||
assert render_to_string(HelloWeb.ErrorView, "500.html", []) ==
|
||||
"Internal Server Error"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
defmodule HelloWeb.LayoutViewTest do
|
||||
use HelloWeb.ConnCase, async: true
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
defmodule HelloWeb.PageViewTest do
|
||||
use HelloWeb.ConnCase, async: true
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
defmodule HelloWeb.ChannelCase do
|
||||
@moduledoc """
|
||||
This module defines the test case to be used by
|
||||
channel tests.
|
||||
|
||||
Such tests rely on `Phoenix.ChannelTest` and also
|
||||
import other functionality to make it easier
|
||||
to build common datastructures and query the data layer.
|
||||
|
||||
Finally, if the test case interacts with the database,
|
||||
it cannot be async. For this reason, every test runs
|
||||
inside a transaction which is reset at the beginning
|
||||
of the test unless the test case is marked as async.
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
using do
|
||||
quote do
|
||||
# Import conveniences for testing with channels
|
||||
use Phoenix.ChannelTest
|
||||
|
||||
# The default endpoint for testing
|
||||
@endpoint HelloWeb.Endpoint
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
setup _tags do
|
||||
:ok
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
defmodule HelloWeb.ConnCase do
|
||||
@moduledoc """
|
||||
This module defines the test case to be used by
|
||||
tests that require setting up a connection.
|
||||
|
||||
Such tests rely on `Phoenix.ConnTest` and also
|
||||
import other functionality to make it easier
|
||||
to build common datastructures and query the data layer.
|
||||
|
||||
Finally, if the test case interacts with the database,
|
||||
it cannot be async. For this reason, every test runs
|
||||
inside a transaction which is reset at the beginning
|
||||
of the test unless the test case is marked as async.
|
||||
"""
|
||||
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
using do
|
||||
quote do
|
||||
# Import conveniences for testing with connections
|
||||
use Phoenix.ConnTest
|
||||
import HelloWeb.Router.Helpers
|
||||
|
||||
# The default endpoint for testing
|
||||
@endpoint HelloWeb.Endpoint
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
setup _tags do
|
||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
ExUnit.start()
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
.stack-work/
|
||||
*.cabal
|
||||
*~
|
||||
/.idea/
|
||||
/dist/
|
||||
/out/
|
|
@ -0,0 +1,22 @@
|
|||
# Use the official Haskell image to create a build artifact.
|
||||
# https://hub.docker.com/_/haskell/
|
||||
FROM haskell:8.2.2 as builder
|
||||
|
||||
# Copy local code to the container image.
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# Build and test our code, then build the “helloworld-haskell-exe” executable.
|
||||
RUN stack setup
|
||||
RUN stack build --copy-bins
|
||||
|
||||
# Use a Docker multi-stage build to create a lean production image.
|
||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||
FROM fpco/haskell-scratch:integer-gmp
|
||||
|
||||
# Copy the "helloworld-haskell-exe" executable from the builder stage to the production image.
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /root/.local/bin/helloworld-haskell-exe .
|
||||
|
||||
# Run the web service on container startup.
|
||||
CMD ["./helloworld-haskell-exe"]
|
|
@ -0,0 +1,183 @@
|
|||
# Hello World - Haskell
|
||||
|
||||
A simple web app written in Haskell that you can use for testing. It reads in an
|
||||
env variable `TARGET` and prints "Hello \${TARGET}!". If TARGET is not
|
||||
specified, it will use "World" as the TARGET.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kubernetes cluster with Knative installed and DNS configured. Follow the
|
||||
[Knative installation instructions](https://knative.dev/docs/install/) if you need to create
|
||||
one.
|
||||
- [Docker](https://www.docker.com) installed and running on your local machine,
|
||||
and a Docker Hub account configured (we'll use it for a container registry).
|
||||
|
||||
## Recreating the sample code
|
||||
|
||||
While you can clone all of the code from this directory, hello world apps are
|
||||
generally more useful if you build them step-by-step. The following instructions
|
||||
recreate the source files from this folder.
|
||||
|
||||
1. Create a new file named `stack.yaml` and paste the following code:
|
||||
|
||||
```yaml
|
||||
flags: {}
|
||||
packages:
|
||||
- .
|
||||
extra-deps: []
|
||||
resolver: lts-10.7
|
||||
```
|
||||
|
||||
1. Create a new file named `package.yaml` and paste the following code
|
||||
|
||||
```yaml
|
||||
name: helloworld-haskell
|
||||
version: 0.1.0.0
|
||||
dependencies:
|
||||
- base >= 4.7 && < 5
|
||||
- scotty
|
||||
- text
|
||||
|
||||
executables:
|
||||
helloworld-haskell-exe:
|
||||
main: Main.hs
|
||||
source-dirs: app
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
- -with-rtsopts=-N
|
||||
```
|
||||
|
||||
1. Create a `app` folder, then create a new file named `Main.hs` in that folder
|
||||
and paste the following code. This code creates a basic web server which
|
||||
listens on port 8080:
|
||||
|
||||
```haskell
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
import Data.Maybe
|
||||
import Data.Monoid ((<>))
|
||||
import Data.Text.Lazy (Text)
|
||||
import Data.Text.Lazy
|
||||
import System.Environment (lookupEnv)
|
||||
import Web.Scotty (ActionM, ScottyM, scotty)
|
||||
import Web.Scotty.Trans
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
t <- fromMaybe "World" <$> lookupEnv "TARGET"
|
||||
pStr <- fromMaybe "8080" <$> lookupEnv "PORT"
|
||||
let p = read pStr :: Int
|
||||
scotty p (route t)
|
||||
|
||||
route :: String -> ScottyM()
|
||||
route t = get "/" $ hello t
|
||||
|
||||
hello :: String -> ActionM()
|
||||
hello t = text $ pack ("Hello " ++ t)
|
||||
```
|
||||
|
||||
1. In your project directory, create a file named `Dockerfile` and copy the code
|
||||
block below into it.
|
||||
|
||||
```docker
|
||||
# Use the official Haskell image to create a build artifact.
|
||||
# https://hub.docker.com/_/haskell/
|
||||
FROM haskell:8.2.2 as builder
|
||||
|
||||
# Copy local code to the container image.
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# Build and test our code, then build the “helloworld-haskell-exe” executable.
|
||||
RUN stack setup
|
||||
RUN stack build --copy-bins
|
||||
|
||||
# Use a Docker multi-stage build to create a lean production image.
|
||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||
FROM fpco/haskell-scratch:integer-gmp
|
||||
|
||||
# Copy the "helloworld-haskell-exe" executable from the builder stage to the production image.
|
||||
WORKDIR /root/
|
||||
COPY --from=builder /root/.local/bin/helloworld-haskell-exe .
|
||||
|
||||
# Run the web service on container startup.
|
||||
CMD ["./helloworld-haskell-exe"]
|
||||
```
|
||||
|
||||
1. Create a new file, `service.yaml` and copy the following service definition
|
||||
into the file. Make sure to replace `{username}` with your Docker Hub
|
||||
username.
|
||||
|
||||
```yaml
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-haskell
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-haskell
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Haskell Sample v1"
|
||||
```
|
||||
|
||||
## Build and deploy this sample
|
||||
|
||||
Once you have recreated the sample code files (or used the files in the sample
|
||||
folder) you're ready to build and deploy the sample app.
|
||||
|
||||
1. Use Docker to build the sample code into a container. To build and push with
|
||||
Docker Hub, enter these commands replacing `{username}` with your Docker Hub
|
||||
username:
|
||||
|
||||
```bash
|
||||
# Build the container on your local machine
|
||||
docker build -t {username}/helloworld-haskell .
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/helloworld-haskell
|
||||
```
|
||||
|
||||
1. After the build has completed and the container is pushed to Docker Hub, you
|
||||
can deploy the app into your cluster. Ensure that the container image value
|
||||
in `service.yaml` matches the container you built in the previous step. Apply
|
||||
the configuration using `kubectl`:
|
||||
|
||||
```bash
|
||||
kubectl apply --filename service.yaml
|
||||
```
|
||||
|
||||
1. Now that your service is created, Knative will perform the following steps:
|
||||
|
||||
- Create a new immutable revision for this version of the app.
|
||||
- Network programming to create a route, ingress, service, and load balance
|
||||
for your app.
|
||||
- Automatically scale your pods up and down (including to zero active pods).
|
||||
|
||||
1. To find the URL for your service, enter:
|
||||
|
||||
```
|
||||
kubectl get ksvc helloworld-haskell --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||
NAME URL
|
||||
helloworld-haskell http://helloworld-haskell.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
1. Now you can make a request to your app and see the result. Replace
|
||||
the URL below with the URL returned in the previous command.
|
||||
|
||||
```bash
|
||||
curl http://helloworld-haskell.default.1.2.3.4.sslip.io
|
||||
Hello world: Haskell Sample v1
|
||||
```
|
||||
|
||||
## Removing the sample app deployment
|
||||
|
||||
To remove the sample app from your cluster, delete the service record:
|
||||
|
||||
```bash
|
||||
kubectl delete --filename service.yaml
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
import Data.Maybe
|
||||
import Data.Monoid ((<>))
|
||||
import Data.Text.Lazy (Text)
|
||||
import Data.Text.Lazy
|
||||
import System.Environment (lookupEnv)
|
||||
import Web.Scotty (ActionM, ScottyM, scotty)
|
||||
import Web.Scotty.Trans
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
t <- fromMaybe "World" <$> lookupEnv "TARGET"
|
||||
pStr <- fromMaybe "8080" <$> lookupEnv "PORT"
|
||||
let p = read pStr :: Int
|
||||
scotty p (route t)
|
||||
|
||||
route :: String -> ScottyM()
|
||||
route t = get "/" $ hello t
|
||||
|
||||
hello :: String -> ActionM()
|
||||
hello t = text $ pack ("Hello " ++ t)
|
|
@ -0,0 +1,15 @@
|
|||
name: helloworld-haskell
|
||||
version: 0.1.0.0
|
||||
dependencies:
|
||||
- base >= 4.7 && < 5
|
||||
- scotty
|
||||
- text
|
||||
|
||||
executables:
|
||||
helloworld-haskell-exe:
|
||||
main: Main.hs
|
||||
source-dirs: app
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
- -with-rtsopts=-N
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-haskell
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-haskell
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Haskell Sample v1"
|
|
@ -0,0 +1,5 @@
|
|||
flags: {}
|
||||
packages:
|
||||
- .
|
||||
extra-deps: []
|
||||
resolver: lts-10.7
|
|
@ -0,0 +1 @@
|
|||
target/
|
|
@ -0,0 +1,14 @@
|
|||
Thumbs.db
|
||||
.DS_Store
|
||||
.gradle
|
||||
build/
|
||||
target/
|
||||
out/
|
||||
.idea
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.project
|
||||
.settings
|
||||
.classpath
|
||||
.factorypath
|
|
@ -0,0 +1 @@
|
|||
-Dcom.sun.management.jmxremote -noverify -XX:TieredStopAtLevel=1
|
110
code-samples/community/serving/helloworld-java-micronaut/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
110
code-samples/community/serving/helloworld-java-micronaut/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL =
|
||||
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: : " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
BIN
code-samples/community/serving/helloworld-java-micronaut/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
code-samples/community/serving/helloworld-java-micronaut/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip
|
|
@ -0,0 +1,23 @@
|
|||
# Use the official maven/Java 8 image to create a build artifact.
|
||||
# https://hub.docker.com/_/maven
|
||||
FROM maven:3.5-jdk-8-alpine as builder
|
||||
|
||||
# Copy local code to the container image.
|
||||
WORKDIR /app
|
||||
COPY pom.xml .
|
||||
COPY src ./src
|
||||
|
||||
# Build a release artifact.
|
||||
RUN mvn package -DskipTests
|
||||
|
||||
# Use AdoptOpenJDK for base image.
|
||||
# It's important to use OpenJDK 8u191 or above that has container support enabled.
|
||||
# https://hub.docker.com/r/adoptopenjdk/openjdk8
|
||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||
FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
|
||||
|
||||
# Copy the jar to the production image from the builder stage.
|
||||
COPY --from=builder /app/target/helloworld-1.0.0-SNAPSHOT.jar /helloworld.jar
|
||||
|
||||
# Run the web service on container startup.
|
||||
CMD ["java","-jar","/helloworld.jar"]
|
|
@ -0,0 +1,284 @@
|
|||
# Hello World - Java (Micronaut)
|
||||
|
||||
Learn how to deploy a simple web app that is written in Java and uses Micronaut.
|
||||
|
||||
This samples uses Docker to build locally. The app reads in a `TARGET` env
|
||||
variable and then prints "Hello World: \${TARGET}!". If a value for `TARGET` is
|
||||
not specified, the "NOT SPECIFIED" default value is used.
|
||||
|
||||
Use this sample to walk you through the steps of creating and modifying the
|
||||
sample app, building and pushing your container image to a registry, and then
|
||||
deploying your app to your Knative cluster.
|
||||
|
||||
## Before you begin
|
||||
|
||||
You must meet the following requirements to complete this sample:
|
||||
|
||||
- A version of the Knative Serving component installed and DNS configured. Follow the
|
||||
[Knative installation instructions](https://knative.dev/docs/install/) if you need
|
||||
to create a Knative cluster.
|
||||
- The following software downloaded and install on your loacal machine:
|
||||
- [Java SE 8 or later JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
||||
- [Micronaut 1.1](https://micronaut.io/).
|
||||
- [Docker](https://www.docker.com) for building and pushing your container
|
||||
image.
|
||||
- [curl](https://curl.haxx.se/) to test the sample app after deployment.
|
||||
- A [Docker Hub](https://hub.docker.com/) account where you can push your
|
||||
container image.
|
||||
|
||||
**Tip**: You can clone the [Knatve/docs repo](https://github.com/knative/docs)
|
||||
and then modify the source files. Alternatively, learn more by manually creating
|
||||
the files yourself.
|
||||
|
||||
## Creating and configuring the sample code
|
||||
|
||||
To create and configure the source files in the root of your working directory:
|
||||
|
||||
1. Create the `pom.xml` file:
|
||||
|
||||
```xml
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.example.micronaut</groupId>
|
||||
<artifactId>helloworld</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<micronaut.version>1.1.0</micronaut.version>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<exec.mainClass>com.example.helloworld.Application</exec.mainClass>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-bom</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-runtime</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-http-client</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-http-server-netty</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>${exec.mainClass}</mainClass>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
```
|
||||
|
||||
1. Create the `HelloWorldController.java` file in the
|
||||
`src/main/java/com/example/helloworld` directory. The
|
||||
`[ROOT]/src/main/java/com/example/helloworld/HelloWorldController.java` file
|
||||
handles requests to the root URI `/`.
|
||||
|
||||
```java
|
||||
package com.example.helloworld;
|
||||
|
||||
import io.micronaut.http.MediaType;
|
||||
import io.micronaut.http.annotation.Controller;
|
||||
import io.micronaut.http.annotation.Get;
|
||||
|
||||
@Controller("/")
|
||||
public class HelloWorldController {
|
||||
|
||||
@Get(value = "/", produces = MediaType.TEXT_PLAIN)
|
||||
public String index() {
|
||||
String target = System.getenv("TARGET");
|
||||
if (target == null) {
|
||||
target = "NOT SPECIFIED";
|
||||
}
|
||||
return "Hello World: " + target;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. The Micronaut application is configured via
|
||||
`src/main/resources/application.yml`:
|
||||
|
||||
```yaml
|
||||
micronaut:
|
||||
application:
|
||||
name: helloworld-java-micronaut
|
||||
server:
|
||||
port: ${PORT:8080}
|
||||
```
|
||||
|
||||
1. Create the `Dockerfile` file:
|
||||
|
||||
```docker
|
||||
# Use the official maven/Java 8 image to create a build artifact.
|
||||
# https://hub.docker.com/_/maven
|
||||
FROM maven:3.5-jdk-8-alpine as builder
|
||||
|
||||
# Copy local code to the container image.
|
||||
WORKDIR /app
|
||||
COPY pom.xml .
|
||||
COPY src ./src
|
||||
|
||||
# Build a release artifact.
|
||||
RUN mvn package -DskipTests
|
||||
|
||||
# Use AdoptOpenJDK for base image.
|
||||
# It's important to use OpenJDK 8u191 or above that has container support enabled.
|
||||
# https://hub.docker.com/r/adoptopenjdk/openjdk8
|
||||
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
|
||||
FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
|
||||
|
||||
# Copy the jar to the production image from the builder stage.
|
||||
COPY --from=builder /app/target/helloworld-1.0.0-SNAPSHOT.jar /helloworld.jar
|
||||
|
||||
# Run the web service on container startup.
|
||||
CMD ["java","-jar","/helloworld.jar"]
|
||||
```
|
||||
|
||||
1. Create the `service.yaml` file. You must specify your Docker Hub username in
|
||||
`{username}`. You can also configure the `TARGET`, for example you can modify
|
||||
the `Micronaut Sample v1` value.
|
||||
|
||||
```yaml
|
||||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-java-micronaut
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-java-micronaut
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Micronaut Sample v1"
|
||||
```
|
||||
|
||||
## Building and deploying the sample
|
||||
|
||||
To build a container image, push your image to the registry, and then deploy
|
||||
your sample app to your cluster:
|
||||
|
||||
1. Use Docker to build your container image and then push that image to your
|
||||
Docker Hub registry. You must replace the `{username}` variables in the
|
||||
following commands with your Docker Hub username.
|
||||
|
||||
```bash
|
||||
# Build the container on your local machine
|
||||
docker build -t {username}/helloworld-java-micronaut .
|
||||
|
||||
# Push the container to docker registry
|
||||
docker push {username}/helloworld-java-micronaut
|
||||
```
|
||||
|
||||
1. Now that your container image is in the registry, you can deploy it to your
|
||||
Knative cluster by running the `kubectl apply` command:
|
||||
|
||||
```bash
|
||||
kubectl apply --filename service.yaml
|
||||
```
|
||||
|
||||
Result: A service name `helloworld-java-micronaut` is created in your cluster
|
||||
along with the following resources:
|
||||
|
||||
- A new immutable revision for the version of the app that you just deployed.
|
||||
- The following networking resources are created for your app:
|
||||
- route
|
||||
- ingress
|
||||
- service
|
||||
- load balancer
|
||||
- Auto scaling is enable to allow your pods to scale up to meet traffic, and
|
||||
also back down to zero when there is no traffic.
|
||||
|
||||
## Testing the sample app
|
||||
|
||||
To verify that your sample app has been successfully deployed:
|
||||
|
||||
1. Retrieve the URL for your service, by running the following `kubectl get`
|
||||
command:
|
||||
|
||||
```bash
|
||||
kubectl get ksvc helloworld-java-micronaut --output=custom-columns=NAME:.metadata.name,URL:.status.url
|
||||
```
|
||||
|
||||
Example result:
|
||||
|
||||
```bash
|
||||
NAME URL
|
||||
helloworld-java-micronaut http://helloworld-java-micronaut.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
1. Now you can make a request to your app and see the result. Replace
|
||||
the URL below with the URL returned in the previous command.
|
||||
|
||||
```bash
|
||||
curl http://helloworld-java-micronaut.default.1.2.3.4.sslip.io
|
||||
```
|
||||
|
||||
Example result:
|
||||
|
||||
```bash
|
||||
Hello World: Micronaut Sample v1
|
||||
```
|
||||
|
||||
Congratulations on deploying your sample Java app to Knative!
|
||||
|
||||
## Removing the sample app deployment
|
||||
|
||||
To remove the sample app from your cluster, run the following `kubectl delete`
|
||||
command:
|
||||
|
||||
```bash
|
||||
kubectl delete --filename service.yaml
|
||||
```
|
|
@ -0,0 +1,173 @@
|
|||
<?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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.example.micronaut</groupId>
|
||||
<artifactId>helloworld</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject-java</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<source>${jdk.version}</source>
|
||||
<target>${jdk.version}</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject-java</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer>
|
||||
<mainClass>${exec.mainClass}</mainClass>
|
||||
</transformer>
|
||||
<transformer />
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<argument>-noverify</argument>
|
||||
<argument>-Dmicronaut.env.deduction=false</argument>
|
||||
<argument>-XX:TieredStopAtLevel=1</argument>
|
||||
<argument>-Dcom.sun.management.jmxremote</argument>
|
||||
<argument>-classpath</argument>
|
||||
<classpath />
|
||||
<argument>${exec.mainClass}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.3.1</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>apiguardian-api</artifactId>
|
||||
<groupId>org.apiguardian</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>opentest4j</artifactId>
|
||||
<groupId>org.opentest4j</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>junit-platform-commons</artifactId>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.3.1</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit-platform-engine</artifactId>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>apiguardian-api</artifactId>
|
||||
<groupId>org.apiguardian</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut.test</groupId>
|
||||
<artifactId>micronaut-test-junit5</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>micronaut-test-core</artifactId>
|
||||
<groupId>io.micronaut.test</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-bom</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<properties>
|
||||
<micronaut.version>1.1.0</micronaut.version>
|
||||
<exec.mainClass>com.example.helloworld.Application</exec.mainClass>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
profile: service
|
||||
defaultPackage: com.example.helloworld
|
||||
---
|
||||
testFramework: junit
|
||||
sourceLanguage: java
|
|
@ -0,0 +1,286 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar"
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
wget "$jarUrl" -O "$wrapperJarPath"
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
curl -o "$wrapperJarPath" "$jarUrl"
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
|
@ -0,0 +1,161 @@
|
|||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar"
|
||||
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
echo Found %WRAPPER_JAR%
|
||||
) else (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
|
@ -0,0 +1,172 @@
|
|||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.example.micronaut</groupId>
|
||||
<artifactId>helloworld</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<micronaut.version>1.1.0</micronaut.version>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<exec.mainClass>com.example.helloworld.Application</exec.mainClass>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-bom</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-runtime</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-http-client</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-http-server-netty</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut.test</groupId>
|
||||
<artifactId>micronaut-test-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>${exec.mainClass}</mainClass>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<configuration>
|
||||
<executable>java</executable>
|
||||
<arguments>
|
||||
<!-- Non production flags -->
|
||||
<argument>-noverify</argument>
|
||||
<argument>-Dmicronaut.env.deduction=false</argument>
|
||||
<argument>-XX:TieredStopAtLevel=1</argument>
|
||||
<argument>-Dcom.sun.management.jmxremote</argument>
|
||||
<argument>-classpath</argument>
|
||||
<classpath/>
|
||||
<argument>${exec.mainClass}</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>${jdk.version}</source>
|
||||
<target>${jdk.version}</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject-java</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject-java</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: serving.knative.dev/v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: helloworld-java-micronaut
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: docker.io/{username}/helloworld-java-micronaut
|
||||
env:
|
||||
- name: TARGET
|
||||
value: "Micronaut Sample v1"
|
|
@ -0,0 +1,10 @@
|
|||
package com.example.helloworld;
|
||||
|
||||
import io.micronaut.runtime.Micronaut;
|
||||
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Micronaut.run(Application.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.example.helloworld;
|
||||
|
||||
import io.micronaut.http.MediaType;
|
||||
import io.micronaut.http.annotation.Controller;
|
||||
import io.micronaut.http.annotation.Get;
|
||||
|
||||
@Controller("/")
|
||||
public class HelloWorldController {
|
||||
|
||||
@Get(value = "/", produces = MediaType.TEXT_PLAIN)
|
||||
public String index() {
|
||||
String target = System.getenv("TARGET");
|
||||
if (target == null) {
|
||||
target = "NOT SPECIFIED";
|
||||
}
|
||||
return "Hello World: " + target;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
micronaut:
|
||||
application:
|
||||
name: helloworld-micronaut
|
||||
server:
|
||||
port: ${PORT:8080}
|
|
@ -0,0 +1,15 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<withJansi>true</withJansi>
|
||||
<!-- encoders are assigned the type
|
||||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||
<encoder>
|
||||
<pattern>%cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
|
@ -0,0 +1,28 @@
|
|||
package com.example.helloworld;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import io.micronaut.http.HttpResponse;
|
||||
import io.micronaut.http.HttpStatus;
|
||||
import io.micronaut.http.client.RxHttpClient;
|
||||
import io.micronaut.http.client.annotation.Client;
|
||||
import io.micronaut.test.annotation.MicronautTest;
|
||||
|
||||
@MicronautTest
|
||||
public class HelloWorldControllerTest {
|
||||
|
||||
@Inject
|
||||
@Client("/")
|
||||
RxHttpClient client;
|
||||
|
||||
@Test
|
||||
public void testIndex() throws Exception {
|
||||
HttpResponse<String> response = client.toBlocking().exchange("/", String.class);
|
||||
assertEquals(HttpStatus.OK, response.status());
|
||||
assertEquals("Hello World: NOT SPECIFIED", response.body());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
README.md
|
||||
_index.md
|
||||
.editorconfig
|
||||
.gitignore
|
||||
.git
|
||||
target/
|
||||
.settings
|
||||
.idea
|
||||
.project
|
||||
.classpath
|
||||
*.iml
|
|
@ -0,0 +1,8 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
|
@ -0,0 +1,31 @@
|
|||
/target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/build/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VScode ###
|
||||
.vscode
|
||||
|
||||
st
|
||||
**/*.log
|
117
code-samples/community/serving/helloworld-java-quarkus/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
117
code-samples/community/serving/helloworld-java-quarkus/.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2007-present the original author or authors.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.3";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + " .jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
BIN
code-samples/community/serving/helloworld-java-quarkus/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
code-samples/community/serving/helloworld-java-quarkus/.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
code-samples/community/serving/helloworld-java-quarkus/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
code-samples/community/serving/helloworld-java-quarkus/.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
distributionUrl=http://repo2.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
|
||||
wrapperUrl=http://repo2.maven.org/maven2/io/takari/maven-wrapper/0.5.4/maven-wrapper-0.5.4.jar
|
|
@ -0,0 +1,18 @@
|
|||
FROM quay.io/rhdevelopers/quarkus-java-builder as builder
|
||||
COPY . /project
|
||||
WORKDIR /project
|
||||
# uncomment this to set the MAVEN_MIRROR_URL of your choice, to make faster builds
|
||||
# ARG MAVEN_MIRROR_URL=<your-maven-mirror-url>
|
||||
# e.g.
|
||||
#ARG MAVEN_MIRROR_URL=http://192.168.64.1:8081/nexus/content/groups/public
|
||||
|
||||
RUN /usr/local/bin/entrypoint-run.sh mvn -DskipTests clean package
|
||||
|
||||
FROM fabric8/java-jboss-openjdk8-jdk:1.5.4
|
||||
USER jboss
|
||||
ENV JAVA_APP_DIR=/deployments
|
||||
|
||||
COPY --from=builder /project/target/lib/* /deployments/lib/
|
||||
COPY --from=builder /project/target/*-runner.jar /deployments/app.jar
|
||||
|
||||
ENTRYPOINT [ "/deployments/run-java.sh" ]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue