Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4d42797e6 | ||
|
|
6a394889f6 | ||
|
|
59c18693fa | ||
|
|
0537c4b805 | ||
|
|
6734bfbf7b | ||
|
|
557c2ee6fc | ||
|
|
52c77c5bf5 | ||
|
|
63a2cbb417 | ||
|
|
d2f4be7a44 | ||
|
|
33f967b61b | ||
|
|
3f58247b59 | ||
|
|
45756363bc | ||
|
|
e587eca08f | ||
|
|
a720377f3c | ||
|
|
42819ba362 | ||
|
|
e56e6482b3 | ||
|
|
0d252fabcd | ||
|
|
dedeef7077 | ||
|
|
7bd3f20ad6 | ||
|
|
dc1ffa859d | ||
|
|
c63a427ca3 | ||
|
|
e4a4ec4bff | ||
|
|
7190661360 | ||
|
|
67c38f2f29 | ||
|
|
23e20115da | ||
|
|
5072a13c7c | ||
|
|
9d8a46e847 | ||
|
|
dca2915a7e | ||
|
|
bc02d159f3 |
@@ -48,7 +48,7 @@ First, you'll need the helm CLI:
|
|||||||
|
|
||||||
On __OS X__:
|
On __OS X__:
|
||||||
```
|
```
|
||||||
$ curl -L https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-darwin-amd64.tar.gz
|
$ curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-darwin-amd64.tar.gz
|
||||||
|
|
||||||
$ tar xzf helm-v2.6.1-darwin-amd64.tar.gz
|
$ tar xzf helm-v2.6.1-darwin-amd64.tar.gz
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ $ mv darwin-amd64/helm /usr/local/bin
|
|||||||
|
|
||||||
On __Linux__:
|
On __Linux__:
|
||||||
```
|
```
|
||||||
$ curl -L https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-linux-amd64.tar.gz
|
$ curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-linux-amd64.tar.gz
|
||||||
|
|
||||||
$ tar xzf helm-v2.6.1-linux-amd64.tar.gz
|
$ tar xzf helm-v2.6.1-linux-amd64.tar.gz
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ role-based access control.)
|
|||||||
#### Minikube
|
#### Minikube
|
||||||
|
|
||||||
```
|
```
|
||||||
$ helm install --namespace fission --set serviceType=NodePort https://github.com/fission/fission/releases/download/v0.2.1/fission-all-v0.2.1.tgz
|
$ helm install --namespace fission --set serviceType=NodePort https://github.com/fission/fission/releases/download/0.3.0/fission-all-0.3.0.tgz
|
||||||
```
|
```
|
||||||
|
|
||||||
The serviceType variable allows configuring the type of Kubernetes
|
The serviceType variable allows configuring the type of Kubernetes
|
||||||
@@ -94,7 +94,7 @@ want to expose anything outside the cluster.
|
|||||||
#### Cloud hosted clusters (GKE, AWS, Azure etc.)
|
#### Cloud hosted clusters (GKE, AWS, Azure etc.)
|
||||||
|
|
||||||
```
|
```
|
||||||
$ helm install --namespace fission https://github.com/fission/fission/releases/download/v0.2.1/fission-all-v0.2.1.tgz
|
$ helm install --namespace fission https://github.com/fission/fission/releases/download/0.3.0/fission-all-0.3.0.tgz
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Minimal version
|
#### Minimal version
|
||||||
@@ -104,7 +104,7 @@ the NATS message queue, influxDB for logs, etc. If you want a more
|
|||||||
minimal setup, you can install the fission-core chart instead:
|
minimal setup, you can install the fission-core chart instead:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ helm install --namespace fission https://github.com/fission/fission/releases/download/v0.2.1/fission-core-v0.2.1.tgz
|
$ helm install --namespace fission https://github.com/fission/fission/releases/download/0.3.0/fission-core-0.3.0.tgz
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install the Fission CLI
|
### Install the Fission CLI
|
||||||
@@ -114,19 +114,19 @@ $ helm install --namespace fission https://github.com/fission/fission/releases/d
|
|||||||
Get the CLI binary for Mac:
|
Get the CLI binary for Mac:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
```
|
```
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
For Windows, you can use the linux binary on WSL. Or you can download
|
For Windows, you can use the linux binary on WSL. Or you can download
|
||||||
this windows executable: [fission.exe](https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-windows.exe)
|
this windows executable: [fission.exe](https://github.com/fission/fission/releases/download/0.3.0/fission-cli-windows.exe)
|
||||||
|
|
||||||
### Set environment vars
|
### Set environment vars
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ svc```). Then:
|
|||||||
Finally, you're ready to use Fission!
|
Finally, you're ready to use Fission!
|
||||||
|
|
||||||
```
|
```
|
||||||
$ fission env create --name nodejs --image fission/node-env:v0.2.1
|
$ fission env create --name nodejs --image fission/node-env:0.3.0
|
||||||
|
|
||||||
$ curl -LO https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js
|
$ curl -LO https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js
|
||||||
|
|
||||||
|
|||||||
+2
-221
@@ -1,221 +1,2 @@
|
|||||||
|
These instructions are replaced by:
|
||||||
- [Running Fission on your Cluster](#running-fission-on-your-cluster)
|
http://fission.io/docs/v0.2.1/install/
|
||||||
* [Setup Kubernetes](#setup-kubernetes)
|
|
||||||
+ [Install and start Kubernetes on OSX:](#install-and-start-kubernetes-on-osx)
|
|
||||||
+ [Or, install and start Kubernetes on Linux:](#or-install-and-start-kubernetes-on-linux)
|
|
||||||
* [Verify access to the cluster](#verify-access-to-the-cluster)
|
|
||||||
* [Get and Run Fission: Minikube or Local cluster](#get-and-run-fission-minikube-or-local-cluster)
|
|
||||||
* [Get and Run Fission: GKE or other Cloud](#get-and-run-fission-gke-or-other-cloud)
|
|
||||||
* [Get and Run Fission: OpenShift](#get-and-run-fission-openshift)
|
|
||||||
+ [Using Minishift or Local Cluster](#using-minishift-or-local-cluster)
|
|
||||||
+ [Using other clouds](#using-other-clouds)
|
|
||||||
* [Install the client CLI](#install-the-client-cli)
|
|
||||||
* [Run an example](#run-an-example)
|
|
||||||
* [Enable Persistent Function Logs (Optional)](#enable-persistent-function-logs-optional)
|
|
||||||
* [Use the web based Fission-ui (Optional)](#use-the-web-based-fission-ui-optional)
|
|
||||||
|
|
||||||
## Running Fission on your Cluster
|
|
||||||
|
|
||||||
### Setup Kubernetes
|
|
||||||
|
|
||||||
You can install Kubernetes on your laptop with [minikube](https://github.com/kubernetes/minikube):
|
|
||||||
|
|
||||||
#### Install and start Kubernetes on OSX:
|
|
||||||
```bash
|
|
||||||
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin
|
|
||||||
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.16.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
|
|
||||||
$ minikube start
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Or, install and start Kubernetes on Linux:
|
|
||||||
```bash
|
|
||||||
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin
|
|
||||||
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.16.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
|
|
||||||
$ minikube start
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, you can use [Google Container Engine's](https://cloud.google.com/container-engine/) free trial to get a 3 node cluster.
|
|
||||||
|
|
||||||
### Verify access to the cluster
|
|
||||||
|
|
||||||
```
|
|
||||||
$ kubectl version
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get and Run Fission: Minikube or Local cluster
|
|
||||||
|
|
||||||
If you're using minikube or no cloud provider, use these commands to
|
|
||||||
set up services with NodePort. This exposes fission on ports 31313
|
|
||||||
and 31314.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ kubectl create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-rbac.yaml
|
|
||||||
$ kubectl create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-nodeport.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Set the FISSION_URL and FISSION_ROUTER environment variables.
|
|
||||||
FISSION_URL is used by the fission CLI to find the server.
|
|
||||||
FISSION_URL should be prefixed with a `http://`. (FISSION_ROUTER is
|
|
||||||
only needed for the examples below to work.)
|
|
||||||
|
|
||||||
If you're using minikube, use these commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ export FISSION_URL=http://$(minikube ip):31313
|
|
||||||
$ export FISSION_ROUTER=$(minikube ip):31314
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Get and Run Fission: GKE or other Cloud
|
|
||||||
|
|
||||||
If you're using GKE or any other cloud provider that supports the
|
|
||||||
LoadBalancer service type, use these commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ kubectl create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-rbac.yaml
|
|
||||||
$ kubectl create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-cloud.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Save the external IP addresses of controller and router services in
|
|
||||||
FISSION_URL and FISSION_ROUTER, respectively. Wait for services to
|
|
||||||
get IP addresses (check this with ```kubectl --namespace fission get
|
|
||||||
svc```). Then:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ export FISSION_URL=http://$(kubectl --namespace fission get svc controller -o=jsonpath='{..ip}')
|
|
||||||
$ export FISSION_ROUTER=$(kubectl --namespace fission get svc router -o=jsonpath='{..ip}')
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get and Run Fission: OpenShift
|
|
||||||
|
|
||||||
If you're using OpenShift, it's possible to run Fission on it! The
|
|
||||||
deployment template needs to be deployed as a user with cluster-admin
|
|
||||||
permissions (like `system:admin`), as it needs to create a
|
|
||||||
`ClusterRole` for deploying function containers from the `fission`
|
|
||||||
namespace/project.
|
|
||||||
|
|
||||||
Identically as with Kubernetes, you need to set the FISSION_URL and FISSION_ROUTER environment variables. If you're using minishift, use these commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ export FISSION_URL=http://$(minishift ip):31313¬
|
|
||||||
$ export FISSION_ROUTER=$(minishift ip):31314¬
|
|
||||||
```
|
|
||||||
#### Using Minishift or Local Cluster
|
|
||||||
|
|
||||||
If you're using minishift or no cloud provider, use these commands to set up services with NodePort. This exposes fission on ports 31313 and 31314.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ oc login -u system:admin
|
|
||||||
$ oc create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-openshift.yaml
|
|
||||||
$ oc create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-nodeport.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Using other clouds
|
|
||||||
|
|
||||||
If you're using any cloud provider that supports the LoadBalancer service type, use these commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ oc login -u system:admin
|
|
||||||
$ oc create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-openshift.yaml
|
|
||||||
$ oc create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-cloud.yaml
|
|
||||||
```
|
|
||||||
After these steps, you should be able to run fission client as with kubernetes.
|
|
||||||
|
|
||||||
### Install the client CLI
|
|
||||||
|
|
||||||
#### Mac OS
|
|
||||||
|
|
||||||
Get the CLI binary for Mac:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/nightly20170705/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Linux
|
|
||||||
|
|
||||||
```
|
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/nightly20170705/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Windows
|
|
||||||
|
|
||||||
For Windows, you can use the linux binary on WSL. Or you can download
|
|
||||||
this windows executable: [fission.exe](https://github.com/fission/fission/releases/download/nightly20170705/fission-cli-windows.exe)
|
|
||||||
|
|
||||||
### Run an example
|
|
||||||
|
|
||||||
Finally, you're ready to use Fission!
|
|
||||||
|
|
||||||
```
|
|
||||||
$ fission env create --name nodejs --image fission/node-env
|
|
||||||
|
|
||||||
$ curl https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js > hello.js
|
|
||||||
|
|
||||||
$ fission function create --name hello --env nodejs --code hello.js
|
|
||||||
|
|
||||||
$ fission route create --method GET --url /hello --function hello
|
|
||||||
|
|
||||||
$ curl http://$FISSION_ROUTER/hello
|
|
||||||
Hello, world!
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Enable Persistent Function Logs (Optional)
|
|
||||||
|
|
||||||
Fission uses InfluxDB to store logs and fluentd to forward them from
|
|
||||||
function pods into InfluxDB.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ kubectl create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-logger.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
That's it for the basic setup. You can now use following command to view function logs:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ fission function logs --name hello
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also list the all the pods that have hosted the function
|
|
||||||
(including ones that aren't alive any more) and view logs for a
|
|
||||||
particular pod:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ fission function pods --name hello
|
|
||||||
|
|
||||||
$ fission function logs --name hello --pod <pod name>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Use the web based Fission-ui (Optional)
|
|
||||||
|
|
||||||
[Fission-ui](https://github.com/fission/fission-ui) is the ui for fission maintained by the community.
|
|
||||||
It allows users to observe and manage fission. It also provides a simple online development environment for serverless functions.
|
|
||||||
|
|
||||||
To setup Fission-ui with fission in k8s is simple:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run this after fission is deployed
|
|
||||||
$ kubectl create -f https://raw.githubusercontent.com/fission/fission-ui/master/docker/fission-ui.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Then open `http://node-ip:31319` to use Fission-ui.
|
|
||||||
|
|
||||||
For more infomation, please check out [Fission-ui Readme](https://github.com/fission/fission-ui/blob/master/README.md).
|
|
||||||
|
|
||||||
### Install NATS for message-queue based triggers (Optional)
|
|
||||||
|
|
||||||
Fission supports message queue triggers that allow you to invoke
|
|
||||||
functions based on events in a queue. For now, NATS-Streaming is the
|
|
||||||
only supported message queue.
|
|
||||||
|
|
||||||
You can install NATS Streaming on your Kubernetes cluster with:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ kubectl create -f https://github.com/fission/fission/releases/download/nightly20170705/fission-nats.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
You can subscribe to a NATS Streaming queue with a command like this:
|
|
||||||
(See `fission mqtrigger --help` for details)
|
|
||||||
|
|
||||||
```
|
|
||||||
$ fission mqtrigger create --name myQueueTrigger --function processEvent --topic "myQueue.request"
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ See the [examples](examples) directory for more.
|
|||||||
Running Fission on your Cluster
|
Running Fission on your Cluster
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
See the [installation guide](INSTALL.md).
|
See the [installation guide](http://fission.io/docs/v0.2.1/install/).
|
||||||
|
|
||||||
Compiling Fission
|
Compiling Fission
|
||||||
=================
|
=================
|
||||||
|
|||||||
+6
-1
@@ -98,7 +98,12 @@ func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
srcPkgPath := filepath.Join(builder.sharedVolumePath, req.SrcPkgFilename)
|
srcPkgPath := filepath.Join(builder.sharedVolumePath, req.SrcPkgFilename)
|
||||||
deployPkgFilename := fmt.Sprintf("%v-%v", req.SrcPkgFilename, strings.ToLower(uniuri.NewLen(6)))
|
deployPkgFilename := fmt.Sprintf("%v-%v", req.SrcPkgFilename, strings.ToLower(uniuri.NewLen(6)))
|
||||||
deployPkgPath := filepath.Join(builder.sharedVolumePath, deployPkgFilename)
|
deployPkgPath := filepath.Join(builder.sharedVolumePath, deployPkgFilename)
|
||||||
buildLogs, err := builder.build(req.BuildCommand, srcPkgPath, deployPkgPath)
|
buildCmd := req.BuildCommand
|
||||||
|
if len(buildCmd) == 0 {
|
||||||
|
// use default build command
|
||||||
|
buildCmd = "/build"
|
||||||
|
}
|
||||||
|
buildLogs, err := builder.build(buildCmd, srcPkgPath, deployPkgPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := errors.New(fmt.Sprintf("Error building source package: %v", err))
|
e := errors.New(fmt.Sprintf("Error building source package: %v", err))
|
||||||
http.Error(w, e.Error(), 500)
|
http.Error(w, e.Error(), 500)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package client
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -32,25 +33,37 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func MakeClient(serverUrl string) *Client {
|
func MakeClient(builderUrl string) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
url: strings.TrimSuffix(serverUrl, "/"),
|
url: strings.TrimSuffix(builderUrl, "/"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Build(req *builder.PackageBuildRequest) error {
|
func (c *Client) Build(req *builder.PackageBuildRequest) (*builder.PackageBuildResponse, error) {
|
||||||
body, err := json.Marshal(req)
|
body, err := json.Marshal(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp, err := http.Post(c.url, "application/json", bytes.NewReader(body))
|
resp, err := http.Post(c.url, "application/json", bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
return fission.MakeErrorFromHTTP(resp)
|
return nil, fission.MakeErrorFromHTTP(resp)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
rBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgBuildResp := builder.PackageBuildResponse{}
|
||||||
|
err = json.Unmarshal([]byte(rBody), &pkgBuildResp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pkgBuildResp, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
FROM alpine:3.4
|
|
||||||
|
|
||||||
ADD builder /
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
GOOS=linux GOARCH=386 go build -o builder .
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o builder .
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -38,5 +38,5 @@ func main() {
|
|||||||
builder := builder.MakeBuilder(dir)
|
builder := builder.MakeBuilder(dir)
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", builder.Handler)
|
mux.HandleFunc("/", builder.Handler)
|
||||||
http.ListenAndServe(":8000", mux)
|
http.ListenAndServe(":8001", mux)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package buildermgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gorilla/handlers"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"k8s.io/client-go/1.5/kubernetes"
|
||||||
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
|
||||||
|
"github.com/fission/fission"
|
||||||
|
"github.com/fission/fission/tpr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
BuildRequest struct {
|
||||||
|
Package api.ObjectMeta `json:"package"`
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderMgr struct {
|
||||||
|
fissionClient *tpr.FissionClient
|
||||||
|
kubernetesClient *kubernetes.Clientset
|
||||||
|
storageSvcUrl string
|
||||||
|
namespace string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeBuilderMgr(fissionClient *tpr.FissionClient,
|
||||||
|
kubernetesClient *kubernetes.Clientset, storageSvcUrl string,
|
||||||
|
envBuilderNamespace string) *BuilderMgr {
|
||||||
|
|
||||||
|
envWatcher := makeEnvironmentWatcher(fissionClient, kubernetesClient, envBuilderNamespace)
|
||||||
|
go envWatcher.watchEnvironments()
|
||||||
|
|
||||||
|
pkgWatcher := makePackageWatcher(fissionClient, kubernetesClient, envBuilderNamespace, storageSvcUrl)
|
||||||
|
go pkgWatcher.watchPackages()
|
||||||
|
|
||||||
|
return &BuilderMgr{
|
||||||
|
fissionClient: fissionClient,
|
||||||
|
kubernetesClient: kubernetesClient,
|
||||||
|
storageSvcUrl: storageSvcUrl,
|
||||||
|
namespace: envBuilderNamespace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builderMgr *BuilderMgr) build(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Failed to read request: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buildReq := BuildRequest{}
|
||||||
|
err = json.Unmarshal([]byte(body), &buildReq)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("invalid request body: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buildLogs, err := buildPackage(builderMgr.fissionClient, builderMgr.kubernetesClient,
|
||||||
|
builderMgr.namespace, builderMgr.storageSvcUrl, buildReq)
|
||||||
|
if err != nil {
|
||||||
|
code, e := fission.GetHTTPError(err)
|
||||||
|
http.Error(w, e, code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
_, err = w.Write([]byte(buildLogs))
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Failed to reply http request: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (builderMgr *BuilderMgr) Serve(port int) {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.HandleFunc("/v1/build", builderMgr.build).Methods("POST")
|
||||||
|
address := fmt.Sprintf(":%v", port)
|
||||||
|
log.Printf("Start buildermgr at port %v", address)
|
||||||
|
log.Fatal(http.ListenAndServe(address, handlers.LoggingHandler(os.Stdout, r)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package buildermgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/fission/fission/tpr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Start the buildermgr service.
|
||||||
|
func Start(port int, storageSvcUrl string, envBuilderNamespace string) error {
|
||||||
|
fissionClient, kubernetesClient, err := tpr.MakeFissionClient()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to get kubernetes client: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
api := MakeBuilderMgr(fissionClient, kubernetesClient,
|
||||||
|
storageSvcUrl, envBuilderNamespace)
|
||||||
|
|
||||||
|
go api.Serve(port)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fission/fission"
|
||||||
|
"github.com/fission/fission/buildermgr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Client struct {
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeClient(builderUrl string) *Client {
|
||||||
|
return &Client{
|
||||||
|
url: strings.TrimSuffix(builderUrl, "/") + "/v1",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) PackageBuild(req *buildermgr.BuildRequest) ([]byte, error) {
|
||||||
|
body, err := json.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := http.Post(c.url+"/build", "application/json", bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.handleResponse(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleResponse(resp *http.Response) ([]byte, error) {
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fission.MakeErrorFromHTTP(resp)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package buildermgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/client-go/1.5/kubernetes"
|
||||||
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
|
||||||
|
"github.com/dchest/uniuri"
|
||||||
|
"github.com/fission/fission"
|
||||||
|
"github.com/fission/fission/builder"
|
||||||
|
builderClient "github.com/fission/fission/builder/client"
|
||||||
|
"github.com/fission/fission/environments/fetcher"
|
||||||
|
fetcherClient "github.com/fission/fission/environments/fetcher/client"
|
||||||
|
"github.com/fission/fission/tpr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// buildPackage helps to build source package into deployment package.
|
||||||
|
// Following is steps buildPackage takes to complete the build process.
|
||||||
|
// 1. Check package status
|
||||||
|
// 2. Update package status to running state
|
||||||
|
// 3. Send fetch request to fetcher to fetch source package.
|
||||||
|
// 4. Send build request to builder to start a build.
|
||||||
|
// 5. Send upload request to fetcher to upload deployment package.
|
||||||
|
// 6. Update package status to succeed state
|
||||||
|
// 7. Update package resource in package ref of functions that share the same package
|
||||||
|
// *. Update package status to failed state,if any one of steps above failed
|
||||||
|
func buildPackage(fissionClient *tpr.FissionClient, kubernetesClient *kubernetes.Clientset,
|
||||||
|
builderNamespace string, storageSvcUrl string, buildReq BuildRequest) (buildLogs string, err error) {
|
||||||
|
|
||||||
|
pkg, err := fissionClient.Packages(
|
||||||
|
buildReq.Package.Namespace).Get(buildReq.Package.Name)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error getting function TPR info: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only do build for pending packages
|
||||||
|
if pkg.Status.BuildStatus != fission.BuildStatusPending {
|
||||||
|
e := "package is not in pending state"
|
||||||
|
log.Println(e)
|
||||||
|
return e, fission.MakeError(400, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// update package status to running state, so that
|
||||||
|
// we can know what status a package is through cli.
|
||||||
|
_, err = updatePackage(fissionClient, pkg, fission.BuildStatusRunning, "", nil)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error setting package pending state: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
env, err := fissionClient.Environments(api.NamespaceDefault).Get(pkg.Spec.Environment.Name)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error getting environment TPR info: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
svcName := fmt.Sprintf("%v-%v.%v", env.Metadata.Name, env.Metadata.ResourceVersion, builderNamespace)
|
||||||
|
srcPkgFilename := fmt.Sprintf("%v-%v", pkg.Metadata.Name, strings.ToLower(uniuri.NewLen(6)))
|
||||||
|
fetcherC := fetcherClient.MakeClient(fmt.Sprintf("http://%v:8000", svcName))
|
||||||
|
builderC := builderClient.MakeClient(fmt.Sprintf("http://%v:8001", svcName))
|
||||||
|
|
||||||
|
fetchReq := &fetcher.FetchRequest{
|
||||||
|
FetchType: fetcher.FETCH_SOURCE,
|
||||||
|
Package: pkg.Metadata,
|
||||||
|
Filename: srcPkgFilename,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send fetch request to fetcher
|
||||||
|
err = fetcherC.Fetch(fetchReq)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error fetching source package: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgBuildReq := &builder.PackageBuildRequest{
|
||||||
|
SrcPkgFilename: srcPkgFilename,
|
||||||
|
BuildCommand: pkg.Spec.BuildCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Start building with source package: %v", srcPkgFilename)
|
||||||
|
// send build request to builder
|
||||||
|
buildResp, err := builderC.Build(pkgBuildReq)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error building deployment package: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Build succeed, source package: %v, deployment package: %v", srcPkgFilename, buildResp.ArtifactFilename)
|
||||||
|
|
||||||
|
uploadReq := &fetcher.UploadRequest{
|
||||||
|
Filename: buildResp.ArtifactFilename,
|
||||||
|
StorageSvcUrl: storageSvcUrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Start uploading deployment package: %v", buildResp.ArtifactFilename)
|
||||||
|
// ask fetcher to upload the deployment package
|
||||||
|
uploadResp, err := fetcherC.Upload(uploadReq)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error uploading deployment package: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Start updating info of package: %v", pkg.Metadata.Name)
|
||||||
|
// update package status and also build logs
|
||||||
|
newPkgRV, err := updatePackage(fissionClient, pkg,
|
||||||
|
fission.BuildStatusSucceeded, buildResp.BuildLogs, uploadResp)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error creating deployment package TPR resource: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
fnList, err := fissionClient.
|
||||||
|
Functions(api.NamespaceDefault).List(api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error getting function list: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A package may be used by multiple functions. Update
|
||||||
|
// functions with old package resource version
|
||||||
|
for _, fn := range fnList.Items {
|
||||||
|
if fn.Spec.Package.PackageRef.Name == pkg.Metadata.Name &&
|
||||||
|
fn.Spec.Package.PackageRef.Namespace == pkg.Metadata.Namespace &&
|
||||||
|
fn.Spec.Package.PackageRef.ResourceVersion != pkg.Metadata.ResourceVersion {
|
||||||
|
fn.Spec.Package.PackageRef.ResourceVersion = newPkgRV
|
||||||
|
// update TPR
|
||||||
|
_, err = fissionClient.Functions(fn.Metadata.Namespace).Update(&fn)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error updating function package resource version: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
|
||||||
|
return e, fission.MakeError(500, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Completed build request for package: %v", pkg.Metadata.Name)
|
||||||
|
|
||||||
|
return buildResp.BuildLogs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updatePackage(fissionClient *tpr.FissionClient,
|
||||||
|
pkg *tpr.Package, status fission.BuildStatus, buildLogs string,
|
||||||
|
uploadResp *fetcher.UploadResponse) (string, error) {
|
||||||
|
|
||||||
|
// Kubernetes checks resource version before applying
|
||||||
|
// new resource config. The update operation will be
|
||||||
|
// rejected if the resource version in metadata is lower
|
||||||
|
// than the latest version. Set resource version empty
|
||||||
|
// string to skip resource version check.
|
||||||
|
pkg.Metadata.ResourceVersion = ""
|
||||||
|
|
||||||
|
pkg.Status = fission.PackageStatus{
|
||||||
|
BuildStatus: status,
|
||||||
|
BuildLog: buildLogs,
|
||||||
|
}
|
||||||
|
|
||||||
|
if uploadResp != nil {
|
||||||
|
pkg.Spec.Deployment = fission.Archive{
|
||||||
|
Type: fission.ArchiveTypeUrl,
|
||||||
|
URL: uploadResp.ArchiveDownloadUrl,
|
||||||
|
Checksum: uploadResp.Checksum,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update package spec
|
||||||
|
pkg, err := fissionClient.Packages(api.NamespaceDefault).Update(pkg)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error updating package: %v", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// return resource version for function to update function package ref
|
||||||
|
return pkg.Metadata.ResourceVersion, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,477 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package buildermgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/1.5/kubernetes"
|
||||||
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
"k8s.io/client-go/1.5/pkg/api/v1"
|
||||||
|
"k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1"
|
||||||
|
"k8s.io/client-go/1.5/pkg/labels"
|
||||||
|
"k8s.io/client-go/1.5/pkg/util/intstr"
|
||||||
|
"k8s.io/client-go/1.5/pkg/watch"
|
||||||
|
|
||||||
|
"github.com/fission/fission/tpr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type requestType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
GET_BUILDER requestType = iota
|
||||||
|
CLEANUP_BUILDERS
|
||||||
|
|
||||||
|
LABEL_ENV_NAME = "envName"
|
||||||
|
LABEL_ENV_RESOURCEVERSION = "envResourceVersion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
builderInfo struct {
|
||||||
|
envMetadata *api.ObjectMeta
|
||||||
|
deployment *v1beta1.Deployment
|
||||||
|
service *v1.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
envwRequest struct {
|
||||||
|
requestType
|
||||||
|
env *tpr.Environment
|
||||||
|
envList []tpr.Environment
|
||||||
|
respChan chan envwResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
envwResponse struct {
|
||||||
|
builderInfo *builderInfo
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
environmentWatcher struct {
|
||||||
|
cache map[string]*builderInfo
|
||||||
|
requestChan chan envwRequest
|
||||||
|
builderNamespace string
|
||||||
|
fissionClient *tpr.FissionClient
|
||||||
|
kubernetesClient *kubernetes.Clientset
|
||||||
|
fetcherImage string
|
||||||
|
fetcherImagePullPolicy v1.PullPolicy
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeEnvironmentWatcher(fissionClient *tpr.FissionClient,
|
||||||
|
kubernetesClient *kubernetes.Clientset, builderNamespace string) *environmentWatcher {
|
||||||
|
|
||||||
|
fetcherImage := os.Getenv("FETCHER_IMAGE")
|
||||||
|
if len(fetcherImage) == 0 {
|
||||||
|
fetcherImage = "fission/fetcher"
|
||||||
|
}
|
||||||
|
|
||||||
|
fetcherImagePullPolicy := os.Getenv("FETCHER_IMAGE_PULL_POLICY")
|
||||||
|
if len(fetcherImagePullPolicy) == 0 {
|
||||||
|
fetcherImagePullPolicy = "IfNotPresent"
|
||||||
|
}
|
||||||
|
|
||||||
|
var pullPolicy v1.PullPolicy
|
||||||
|
switch fetcherImagePullPolicy {
|
||||||
|
case "Always":
|
||||||
|
pullPolicy = v1.PullAlways
|
||||||
|
case "Never":
|
||||||
|
pullPolicy = v1.PullNever
|
||||||
|
default:
|
||||||
|
pullPolicy = v1.PullIfNotPresent
|
||||||
|
}
|
||||||
|
|
||||||
|
envWatcher := &environmentWatcher{
|
||||||
|
cache: make(map[string]*builderInfo),
|
||||||
|
requestChan: make(chan envwRequest),
|
||||||
|
builderNamespace: builderNamespace,
|
||||||
|
fissionClient: fissionClient,
|
||||||
|
kubernetesClient: kubernetesClient,
|
||||||
|
fetcherImage: fetcherImage,
|
||||||
|
fetcherImagePullPolicy: pullPolicy,
|
||||||
|
}
|
||||||
|
|
||||||
|
go envWatcher.service()
|
||||||
|
|
||||||
|
return envWatcher
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) getCacheKey(envName string, envResourceVersion string) string {
|
||||||
|
return fmt.Sprintf("%v-%v", envName, envResourceVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) getLabels(envName string, envResourceVersion string) map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
LABEL_ENV_NAME: envName,
|
||||||
|
LABEL_ENV_RESOURCEVERSION: envResourceVersion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) watchEnvironments() {
|
||||||
|
rv := ""
|
||||||
|
for {
|
||||||
|
wi, err := envw.fissionClient.Environments(api.NamespaceAll).Watch(api.ListOptions{
|
||||||
|
ResourceVersion: rv,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error watching environment list: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
ev, more := <-wi.ResultChan()
|
||||||
|
if !more {
|
||||||
|
// restart watch from last rv
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ev.Type == watch.Error {
|
||||||
|
// restart watch from the start
|
||||||
|
rv = ""
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
env := ev.Object.(*tpr.Environment)
|
||||||
|
rv = env.Metadata.ResourceVersion
|
||||||
|
envw.sync()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) sync() {
|
||||||
|
envList, err := envw.fissionClient.Environments(api.NamespaceAll).List(api.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error syncing environment TPR resources: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create environment builders for all environments
|
||||||
|
for i := range envList.Items {
|
||||||
|
env := envList.Items[i]
|
||||||
|
|
||||||
|
if env.Spec.Version == 1 || // builder is not supported with v1 interface
|
||||||
|
len(env.Spec.Builder.Image) == 0 { // ignore env without builder image
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err := envw.getEnvBuilder(&env)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error creating builder for %v: %v", env.Metadata.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
envw.cleanupEnvBuilders(envList.Items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) service() {
|
||||||
|
for {
|
||||||
|
req := <-envw.requestChan
|
||||||
|
switch req.requestType {
|
||||||
|
case GET_BUILDER:
|
||||||
|
key := envw.getCacheKey(req.env.Metadata.Name, req.env.Metadata.ResourceVersion)
|
||||||
|
builderInfo, ok := envw.cache[key]
|
||||||
|
if !ok {
|
||||||
|
builderInfo, err := envw.createBuilder(req.env)
|
||||||
|
if err != nil {
|
||||||
|
req.respChan <- envwResponse{err: err}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
envw.cache[key] = builderInfo
|
||||||
|
}
|
||||||
|
req.respChan <- envwResponse{builderInfo: builderInfo}
|
||||||
|
|
||||||
|
case CLEANUP_BUILDERS:
|
||||||
|
latestEnvList := make(map[string]*tpr.Environment)
|
||||||
|
for i := range req.envList {
|
||||||
|
env := req.envList[i]
|
||||||
|
key := envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||||
|
latestEnvList[key] = &env
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an environment is deleted when builder manager down,
|
||||||
|
// the builder belongs to the environment will be out-of-
|
||||||
|
// control (an orphan builder) since there is no record in
|
||||||
|
// cache and TPR. We need to iterate over the services &
|
||||||
|
// deployments to remove both normal and orphan builders.
|
||||||
|
|
||||||
|
svcList, err := envw.getBuilderServiceList(nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
for _, svc := range svcList {
|
||||||
|
envName := svc.ObjectMeta.Labels[LABEL_ENV_NAME]
|
||||||
|
envResourceVersion := svc.ObjectMeta.Labels[LABEL_ENV_RESOURCEVERSION]
|
||||||
|
key := envw.getCacheKey(envName, envResourceVersion)
|
||||||
|
if _, ok := latestEnvList[key]; !ok {
|
||||||
|
err := envw.deleteBuilderService(svc.ObjectMeta.Labels)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error removing builder service: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(envw.cache, svc.ObjectMeta.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
deployList, err := envw.getBuilderDeploymentList(nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(err.Error())
|
||||||
|
}
|
||||||
|
for _, deploy := range deployList {
|
||||||
|
envName := deploy.ObjectMeta.Labels[LABEL_ENV_NAME]
|
||||||
|
envResourceVersion := deploy.ObjectMeta.Labels[LABEL_ENV_RESOURCEVERSION]
|
||||||
|
key := envw.getCacheKey(envName, envResourceVersion)
|
||||||
|
if _, ok := latestEnvList[key]; !ok {
|
||||||
|
err := envw.deleteBuilderDeployment(deploy.ObjectMeta.Labels)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error removing builder deployment: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(envw.cache, deploy.ObjectMeta.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) getEnvBuilder(env *tpr.Environment) (*builderInfo, error) {
|
||||||
|
respChan := make(chan envwResponse)
|
||||||
|
envw.requestChan <- envwRequest{
|
||||||
|
requestType: GET_BUILDER,
|
||||||
|
env: env,
|
||||||
|
respChan: respChan,
|
||||||
|
}
|
||||||
|
resp := <-respChan
|
||||||
|
return resp.builderInfo, resp.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) cleanupEnvBuilders(envs []tpr.Environment) {
|
||||||
|
envw.requestChan <- envwRequest{
|
||||||
|
requestType: CLEANUP_BUILDERS,
|
||||||
|
envList: envs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) createBuilder(env *tpr.Environment) (*builderInfo, error) {
|
||||||
|
var svc *v1.Service
|
||||||
|
var deploy *v1beta1.Deployment
|
||||||
|
|
||||||
|
sel := envw.getLabels(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||||
|
|
||||||
|
svcList, err := envw.getBuilderServiceList(sel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(svcList) == 0 {
|
||||||
|
svc, err = envw.createBuilderService(env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error creating builder service: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deployList, err := envw.getBuilderDeploymentList(sel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(deployList) == 0 {
|
||||||
|
deploy, err = envw.createBuilderDeployment(env)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error creating builder deployment: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &builderInfo{
|
||||||
|
envMetadata: &env.Metadata,
|
||||||
|
service: svc,
|
||||||
|
deployment: deploy,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) deleteBuilderService(sel map[string]string) error {
|
||||||
|
svcList, err := envw.getBuilderServiceList(sel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, svc := range svcList {
|
||||||
|
log.Printf("Removing builder service: %v", svc.ObjectMeta.Name)
|
||||||
|
|
||||||
|
// cascading deletion
|
||||||
|
// https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/
|
||||||
|
falseVal := false
|
||||||
|
delOpt := &api.DeleteOptions{
|
||||||
|
OrphanDependents: &falseVal,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = envw.kubernetesClient.
|
||||||
|
Services(envw.builderNamespace).
|
||||||
|
Delete(svc.ObjectMeta.Name, delOpt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting builder service: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) deleteBuilderDeployment(sel map[string]string) error {
|
||||||
|
deployList, err := envw.getBuilderDeploymentList(sel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, deploy := range deployList {
|
||||||
|
log.Printf("Removing builder deployment: %v", deploy.ObjectMeta.Name)
|
||||||
|
|
||||||
|
falseVal := false
|
||||||
|
delOpt := &api.DeleteOptions{
|
||||||
|
OrphanDependents: &falseVal,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = envw.kubernetesClient.
|
||||||
|
Deployments(envw.builderNamespace).
|
||||||
|
Delete(deploy.ObjectMeta.Name, delOpt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleteing builder deployment: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string) ([]v1.Service, error) {
|
||||||
|
svcList, err := envw.kubernetesClient.Services(envw.builderNamespace).List(
|
||||||
|
api.ListOptions{
|
||||||
|
LabelSelector: labels.Set(sel).AsSelector(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error getting builder service list: %v", err)
|
||||||
|
}
|
||||||
|
return svcList.Items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) createBuilderService(env *tpr.Environment) (*v1.Service, error) {
|
||||||
|
name := envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||||
|
sel := envw.getLabels(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||||
|
service := v1.Service{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Namespace: envw.builderNamespace,
|
||||||
|
Name: name,
|
||||||
|
Labels: sel,
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Selector: sel,
|
||||||
|
Type: v1.ServiceTypeClusterIP,
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "fetcher-port",
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
Port: 8000,
|
||||||
|
TargetPort: intstr.IntOrString{
|
||||||
|
Type: intstr.Int,
|
||||||
|
IntVal: 8000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "builder-port",
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
Port: 8001,
|
||||||
|
TargetPort: intstr.IntOrString{
|
||||||
|
Type: intstr.Int,
|
||||||
|
IntVal: 8001,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
log.Printf("Creating builder service: %v", name)
|
||||||
|
_, err := envw.kubernetesClient.Services(envw.builderNamespace).Create(&service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &service, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) getBuilderDeploymentList(sel map[string]string) ([]v1beta1.Deployment, error) {
|
||||||
|
deployList, err := envw.kubernetesClient.Deployments(envw.builderNamespace).List(
|
||||||
|
api.ListOptions{
|
||||||
|
LabelSelector: labels.Set(sel).AsSelector(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error getting builder deployment list: %v", err)
|
||||||
|
}
|
||||||
|
return deployList.Items, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (envw *environmentWatcher) createBuilderDeployment(env *tpr.Environment) (*v1beta1.Deployment, error) {
|
||||||
|
sharedMountPath := "/package"
|
||||||
|
name := envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||||
|
sel := envw.getLabels(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||||
|
var replicas int32 = 1
|
||||||
|
deployment := &v1beta1.Deployment{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Namespace: envw.builderNamespace,
|
||||||
|
Name: name,
|
||||||
|
Labels: sel,
|
||||||
|
},
|
||||||
|
Spec: v1beta1.DeploymentSpec{
|
||||||
|
Replicas: &replicas,
|
||||||
|
Selector: &v1beta1.LabelSelector{
|
||||||
|
MatchLabels: sel,
|
||||||
|
},
|
||||||
|
Template: v1.PodTemplateSpec{
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Labels: sel,
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Volumes: []v1.Volume{
|
||||||
|
{
|
||||||
|
Name: "package",
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
EmptyDir: &v1.EmptyDirVolumeSource{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "builder",
|
||||||
|
Image: env.Spec.Builder.Image,
|
||||||
|
ImagePullPolicy: v1.PullAlways,
|
||||||
|
TerminationMessagePath: "/dev/termination-log",
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "package",
|
||||||
|
MountPath: sharedMountPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Command: []string{"/builder", sharedMountPath},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "fetcher",
|
||||||
|
Image: envw.fetcherImage,
|
||||||
|
ImagePullPolicy: envw.fetcherImagePullPolicy,
|
||||||
|
TerminationMessagePath: "/dev/termination-log",
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: "package",
|
||||||
|
MountPath: sharedMountPath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Command: []string{"/fetcher", sharedMountPath},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServiceAccountName: "fission-builder",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
log.Printf("Creating builder deployment: %v", envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion))
|
||||||
|
_, err := envw.kubernetesClient.Deployments(envw.builderNamespace).Create(deployment)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return deployment, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package buildermgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/1.5/kubernetes"
|
||||||
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
"k8s.io/client-go/1.5/pkg/watch"
|
||||||
|
|
||||||
|
"github.com/fission/fission"
|
||||||
|
"github.com/fission/fission/tpr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
packageWatcher struct {
|
||||||
|
fissionClient *tpr.FissionClient
|
||||||
|
kubernetesClient *kubernetes.Clientset
|
||||||
|
builderNamespace string
|
||||||
|
storageSvcUrl string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func makePackageWatcher(fissionClient *tpr.FissionClient,
|
||||||
|
kubernetesClient *kubernetes.Clientset, builderNamespace string, storageSvcUrl string) *packageWatcher {
|
||||||
|
pkgw := &packageWatcher{
|
||||||
|
fissionClient: fissionClient,
|
||||||
|
kubernetesClient: kubernetesClient,
|
||||||
|
builderNamespace: builderNamespace,
|
||||||
|
storageSvcUrl: storageSvcUrl,
|
||||||
|
}
|
||||||
|
return pkgw
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pkgw *packageWatcher) build(pkgMetadata api.ObjectMeta) {
|
||||||
|
buildReq := BuildRequest{
|
||||||
|
Package: pkgMetadata,
|
||||||
|
}
|
||||||
|
_, err := buildPackage(pkgw.fissionClient,
|
||||||
|
pkgw.kubernetesClient, pkgw.builderNamespace, pkgw.storageSvcUrl, buildReq)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error building package %v: %v", buildReq.Package.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pkgw *packageWatcher) watchPackages() {
|
||||||
|
rv := ""
|
||||||
|
for {
|
||||||
|
wi, err := pkgw.fissionClient.Packages(api.NamespaceDefault).Watch(api.ListOptions{
|
||||||
|
ResourceVersion: rv,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error watching package TPR resources: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
ev, more := <-wi.ResultChan()
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ev.Type == watch.Error {
|
||||||
|
rv = ""
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pkg := ev.Object.(*tpr.Package)
|
||||||
|
rv = pkg.Metadata.ResourceVersion
|
||||||
|
|
||||||
|
// only do build for packages in pending state
|
||||||
|
if pkg.Status.BuildStatus == fission.BuildStatusPending {
|
||||||
|
go pkgw.build(pkg.Metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1
-2
@@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ func (c *Cache) service() {
|
|||||||
val := c.cache[req.key]
|
val := c.cache[req.key]
|
||||||
val.atime = time.Now()
|
val.atime = time.Now()
|
||||||
resp.existingValue = val.value
|
resp.existingValue = val.value
|
||||||
resp.error = errors.New("value already exists")
|
resp.error = fission.MakeError(fission.ErrorNameExists, "key already exists")
|
||||||
} else {
|
} else {
|
||||||
c.cache[req.key] = &Value{
|
c.cache[req.key] = &Value{
|
||||||
value: req.value,
|
value: req.value,
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ The following table lists the configurable parameters of the Fission chart and t
|
|||||||
| `controllerPort` | Fission Controller Service Port | `31313` |
|
| `controllerPort` | Fission Controller Service Port | `31313` |
|
||||||
| `routerPort` | Fission Router Service Port | `31314` |
|
| `routerPort` | Fission Router Service Port | `31314` |
|
||||||
| `functionNamespace` | Namespace for Fission functions | `fission-function` |
|
| `functionNamespace` | Namespace for Fission functions | `fission-function` |
|
||||||
|
| `builderNamespace` | Namespace for Fission environment builders | `fission-builder` |
|
||||||
| `openshift` | RBAC for openshift | `false` |
|
| `openshift` | RBAC for openshift | `false` |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
name: fission-all
|
name: fission-all
|
||||||
version: 0.2.1
|
version: 0.3.0
|
||||||
description: Fission is a fast serverless framework for Kubernetes.
|
description: Fission is a fast serverless framework for Kubernetes.
|
||||||
keywords:
|
keywords:
|
||||||
- fission
|
- fission
|
||||||
@@ -12,4 +12,4 @@ maintainers:
|
|||||||
- name: Ta Ching Chen
|
- name: Ta Ching Chen
|
||||||
email: contact@tachingchen.com
|
email: contact@tachingchen.com
|
||||||
engine: gotpl
|
engine: gotpl
|
||||||
appVersion: 0.2.1
|
appVersion: 0.3.0
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
1. Install the client CLI.
|
1. Install the client CLI.
|
||||||
|
|
||||||
Mac:
|
Mac:
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-windows.exe
|
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.3.0/fission-cli-windows.exe
|
||||||
|
|
||||||
2. Set the FISSION_URL and FISSION_ROUTER environment variables.
|
2. Set the FISSION_URL and FISSION_ROUTER environment variables.
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ metadata:
|
|||||||
name: fission-function
|
name: fission-function
|
||||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.builderNamespace }}
|
||||||
|
labels:
|
||||||
|
name: fission-builder
|
||||||
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
@@ -153,6 +162,27 @@ roleRef:
|
|||||||
name: cluster-admin
|
name: cluster-admin
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: fission-builder
|
||||||
|
namespace: {{ .Values.builderNamespace }}
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: fission-builder-tpr
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: fission-builder
|
||||||
|
namespace: {{ .Values.builderNamespace }}
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: cluster-admin
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -240,6 +270,51 @@ spec:
|
|||||||
value: "{{ .Values.fetcherImage }}:{{ .Values.fetcherImageTag }}"
|
value: "{{ .Values.fetcherImage }}:{{ .Values.fetcherImageTag }}"
|
||||||
- name: FETCHER_IMAGE_PULL_POLICY
|
- name: FETCHER_IMAGE_PULL_POLICY
|
||||||
value: "{{ .Values.pullPolicy }}"
|
value: "{{ .Values.pullPolicy }}"
|
||||||
|
- name: RUNTIME_IMAGE_PULL_POLICY
|
||||||
|
value: "{{ .Values.pullPolicy }}"
|
||||||
|
serviceAccount: fission-svc
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: buildermgr
|
||||||
|
labels:
|
||||||
|
svc: buildermgr
|
||||||
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 8889
|
||||||
|
selector:
|
||||||
|
svc: buildermgr
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: buildermgr
|
||||||
|
labels:
|
||||||
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
svc: buildermgr
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: buildermgr
|
||||||
|
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||||
|
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||||
|
command: ["/fission-bundle"]
|
||||||
|
args: ["--builderMgrPort", "8889", "--storageSvcUrl", "http://storagesvc.{{ .Release.Namespace }}", "--envbuilder-namespace", "{{ .Values.builderNamespace }}"]
|
||||||
|
env:
|
||||||
|
- name: FETCHER_IMAGE
|
||||||
|
value: "{{ .Values.fetcherImage }}:{{ .Values.fetcherImageTag }}"
|
||||||
|
- name: FETCHER_IMAGE_PULL_POLICY
|
||||||
|
value: "{{ .Values.pullPolicy }}"
|
||||||
serviceAccount: fission-svc
|
serviceAccount: fission-svc
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{{ if .Values.analytics }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ template "fullname" . }}
|
||||||
|
labels:
|
||||||
|
# The "release" convention makes it easy to tie a release to all of the
|
||||||
|
# Kubernetes resources that were created as part of that release.
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
# This makes it easy to audit chart usage.
|
||||||
|
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||||
|
app: {{ template "name" . }}
|
||||||
|
annotations:
|
||||||
|
# This is what defines this resource as a hook. Without this line, the
|
||||||
|
# job is considered part of the release.
|
||||||
|
"helm.sh/hook": post-install
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: {{ template "fullname" . }}
|
||||||
|
labels:
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
app: {{ template "name" . }}
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: post-install-job
|
||||||
|
image: "fission/alpinecurl"
|
||||||
|
command: ["sh", "-c", "/Usr/bin/curl -m 5 -H \"Content-Type: application/json\" -X POST -d '{\"type\": \"helm-post-install\", \"chartName\": \"{{ .Chart.Name }}\", \"chartName\": \"{{ .Chart.Version }}\"}' https://g.fission.sh/analytics || true"]
|
||||||
|
{{ end }}
|
||||||
@@ -13,13 +13,13 @@ image: fission/fission-bundle
|
|||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
## Fission image version
|
## Fission image version
|
||||||
imageTag: v0.2.1
|
imageTag: 0.3.0
|
||||||
|
|
||||||
## Fission fetcher repository
|
## Fission fetcher repository
|
||||||
fetcherImage: fission/fetcher
|
fetcherImage: fission/fetcher
|
||||||
|
|
||||||
## Fission fetcher image version
|
## Fission fetcher image version
|
||||||
fetcherImageTag: v0.2.1
|
fetcherImageTag: 0.3.0
|
||||||
|
|
||||||
## Port at which Fission controller service should be exposed
|
## Port at which Fission controller service should be exposed
|
||||||
controllerPort: 31313
|
controllerPort: 31313
|
||||||
@@ -34,6 +34,10 @@ natsStreamingPort: 31316
|
|||||||
## the release namespace)
|
## the release namespace)
|
||||||
functionNamespace: fission-function
|
functionNamespace: fission-function
|
||||||
|
|
||||||
|
## Namespace in which to run fission builders (this is different from
|
||||||
|
## the release namespace)
|
||||||
|
builderNamespace: fission-builder
|
||||||
|
|
||||||
## Set up openshift RBAC rule
|
## Set up openshift RBAC rule
|
||||||
openshift: false
|
openshift: false
|
||||||
|
|
||||||
@@ -58,3 +62,7 @@ persistence:
|
|||||||
# storageClass:
|
# storageClass:
|
||||||
accessMode: ReadWriteOnce
|
accessMode: ReadWriteOnce
|
||||||
size: 8Gi
|
size: 8Gi
|
||||||
|
|
||||||
|
## Analytics let us count how many people installed fission. Set to
|
||||||
|
## false to disable analytics.
|
||||||
|
analytics: true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
name: fission-core
|
name: fission-core
|
||||||
version: 0.2.1
|
version: 0.3.0
|
||||||
description: Fission is a fast serverless framework for Kubernetes.
|
description: Fission is a fast serverless framework for Kubernetes.
|
||||||
keywords:
|
keywords:
|
||||||
- fission
|
- fission
|
||||||
@@ -12,4 +12,4 @@ maintainers:
|
|||||||
- name: Ta Ching Chen
|
- name: Ta Ching Chen
|
||||||
email: contact@tachingchen.com
|
email: contact@tachingchen.com
|
||||||
engine: gotpl
|
engine: gotpl
|
||||||
appVersion: 0.2.1
|
appVersion: 0.3.0
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
1. Install the client CLI.
|
1. Install the client CLI.
|
||||||
|
|
||||||
Mac:
|
Mac:
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/v0.2.1/fission-cli-windows.exe
|
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.3.0/fission-cli-windows.exe
|
||||||
|
|
||||||
2. Set the FISSION_URL and FISSION_ROUTER environment variables.
|
2. Set the FISSION_URL and FISSION_ROUTER environment variables.
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ metadata:
|
|||||||
name: fission-function
|
name: fission-function
|
||||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.builderNamespace }}
|
||||||
|
labels:
|
||||||
|
name: fission-builder
|
||||||
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
@@ -153,6 +162,27 @@ roleRef:
|
|||||||
name: cluster-admin
|
name: cluster-admin
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: fission-builder
|
||||||
|
namespace: {{ .Values.builderNamespace }}
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: fission-builder-tpr
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: fission-builder
|
||||||
|
namespace: {{ .Values.builderNamespace }}
|
||||||
|
roleRef:
|
||||||
|
kind: ClusterRole
|
||||||
|
name: cluster-admin
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -242,6 +272,49 @@ spec:
|
|||||||
value: "{{ .Values.pullPolicy }}"
|
value: "{{ .Values.pullPolicy }}"
|
||||||
serviceAccount: fission-svc
|
serviceAccount: fission-svc
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: buildermgr
|
||||||
|
labels:
|
||||||
|
svc: buildermgr
|
||||||
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 8889
|
||||||
|
selector:
|
||||||
|
svc: buildermgr
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: buildermgr
|
||||||
|
labels:
|
||||||
|
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
svc: buildermgr
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: buildermgr
|
||||||
|
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||||
|
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||||
|
command: ["/fission-bundle"]
|
||||||
|
args: ["--builderMgrPort", "8889", "--storageSvcUrl", "http://storagesvc.{{ .Release.Namespace }}", "--envbuilder-namespace", "{{ .Values.builderNamespace }}"]
|
||||||
|
env:
|
||||||
|
- name: FETCHER_IMAGE
|
||||||
|
value: "{{ .Values.fetcherImage }}:{{ .Values.fetcherImageTag }}"
|
||||||
|
- name: FETCHER_IMAGE_PULL_POLICY
|
||||||
|
value: "{{ .Values.pullPolicy }}"
|
||||||
|
serviceAccount: fission-svc
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: extensions/v1beta1
|
apiVersion: extensions/v1beta1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{{ if .Values.analytics }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: {{ template "fullname" . }}
|
||||||
|
labels:
|
||||||
|
# The "release" convention makes it easy to tie a release to all of the
|
||||||
|
# Kubernetes resources that were created as part of that release.
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
# This makes it easy to audit chart usage.
|
||||||
|
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||||
|
app: {{ template "name" . }}
|
||||||
|
annotations:
|
||||||
|
# This is what defines this resource as a hook. Without this line, the
|
||||||
|
# job is considered part of the release.
|
||||||
|
"helm.sh/hook": post-install
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
name: {{ template "fullname" . }}
|
||||||
|
labels:
|
||||||
|
release: {{ .Release.Name }}
|
||||||
|
app: {{ template "name" . }}
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: post-install-job
|
||||||
|
image: "fission/alpinecurl"
|
||||||
|
command: ["sh", "-c", "/usr/bin/curl -m 5 -H \"Content-Type: application/json\" -X POST -d '{\"type\": \"helm-post-install\", \"chartName\": \"{{ .Chart.Name }}\", \"chartName\": \"{{ .Chart.Version }}\"}' https://g.fission.sh/analytics || true"]
|
||||||
|
{{ end }}
|
||||||
@@ -10,7 +10,7 @@ serviceType: LoadBalancer
|
|||||||
image: fission/fission-bundle
|
image: fission/fission-bundle
|
||||||
|
|
||||||
## Fission image version
|
## Fission image version
|
||||||
imageTag: v0.2.1
|
imageTag: 0.3.0
|
||||||
|
|
||||||
## Image pull policy
|
## Image pull policy
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
@@ -19,7 +19,7 @@ pullPolicy: IfNotPresent
|
|||||||
fetcherImage: fission/fetcher
|
fetcherImage: fission/fetcher
|
||||||
|
|
||||||
## Fission fetcher image version
|
## Fission fetcher image version
|
||||||
fetcherImageTag: v0.2.1
|
fetcherImageTag: 0.3.0
|
||||||
|
|
||||||
## Port at which Fission controller service should be exposed
|
## Port at which Fission controller service should be exposed
|
||||||
controllerPort: 31313
|
controllerPort: 31313
|
||||||
@@ -31,6 +31,10 @@ routerPort: 31314
|
|||||||
## the release namespace)
|
## the release namespace)
|
||||||
functionNamespace: fission-function
|
functionNamespace: fission-function
|
||||||
|
|
||||||
|
## Namespace in which to run fission builders (this is different from
|
||||||
|
## the release namespace)
|
||||||
|
builderNamespace: fission-builder
|
||||||
|
|
||||||
## Set up openshift RBAC rule
|
## Set up openshift RBAC rule
|
||||||
openshift: false
|
openshift: false
|
||||||
|
|
||||||
@@ -43,3 +47,7 @@ persistence:
|
|||||||
# storageClass:
|
# storageClass:
|
||||||
accessMode: ReadWriteOnce
|
accessMode: ReadWriteOnce
|
||||||
size: 8Gi
|
size: 8Gi
|
||||||
|
|
||||||
|
## Analytics let us count how many people installed fission. Set to
|
||||||
|
## false to disable analytics.
|
||||||
|
analytics: true
|
||||||
|
|||||||
+20
-1
@@ -37,6 +37,8 @@ type (
|
|||||||
API struct {
|
API struct {
|
||||||
fissionClient *tpr.FissionClient
|
fissionClient *tpr.FissionClient
|
||||||
storageServiceUrl string
|
storageServiceUrl string
|
||||||
|
builderManagerUrl string
|
||||||
|
workflowApiUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
logDBConfig struct {
|
logDBConfig struct {
|
||||||
@@ -56,6 +58,20 @@ func MakeAPI() (*API, error) {
|
|||||||
api.storageServiceUrl = "http://storagesvc"
|
api.storageServiceUrl = "http://storagesvc"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u = os.Getenv("BUILDER_MANAGER_URL")
|
||||||
|
if len(u) > 0 {
|
||||||
|
api.builderManagerUrl = strings.TrimSuffix(u, "/")
|
||||||
|
} else {
|
||||||
|
api.builderManagerUrl = "http://buildermgr"
|
||||||
|
}
|
||||||
|
|
||||||
|
wfEnv := os.Getenv("WORKFLOW_API_URL")
|
||||||
|
if len(u) > 0 {
|
||||||
|
api.workflowApiUrl = strings.TrimSuffix(wfEnv, "/")
|
||||||
|
} else {
|
||||||
|
api.workflowApiUrl = "http://workflows-apiserver"
|
||||||
|
}
|
||||||
|
|
||||||
return api, err
|
return api, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +118,7 @@ func (api *API) getLogDBConfig(dbType string) logDBConfig {
|
|||||||
|
|
||||||
func (api *API) HomeHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) HomeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
fmt.Fprintf(w, "{\"message\": \"Fission API\", \"version\": \"0.2.1\"}\n")
|
fmt.Fprintf(w, "{\"message\": \"Fission API\", \"version\": \"0.3.0\"}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -160,6 +176,9 @@ func (api *API) Serve(port int) {
|
|||||||
|
|
||||||
r.HandleFunc("/proxy/{dbType}", api.FunctionLogsApiPost).Methods("POST")
|
r.HandleFunc("/proxy/{dbType}", api.FunctionLogsApiPost).Methods("POST")
|
||||||
r.HandleFunc("/proxy/storage/v1/archive", api.StorageServiceProxy)
|
r.HandleFunc("/proxy/storage/v1/archive", api.StorageServiceProxy)
|
||||||
|
r.HandleFunc("/proxy/buildermgr/v1/build", api.BuilderManagerBuildProxy)
|
||||||
|
r.HandleFunc("/proxy/buildermgr/v1/builder", api.BuilderManagerEnvBuilderProxy)
|
||||||
|
r.HandleFunc("/proxy/workflows-apiserver/{path:.*}", api.WorkflowApiserverProxy)
|
||||||
|
|
||||||
address := fmt.Sprintf(":%v", port)
|
address := fmt.Sprintf(":%v", port)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2017 The Fission 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (api *API) BuilderManagerBuildProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
u := api.builderManagerUrl + "/v1/build"
|
||||||
|
proxy, err := api._getBuilderManagerProxy(u)
|
||||||
|
if err != nil {
|
||||||
|
msg := fmt.Sprintf("Failed to establish proxy server: %v", err)
|
||||||
|
log.Println(msg)
|
||||||
|
http.Error(w, msg, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
proxy.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) BuilderManagerEnvBuilderProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
u := api.builderManagerUrl + "/v1/builder"
|
||||||
|
proxy, err := api._getBuilderManagerProxy(u)
|
||||||
|
if err != nil {
|
||||||
|
msg := fmt.Sprintf("Failed to establish proxy server: %v", err)
|
||||||
|
log.Println(msg)
|
||||||
|
http.Error(w, msg, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
proxy.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) _getBuilderManagerProxy(targetUrl string) (*httputil.ReverseProxy, error) {
|
||||||
|
svcUrl, err := url.Parse(targetUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// set up proxy server director
|
||||||
|
director := func(req *http.Request) {
|
||||||
|
// only replace url Scheme and Host to remote server
|
||||||
|
// and leave query string intact
|
||||||
|
req.URL.Scheme = svcUrl.Scheme
|
||||||
|
req.URL.Host = svcUrl.Host
|
||||||
|
req.URL.Path = svcUrl.Path
|
||||||
|
}
|
||||||
|
return &httputil.ReverseProxy{
|
||||||
|
Director: director,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -139,6 +139,7 @@ func (a *API) EnvironmentApiUpdate(w http.ResponseWriter, r *http.Request) {
|
|||||||
a.respondWithError(w, err)
|
a.respondWithError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a.respondWithSuccess(w, resp)
|
a.respondWithSuccess(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (api *API) WorkflowApiserverProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
u := api.workflowApiUrl
|
||||||
|
ssUrl, err := url.Parse(u)
|
||||||
|
if err != nil {
|
||||||
|
msg := fmt.Sprintf("Error parsing url %v: %v", u, err)
|
||||||
|
http.Error(w, msg, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
path := fmt.Sprintf("/%s", vars["path"])
|
||||||
|
director := func(req *http.Request) {
|
||||||
|
req.URL.Scheme = ssUrl.Scheme
|
||||||
|
req.URL.Host = ssUrl.Host
|
||||||
|
req.URL.Path = path
|
||||||
|
}
|
||||||
|
proxy := &httputil.ReverseProxy{
|
||||||
|
Director: director,
|
||||||
|
}
|
||||||
|
proxy.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FROM microsoft/dotnet:2.0-runtime
|
||||||
|
|
||||||
|
WORKDIR /fission-workdir
|
||||||
|
COPY out .
|
||||||
|
EXPOSE 8888
|
||||||
|
|
||||||
|
ENTRYPOINT ["dotnet"]
|
||||||
|
|
||||||
|
CMD ["fission-dotnet20.dll"]
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
using Fission.DotNetCore.Compiler;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Nancy;
|
||||||
|
using System.IO;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Fission.DotNetCore
|
||||||
|
{
|
||||||
|
public class ExecutorModule : NancyModule
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
private const string CODE_PATH = "/tmp/func.cs";
|
||||||
|
#else
|
||||||
|
private const string CODE_PATH = "/userfunc/user";
|
||||||
|
#endif
|
||||||
|
private static Function _userFunc;
|
||||||
|
private static Logger _logger = new Logger();
|
||||||
|
|
||||||
|
public ExecutorModule()
|
||||||
|
{
|
||||||
|
Post("/specialize", args => Specialize());
|
||||||
|
Get("/", _ => Run());
|
||||||
|
Post("/", _ => Run());
|
||||||
|
Put("/", _ => Run());
|
||||||
|
Head("/", _ => Run());
|
||||||
|
Options("/", _ => Run());
|
||||||
|
Delete("/", _ => Run());
|
||||||
|
}
|
||||||
|
|
||||||
|
private object Specialize()
|
||||||
|
{
|
||||||
|
var errors = new List<string>();
|
||||||
|
if (File.Exists(CODE_PATH))
|
||||||
|
{
|
||||||
|
var code = File.ReadAllText(CODE_PATH);
|
||||||
|
_userFunc = FissionCompiler.Compile(code, out errors);
|
||||||
|
if (_userFunc == null)
|
||||||
|
{
|
||||||
|
var errstr = string.Join(Environment.NewLine, errors);
|
||||||
|
_logger.WriteError(errstr);
|
||||||
|
var response = (Response)errstr;
|
||||||
|
response.StatusCode = HttpStatusCode.InternalServerError;
|
||||||
|
return response;
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var errstr = $"Unable to locate code at '{CODE_PATH}'";
|
||||||
|
_logger.WriteError(errstr);
|
||||||
|
var response = (Response)errstr;
|
||||||
|
response.StatusCode = HttpStatusCode.InternalServerError;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object Run()
|
||||||
|
{
|
||||||
|
if (_userFunc == null)
|
||||||
|
{
|
||||||
|
var response = (Response)"Generic container: no requests supported";
|
||||||
|
response.StatusCode = HttpStatusCode.InternalServerError;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _userFunc.Invoke(FissionContext.Build(Request, new Logger()));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.WriteError(e.ToString());
|
||||||
|
var response = (Response)e.Message;
|
||||||
|
response.StatusCode = HttpStatusCode.BadRequest;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Loader;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
|
using Microsoft.CodeAnalysis.Emit;
|
||||||
|
|
||||||
|
namespace Fission.DotNetCore.Compiler
|
||||||
|
{
|
||||||
|
//adapted from this article http://www.tugberkugurlu.com/archive/compiling-c-sharp-code-into-memory-and-executing-it-with-roslyn
|
||||||
|
class FissionCompiler
|
||||||
|
{
|
||||||
|
public static Function Compile(string code, out List<string> errors)
|
||||||
|
{
|
||||||
|
errors = new List<string>();
|
||||||
|
|
||||||
|
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
|
||||||
|
|
||||||
|
string assemblyName = Path.GetRandomFileName();
|
||||||
|
|
||||||
|
var coreDir = Directory.GetParent(typeof(Enumerable).GetTypeInfo().Assembly.Location);
|
||||||
|
|
||||||
|
List<MetadataReference> references = new List<MetadataReference>
|
||||||
|
{
|
||||||
|
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
|
||||||
|
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
|
||||||
|
MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location),
|
||||||
|
MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.Json.DataContractJsonSerializer).GetTypeInfo().Assembly.Location)
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var referencedAssembly in Assembly.GetEntryAssembly().GetReferencedAssemblies())
|
||||||
|
{
|
||||||
|
var assembly = Assembly.Load(referencedAssembly);
|
||||||
|
references.Add(MetadataReference.CreateFromFile(assembly.Location));
|
||||||
|
}
|
||||||
|
|
||||||
|
CSharpCompilation compilation = CSharpCompilation.Create(
|
||||||
|
assemblyName,
|
||||||
|
syntaxTrees: new[] { syntaxTree },
|
||||||
|
references: references,
|
||||||
|
options: new CSharpCompilationOptions(
|
||||||
|
OutputKind.DynamicallyLinkedLibrary,
|
||||||
|
optimizationLevel: OptimizationLevel.Release));
|
||||||
|
|
||||||
|
using (var ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
EmitResult result = compilation.Emit(ms);
|
||||||
|
|
||||||
|
if (!result.Success)
|
||||||
|
{
|
||||||
|
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
|
||||||
|
diagnostic.IsWarningAsError ||
|
||||||
|
diagnostic.Severity == DiagnosticSeverity.Error).ToList();
|
||||||
|
|
||||||
|
foreach (Diagnostic diagnostic in failures)
|
||||||
|
{
|
||||||
|
errors.Add($"{diagnostic.Id}: {diagnostic.GetMessage()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(ms);
|
||||||
|
var type = assembly.GetType("FissionFunction");
|
||||||
|
var info = type.GetMember("Execute").First() as MethodInfo;
|
||||||
|
return new Function(assembly, type, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
using Nancy;
|
||||||
|
|
||||||
|
namespace Fission.DotNetCore.Api
|
||||||
|
{
|
||||||
|
public class FissionContext
|
||||||
|
{
|
||||||
|
public FissionContext(Dictionary<string, object> args, Logger logger, FissionHttpRequest request)
|
||||||
|
{
|
||||||
|
if (args == null) throw new ArgumentNullException(nameof(args));
|
||||||
|
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||||
|
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||||
|
Arguments = args;
|
||||||
|
Logger = logger;
|
||||||
|
Request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, object> Arguments { get; private set; }
|
||||||
|
|
||||||
|
public FissionHttpRequest Request { get; private set; }
|
||||||
|
|
||||||
|
public Logger Logger { get; private set; }
|
||||||
|
|
||||||
|
public static FissionContext Build(Request request, Logger logger)
|
||||||
|
{
|
||||||
|
return new FissionContext(((DynamicDictionary)request.Query).ToDictionary(),
|
||||||
|
logger,
|
||||||
|
new FissionHttpRequest(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Logger
|
||||||
|
{
|
||||||
|
public void Write(Severity severity, string format, params object[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{DateTime.Now.ToString("MM/dd/yy H:mm:ss zzz")} {severity}: " + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteInfo(string format, params object[] args)
|
||||||
|
{
|
||||||
|
Write(Severity.Info, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteWarning(string format, params object[] args)
|
||||||
|
{
|
||||||
|
Write(Severity.Warning, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteError(string format, params object[] args)
|
||||||
|
{
|
||||||
|
Write(Severity.Error, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteCritical(string format, params object[] args)
|
||||||
|
{
|
||||||
|
Write(Severity.Critical, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteVerbose(string format, params object[] args)
|
||||||
|
{
|
||||||
|
Write(Severity.Verbose, format, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Severity
|
||||||
|
{
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Critical,
|
||||||
|
Verbose
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FissionHttpRequest
|
||||||
|
{
|
||||||
|
private readonly Request _request;
|
||||||
|
internal FissionHttpRequest(Request request)
|
||||||
|
{
|
||||||
|
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||||
|
_request = request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream Body { get { return _request.Body; } }
|
||||||
|
|
||||||
|
public string BodyAsString()
|
||||||
|
{
|
||||||
|
int length = (int)_request.Body.Length;
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
_request.Body.Read(data, 0, length);
|
||||||
|
return Encoding.UTF8.GetString(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, IEnumerable<string>> Headers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var headers = new Dictionary<string, IEnumerable<string>>();
|
||||||
|
foreach (var kv in _request.Headers)
|
||||||
|
{
|
||||||
|
headers.Add(kv.Key, kv.Value);
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate Certificate { get { return _request.ClientCertificate; } }
|
||||||
|
public string Url { get { return _request.Url.ToString(); } }
|
||||||
|
public string Method { get { return _request.Method; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
namespace Fission.DotNetCore.Compiler
|
||||||
|
{
|
||||||
|
class Function
|
||||||
|
{
|
||||||
|
private readonly Assembly _assembly;
|
||||||
|
private readonly Type _type;
|
||||||
|
private readonly MethodInfo _info;
|
||||||
|
|
||||||
|
public Function(Assembly assembly, Type type, MethodInfo info)
|
||||||
|
{
|
||||||
|
if (info == null) throw new ArgumentNullException(nameof(info));
|
||||||
|
if (assembly == null) throw new ArgumentNullException(nameof(assembly));
|
||||||
|
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||||
|
_assembly = assembly;
|
||||||
|
_type = type;
|
||||||
|
_info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Invoke(FissionContext context)
|
||||||
|
{
|
||||||
|
return _info.Invoke(_assembly.CreateInstance(_type.FullName), new[] { context });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Nancy.Owin;
|
||||||
|
|
||||||
|
namespace Fission.DotNetCore
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseKestrel()
|
||||||
|
.UseUrls("http://*:8888")
|
||||||
|
.Configure(app => app.UseOwin(x => x.UseNancy()))
|
||||||
|
.Build();
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
# Fission: dotnet 2.0 C# Environment
|
||||||
|
|
||||||
|
This is a simple dotnet core 2.0 C# environment for Fission.
|
||||||
|
|
||||||
|
It's a Docker image containing the dotnet 2.0.0 runtime. The image
|
||||||
|
uses Kestrel with Nancy to host the internal web server and uses
|
||||||
|
Roslyn to compile the uploaded code.
|
||||||
|
|
||||||
|
The image supports compiling and running code with types defined in
|
||||||
|
mscorlib and does not at present support other library references.
|
||||||
|
One workaround for this would be to add the references to this project's
|
||||||
|
project.json file and rebuild the container.
|
||||||
|
|
||||||
|
The environment works via convention where you create a C# class
|
||||||
|
called FissionFunction which has a method named Execute taking a single
|
||||||
|
parameter, a FissionContext object.
|
||||||
|
|
||||||
|
The FissionContext object gives access to the arguments and other items
|
||||||
|
like logging. Please see FissionContext.cs for public API.
|
||||||
|
|
||||||
|
Example of simplest possible class to be executed:
|
||||||
|
|
||||||
|
```
|
||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction {
|
||||||
|
public string Execute(FissionContext context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Please see examples below.
|
||||||
|
|
||||||
|
## Rebuilding and pushing the image
|
||||||
|
|
||||||
|
To rebuild the image you need either a computer with dotnet core 2.0.0
|
||||||
|
installed or else you will have to map the source directory into a
|
||||||
|
container containing the dotnet core 2.0.0 environment.
|
||||||
|
|
||||||
|
### Locally installed Dotnet core 2.0.0
|
||||||
|
|
||||||
|
Simply move to the source directory in a terminal and run the ./build.sh script.
|
||||||
|
|
||||||
|
The script will restore dependencies, compile a release build and
|
||||||
|
and build the container. If you need to change the name of the container
|
||||||
|
simply change it in the script.
|
||||||
|
|
||||||
|
After the build finishes push the new image to a Docker registry using the
|
||||||
|
standard procedure.
|
||||||
|
|
||||||
|
### Build in a container
|
||||||
|
|
||||||
|
Move to the directory containing the source and start the Docker container
|
||||||
|
with dotnet and mount the current directory to a build location:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -it --rm -v $PWD:/build microsoft/dotnet
|
||||||
|
```
|
||||||
|
|
||||||
|
Move to the build directory inside the container and restore the packages:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd /build
|
||||||
|
dotnet restore fission-dotnet20.csproj
|
||||||
|
log : Restoring packages for /source/project.json...
|
||||||
|
log : Installing System.Net.WebSockets 4.0.0.
|
||||||
|
log : Installing runtime.native.System.IO.Compression 4.1.0.
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Compile and publish a release build of the source to the 'out' folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
dotnet publish -c Release -o out
|
||||||
|
Publishing source for .NETCoreApp,Version
|
||||||
|
...
|
||||||
|
```
|
||||||
|
Exit the build container and build the Docker container on the local host:
|
||||||
|
|
||||||
|
```
|
||||||
|
exit
|
||||||
|
docker build -t USER/dotnet20-env .
|
||||||
|
```
|
||||||
|
After the build finishes push the new image to a Docker registry using the
|
||||||
|
standard procedure.
|
||||||
|
|
||||||
|
## Echo example
|
||||||
|
|
||||||
|
### Setup fission environment
|
||||||
|
First you need to setup the fission according to your cluster setup as
|
||||||
|
specified here: https://github.com/fission/fission
|
||||||
|
|
||||||
|
|
||||||
|
### Create the class to run
|
||||||
|
|
||||||
|
Secondly you need to create a file /tmp/func.cs containing the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context){
|
||||||
|
context.Logger.WriteInfo("executing.. {0}", context.Arguments["text"]);
|
||||||
|
return (string)context.Arguments["text"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Run the example
|
||||||
|
|
||||||
|
Lastly to run the example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ fission env create --name dotnet --image fission/dotnet20-env
|
||||||
|
|
||||||
|
$ fission function create --name echo --env dotnet --code /tmp/func.cs
|
||||||
|
|
||||||
|
$ fission route create --method GET --url /echo --function echo
|
||||||
|
|
||||||
|
$ curl http://$FISSION_ROUTER/echo?text=hello%20world!
|
||||||
|
hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
## Addition service example
|
||||||
|
|
||||||
|
### Setup fission environment
|
||||||
|
First you need to setup the fission according to your cluster setup as
|
||||||
|
specified here: https://github.com/fission/fission
|
||||||
|
|
||||||
|
|
||||||
|
### Create the class to run
|
||||||
|
|
||||||
|
Secondly you need to create a file /tmp/func.cs containing the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context){
|
||||||
|
var x = Convert.ToInt32(context.Arguments["x"]);
|
||||||
|
var y = Convert.ToInt32(context.Arguments["y"]);
|
||||||
|
return (x+y).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Run the example
|
||||||
|
|
||||||
|
Lastly to run the example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ fission env create --name dotnet --image fission/dotnet20-env
|
||||||
|
|
||||||
|
$ fission function create --name addition --env dotnet --code /tmp/func.cs
|
||||||
|
|
||||||
|
$ fission route create --method GET --url /add --function addition
|
||||||
|
|
||||||
|
$ curl "http://$FISSION_ROUTER/add?x=30&y=12"
|
||||||
|
42
|
||||||
|
```
|
||||||
|
|
||||||
|
## Accessing http request information example
|
||||||
|
|
||||||
|
### Setup fission environment
|
||||||
|
First you need to setup the fission according to your cluster setup as
|
||||||
|
specified here: https://github.com/fission/fission
|
||||||
|
|
||||||
|
|
||||||
|
### Create the class to run
|
||||||
|
|
||||||
|
Secondly you need to create a file /tmp/func.cs containing the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context){
|
||||||
|
var buffer = new System.Text.StringBuilder();
|
||||||
|
foreach(var header in context.Request.Headers){
|
||||||
|
buffer.AppendLine(header.Key);
|
||||||
|
foreach(var item in header.Value){
|
||||||
|
buffer.AppendLine($"\t{item}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.AppendLine($"Url: {context.Request.Url}, method: {context.Request.Method}");
|
||||||
|
return buffer.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
### Run the example
|
||||||
|
|
||||||
|
Lastly to run the example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ fission env create --name dotnet --image fission/dotnet20-env
|
||||||
|
|
||||||
|
$ fission function create --name httpinfo --env dotnet --code /tmp/func.cs
|
||||||
|
|
||||||
|
$ fission route create --method GET --url /http_info --function httpinfo
|
||||||
|
|
||||||
|
$ curl "http://$FISSION_ROUTER/http_info"
|
||||||
|
Accept
|
||||||
|
*/*;q=1
|
||||||
|
Host
|
||||||
|
fissionserver:8888
|
||||||
|
User-Agent
|
||||||
|
curl/7.47.0
|
||||||
|
Url: http://fissionserver:8888, method: GET
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Accessing http request body example
|
||||||
|
|
||||||
|
### Setup fission environment
|
||||||
|
First you need to setup the fission according to your cluster setup as
|
||||||
|
specified here: https://github.com/fission/fission
|
||||||
|
|
||||||
|
|
||||||
|
### Create the class to run
|
||||||
|
|
||||||
|
Secondly you need to create a file /tmp/func.cs containing the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization.Json;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context)
|
||||||
|
{
|
||||||
|
var person = Person.Deserialize(context.Request.Body);
|
||||||
|
return $"Hello, my name is {person.Name} and I am {person.Age} years old.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Age { get; set; }
|
||||||
|
|
||||||
|
public static Person Deserialize(Stream json)
|
||||||
|
{
|
||||||
|
var serializer = new DataContractJsonSerializer(typeof(Person));
|
||||||
|
return (Person)serializer.ReadObject(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
### Run the example
|
||||||
|
|
||||||
|
Lastly to run the example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ fission env create --name dotnet --image fission/dotnet20-env
|
||||||
|
|
||||||
|
$ fission function create --name httpbody --env dotnet --code /tmp/func.cs
|
||||||
|
|
||||||
|
$ fission route create --method GET --url /http_body --function httpbody
|
||||||
|
|
||||||
|
$ curl -XPOST "http://$FISSION_ROUTER/http_body" -d '{ "Name":"Arthur", "Age":42}'
|
||||||
|
Hello, my name is Arthur and I am 42 years old.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Developing/debugging the enviroment locally
|
||||||
|
|
||||||
|
The easiest way to debug the environment is to open the directory in
|
||||||
|
Visual Studio Code (VSCode) as that will setup debugger for you the
|
||||||
|
first time.
|
||||||
|
|
||||||
|
Remember to install the excellent extension
|
||||||
|
"C# for Visual Studio Code(powered by OmniSharp)" to get statement completion
|
||||||
|
|
||||||
|
The class ExecutorModule contain preprocessor directive overriding where
|
||||||
|
the input code file should be found:
|
||||||
|
|
||||||
|
```
|
||||||
|
#if DEBUG
|
||||||
|
private const string CODE_PATH = "/tmp/func.cs";
|
||||||
|
#else
|
||||||
|
private const string CODE_PATH = "/userfunc/user";
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
So what you need to do is:
|
||||||
|
1. Open the directory in VSCode.
|
||||||
|
This will prompt restore of packages and query is debugger setup is needed. Accept both prompts.
|
||||||
|
2. Press F5 to start the web server. Set breakpoints etc..
|
||||||
|
3. Add a code file containing valid C# at /tmp/func.cs
|
||||||
|
4. Specialize the service with curl via post
|
||||||
|
```
|
||||||
|
$ curl -XPOST http://localhost:8888/specialize
|
||||||
|
```
|
||||||
|
5. Call your function with curl
|
||||||
|
```
|
||||||
|
$ curl -XGET http://localhost:8888
|
||||||
|
```
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
THIS_DIR=$(realpath $(dirname $0))
|
||||||
|
|
||||||
|
docker run -v $THIS_DIR:/proj microsoft/dotnet:2.0.0-sdk sh -c "cd /proj && ./project-build.sh"
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.26730.12
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fission-dotnet20", "dotnet20\fission-dotnet20.csproj", "{3F044DE1-74E5-48F7-8D23-233C24AAA45C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{3F044DE1-74E5-48F7-8D23-233C24AAA45C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3F044DE1-74E5-48F7-8D23-233C24AAA45C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3F044DE1-74E5-48F7-8D23-233C24AAA45C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3F044DE1-74E5-48F7-8D23-233C24AAA45C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {272000F7-BBEC-4B61-8865-783EF7E5CEE9}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Nancy" Version="2.0.0-clinteastwood" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.3.2" />
|
||||||
|
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Runtime.Serialization.Json" Version="4.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
dotnet restore fission-dotnet20.csproj
|
||||||
|
dotnet publish fission-dotnet20.csproj -c Release -o out
|
||||||
@@ -3,6 +3,8 @@ package client
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
//"time"
|
//"time"
|
||||||
|
|
||||||
@@ -11,7 +13,19 @@ import (
|
|||||||
//"github.com/fission/fission/router"
|
//"github.com/fission/fission/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DoFetchRequest(fetcherUrl string, fr *fetcher.FetchRequest) error {
|
type (
|
||||||
|
Client struct {
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeClient(fetcherUrl string) *Client {
|
||||||
|
return &Client{
|
||||||
|
url: fetcherUrl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Fetch(fr *fetcher.FetchRequest) error {
|
||||||
body, err := json.Marshal(fr)
|
body, err := json.Marshal(fr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -21,7 +35,7 @@ func DoFetchRequest(fetcherUrl string, fr *fetcher.FetchRequest) error {
|
|||||||
// Transport: router.MakeRetryingRoundTripper(10, 50*time.Millisecond),
|
// Transport: router.MakeRetryingRoundTripper(10, 50*time.Millisecond),
|
||||||
// }
|
// }
|
||||||
|
|
||||||
resp, err := http.Post(fetcherUrl, "application/json", bytes.NewReader(body))
|
resp, err := http.Post(c.url, "application/json", bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -33,3 +47,34 @@ func DoFetchRequest(fetcherUrl string, fr *fetcher.FetchRequest) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Upload(fr *fetcher.UploadRequest) (*fetcher.UploadResponse, error) {
|
||||||
|
body, err := json.Marshal(fr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := http.Post(c.url+"/upload", "application/json", bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return nil, fission.MakeErrorFromHTTP(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
rBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Received upload response: %v", string(rBody))
|
||||||
|
|
||||||
|
uploadReq := fetcher.UploadResponse{}
|
||||||
|
err = json.Unmarshal([]byte(rBody), &uploadReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &uploadReq, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
fetcher := fetcher.MakeFetcher(dir)
|
fetcher := fetcher.MakeFetcher(dir)
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", fetcher.Handler)
|
mux.HandleFunc("/", fetcher.FetchHandler)
|
||||||
|
mux.HandleFunc("/upload", fetcher.UploadHandler)
|
||||||
http.ListenAndServe(":8000", mux)
|
http.ListenAndServe(":8000", mux)
|
||||||
}
|
}
|
||||||
|
|||||||
+135
-26
@@ -20,6 +20,7 @@ import (
|
|||||||
"k8s.io/client-go/1.5/pkg/api"
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
|
||||||
"github.com/fission/fission"
|
"github.com/fission/fission"
|
||||||
|
storageSvcClient "github.com/fission/fission/storagesvc/client"
|
||||||
"github.com/fission/fission/tpr"
|
"github.com/fission/fission/tpr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,12 +29,26 @@ type (
|
|||||||
|
|
||||||
FetchRequest struct {
|
FetchRequest struct {
|
||||||
FetchType FetchRequestType `json:"fetchType"`
|
FetchType FetchRequestType `json:"fetchType"`
|
||||||
Function api.ObjectMeta `json:"function"`
|
Package api.ObjectMeta `json:"package"`
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
StorageSvcUrl string `json:"storagesvcurl"`
|
StorageSvcUrl string `json:"storagesvcurl"`
|
||||||
Filename string `json:"filename"`
|
Filename string `json:"filename"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UploadRequest send from builder manager describes which
|
||||||
|
// deployment package should be upload to storage service.
|
||||||
|
UploadRequest struct {
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
StorageSvcUrl string `json:"storagesvcurl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadResponse defines the download url of an archive and
|
||||||
|
// its checksum.
|
||||||
|
UploadResponse struct {
|
||||||
|
ArchiveDownloadUrl string `json:"archiveDownloadUrl"`
|
||||||
|
Checksum fission.Checksum `json:"checksum"`
|
||||||
|
}
|
||||||
|
|
||||||
Fetcher struct {
|
Fetcher struct {
|
||||||
sharedVolumePath string
|
sharedVolumePath string
|
||||||
fissionClient *tpr.FissionClient
|
fissionClient *tpr.FissionClient
|
||||||
@@ -79,33 +94,44 @@ func downloadUrl(url string, localPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyChecksum(path string, checksum *fission.Checksum) error {
|
func getChecksum(path string) (*fission.Checksum, error) {
|
||||||
if checksum.Type != fission.ChecksumTypeSHA256 {
|
|
||||||
return fission.MakeError(fission.ErrorInvalidArgument, "Unsupported checksum type")
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
_, err = io.Copy(hasher, f)
|
_, err = io.Copy(hasher, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c := hex.EncodeToString(hasher.Sum(nil))
|
c := hex.EncodeToString(hasher.Sum(nil))
|
||||||
if c != checksum.Sum {
|
|
||||||
|
return &fission.Checksum{
|
||||||
|
Type: fission.ChecksumTypeSHA256,
|
||||||
|
Sum: c,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyChecksum(path string, checksum *fission.Checksum) error {
|
||||||
|
if checksum.Type != fission.ChecksumTypeSHA256 {
|
||||||
|
return fission.MakeError(fission.ErrorInvalidArgument, "Unsupported checksum type")
|
||||||
|
}
|
||||||
|
c, err := getChecksum(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.Sum != checksum.Sum {
|
||||||
return fission.MakeError(fission.ErrorChecksumFail, "Checksum validation failed")
|
return fission.MakeError(fission.ErrorChecksumFail, "Checksum validation failed")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fetcher *Fetcher) Handler(w http.ResponseWriter, r *http.Request) {
|
func (fetcher *Fetcher) FetchHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != "POST" {
|
if r.Method != "POST" {
|
||||||
http.Error(w, "", 405)
|
http.Error(w, "only POST is supported on this endpoint", 405)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,11 +155,13 @@ func (fetcher *Fetcher) Handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, err.Error(), 400)
|
http.Error(w, err.Error(), 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("fetcher received request: %v", req)
|
log.Printf("fetcher received fetch request: %v", req)
|
||||||
|
|
||||||
tmpFile := req.Filename + ".tmp"
|
tmpFile := req.Filename + ".tmp"
|
||||||
tmpPath := filepath.Join(fetcher.sharedVolumePath, tmpFile)
|
tmpPath := filepath.Join(fetcher.sharedVolumePath, tmpFile)
|
||||||
|
|
||||||
|
log.Printf("Start downloading...")
|
||||||
|
|
||||||
if req.FetchType == FETCH_URL {
|
if req.FetchType == FETCH_URL {
|
||||||
// fetch the file and save it to the tmp path
|
// fetch the file and save it to the tmp path
|
||||||
err := downloadUrl(req.Url, tmpPath)
|
err := downloadUrl(req.Url, tmpPath)
|
||||||
@@ -144,19 +172,8 @@ func (fetcher *Fetcher) Handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// get function object
|
|
||||||
fn, err := fetcher.fissionClient.Functions(req.Function.Namespace).Get(req.Function.Name)
|
|
||||||
if err != nil {
|
|
||||||
e := fmt.Sprintf("Failed to get function: %v", err)
|
|
||||||
log.Printf(e)
|
|
||||||
http.Error(w, e, 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// get pkg
|
// get pkg
|
||||||
var pkg *tpr.Package
|
pkg, err := fetcher.fissionClient.Packages(req.Package.Namespace).Get(req.Package.Name)
|
||||||
pkg, err = fetcher.fissionClient.
|
|
||||||
Packages(fn.Spec.Package.PackageRef.Namespace).Get(fn.Spec.Package.PackageRef.Name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := fmt.Sprintf("Failed to get package: %v", err)
|
e := fmt.Sprintf("Failed to get package: %v", err)
|
||||||
log.Printf(e)
|
log.Printf(e)
|
||||||
@@ -200,7 +217,6 @@ func (fetcher *Fetcher) Handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check file type here, if the file is a zip file unarchive it.
|
// check file type here, if the file is a zip file unarchive it.
|
||||||
@@ -229,6 +245,85 @@ func (fetcher *Fetcher) Handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fetcher *Fetcher) UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.Error(w, "only POST is supported on this endpoint", 405)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
defer func() {
|
||||||
|
elapsed := time.Now().Sub(startTime)
|
||||||
|
log.Printf("elapsed time in upload request = %v", elapsed)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// parse request
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error reading request body")
|
||||||
|
http.Error(w, err.Error(), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req UploadRequest
|
||||||
|
err = json.Unmarshal(body, &req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error reading request body: %v", err)
|
||||||
|
http.Error(w, err.Error(), 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("fetcher received upload request: %v", req)
|
||||||
|
|
||||||
|
zipFilename := req.Filename + ".zip"
|
||||||
|
srcFilepath := filepath.Join(fetcher.sharedVolumePath, req.Filename)
|
||||||
|
dstFilepath := filepath.Join(fetcher.sharedVolumePath, zipFilename)
|
||||||
|
|
||||||
|
err = fetcher.archive(srcFilepath, dstFilepath)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error archiving zip file: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Start uploading...")
|
||||||
|
ssClient := storageSvcClient.MakeClient(req.StorageSvcUrl)
|
||||||
|
|
||||||
|
fileID, err := ssClient.Upload(dstFilepath, nil)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error uploading zip file: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sum, err := getChecksum(dstFilepath)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error calculating checksum of zip file: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := UploadResponse{
|
||||||
|
ArchiveDownloadUrl: ssClient.GetUrl(fileID),
|
||||||
|
Checksum: *sum,
|
||||||
|
}
|
||||||
|
|
||||||
|
rBody, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("Error encoding upload response: %v", err)
|
||||||
|
log.Println(e)
|
||||||
|
http.Error(w, e, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Completed upload request")
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.Write(rBody)
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
func (fetcher *Fetcher) rename(src string, dst string) error {
|
func (fetcher *Fetcher) rename(src string, dst string) error {
|
||||||
err := os.Rename(src, dst)
|
err := os.Rename(src, dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -239,7 +334,21 @@ func (fetcher *Fetcher) rename(src string, dst string) error {
|
|||||||
|
|
||||||
// archive is a function that zips directory into a zip file
|
// archive is a function that zips directory into a zip file
|
||||||
func (fetcher *Fetcher) archive(src string, dst string) error {
|
func (fetcher *Fetcher) archive(src string, dst string) error {
|
||||||
return archiver.Zip.Make(dst, []string{src})
|
var files []string
|
||||||
|
target, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("Failed to zip file: %v", err))
|
||||||
|
}
|
||||||
|
if target.IsDir() {
|
||||||
|
// list all
|
||||||
|
fs, _ := ioutil.ReadDir(src)
|
||||||
|
for _, f := range fs {
|
||||||
|
files = append(files, filepath.Join(src, f.Name()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
files = append(files, src)
|
||||||
|
}
|
||||||
|
return archiver.Zip.Make(dst, files)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unarchive is a function that unzips a zip file to destination
|
// unarchive is a function that unzips a zip file to destination
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# A docker image for the func container.
|
# A docker image for the func container.
|
||||||
|
|
||||||
FROM node:7-onbuild
|
FROM node:8-onbuild
|
||||||
|
|
||||||
ADD server.js /usr/src/app/server.js
|
ADD server.js /usr/src/app/server.js
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
"node": ">=7.6.0"
|
"node": ">=7.6.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "",
|
"body-parser": "*",
|
||||||
"co": "~4.6.0",
|
"co": "~4.6.0",
|
||||||
"express": "",
|
"express": "*",
|
||||||
"minimist": "",
|
"minimist": "*",
|
||||||
"morgan": "",
|
"morgan": "*",
|
||||||
"mz": "~2.1.0",
|
"mz": "~2.7.0",
|
||||||
"request": "^2.81.0",
|
"request": "^2.81.0",
|
||||||
"request-promise-native": "^1.0.3",
|
"request-promise-native": "^1.0.3",
|
||||||
"underscore": ">=1.8.3"
|
"underscore": ">=1.8.3"
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ app.use(morgan('combined'))
|
|||||||
app.use(bodyParser.urlencoded({ extended: false }));
|
app.use(bodyParser.urlencoded({ extended: false }));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.raw());
|
app.use(bodyParser.raw());
|
||||||
|
app.use(bodyParser.text({ type : "text/*" }));
|
||||||
|
|
||||||
app.post('/specialize', specialize);
|
app.post('/specialize', specialize);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ RUN pip3 install --upgrade pip
|
|||||||
RUN rm -r /root/.cache
|
RUN rm -r /root/.cache
|
||||||
|
|
||||||
ADD defaultBuildCmd /usr/local/bin/build
|
ADD defaultBuildCmd /usr/local/bin/build
|
||||||
ADD builder /
|
ADD builder /builder
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8001
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
builderDir=${GOPATH}/src/github.com/fission/fission/builder/cmd
|
|
||||||
pushd ${builderDir}
|
|
||||||
GOOS=linux GOARCH=386 go build -o builder .
|
|
||||||
popd
|
|
||||||
cp ${builderDir}/builder .
|
|
||||||
docker build -t python-builder .
|
|
||||||
docker tag python-builder fission/python-builder:$tag
|
|
||||||
docker push fission/python-builder:$tag
|
|
||||||
|
|
||||||
@@ -3,21 +3,35 @@
|
|||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import imp
|
import imp
|
||||||
|
import os
|
||||||
|
|
||||||
from flask import Flask, request, abort, g
|
from flask import Flask, request, abort, g
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
codepath = '/userfunc/user'
|
|
||||||
|
|
||||||
userfunc = None
|
userfunc = None
|
||||||
|
|
||||||
@app.route('/specialize', methods=['POST'])
|
@app.route('/specialize', methods=['POST'])
|
||||||
def load():
|
def load():
|
||||||
global userfunc
|
global userfunc
|
||||||
|
# load user function from codepath
|
||||||
|
codepath = '/userfunc/user'
|
||||||
userfunc = (imp.load_source('user', codepath)).main
|
userfunc = (imp.load_source('user', codepath)).main
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@app.route('/v2/specialize', methods=['POST'])
|
||||||
|
def loadv2():
|
||||||
|
global userfunc
|
||||||
|
body = request.get_json()
|
||||||
|
filepath = body['filepath']
|
||||||
|
functionName = body['functionName']
|
||||||
|
# add filepath into syspath for module import
|
||||||
|
sys.path.append(filepath)
|
||||||
|
fn, path, desc = imp.find_module('user', [filepath])
|
||||||
|
mod = imp.load_module('user', fn, path, desc)
|
||||||
|
userfunc = getattr(mod, functionName)
|
||||||
|
return ""
|
||||||
|
|
||||||
@app.route('/', methods=['GET', 'POST', 'PUT', 'HEAD', 'OPTIONS', 'DELETE'])
|
@app.route('/', methods=['GET', 'POST', 'PUT', 'HEAD', 'OPTIONS', 'DELETE'])
|
||||||
def f():
|
def f():
|
||||||
if userfunc == None:
|
if userfunc == None:
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context){
|
||||||
|
var x = Convert.ToInt32(context.Arguments["x"]);
|
||||||
|
var y = Convert.ToInt32(context.Arguments["y"]);
|
||||||
|
return (x+y).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context){
|
||||||
|
context.Logger.WriteInfo("executing.. {0}", context.Arguments["text"]);
|
||||||
|
return (string)context.Arguments["text"];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context)
|
||||||
|
{
|
||||||
|
return "Hello World!";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization.Json;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context)
|
||||||
|
{
|
||||||
|
var person = Person.Deserialize(context.Request.Body);
|
||||||
|
return $"Hello, my name is {person.Name} and I am {person.Age} years old.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Age { get; set; }
|
||||||
|
|
||||||
|
public static Person Deserialize(Stream json)
|
||||||
|
{
|
||||||
|
var serializer = new DataContractJsonSerializer(typeof(Person));
|
||||||
|
return (Person)serializer.ReadObject(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using Fission.DotNetCore.Api;
|
||||||
|
|
||||||
|
public class FissionFunction
|
||||||
|
{
|
||||||
|
public string Execute(FissionContext context){
|
||||||
|
var buffer = new System.Text.StringBuilder();
|
||||||
|
foreach(var header in context.Request.Headers){
|
||||||
|
buffer.AppendLine(header.Key);
|
||||||
|
foreach(var item in header.Value){
|
||||||
|
buffer.AppendLine($"\t{item}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.AppendLine($"Url: {context.Request.Url}, method: {context.Request.Method}");
|
||||||
|
return buffer.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
pip3 install -r ${SRC_PKG}/requirements.txt -t ${SRC_PKG} && cp -r ${SRC_PKG} ${DEPLOY_PKG}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pyyaml
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
document = """
|
||||||
|
a: 1
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
d: 4
|
||||||
|
"""
|
||||||
|
|
||||||
|
def main():
|
||||||
|
return yaml.dump(yaml.load(document))
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
|
||||||
|
|||||||
+31
-13
@@ -6,6 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/docopt/docopt-go"
|
"github.com/docopt/docopt-go"
|
||||||
|
"github.com/fission/fission/buildermgr"
|
||||||
"github.com/fission/fission/controller"
|
"github.com/fission/fission/controller"
|
||||||
"github.com/fission/fission/kubewatcher"
|
"github.com/fission/fission/kubewatcher"
|
||||||
"github.com/fission/fission/logger"
|
"github.com/fission/fission/logger"
|
||||||
@@ -68,6 +69,13 @@ func runStorageSvc(port int, filePath string) {
|
|||||||
filePath, subdir, port)
|
filePath, subdir, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runBuilderMgr(port int, storageSvcUrl string, envBuilderNamespace string) {
|
||||||
|
err := buildermgr.Start(port, storageSvcUrl, envBuilderNamespace)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error starting buildermgr: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getPort(portArg interface{}) int {
|
func getPort(portArg interface{}) int {
|
||||||
portArgStr := portArg.(string)
|
portArgStr := portArg.(string)
|
||||||
port, err := strconv.Atoi(portArgStr)
|
port, err := strconv.Atoi(portArgStr)
|
||||||
@@ -113,23 +121,26 @@ Usage:
|
|||||||
fission-bundle --poolmgrPort=<port> [--namespace=<namespace>] [--fission-namespace=<namespace>]
|
fission-bundle --poolmgrPort=<port> [--namespace=<namespace>] [--fission-namespace=<namespace>]
|
||||||
fission-bundle --kubewatcher [--routerUrl=<url>]
|
fission-bundle --kubewatcher [--routerUrl=<url>]
|
||||||
fission-bundle --storageServicePort=<port> --filePath=<filePath>
|
fission-bundle --storageServicePort=<port> --filePath=<filePath>
|
||||||
|
fission-bundle --builderMgrPort=<port> [--storageSvcUrl=<url>] [--envbuilder-namespace=<namespace>]
|
||||||
fission-bundle --logger
|
fission-bundle --logger
|
||||||
fission-bundle --timer [--routerUrl=<url>]
|
fission-bundle --timer [--routerUrl=<url>]
|
||||||
fission-bundle --mqt [--routerUrl=<url>]
|
fission-bundle --mqt [--routerUrl=<url>]
|
||||||
Options:
|
Options:
|
||||||
--controllerPort=<port> Port that the controller should listen on.
|
--controllerPort=<port> Port that the controller should listen on.
|
||||||
--routerPort=<port> Port that the router should listen on.
|
--routerPort=<port> Port that the router should listen on.
|
||||||
--poolmgrPort=<port> Port that the poolmgr should listen on.
|
--poolmgrPort=<port> Port that the poolmgr should listen on.
|
||||||
--storageServicePort=<port> Port that the storage service should listen on.
|
--storageServicePort=<port> Port that the storage service should listen on.
|
||||||
--poolmgrUrl=<url> Poolmgr URL. Not required if --poolmgrPort is specified.
|
--builderMgrPort=<port> Port that the buildermgr should listen on.
|
||||||
--routerUrl=<url> Router URL.
|
--poolmgrUrl=<url> Poolmgr URL. Not required if --poolmgrPort is specified.
|
||||||
--etcdUrl=<etcdUrl> Etcd URL.
|
--routerUrl=<url> Router URL.
|
||||||
--filePath=<filePath> Directory to store functions in.
|
--etcdUrl=<etcdUrl> Etcd URL.
|
||||||
--namespace=<namespace> Kubernetes namespace in which to run function containers. Defaults to 'fission-function'.
|
--storageSvcUrl=<url> StorageService URL.
|
||||||
--kubewatcher Start Kubernetes events watcher.
|
--filePath=<filePath> Directory to store functions in.
|
||||||
--logger Start logger.
|
--namespace=<namespace> Kubernetes namespace in which to run function containers. Defaults to 'fission-function'.
|
||||||
--timer Start Timer.
|
--kubewatcher Start Kubernetes events watcher.
|
||||||
--mqt Start message queue trigger.
|
--logger Start logger.
|
||||||
|
--timer Start Timer.
|
||||||
|
--mqt Start message queue trigger.
|
||||||
`
|
`
|
||||||
arguments, err := docopt.Parse(usage, nil, true, "fission-bundle", false)
|
arguments, err := docopt.Parse(usage, nil, true, "fission-bundle", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -138,9 +149,11 @@ Options:
|
|||||||
|
|
||||||
functionNs := getStringArgWithDefault(arguments["--namespace"], "fission-function")
|
functionNs := getStringArgWithDefault(arguments["--namespace"], "fission-function")
|
||||||
fissionNs := getStringArgWithDefault(arguments["--fission-namespace"], "fission")
|
fissionNs := getStringArgWithDefault(arguments["--fission-namespace"], "fission")
|
||||||
|
envBuilderNs := getStringArgWithDefault(arguments["--envbuilder-namespace"], "fission-builder")
|
||||||
|
|
||||||
poolmgrUrl := getStringArgWithDefault(arguments["--poolmgrUrl"], "http://poolmgr.fission")
|
poolmgrUrl := getStringArgWithDefault(arguments["--poolmgrUrl"], "http://poolmgr.fission")
|
||||||
routerUrl := getStringArgWithDefault(arguments["--routerUrl"], "http://router.fission")
|
routerUrl := getStringArgWithDefault(arguments["--routerUrl"], "http://router.fission")
|
||||||
|
storageSvcUrl := getStringArgWithDefault(arguments["--storageSvcUrl"], "http://storagesvc.fission")
|
||||||
|
|
||||||
if arguments["--controllerPort"] != nil {
|
if arguments["--controllerPort"] != nil {
|
||||||
port := getPort(arguments["--controllerPort"])
|
port := getPort(arguments["--controllerPort"])
|
||||||
@@ -179,5 +192,10 @@ Options:
|
|||||||
runStorageSvc(port, filePath)
|
runStorageSvc(port, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if arguments["--builderMgrPort"] != nil {
|
||||||
|
port := getPort(arguments["--builderMgrPort"])
|
||||||
|
runBuilderMgr(port, storageSvcUrl, envBuilderNs)
|
||||||
|
}
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: router
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: router
|
|
||||||
spec:
|
|
||||||
type: LoadBalancer
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
nodePort: 31314
|
|
||||||
selector:
|
|
||||||
svc: router
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: controller
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: controller
|
|
||||||
spec:
|
|
||||||
type: LoadBalancer
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
nodePort: 31313
|
|
||||||
selector:
|
|
||||||
svc: controller
|
|
||||||
|
|
||||||
---
|
|
||||||
# If you want to switch to external db service, please checkout
|
|
||||||
# sample Kubernetes Service config in fission-logger.yaml.
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: influxdb
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: influxdb
|
|
||||||
spec:
|
|
||||||
type: LoadBalancer
|
|
||||||
ports:
|
|
||||||
- port: 8086
|
|
||||||
targetPort: 8086
|
|
||||||
nodePort: 31315
|
|
||||||
selector:
|
|
||||||
svc: influxdb
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: nats-streaming
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: nats-streaming
|
|
||||||
spec:
|
|
||||||
type: LoadBalancer
|
|
||||||
ports:
|
|
||||||
- port: 4222
|
|
||||||
targetPort: 4222
|
|
||||||
nodePort: 31316
|
|
||||||
selector:
|
|
||||||
svc: nats-streaming
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
# Sample Kubernetes Service config for external db service.
|
|
||||||
#
|
|
||||||
# apiVersion: v1
|
|
||||||
# kind: Service
|
|
||||||
# metadata:
|
|
||||||
# name: influxdb
|
|
||||||
# namespace: fission
|
|
||||||
# spec:
|
|
||||||
# ports:
|
|
||||||
# - name: "8086"
|
|
||||||
# port: 8086
|
|
||||||
# targetPort: 8086
|
|
||||||
# protocol: TCP
|
|
||||||
|
|
||||||
# ---
|
|
||||||
# apiVersion: v1
|
|
||||||
# kind: Endpoints
|
|
||||||
# metadata:
|
|
||||||
# name: influxdb
|
|
||||||
# namespace: fission
|
|
||||||
# subsets:
|
|
||||||
# - addresses:
|
|
||||||
# - ip: replace.influxdb.host.here
|
|
||||||
# ports:
|
|
||||||
# - name: "8086"
|
|
||||||
# port: 8086
|
|
||||||
# protocol: TCP
|
|
||||||
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: influxdb
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: influxdb
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: influxdb
|
|
||||||
image: tutum/influxdb
|
|
||||||
env:
|
|
||||||
- name: PRE_CREATE_DB
|
|
||||||
value: fissionFunctionLog
|
|
||||||
# Create a random username/password for InfluxDB here, and
|
|
||||||
# repeat it in the fluentd spec below.
|
|
||||||
- name: ADMIN_USER
|
|
||||||
value: ""
|
|
||||||
- name: INFLUXDB_INIT_PWD
|
|
||||||
value: ""
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: DaemonSet
|
|
||||||
metadata:
|
|
||||||
name: logger
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: logger
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: logger
|
|
||||||
image: fission/fission-bundle
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--logger"]
|
|
||||||
volumeMounts:
|
|
||||||
- name: container-log
|
|
||||||
mountPath: /var/log/containers
|
|
||||||
readOnly: true
|
|
||||||
- name: docker-log
|
|
||||||
mountPath: /var/lib/docker/containers
|
|
||||||
readOnly: true
|
|
||||||
- name: fission-log
|
|
||||||
mountPath: /var/log/fission
|
|
||||||
readOnly: false
|
|
||||||
ports:
|
|
||||||
- containerPort: 1234
|
|
||||||
hostPort: 1234
|
|
||||||
protocol: TCP
|
|
||||||
- name: fluentd
|
|
||||||
image: fission/fluentd
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
env:
|
|
||||||
- name: INFLUXDB_ADDRESS
|
|
||||||
value: influxdb
|
|
||||||
- name: INFLUXDB_PORT
|
|
||||||
value: "8086"
|
|
||||||
- name: INFLUXDB_DBNAME
|
|
||||||
value: "fissionFunctionLog"
|
|
||||||
# Username/password for fluentd to push logs to
|
|
||||||
# influxdb. This should match the influxdb
|
|
||||||
# username/passowrd defined above.
|
|
||||||
- name: INFLUXDB_USERNAME
|
|
||||||
value: ""
|
|
||||||
- name: INFLUXDB_PASSWD
|
|
||||||
value: ""
|
|
||||||
volumeMounts:
|
|
||||||
- name: container-log
|
|
||||||
mountPath: /var/log/containers
|
|
||||||
readOnly: true
|
|
||||||
- name: docker-log
|
|
||||||
mountPath: /var/lib/docker/containers
|
|
||||||
readOnly: true
|
|
||||||
- name: fission-log
|
|
||||||
mountPath: /var/log/fission
|
|
||||||
readOnly: false
|
|
||||||
volumes:
|
|
||||||
- name: container-log
|
|
||||||
hostPath:
|
|
||||||
path: /var/log/containers
|
|
||||||
- name: docker-log
|
|
||||||
hostPath:
|
|
||||||
path: /var/lib/docker/containers
|
|
||||||
- name: fission-log
|
|
||||||
hostPath:
|
|
||||||
path: /var/log/fission
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# To enable nats authentication, please follow the instruction described in
|
|
||||||
# http://nats.io/documentation/server/gnatsd-authentication/.
|
|
||||||
# And dont forget to change the MESSAGE_QUEUE_URL in mqtrigger deployment.
|
|
||||||
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: mqtrigger
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: mqtrigger
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: mqtrigger
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--mqt"]
|
|
||||||
env:
|
|
||||||
- name: MESSAGE_QUEUE_TYPE
|
|
||||||
value: nats-streaming
|
|
||||||
- name: MESSAGE_QUEUE_URL
|
|
||||||
value: nats://nats-streaming:4222
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: nats-streaming
|
|
||||||
name: nats-streaming
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
svc: nats-streaming
|
|
||||||
strategy:
|
|
||||||
rollingUpdate:
|
|
||||||
maxSurge: 1
|
|
||||||
maxUnavailable: 1
|
|
||||||
type: RollingUpdate
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
creationTimestamp: null
|
|
||||||
labels:
|
|
||||||
svc: nats-streaming
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nats-streaming
|
|
||||||
image: nats-streaming
|
|
||||||
args: ["--cluster_id", "fissionMQTrigger"]
|
|
||||||
ports:
|
|
||||||
- containerPort: 4222
|
|
||||||
hostPort: 4222
|
|
||||||
protocol: TCP
|
|
||||||
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: router
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: router
|
|
||||||
spec:
|
|
||||||
type: NodePort
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
nodePort: 31314
|
|
||||||
selector:
|
|
||||||
svc: router
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: controller
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: controller
|
|
||||||
spec:
|
|
||||||
type: NodePort
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
nodePort: 31313
|
|
||||||
selector:
|
|
||||||
svc: controller
|
|
||||||
|
|
||||||
---
|
|
||||||
# If you want to switch to external db service, please checkout
|
|
||||||
# sample Kubernetes Service config in fission-logger.yaml.
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: influxdb
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: influxdb
|
|
||||||
spec:
|
|
||||||
type: NodePort
|
|
||||||
ports:
|
|
||||||
- port: 8086
|
|
||||||
targetPort: 8086
|
|
||||||
nodePort: 31315
|
|
||||||
selector:
|
|
||||||
svc: influxdb
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: nats-streaming
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: nats-streaming
|
|
||||||
spec:
|
|
||||||
type: NodePort
|
|
||||||
ports:
|
|
||||||
- port: 4222
|
|
||||||
targetPort: 4222
|
|
||||||
nodePort: 31316
|
|
||||||
selector:
|
|
||||||
svc: nats-streaming
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ProjectRequest
|
|
||||||
metadata:
|
|
||||||
name: fission
|
|
||||||
labels:
|
|
||||||
name: fission
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ProjectRequest
|
|
||||||
metadata:
|
|
||||||
name: fission-function
|
|
||||||
labels:
|
|
||||||
name: fission-function
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ClusterRole
|
|
||||||
metadata:
|
|
||||||
name: fission:poolmgr
|
|
||||||
rules:
|
|
||||||
- apiGroups:
|
|
||||||
- extensions
|
|
||||||
attributeRestrictions: null
|
|
||||||
resources:
|
|
||||||
- deployments
|
|
||||||
verbs:
|
|
||||||
- create
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- update
|
|
||||||
- watch
|
|
||||||
- apiGroups:
|
|
||||||
- ""
|
|
||||||
attributeRestrictions: null
|
|
||||||
resources:
|
|
||||||
- pods
|
|
||||||
verbs:
|
|
||||||
- get
|
|
||||||
- list
|
|
||||||
- update
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: controller
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: controller
|
|
||||||
spec:
|
|
||||||
volumes:
|
|
||||||
- name: controller-storage
|
|
||||||
emptyDir: {}
|
|
||||||
containers:
|
|
||||||
- name: controller
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--controllerPort", "8888", "--filepath", "/filestore"]
|
|
||||||
volumeMounts:
|
|
||||||
- name: controller-storage
|
|
||||||
mountPath: /filestore
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: router
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: router
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: router
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--routerPort", "8888"]
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: poolmgr
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
selector:
|
|
||||||
svc: poolmgr
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: poolmgr
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: poolmgr
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--poolmgrPort", "8888"]
|
|
||||||
serviceAccount: poolmgr
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: kubewatcher
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: kubewatcher
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: kubewatcher
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--kubewatcher"]
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: etcd
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: etcd
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 2379
|
|
||||||
targetPort: 2379
|
|
||||||
selector:
|
|
||||||
svc: etcd
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: etcd
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: etcd
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: etcd
|
|
||||||
image: quay.io/coreos/etcd
|
|
||||||
env:
|
|
||||||
- name: ETCD_LISTEN_CLIENT_URLS
|
|
||||||
value: http://0.0.0.0:2379
|
|
||||||
- name: ETCD_ADVERTISE_CLIENT_URLS
|
|
||||||
value: http://etcd:2379
|
|
||||||
- name: ETCD_DATA_DIR
|
|
||||||
value: /tmp/default.etcd
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
groupNames: null
|
|
||||||
kind: RoleBinding
|
|
||||||
metadata:
|
|
||||||
name: fission:poolmgr
|
|
||||||
namespace: fission-function
|
|
||||||
roleRef:
|
|
||||||
name: fission:poolmgr
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
userNames:
|
|
||||||
- system:serviceaccount:fission:poolmgr
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Namespace
|
|
||||||
metadata:
|
|
||||||
name: fission
|
|
||||||
labels:
|
|
||||||
name: fission
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Namespace
|
|
||||||
metadata:
|
|
||||||
name: fission-function
|
|
||||||
labels:
|
|
||||||
name: fission-function
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: fission-svc
|
|
||||||
namespace: fission
|
|
||||||
---
|
|
||||||
kind: RoleBinding
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1alpha1
|
|
||||||
metadata:
|
|
||||||
name: fission-admin
|
|
||||||
namespace: fission
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: fission-svc
|
|
||||||
namespace: fission
|
|
||||||
roleRef:
|
|
||||||
kind: ClusterRole
|
|
||||||
name: admin
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
---
|
|
||||||
kind: RoleBinding
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1alpha1
|
|
||||||
metadata:
|
|
||||||
name: fission-function-admin
|
|
||||||
namespace: fission-function
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: fission-svc
|
|
||||||
namespace: fission
|
|
||||||
roleRef:
|
|
||||||
kind: ClusterRole
|
|
||||||
name: admin
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: fission-fetcher
|
|
||||||
namespace: fission-function
|
|
||||||
---
|
|
||||||
kind: ClusterRoleBinding
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
|
||||||
metadata:
|
|
||||||
name: fission-fetcher-tpr
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: fission-fetcher
|
|
||||||
namespace: fission-function
|
|
||||||
roleRef:
|
|
||||||
kind: ClusterRole
|
|
||||||
name: cluster-admin
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: controller
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: controller
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: controller
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--controllerPort", "8888"]
|
|
||||||
serviceAccountName: fission-svc
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: router
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: router
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: router
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--routerPort", "8888"]
|
|
||||||
serviceAccountName: fission-svc
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: poolmgr
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
selector:
|
|
||||||
svc: poolmgr
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: poolmgr
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: poolmgr
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--poolmgrPort", "8888"]
|
|
||||||
env:
|
|
||||||
- name: FETCHER_IMAGE
|
|
||||||
value: fission/fetcher:v2
|
|
||||||
serviceAccountName: fission-svc
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: kubewatcher
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: kubewatcher
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: kubewatcher
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--kubewatcher"]
|
|
||||||
serviceAccountName: fission-svc
|
|
||||||
-127
@@ -1,127 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Namespace
|
|
||||||
metadata:
|
|
||||||
name: fission
|
|
||||||
labels:
|
|
||||||
name: fission
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Namespace
|
|
||||||
metadata:
|
|
||||||
name: fission-function
|
|
||||||
labels:
|
|
||||||
name: fission-function
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: controller
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: controller
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: controller
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--controllerPort", "8888"]
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: router
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: router
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: router
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--routerPort", "8888"]
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
labels:
|
|
||||||
svc: poolmgr
|
|
||||||
spec:
|
|
||||||
ports:
|
|
||||||
- port: 80
|
|
||||||
targetPort: 8888
|
|
||||||
selector:
|
|
||||||
svc: poolmgr
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: poolmgr
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: poolmgr
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: poolmgr
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--poolmgrPort", "8888"]
|
|
||||||
env:
|
|
||||||
- name: FETCHER_IMAGE
|
|
||||||
value: fission/fetcher:v2
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: kubewatcher
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: kubewatcher
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: kubewatcher
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--kubewatcher"]
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: extensions/v1beta1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: timer
|
|
||||||
namespace: fission
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
svc: timer
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: timer
|
|
||||||
image: fission/fission-bundle
|
|
||||||
command: ["/fission-bundle"]
|
|
||||||
args: ["--timer"]
|
|
||||||
+20
-6
@@ -18,7 +18,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
@@ -42,12 +41,22 @@ func envCreate(c *cli.Context) error {
|
|||||||
fatal("Need an image, use --image.")
|
fatal("Need an image, use --image.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
envVersion := c.Int("version")
|
||||||
envBuilderImg := c.String("builder")
|
envBuilderImg := c.String("builder")
|
||||||
|
|
||||||
envBuildCmd := c.String("buildcmd")
|
envBuildCmd := c.String("buildcmd")
|
||||||
if len(envBuilderImg) > 0 && len(envBuildCmd) == 0 {
|
|
||||||
log.Printf("No build command is specified, use the default build command.")
|
if len(envBuilderImg) > 0 {
|
||||||
envBuildCmd = "build"
|
envVersion = 2
|
||||||
|
if len(envBuildCmd) == 0 {
|
||||||
|
envBuildCmd = "build"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment API interface version is not specified and
|
||||||
|
// builder image is empty, set default interface version
|
||||||
|
if envVersion == 0 {
|
||||||
|
fmt.Println("Use default environment v1 API interface")
|
||||||
|
envVersion = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
env := &tpr.Environment{
|
env := &tpr.Environment{
|
||||||
@@ -56,7 +65,7 @@ func envCreate(c *cli.Context) error {
|
|||||||
Namespace: api.NamespaceDefault,
|
Namespace: api.NamespaceDefault,
|
||||||
},
|
},
|
||||||
Spec: fission.EnvironmentSpec{
|
Spec: fission.EnvironmentSpec{
|
||||||
Version: 1,
|
Version: envVersion,
|
||||||
Runtime: fission.Runtime{
|
Runtime: fission.Runtime{
|
||||||
Image: envImg,
|
Image: envImg,
|
||||||
},
|
},
|
||||||
@@ -121,6 +130,11 @@ func envUpdate(c *cli.Context) error {
|
|||||||
if len(envImg) > 0 {
|
if len(envImg) > 0 {
|
||||||
env.Spec.Runtime.Image = envImg
|
env.Spec.Runtime.Image = envImg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if env.Spec.Version == 1 && (len(envBuilderImg) > 0 || len(envBuildCmd) > 0) {
|
||||||
|
fatal("Environment v1 API interface doesn't supported environment builder.")
|
||||||
|
}
|
||||||
|
|
||||||
if len(envBuilderImg) > 0 {
|
if len(envBuilderImg) > 0 {
|
||||||
env.Spec.Builder.Image = envBuilderImg
|
env.Spec.Builder.Image = envBuilderImg
|
||||||
}
|
}
|
||||||
|
|||||||
+127
-62
@@ -18,14 +18,16 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dchest/uniuri"
|
|
||||||
"github.com/satori/go.uuid"
|
"github.com/satori/go.uuid"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"k8s.io/client-go/1.5/pkg/api"
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
@@ -62,10 +64,67 @@ func createArchive(client *client.Client, fileName string) *fission.Archive {
|
|||||||
|
|
||||||
archive.Type = fission.ArchiveTypeUrl
|
archive.Type = fission.ArchiveTypeUrl
|
||||||
archive.URL = archiveUrl
|
archive.URL = archiveUrl
|
||||||
|
|
||||||
|
f, err := os.Open(fileName)
|
||||||
|
if err != nil {
|
||||||
|
checkErr(err, fmt.Sprintf("find file %v", fileName))
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
h := sha256.New()
|
||||||
|
if _, err := io.Copy(h, f); err != nil {
|
||||||
|
checkErr(err, fmt.Sprintf("calculate checksum for file %v", fileName))
|
||||||
|
}
|
||||||
|
|
||||||
|
archive.Checksum = fission.Checksum{
|
||||||
|
Type: fission.ChecksumTypeSHA256,
|
||||||
|
Sum: hex.EncodeToString(h.Sum(nil)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &archive
|
return &archive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createPackage(client *client.Client, envName, srcArchiveName, deployArchiveName, buildcmd string) *api.ObjectMeta {
|
||||||
|
pkgSpec := fission.PackageSpec{
|
||||||
|
Environment: fission.EnvironmentReference{
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
Name: envName,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
var pkgStatus fission.BuildStatus = fission.BuildStatusSucceeded
|
||||||
|
|
||||||
|
if len(deployArchiveName) > 0 {
|
||||||
|
pkgSpec.Deployment = *createArchive(client, deployArchiveName)
|
||||||
|
if len(srcArchiveName) > 0 {
|
||||||
|
fmt.Println("Deployment may be overwritten by builder manager after source package compilation")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(srcArchiveName) > 0 {
|
||||||
|
pkgSpec.Source = *createArchive(client, srcArchiveName)
|
||||||
|
// set pending status to package
|
||||||
|
pkgStatus = fission.BuildStatusPending
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(buildcmd) > 0 {
|
||||||
|
pkgSpec.BuildCommand = buildcmd
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgName := strings.ToLower(uuid.NewV4().String())
|
||||||
|
pkg := &tpr.Package{
|
||||||
|
Metadata: api.ObjectMeta{
|
||||||
|
Name: pkgName,
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: pkgSpec,
|
||||||
|
Status: fission.PackageStatus{
|
||||||
|
BuildStatus: pkgStatus,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pkgMetadata, err := client.PackageCreate(pkg)
|
||||||
|
checkErr(err, "create package")
|
||||||
|
return pkgMetadata
|
||||||
|
}
|
||||||
|
|
||||||
func getContents(filePath string) []byte {
|
func getContents(filePath string) []byte {
|
||||||
var code []byte
|
var code []byte
|
||||||
var err error
|
var err error
|
||||||
@@ -78,6 +137,10 @@ func getContents(filePath string) []byte {
|
|||||||
func fnCreate(c *cli.Context) error {
|
func fnCreate(c *cli.Context) error {
|
||||||
client := getClient(c.GlobalString("server"))
|
client := getClient(c.GlobalString("server"))
|
||||||
|
|
||||||
|
if len(c.String("package")) > 0 {
|
||||||
|
fatal("--package is deprecated, please use --deploy instead.")
|
||||||
|
}
|
||||||
|
|
||||||
fnName := c.String("name")
|
fnName := c.String("name")
|
||||||
if len(fnName) == 0 {
|
if len(fnName) == 0 {
|
||||||
fatal("Need --name argument.")
|
fatal("Need --name argument.")
|
||||||
@@ -88,17 +151,24 @@ func fnCreate(c *cli.Context) error {
|
|||||||
fatal("Need --env argument.")
|
fatal("Need --env argument.")
|
||||||
}
|
}
|
||||||
|
|
||||||
srcPkgName := c.String("srcpkg")
|
srcArchiveName := c.String("src")
|
||||||
|
deployArchiveName := c.String("code")
|
||||||
deployPkgName := c.String("code")
|
if len(deployArchiveName) == 0 {
|
||||||
if len(deployPkgName) == 0 {
|
deployArchiveName = c.String("deploy")
|
||||||
deployPkgName = c.String("package")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(srcPkgName) == 0 && len(deployPkgName) == 0 {
|
if len(srcArchiveName) == 0 && len(deployArchiveName) == 0 {
|
||||||
fatal("Need --code or --package to specify deployment package, or use --srcpkg to specify source package.")
|
fatal("Need --code or --deploy to specify deployment archive, or use --src to specify source archive.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entrypoint := c.String("entrypoint")
|
||||||
|
buildcmd := c.String("buildcmd")
|
||||||
|
if len(buildcmd) == 0 {
|
||||||
|
buildcmd = "/builder"
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgMetadata := createPackage(client, envName, srcArchiveName, deployArchiveName, buildcmd)
|
||||||
|
|
||||||
function := &tpr.Function{
|
function := &tpr.Function{
|
||||||
Metadata: api.ObjectMeta{
|
Metadata: api.ObjectMeta{
|
||||||
Name: fnName,
|
Name: fnName,
|
||||||
@@ -109,35 +179,18 @@ func fnCreate(c *cli.Context) error {
|
|||||||
Name: envName,
|
Name: envName,
|
||||||
Namespace: api.NamespaceDefault,
|
Namespace: api.NamespaceDefault,
|
||||||
},
|
},
|
||||||
|
Package: fission.FunctionPackageRef{
|
||||||
|
FunctionName: entrypoint,
|
||||||
|
PackageRef: fission.PackageRef{
|
||||||
|
Namespace: pkgMetadata.Namespace,
|
||||||
|
Name: pkgMetadata.Name,
|
||||||
|
ResourceVersion: pkgMetadata.ResourceVersion,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var pkgSpec fission.PackageSpec
|
_, err := client.FunctionCreate(function)
|
||||||
if len(srcPkgName) > 0 {
|
|
||||||
pkgSpec.Source = *createArchive(client, srcPkgName)
|
|
||||||
}
|
|
||||||
if len(deployPkgName) > 0 {
|
|
||||||
pkgSpec.Deployment = *createArchive(client, deployPkgName)
|
|
||||||
}
|
|
||||||
pkgName := fmt.Sprintf("%v-%v", fnName, strings.ToLower(uniuri.NewLen(6)))
|
|
||||||
pkg := &tpr.Package{
|
|
||||||
Metadata: api.ObjectMeta{
|
|
||||||
Name: pkgName,
|
|
||||||
Namespace: api.NamespaceDefault,
|
|
||||||
},
|
|
||||||
Spec: pkgSpec,
|
|
||||||
}
|
|
||||||
newpkg, err := client.PackageCreate(pkg)
|
|
||||||
checkErr(err, "create package")
|
|
||||||
|
|
||||||
function.Spec.Package = fission.FunctionPackageRef{
|
|
||||||
PackageRef: fission.PackageRef{
|
|
||||||
Name: newpkg.Name,
|
|
||||||
Namespace: newpkg.Namespace,
|
|
||||||
ResourceVersion: newpkg.ResourceVersion,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
_, err = client.FunctionCreate(function)
|
|
||||||
checkErr(err, "create function")
|
checkErr(err, "create function")
|
||||||
|
|
||||||
fmt.Printf("function '%v' created\n", fnName)
|
fmt.Printf("function '%v' created\n", fnName)
|
||||||
@@ -229,6 +282,10 @@ func fnUpdate(c *cli.Context) error {
|
|||||||
fatal("Need name of function, use --name")
|
fatal("Need name of function, use --name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.String("package")) > 0 {
|
||||||
|
fatal("--package is deprecated, please use --deploy instead.")
|
||||||
|
}
|
||||||
|
|
||||||
function, err := client.FunctionGet(&api.ObjectMeta{
|
function, err := client.FunctionGet(&api.ObjectMeta{
|
||||||
Name: fnName,
|
Name: fnName,
|
||||||
Namespace: api.NamespaceDefault,
|
Namespace: api.NamespaceDefault,
|
||||||
@@ -236,42 +293,50 @@ func fnUpdate(c *cli.Context) error {
|
|||||||
checkErr(err, fmt.Sprintf("read function '%v'", fnName))
|
checkErr(err, fmt.Sprintf("read function '%v'", fnName))
|
||||||
|
|
||||||
envName := c.String("env")
|
envName := c.String("env")
|
||||||
deployPkgName := c.String("code")
|
deployArchiveName := c.String("code")
|
||||||
if len(deployPkgName) == 0 {
|
if len(deployArchiveName) == 0 {
|
||||||
deployPkgName = c.String("package")
|
deployArchiveName = c.String("deploy")
|
||||||
}
|
}
|
||||||
srcPkgName := c.String("srcpkg")
|
srcArchiveName := c.String("src")
|
||||||
|
|
||||||
if len(envName) == 0 && len(deployPkgName) == 0 && len(srcPkgName) == 0 {
|
if len(envName) == 0 && len(deployArchiveName) == 0 && len(srcArchiveName) == 0 {
|
||||||
fatal("Need --env or --code or --package or --srcpkg argument.")
|
fatal("Need --env or --code or --package or --deploy argument.")
|
||||||
}
|
|
||||||
|
|
||||||
if len(deployPkgName) != 0 || len(srcPkgName) != 0 {
|
|
||||||
// get existing package
|
|
||||||
pkg, err := client.PackageGet(&api.ObjectMeta{
|
|
||||||
Name: function.Spec.Package.PackageRef.Name,
|
|
||||||
Namespace: function.Spec.Package.PackageRef.Namespace,
|
|
||||||
})
|
|
||||||
// update package spec
|
|
||||||
if len(srcPkgName) > 0 {
|
|
||||||
archive := createArchive(client, srcPkgName)
|
|
||||||
pkg.Spec.Source = *archive
|
|
||||||
}
|
|
||||||
if len(deployPkgName) > 0 {
|
|
||||||
archive := createArchive(client, deployPkgName)
|
|
||||||
pkg.Spec.Deployment = *archive
|
|
||||||
}
|
|
||||||
// updage package object
|
|
||||||
newpkg, err := client.PackageUpdate(pkg)
|
|
||||||
checkErr(err, "update package")
|
|
||||||
// update function spec with resource version
|
|
||||||
function.Spec.Package.PackageRef.ResourceVersion = newpkg.ResourceVersion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(envName) > 0 {
|
if len(envName) > 0 {
|
||||||
function.Spec.Environment.Name = envName
|
function.Spec.Environment.Name = envName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entrypoint := c.String("entrypoint")
|
||||||
|
if len(entrypoint) > 0 {
|
||||||
|
function.Spec.Package.FunctionName = entrypoint
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg, err := client.PackageGet(&api.ObjectMeta{
|
||||||
|
Name: function.Spec.Package.PackageRef.Name,
|
||||||
|
Namespace: function.Spec.Package.PackageRef.Namespace,
|
||||||
|
})
|
||||||
|
checkErr(err, fmt.Sprintf("read package '%v'", function.Spec.Package.PackageRef.Name))
|
||||||
|
|
||||||
|
buildcmd := c.String("buildcmd")
|
||||||
|
if len(buildcmd) == 0 {
|
||||||
|
// use previous build command if not specified.
|
||||||
|
buildcmd = pkg.Spec.BuildCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deployArchiveName) > 0 || len(srcArchiveName) > 0 {
|
||||||
|
// create a new package for function
|
||||||
|
pkgMetadata := createPackage(client,
|
||||||
|
function.Spec.Environment.Name, srcArchiveName, deployArchiveName, buildcmd)
|
||||||
|
|
||||||
|
// update function spec with resource version
|
||||||
|
function.Spec.Package.PackageRef = fission.PackageRef{
|
||||||
|
Namespace: pkgMetadata.Namespace,
|
||||||
|
Name: pkgMetadata.Name,
|
||||||
|
ResourceVersion: pkgMetadata.ResourceVersion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_, err = client.FunctionUpdate(function)
|
_, err = client.FunctionUpdate(function)
|
||||||
checkErr(err, "update function")
|
checkErr(err, "update function")
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -26,7 +26,7 @@ func main() {
|
|||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "fission"
|
app.Name = "fission"
|
||||||
app.Usage = "Serverless functions for Kubernetes"
|
app.Usage = "Serverless functions for Kubernetes"
|
||||||
app.Version = "0.2.1"
|
app.Version = "0.3.0"
|
||||||
|
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
cli.StringFlag{Name: "server", Usage: "Fission server URL", EnvVar: "FISSION_URL"},
|
cli.StringFlag{Name: "server", Usage: "Fission server URL", EnvVar: "FISSION_URL"},
|
||||||
@@ -40,17 +40,20 @@ func main() {
|
|||||||
fnNameFlag := cli.StringFlag{Name: "name", Usage: "function name"}
|
fnNameFlag := cli.StringFlag{Name: "name", Usage: "function name"}
|
||||||
fnEnvNameFlag := cli.StringFlag{Name: "env", Usage: "environment name for function"}
|
fnEnvNameFlag := cli.StringFlag{Name: "env", Usage: "environment name for function"}
|
||||||
fnCodeFlag := cli.StringFlag{Name: "code", Usage: "local path or URL for source code"}
|
fnCodeFlag := cli.StringFlag{Name: "code", Usage: "local path or URL for source code"}
|
||||||
fnPackageFlag := cli.StringFlag{Name: "package", Usage: "local path or URL for binary package"}
|
fnPackageFlag := cli.StringFlag{Name: "package", Usage: "(Deprecated) local path or URL for binary package"}
|
||||||
fnSrcPackageFlag := cli.StringFlag{Name: "srcpkg", Usage: "local path or URL for source package"}
|
fnDeployArchiveFlag := cli.StringFlag{Name: "deployarchive, deploy", Usage: "local path or URL for deployment archive"}
|
||||||
|
fnSrcArchiveFlag := cli.StringFlag{Name: "sourcearchive, src", Usage: "local path or URL for source archive"}
|
||||||
fnPodFlag := cli.StringFlag{Name: "pod", Usage: "function pod name, optional (use latest if unspecified)"}
|
fnPodFlag := cli.StringFlag{Name: "pod", Usage: "function pod name, optional (use latest if unspecified)"}
|
||||||
fnFollowFlag := cli.BoolFlag{Name: "follow, f", Usage: "specify if the logs should be streamed"}
|
fnFollowFlag := cli.BoolFlag{Name: "follow, f", Usage: "specify if the logs should be streamed"}
|
||||||
fnDetailFlag := cli.BoolFlag{Name: "detail, d", Usage: "display detailed information"}
|
fnDetailFlag := cli.BoolFlag{Name: "detail, d", Usage: "display detailed information"}
|
||||||
fnLogDBTypeFlag := cli.StringFlag{Name: "dbtype", Usage: "log database type, e.g. influxdb (currently only influxdb is supported)"}
|
fnLogDBTypeFlag := cli.StringFlag{Name: "dbtype", Usage: "log database type, e.g. influxdb (currently only influxdb is supported)"}
|
||||||
|
fnEntryPointFlag := cli.StringFlag{Name: "entrypoint", Usage: "entry point for environment v2 to load with"}
|
||||||
|
fnBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "build command for builder to run with"}
|
||||||
fnSubcommands := []cli.Command{
|
fnSubcommands := []cli.Command{
|
||||||
{Name: "create", Usage: "Create new function (and optionally, an HTTP route to it)", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcPackageFlag, htUrlFlag, htMethodFlag}, Action: fnCreate},
|
{Name: "create", Usage: "Create new function (and optionally, an HTTP route to it)", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnEntryPointFlag, fnBuildCmdFlag, htUrlFlag, htMethodFlag}, Action: fnCreate},
|
||||||
{Name: "get", Usage: "Get function source code", Flags: []cli.Flag{fnNameFlag}, Action: fnGet},
|
{Name: "get", Usage: "Get function source code", Flags: []cli.Flag{fnNameFlag}, Action: fnGet},
|
||||||
{Name: "getmeta", Usage: "Get function metadata", Flags: []cli.Flag{fnNameFlag}, Action: fnGetMeta},
|
{Name: "getmeta", Usage: "Get function metadata", Flags: []cli.Flag{fnNameFlag}, Action: fnGetMeta},
|
||||||
{Name: "update", Usage: "Update function source code", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcPackageFlag}, Action: fnUpdate},
|
{Name: "update", Usage: "Update function source code", Flags: []cli.Flag{fnNameFlag, fnEnvNameFlag, fnCodeFlag, fnPackageFlag, fnSrcArchiveFlag, fnDeployArchiveFlag, fnEntryPointFlag, fnBuildCmdFlag}, Action: fnUpdate},
|
||||||
{Name: "delete", Usage: "Delete function", Flags: []cli.Flag{fnNameFlag}, Action: fnDelete},
|
{Name: "delete", Usage: "Delete function", Flags: []cli.Flag{fnNameFlag}, Action: fnDelete},
|
||||||
{Name: "list", Usage: "List all functions", Flags: []cli.Flag{}, Action: fnList},
|
{Name: "list", Usage: "List all functions", Flags: []cli.Flag{}, Action: fnList},
|
||||||
{Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag}, Action: fnLogs},
|
{Name: "logs", Usage: "Display function logs", Flags: []cli.Flag{fnNameFlag, fnPodFlag, fnFollowFlag, fnDetailFlag, fnLogDBTypeFlag}, Action: fnLogs},
|
||||||
@@ -100,8 +103,9 @@ func main() {
|
|||||||
envImageFlag := cli.StringFlag{Name: "image", Usage: "Environment image URL"}
|
envImageFlag := cli.StringFlag{Name: "image", Usage: "Environment image URL"}
|
||||||
envBuilderImageFlag := cli.StringFlag{Name: "builder", Usage: "Environment builder image URL (optional)"}
|
envBuilderImageFlag := cli.StringFlag{Name: "builder", Usage: "Environment builder image URL (optional)"}
|
||||||
envBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "Build command for environment builder to build source package (optional)"}
|
envBuildCmdFlag := cli.StringFlag{Name: "buildcmd", Usage: "Build command for environment builder to build source package (optional)"}
|
||||||
|
envVersionFlag := cli.IntFlag{Name: "version", Usage: "Environment API version: defaults to 1 (means v1 interface)"}
|
||||||
envSubcommands := []cli.Command{
|
envSubcommands := []cli.Command{
|
||||||
{Name: "create", Aliases: []string{"add"}, Usage: "Add an environment", Flags: []cli.Flag{envNameFlag, envImageFlag, envBuilderImageFlag, envBuildCmdFlag}, Action: envCreate},
|
{Name: "create", Aliases: []string{"add"}, Usage: "Add an environment", Flags: []cli.Flag{envNameFlag, envImageFlag, envBuilderImageFlag, envBuildCmdFlag, envVersionFlag}, Action: envCreate},
|
||||||
{Name: "get", Usage: "Get environment details", Flags: []cli.Flag{envNameFlag}, Action: envGet},
|
{Name: "get", Usage: "Get environment details", Flags: []cli.Flag{envNameFlag}, Action: envGet},
|
||||||
{Name: "update", Usage: "Update environment", Flags: []cli.Flag{envNameFlag, envImageFlag, envBuilderImageFlag, envBuildCmdFlag}, Action: envUpdate},
|
{Name: "update", Usage: "Update environment", Flags: []cli.Flag{envNameFlag, envImageFlag, envBuilderImageFlag, envBuildCmdFlag}, Action: envUpdate},
|
||||||
{Name: "delete", Usage: "Delete environment", Flags: []cli.Flag{envNameFlag}, Action: envDelete},
|
{Name: "delete", Usage: "Delete environment", Flags: []cli.Flag{envNameFlag}, Action: envDelete},
|
||||||
@@ -125,7 +129,7 @@ func main() {
|
|||||||
upgradeFileFlag := cli.StringFlag{Name: "file", Usage: "JSON file containing all fission state"}
|
upgradeFileFlag := cli.StringFlag{Name: "file", Usage: "JSON file containing all fission state"}
|
||||||
upgradeSubCommands := []cli.Command{
|
upgradeSubCommands := []cli.Command{
|
||||||
{Name: "dump", Usage: "Dump all state from a v0.1 fission installation", Flags: []cli.Flag{upgradeFileFlag}, Action: upgradeDumpState},
|
{Name: "dump", Usage: "Dump all state from a v0.1 fission installation", Flags: []cli.Flag{upgradeFileFlag}, Action: upgradeDumpState},
|
||||||
{Name: "restore", Usage: "Restore state dumped from a v0.1 install into a v0.2 install", Flags: []cli.Flag{upgradeFileFlag}, Action: upgradeRestoreState},
|
{Name: "restore", Usage: "Restore state dumped from a v0.1 install into a v0.2+ install", Flags: []cli.Flag{upgradeFileFlag}, Action: upgradeRestoreState},
|
||||||
}
|
}
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []cli.Command{
|
||||||
{Name: "function", Aliases: []string{"fn"}, Usage: "Create, update and manage functions", Subcommands: fnSubcommands},
|
{Name: "function", Aliases: []string{"fn"}, Usage: "Create, update and manage functions", Subcommands: fnSubcommands},
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# deploy.sh - (Almost) automatic setup of a Fission Workflows deployment
|
||||||
|
#
|
||||||
|
|
||||||
|
# Configs
|
||||||
|
FISSION_VERSION=0.3.0-rc
|
||||||
|
FISSION_WORKFLOWS_VERSION=0.1.0
|
||||||
|
|
||||||
|
echo "Fission Workflows Deploy Script v1"
|
||||||
|
|
||||||
|
# Check if kubectl is installed
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
echo "kubectl is not installed"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if minikube is installed
|
||||||
|
if ! command -v minikube >/dev/null 2>&1 ; then
|
||||||
|
echo "minikube is not installed."
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if helm is installed
|
||||||
|
if ! command -v helm >/dev/null 2>&1 ; then
|
||||||
|
echo "helm is not installed."
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure that minikube is running
|
||||||
|
if ! minikube ip >/dev/null 2>&1 ; then
|
||||||
|
echo "Starting minikube cluster..."
|
||||||
|
minikube start
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install helm on cluster
|
||||||
|
if ! helm list >/dev/null 2>&1 ; then
|
||||||
|
echo "Installing helm..."
|
||||||
|
kubectl -n kube-system create sa tiller
|
||||||
|
|
||||||
|
kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller
|
||||||
|
|
||||||
|
helm init --service-account tiller
|
||||||
|
|
||||||
|
printf "Waiting for Helm"
|
||||||
|
until helm list >/dev/null 2>&1
|
||||||
|
do
|
||||||
|
printf "."
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
printf "\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output debug logs
|
||||||
|
echo "---------- Debug ----------"
|
||||||
|
minikube version
|
||||||
|
printf "K8S "
|
||||||
|
kubectl version --client --short
|
||||||
|
printf "K8S "
|
||||||
|
kubectl version --short | grep Server
|
||||||
|
printf "Helm "
|
||||||
|
helm version --short -c
|
||||||
|
printf "Helm "
|
||||||
|
helm version --short -s
|
||||||
|
echo "Fission: ${FISSION_VERSION}"
|
||||||
|
echo "Fission Workflows: ${FISSION_WORKFLOWS_VERSION}"
|
||||||
|
echo "---------------------------"
|
||||||
|
|
||||||
|
# Ensure that fission-charts helm repo is added
|
||||||
|
if ! helm repo list | grep fission-charts >/dev/null 2>&1 ; then
|
||||||
|
echo "Setting up fission-charts Helm repo..."
|
||||||
|
helm repo add fission-charts https://fission.github.io/fission-charts/
|
||||||
|
helm repo update
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install Fission
|
||||||
|
if ! fission fn list >/dev/null 2>&1 ; then
|
||||||
|
echo "Installing Fission..."
|
||||||
|
helm install --namespace fission --set serviceType=NodePort -n fission-all fission-charts/fission-all --wait --version ${FISSION_VERSION}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install Fission Workflows
|
||||||
|
if ! fission env get --name workflow >/dev/null 2>&1 ; then
|
||||||
|
echo "Installing Fission Workflows..."
|
||||||
|
if [[ -z "${FISSION_WORKFLOWS_VERSION// }" ]] ; then
|
||||||
|
helm install -n fission-workflows fission-charts/fission-workflows --wait --version ${FISSION_WORKFLOWS_VERSION}
|
||||||
|
else
|
||||||
|
helm install -n fission-workflows fission-charts/fission-workflows --wait
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -106,7 +106,9 @@ build_and_push_env_image() {
|
|||||||
./build.sh
|
./build.sh
|
||||||
fi
|
fi
|
||||||
docker build -t fission/$imgname:$version .
|
docker build -t fission/$imgname:$version .
|
||||||
|
docker tag fission/$imgname:$version fission/$imgname:latest
|
||||||
docker push fission/$imgname:$version
|
docker push fission/$imgname:$version
|
||||||
|
docker push fission/$imgname:latest
|
||||||
popd
|
popd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +118,7 @@ build_and_push_all_envs() {
|
|||||||
build_and_push_env_image $version nodejs node-env
|
build_and_push_env_image $version nodejs node-env
|
||||||
build_and_push_env_image $version binary binary-env
|
build_and_push_env_image $version binary binary-env
|
||||||
build_and_push_env_image $version dotnet dotnet-env
|
build_and_push_env_image $version dotnet dotnet-env
|
||||||
|
build_and_push_env_image $version dotnet20 dotnet20-env
|
||||||
build_and_push_env_image $version go go-env
|
build_and_push_env_image $version go go-env
|
||||||
build_and_push_env_image $version perl perl-env
|
build_and_push_env_image $version perl perl-env
|
||||||
build_and_push_env_image $version php7 php-env
|
build_and_push_env_image $version php7 php-env
|
||||||
|
|||||||
@@ -165,8 +165,9 @@ func (mqt *MessageQueueTriggerManager) syncTriggers() {
|
|||||||
log.Fatalf("Failed to read message queue trigger list: %v", err)
|
log.Fatalf("Failed to read message queue trigger list: %v", err)
|
||||||
}
|
}
|
||||||
newTriggerMap := make(map[string]*tpr.Messagequeuetrigger)
|
newTriggerMap := make(map[string]*tpr.Messagequeuetrigger)
|
||||||
for _, trigger := range newTriggers.Items {
|
for index := range newTriggers.Items {
|
||||||
newTriggerMap[tpr.CacheKey(&trigger.Metadata)] = &trigger
|
newTrigger := &newTriggers.Items[index]
|
||||||
|
newTriggerMap[tpr.CacheKey(&newTrigger.Metadata)] = newTrigger
|
||||||
}
|
}
|
||||||
|
|
||||||
// get current set of triggers
|
// get current set of triggers
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/client-go/1.5/pkg/api"
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
|
||||||
|
"github.com/fission/fission"
|
||||||
"github.com/fission/fission/cache"
|
"github.com/fission/fission/cache"
|
||||||
"github.com/fission/fission/tpr"
|
"github.com/fission/fission/tpr"
|
||||||
)
|
)
|
||||||
@@ -58,6 +59,7 @@ type (
|
|||||||
address string
|
address string
|
||||||
podName string
|
podName string
|
||||||
age time.Duration
|
age time.Duration
|
||||||
|
env *api.ObjectMeta // used for ListOld
|
||||||
responseChannel chan *fscResponse
|
responseChannel chan *fscResponse
|
||||||
}
|
}
|
||||||
fscResponse struct {
|
fscResponse struct {
|
||||||
@@ -97,7 +99,9 @@ func (fsc *functionServiceCache) service() {
|
|||||||
resp.error = err
|
resp.error = err
|
||||||
} else {
|
} else {
|
||||||
fsvc := fsvcI.(*funcSvc)
|
fsvc := fsvcI.(*funcSvc)
|
||||||
if time.Now().Sub(fsvc.atime) > req.age {
|
if fsvc.environment.Metadata.UID == req.env.UID &&
|
||||||
|
time.Now().Sub(fsvc.atime) > req.age {
|
||||||
|
|
||||||
podName := podNameI.(string)
|
podName := podNameI.(string)
|
||||||
pods = append(pods, podName)
|
pods = append(pods, podName)
|
||||||
}
|
}
|
||||||
@@ -134,6 +138,7 @@ func (fsc *functionServiceCache) GetByFunction(m *api.ObjectMeta) (*funcSvc, err
|
|||||||
return &fsvcCopy, nil
|
return &fsvcCopy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: error should be second return
|
||||||
func (fsc *functionServiceCache) Add(fsvc funcSvc) (error, *funcSvc) {
|
func (fsc *functionServiceCache) Add(fsvc funcSvc) (error, *funcSvc) {
|
||||||
err, existing := fsc.byFunction.Set(tpr.CacheKey(fsvc.function), &fsvc)
|
err, existing := fsc.byFunction.Set(tpr.CacheKey(fsvc.function), &fsvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -152,13 +157,25 @@ func (fsc *functionServiceCache) Add(fsvc funcSvc) (error, *funcSvc) {
|
|||||||
fsvc.ctime = now
|
fsvc.ctime = now
|
||||||
fsvc.atime = now
|
fsvc.atime = now
|
||||||
|
|
||||||
|
// Add to byAddress and byPod caches. Ignore NameExists errors
|
||||||
|
// because of multiple-specialization. See issue #331.
|
||||||
err, _ = fsc.byAddress.Set(fsvc.address, *fsvc.function)
|
err, _ = fsc.byAddress.Set(fsvc.address, *fsvc.function)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if fe, ok := err.(fission.Error); ok {
|
||||||
|
if fe.Code == fission.ErrorNameExists {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
log.Printf("error caching fsvc: %v", err)
|
log.Printf("error caching fsvc: %v", err)
|
||||||
return err, nil
|
return err, nil
|
||||||
}
|
}
|
||||||
err, _ = fsc.byPod.Set(fsvc.podName, *fsvc.function)
|
err, _ = fsc.byPod.Set(fsvc.podName, *fsvc.function)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if fe, ok := err.(fission.Error); ok {
|
||||||
|
if fe.Code == fission.ErrorNameExists {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
log.Printf("error caching fsvc: %v", err)
|
log.Printf("error caching fsvc: %v", err)
|
||||||
return err, nil
|
return err, nil
|
||||||
}
|
}
|
||||||
@@ -227,11 +244,12 @@ func (fsc *functionServiceCache) _deleteByPod(podName string, minAge time.Durati
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsc *functionServiceCache) ListOld(age time.Duration) ([]string, error) {
|
func (fsc *functionServiceCache) ListOld(env *api.ObjectMeta, age time.Duration) ([]string, error) {
|
||||||
responseChannel := make(chan *fscResponse)
|
responseChannel := make(chan *fscResponse)
|
||||||
fsc.requestChannel <- &fscRequest{
|
fsc.requestChannel <- &fscRequest{
|
||||||
requestType: LISTOLD,
|
requestType: LISTOLD,
|
||||||
age: age,
|
age: age,
|
||||||
|
env: env,
|
||||||
responseChannel: responseChannel,
|
responseChannel: responseChannel,
|
||||||
}
|
}
|
||||||
resp := <-responseChannel
|
resp := <-responseChannel
|
||||||
|
|||||||
+104
-47
@@ -27,6 +27,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -61,10 +62,13 @@ type (
|
|||||||
poolInstanceId string // small random string to uniquify pod names
|
poolInstanceId string // small random string to uniquify pod names
|
||||||
fetcherImage string
|
fetcherImage string
|
||||||
fetcherImagePullPolicy v1.PullPolicy
|
fetcherImagePullPolicy v1.PullPolicy
|
||||||
|
runtimeImagePullPolicy v1.PullPolicy // pull policy for generic pool to created env deployment
|
||||||
kubernetesClient *kubernetes.Clientset
|
kubernetesClient *kubernetes.Clientset
|
||||||
|
fissionClient *tpr.FissionClient
|
||||||
instanceId string // poolmgr instance id
|
instanceId string // poolmgr instance id
|
||||||
labelsForPool map[string]string
|
labelsForPool map[string]string
|
||||||
requestChannel chan *choosePodRequest
|
requestChannel chan *choosePodRequest
|
||||||
|
sharedMountPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize the choosing of pods so that choices don't conflict
|
// serialize the choosing of pods so that choices don't conflict
|
||||||
@@ -78,7 +82,19 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getImagePullPolicy(policy string) v1.PullPolicy {
|
||||||
|
switch policy {
|
||||||
|
case "Always":
|
||||||
|
return v1.PullAlways
|
||||||
|
case "Never":
|
||||||
|
return v1.PullNever
|
||||||
|
default:
|
||||||
|
return v1.PullIfNotPresent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MakeGenericPool(
|
func MakeGenericPool(
|
||||||
|
fissionClient *tpr.FissionClient,
|
||||||
kubernetesClient *kubernetes.Clientset,
|
kubernetesClient *kubernetes.Clientset,
|
||||||
env *tpr.Environment,
|
env *tpr.Environment,
|
||||||
initialReplicas int32,
|
initialReplicas int32,
|
||||||
@@ -92,9 +108,13 @@ func MakeGenericPool(
|
|||||||
if len(fetcherImage) == 0 {
|
if len(fetcherImage) == 0 {
|
||||||
fetcherImage = "fission/fetcher"
|
fetcherImage = "fission/fetcher"
|
||||||
}
|
}
|
||||||
fetcherImagePullPolicyS := os.Getenv("FETCHER_IMAGE_PULL_POLICY")
|
fetcherImagePullPolicy := os.Getenv("FETCHER_IMAGE_PULL_POLICY")
|
||||||
if len(fetcherImagePullPolicyS) == 0 {
|
if len(fetcherImagePullPolicy) == 0 {
|
||||||
fetcherImagePullPolicyS = "IfNotPresent"
|
fetcherImagePullPolicy = "IfNotPresent"
|
||||||
|
}
|
||||||
|
runtimeImagePullPolicy := os.Getenv("RUNTIME_IMAGE_PULL_POLICY")
|
||||||
|
if len(runtimeImagePullPolicy) == 0 {
|
||||||
|
runtimeImagePullPolicy = "IfNotPresent"
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: in general we need to provide the user a way to configure pools. Initial
|
// TODO: in general we need to provide the user a way to configure pools. Initial
|
||||||
@@ -103,6 +123,7 @@ func MakeGenericPool(
|
|||||||
env: env,
|
env: env,
|
||||||
replicas: initialReplicas, // TODO make this an env param instead?
|
replicas: initialReplicas, // TODO make this an env param instead?
|
||||||
requestChannel: make(chan *choosePodRequest),
|
requestChannel: make(chan *choosePodRequest),
|
||||||
|
fissionClient: fissionClient,
|
||||||
kubernetesClient: kubernetesClient,
|
kubernetesClient: kubernetesClient,
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
podReadyTimeout: 5 * time.Minute, // TODO make this an env param?
|
podReadyTimeout: 5 * time.Minute, // TODO make this an env param?
|
||||||
@@ -111,18 +132,13 @@ func MakeGenericPool(
|
|||||||
poolInstanceId: uniuri.NewLen(8),
|
poolInstanceId: uniuri.NewLen(8),
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
fetcherImage: fetcherImage,
|
fetcherImage: fetcherImage,
|
||||||
useSvc: false, // defaults off -- svc takes a second or more to become routable, slowing cold start
|
useSvc: false, // defaults off -- svc takes a second or more to become routable, slowing cold start
|
||||||
|
sharedMountPath: "/userfunc", // used by generic pool when creating env deployment to specify the share volume path for fetcher & env
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fetcherImagePullPolicyS {
|
gp.runtimeImagePullPolicy = getImagePullPolicy(runtimeImagePullPolicy)
|
||||||
case "Always":
|
|
||||||
gp.fetcherImagePullPolicy = v1.PullAlways
|
|
||||||
case "Never":
|
|
||||||
gp.fetcherImagePullPolicy = v1.PullNever
|
|
||||||
default:
|
|
||||||
gp.fetcherImagePullPolicy = v1.PullIfNotPresent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
gp.fetcherImagePullPolicy = getImagePullPolicy(fetcherImagePullPolicy)
|
||||||
log.Printf("fetcher image: %v, pull policy: %v", gp.fetcherImage, gp.fetcherImagePullPolicy)
|
log.Printf("fetcher image: %v, pull policy: %v", gp.fetcherImage, gp.fetcherImagePullPolicy)
|
||||||
|
|
||||||
// Labels for generic deployment/RS/pods.
|
// Labels for generic deployment/RS/pods.
|
||||||
@@ -141,7 +157,10 @@ func MakeGenericPool(
|
|||||||
|
|
||||||
go gp.choosePodService()
|
go gp.choosePodService()
|
||||||
|
|
||||||
go gp.idlePodReaper()
|
// Unless specified otherwise, periodically cleanup inactive pods.
|
||||||
|
if env.Spec.AllowedFunctionsPerContainer != fission.AllowedFunctionsPerContainerInfinite {
|
||||||
|
go gp.idlePodReaper()
|
||||||
|
}
|
||||||
|
|
||||||
return gp, nil
|
return gp, nil
|
||||||
}
|
}
|
||||||
@@ -186,8 +205,7 @@ func (gp *GenericPool) _choosePod(newLabels map[string]string) (*v1.Pod, error)
|
|||||||
// Get pods; filter the ones that are ready
|
// Get pods; filter the ones that are ready
|
||||||
podList, err := gp.kubernetesClient.Core().Pods(gp.namespace).List(
|
podList, err := gp.kubernetesClient.Core().Pods(gp.namespace).List(
|
||||||
api.ListOptions{
|
api.ListOptions{
|
||||||
LabelSelector: labels.Set(
|
LabelSelector: labels.Set(gp.deployment.Spec.Selector.MatchLabels).AsSelector(),
|
||||||
gp.deployment.Spec.Selector.MatchLabels).AsSelector(),
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -212,8 +230,7 @@ func (gp *GenericPool) _choosePod(newLabels map[string]string) (*v1.Pod, error)
|
|||||||
readyPods = append(readyPods, &pod)
|
readyPods = append(readyPods, &pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("[%v] found %v ready pods of %v total",
|
log.Printf("[%v] found %v ready pods of %v total", newLabels, len(readyPods), len(podList.Items))
|
||||||
newLabels, len(readyPods), len(podList.Items))
|
|
||||||
|
|
||||||
// If there are no ready pods, wait and retry.
|
// If there are no ready pods, wait and retry.
|
||||||
if len(readyPods) == 0 {
|
if len(readyPods) == 0 {
|
||||||
@@ -229,15 +246,17 @@ func (gp *GenericPool) _choosePod(newLabels map[string]string) (*v1.Pod, error)
|
|||||||
// and make a good scheduling decision.
|
// and make a good scheduling decision.
|
||||||
chosenPod := readyPods[rand.Intn(len(readyPods))]
|
chosenPod := readyPods[rand.Intn(len(readyPods))]
|
||||||
|
|
||||||
// Relabel. If the pod already got picked and
|
if gp.env.Spec.AllowedFunctionsPerContainer != fission.AllowedFunctionsPerContainerInfinite {
|
||||||
// modified, this should fail; in that case just
|
// Relabel. If the pod already got picked and
|
||||||
// retry.
|
// modified, this should fail; in that case just
|
||||||
chosenPod.ObjectMeta.Labels = newLabels
|
// retry.
|
||||||
log.Printf("relabeling pod: [%v]", chosenPod.ObjectMeta.Name)
|
chosenPod.ObjectMeta.Labels = newLabels
|
||||||
_, err = gp.kubernetesClient.Core().Pods(gp.namespace).Update(chosenPod)
|
log.Printf("relabeling pod: [%v]", chosenPod.ObjectMeta.Name)
|
||||||
if err != nil {
|
_, err = gp.kubernetesClient.Core().Pods(gp.namespace).Update(chosenPod)
|
||||||
log.Printf("failed to relabel pod [%v]: %v", chosenPod.ObjectMeta.Name, err)
|
if err != nil {
|
||||||
continue
|
log.Printf("failed to relabel pod [%v]: %v", chosenPod.ObjectMeta.Name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Chosen pod: %v (in %v)", chosenPod.ObjectMeta.Name, time.Now().Sub(startTime))
|
log.Printf("Chosen pod: %v (in %v)", chosenPod.ObjectMeta.Name, time.Now().Sub(startTime))
|
||||||
return chosenPod, nil
|
return chosenPod, nil
|
||||||
@@ -276,12 +295,15 @@ func (gp *GenericPool) getFetcherUrl(podIP string) string {
|
|||||||
return fmt.Sprintf("http://%v:8000/", podIP)
|
return fmt.Sprintf("http://%v:8000/", podIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gp *GenericPool) getSpecializeUrl(podIP string) string {
|
func (gp *GenericPool) getSpecializeUrl(podIP string, version int) string {
|
||||||
u := os.Getenv("TEST_SPECIALIZE_URL")
|
u := os.Getenv("TEST_SPECIALIZE_URL")
|
||||||
if len(u) != 0 {
|
if len(u) != 0 {
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("http://%v:8888/specialize", podIP)
|
if version == 1 {
|
||||||
|
return fmt.Sprintf("http://%v:8888/specialize", podIP)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("http://%v:8888/v%v/specialize", podIP, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// specializePod chooses a pod, copies the required user-defined function to that pod
|
// specializePod chooses a pod, copies the required user-defined function to that pod
|
||||||
@@ -297,10 +319,23 @@ func (gp *GenericPool) specializePod(pod *v1.Pod, metadata *api.ObjectMeta) erro
|
|||||||
// tell fetcher to get the function.
|
// tell fetcher to get the function.
|
||||||
fetcherUrl := gp.getFetcherUrl(podIP)
|
fetcherUrl := gp.getFetcherUrl(podIP)
|
||||||
log.Printf("[%v] calling fetcher to copy function", metadata.Name)
|
log.Printf("[%v] calling fetcher to copy function", metadata.Name)
|
||||||
err := fetcherClient.DoFetchRequest(fetcherUrl, &fetcher.FetchRequest{
|
|
||||||
|
fn, err := gp.fissionClient.
|
||||||
|
Functions(metadata.Namespace).
|
||||||
|
Get(metadata.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetFilename := "user"
|
||||||
|
|
||||||
|
err = fetcherClient.MakeClient(fetcherUrl).Fetch(&fetcher.FetchRequest{
|
||||||
FetchType: fetcher.FETCH_DEPLOYMENT,
|
FetchType: fetcher.FETCH_DEPLOYMENT,
|
||||||
Function: *metadata,
|
Package: api.ObjectMeta{
|
||||||
Filename: "user", // XXX use function id instead
|
Namespace: fn.Spec.Package.PackageRef.Namespace,
|
||||||
|
Name: fn.Spec.Package.PackageRef.Name,
|
||||||
|
},
|
||||||
|
Filename: targetFilename, // XXX use function id instead
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -311,12 +346,30 @@ func (gp *GenericPool) specializePod(pod *v1.Pod, metadata *api.ObjectMeta) erro
|
|||||||
|
|
||||||
// get function run container to specialize
|
// get function run container to specialize
|
||||||
log.Printf("[%v] specializing pod", metadata.Name)
|
log.Printf("[%v] specializing pod", metadata.Name)
|
||||||
specializeUrl := gp.getSpecializeUrl(podIP)
|
|
||||||
|
|
||||||
// retry the specialize call a few times in case the env server hasn't come up yet
|
// retry the specialize call a few times in case the env server hasn't come up yet
|
||||||
maxRetries := 20
|
maxRetries := 20
|
||||||
|
|
||||||
|
loadReq := fission.FunctionLoadRequest{
|
||||||
|
FilePath: filepath.Join(gp.sharedMountPath, targetFilename),
|
||||||
|
FunctionName: fn.Spec.Package.FunctionName,
|
||||||
|
FunctionMetadata: &fn.Metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := json.Marshal(loadReq)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < maxRetries; i++ {
|
for i := 0; i < maxRetries; i++ {
|
||||||
resp2, err := http.Post(specializeUrl, "text/plain", bytes.NewReader([]byte{}))
|
var resp2 *http.Response
|
||||||
|
if gp.env.Spec.Version == 2 {
|
||||||
|
specializeUrl := gp.getSpecializeUrl(podIP, 2)
|
||||||
|
resp2, err = http.Post(specializeUrl, "application/json", bytes.NewReader(body))
|
||||||
|
} else {
|
||||||
|
specializeUrl := gp.getSpecializeUrl(podIP, 1)
|
||||||
|
resp2, err = http.Post(specializeUrl, "text/plain", bytes.NewReader([]byte{}))
|
||||||
|
}
|
||||||
if err == nil && resp2.StatusCode < 300 {
|
if err == nil && resp2.StatusCode < 300 {
|
||||||
// Success
|
// Success
|
||||||
resp2.Body.Close()
|
resp2.Body.Close()
|
||||||
@@ -352,7 +405,6 @@ func (gp *GenericPool) createPool() error {
|
|||||||
poolDeploymentName := fmt.Sprintf("%v-%v-%v",
|
poolDeploymentName := fmt.Sprintf("%v-%v-%v",
|
||||||
gp.env.Metadata.Name, gp.env.Metadata.UID, strings.ToLower(gp.poolInstanceId))
|
gp.env.Metadata.Name, gp.env.Metadata.UID, strings.ToLower(gp.poolInstanceId))
|
||||||
|
|
||||||
sharedMountPath := "/userfunc"
|
|
||||||
deployment := &v1beta1.Deployment{
|
deployment := &v1beta1.Deployment{
|
||||||
ObjectMeta: v1.ObjectMeta{
|
ObjectMeta: v1.ObjectMeta{
|
||||||
Name: poolDeploymentName,
|
Name: poolDeploymentName,
|
||||||
@@ -380,12 +432,12 @@ func (gp *GenericPool) createPool() error {
|
|||||||
{
|
{
|
||||||
Name: gp.env.Metadata.Name,
|
Name: gp.env.Metadata.Name,
|
||||||
Image: gp.env.Spec.Runtime.Image,
|
Image: gp.env.Spec.Runtime.Image,
|
||||||
ImagePullPolicy: v1.PullIfNotPresent,
|
ImagePullPolicy: gp.runtimeImagePullPolicy,
|
||||||
TerminationMessagePath: "/dev/termination-log",
|
TerminationMessagePath: "/dev/termination-log",
|
||||||
VolumeMounts: []v1.VolumeMount{
|
VolumeMounts: []v1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "userfunc",
|
Name: "userfunc",
|
||||||
MountPath: sharedMountPath,
|
MountPath: gp.sharedMountPath,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -397,10 +449,10 @@ func (gp *GenericPool) createPool() error {
|
|||||||
VolumeMounts: []v1.VolumeMount{
|
VolumeMounts: []v1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "userfunc",
|
Name: "userfunc",
|
||||||
MountPath: sharedMountPath,
|
MountPath: gp.sharedMountPath,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Command: []string{"/fetcher", sharedMountPath},
|
Command: []string{"/fetcher", gp.sharedMountPath},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ServiceAccountName: "fission-fetcher",
|
ServiceAccountName: "fission-fetcher",
|
||||||
@@ -478,7 +530,7 @@ func (gp *GenericPool) GetFuncSvc(m *api.ObjectMeta) (*funcSvc, error) {
|
|||||||
if gp.useSvc {
|
if gp.useSvc {
|
||||||
svcName := fmt.Sprintf("svc-%v", m.Name)
|
svcName := fmt.Sprintf("svc-%v", m.Name)
|
||||||
if len(m.UID) > 0 {
|
if len(m.UID) > 0 {
|
||||||
svcName += ("-" + string(m.UID))
|
svcName = fmt.Sprintf("%s-%v", svcName, m.UID)
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := gp.labelsForFunction(m)
|
labels := gp.labelsForFunction(m)
|
||||||
@@ -511,13 +563,18 @@ func (gp *GenericPool) GetFuncSvc(m *api.ObjectMeta) (*funcSvc, error) {
|
|||||||
|
|
||||||
err, existingFsvc := gp.fsCache.Add(*fsvc)
|
err, existingFsvc := gp.fsCache.Add(*fsvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Some other thread beat us to it -- return the other thread's fsvc and clean up
|
if fe, ok := err.(fission.Error); ok {
|
||||||
// our own.
|
if fe.Code == fission.ErrorNameExists {
|
||||||
log.Printf("func svc already exists: %v", existingFsvc.podName)
|
// Some other thread beat us to it -- return the other thread's fsvc and clean up
|
||||||
go func() {
|
// our own.
|
||||||
gp.kubernetesClient.Core().Pods(gp.namespace).Delete(fsvc.podName, nil)
|
log.Printf("func svc already exists: %v", existingFsvc.podName)
|
||||||
}()
|
go func() {
|
||||||
return existingFsvc, nil
|
gp.kubernetesClient.Core().Pods(gp.namespace).Delete(fsvc.podName, nil)
|
||||||
|
}()
|
||||||
|
return existingFsvc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return fsvc, nil
|
return fsvc, nil
|
||||||
}
|
}
|
||||||
@@ -563,7 +620,7 @@ func (gp *GenericPool) CleanupFunctionService(podName string) error {
|
|||||||
func (gp *GenericPool) idlePodReaper() {
|
func (gp *GenericPool) idlePodReaper() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Minute)
|
time.Sleep(time.Minute)
|
||||||
podNames, err := gp.fsCache.ListOld(gp.idlePodReapTime)
|
podNames, err := gp.fsCache.ListOld(&gp.env.Metadata, gp.idlePodReapTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error reaping idle pods: %v", err)
|
log.Printf("Error reaping idle pods: %v", err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
+8
-2
@@ -23,6 +23,7 @@ import (
|
|||||||
"k8s.io/client-go/1.5/kubernetes"
|
"k8s.io/client-go/1.5/kubernetes"
|
||||||
"k8s.io/client-go/1.5/pkg/api"
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
|
||||||
|
"github.com/fission/fission"
|
||||||
"github.com/fission/fission/tpr"
|
"github.com/fission/fission/tpr"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -86,9 +87,14 @@ func (gpm *GenericPoolManager) service() {
|
|||||||
var err error
|
var err error
|
||||||
pool, ok := gpm.pools[tpr.CacheKey(&req.env.Metadata)]
|
pool, ok := gpm.pools[tpr.CacheKey(&req.env.Metadata)]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
var poolSize int32 = 3 // TODO configurable/autoscalable
|
||||||
|
switch req.env.Spec.AllowedFunctionsPerContainer {
|
||||||
|
case fission.AllowedFunctionsPerContainerInfinite:
|
||||||
|
poolSize = 1
|
||||||
|
}
|
||||||
|
|
||||||
pool, err = MakeGenericPool(
|
pool, err = MakeGenericPool(
|
||||||
gpm.kubernetesClient, req.env,
|
gpm.fissionClient, gpm.kubernetesClient, req.env, poolSize,
|
||||||
3, // TODO configurable/autoscalable
|
|
||||||
gpm.namespace, gpm.fsCache, gpm.instanceId)
|
gpm.namespace, gpm.fsCache, gpm.instanceId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.responseChannel <- &response{error: err}
|
req.responseChannel <- &response{error: err}
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ func (fh *functionHandler) handler(responseWriter http.ResponseWriter, request *
|
|||||||
request.Header.Add(fmt.Sprintf("X-Fission-Params-%v", k), v)
|
request.Header.Add(fmt.Sprintf("X-Fission-Params-%v", k), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// System Params
|
||||||
|
MetadataToHeaders(HEADERS_FISSION_FUNCTION_PREFIX, fh.function, request)
|
||||||
|
|
||||||
// cache lookup
|
// cache lookup
|
||||||
serviceUrl, err := fh.fmap.lookup(fh.function)
|
serviceUrl, err := fh.fmap.lookup(fh.function)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -115,9 +115,10 @@ func (ts *HTTPTriggerSet) getRouter() *mux.Router {
|
|||||||
// Internal triggers for each function by name. Non-http
|
// Internal triggers for each function by name. Non-http
|
||||||
// triggers route into these.
|
// triggers route into these.
|
||||||
for _, function := range ts.functions {
|
for _, function := range ts.functions {
|
||||||
|
m := function.Metadata
|
||||||
fh := &functionHandler{
|
fh := &functionHandler{
|
||||||
fmap: ts.functionServiceMap,
|
fmap: ts.functionServiceMap,
|
||||||
function: &function.Metadata,
|
function: &m,
|
||||||
poolmgr: ts.poolmgr,
|
poolmgr: ts.poolmgr,
|
||||||
}
|
}
|
||||||
muxRouter.HandleFunc(fission.UrlForFunction(function.Metadata.Name), fh.handler)
|
muxRouter.HandleFunc(fission.UrlForFunction(function.Metadata.Name), fh.handler)
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"k8s.io/client-go/1.5/pkg/api"
|
||||||
|
"k8s.io/client-go/1.5/pkg/types"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
HEADERS_FISSION_FUNCTION_PREFIX = "Fission-Function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MetadataToHeaders(prefix string, meta *api.ObjectMeta, request *http.Request) {
|
||||||
|
request.Header.Add(fmt.Sprintf("X-%s-Uid", prefix), string(meta.UID))
|
||||||
|
request.Header.Add(fmt.Sprintf("X-%s-Name", prefix), meta.Name)
|
||||||
|
request.Header.Add(fmt.Sprintf("X-%s-Namespace", prefix), meta.Namespace)
|
||||||
|
request.Header.Add(fmt.Sprintf("X-%s-ResourceVersion", prefix), meta.ResourceVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HeadersToMetadata(prefix string, headers http.Header) *api.ObjectMeta {
|
||||||
|
return &api.ObjectMeta{
|
||||||
|
Name: headers.Get(fmt.Sprintf("X-%s-Name", prefix)),
|
||||||
|
UID: types.UID(headers.Get(fmt.Sprintf("X-%s-Uid", prefix))),
|
||||||
|
Namespace: headers.Get(fmt.Sprintf("X-%s-Namespace", prefix)),
|
||||||
|
ResourceVersion: headers.Get(fmt.Sprintf("X-%s-ResourceVersion", prefix)),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -201,6 +201,21 @@ func MakeStorageService(sc *storageConfig) (*StorageService, error) {
|
|||||||
ss.location = loc
|
ss.location = loc
|
||||||
|
|
||||||
con, err := loc.CreateContainer(sc.containerName)
|
con, err := loc.CreateContainer(sc.containerName)
|
||||||
|
if os.IsExist(err) {
|
||||||
|
var cons []stow.Container
|
||||||
|
var cursor string
|
||||||
|
|
||||||
|
// use location.Containers to find containers that match the prefix (container name)
|
||||||
|
cons, cursor, err = loc.Containers(sc.containerName, stow.CursorStart, 1)
|
||||||
|
if err == nil {
|
||||||
|
if !stow.IsCursorEnd(cursor) {
|
||||||
|
// Should only have one storage container
|
||||||
|
err = errors.New("Found more than one matched storage containers")
|
||||||
|
} else {
|
||||||
|
con = cons[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error initializing storage: %v", err)
|
log.Printf("Error initializing storage: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -12,12 +12,18 @@ source $(dirname $0)/test_utils.sh
|
|||||||
|
|
||||||
IMAGE=gcr.io/fission-ci/fission-bundle
|
IMAGE=gcr.io/fission-ci/fission-bundle
|
||||||
FETCHER_IMAGE=gcr.io/fission-ci/fetcher
|
FETCHER_IMAGE=gcr.io/fission-ci/fetcher
|
||||||
|
PYTHON_RUNTIME_IMAGE=gcr.io/fission-ci/python-env
|
||||||
|
PYTHON_BUILDER_IMAGE=gcr.io/fission-ci/python-env-builder
|
||||||
TAG=test
|
TAG=test
|
||||||
|
|
||||||
build_and_push_fission_bundle $IMAGE:$TAG
|
build_and_push_fission_bundle $IMAGE:$TAG
|
||||||
|
|
||||||
build_and_push_fetcher $FETCHER_IMAGE:$TAG
|
build_and_push_fetcher $FETCHER_IMAGE:$TAG
|
||||||
|
|
||||||
|
build_and_push_python_env_runtime $PYTHON_RUNTIME_IMAGE:$TAG
|
||||||
|
|
||||||
|
build_and_push_python_env_builder $PYTHON_BUILDER_IMAGE:$TAG
|
||||||
|
|
||||||
build_fission_cli
|
build_fission_cli
|
||||||
|
|
||||||
install_and_test $IMAGE $TAG $FETCHER_IMAGE $TAG
|
install_and_test $IMAGE $TAG $FETCHER_IMAGE $TAG
|
||||||
|
|||||||
+32
-1
@@ -50,6 +50,36 @@ build_and_push_fetcher() {
|
|||||||
popd
|
popd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_and_push_python_env_runtime() {
|
||||||
|
image_tag=$1
|
||||||
|
|
||||||
|
pushd $ROOT/environments/python3/
|
||||||
|
docker build -t $image_tag .
|
||||||
|
|
||||||
|
gcloud_login
|
||||||
|
|
||||||
|
gcloud docker -- push $image_tag
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
build_and_push_python_env_builder() {
|
||||||
|
image_tag=$1
|
||||||
|
|
||||||
|
pushd $ROOT/builder/cmd
|
||||||
|
./build.sh
|
||||||
|
popd
|
||||||
|
pushd $ROOT/environments/python3/builder
|
||||||
|
builderDir=${GOPATH}/src/github.com/fission/fission/builder/cmd
|
||||||
|
cp ${builderDir}/builder .
|
||||||
|
|
||||||
|
docker build -t $image_tag .
|
||||||
|
|
||||||
|
gcloud_login
|
||||||
|
|
||||||
|
gcloud docker -- push $image_tag
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
build_fission_cli() {
|
build_fission_cli() {
|
||||||
pushd $ROOT/fission
|
pushd $ROOT/fission
|
||||||
@@ -73,7 +103,7 @@ helm_install_fission() {
|
|||||||
ns=f-$id
|
ns=f-$id
|
||||||
fns=f-func-$id
|
fns=f-func-$id
|
||||||
|
|
||||||
helmVars=image=$image,imageTag=$imageTag,fetcherImage=$fetcherImage,fetcherImageTag=$fetcherImageTag,functionNamespace=$fns,controllerPort=$controllerNodeport,routerPort=$routerNodeport,pullPolicy=Always
|
helmVars=image=$image,imageTag=$imageTag,fetcherImage=$fetcherImage,fetcherImageTag=$fetcherImageTag,functionNamespace=$fns,controllerPort=$controllerNodeport,routerPort=$routerNodeport,pullPolicy=Always,analytics=false
|
||||||
|
|
||||||
helm_setup
|
helm_setup
|
||||||
|
|
||||||
@@ -171,6 +201,7 @@ dump_fission_tpr() {
|
|||||||
|
|
||||||
dump_fission_tprs() {
|
dump_fission_tprs() {
|
||||||
dump_fission_tpr function.fission.io
|
dump_fission_tpr function.fission.io
|
||||||
|
dump_fission_tpr package.fission.io
|
||||||
dump_fission_tpr httptrigger.fission.io
|
dump_fission_tpr httptrigger.fission.io
|
||||||
dump_fission_tpr environment.fission.io
|
dump_fission_tpr environment.fission.io
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+73
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Create a function with source package in python
|
||||||
|
# to test builder manger functionality.
|
||||||
|
# There are two ways to trigger the build
|
||||||
|
# 1. manually trigger by http post
|
||||||
|
# 2. package watcher triggers the build if any changes to packages
|
||||||
|
|
||||||
|
ROOT=$(dirname $0)/../..
|
||||||
|
PYTHON_RUNTIME_IMAGE=gcr.io/fission-ci/python-env:test
|
||||||
|
PYTHON_BUILDER_IMAGE=gcr.io/fission-ci/python-env-builder:test
|
||||||
|
|
||||||
|
fn=python-srcbuild-$(date +%s)
|
||||||
|
|
||||||
|
checkFunctionResponse() {
|
||||||
|
echo "Doing an HTTP GET on the function's route"
|
||||||
|
response=$(curl http://$FISSION_ROUTER/$1)
|
||||||
|
|
||||||
|
echo "Checking for valid response"
|
||||||
|
echo $response
|
||||||
|
echo $response | grep -i "a: 1 b: {c: 3, d: 4}"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Pre-test cleanup"
|
||||||
|
fission env delete --name python || true
|
||||||
|
|
||||||
|
echo "Creating python env"
|
||||||
|
fission env create --name python --image $PYTHON_RUNTIME_IMAGE --builder $PYTHON_BUILDER_IMAGE
|
||||||
|
trap "fission env delete --name python" EXIT
|
||||||
|
|
||||||
|
echo "Waiting for env builder to catch up"
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
echo "Creating source pacakage"
|
||||||
|
zip -jr demo-src-pkg.zip $ROOT/examples/python/sourcepkg/
|
||||||
|
|
||||||
|
echo "Creating function " $fn
|
||||||
|
fission fn create --name $fn --env python --src demo-src-pkg.zip --entrypoint "main" --buildcmd "./build.sh"
|
||||||
|
trap "fission fn delete --name $fn" EXIT
|
||||||
|
|
||||||
|
echo "Creating route"
|
||||||
|
fission route create --function $fn --url /$fn --method GET
|
||||||
|
|
||||||
|
echo "Waiting for router to catch up"
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo "Doing an HTTP POST on the builder manager's route to start a build"
|
||||||
|
pkg=$(kubectl --namespace default get functions $fn -o jsonpath='{.spec.package.packageref.name}')
|
||||||
|
echo $pkg
|
||||||
|
response=$(curl -X POST $FISSION_URL/proxy/buildermgr/v1/build \
|
||||||
|
-H 'content-type: application/json' \
|
||||||
|
-d "{\"package\": {\"namespace\": \"default\",\"name\": \"$pkg\"}}")
|
||||||
|
|
||||||
|
echo "Waiting for builder manager to finish the build triggered by http request"
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
checkFunctionResponse $fn
|
||||||
|
|
||||||
|
echo "Updating function " $fn
|
||||||
|
fission fn update --name $fn --src demo-src-pkg.zip
|
||||||
|
trap "fission fn delete --name $fn" EXIT
|
||||||
|
|
||||||
|
echo "Waiting for builder manager to finish the build triggered by packageWatcher"
|
||||||
|
sleep 30
|
||||||
|
|
||||||
|
checkFunctionResponse $fn
|
||||||
|
|
||||||
|
# crappy cleanup, improve this later
|
||||||
|
kubectl get httptrigger -o name | tail -1 | cut -f2 -d'/' | xargs kubectl delete httptrigger
|
||||||
|
|
||||||
|
echo "All done."
|
||||||
Executable
+46
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create two functions, make sure their internal http triggers invoke
|
||||||
|
# them correctly.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT=$(dirname $0)/../..
|
||||||
|
|
||||||
|
echo "Pre-test cleanup"
|
||||||
|
fission env delete --name nodejs || true
|
||||||
|
|
||||||
|
echo "Creating nodejs env"
|
||||||
|
fission env create --name nodejs --image fission/node-env
|
||||||
|
trap "fission env delete --name nodejs" EXIT
|
||||||
|
|
||||||
|
echo "Writing functions"
|
||||||
|
f1=f1-$(date +%s)
|
||||||
|
f2=f2-$(date +%s)
|
||||||
|
echo $f1 $f2
|
||||||
|
|
||||||
|
for f in $f1 $f2
|
||||||
|
do
|
||||||
|
echo "module.exports = function(context, callback) { callback(200, \"$f\n\"); }" > $f.js
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Creating functions"
|
||||||
|
for f in $f1 $f2
|
||||||
|
do
|
||||||
|
fission fn create --name $f --env nodejs --code $f.js
|
||||||
|
trap "fission fn delete --name $f" EXIT
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Waiting for router to catch up"
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo "Testing internal routes"
|
||||||
|
for f in $f1 $f2
|
||||||
|
do
|
||||||
|
response=$(curl http://$FISSION_ROUTER/fission-function/$f)
|
||||||
|
echo $response | grep $f
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "All done."
|
||||||
@@ -43,6 +43,8 @@ type (
|
|||||||
unversioned.TypeMeta `json:",inline"`
|
unversioned.TypeMeta `json:",inline"`
|
||||||
Metadata api.ObjectMeta `json:"metadata"`
|
Metadata api.ObjectMeta `json:"metadata"`
|
||||||
Spec fission.PackageSpec `json:"spec"`
|
Spec fission.PackageSpec `json:"spec"`
|
||||||
|
|
||||||
|
Status fission.PackageStatus `json:"status"`
|
||||||
}
|
}
|
||||||
PackageList struct {
|
PackageList struct {
|
||||||
unversioned.TypeMeta `json:",inline"`
|
unversioned.TypeMeta `json:",inline"`
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ limitations under the License.
|
|||||||
|
|
||||||
package fission
|
package fission
|
||||||
|
|
||||||
|
import "k8s.io/client-go/1.5/pkg/api"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
//
|
//
|
||||||
// Functions and packages
|
// Functions and packages
|
||||||
@@ -65,9 +67,10 @@ type (
|
|||||||
BuildStatus string
|
BuildStatus string
|
||||||
|
|
||||||
PackageSpec struct {
|
PackageSpec struct {
|
||||||
Environment EnvironmentReference `json:"environment"`
|
Environment EnvironmentReference `json:"environment"`
|
||||||
Source Archive `json:"source"`
|
Source Archive `json:"source"`
|
||||||
Deployment Archive `json:"deployment"`
|
Deployment Archive `json:"deployment"`
|
||||||
|
BuildCommand string `json:"buildcmd"`
|
||||||
// In the future, we can have a debug build here too
|
// In the future, we can have a debug build here too
|
||||||
}
|
}
|
||||||
PackageStatus struct {
|
PackageStatus struct {
|
||||||
@@ -162,8 +165,14 @@ type (
|
|||||||
// Optional, but strongly encouraged. Used to populate
|
// Optional, but strongly encouraged. Used to populate
|
||||||
// links from UI, CLI, etc.
|
// links from UI, CLI, etc.
|
||||||
DocumentationURL string `json:"documentationurl"`
|
DocumentationURL string `json:"documentationurl"`
|
||||||
|
|
||||||
|
// Optional
|
||||||
|
// Defaults to 'Single'
|
||||||
|
AllowedFunctionsPerContainer AllowedFunctionsPerContainer `json:"allowedFunctionsPerContainer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AllowedFunctionsPerContainer string
|
||||||
|
|
||||||
//
|
//
|
||||||
// Triggers
|
// Triggers
|
||||||
//
|
//
|
||||||
@@ -220,15 +229,18 @@ type (
|
|||||||
// env-specific. Optional.
|
// env-specific. Optional.
|
||||||
FilePath string `json:"filepath"`
|
FilePath string `json:"filepath"`
|
||||||
|
|
||||||
// Entrypoint has an environment-specific meaning;
|
// FunctionName has an environment-specific meaning;
|
||||||
// usually, it defines a function within a module
|
// usually, it defines a function within a module
|
||||||
// containing multiple functions. Optional; default is
|
// containing multiple functions. Optional; default is
|
||||||
// environment-specific.
|
// environment-specific.
|
||||||
EntryPoint string `json:"entrypoint"`
|
FunctionName string `json:"functionName"`
|
||||||
|
|
||||||
// URL to expose this function at. Optional; defaults
|
// URL to expose this function at. Optional; defaults
|
||||||
// to "/".
|
// to "/".
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
|
||||||
|
// Metatdata
|
||||||
|
FunctionMetadata *api.ObjectMeta
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -252,6 +264,11 @@ const (
|
|||||||
BuildStatusFailed = "failed"
|
BuildStatusFailed = "failed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AllowedFunctionsPerContainerSingle = "single"
|
||||||
|
AllowedFunctionsPerContainerInfinite = "infinite"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// FunctionReferenceFunctionName means that the function
|
// FunctionReferenceFunctionName means that the function
|
||||||
// reference is simply by function name.
|
// reference is simply by function name.
|
||||||
|
|||||||
Reference in New Issue
Block a user