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