Compare commits

...
62 Commits
Author SHA1 Message Date
Soam Vasani db372c11eb Version -> 0.4.1 2018-01-20 06:15:11 -08:00
Ta-Ching ChenandSoam Vasani 6a1da19e73 Fix python environment failed to launch due to port needs integer not string (#451) 2018-01-20 06:06:50 -08:00
Soam Vasani 816fd25a6c Version -> 0.4.1 2018-01-20 06:05:19 -08:00
prithvirameshandSoam Vasani c03bb01bca Fix fission function logs (#448)
Remove hard coded field indices in influx query, instead searching for them by name.
2018-01-19 17:37:12 -08:00
VishalandSoam Vasani bed189c715 Fscache support for multiple kubernetes objects (#435)
Modifies the fsCache to support a list of arbitrary kubernetes objects instead of just one pod.  This allows better support for the newdeploy backend.

Also removes the byKubeObject cache index; cleanup is changed to use the byFunction index, and byKubeObject is no longer needed.
2018-01-16 13:05:24 -08:00
Soam VasaniandGitHub 80a4bcbcff Integration test improvements (#447)
A few improvements to the integration test:

* Search for test files recursively in the test dir
* Output a test report at the end for a quick summary of what tests passed/failed/were skipped
* Add support skipping test files; skip the logging test since it's broken (#446 is tracking this)
* Switch to latest helm version
* Cleanup namespace
2018-01-15 16:08:38 -08:00
Graham RoundsandSoam Vasani f420383882 Use storageClassName in Helm Charts (#444) (#445) 2018-01-13 00:24:44 -08:00
Soam Vasani fac508c7e0 Demo script bugfix 2018-01-02 14:10:23 +05:30
Ta-Ching ChenandSoam Vasani 64a82747a9 Improve travi-ci test scripts (#434)
Make our travis-based integration test less flaky:

* Wait for tiller ready before installation

* Remove all existing old releases before installation
2018-01-01 11:34:11 +05:30
Ta-Ching ChenandSoam Vasani 5f9e54bbeb Fix glide failed to check out github.com/dsnet/compress & update gorilla pkg version (#429) 2017-12-14 05:23:49 +05:30
Valentin OuvrardandSoam Vasani 8d6b33258d Format fetcher and specialize URLs correctly in case of IPv6 (#408) 2017-12-11 01:26:13 -06:00
Adam BouhenguelandSoam Vasani be84a864fb Add support for Host matching in HTTP triggers (#425)
Include Host in httptrigger output table and fix duplicate error detection to consider Host as well.
2017-12-11 01:22:05 -06:00
Soam Vasani dff34b08e9 Update install link 2017-12-07 17:33:24 -06:00
Soam VasaniandGitHub 1e6b7a4fc8 Golang v2 environment -- runtime and builder (#427)
v2 environment for Go; includes runtime and builder.
2017-12-06 23:03:05 -06:00
Ta-Ching ChenandSoam Vasani eed3018458 [Issue 423] build logs not saved on build error (#426)
* Fix builder return empty buildlogs when encounters errors

* Append error logs to build logs

* Builder manager updates package with build logs plus error log

* Fix potential nil pointer bug

* Replace numeric status code with built-in const

* Remove no use parameter

* Fix go fmt
2017-12-06 22:20:41 -06:00
Karim BoumedhelandSoam Vasani fa810e6f80 Removed openshift specifics as they are no longer necessary (#424)
tested fission on openshift 3.7.0 and installed fine, without having to use openshift variables
those variables were used prior to switching to custom resource definitions, and as such are obsolete
2017-12-04 13:25:39 -08:00
Soam Vasani b1483e5e78 minor comment update in fetcher 2017-12-01 10:45:31 -08:00
Ta-Ching ChenandSoam Vasani 43fea01bd9 Overwrite request host with internal host to prevent request rejection (#419) 2017-11-30 23:58:14 -08:00
Ta-Ching ChenandSoam Vasani 49169e672d Fix pool manager crash problem if failed at http call (#418) 2017-11-30 13:40:17 -08:00
Ta-Ching ChenandSoam Vasani 140b132c8e Update nats dependencies (#411) 2017-11-28 16:12:31 -08:00
Ta-Ching ChenandSoam Vasani 36008f28d8 Add package command (#385)
Add package command support: This PR adds package command to CLI. package provides some useful subcommands to use such as packages CRUD and display package detail information. Also it is able to reuse existing package at function creation.

* Check function existence before creating package

* Check package existence

* Add support for downloading archive from given url

The functionality was supported before e238776bf7. Add this functionality back for more flexible usage.

* Add output flag to save archive content in specific file

* Add logs when package create/update

* Fix fnCreate requires environment argument when a pkg is specified

* Fix fnUpdate failed to update function pkg info when a package is specified

* Add package command test

* Fix wrong python test image in test script

* Remove package description fields

* Fix package command not update package but creating a new one

* Set package as pending status only when there is no deploy archive

* Rename function from fetchArchiveFromArbitraryURL to downloadToTempFile

* Use io.Copy to prevent loading all body into memory

* Revise some messages

* Allow user to update package build command

* Allow user to update package content when using function update

* Retrieve pkgName from function packageref if it’s not specified

* Fix function failed to update due to resource conflict

* Fix test case failure due to single quote

* kick ci

* Fix failed to update function packageRef

* kick ci

* kick ci
2017-11-25 06:54:43 -08:00
Soam Vasani 8fc1bf4bc1 script to update and copy hugo site 2017-11-23 09:55:16 -08:00
prithvirameshandSoam Vasani 2247d3118a fission function logs returns logs in correct order now (#405)
Fix a bug in `fission function logs` due to which logs with the same timestamp were printed in the wrong order.
2017-11-22 18:05:49 -08:00
VishalandSoam Vasani 04531850d5 Executor API panics if there is err in getting function from backends (#407) 2017-11-22 14:06:36 -08:00
VishalandSoam Vasani 13a58e715d Fetcher retry (#403)
Before this change, poolmgr tried to hit fetcher just once.  However if the pod has just started, fetcher may not be up yet, causing the initial request to fail with a connection refused error.  This change adds a similar retry loop that we currently use on the specialize endpoint of the runtime environment container.
2017-11-22 11:27:37 -08:00
Erwin van EykandSoam Vasani b2678783b6 fission/builder image, log collection improvement in builder (#397)
Create a container image with the buidler, so we can avoid copying the builder binary into the env container during the env container build. 

Gather both stdout and stderr of a build into the logs.
 

* Add Dockerfile for builder + update release scripts

* Improve logging of buildermgr and builder

* Add support for environment-scoped buildcmd

* Fix fork/exec wd when package is a file

* Update tests to also include builder image

* Add logging to builder's fork/exec
2017-11-20 23:58:33 -08:00
VishalandSoam Vasani da820186f0 Executor abstraction (#384)
This change adds a layer of abstraction over poolmgr. Poolmgr is now just one of the ways to turn a function into a service; other implementations will be added. The executor abstraction is a uniform API over all these implementations.

* Executor layer added on top of pool manager

* Removed the external server for executor

* Minor changes to keep existing semantics as much possible

* Separating the executor vs. poolmgr backend functionality and associated data members

* Executor logic separated from Poolmgr backend completely, placeholder for new backend

* Changed references to poolmgr in tests

* Moved poolmgr to it's package, as a side effect moved Cache to its's package (was causing cyclical dependency) and had to make some data structures exposed outside package

* Rebased from master and changed references to tpr -> crd

* Executor layer added on top of pool manager

* Executor logic separated from Poolmgr backend completely, placeholder for new backend

* Changed podName to a generic objectReference in fscache (#391)

Changed podName to a generic objectReference in function service cache implementation.

* Moved poolmgr to it's package, as a side effect moved Cache to its's package (was causing cyclical dependency) and had to make some data structures exposed outside package

* Rebased from master and changed references to tpr -> crd

* Merged from master with latest changes

* Removed stale executor service & deployment from previous merge

* Addressed review comments, still testing some areas
2017-11-20 20:51:14 -08:00
VishalandSoam Vasani 7bb397dfee Changed podName to a generic objectReference in fscache (#391)
Changed podName to a generic objectReference in function service cache implementation.
2017-11-15 13:57:19 -08:00
Soam Vasani 8a097abf9b Chart version update 2017-11-15 13:25:28 -08:00
Soam Vasani 6d0ebfd881 update version to 0.4.0 in docs 2017-11-15 13:18:50 -08:00
Soam Vasani 310183a944 update version to 0.4.0 2017-11-15 13:18:22 -08:00
Soam Vasani 8fc3479428 only set nodeports when servicetype == nodeport 2017-11-15 13:18:22 -08:00
Josh KellyandSoam Vasani b2883a30de Added AWS to install cloud setup (#392)
Add AWS instructions to setup commands, since AWS only provides service hostname, not IP.
2017-11-15 12:49:19 -08:00
prithvirameshandSoam Vasani 8b40ad0b33 Refactor logging to remove logger, use fluentd with kubernetes filter (#380)
Remove the `logger` container from the logging daemonset. 

Remove the outgoing call from the poolmgr to the logger.  Use Fluentd's Kubernetes filter to add function name and UID to influx metadata.  

This means fluentd now figures out when to start collecting function logs on its own, without being informed by poolmgr.  This is great for other execution strategies, and for autoscaling, where fission isn't in direct control of function pod creation.

Also adds an integration test to make sure logging keeps working.
2017-11-14 18:08:57 -08:00
svicenteruizandSoam Vasani 74e05ba3a1 created weather.js in node.js examples, modified README.md (#394) 2017-11-14 15:33:41 -08:00
Cody HillandSoam Vasani e77a3946d7 Added python example to demonstrate status codes. (#395) 2017-11-14 05:51:37 -08:00
Soam Vasani bcf04b1a6c Build both python 3.5 and 2.7 images from the same env 2017-11-09 14:01:02 -08:00
Soam Vasani d8844ab13c release script: use helm package to create charts 2017-11-09 13:38:01 -08:00
Soam Vasani 2e63787b96 rename readme to format markdown 2017-11-09 08:12:47 -08:00
Soam Vasani de19a42b8b multifile example 2017-11-09 08:11:02 -08:00
Ta-Ching ChenandSoam Vasani da07b35a96 Use common controller/store for httpTriggerSet and functionReferenceResolver (#390)
This fixes a bug where functionReferenceResolver returned out-of-date function metadata and caused the router to proxy requests to old function pods.

It also uses the go context package to shutdown the controller when the router is shutting down.
2017-11-09 07:07:14 -08:00
Ta-Ching ChenandSoam Vasani 9694ba4fd1 Delete failed helm releases to prevent test case failure (#393) 2017-11-09 06:04:06 -08:00
Soam Vasani 3644760f19 hugo config 2017-11-08 17:15:54 -08:00
Soam Vasani b89576ff7d chart version update 2017-11-08 15:51:23 -08:00
Soam Vasani d4b4385596 0.4.0rc version update 2017-11-08 12:45:09 -08:00
Soam Vasani b8eb27d276 Upgrade guide doc update 2017-11-07 15:45:39 -08:00
Ta-Ching ChenandSoam Vasani a63b8b372f Builder manager bugfixes (#367)
This contains a few different builder manager fixes:

* Update the zip file structure to avoid an extra subdirectory
* Annotate packages with what functions are using them
* Only trigger builds when there is no deployment archive
* Python environment loadpath bugfixes
* Other bugfixes
2017-11-06 23:01:46 -08:00
Ta-Ching ChenandSoam Vasani 380b7d1bcd Use k8s client store to sync functions and triggers for fast synchronization (#382) 2017-11-06 12:58:19 -08:00
Ta-Ching ChenandSoam Vasani 5f14b9b0ae Switch from ThirdPartyResources to CustomResourceDefinitions (#381)
Switch Fission's storage over to the new CustomResourceDefinitions, from the deprecated ThirdPartyResources. This allows us to be compatible with Kubernets 1.8 and onwards.

This also adds a CLI tool for dumping state from an old fission version and restoring state into new CRDs.

The storage service is unaffected by this change.
2017-11-04 14:55:16 -07:00
VishalandSoam Vasani 746c51901d Test functions 236 (#355)
A single CLI command to invoke a function, print results, and get logs if the function fails. Meant to be an easy way to do testing from the CLI.
2017-10-30 22:32:15 -07:00
Ta-Ching ChenandSoam Vasani 439e7d4535 Use Kubernetes informer and cache in router (#376)
Use Kubernetes client's informer and cache to watch functions and triggers in the router. This replaces the polling loop we were using so far.
2017-10-25 15:10:44 -07:00
prithvirameshandSoam Vasani 8abb0005f6 Compile instructions: changed pullPolicy to IfNotPresent (#378)
Containers will get stuck in ErrImagePull/ImagePullBackOff state otherwise
2017-10-16 13:39:46 -07:00
Soam Vasani c8f4647373 update compiling.md to use helm 2017-10-05 16:24:25 -07:00
rapitableandSoam Vasani 5c47073518 Make default node-env use alpine. List envs in documentation. (#354)
closes #319 

* Make default node-env use alpine, and support separate debian env. List envs in documentation.

* Copy ONBUILD base image commands into node Dockerfiles

* Copy more commands from onbuild image

* Tidy dockerfiles
2017-10-04 19:05:43 -07:00
Soam Vasani fd1461cc98 doc formatting fixes 2017-10-02 14:54:40 -07:00
Ta-Ching ChenandSoam Vasani a25c167d23 Update k8s client version to 4.0.0 (#351)
Move to client-go v4.0.0 from 1.5.
2017-09-29 07:37:36 -07:00
Soam Vasani e4d42797e6 set versions to 0.3.0 2017-09-28 23:44:53 -07:00
Soam VasaniandGitHub 6a394889f6 dotnet20 build fixes (#365)
Fix the dotnet20 build, use docker for builds, and re-enable dotnet20 in the release script.
2017-09-28 23:36:11 -07:00
Erwin van EykandSoam Vasani 59c18693fa Fix workflow apiserver proxy (#363) 2017-09-28 22:45:53 -07:00
Erwin van EykandSoam Vasani 0537c4b805 Added experimental deploy script (#364) 2017-09-28 22:19:55 -07:00
Soam VasaniandGitHub 6734bfbf7b Differentiate by environment in fscache eviction (#361) 2017-09-28 10:00:23 -07:00
Soam Vasani 557c2ee6fc Time out post-install hooks in 5 sec 2017-09-27 19:03:45 -07:00
159 changed files with 5178 additions and 3376 deletions
+7
View File
@@ -12,6 +12,13 @@ cache:
- $HOME/google-cloud-sdk/
- $HOME/k8scli
services:
- docker
before_install:
- sudo apt-get update
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
install:
- go get github.com/Masterminds/glide
- hack/travis-kube-setup.sh
+2 -5
View File
@@ -38,13 +38,10 @@ minikube and its built-in docker daemon:
$ docker build -t minikube/fission-bundle .
```
Next, install fission on your kubernetes cluster:
Next, install fission with this image on your kubernetes cluster using the helm chart:
```
# To install, update fission.yaml to point to the image you just made: "minikube/fission-bundle"
$ $EDITOR fission.yaml
$ kubectl create -f fission.yaml
$ kubectl create -f fission-nodeport.yaml
$ helm install --set "image=minikube/fission-bundle,pullPolicy=IfNotPresent,analytics=false" charts/fission-all
```
And if you're changing the CLI too, you can build it with:
+5 -5
View File
@@ -24,7 +24,7 @@ Language-neutral components:
Language-specific components:
* Environment container
* Environment container(s)
Controller
@@ -112,13 +112,13 @@ Environment Container
---------------------
Environment containers run user-defined functions. Environment
containers are language specific. They must contain an HTTP server
and a loader for functions.
containers are language specific. Each environment container must
contain an HTTP server and a loader for functions.
Poolmgr deploys the environment container into a pod with fetcher
(fetcher is a simple utility that can fetch an HTTP url to a file at a
configured location). This pod forms a "generic pod", because it can
be loaded with any function.
be loaded with any function in that language.
When poolmgr needs to create a service for a function, it calls
fetcher to fetch the function. Fetcher downloads the function into a
@@ -134,7 +134,7 @@ Following is a diagram describe how log service works:
![Logger Diagram](https://cloud.githubusercontent.com/assets/202578/23100399/b0e3ea00-f6ba-11e6-8f2f-6588cfef2e84.png)
1. Pool manager choose a pod from pool to execute user function
1. Pool manager chooses a pod from the pool to execute user function
2. Pool manager makes a HTTP POST to logger helper, once helper receives
the request it creates a symlink to container log for fluentd.
3. Fluentd reads log from symlink and pipes to influxdb
+1 -1
View File
@@ -10,7 +10,7 @@
## Fission API ([area-api](https://github.com/fission/fission/labels/area-api))
- TPR-based controller
- CRD-based controller
- API authentication
- Aggregated API server
+2 -1
View File
@@ -1,3 +1,4 @@
baseURL = "http://fission.io/docs/v0.2.1"
baseURL = "http://fission.io/docs/0.3.0"
languageCode = "en-us"
title = "Fission: Serverless Functions for Kubernetes"
theme = "docdock"
+3 -3
View File
@@ -1,6 +1,6 @@
## Fission Documentation
* [Installation guide](install)
[Installation guide](install)
[Upgrade guide](upgrade-from-v0.1)
* [Upgrade guide for v0.3 to v0.4](upgrade-from-v0.3)
+20 -22
View File
@@ -6,7 +6,7 @@ draft: false
Welcome! This guide will get you up and running with Fission on a
Kubernetes cluster.
### Cluster preliminaries
If you don't have a Kubernetes cluster, [here's a quick guide to set
@@ -48,18 +48,18 @@ First, you'll need the helm CLI:
On __OS X__:
```
$ curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-darwin-amd64.tar.gz
$ curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.7.0-darwin-amd64.tar.gz
$ tar xzf helm-v2.6.1-darwin-amd64.tar.gz
$ tar xzf helm-v2.7.0-darwin-amd64.tar.gz
$ mv darwin-amd64/helm /usr/local/bin
```
On __Linux__:
```
$ curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.6.1-linux-amd64.tar.gz
$ curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.7.0-linux-amd64.tar.gz
$ tar xzf helm-v2.6.1-linux-amd64.tar.gz
$ tar xzf helm-v2.7.0-linux-amd64.tar.gz
$ mv linux-amd64/helm /usr/local/bin
```
@@ -67,24 +67,15 @@ $ mv linux-amd64/helm /usr/local/bin
Next, install the Helm server on your Kubernetes cluster:
```
$ kubectl -n kube-system create sa tiller
$ kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller
$ helm init --service-account tiller
$ helm init
```
(The first two commands are there to make sure that helm is allowed to
install stuff on Kubernetes, in the common case that your cluster has
role-based access control.)
### Install Fission
#### 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.4.1/fission-all-0.4.1.tgz
```
The serviceType variable allows configuring the type of Kubernetes
@@ -94,7 +85,7 @@ want to expose anything outside the cluster.
#### 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.4.1/fission-all-0.4.1.tgz
```
#### Minimal version
@@ -104,7 +95,7 @@ the NATS message queue, influxDB for logs, etc. If you want a more
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.4.1/fission-core-0.4.1.tgz
```
### Install the Fission CLI
@@ -114,19 +105,19 @@ $ helm install --namespace fission https://github.com/fission/fission/releases/d
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.4.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
```
#### 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.4.1/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/v0.2.1/fission-cli-windows.exe)
this windows executable: [fission.exe](https://github.com/fission/fission/releases/download/0.4.1/fission-cli-windows.exe)
### Set environment vars
@@ -149,6 +140,13 @@ FISSION_URL and FISSION_ROUTER, respectively. Wait for services to
get IP addresses (check this with ```kubectl --namespace fission get
svc```). Then:
##### AWS
```
$ export FISSION_URL=http://$(kubectl --namespace fission get svc controller -o=jsonpath='{..hostname}')
$ export FISSION_ROUTER=$(kubectl --namespace fission get svc router -o=jsonpath='{..hostname}')
```
##### GCP
```
$ 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}')
@@ -159,7 +157,7 @@ svc```). Then:
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.4.1
$ curl -LO https://raw.githubusercontent.com/fission/fission/master/examples/nodejs/hello.js
@@ -0,0 +1,131 @@
---
title: "Upgrading from Fission v0.3 to v0.4.x"
date: 2017-11-04T03:38:29+08:00
draft: false
---
## Introduction
Kubernetes ThirdPartyResources ("TPR") are replaced by
CustomResourceDefinitions ("CRD"). TPRs have been deprecated and are
removed in Kubernetes 1.8.
Since Fission stores state in TPRs, we need to migrate this state from
TPRs to CRDs while upgrading.
Follow the instructions below if you're upgrading a Fission 0.2.1 or
0.3.0 cluster to 0.4. If you're using a pre-0.2 Fission cluster, use
the [upgrade guide from 0.1 to 0.2]() and then upgrade to 0.4.0.
## How to Upgrade
1. Get the 0.4.0 CLI
2. Get the Fission state from v0.3 install
3. Upgrade to Fission 0.4.0
4. Upgrade Kubernetes cluster version to 1.7.x or higher
5. Remove all TPR definition (for Kubernetes 1.7.x)
6. Restore Fission state into CRDs
### Get the new CLI
#### OS X
```
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.4.0/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
```
#### Linux
```
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.4.0/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/0.4.0/fission-cli-windows.exe)
### Get Fission state from v0.3 install
```
fission --server <your v0.3 server> tpr2crd dump --file state.json
```
You can skip the --server argument if you have the environment
variable `$FISSION_URL` set to point at a v0.3 Fission server.
This will create a JSON file with all your fission state in the
current directory.
### Upgrade to Fission 0.4.0
Upgrade fission with a command similar to this:
```
helm upgrade fission-all --namespace fission
```
### Upgrade Kubernetes cluster version
Since CustomResource is only supported on Kubernetes v1.7+ and higher, please make sure
that you upgrade to the right version that supports CustomResource.
### Remove all TPR definition (for Kubernetes 1.7.x)
** NOTICE **: This step will remove TPR definition from your kubernetes cluster. Please make sure that you dump all TPRs at the second step!
Though Kubernetes will migrate TPRs to CRDs automatically when TPR definition is deleted if the same name CRD exists. We still need to make sure that there is no resource gets lost during the migration. Also, since we changed the capitalization of some CRDs to CamelCase (e.g. Httptrigger -> HTTPTrigger), we need to recreate those resources by ourselves.
```
fission tpr2crd delete
```
### Restore your Fission state into Fission 0.4.0
```
fission tpr2crd restore --file state.json
```
This commands needs `$FISSION_URL` set to point to new fission installation.
It uses the file created in the first step. It doesn't modify state.json.
(Note that you can run this restore on any cluster; it doesn't have the be the same kubernetes
cluster as your old install.)
### Verify
Let's check the migration result, first run following command to check CRD established state.
```
kubectl get crd -o 'custom-columns=NAME:{.metadata.name},ESTABLISHED:{.status.conditions[?(@.type=="Established")].status}'
```
The output should be like this
```
NAME ESTABLISHED
environments.fission.io True
functions.fission.io True
httptriggers.fission.io True
kuberneteswatchtriggers.fission.io True
messagequeuetriggers.fission.io True
packages.fission.io True
timetriggers.fission.io True
```
And check that CRD resources you expect are there.
```
COMMAND:
fission [resource] list
RESOURCES:
environments
functions
httptriggers
kuberneteswatchtriggers
messagequeuetriggers
packages
timetriggers
```
+19 -3
View File
@@ -45,8 +45,24 @@ A _function_ is a piece of code that follows the fission function
interface.
An _environment_ contains the language- and runtime-specific parts of
running a function. Fission comes with NodeJS and Python
environments; you can also extend environments or create entirely new
running a function.
The following environments are currently available:
| Environment | Image |
| ------------------------------------ | ------------------------- |
| Binary (for executables or scripts) | `fission/binary-env` |
| Go | `fission/go-env` |
| .NET | `fission/dotnet-env` |
| .NET 2.0 | `fission/dotnet20-env` |
| NodeJS (Alpine) | `fission/node-env` |
| NodeJS (Debian) | `fission/node-env-debian` |
| Perl | `fission/perl-env` |
| PHP 7 | `fission/php-env` |
| Python 3 | `fission/python-env` |
| Ruby | `fission/ruby-env` |
You can also extend environments or create entirely new
ones if you want. (An environment is essentially just a container
with a webserver and dynamic loader.)
@@ -81,7 +97,7 @@ See the [examples](examples) directory for more.
Running Fission on your Cluster
===============================
See the [installation guide](http://fission.io/docs/v0.2.1/install/).
See the [installation guide](http://fission.io/docs/0.4.0/install/).
Compiling Fission
=================
+59 -19
View File
@@ -21,11 +21,13 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
@@ -68,7 +70,9 @@ func MakeBuilder(sharedVolumePath string) *Builder {
func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "", 405)
e := fmt.Sprintf("Method not allowed: %v", r.Method)
log.Println(e)
builder.reply(w, "", e, http.StatusMethodNotAllowed)
return
}
@@ -81,15 +85,17 @@ func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
// parse request
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading request body")
http.Error(w, err.Error(), 500)
e := errors.New(fmt.Sprintf("Error reading request body: %v", err))
log.Println(e.Error())
builder.reply(w, "", e.Error(), http.StatusInternalServerError)
return
}
var req PackageBuildRequest
err = json.Unmarshal(body, &req)
if err != nil {
log.Printf("Error parsing json body: %v", err)
http.Error(w, err.Error(), 400)
e := errors.New(fmt.Sprintf("Error parsing json body: %v", err))
log.Println(e.Error())
builder.reply(w, "", e.Error(), http.StatusBadRequest)
return
}
log.Printf("Builder received request: %v", req)
@@ -106,66 +112,100 @@ func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
buildLogs, err := builder.build(buildCmd, srcPkgPath, deployPkgPath)
if err != nil {
e := errors.New(fmt.Sprintf("Error building source package: %v", err))
http.Error(w, e.Error(), 500)
log.Println(e.Error())
// append error at the end of build logs
buildLogs += fmt.Sprintf("%v\n", e.Error())
builder.reply(w, deployPkgFilename, buildLogs, http.StatusInternalServerError)
return
}
builder.reply(w, deployPkgFilename, buildLogs, http.StatusOK)
}
func (builder *Builder) reply(w http.ResponseWriter, pkgFilename string, buildLogs string, statusCode int) {
resp := PackageBuildResponse{
ArtifactFilename: deployPkgFilename,
ArtifactFilename: pkgFilename,
BuildLogs: buildLogs,
}
rBody, err := json.Marshal(resp)
if err != nil {
e := errors.New(fmt.Sprintf("Error encoding response body: %v", err))
http.Error(w, e.Error(), 500)
return
rBody = []byte(fmt.Sprintf(`{"buildLogs": "%v"}`, e.Error()))
statusCode = http.StatusInternalServerError
}
w.Header().Add("Content-Type", "application/json")
// should write header before writing the body,
// or client will receive HTTP 200 regardless the real status code
w.WriteHeader(statusCode)
w.Write(rBody)
w.WriteHeader(http.StatusOK)
}
func (builder *Builder) build(command string, srcPkgPath string, deployPkgPath string) (string, error) {
cmd := exec.Command(command)
cmd.Dir = srcPkgPath
fi, err := os.Stat(srcPkgPath)
if err != nil {
return "", errors.New(fmt.Sprintf("could not find srcPkgPath: '%s'", srcPkgPath))
}
if fi.IsDir() {
cmd.Dir = srcPkgPath
} else {
cmd.Dir = path.Dir(srcPkgPath)
}
// set env variables for build command
cmd.Env = append(os.Environ(),
fmt.Sprintf("%v=%v", envSrcPkg, srcPkgPath),
fmt.Sprintf("%v=%v", envDeployPkg, deployPkgPath),
)
cmdReader, err := cmd.StdoutPipe()
stdout, err := cmd.StdoutPipe()
if err != nil {
return "", errors.New(fmt.Sprintf("Error creating stdout pipe for cmd: %v", err.Error()))
}
scanner := bufio.NewScanner(cmdReader)
stderr, err := cmd.StderrPipe()
if err != nil {
return "", errors.New(fmt.Sprintf("Error creating stderr pipe for cmd: %v", err.Error()))
}
var buildLogs string
fmt.Println("\n=== Build Logs ===")
// Init logs
fmt.Printf("command=%v\n", command)
fmt.Printf("env=%v\n", cmd.Env)
out := io.MultiReader(stdout, stderr)
scanner := bufio.NewScanner(out)
err = cmd.Start()
if err != nil {
return "", errors.New(fmt.Sprintf("Error starting cmd: %v", err.Error()))
}
var buildLogs string
fmt.Println("\n=== Build Logs ===")
// Runtime logs
for scanner.Scan() {
output := scanner.Text()
fmt.Println(output)
buildLogs += fmt.Sprintf("%v\n", output)
}
fmt.Println("==================\n")
if err := scanner.Err(); err != nil {
return "", errors.New(fmt.Sprintf("Error reading cmd output: %v", err.Error()))
scanErr := errors.New(fmt.Sprintf("Error reading cmd output: %v", err.Error()))
fmt.Println(scanErr)
return buildLogs, scanErr
}
err = cmd.Wait()
if err != nil {
return "", errors.New(fmt.Sprintf("Error waiting for cmd: %v", err.Error()))
cmdErr := errors.New(fmt.Sprintf("Error waiting for cmd '%v': %v", command, err.Error()))
fmt.Println(cmdErr)
return buildLogs, cmdErr
}
fmt.Println("==================\n")
return buildLogs, nil
}
+4 -5
View File
@@ -20,6 +20,7 @@ import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"strings"
@@ -50,20 +51,18 @@ func (c *Client) Build(req *builder.PackageBuildRequest) (*builder.PackageBuildR
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fission.MakeErrorFromHTTP(resp)
}
rBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("Error reading resp body: %v", err)
return nil, err
}
pkgBuildResp := builder.PackageBuildResponse{}
err = json.Unmarshal([]byte(rBody), &pkgBuildResp)
if err != nil {
log.Printf("Error parsing resp body: %v", err)
return nil, err
}
return &pkgBuildResp, nil
return &pkgBuildResp, fission.MakeErrorFromHTTP(resp)
}
+9
View File
@@ -0,0 +1,9 @@
FROM alpine:3.5
RUN apk update
# Install some utility libraries for builders extending image
RUN apk add coreutils binutils findutils grep
ADD builder /builder
EXPOSE 8001
+24 -17
View File
@@ -26,41 +26,39 @@ import (
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"k8s.io/client-go/1.5/kubernetes"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
type (
BuildRequest struct {
Package api.ObjectMeta `json:"package"`
Package metav1.ObjectMeta `json:"package"`
}
BuilderMgr struct {
fissionClient *tpr.FissionClient
kubernetesClient *kubernetes.Clientset
storageSvcUrl string
namespace string
fissionClient *crd.FissionClient
storageSvcUrl string
namespace string
}
)
func MakeBuilderMgr(fissionClient *tpr.FissionClient,
func MakeBuilderMgr(fissionClient *crd.FissionClient,
kubernetesClient *kubernetes.Clientset, storageSvcUrl string,
envBuilderNamespace string) *BuilderMgr {
envWatcher := makeEnvironmentWatcher(fissionClient, kubernetesClient, envBuilderNamespace)
go envWatcher.watchEnvironments()
pkgWatcher := makePackageWatcher(fissionClient, kubernetesClient, envBuilderNamespace, storageSvcUrl)
pkgWatcher := makePackageWatcher(fissionClient, envBuilderNamespace, storageSvcUrl)
go pkgWatcher.watchPackages()
return &BuilderMgr{
fissionClient: fissionClient,
kubernetesClient: kubernetesClient,
storageSvcUrl: storageSvcUrl,
namespace: envBuilderNamespace,
fissionClient: fissionClient,
storageSvcUrl: storageSvcUrl,
namespace: envBuilderNamespace,
}
}
@@ -76,14 +74,23 @@ func (builderMgr *BuilderMgr) build(w http.ResponseWriter, r *http.Request) {
buildReq := BuildRequest{}
err = json.Unmarshal([]byte(body), &buildReq)
if err != nil {
e := fmt.Sprintf("invalid request body: %v", err)
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)
pkg, err := builderMgr.fissionClient.
Packages(buildReq.Package.Namespace).
Get(buildReq.Package.Name)
if err != nil {
e := fmt.Sprintf("Error getting package CRD info: %v", err)
log.Println(e)
http.Error(w, e, 500)
return
}
buildLogs, err := buildPackage(builderMgr.fissionClient, builderMgr.namespace, builderMgr.storageSvcUrl, pkg)
if err != nil {
code, e := fission.GetHTTPError(err)
http.Error(w, e, code)
+2 -2
View File
@@ -19,12 +19,12 @@ package buildermgr
import (
"log"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
// Start the buildermgr service.
func Start(port int, storageSvcUrl string, envBuilderNamespace string) error {
fissionClient, kubernetesClient, err := tpr.MakeFissionClient()
fissionClient, kubernetesClient, _, err := crd.MakeFissionClient()
if err != nil {
log.Printf("Failed to get kubernetes client: %v", err)
return err
+52 -46
View File
@@ -19,18 +19,18 @@ package buildermgr
import (
"fmt"
"log"
"net/http"
"strings"
"k8s.io/client-go/1.5/kubernetes"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/dchest/uniuri"
"github.com/fission/fission"
"github.com/fission/fission/builder"
builderClient "github.com/fission/fission/builder/client"
"github.com/fission/fission/crd"
"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.
@@ -43,41 +43,39 @@ import (
// 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)
}
func buildPackage(fissionClient *crd.FissionClient, builderNamespace string,
storageSvcUrl string, pkg *crd.Package) (buildLogs string, err error) {
// 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)
return e, fission.MakeError(http.StatusBadRequest, 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)
newPkgRV, err := updatePackage(fissionClient, pkg, fission.BuildStatusRunning, "", nil)
// 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 with
// latest return from updatePackage.
pkg.Metadata.ResourceVersion = newPkgRV
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)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
env, err := fissionClient.Environments(api.NamespaceDefault).Get(pkg.Spec.Environment.Name)
env, err := fissionClient.Environments(metav1.NamespaceDefault).Get(pkg.Spec.Environment.Name)
if err != nil {
e := fmt.Sprintf("Error getting environment TPR info: %v", err)
e := fmt.Sprintf("Error getting environment CRD info: %v", err)
log.Println(e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
return e, fission.MakeError(500, e)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
svcName := fmt.Sprintf("%v-%v.%v", env.Metadata.Name, env.Metadata.ResourceVersion, builderNamespace)
@@ -97,12 +95,17 @@ func buildPackage(fissionClient *tpr.FissionClient, kubernetesClient *kubernetes
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)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
buildCmd := pkg.Spec.BuildCommand
if len(buildCmd) == 0 {
buildCmd = env.Spec.Builder.Command
}
pkgBuildReq := &builder.PackageBuildRequest{
SrcPkgFilename: srcPkgFilename,
BuildCommand: pkg.Spec.BuildCommand,
BuildCommand: buildCmd,
}
log.Printf("Start building with source package: %v", srcPkgFilename)
@@ -111,8 +114,13 @@ func buildPackage(fissionClient *tpr.FissionClient, kubernetesClient *kubernetes
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)
var buildLogs string
if buildResp != nil {
buildLogs = buildResp.BuildLogs
}
buildLogs += fmt.Sprintf("%v\n", e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, buildLogs, nil)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
log.Printf("Build succeed, source package: %v, deployment package: %v", srcPkgFilename, buildResp.ArtifactFilename)
@@ -128,28 +136,32 @@ func buildPackage(fissionClient *tpr.FissionClient, kubernetesClient *kubernetes
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)
buildResp.BuildLogs += fmt.Sprintf("%v\n", e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, buildResp.BuildLogs, nil)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
log.Printf("Start updating info of package: %v", pkg.Metadata.Name)
// update package status and also build logs
newPkgRV, err := updatePackage(fissionClient, pkg,
newPkgRV, err = updatePackage(fissionClient, pkg,
fission.BuildStatusSucceeded, buildResp.BuildLogs, uploadResp)
pkg.Metadata.ResourceVersion = newPkgRV
if err != nil {
e := fmt.Sprintf("Error creating deployment package TPR resource: %v", err)
e := fmt.Sprintf("Error creating deployment package CRD resource: %v", err)
log.Println(e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, e, nil)
return e, fission.MakeError(500, e)
buildResp.BuildLogs += fmt.Sprintf("%v\n", e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, buildResp.BuildLogs, nil)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
fnList, err := fissionClient.
Functions(api.NamespaceDefault).List(api.ListOptions{})
Functions(metav1.NamespaceDefault).List(metav1.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)
buildResp.BuildLogs += fmt.Sprintf("%v\n", e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, buildResp.BuildLogs, nil)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
// A package may be used by multiple functions. Update
@@ -159,13 +171,14 @@ func buildPackage(fissionClient *tpr.FissionClient, kubernetesClient *kubernetes
fn.Spec.Package.PackageRef.Namespace == pkg.Metadata.Namespace &&
fn.Spec.Package.PackageRef.ResourceVersion != pkg.Metadata.ResourceVersion {
fn.Spec.Package.PackageRef.ResourceVersion = newPkgRV
// update TPR
// update CRD
_, 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)
buildResp.BuildLogs += fmt.Sprintf("%v\n", e)
updatePackage(fissionClient, pkg, fission.BuildStatusFailed, buildResp.BuildLogs, nil)
return e, fission.MakeError(http.StatusInternalServerError, e)
}
}
}
@@ -175,17 +188,10 @@ func buildPackage(fissionClient *tpr.FissionClient, kubernetesClient *kubernetes
return buildResp.BuildLogs, nil
}
func updatePackage(fissionClient *tpr.FissionClient,
pkg *tpr.Package, status fission.BuildStatus, buildLogs string,
func updatePackage(fissionClient *crd.FissionClient,
pkg *crd.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,
@@ -200,7 +206,7 @@ func updatePackage(fissionClient *tpr.FissionClient,
}
// update package spec
pkg, err := fissionClient.Packages(api.NamespaceDefault).Update(pkg)
pkg, err := fissionClient.Packages(metav1.NamespaceDefault).Update(pkg)
if err != nil {
log.Printf("Error updating package: %v", err)
return "", err
+70 -60
View File
@@ -22,15 +22,15 @@ import (
"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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
apiv1 "k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
type requestType int
@@ -45,15 +45,15 @@ const (
type (
builderInfo struct {
envMetadata *api.ObjectMeta
envMetadata *metav1.ObjectMeta
deployment *v1beta1.Deployment
service *v1.Service
service *apiv1.Service
}
envwRequest struct {
requestType
env *tpr.Environment
envList []tpr.Environment
env *crd.Environment
envList []crd.Environment
respChan chan envwResponse
}
@@ -66,14 +66,14 @@ type (
cache map[string]*builderInfo
requestChan chan envwRequest
builderNamespace string
fissionClient *tpr.FissionClient
fissionClient *crd.FissionClient
kubernetesClient *kubernetes.Clientset
fetcherImage string
fetcherImagePullPolicy v1.PullPolicy
fetcherImagePullPolicy apiv1.PullPolicy
}
)
func makeEnvironmentWatcher(fissionClient *tpr.FissionClient,
func makeEnvironmentWatcher(fissionClient *crd.FissionClient,
kubernetesClient *kubernetes.Clientset, builderNamespace string) *environmentWatcher {
fetcherImage := os.Getenv("FETCHER_IMAGE")
@@ -86,14 +86,14 @@ func makeEnvironmentWatcher(fissionClient *tpr.FissionClient,
fetcherImagePullPolicy = "IfNotPresent"
}
var pullPolicy v1.PullPolicy
var pullPolicy apiv1.PullPolicy
switch fetcherImagePullPolicy {
case "Always":
pullPolicy = v1.PullAlways
pullPolicy = apiv1.PullAlways
case "Never":
pullPolicy = v1.PullNever
pullPolicy = apiv1.PullNever
default:
pullPolicy = v1.PullIfNotPresent
pullPolicy = apiv1.PullIfNotPresent
}
envWatcher := &environmentWatcher{
@@ -125,7 +125,7 @@ func (envw *environmentWatcher) getLabels(envName string, envResourceVersion str
func (envw *environmentWatcher) watchEnvironments() {
rv := ""
for {
wi, err := envw.fissionClient.Environments(api.NamespaceAll).Watch(api.ListOptions{
wi, err := envw.fissionClient.Environments(metav1.NamespaceAll).Watch(metav1.ListOptions{
ResourceVersion: rv,
})
if err != nil {
@@ -144,7 +144,7 @@ func (envw *environmentWatcher) watchEnvironments() {
time.Sleep(time.Second)
break
}
env := ev.Object.(*tpr.Environment)
env := ev.Object.(*crd.Environment)
rv = env.Metadata.ResourceVersion
envw.sync()
}
@@ -152,9 +152,9 @@ func (envw *environmentWatcher) watchEnvironments() {
}
func (envw *environmentWatcher) sync() {
envList, err := envw.fissionClient.Environments(api.NamespaceAll).List(api.ListOptions{})
envList, err := envw.fissionClient.Environments(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
log.Fatalf("Error syncing environment TPR resources: %v", err)
log.Fatalf("Error syncing environment CRD resources: %v", err)
}
// Create environment builders for all environments
@@ -191,7 +191,7 @@ func (envw *environmentWatcher) service() {
req.respChan <- envwResponse{builderInfo: builderInfo}
case CLEANUP_BUILDERS:
latestEnvList := make(map[string]*tpr.Environment)
latestEnvList := make(map[string]*crd.Environment)
for i := range req.envList {
env := req.envList[i]
key := envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion)
@@ -201,7 +201,7 @@ func (envw *environmentWatcher) service() {
// 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 &
// cache and CRD. We need to iterate over the services &
// deployments to remove both normal and orphan builders.
svcList, err := envw.getBuilderServiceList(nil)
@@ -241,7 +241,7 @@ func (envw *environmentWatcher) service() {
}
}
func (envw *environmentWatcher) getEnvBuilder(env *tpr.Environment) (*builderInfo, error) {
func (envw *environmentWatcher) getEnvBuilder(env *crd.Environment) (*builderInfo, error) {
respChan := make(chan envwResponse)
envw.requestChan <- envwRequest{
requestType: GET_BUILDER,
@@ -252,15 +252,15 @@ func (envw *environmentWatcher) getEnvBuilder(env *tpr.Environment) (*builderInf
return resp.builderInfo, resp.err
}
func (envw *environmentWatcher) cleanupEnvBuilders(envs []tpr.Environment) {
func (envw *environmentWatcher) cleanupEnvBuilders(envs []crd.Environment) {
envw.requestChan <- envwRequest{
requestType: CLEANUP_BUILDERS,
envList: envs,
}
}
func (envw *environmentWatcher) createBuilder(env *tpr.Environment) (*builderInfo, error) {
var svc *v1.Service
func (envw *environmentWatcher) createBuilder(env *crd.Environment) (*builderInfo, error) {
var svc *apiv1.Service
var deploy *v1beta1.Deployment
sel := envw.getLabels(env.Metadata.Name, env.Metadata.ResourceVersion)
@@ -269,22 +269,32 @@ func (envw *environmentWatcher) createBuilder(env *tpr.Environment) (*builderInf
if err != nil {
return nil, err
}
// there should be only one service in svcList
if len(svcList) == 0 {
svc, err = envw.createBuilderService(env)
if err != nil {
return nil, fmt.Errorf("Error creating builder service: %v", err)
}
} else if len(svcList) == 1 {
svc = &svcList[0]
} else {
return nil, fmt.Errorf("Found more than one builder service for environment %v", env.Metadata.Name)
}
deployList, err := envw.getBuilderDeploymentList(sel)
if err != nil {
return nil, err
}
// there should be only one deploy in deployList
if len(deployList) == 0 {
deploy, err = envw.createBuilderDeployment(env)
if err != nil {
return nil, fmt.Errorf("Error creating builder deployment: %v", err)
}
} else if len(deployList) == 1 {
deploy = &deployList[0]
} else {
return nil, fmt.Errorf("Found more than one builder deployment for environment %v", env.Metadata.Name)
}
return &builderInfo{
@@ -305,7 +315,7 @@ func (envw *environmentWatcher) deleteBuilderService(sel map[string]string) erro
// cascading deletion
// https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/
falseVal := false
delOpt := &api.DeleteOptions{
delOpt := &metav1.DeleteOptions{
OrphanDependents: &falseVal,
}
@@ -328,11 +338,11 @@ func (envw *environmentWatcher) deleteBuilderDeployment(sel map[string]string) e
log.Printf("Removing builder deployment: %v", deploy.ObjectMeta.Name)
falseVal := false
delOpt := &api.DeleteOptions{
delOpt := &metav1.DeleteOptions{
OrphanDependents: &falseVal,
}
err = envw.kubernetesClient.
err = envw.kubernetesClient.ExtensionsV1beta1().
Deployments(envw.builderNamespace).
Delete(deploy.ObjectMeta.Name, delOpt)
if err != nil {
@@ -342,10 +352,10 @@ func (envw *environmentWatcher) deleteBuilderDeployment(sel map[string]string) e
return nil
}
func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string) ([]v1.Service, error) {
func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string) ([]apiv1.Service, error) {
svcList, err := envw.kubernetesClient.Services(envw.builderNamespace).List(
api.ListOptions{
LabelSelector: labels.Set(sel).AsSelector(),
metav1.ListOptions{
LabelSelector: labels.Set(sel).AsSelector().String(),
})
if err != nil {
return nil, fmt.Errorf("Error getting builder service list: %v", err)
@@ -353,22 +363,22 @@ func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string) ([]
return svcList.Items, nil
}
func (envw *environmentWatcher) createBuilderService(env *tpr.Environment) (*v1.Service, error) {
func (envw *environmentWatcher) createBuilderService(env *crd.Environment) (*apiv1.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{
service := apiv1.Service{
ObjectMeta: metav1.ObjectMeta{
Namespace: envw.builderNamespace,
Name: name,
Labels: sel,
},
Spec: v1.ServiceSpec{
Spec: apiv1.ServiceSpec{
Selector: sel,
Type: v1.ServiceTypeClusterIP,
Ports: []v1.ServicePort{
Type: apiv1.ServiceTypeClusterIP,
Ports: []apiv1.ServicePort{
{
Name: "fetcher-port",
Protocol: v1.ProtocolTCP,
Protocol: apiv1.ProtocolTCP,
Port: 8000,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
@@ -377,7 +387,7 @@ func (envw *environmentWatcher) createBuilderService(env *tpr.Environment) (*v1.
},
{
Name: "builder-port",
Protocol: v1.ProtocolTCP,
Protocol: apiv1.ProtocolTCP,
Port: 8001,
TargetPort: intstr.IntOrString{
Type: intstr.Int,
@@ -396,9 +406,9 @@ func (envw *environmentWatcher) createBuilderService(env *tpr.Environment) (*v1.
}
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(),
deployList, err := envw.kubernetesClient.ExtensionsV1beta1().Deployments(envw.builderNamespace).List(
metav1.ListOptions{
LabelSelector: labels.Set(sel).AsSelector().String(),
})
if err != nil {
return nil, fmt.Errorf("Error getting builder deployment list: %v", err)
@@ -406,42 +416,42 @@ func (envw *environmentWatcher) getBuilderDeploymentList(sel map[string]string)
return deployList.Items, nil
}
func (envw *environmentWatcher) createBuilderDeployment(env *tpr.Environment) (*v1beta1.Deployment, error) {
func (envw *environmentWatcher) createBuilderDeployment(env *crd.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{
ObjectMeta: metav1.ObjectMeta{
Namespace: envw.builderNamespace,
Name: name,
Labels: sel,
},
Spec: v1beta1.DeploymentSpec{
Replicas: &replicas,
Selector: &v1beta1.LabelSelector{
Selector: &metav1.LabelSelector{
MatchLabels: sel,
},
Template: v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{
Template: apiv1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: sel,
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
Spec: apiv1.PodSpec{
Volumes: []apiv1.Volume{
{
Name: "package",
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
VolumeSource: apiv1.VolumeSource{
EmptyDir: &apiv1.EmptyDirVolumeSource{},
},
},
},
Containers: []v1.Container{
Containers: []apiv1.Container{
{
Name: "builder",
Image: env.Spec.Builder.Image,
ImagePullPolicy: v1.PullAlways,
ImagePullPolicy: apiv1.PullAlways,
TerminationMessagePath: "/dev/termination-log",
VolumeMounts: []v1.VolumeMount{
VolumeMounts: []apiv1.VolumeMount{
{
Name: "package",
MountPath: sharedMountPath,
@@ -454,7 +464,7 @@ func (envw *environmentWatcher) createBuilderDeployment(env *tpr.Environment) (*
Image: envw.fetcherImage,
ImagePullPolicy: envw.fetcherImagePullPolicy,
TerminationMessagePath: "/dev/termination-log",
VolumeMounts: []v1.VolumeMount{
VolumeMounts: []apiv1.VolumeMount{
{
Name: "package",
MountPath: sharedMountPath,
@@ -469,7 +479,7 @@ func (envw *environmentWatcher) createBuilderDeployment(env *tpr.Environment) (*
},
}
log.Printf("Creating builder deployment: %v", envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion))
_, err := envw.kubernetesClient.Deployments(envw.builderNamespace).Create(deployment)
_, err := envw.kubernetesClient.ExtensionsV1beta1().Deployments(envw.builderNamespace).Create(deployment)
if err != nil {
return nil, err
}
+13 -20
View File
@@ -20,53 +20,46 @@ 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"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
type (
packageWatcher struct {
fissionClient *tpr.FissionClient
kubernetesClient *kubernetes.Clientset
fissionClient *crd.FissionClient
builderNamespace string
storageSvcUrl string
}
)
func makePackageWatcher(fissionClient *tpr.FissionClient,
kubernetesClient *kubernetes.Clientset, builderNamespace string, storageSvcUrl string) *packageWatcher {
func makePackageWatcher(fissionClient *crd.FissionClient,
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)
func (pkgw *packageWatcher) build(pkg *crd.Package) {
_, err := buildPackage(pkgw.fissionClient, pkgw.builderNamespace, pkgw.storageSvcUrl, pkg)
if err != nil {
log.Printf("Error building package %v: %v", buildReq.Package.Name, err)
log.Printf("Error building package %v: %v", pkg.Metadata.Name, err)
}
}
func (pkgw *packageWatcher) watchPackages() {
rv := ""
for {
wi, err := pkgw.fissionClient.Packages(api.NamespaceDefault).Watch(api.ListOptions{
wi, err := pkgw.fissionClient.Packages(metav1.NamespaceDefault).Watch(metav1.ListOptions{
ResourceVersion: rv,
})
if err != nil {
log.Fatalf("Error watching package TPR resources: %v", err)
log.Fatalf("Error watching package CRD resources: %v", err)
}
for {
@@ -79,12 +72,12 @@ func (pkgw *packageWatcher) watchPackages() {
time.Sleep(time.Second)
break
}
pkg := ev.Object.(*tpr.Package)
pkg := ev.Object.(*crd.Package)
rv = pkg.Metadata.ResourceVersion
// only do build for packages in pending state
if pkg.Status.BuildStatus == fission.BuildStatusPending {
go pkgw.build(pkg.Metadata)
go pkgw.build(pkg)
}
}
}
+1 -2
View File
@@ -5,7 +5,7 @@
## Prerequisites
- Kubernetes 1.6+ with Beta APIs enabled
- Kubernetes 1.8 or later
## Helm charts
@@ -48,7 +48,6 @@ The following table lists the configurable parameters of the Fission chart and t
| `routerPort` | Fission Router Service Port | `31314` |
| `functionNamespace` | Namespace for Fission functions | `fission-function` |
| `builderNamespace` | Namespace for Fission environment builders | `fission-builder` |
| `openshift` | RBAC for openshift | `false` |
* Extra configuration for `fission-all`
+2 -2
View File
@@ -1,6 +1,6 @@
apiVersion: v1
name: fission-all
version: 0.3.0-rc
version: 0.4.1
description: Fission is a fast serverless framework for Kubernetes.
keywords:
- fission
@@ -12,4 +12,4 @@ maintainers:
- name: Ta Ching Chen
email: contact@tachingchen.com
engine: gotpl
appVersion: 0.3.0-rc
appVersion: 0.4.1
+3 -3
View File
@@ -1,13 +1,13 @@
1. Install the client CLI.
Mac:
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0-rc/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.4.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
Linux:
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0-rc/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.4.1/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: https://github.com/fission/fission/releases/download/0.3.0-rc/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.4.1/fission-cli-windows.exe
2. Set the FISSION_URL and FISSION_ROUTER environment variables.
+16 -110
View File
@@ -1,77 +1,3 @@
{{ if .Values.openshift }}
# For openshift
---
apiVersion: v1
kind: ProjectRequest
metadata:
name: fission
labels:
name: fission
---
apiVersion: v1
kind: ProjectRequest
metadata:
name: {{ .Values.functionNamespace }}
labels:
name: fission-function
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fission-admin
namespace: {{ .Release.Namespace }}
---
apiVersion: v1
kind: ClusterRole
metadata:
name: fission:fission-admin
rules:
- apiGroups:
- extensions
attributeRestrictions: null
resources:
- deployments
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- ""
attributeRestrictions: null
resources:
- pods
verbs:
- get
- list
- update
---
apiVersion: v1
groupNames: null
kind: RoleBinding
metadata:
name: fission:fission-admin
namespace: {{ .Values.functionNamespace }}
roleRef:
name: fission:fission-admin
subjects:
- kind: ServiceAccount
name: fission-admin
namespace: {{ .Release.Namespace }}
userNames:
- system:serviceaccount:fission:fission-admin
{{ else }}
# For all environments except openshift
---
apiVersion: v1
kind: Namespace
@@ -131,7 +57,7 @@ roleRef:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: fission-tpr
name: fission-crd
subjects:
- kind: ServiceAccount
name: fission-svc
@@ -152,7 +78,7 @@ metadata:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: fission-fetcher-tpr
name: fission-fetcher-crd
subjects:
- kind: ServiceAccount
name: fission-fetcher
@@ -173,7 +99,7 @@ metadata:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: fission-builder-tpr
name: fission-builder-crd
subjects:
- kind: ServiceAccount
name: fission-builder
@@ -183,8 +109,6 @@ roleRef:
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
{{ end }}
---
apiVersion: extensions/v1beta1
kind: Deployment
@@ -226,16 +150,16 @@ spec:
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: {{ .Values.pullPolicy }}
command: ["/fission-bundle"]
args: ["--routerPort", "8888", "--poolmgrUrl", "http://poolmgr.{{ .Release.Namespace }}"]
args: ["--routerPort", "8888", "--executorUrl", "http://executor.{{ .Release.Namespace }}"]
serviceAccount: fission-svc
---
apiVersion: v1
kind: Service
metadata:
name: poolmgr
name: executor
labels:
svc: poolmgr
svc: executor
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: ClusterIP
@@ -243,13 +167,13 @@ spec:
- port: 80
targetPort: 8888
selector:
svc: poolmgr
svc: executor
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: poolmgr
name: executor
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
@@ -257,14 +181,14 @@ spec:
template:
metadata:
labels:
svc: poolmgr
svc: executor
spec:
containers:
- name: poolmgr
- name: executor
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: {{ .Values.pullPolicy }}
command: ["/fission-bundle"]
args: ["--poolmgrPort", "8888", "--namespace", "{{ .Values.functionNamespace }}", "--fission-namespace", "{{ .Release.Namespace }}"]
args: ["--executorPort", "8888", "--namespace", "{{ .Values.functionNamespace }}", "--fission-namespace", "{{ .Release.Namespace }}"]
env:
- name: FETCHER_IMAGE
value: "{{ .Values.fetcherImage }}:{{ .Values.fetcherImageTag }}"
@@ -273,7 +197,6 @@ spec:
- name: RUNTIME_IMAGE_PULL_POLICY
value: "{{ .Values.pullPolicy }}"
serviceAccount: fission-svc
---
apiVersion: v1
kind: Service
@@ -348,7 +271,7 @@ metadata:
svc: influxdb
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: ClusterIP
type: ClusterIP
ports:
- port: 8086
targetPort: 8086
@@ -400,25 +323,6 @@ spec:
svc: logger
spec:
containers:
- name: logger
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: {{ .Values.pullPolicy }}
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: {{ .Values.logger.fluentdImage }}
imagePullPolicy: {{ .Values.pullPolicy }}
@@ -439,9 +343,11 @@ spec:
secretKeyRef:
name: influxdb
key: password
- name: FLUENTD_PATH
value: /var/log/containers/*{{.Values.functionNamespace}}*.log
volumeMounts:
- name: container-log
mountPath: /var/log/containers
mountPath: /var/log/
readOnly: true
- name: docker-log
mountPath: /var/lib/docker/containers
@@ -453,7 +359,7 @@ spec:
volumes:
- name: container-log
hostPath:
path: /var/log/containers
path: /var/log/
- name: docker-log
hostPath:
path: /var/lib/docker/containers
@@ -26,5 +26,5 @@ spec:
containers:
- name: post-install-job
image: "fission/alpinecurl"
command: ["sh", "-c", "/usr/bin/curl -H \"Content-Type: application/json\" -X POST -d '{\"type\": \"helm-post-install\", \"chartName\": \"{{ .Chart.Name }}\", \"chartName\": \"{{ .Chart.Version }}\"}' https://g.fission.sh/analytics || true"]
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 }}
+7 -7
View File
@@ -7,17 +7,17 @@ metadata:
app: fission-storage
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
annotations:
{{- if .Values.persistence.storageClass }}
volume.beta.kubernetes.io/storage-class: {{ .Values.persistence.storageClass | quote }}
{{- else }}
volume.alpha.kubernetes.io/storage-class: default
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.persistence.storageClass | quote }}
{{- end }}
{{- end }}
{{- end }}
+6
View File
@@ -10,7 +10,9 @@ spec:
ports:
- port: 80
targetPort: 8888
{{ if eq .Values.serviceType "NodePort" }}
nodePort: {{ .Values.routerPort }}
{{ end }}
selector:
svc: router
@@ -27,7 +29,9 @@ spec:
ports:
- port: 80
targetPort: 8888
{{ if eq .Values.serviceType "NodePort" }}
nodePort: {{ .Values.controllerPort }}
{{ end }}
selector:
svc: controller
@@ -44,7 +48,9 @@ spec:
ports:
- port: 4222
targetPort: 4222
{{ if eq .Values.serviceType "NodePort" }}
nodePort: {{ .Values.natsStreamingPort }}
{{ end }}
selector:
svc: nats-streaming
+10 -10
View File
@@ -1,6 +1,6 @@
#
# Fission chart configuration
#
#
## Kubernetes configuration
## For minikube, set this to NodePort, elsewhere use LoadBalancer.
@@ -13,13 +13,13 @@ image: fission/fission-bundle
pullPolicy: IfNotPresent
## Fission image version
imageTag: 0.3.0-rc
imageTag: 0.4.1
## Fission fetcher repository
fetcherImage: fission/fetcher
## Fission fetcher image version
fetcherImageTag: 0.3.0-rc
fetcherImageTag: 0.4.1
## Port at which Fission controller service should be exposed
controllerPort: 31313
@@ -38,9 +38,6 @@ functionNamespace: fission-function
## the release namespace)
builderNamespace: fission-builder
## Set up openshift RBAC rule
openshift: false
## Logger config
logger:
influxdbAdmin: "admin"
@@ -51,15 +48,18 @@ logger:
nats:
authToken: "defaultFissionAuthToken"
clusterID: "fissionMQTrigger"
## Persist data to a persistent volume.
persistence:
enabled: true
## If defined, volume.beta.kubernetes.io/storage-class: <storageClass>
## Default: volume.alpha.kubernetes.io/storage-class: default
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass:
# storageClass: "-"
accessMode: ReadWriteOnce
size: 8Gi
+2 -2
View File
@@ -1,6 +1,6 @@
apiVersion: v1
name: fission-core
version: 0.3.0-rc
version: 0.4.1
description: Fission is a fast serverless framework for Kubernetes.
keywords:
- fission
@@ -12,4 +12,4 @@ maintainers:
- name: Ta Ching Chen
email: contact@tachingchen.com
engine: gotpl
appVersion: 0.3.0-rc
appVersion: 0.4.1
+3 -3
View File
@@ -1,13 +1,13 @@
1. Install the client CLI.
Mac:
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0-rc/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.4.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
Linux:
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.3.0-rc/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.4.1/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: https://github.com/fission/fission/releases/download/0.3.0-rc/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.4.1/fission-cli-windows.exe
2. Set the FISSION_URL and FISSION_ROUTER environment variables.
+11 -87
View File
@@ -1,77 +1,3 @@
{{ if .Values.openshift }}
# For openshift
---
apiVersion: v1
kind: ProjectRequest
metadata:
name: fission
labels:
name: fission
---
apiVersion: v1
kind: ProjectRequest
metadata:
name: {{ .Values.functionNamespace }}
labels:
name: fission-function
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fission-admin
namespace: {{ .Release.Namespace }}
---
apiVersion: v1
kind: ClusterRole
metadata:
name: fission:fission-admin
rules:
- apiGroups:
- extensions
attributeRestrictions: null
resources:
- deployments
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- ""
attributeRestrictions: null
resources:
- pods
verbs:
- get
- list
- update
---
apiVersion: v1
groupNames: null
kind: RoleBinding
metadata:
name: fission:fission-admin
namespace: {{ .Values.functionNamespace }}
roleRef:
name: fission:fission-admin
subjects:
- kind: ServiceAccount
name: fission-admin
namespace: {{ .Release.Namespace }}
userNames:
- system:serviceaccount:fission:fission-admin
{{ else }}
# For all environments except openshift
---
apiVersion: v1
kind: Namespace
@@ -131,7 +57,7 @@ roleRef:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: fission-tpr
name: fission-crd
subjects:
- kind: ServiceAccount
name: fission-svc
@@ -152,7 +78,7 @@ metadata:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: fission-fetcher-tpr
name: fission-fetcher-crd
subjects:
- kind: ServiceAccount
name: fission-fetcher
@@ -173,7 +99,7 @@ metadata:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: fission-builder-tpr
name: fission-builder-crd
subjects:
- kind: ServiceAccount
name: fission-builder
@@ -183,8 +109,6 @@ roleRef:
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
{{ end }}
---
apiVersion: extensions/v1beta1
kind: Deployment
@@ -226,16 +150,16 @@ spec:
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: {{ .Values.pullPolicy }}
command: ["/fission-bundle"]
args: ["--routerPort", "8888", "--poolmgrUrl", "http://poolmgr.{{ .Release.Namespace }}"]
args: ["--routerPort", "8888", "--executorUrl", "http://executor.{{ .Release.Namespace }}"]
serviceAccount: fission-svc
---
apiVersion: v1
kind: Service
metadata:
name: poolmgr
name: executor
labels:
svc: poolmgr
svc: executor
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: ClusterIP
@@ -243,13 +167,13 @@ spec:
- port: 80
targetPort: 8888
selector:
svc: poolmgr
svc: executor
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: poolmgr
name: executor
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
@@ -257,14 +181,14 @@ spec:
template:
metadata:
labels:
svc: poolmgr
svc: executor
spec:
containers:
- name: poolmgr
- name: executor
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
imagePullPolicy: {{ .Values.pullPolicy }}
command: ["/fission-bundle"]
args: ["--poolmgrPort", "8888", "--namespace", "{{ .Values.functionNamespace }}", "--fission-namespace", "{{ .Release.Namespace }}"]
args: ["--executorPort", "8888", "--namespace", "{{ .Values.functionNamespace }}", "--fission-namespace", "{{ .Release.Namespace }}"]
env:
- name: FETCHER_IMAGE
value: "{{ .Values.fetcherImage }}:{{ .Values.fetcherImageTag }}"
@@ -26,5 +26,5 @@ spec:
containers:
- name: post-install-job
image: "fission/alpinecurl"
command: ["sh", "-c", "/usr/bin/curl -H \"Content-Type: application/json\" -X POST -d '{\"type\": \"helm-post-install\", \"chartName\": \"{{ .Chart.Name }}\", \"chartName\": \"{{ .Chart.Version }}\"}' https://g.fission.sh/analytics || true"]
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 }}
+7 -7
View File
@@ -7,17 +7,17 @@ metadata:
app: fission-storage
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
annotations:
{{- if .Values.persistence.storageClass }}
volume.beta.kubernetes.io/storage-class: {{ .Values.persistence.storageClass | quote }}
{{- else }}
volume.alpha.kubernetes.io/storage-class: default
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.persistence.storageClass | quote }}
{{- end }}
{{- end }}
{{- end }}
+4
View File
@@ -10,7 +10,9 @@ spec:
ports:
- port: 80
targetPort: 8888
{{ if eq .Values.serviceType "NodePort" }}
nodePort: {{ .Values.routerPort }}
{{ end }}
selector:
svc: router
@@ -27,7 +29,9 @@ spec:
ports:
- port: 80
targetPort: 8888
{{ if eq .Values.serviceType "NodePort" }}
nodePort: {{ .Values.controllerPort }}
{{ end }}
selector:
svc: controller
+9 -9
View File
@@ -1,6 +1,6 @@
#
# Fission chart configuration
#
#
## Kubernetes configuration
## For minikube, set this to NodePort, elsewhere use LoadBalancer.
@@ -10,7 +10,7 @@ serviceType: LoadBalancer
image: fission/fission-bundle
## Fission image version
imageTag: 0.3.0-rc
imageTag: 0.4.1
## Image pull policy
pullPolicy: IfNotPresent
@@ -19,7 +19,7 @@ pullPolicy: IfNotPresent
fetcherImage: fission/fetcher
## Fission fetcher image version
fetcherImageTag: 0.3.0-rc
fetcherImageTag: 0.4.1
## Port at which Fission controller service should be exposed
controllerPort: 31313
@@ -35,16 +35,16 @@ functionNamespace: fission-function
## the release namespace)
builderNamespace: fission-builder
## Set up openshift RBAC rule
openshift: false
## Persist data to a persistent volume.
persistence:
enabled: true
## If defined, volume.beta.kubernetes.io/storage-class: <storageClass>
## Default: volume.alpha.kubernetes.io/storage-class: default
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass:
# storageClass: "-"
accessMode: ReadWriteOnce
size: 8Gi
+12 -8
View File
@@ -26,16 +26,18 @@ import (
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
kerrors "k8s.io/client-go/1.5/pkg/api/errors"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/kubernetes"
"github.com/fission/fission"
"github.com/fission/fission/crd"
"github.com/fission/fission/fission/logdb"
"github.com/fission/fission/tpr"
)
type (
API struct {
fissionClient *tpr.FissionClient
fissionClient *crd.FissionClient
kubernetesClient *kubernetes.Clientset
storageServiceUrl string
builderManagerUrl string
workflowApiUrl string
@@ -49,7 +51,7 @@ type (
)
func MakeAPI() (*API, error) {
api, err := makeTPRBackedAPI()
api, err := makeCRDBackedAPI()
u := os.Getenv("STORAGE_SERVICE_URL")
if len(u) > 0 {
@@ -69,7 +71,7 @@ func MakeAPI() (*API, error) {
if len(u) > 0 {
api.workflowApiUrl = strings.TrimSuffix(wfEnv, "/")
} else {
api.workflowApiUrl = "http://workflow-apiserver"
api.workflowApiUrl = "http://workflows-apiserver"
}
return api, err
@@ -118,7 +120,7 @@ func (api *API) getLogDBConfig(dbType string) logDBConfig {
func (api *API) HomeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
fmt.Fprintf(w, "{\"message\": \"Fission API\", \"version\": \"0.3.0-rc\"}\n")
fmt.Fprintf(w, "{\"message\": \"Fission API\", \"version\": \"0.4.1\"}\n")
}
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
@@ -174,11 +176,13 @@ func (api *API) Serve(port int) {
r.HandleFunc("/v2/triggers/messagequeue/{mqTrigger}", api.MessageQueueTriggerApiUpdate).Methods("PUT")
r.HandleFunc("/v2/triggers/messagequeue/{mqTrigger}", api.MessageQueueTriggerApiDelete).Methods("DELETE")
r.HandleFunc("/v2/deleteTpr", api.Tpr2crdApi).Methods("DELETE")
r.HandleFunc("/proxy/{dbType}", api.FunctionLogsApiPost).Methods("POST")
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/workflow", api.WorkflowApiProxy)
r.HandleFunc("/proxy/logs/{function}", api.FunctionPodLogs).Methods("POST")
r.HandleFunc("/proxy/workflows-apiserver/{path:.*}", api.WorkflowApiserverProxy)
address := fmt.Sprintf(":%v", port)
+50 -45
View File
@@ -18,6 +18,7 @@ package controller
import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
@@ -25,11 +26,11 @@ import (
"testing"
"time"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/controller/client"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
var g struct {
@@ -72,13 +73,10 @@ func assertCronSpecFails(err error) {
}
func TestFunctionApi(t *testing.T) {
name1 := "foo"
name2 := "bar"
testFunc := &tpr.Function{
Metadata: api.ObjectMeta{
Name: name1,
Namespace: api.NamespaceDefault,
testFunc := &crd.Function{
Metadata: metav1.ObjectMeta{
Name: "foo",
Namespace: metav1.NamespaceDefault,
},
Spec: fission.FunctionSpec{
Environment: fission.EnvironmentReference{
@@ -89,30 +87,36 @@ func TestFunctionApi(t *testing.T) {
},
},
}
_, err := g.client.FunctionGet(&api.ObjectMeta{
_, err := g.client.FunctionGet(&metav1.ObjectMeta{
Name: testFunc.Metadata.Name,
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
})
assertNotFoundFailure(err, "function")
_, err = g.client.FunctionCreate(testFunc)
m, err := g.client.FunctionCreate(testFunc)
panicIf(err)
defer func() {
err := g.client.FunctionDelete(m)
panicIf(err)
}()
_, err = g.client.FunctionCreate(testFunc)
assertNameReuseFailure(err, "function")
testFunc.Metadata.ResourceVersion = m.ResourceVersion
testFunc.Spec.Package.FunctionName = "yyy"
_, err = g.client.FunctionUpdate(testFunc)
panicIf(err)
testFunc.Metadata.Name = name2
_, err = g.client.FunctionCreate(testFunc)
testFunc.Metadata.ResourceVersion = ""
testFunc.Metadata.Name = "bar"
m2, err := g.client.FunctionCreate(testFunc)
panicIf(err)
defer g.client.FunctionDelete(m2)
funcs, err := g.client.FunctionList()
panicIf(err)
assert(len(funcs) == 2,
"created two functions, but didn't find them")
assert(len(funcs) == 2, fmt.Sprintf("created two functions, but found %v", len(funcs)))
funcs_url := g.client.Url + "/v2/functions"
resp, err := http.Get(funcs_url)
@@ -127,18 +131,13 @@ func TestFunctionApi(t *testing.T) {
}
}
assert(found, "incorrect response content type")
err = g.client.FunctionDelete(&api.ObjectMeta{Name: name1, Namespace: api.NamespaceDefault})
panicIf(err)
err = g.client.FunctionDelete(&api.ObjectMeta{Name: name2, Namespace: api.NamespaceDefault})
panicIf(err)
}
func TestHTTPTriggerApi(t *testing.T) {
testTrigger := &tpr.Httptrigger{
Metadata: api.ObjectMeta{
testTrigger := &crd.HTTPTrigger{
Metadata: metav1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
},
Spec: fission.HTTPTriggerSpec{
RelativeURL: "/hello",
@@ -148,9 +147,9 @@ func TestHTTPTriggerApi(t *testing.T) {
},
},
}
_, err := g.client.HTTPTriggerGet(&api.ObjectMeta{
_, err := g.client.HTTPTriggerGet(&metav1.ObjectMeta{
Name: testTrigger.Metadata.Name,
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
})
assertNotFoundFailure(err, "httptrigger")
@@ -165,10 +164,12 @@ func TestHTTPTriggerApi(t *testing.T) {
panicIf(err)
assert(testTrigger.Spec == tr.Spec, "trigger should match after reading")
testTrigger.Metadata.ResourceVersion = m.ResourceVersion
testTrigger.Spec.RelativeURL = "/hi"
_, err = g.client.HTTPTriggerUpdate(testTrigger)
panicIf(err)
testTrigger.Metadata.ResourceVersion = ""
testTrigger.Metadata.Name = "yyy"
_, err = g.client.HTTPTriggerCreate(testTrigger)
assert(err != nil, "duplicate trigger should not be allowed")
@@ -180,14 +181,14 @@ func TestHTTPTriggerApi(t *testing.T) {
ts, err := g.client.HTTPTriggerList()
panicIf(err)
assert(len(ts) == 2, "created two triggers, but didn't find them")
assert(len(ts) == 2, fmt.Sprintf("created two triggers, but found %v", len(ts)))
}
func TestEnvironmentApi(t *testing.T) {
testEnv := &tpr.Environment{
Metadata: api.ObjectMeta{
testEnv := &crd.Environment{
Metadata: metav1.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
},
Spec: fission.EnvironmentSpec{
Runtime: fission.Runtime{
@@ -195,9 +196,9 @@ func TestEnvironmentApi(t *testing.T) {
},
},
}
_, err := g.client.EnvironmentGet(&api.ObjectMeta{
_, err := g.client.EnvironmentGet(&metav1.ObjectMeta{
Name: testEnv.Metadata.Name,
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
})
assertNotFoundFailure(err, "environment")
@@ -212,10 +213,12 @@ func TestEnvironmentApi(t *testing.T) {
panicIf(err)
assert(testEnv.Spec == e.Spec, "env should match after reading")
testEnv.Metadata.ResourceVersion = m.ResourceVersion
testEnv.Spec.Runtime.Image = "another-img"
_, err = g.client.EnvironmentUpdate(testEnv)
panicIf(err)
testEnv.Metadata.ResourceVersion = ""
testEnv.Metadata.Name = "bar"
m2, err := g.client.EnvironmentCreate(testEnv)
panicIf(err)
@@ -223,14 +226,14 @@ func TestEnvironmentApi(t *testing.T) {
ts, err := g.client.EnvironmentList()
panicIf(err)
assert(len(ts) == 2, "created two envs, but didn't find them")
assert(len(ts) == 2, fmt.Sprintf("created two envs, but found %v", len(ts)))
}
func TestWatchApi(t *testing.T) {
testWatch := &tpr.Kuberneteswatchtrigger{
Metadata: api.ObjectMeta{
testWatch := &crd.KubernetesWatchTrigger{
Metadata: metav1.ObjectMeta{
Name: "xxx",
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
},
Spec: fission.KubernetesWatchTriggerSpec{
Namespace: "default",
@@ -241,9 +244,9 @@ func TestWatchApi(t *testing.T) {
},
},
}
_, err := g.client.WatchGet(&api.ObjectMeta{
_, err := g.client.WatchGet(&metav1.ObjectMeta{
Name: testWatch.Metadata.Name,
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
})
assertNotFoundFailure(err, "watch")
@@ -267,14 +270,14 @@ func TestWatchApi(t *testing.T) {
ws, err := g.client.WatchList()
panicIf(err)
assert(len(ws) == 2, "created two envs, but didn't find them")
assert(len(ws) == 2, fmt.Sprintf("created two watches, but found %v", len(ws)))
}
func TestTimeTriggerApi(t *testing.T) {
testTrigger := &tpr.Timetrigger{
Metadata: api.ObjectMeta{
testTrigger := &crd.TimeTrigger{
Metadata: metav1.ObjectMeta{
Name: "xxx",
Namespace: api.NamespaceDefault,
Namespace: metav1.NamespaceDefault,
},
Spec: fission.TimeTriggerSpec{
Cron: "0 30 * * * *",
@@ -284,7 +287,7 @@ func TestTimeTriggerApi(t *testing.T) {
},
},
}
_, err := g.client.TimeTriggerGet(&api.ObjectMeta{Name: testTrigger.Metadata.Name})
_, err := g.client.TimeTriggerGet(&metav1.ObjectMeta{Name: testTrigger.Metadata.Name})
assertNotFoundFailure(err, "trigger")
m, err := g.client.TimeTriggerCreate(testTrigger)
@@ -298,10 +301,12 @@ func TestTimeTriggerApi(t *testing.T) {
panicIf(err)
assert(testTrigger.Spec == tr.Spec, "trigger should match after reading")
testTrigger.Metadata.ResourceVersion = m.ResourceVersion
testTrigger.Spec.Cron = "@hourly"
_, err = g.client.TimeTriggerUpdate(testTrigger)
panicIf(err)
testTrigger.Metadata.ResourceVersion = ""
testTrigger.Metadata.Name = "yyy"
testTrigger.Spec.Cron = "Not valid cron spec"
_, err = g.client.TimeTriggerCreate(testTrigger)
@@ -309,7 +314,7 @@ func TestTimeTriggerApi(t *testing.T) {
ts, err := g.client.TimeTriggerList()
panicIf(err)
assert(len(ts) == 1, "created one trigger, but didn't find it")
assert(len(ts) == 1, fmt.Sprintf("created two time triggers, but found %v", len(ts)))
}
func TestMain(m *testing.M) {
@@ -324,7 +329,7 @@ func TestMain(m *testing.M) {
go Start(8888)
time.Sleep(time.Second)
time.Sleep(5 * time.Second)
g.client = client.MakeClient("http://localhost:8888")
resp, err := http.Get("http://localhost:8888/")
+2 -14
View File
@@ -26,7 +26,7 @@ import (
func (api *API) BuilderManagerBuildProxy(w http.ResponseWriter, r *http.Request) {
u := api.builderManagerUrl + "/v1/build"
proxy, err := api._getBuilderManagerProxy(u)
proxy, err := api.getBuilderManagerProxy(u)
if err != nil {
msg := fmt.Sprintf("Failed to establish proxy server: %v", err)
log.Println(msg)
@@ -36,19 +36,7 @@ func (api *API) BuilderManagerBuildProxy(w http.ResponseWriter, r *http.Request)
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) {
func (api *API) getBuilderManagerProxy(targetUrl string) (*httputil.ReverseProxy, error) {
svcUrl, err := url.Parse(targetUrl)
if err != nil {
return nil, err
+11 -11
View File
@@ -22,12 +22,12 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) EnvironmentCreate(env *tpr.Environment) (*api.ObjectMeta, error) {
func (c *Client) EnvironmentCreate(env *crd.Environment) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(env)
if err != nil {
return nil, err
@@ -44,7 +44,7 @@ func (c *Client) EnvironmentCreate(env *tpr.Environment) (*api.ObjectMeta, error
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (c *Client) EnvironmentCreate(env *tpr.Environment) (*api.ObjectMeta, error
return &m, nil
}
func (c *Client) EnvironmentGet(m *api.ObjectMeta) (*tpr.Environment, error) {
func (c *Client) EnvironmentGet(m *metav1.ObjectMeta) (*crd.Environment, error) {
relativeUrl := fmt.Sprintf("environments/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -68,7 +68,7 @@ func (c *Client) EnvironmentGet(m *api.ObjectMeta) (*tpr.Environment, error) {
return nil, err
}
var env tpr.Environment
var env crd.Environment
err = json.Unmarshal(body, &env)
if err != nil {
return nil, err
@@ -77,7 +77,7 @@ func (c *Client) EnvironmentGet(m *api.ObjectMeta) (*tpr.Environment, error) {
return &env, nil
}
func (c *Client) EnvironmentUpdate(env *tpr.Environment) (*api.ObjectMeta, error) {
func (c *Client) EnvironmentUpdate(env *crd.Environment) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(env)
if err != nil {
return nil, err
@@ -95,7 +95,7 @@ func (c *Client) EnvironmentUpdate(env *tpr.Environment) (*api.ObjectMeta, error
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -103,14 +103,14 @@ func (c *Client) EnvironmentUpdate(env *tpr.Environment) (*api.ObjectMeta, error
return &m, nil
}
func (c *Client) EnvironmentDelete(m *api.ObjectMeta) error {
func (c *Client) EnvironmentDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("environments/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) EnvironmentList() ([]tpr.Environment, error) {
func (c *Client) EnvironmentList() ([]crd.Environment, error) {
resp, err := http.Get(c.url("environments"))
if err != nil {
return nil, err
@@ -122,7 +122,7 @@ func (c *Client) EnvironmentList() ([]tpr.Environment, error) {
return nil, err
}
envs := make([]tpr.Environment, 0)
envs := make([]crd.Environment, 0)
err = json.Unmarshal(body, &envs)
if err != nil {
return nil, err
+12 -12
View File
@@ -22,12 +22,12 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) FunctionCreate(f *tpr.Function) (*api.ObjectMeta, error) {
func (c *Client) FunctionCreate(f *crd.Function) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(f)
if err != nil {
@@ -45,7 +45,7 @@ func (c *Client) FunctionCreate(f *tpr.Function) (*api.ObjectMeta, error) {
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -54,7 +54,7 @@ func (c *Client) FunctionCreate(f *tpr.Function) (*api.ObjectMeta, error) {
return &m, nil
}
func (c *Client) FunctionGet(m *api.ObjectMeta) (*tpr.Function, error) {
func (c *Client) FunctionGet(m *metav1.ObjectMeta) (*crd.Function, error) {
relativeUrl := fmt.Sprintf("functions/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -69,7 +69,7 @@ func (c *Client) FunctionGet(m *api.ObjectMeta) (*tpr.Function, error) {
return nil, err
}
var f tpr.Function
var f crd.Function
err = json.Unmarshal(body, &f)
if err != nil {
return nil, err
@@ -78,7 +78,7 @@ func (c *Client) FunctionGet(m *api.ObjectMeta) (*tpr.Function, error) {
return &f, nil
}
func (c *Client) FunctionGetRawDeployment(m *api.ObjectMeta) ([]byte, error) {
func (c *Client) FunctionGetRawDeployment(m *metav1.ObjectMeta) ([]byte, error) {
relativeUrl := fmt.Sprintf("functions/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
relativeUrl += fmt.Sprintf("&deploymentraw=1")
@@ -92,7 +92,7 @@ func (c *Client) FunctionGetRawDeployment(m *api.ObjectMeta) ([]byte, error) {
return c.handleResponse(resp)
}
func (c *Client) FunctionUpdate(f *tpr.Function) (*api.ObjectMeta, error) {
func (c *Client) FunctionUpdate(f *crd.Function) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(f)
if err != nil {
return nil, err
@@ -110,7 +110,7 @@ func (c *Client) FunctionUpdate(f *tpr.Function) (*api.ObjectMeta, error) {
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -118,13 +118,13 @@ func (c *Client) FunctionUpdate(f *tpr.Function) (*api.ObjectMeta, error) {
return &m, nil
}
func (c *Client) FunctionDelete(m *api.ObjectMeta) error {
func (c *Client) FunctionDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("functions/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) FunctionList() ([]tpr.Function, error) {
func (c *Client) FunctionList() ([]crd.Function, error) {
resp, err := http.Get(c.url("functions"))
if err != nil {
return nil, err
@@ -136,7 +136,7 @@ func (c *Client) FunctionList() ([]tpr.Function, error) {
return nil, err
}
funcs := make([]tpr.Function, 0)
funcs := make([]crd.Function, 0)
err = json.Unmarshal(body, &funcs)
if err != nil {
return nil, err
+11 -11
View File
@@ -22,12 +22,12 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) HTTPTriggerCreate(t *tpr.Httptrigger) (*api.ObjectMeta, error) {
func (c *Client) HTTPTriggerCreate(t *crd.HTTPTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
@@ -44,7 +44,7 @@ func (c *Client) HTTPTriggerCreate(t *tpr.Httptrigger) (*api.ObjectMeta, error)
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (c *Client) HTTPTriggerCreate(t *tpr.Httptrigger) (*api.ObjectMeta, error)
return &m, nil
}
func (c *Client) HTTPTriggerGet(m *api.ObjectMeta) (*tpr.Httptrigger, error) {
func (c *Client) HTTPTriggerGet(m *metav1.ObjectMeta) (*crd.HTTPTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/http/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -68,7 +68,7 @@ func (c *Client) HTTPTriggerGet(m *api.ObjectMeta) (*tpr.Httptrigger, error) {
return nil, err
}
var t tpr.Httptrigger
var t crd.HTTPTrigger
err = json.Unmarshal(body, &t)
if err != nil {
return nil, err
@@ -77,7 +77,7 @@ func (c *Client) HTTPTriggerGet(m *api.ObjectMeta) (*tpr.Httptrigger, error) {
return &t, nil
}
func (c *Client) HTTPTriggerUpdate(t *tpr.Httptrigger) (*api.ObjectMeta, error) {
func (c *Client) HTTPTriggerUpdate(t *crd.HTTPTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
@@ -95,7 +95,7 @@ func (c *Client) HTTPTriggerUpdate(t *tpr.Httptrigger) (*api.ObjectMeta, error)
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -103,13 +103,13 @@ func (c *Client) HTTPTriggerUpdate(t *tpr.Httptrigger) (*api.ObjectMeta, error)
return &m, nil
}
func (c *Client) HTTPTriggerDelete(m *api.ObjectMeta) error {
func (c *Client) HTTPTriggerDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("triggers/http/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) HTTPTriggerList() ([]tpr.Httptrigger, error) {
func (c *Client) HTTPTriggerList() ([]crd.HTTPTrigger, error) {
resp, err := http.Get(c.url("triggers/http"))
if err != nil {
return nil, err
@@ -121,7 +121,7 @@ func (c *Client) HTTPTriggerList() ([]tpr.Httptrigger, error) {
return nil, err
}
triggers := make([]tpr.Httptrigger, 0)
triggers := make([]crd.HTTPTrigger, 0)
err = json.Unmarshal(body, &triggers)
if err != nil {
return nil, err
+10 -10
View File
@@ -22,13 +22,13 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) WatchCreate(w *tpr.Kuberneteswatchtrigger) (*api.ObjectMeta, error) {
func (c *Client) WatchCreate(w *crd.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(w)
if err != nil {
return nil, err
@@ -45,7 +45,7 @@ func (c *Client) WatchCreate(w *tpr.Kuberneteswatchtrigger) (*api.ObjectMeta, er
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -54,7 +54,7 @@ func (c *Client) WatchCreate(w *tpr.Kuberneteswatchtrigger) (*api.ObjectMeta, er
return &m, nil
}
func (c *Client) WatchGet(m *api.ObjectMeta) (*tpr.Kuberneteswatchtrigger, error) {
func (c *Client) WatchGet(m *metav1.ObjectMeta) (*crd.KubernetesWatchTrigger, error) {
relativeUrl := fmt.Sprintf("watches/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -69,7 +69,7 @@ func (c *Client) WatchGet(m *api.ObjectMeta) (*tpr.Kuberneteswatchtrigger, error
return nil, err
}
var w tpr.Kuberneteswatchtrigger
var w crd.KubernetesWatchTrigger
err = json.Unmarshal(body, &w)
if err != nil {
return nil, err
@@ -78,18 +78,18 @@ func (c *Client) WatchGet(m *api.ObjectMeta) (*tpr.Kuberneteswatchtrigger, error
return &w, nil
}
func (c *Client) WatchUpdate(w *tpr.Kuberneteswatchtrigger) (*api.ObjectMeta, error) {
func (c *Client) WatchUpdate(w *crd.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
return nil, fission.MakeError(fission.ErrorNotImplmented,
"watch update not implemented")
}
func (c *Client) WatchDelete(m *api.ObjectMeta) error {
func (c *Client) WatchDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("watches/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) WatchList() ([]tpr.Kuberneteswatchtrigger, error) {
func (c *Client) WatchList() ([]crd.KubernetesWatchTrigger, error) {
resp, err := http.Get(c.url("watches"))
if err != nil {
return nil, err
@@ -101,7 +101,7 @@ func (c *Client) WatchList() ([]tpr.Kuberneteswatchtrigger, error) {
return nil, err
}
watches := make([]tpr.Kuberneteswatchtrigger, 0)
watches := make([]crd.KubernetesWatchTrigger, 0)
err = json.Unmarshal(body, &watches)
if err != nil {
return nil, err
+11 -11
View File
@@ -22,12 +22,12 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) MessageQueueTriggerCreate(t *tpr.Messagequeuetrigger) (*api.ObjectMeta, error) {
func (c *Client) MessageQueueTriggerCreate(t *crd.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
@@ -44,7 +44,7 @@ func (c *Client) MessageQueueTriggerCreate(t *tpr.Messagequeuetrigger) (*api.Obj
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (c *Client) MessageQueueTriggerCreate(t *tpr.Messagequeuetrigger) (*api.Obj
return &m, nil
}
func (c *Client) MessageQueueTriggerGet(m *api.ObjectMeta) (*tpr.Messagequeuetrigger, error) {
func (c *Client) MessageQueueTriggerGet(m *metav1.ObjectMeta) (*crd.MessageQueueTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/messagequeue/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -68,7 +68,7 @@ func (c *Client) MessageQueueTriggerGet(m *api.ObjectMeta) (*tpr.Messagequeuetri
return nil, err
}
var t tpr.Messagequeuetrigger
var t crd.MessageQueueTrigger
err = json.Unmarshal(body, &t)
if err != nil {
return nil, err
@@ -77,7 +77,7 @@ func (c *Client) MessageQueueTriggerGet(m *api.ObjectMeta) (*tpr.Messagequeuetri
return &t, nil
}
func (c *Client) MessageQueueTriggerUpdate(mqTrigger *tpr.Messagequeuetrigger) (*api.ObjectMeta, error) {
func (c *Client) MessageQueueTriggerUpdate(mqTrigger *crd.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(mqTrigger)
if err != nil {
return nil, err
@@ -95,7 +95,7 @@ func (c *Client) MessageQueueTriggerUpdate(mqTrigger *tpr.Messagequeuetrigger) (
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -103,13 +103,13 @@ func (c *Client) MessageQueueTriggerUpdate(mqTrigger *tpr.Messagequeuetrigger) (
return &m, nil
}
func (c *Client) MessageQueueTriggerDelete(m *api.ObjectMeta) error {
func (c *Client) MessageQueueTriggerDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("triggers/messagequeue/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) MessageQueueTriggerList(mqType string) ([]tpr.Messagequeuetrigger, error) {
func (c *Client) MessageQueueTriggerList(mqType string) ([]crd.MessageQueueTrigger, error) {
relativeUrl := "triggers/messagequeue"
if len(mqType) > 0 {
// TODO remove this, replace with field selector
@@ -127,7 +127,7 @@ func (c *Client) MessageQueueTriggerList(mqType string) ([]tpr.Messagequeuetrigg
return nil, err
}
triggers := make([]tpr.Messagequeuetrigger, 0)
triggers := make([]crd.MessageQueueTrigger, 0)
err = json.Unmarshal(body, &triggers)
if err != nil {
return nil, err
+11 -11
View File
@@ -22,12 +22,12 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) PackageCreate(f *tpr.Package) (*api.ObjectMeta, error) {
func (c *Client) PackageCreate(f *crd.Package) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(f)
if err != nil {
@@ -45,7 +45,7 @@ func (c *Client) PackageCreate(f *tpr.Package) (*api.ObjectMeta, error) {
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -54,7 +54,7 @@ func (c *Client) PackageCreate(f *tpr.Package) (*api.ObjectMeta, error) {
return &m, nil
}
func (c *Client) PackageGet(m *api.ObjectMeta) (*tpr.Package, error) {
func (c *Client) PackageGet(m *metav1.ObjectMeta) (*crd.Package, error) {
relativeUrl := fmt.Sprintf("packages/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -69,7 +69,7 @@ func (c *Client) PackageGet(m *api.ObjectMeta) (*tpr.Package, error) {
return nil, err
}
var f tpr.Package
var f crd.Package
err = json.Unmarshal(body, &f)
if err != nil {
return nil, err
@@ -78,7 +78,7 @@ func (c *Client) PackageGet(m *api.ObjectMeta) (*tpr.Package, error) {
return &f, nil
}
func (c *Client) PackageUpdate(f *tpr.Package) (*api.ObjectMeta, error) {
func (c *Client) PackageUpdate(f *crd.Package) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(f)
if err != nil {
return nil, err
@@ -96,7 +96,7 @@ func (c *Client) PackageUpdate(f *tpr.Package) (*api.ObjectMeta, error) {
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -104,13 +104,13 @@ func (c *Client) PackageUpdate(f *tpr.Package) (*api.ObjectMeta, error) {
return &m, nil
}
func (c *Client) PackageDelete(m *api.ObjectMeta) error {
func (c *Client) PackageDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("packages/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) PackageList() ([]tpr.Package, error) {
func (c *Client) PackageList() ([]crd.Package, error) {
resp, err := http.Get(c.url("packages"))
if err != nil {
return nil, err
@@ -122,7 +122,7 @@ func (c *Client) PackageList() ([]tpr.Package, error) {
return nil, err
}
funcs := make([]tpr.Package, 0)
funcs := make([]crd.Package, 0)
err = json.Unmarshal(body, &funcs)
if err != nil {
return nil, err
+11 -11
View File
@@ -22,12 +22,12 @@ import (
"fmt"
"net/http"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (c *Client) TimeTriggerCreate(t *tpr.Timetrigger) (*api.ObjectMeta, error) {
func (c *Client) TimeTriggerCreate(t *crd.TimeTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
@@ -44,7 +44,7 @@ func (c *Client) TimeTriggerCreate(t *tpr.Timetrigger) (*api.ObjectMeta, error)
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -53,7 +53,7 @@ func (c *Client) TimeTriggerCreate(t *tpr.Timetrigger) (*api.ObjectMeta, error)
return &m, nil
}
func (c *Client) TimeTriggerGet(m *api.ObjectMeta) (*tpr.Timetrigger, error) {
func (c *Client) TimeTriggerGet(m *metav1.ObjectMeta) (*crd.TimeTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/time/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
@@ -68,7 +68,7 @@ func (c *Client) TimeTriggerGet(m *api.ObjectMeta) (*tpr.Timetrigger, error) {
return nil, err
}
var t tpr.Timetrigger
var t crd.TimeTrigger
err = json.Unmarshal(body, &t)
if err != nil {
return nil, err
@@ -77,7 +77,7 @@ func (c *Client) TimeTriggerGet(m *api.ObjectMeta) (*tpr.Timetrigger, error) {
return &t, nil
}
func (c *Client) TimeTriggerUpdate(t *tpr.Timetrigger) (*api.ObjectMeta, error) {
func (c *Client) TimeTriggerUpdate(t *crd.TimeTrigger) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
@@ -95,7 +95,7 @@ func (c *Client) TimeTriggerUpdate(t *tpr.Timetrigger) (*api.ObjectMeta, error)
return nil, err
}
var m api.ObjectMeta
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
@@ -103,13 +103,13 @@ func (c *Client) TimeTriggerUpdate(t *tpr.Timetrigger) (*api.ObjectMeta, error)
return &m, nil
}
func (c *Client) TimeTriggerDelete(m *api.ObjectMeta) error {
func (c *Client) TimeTriggerDelete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("triggers/time/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.delete(relativeUrl)
}
func (c *Client) TimeTriggerList() ([]tpr.Timetrigger, error) {
func (c *Client) TimeTriggerList() ([]crd.TimeTrigger, error) {
resp, err := http.Get(c.url("triggers/time"))
if err != nil {
return nil, err
@@ -121,7 +121,7 @@ func (c *Client) TimeTriggerList() ([]tpr.Timetrigger, error) {
return nil, err
}
triggers := make([]tpr.Timetrigger, 0)
triggers := make([]crd.TimeTrigger, 0)
err = json.Unmarshal(body, &triggers)
if err != nil {
return nil, err
+5 -5
View File
@@ -19,21 +19,21 @@ package controller
import (
"log"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func Start(port int) {
fc, kc, err := tpr.MakeFissionClient()
fc, _, apiExtClient, err := crd.MakeFissionClient()
if err != nil {
log.Fatalf("Failed to connect to K8s API: %v", err)
}
err = tpr.EnsureFissionTPRs(kc)
err = crd.EnsureFissionCRDs(apiExtClient)
if err != nil {
log.Fatalf("Failed to create fission TPRs: %v", err)
log.Fatalf("Failed to create fission CRDs: %v", err)
}
fc.WaitForTPRs()
fc.WaitForCRDs()
api, err := MakeAPI()
if err != nil {
+4 -4
View File
@@ -20,15 +20,15 @@ import (
"errors"
"regexp"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func makeTPRBackedAPI() (*API, error) {
fissionClient, _, err := tpr.MakeFissionClient()
func makeCRDBackedAPI() (*API, error) {
fissionClient, kubernetesClient, _, err := crd.MakeFissionClient()
if err != nil {
return nil, err
}
return &API{fissionClient: fissionClient}, nil
return &API{fissionClient: fissionClient, kubernetesClient: kubernetesClient}, nil
}
func validateResourceName(name string) error {
+8 -8
View File
@@ -23,14 +23,14 @@ import (
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) EnvironmentApiList(w http.ResponseWriter, r *http.Request) {
envs, err := a.fissionClient.Environments(api.NamespaceAll).List(api.ListOptions{})
envs, err := a.fissionClient.Environments(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -52,7 +52,7 @@ func (a *API) EnvironmentApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
var env tpr.Environment
var env crd.Environment
err = json.Unmarshal(body, &env)
if err != nil {
log.Printf("Failed to unmarshal request body: [%v]", body)
@@ -87,7 +87,7 @@ func (a *API) EnvironmentApiGet(w http.ResponseWriter, r *http.Request) {
name := vars["environment"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
env, err := a.fissionClient.Environments(ns).Get(name)
@@ -115,7 +115,7 @@ func (a *API) EnvironmentApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
var env tpr.Environment
var env crd.Environment
err = json.Unmarshal(body, &env)
if err != nil {
a.respondWithError(w, err)
@@ -148,10 +148,10 @@ func (a *API) EnvironmentApiDelete(w http.ResponseWriter, r *http.Request) {
name := vars["environment"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Environments(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.Environments(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
+76 -8
View File
@@ -18,21 +18,27 @@ package controller
import (
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"net/http/httputil"
"net/url"
"sort"
"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
restclient "k8s.io/client-go/rest"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) FunctionApiList(w http.ResponseWriter, r *http.Request) {
funcs, err := a.fissionClient.Functions(api.NamespaceAll).List(api.ListOptions{})
funcs, err := a.fissionClient.Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -54,7 +60,7 @@ func (a *API) FunctionApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
var f tpr.Function
var f crd.Function
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
@@ -88,7 +94,7 @@ func (a *API) FunctionApiGet(w http.ResponseWriter, r *http.Request) {
name := vars["function"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
f, err := a.fissionClient.Functions(ns).Get(name)
@@ -115,7 +121,7 @@ func (a *API) FunctionApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
var f tpr.Function
var f crd.Function
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
@@ -147,10 +153,10 @@ func (a *API) FunctionApiDelete(w http.ResponseWriter, r *http.Request) {
name := vars["function"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Functions(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.Functions(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -188,3 +194,65 @@ func (a *API) FunctionLogsApiPost(w http.ResponseWriter, r *http.Request) {
}
proxy.ServeHTTP(w, r)
}
// FunctionPodLogs : Get logs for a function directly from pod
func (a *API) FunctionPodLogs(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
fnName := vars["function"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = "fission-function"
}
f, err := a.fissionClient.Functions(api.NamespaceDefault).Get(fnName)
if err != nil {
a.respondWithError(w, err)
return
}
envName := f.Spec.Environment.Name
if err != nil {
a.respondWithError(w, err)
return
}
// Get function Pods first
selector := "functionName=" + fnName
podList, err := a.kubernetesClient.Core().Pods(ns).List(metav1.ListOptions{LabelSelector: selector})
if err != nil {
a.respondWithError(w, err)
return
}
// Get the logs for last Pod executed
pods := podList.Items
sort.Slice(pods, func(i, j int) bool {
itime := pods[i].ObjectMeta.CreationTimestamp.Time
jtime := pods[j].ObjectMeta.CreationTimestamp.Time
return itime.After(jtime)
})
podLogOpts := v1.PodLogOptions{Container: envName} // Only the env container, not fetcher
var podLogsReq *restclient.Request
if len(pods) > 0 {
podLogsReq = a.kubernetesClient.Core().Pods(ns).GetLogs(pods[0].ObjectMeta.Name, &podLogOpts)
} else {
a.respondWithError(w, errors.New("No active pods found"))
return
}
podLogs, err := podLogsReq.Stream()
if err != nil {
a.respondWithError(w, err)
return
}
defer podLogs.Close()
_, err = io.Copy(w, podLogs)
if err != nil {
a.respondWithError(w, err)
return
}
return
}
+17 -17
View File
@@ -23,14 +23,14 @@ import (
"net/http"
"github.com/gorilla/mux"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) HTTPTriggerApiList(w http.ResponseWriter, r *http.Request) {
triggers, err := a.fissionClient.Httptriggers(api.NamespaceAll).List(api.ListOptions{})
triggers, err := a.fissionClient.HTTPTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -45,15 +45,15 @@ func (a *API) HTTPTriggerApiList(w http.ResponseWriter, r *http.Request) {
a.respondWithSuccess(w, resp)
}
func (a *API) checkHttpTriggerDuplicates(t *tpr.Httptrigger) error {
triggers, err := a.fissionClient.Httptriggers(api.NamespaceAll).List(api.ListOptions{})
func (a *API) checkHTTPTriggerDuplicates(t *crd.HTTPTrigger) error {
triggers, err := a.fissionClient.HTTPTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
return err
}
for _, ht := range triggers.Items {
if ht.Spec.RelativeURL == t.Spec.RelativeURL && ht.Spec.Method == t.Spec.Method {
if ht.Spec.RelativeURL == t.Spec.RelativeURL && ht.Spec.Method == t.Spec.Method && ht.Spec.Host == t.Spec.Host {
return fission.MakeError(fission.ErrorNameExists,
fmt.Sprintf("HTTPTrigger with same URL & method already exists (%v)",
fmt.Sprintf("HTTPTrigger with same Host, URL & method already exists (%v)",
ht.Metadata.Name))
}
}
@@ -67,7 +67,7 @@ func (a *API) HTTPTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
var t tpr.Httptrigger
var t crd.HTTPTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
@@ -81,13 +81,13 @@ func (a *API) HTTPTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
}
// Ensure we don't have a duplicate HTTP route defined (same URL and method)
err = a.checkHttpTriggerDuplicates(&t)
err = a.checkHTTPTriggerDuplicates(&t)
if err != nil {
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.Httptriggers(t.Metadata.Namespace).Create(&t)
tnew, err := a.fissionClient.HTTPTriggers(t.Metadata.Namespace).Create(&t)
if err != nil {
a.respondWithError(w, err)
return
@@ -108,10 +108,10 @@ func (a *API) HTTPTriggerApiGet(w http.ResponseWriter, r *http.Request) {
name := vars["httpTrigger"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
t, err := a.fissionClient.Httptriggers(ns).Get(name)
t, err := a.fissionClient.HTTPTriggers(ns).Get(name)
if err != nil {
a.respondWithError(w, err)
return
@@ -136,7 +136,7 @@ func (a *API) HTTPTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
var t tpr.Httptrigger
var t crd.HTTPTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
@@ -149,13 +149,13 @@ func (a *API) HTTPTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
err = a.checkHttpTriggerDuplicates(&t)
err = a.checkHTTPTriggerDuplicates(&t)
if err != nil {
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.Httptriggers(t.Metadata.Namespace).Update(&t)
tnew, err := a.fissionClient.HTTPTriggers(t.Metadata.Namespace).Update(&t)
if err != nil {
a.respondWithError(w, err)
return
@@ -174,10 +174,10 @@ func (a *API) HTTPTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
name := vars["httpTrigger"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Httptriggers(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.HTTPTriggers(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
+11 -11
View File
@@ -22,15 +22,15 @@ import (
"net/http"
"github.com/gorilla/mux"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) MessageQueueTriggerApiList(w http.ResponseWriter, r *http.Request) {
//mqType := r.FormValue("mqtype") // ignored for now
triggers, err := a.fissionClient.Messagequeuetriggers(api.NamespaceAll).List(api.ListOptions{})
triggers, err := a.fissionClient.MessageQueueTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -50,7 +50,7 @@ func (a *API) MessageQueueTriggerApiCreate(w http.ResponseWriter, r *http.Reques
return
}
var mqTrigger tpr.Messagequeuetrigger
var mqTrigger crd.MessageQueueTrigger
err = json.Unmarshal(body, &mqTrigger)
if err != nil {
a.respondWithError(w, err)
@@ -63,7 +63,7 @@ func (a *API) MessageQueueTriggerApiCreate(w http.ResponseWriter, r *http.Reques
return
}
tnew, err := a.fissionClient.Messagequeuetriggers(mqTrigger.Metadata.Namespace).Create(&mqTrigger)
tnew, err := a.fissionClient.MessageQueueTriggers(mqTrigger.Metadata.Namespace).Create(&mqTrigger)
if err != nil {
a.respondWithError(w, err)
return
@@ -83,10 +83,10 @@ func (a *API) MessageQueueTriggerApiGet(w http.ResponseWriter, r *http.Request)
name := vars["mqTrigger"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
mqTrigger, err := a.fissionClient.Messagequeuetriggers(ns).Get(name)
mqTrigger, err := a.fissionClient.MessageQueueTriggers(ns).Get(name)
if err != nil {
a.respondWithError(w, err)
return
@@ -109,7 +109,7 @@ func (a *API) MessageQueueTriggerApiUpdate(w http.ResponseWriter, r *http.Reques
return
}
var mqTrigger tpr.Messagequeuetrigger
var mqTrigger crd.MessageQueueTrigger
err = json.Unmarshal(body, &mqTrigger)
if err != nil {
a.respondWithError(w, err)
@@ -122,7 +122,7 @@ func (a *API) MessageQueueTriggerApiUpdate(w http.ResponseWriter, r *http.Reques
return
}
tnew, err := a.fissionClient.Messagequeuetriggers(mqTrigger.Metadata.Namespace).Update(&mqTrigger)
tnew, err := a.fissionClient.MessageQueueTriggers(mqTrigger.Metadata.Namespace).Update(&mqTrigger)
if err != nil {
a.respondWithError(w, err)
return
@@ -141,10 +141,10 @@ func (a *API) MessageQueueTriggerApiDelete(w http.ResponseWriter, r *http.Reques
name := vars["mqTrigger"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Messagequeuetriggers(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.MessageQueueTriggers(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
+8 -8
View File
@@ -22,14 +22,14 @@ import (
"net/http"
"github.com/gorilla/mux"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) PackageApiList(w http.ResponseWriter, r *http.Request) {
funcs, err := a.fissionClient.Packages(api.NamespaceAll).List(api.ListOptions{})
funcs, err := a.fissionClient.Packages(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -51,7 +51,7 @@ func (a *API) PackageApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
var f tpr.Package
var f crd.Package
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
@@ -97,7 +97,7 @@ func (a *API) PackageApiGet(w http.ResponseWriter, r *http.Request) {
name := vars["package"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
raw := r.FormValue("raw") // just the deployment pkg
@@ -130,7 +130,7 @@ func (a *API) PackageApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
var f tpr.Package
var f crd.Package
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
@@ -162,10 +162,10 @@ func (a *API) PackageApiDelete(w http.ResponseWriter, r *http.Request) {
name := vars["package"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Packages(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.Packages(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
+11 -11
View File
@@ -23,14 +23,14 @@ import (
"github.com/gorilla/mux"
"github.com/robfig/cron"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) TimeTriggerApiList(w http.ResponseWriter, r *http.Request) {
triggers, err := a.fissionClient.Timetriggers(api.NamespaceAll).List(api.ListOptions{})
triggers, err := a.fissionClient.TimeTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -52,7 +52,7 @@ func (a *API) TimeTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
var t tpr.Timetrigger
var t crd.TimeTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
@@ -73,7 +73,7 @@ func (a *API) TimeTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
tnew, err := a.fissionClient.Timetriggers(t.Metadata.Namespace).Create(&t)
tnew, err := a.fissionClient.TimeTriggers(t.Metadata.Namespace).Create(&t)
if err != nil {
a.respondWithError(w, err)
return
@@ -94,10 +94,10 @@ func (a *API) TimeTriggerApiGet(w http.ResponseWriter, r *http.Request) {
name := vars["timeTrigger"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
t, err := a.fissionClient.Timetriggers(ns).Get(name)
t, err := a.fissionClient.TimeTriggers(ns).Get(name)
if err != nil {
a.respondWithError(w, err)
return
@@ -122,7 +122,7 @@ func (a *API) TimeTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
var t tpr.Timetrigger
var t crd.TimeTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
@@ -142,7 +142,7 @@ func (a *API) TimeTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
return
}
tnew, err := a.fissionClient.Timetriggers(t.Metadata.Namespace).Update(&t)
tnew, err := a.fissionClient.TimeTriggers(t.Metadata.Namespace).Update(&t)
if err != nil {
a.respondWithError(w, err)
return
@@ -161,10 +161,10 @@ func (a *API) TimeTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
name := vars["timeTrigger"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Timetriggers(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.TimeTriggers(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
+64
View File
@@ -0,0 +1,64 @@
/*
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 (
"net/http"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/crd"
)
func (a *API) Tpr2crdApi(w http.ResponseWriter, r *http.Request) {
_, kubeClient, _, err := crd.MakeFissionClient()
if err != nil {
a.respondWithError(w, err)
return
}
fissionTprs := []string{
"function.fission.io",
"environment.fission.io",
"httptrigger.fission.io",
"kuberneteswatchtrigger.fission.io",
"timetrigger.fission.io",
"messagequeuetrigger.fission.io",
"package.fission.io",
}
tprList, err := kubeClient.ThirdPartyResources().List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
for _, tpr := range tprList.Items {
for _, tprName := range fissionTprs {
if tpr.Name == tprName {
err := kubeClient.ThirdPartyResources().Delete(tpr.Name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
break
}
}
}
a.respondWithSuccess(w, nil)
}
+9 -9
View File
@@ -22,14 +22,14 @@ import (
"net/http"
"github.com/gorilla/mux"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func (a *API) WatchApiList(w http.ResponseWriter, r *http.Request) {
watches, err := a.fissionClient.Kuberneteswatchtriggers(api.NamespaceAll).List(api.ListOptions{})
watches, err := a.fissionClient.KubernetesWatchTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
@@ -51,7 +51,7 @@ func (a *API) WatchApiCreate(w http.ResponseWriter, r *http.Request) {
return
}
var watch tpr.Kuberneteswatchtrigger
var watch crd.KubernetesWatchTrigger
err = json.Unmarshal(body, &watch)
if err != nil {
a.respondWithError(w, err)
@@ -66,7 +66,7 @@ func (a *API) WatchApiCreate(w http.ResponseWriter, r *http.Request) {
// TODO check for duplicate watches
wnew, err := a.fissionClient.Kuberneteswatchtriggers(watch.Metadata.Namespace).Create(&watch)
wnew, err := a.fissionClient.KubernetesWatchTriggers(watch.Metadata.Namespace).Create(&watch)
if err != nil {
a.respondWithError(w, err)
return
@@ -87,10 +87,10 @@ func (a *API) WatchApiGet(w http.ResponseWriter, r *http.Request) {
name := vars["watch"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
watch, err := a.fissionClient.Kuberneteswatchtriggers(ns).Get(name)
watch, err := a.fissionClient.KubernetesWatchTriggers(ns).Get(name)
if err != nil {
a.respondWithError(w, err)
return
@@ -115,10 +115,10 @@ func (a *API) WatchApiDelete(w http.ResponseWriter, r *http.Request) {
name := vars["watch"]
ns := vars["namespace"]
if len(ns) == 0 {
ns = api.NamespaceDefault
ns = metav1.NamespaceDefault
}
err := a.fissionClient.Kuberneteswatchtriggers(ns).Delete(name, &api.DeleteOptions{})
err := a.fissionClient.KubernetesWatchTriggers(ns).Delete(name, &metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
+7 -5
View File
@@ -2,25 +2,27 @@ package controller
import (
"fmt"
"github.com/gorilla/mux"
"net/http"
"net/http/httputil"
"net/url"
"strings"
)
func (api *API) WorkflowApiProxy(w http.ResponseWriter, r *http.Request) {
u := api.storageServiceUrl
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 = strings.TrimPrefix(ssUrl.Path, "/proxy/workflow")
req.URL.RawQuery = ssUrl.RawQuery
req.URL.Path = path
}
proxy := &httputil.ReverseProxy{
Director: director,
+220
View File
@@ -0,0 +1,220 @@
/*
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 crd
import (
"errors"
"os"
"time"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
type (
FissionClient struct {
crdClient *rest.RESTClient
}
)
// Get a kubernetes client using the kubeconfig file at the
// environment var $KUBECONFIG, or an in-cluster config if that's
// undefined.
func GetKubernetesClient() (*rest.Config, *kubernetes.Clientset, *apiextensionsclient.Clientset, error) {
var config *rest.Config
var err error
// get the config, either from kubeconfig or using our
// in-cluster service account
kubeConfig := os.Getenv("KUBECONFIG")
if len(kubeConfig) != 0 {
config, err = clientcmd.BuildConfigFromFlags("", kubeConfig)
if err != nil {
return nil, nil, nil, err
}
} else {
config, err = rest.InClusterConfig()
if err != nil {
return nil, nil, nil, err
}
}
// creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, nil, nil, err
}
apiExtClientset, err := apiextensionsclient.NewForConfig(config)
if err != nil {
return nil, nil, nil, err
}
return config, clientset, apiExtClientset, nil
}
// GetCrdClient gets a CRD client config
func GetCrdClient(config *rest.Config) (*rest.RESTClient, error) {
// mutate config to add our types
configureClient(config)
// make a REST client with that config
return rest.RESTClientFor(config)
}
// configureClient sets up a REST client for Fission CRD types.
//
// This is copied from the client-go CRD example. (I don't understand
// all of it completely.) It registers our types with the global API
// "scheme" (api.Scheme), which keeps a directory of types [I guess so
// it can use the string in the Kind field to make a Go object?]. It
// also puts the fission CRD types under a "group version" which we
// create for our CRDs types.
func configureClient(config *rest.Config) {
groupversion := schema.GroupVersion{
Group: "fission.io",
Version: "v1",
}
config.GroupVersion = &groupversion
config.APIPath = "/apis"
config.ContentType = runtime.ContentTypeJSON
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
schemeBuilder := runtime.NewSchemeBuilder(
func(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(
groupversion,
&Function{},
&FunctionList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
scheme.AddKnownTypes(
groupversion,
&Environment{},
&EnvironmentList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
scheme.AddKnownTypes(
groupversion,
&HTTPTrigger{},
&HTTPTriggerList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
scheme.AddKnownTypes(
groupversion,
&KubernetesWatchTrigger{},
&KubernetesWatchTriggerList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
scheme.AddKnownTypes(
groupversion,
&TimeTrigger{},
&TimeTriggerList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
scheme.AddKnownTypes(
groupversion,
&MessageQueueTrigger{},
&MessageQueueTriggerList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
scheme.AddKnownTypes(
groupversion,
&Package{},
&PackageList{},
&metav1.ListOptions{},
&metav1.DeleteOptions{},
)
return nil
})
schemeBuilder.AddToScheme(scheme.Scheme)
}
func waitForCRDs(crdClient *rest.RESTClient) error {
start := time.Now()
for {
fi := MakeFunctionInterface(crdClient, metav1.NamespaceDefault)
_, err := fi.List(metav1.ListOptions{})
if err != nil {
time.Sleep(100 * time.Millisecond)
} else {
return nil
}
if time.Now().Sub(start) > 30*time.Second {
return errors.New("timeout waiting for CRDs")
}
}
}
func MakeFissionClient() (*FissionClient, *kubernetes.Clientset, *apiextensionsclient.Clientset, error) {
config, kubeClient, apiExtClient, err := GetKubernetesClient()
if err != nil {
return nil, nil, nil, err
}
crdClient, err := GetCrdClient(config)
if err != nil {
return nil, nil, nil, err
}
fc := &FissionClient{
crdClient: crdClient,
}
return fc, kubeClient, apiExtClient, nil
}
func (fc *FissionClient) Functions(ns string) FunctionInterface {
return MakeFunctionInterface(fc.crdClient, ns)
}
func (fc *FissionClient) Environments(ns string) EnvironmentInterface {
return MakeEnvironmentInterface(fc.crdClient, ns)
}
func (fc *FissionClient) HTTPTriggers(ns string) HTTPTriggerInterface {
return MakeHTTPTriggerInterface(fc.crdClient, ns)
}
func (fc *FissionClient) KubernetesWatchTriggers(ns string) KubernetesWatchTriggerInterface {
return MakeKubernetesWatchTriggerInterface(fc.crdClient, ns)
}
func (fc *FissionClient) TimeTriggers(ns string) TimeTriggerInterface {
return MakeTimeTriggerInterface(fc.crdClient, ns)
}
func (fc *FissionClient) MessageQueueTriggers(ns string) MessageQueueTriggerInterface {
return MakeMessageQueueTriggerInterface(fc.crdClient, ns)
}
func (fc *FissionClient) Packages(ns string) PackageInterface {
return MakePackageInterface(fc.crdClient, ns)
}
func (fc *FissionClient) WaitForCRDs() {
waitForCRDs(fc.crdClient)
}
func (fc *FissionClient) GetCrdClient() *rest.RESTClient {
return fc.crdClient
}
+170
View File
@@ -0,0 +1,170 @@
/*
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 crd
import (
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
crdGroupName = "fission.io"
crdVersion = "v1"
)
// ensureCRD checks if the given CRD type exists, and creates it if
// needed. (Note that this creates the CRD type; it doesn't create any
// _instances_ of that type.)
func ensureCRD(clientset *apiextensionsclient.Clientset, crd *apiextensionsv1beta1.CustomResourceDefinition) error {
_, err := clientset.Apiextensions().CustomResourceDefinitions().Get(crd.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
_, err := clientset.Apiextensions().CustomResourceDefinitions().Create(crd)
if err != nil {
return err
}
}
}
return nil
}
// Ensure CRDs
func EnsureFissionCRDs(clientset *apiextensionsclient.Clientset) error {
crds := []apiextensionsv1beta1.CustomResourceDefinition{
// Functions
{
ObjectMeta: metav1.ObjectMeta{
Name: "functions.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "Function",
Plural: "functions",
Singular: "function",
},
},
},
// Environments (function containers)
{
ObjectMeta: metav1.ObjectMeta{
Name: "environments.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "Environment",
Plural: "environments",
Singular: "environment",
},
},
},
// HTTP triggers for functions
{
ObjectMeta: metav1.ObjectMeta{
Name: "httptriggers.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "HTTPTrigger",
Plural: "httptriggers",
Singular: "httptrigger",
},
},
},
// Kubernetes watch triggers for functions
{
ObjectMeta: metav1.ObjectMeta{
Name: "kuberneteswatchtriggers.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "KubernetesWatchTrigger",
Plural: "kuberneteswatchtriggers",
Singular: "kuberneteswatchtrigger",
},
},
},
// Time-based triggers for functions
{
ObjectMeta: metav1.ObjectMeta{
Name: "timetriggers.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "TimeTrigger",
Plural: "timetriggers",
Singular: "timetrigger",
},
},
},
// Message queue triggers for functions
{
ObjectMeta: metav1.ObjectMeta{
Name: "messagequeuetriggers.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "MessageQueueTrigger",
Plural: "messagequeuetriggers",
Singular: "messagequeuetrigger",
},
},
},
// Packages: archives containing source or binaries for one or more functions
{
ObjectMeta: metav1.ObjectMeta{
Name: "packages.fission.io",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: crdGroupName,
Version: crdVersion,
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Kind: "Package",
Plural: "packages",
Singular: "package",
},
},
},
}
for _, crd := range crds {
err := ensureCRD(clientset, &crd)
if err != nil {
return err
}
}
return nil
}
+69 -58
View File
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"log"
@@ -22,9 +22,8 @@ import (
"testing"
"time"
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/api/unversioned"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"github.com/fission/fission"
)
@@ -35,15 +34,16 @@ func panicIf(err error) {
}
}
func functionTests(tprClient *rest.RESTClient) {
func functionTests(crdClient *rest.RESTClient) {
// sample function object
function := &Function{
TypeMeta: unversioned.TypeMeta{
TypeMeta: metav1.TypeMeta{
Kind: "Function",
APIVersion: "fission.io/v1",
},
Metadata: api.ObjectMeta{
Name: "hello",
Metadata: metav1.ObjectMeta{
Name: "hello",
Namespace: metav1.NamespaceDefault,
},
Spec: fission.FunctionSpec{
Package: fission.FunctionPackageRef{
@@ -60,7 +60,7 @@ func functionTests(tprClient *rest.RESTClient) {
}
// Test function CRUD
fi := MakeFunctionInterface(tprClient, api.NamespaceDefault)
fi := MakeFunctionInterface(crdClient, metav1.NamespaceDefault)
// cleanup from old crashed tests, ignore errors
fi.Delete(function.Metadata.Name, nil)
@@ -82,6 +82,7 @@ func functionTests(tprClient *rest.RESTClient) {
log.Printf("f.Metadata = %#v", f.Metadata)
// update
function.Metadata.ResourceVersion = f.Metadata.ResourceVersion
function.Spec.Environment.Name = "yyy"
f, err = fi.Update(function)
panicIf(err)
@@ -89,12 +90,12 @@ func functionTests(tprClient *rest.RESTClient) {
log.Printf("f.Metadata = %#v", f.Metadata)
// list
fl, err := fi.List(api.ListOptions{})
fl, err := fi.List(metav1.ListOptions{})
panicIf(err)
if len(fl.Items) != 1 {
log.Panicf("wrong count from list: %v", fl)
log.Panicf("wrong count from function list: %v", len(fl.Items))
}
if fl.Items[0].Spec.Environment.Name != function.Spec.Environment.Name {
if fl.Items[0].Spec.Environment.Name != f.Spec.Environment.Name {
log.Panicf("bad object from list: %v", fl.Items[0])
}
@@ -103,10 +104,11 @@ func functionTests(tprClient *rest.RESTClient) {
panicIf(err)
// start a watch
wi, err := fi.Watch(api.ListOptions{})
wi, err := fi.Watch(metav1.ListOptions{})
panicIf(err)
start := time.Now()
function.Metadata.ResourceVersion = ""
f, err = fi.Create(function)
panicIf(err)
defer fi.Delete(f.Metadata.Name, nil)
@@ -132,15 +134,16 @@ func functionTests(tprClient *rest.RESTClient) {
}
func environmentTests(tprClient *rest.RESTClient) {
func environmentTests(crdClient *rest.RESTClient) {
// sample environment object
environment := &Environment{
TypeMeta: unversioned.TypeMeta{
TypeMeta: metav1.TypeMeta{
Kind: "Environment",
APIVersion: "fission.io/v1",
},
Metadata: api.ObjectMeta{
Name: "hello",
Metadata: metav1.ObjectMeta{
Name: "hello",
Namespace: metav1.NamespaceDefault,
},
Spec: fission.EnvironmentSpec{
Runtime: fission.Runtime{
@@ -154,7 +157,7 @@ func environmentTests(tprClient *rest.RESTClient) {
}
// Test environment CRUD
ei := MakeEnvironmentInterface(tprClient, api.NamespaceDefault)
ei := MakeEnvironmentInterface(crdClient, metav1.NamespaceDefault)
// cleanup from old crashed tests, ignore errors
ei.Delete(environment.Metadata.Name, nil)
@@ -174,17 +177,18 @@ func environmentTests(tprClient *rest.RESTClient) {
}
// update
environment.Metadata.ResourceVersion = e.Metadata.ResourceVersion
environment.Spec.Runtime.Image = "www"
e, err = ei.Update(environment)
panicIf(err)
// list
el, err := ei.List(api.ListOptions{})
el, err := ei.List(metav1.ListOptions{})
panicIf(err)
if len(el.Items) != 1 {
log.Panicf("wrong count from list: %v", len(el.Items))
log.Panicf("wrong count from environment list: %v", len(el.Items))
}
if el.Items[0].Spec.Runtime.Image != environment.Spec.Runtime.Image {
if el.Items[0].Spec.Runtime.Image != e.Spec.Runtime.Image {
log.Panicf("bad object from list: %v", el.Items[0])
}
@@ -193,10 +197,11 @@ func environmentTests(tprClient *rest.RESTClient) {
panicIf(err)
// start a watch
wi, err := ei.Watch(api.ListOptions{})
wi, err := ei.Watch(metav1.ListOptions{})
panicIf(err)
start := time.Now()
environment.Metadata.ResourceVersion = ""
e, err = ei.Create(environment)
panicIf(err)
defer ei.Delete(e.Metadata.Name, nil)
@@ -222,15 +227,16 @@ func environmentTests(tprClient *rest.RESTClient) {
}
func httpTriggerTests(tprClient *rest.RESTClient) {
func httpTriggerTests(crdClient *rest.RESTClient) {
// sample httpTrigger object
httpTrigger := &Httptrigger{
TypeMeta: unversioned.TypeMeta{
Kind: "Httptrigger",
httpTrigger := &HTTPTrigger{
TypeMeta: metav1.TypeMeta{
Kind: "HTTPTrigger",
APIVersion: "fission.io/v1",
},
Metadata: api.ObjectMeta{
Name: "hello",
Metadata: metav1.ObjectMeta{
Name: "hello",
Namespace: metav1.NamespaceDefault,
},
Spec: fission.HTTPTriggerSpec{
RelativeURL: "/hi",
@@ -243,7 +249,7 @@ func httpTriggerTests(tprClient *rest.RESTClient) {
}
// Test httpTrigger CRUD
ei := MakeHttptriggerInterface(tprClient, api.NamespaceDefault)
ei := MakeHTTPTriggerInterface(crdClient, metav1.NamespaceDefault)
// cleanup from old crashed tests, ignore errors
ei.Delete(httpTrigger.Metadata.Name, nil)
@@ -263,17 +269,18 @@ func httpTriggerTests(tprClient *rest.RESTClient) {
}
// update
httpTrigger.Metadata.ResourceVersion = e.Metadata.ResourceVersion
httpTrigger.Spec.Method = "POST"
e, err = ei.Update(httpTrigger)
panicIf(err)
// list
el, err := ei.List(api.ListOptions{})
el, err := ei.List(metav1.ListOptions{})
panicIf(err)
if len(el.Items) != 1 {
log.Panicf("wrong count from list: %v", el)
log.Panicf("wrong count from http trigger list: %v", len(el.Items))
}
if el.Items[0].Spec.Method != httpTrigger.Spec.Method {
if el.Items[0].Spec.Method != e.Spec.Method {
log.Panicf("bad object from list: %v", el.Items[0])
}
@@ -282,10 +289,11 @@ func httpTriggerTests(tprClient *rest.RESTClient) {
panicIf(err)
// start a watch
wi, err := ei.Watch(api.ListOptions{})
wi, err := ei.Watch(metav1.ListOptions{})
panicIf(err)
start := time.Now()
httpTrigger.Metadata.ResourceVersion = ""
e, err = ei.Create(httpTrigger)
panicIf(err)
defer ei.Delete(e.Metadata.Name, nil)
@@ -298,9 +306,9 @@ func httpTriggerTests(tprClient *rest.RESTClient) {
log.Panicf("Didn't get watch event")
}
case ev := <-wi.ResultChan():
obj, ok := ev.Object.(*Httptrigger)
obj, ok := ev.Object.(*HTTPTrigger)
if !ok {
log.Panicf("Can't cast to Httptrigger")
log.Panicf("Can't cast to HTTPTrigger")
}
if obj.Spec.Method != httpTrigger.Spec.Method {
log.Panicf("Bad object from watch: %#v", obj)
@@ -311,15 +319,16 @@ func httpTriggerTests(tprClient *rest.RESTClient) {
}
func kubernetesWatchTriggerTests(tprClient *rest.RESTClient) {
func kubernetesWatchTriggerTests(crdClient *rest.RESTClient) {
// sample kubernetesWatchTrigger object
kubernetesWatchTrigger := &Kuberneteswatchtrigger{
TypeMeta: unversioned.TypeMeta{
Kind: "Kuberneteswatchtrigger",
kubernetesWatchTrigger := &KubernetesWatchTrigger{
TypeMeta: metav1.TypeMeta{
Kind: "KubernetesWatchTrigger",
APIVersion: "fission.io/v1",
},
Metadata: api.ObjectMeta{
Name: "hello",
Metadata: metav1.ObjectMeta{
Name: "hello",
Namespace: metav1.NamespaceDefault,
},
Spec: fission.KubernetesWatchTriggerSpec{
Namespace: "foo",
@@ -335,7 +344,7 @@ func kubernetesWatchTriggerTests(tprClient *rest.RESTClient) {
}
// Test kubernetesWatchTrigger CRUD
ei := MakeKuberneteswatchtriggerInterface(tprClient, api.NamespaceDefault)
ei := MakeKubernetesWatchTriggerInterface(crdClient, metav1.NamespaceDefault)
// cleanup from old crashed tests, ignore errors
ei.Delete(kubernetesWatchTrigger.Metadata.Name, nil)
@@ -355,17 +364,18 @@ func kubernetesWatchTriggerTests(tprClient *rest.RESTClient) {
}
// update
kubernetesWatchTrigger.Metadata.ResourceVersion = e.Metadata.ResourceVersion
kubernetesWatchTrigger.Spec.Type = "service"
e, err = ei.Update(kubernetesWatchTrigger)
panicIf(err)
// list
el, err := ei.List(api.ListOptions{})
el, err := ei.List(metav1.ListOptions{})
panicIf(err)
if len(el.Items) != 1 {
log.Panicf("wrong count from list: %v", el)
log.Panicf("wrong count from kubeWatcher list: %v", len(el.Items))
}
if el.Items[0].Spec.Type != kubernetesWatchTrigger.Spec.Type {
if el.Items[0].Spec.Type != e.Spec.Type {
log.Panicf("bad object from list: %v", el.Items[0])
}
@@ -374,10 +384,11 @@ func kubernetesWatchTriggerTests(tprClient *rest.RESTClient) {
panicIf(err)
// start a watch
wi, err := ei.Watch(api.ListOptions{})
wi, err := ei.Watch(metav1.ListOptions{})
panicIf(err)
start := time.Now()
kubernetesWatchTrigger.Metadata.ResourceVersion = ""
e, err = ei.Create(kubernetesWatchTrigger)
panicIf(err)
defer ei.Delete(e.Metadata.Name, nil)
@@ -390,9 +401,9 @@ func kubernetesWatchTriggerTests(tprClient *rest.RESTClient) {
log.Panicf("Didn't get watch event")
}
case ev := <-wi.ResultChan():
obj, ok := ev.Object.(*Kuberneteswatchtrigger)
obj, ok := ev.Object.(*KubernetesWatchTrigger)
if !ok {
log.Panicf("Can't cast to Kuberneteswatchtrigger")
log.Panicf("Can't cast to KubernetesWatchTrigger")
}
if obj.Spec.Type != kubernetesWatchTrigger.Spec.Type {
log.Panicf("Bad object from watch: %#v", obj)
@@ -403,7 +414,7 @@ func kubernetesWatchTriggerTests(tprClient *rest.RESTClient) {
}
func TestTpr(t *testing.T) {
func TestCrd(t *testing.T) {
// skip test if no cluster available for testing
kubeconfig := os.Getenv("KUBECONFIG")
if len(kubeconfig) == 0 {
@@ -413,22 +424,22 @@ func TestTpr(t *testing.T) {
// Create the client config. Needs the KUBECONFIG env var to
// point at a valid kubeconfig.
config, clientset, err := GetKubernetesClient()
config, _, apiExtClient, err := GetKubernetesClient()
panicIf(err)
// init our types
err = EnsureFissionTPRs(clientset)
err = EnsureFissionCRDs(apiExtClient)
panicIf(err)
// rest client with knowledge about our tpr types
tprClient, err := GetTprClient(config)
// rest client with knowledge about our crd types
crdClient, err := GetCrdClient(config)
panicIf(err)
err = waitForTPRs(tprClient)
err = waitForCRDs(crdClient)
panicIf(err)
functionTests(tprClient)
environmentTests(tprClient)
httpTriggerTests(tprClient)
kubernetesWatchTriggerTests(tprClient)
functionTests(crdClient)
environmentTests(crdClient)
httpTriggerTests(crdClient)
kubernetesWatchTriggerTests(crdClient)
}
+15 -14
View File
@@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
@@ -27,9 +28,9 @@ type (
Create(*Environment) (*Environment, error)
Get(name string) (*Environment, error)
Update(*Environment) (*Environment, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*EnvironmentList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*EnvironmentList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
environmentClient struct {
@@ -38,9 +39,9 @@ type (
}
)
func MakeEnvironmentInterface(tprClient *rest.RESTClient, namespace string) EnvironmentInterface {
func MakeEnvironmentInterface(crdClient *rest.RESTClient, namespace string) EnvironmentInterface {
return &environmentClient{
client: tprClient,
client: crdClient,
namespace: namespace,
}
}
@@ -85,7 +86,7 @@ func (ec *environmentClient) Update(e *Environment) (*Environment, error) {
return &result, nil
}
func (ec *environmentClient) Delete(name string, opts *api.DeleteOptions) error {
func (ec *environmentClient) Delete(name string, opts *metav1.DeleteOptions) error {
return ec.client.Delete().
Namespace(ec.namespace).
Resource("environments").
@@ -95,12 +96,12 @@ func (ec *environmentClient) Delete(name string, opts *api.DeleteOptions) error
Error()
}
func (ec *environmentClient) List(opts api.ListOptions) (*EnvironmentList, error) {
func (ec *environmentClient) List(opts metav1.ListOptions) (*EnvironmentList, error) {
var result EnvironmentList
err := ec.client.Get().
Namespace(ec.namespace).
Resource("environments").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (ec *environmentClient) List(opts api.ListOptions) (*EnvironmentList, error
return &result, nil
}
func (ec *environmentClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (ec *environmentClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return ec.client.Get().
Prefix("watch").
Namespace(ec.namespace).
Resource("environments").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
+15 -14
View File
@@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
@@ -27,9 +28,9 @@ type (
Create(*Function) (*Function, error)
Get(name string) (*Function, error)
Update(*Function) (*Function, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*FunctionList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*FunctionList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
functionClient struct {
@@ -38,9 +39,9 @@ type (
}
)
func MakeFunctionInterface(tprClient *rest.RESTClient, namespace string) FunctionInterface {
func MakeFunctionInterface(crdClient *rest.RESTClient, namespace string) FunctionInterface {
return &functionClient{
client: tprClient,
client: crdClient,
namespace: namespace,
}
}
@@ -85,7 +86,7 @@ func (fc *functionClient) Update(f *Function) (*Function, error) {
return &result, nil
}
func (fc *functionClient) Delete(name string, opts *api.DeleteOptions) error {
func (fc *functionClient) Delete(name string, opts *metav1.DeleteOptions) error {
return fc.client.Delete().
Namespace(fc.namespace).
Resource("functions").
@@ -95,12 +96,12 @@ func (fc *functionClient) Delete(name string, opts *api.DeleteOptions) error {
Error()
}
func (fc *functionClient) List(opts api.ListOptions) (*FunctionList, error) {
func (fc *functionClient) List(opts metav1.ListOptions) (*FunctionList, error) {
var result FunctionList
err := fc.client.Get().
Namespace(fc.namespace).
Resource("functions").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (fc *functionClient) List(opts api.ListOptions) (*FunctionList, error) {
return &result, nil
}
func (fc *functionClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (fc *functionClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return fc.client.Get().
Prefix("watch").
Namespace(fc.namespace).
Resource("functions").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
+26 -25
View File
@@ -14,22 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
HttptriggerInterface interface {
Create(*Httptrigger) (*Httptrigger, error)
Get(name string) (*Httptrigger, error)
Update(*Httptrigger) (*Httptrigger, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*HttptriggerList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
HTTPTriggerInterface interface {
Create(*HTTPTrigger) (*HTTPTrigger, error)
Get(name string) (*HTTPTrigger, error)
Update(*HTTPTrigger) (*HTTPTrigger, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*HTTPTriggerList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
httpTriggerClient struct {
@@ -38,15 +39,15 @@ type (
}
)
func MakeHttptriggerInterface(tprClient *rest.RESTClient, namespace string) HttptriggerInterface {
func MakeHTTPTriggerInterface(crdClient *rest.RESTClient, namespace string) HTTPTriggerInterface {
return &httpTriggerClient{
client: tprClient,
client: crdClient,
namespace: namespace,
}
}
func (c *httpTriggerClient) Create(obj *Httptrigger) (*Httptrigger, error) {
var result Httptrigger
func (c *httpTriggerClient) Create(obj *HTTPTrigger) (*HTTPTrigger, error) {
var result HTTPTrigger
err := c.client.Post().
Resource("httptriggers").
Namespace(c.namespace).
@@ -58,8 +59,8 @@ func (c *httpTriggerClient) Create(obj *Httptrigger) (*Httptrigger, error) {
return &result, nil
}
func (c *httpTriggerClient) Get(name string) (*Httptrigger, error) {
var result Httptrigger
func (c *httpTriggerClient) Get(name string) (*HTTPTrigger, error) {
var result HTTPTrigger
err := c.client.Get().
Resource("httptriggers").
Namespace(c.namespace).
@@ -71,8 +72,8 @@ func (c *httpTriggerClient) Get(name string) (*Httptrigger, error) {
return &result, nil
}
func (c *httpTriggerClient) Update(obj *Httptrigger) (*Httptrigger, error) {
var result Httptrigger
func (c *httpTriggerClient) Update(obj *HTTPTrigger) (*HTTPTrigger, error) {
var result HTTPTrigger
err := c.client.Put().
Resource("httptriggers").
Namespace(c.namespace).
@@ -85,7 +86,7 @@ func (c *httpTriggerClient) Update(obj *Httptrigger) (*Httptrigger, error) {
return &result, nil
}
func (c *httpTriggerClient) Delete(name string, opts *api.DeleteOptions) error {
func (c *httpTriggerClient) Delete(name string, opts *metav1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.namespace).
Resource("httptriggers").
@@ -95,12 +96,12 @@ func (c *httpTriggerClient) Delete(name string, opts *api.DeleteOptions) error {
Error()
}
func (c *httpTriggerClient) List(opts api.ListOptions) (*HttptriggerList, error) {
var result HttptriggerList
func (c *httpTriggerClient) List(opts metav1.ListOptions) (*HTTPTriggerList, error) {
var result HTTPTriggerList
err := c.client.Get().
Namespace(c.namespace).
Resource("httptriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (c *httpTriggerClient) List(opts api.ListOptions) (*HttptriggerList, error)
return &result, nil
}
func (c *httpTriggerClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (c *httpTriggerClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Namespace(c.namespace).
Resource("httptriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
+3 -3
View File
@@ -14,12 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"fmt"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Given metadata, create a key that uniquely identifies the contents
@@ -28,6 +28,6 @@ import (
// content. (ResourceVersion may also update on status updates, so
// this will result in some unnecessary cache misses. That should be
// ok.)
func CacheKey(metadata *api.ObjectMeta) string {
func CacheKey(metadata *metav1.ObjectMeta) string {
return fmt.Sprintf("%v_%v", metadata.UID, metadata.ResourceVersion)
}
@@ -14,22 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
KuberneteswatchtriggerInterface interface {
Create(*Kuberneteswatchtrigger) (*Kuberneteswatchtrigger, error)
Get(name string) (*Kuberneteswatchtrigger, error)
Update(*Kuberneteswatchtrigger) (*Kuberneteswatchtrigger, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*KuberneteswatchtriggerList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
KubernetesWatchTriggerInterface interface {
Create(*KubernetesWatchTrigger) (*KubernetesWatchTrigger, error)
Get(name string) (*KubernetesWatchTrigger, error)
Update(*KubernetesWatchTrigger) (*KubernetesWatchTrigger, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*KubernetesWatchTriggerList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
kubernetesWatchTriggerClient struct {
@@ -38,15 +39,15 @@ type (
}
)
func MakeKuberneteswatchtriggerInterface(tprClient *rest.RESTClient, namespace string) KuberneteswatchtriggerInterface {
func MakeKubernetesWatchTriggerInterface(crdClient *rest.RESTClient, namespace string) KubernetesWatchTriggerInterface {
return &kubernetesWatchTriggerClient{
client: tprClient,
client: crdClient,
namespace: namespace,
}
}
func (c *kubernetesWatchTriggerClient) Create(obj *Kuberneteswatchtrigger) (*Kuberneteswatchtrigger, error) {
var result Kuberneteswatchtrigger
func (c *kubernetesWatchTriggerClient) Create(obj *KubernetesWatchTrigger) (*KubernetesWatchTrigger, error) {
var result KubernetesWatchTrigger
err := c.client.Post().
Resource("kuberneteswatchtriggers").
Namespace(c.namespace).
@@ -58,8 +59,8 @@ func (c *kubernetesWatchTriggerClient) Create(obj *Kuberneteswatchtrigger) (*Kub
return &result, nil
}
func (c *kubernetesWatchTriggerClient) Get(name string) (*Kuberneteswatchtrigger, error) {
var result Kuberneteswatchtrigger
func (c *kubernetesWatchTriggerClient) Get(name string) (*KubernetesWatchTrigger, error) {
var result KubernetesWatchTrigger
err := c.client.Get().
Resource("kuberneteswatchtriggers").
Namespace(c.namespace).
@@ -71,8 +72,8 @@ func (c *kubernetesWatchTriggerClient) Get(name string) (*Kuberneteswatchtrigger
return &result, nil
}
func (c *kubernetesWatchTriggerClient) Update(obj *Kuberneteswatchtrigger) (*Kuberneteswatchtrigger, error) {
var result Kuberneteswatchtrigger
func (c *kubernetesWatchTriggerClient) Update(obj *KubernetesWatchTrigger) (*KubernetesWatchTrigger, error) {
var result KubernetesWatchTrigger
err := c.client.Put().
Resource("kuberneteswatchtriggers").
Namespace(c.namespace).
@@ -85,7 +86,7 @@ func (c *kubernetesWatchTriggerClient) Update(obj *Kuberneteswatchtrigger) (*Kub
return &result, nil
}
func (c *kubernetesWatchTriggerClient) Delete(name string, opts *api.DeleteOptions) error {
func (c *kubernetesWatchTriggerClient) Delete(name string, opts *metav1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.namespace).
Resource("kuberneteswatchtriggers").
@@ -95,12 +96,12 @@ func (c *kubernetesWatchTriggerClient) Delete(name string, opts *api.DeleteOptio
Error()
}
func (c *kubernetesWatchTriggerClient) List(opts api.ListOptions) (*KuberneteswatchtriggerList, error) {
var result KuberneteswatchtriggerList
func (c *kubernetesWatchTriggerClient) List(opts metav1.ListOptions) (*KubernetesWatchTriggerList, error) {
var result KubernetesWatchTriggerList
err := c.client.Get().
Namespace(c.namespace).
Resource("kuberneteswatchtriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (c *kubernetesWatchTriggerClient) List(opts api.ListOptions) (*Kuberneteswa
return &result, nil
}
func (c *kubernetesWatchTriggerClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (c *kubernetesWatchTriggerClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Namespace(c.namespace).
Resource("kuberneteswatchtriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
@@ -14,39 +14,40 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
MessagequeuetriggerInterface interface {
Create(*Messagequeuetrigger) (*Messagequeuetrigger, error)
Get(name string) (*Messagequeuetrigger, error)
Update(*Messagequeuetrigger) (*Messagequeuetrigger, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*MessagequeuetriggerList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
MessageQueueTriggerInterface interface {
Create(*MessageQueueTrigger) (*MessageQueueTrigger, error)
Get(name string) (*MessageQueueTrigger, error)
Update(*MessageQueueTrigger) (*MessageQueueTrigger, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*MessageQueueTriggerList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
messagequeuetriggerClient struct {
messageQueueTriggerClient struct {
client *rest.RESTClient
namespace string
}
)
func MakeMessagequeuetriggerInterface(tprClient *rest.RESTClient, namespace string) MessagequeuetriggerInterface {
return &messagequeuetriggerClient{
client: tprClient,
func MakeMessageQueueTriggerInterface(crdClient *rest.RESTClient, namespace string) MessageQueueTriggerInterface {
return &messageQueueTriggerClient{
client: crdClient,
namespace: namespace,
}
}
func (fc *messagequeuetriggerClient) Create(f *Messagequeuetrigger) (*Messagequeuetrigger, error) {
var result Messagequeuetrigger
func (fc *messageQueueTriggerClient) Create(f *MessageQueueTrigger) (*MessageQueueTrigger, error) {
var result MessageQueueTrigger
err := fc.client.Post().
Resource("messagequeuetriggers").
Namespace(fc.namespace).
@@ -58,8 +59,8 @@ func (fc *messagequeuetriggerClient) Create(f *Messagequeuetrigger) (*Messageque
return &result, nil
}
func (fc *messagequeuetriggerClient) Get(name string) (*Messagequeuetrigger, error) {
var result Messagequeuetrigger
func (fc *messageQueueTriggerClient) Get(name string) (*MessageQueueTrigger, error) {
var result MessageQueueTrigger
err := fc.client.Get().
Resource("messagequeuetriggers").
Namespace(fc.namespace).
@@ -71,8 +72,8 @@ func (fc *messagequeuetriggerClient) Get(name string) (*Messagequeuetrigger, err
return &result, nil
}
func (fc *messagequeuetriggerClient) Update(f *Messagequeuetrigger) (*Messagequeuetrigger, error) {
var result Messagequeuetrigger
func (fc *messageQueueTriggerClient) Update(f *MessageQueueTrigger) (*MessageQueueTrigger, error) {
var result MessageQueueTrigger
err := fc.client.Put().
Resource("messagequeuetriggers").
Namespace(fc.namespace).
@@ -85,7 +86,7 @@ func (fc *messagequeuetriggerClient) Update(f *Messagequeuetrigger) (*Messageque
return &result, nil
}
func (fc *messagequeuetriggerClient) Delete(name string, opts *api.DeleteOptions) error {
func (fc *messageQueueTriggerClient) Delete(name string, opts *metav1.DeleteOptions) error {
return fc.client.Delete().
Namespace(fc.namespace).
Resource("messagequeuetriggers").
@@ -95,12 +96,12 @@ func (fc *messagequeuetriggerClient) Delete(name string, opts *api.DeleteOptions
Error()
}
func (fc *messagequeuetriggerClient) List(opts api.ListOptions) (*MessagequeuetriggerList, error) {
var result MessagequeuetriggerList
func (fc *messageQueueTriggerClient) List(opts metav1.ListOptions) (*MessageQueueTriggerList, error) {
var result MessageQueueTriggerList
err := fc.client.Get().
Namespace(fc.namespace).
Resource("messagequeuetriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (fc *messagequeuetriggerClient) List(opts api.ListOptions) (*Messagequeuetr
return &result, nil
}
func (fc *messagequeuetriggerClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (fc *messageQueueTriggerClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return fc.client.Get().
Prefix("watch").
Namespace(fc.namespace).
Resource("messagequeuetriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
+15 -14
View File
@@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
@@ -27,9 +28,9 @@ type (
Create(*Package) (*Package, error)
Get(name string) (*Package, error)
Update(*Package) (*Package, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*PackageList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*PackageList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
packageClient struct {
@@ -38,9 +39,9 @@ type (
}
)
func MakePackageInterface(tprClient *rest.RESTClient, namespace string) PackageInterface {
func MakePackageInterface(crdClient *rest.RESTClient, namespace string) PackageInterface {
return &packageClient{
client: tprClient,
client: crdClient,
namespace: namespace,
}
}
@@ -85,7 +86,7 @@ func (c *packageClient) Update(f *Package) (*Package, error) {
return &result, nil
}
func (c *packageClient) Delete(name string, opts *api.DeleteOptions) error {
func (c *packageClient) Delete(name string, opts *metav1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.namespace).
Resource("packages").
@@ -95,12 +96,12 @@ func (c *packageClient) Delete(name string, opts *api.DeleteOptions) error {
Error()
}
func (c *packageClient) List(opts api.ListOptions) (*PackageList, error) {
func (c *packageClient) List(opts metav1.ListOptions) (*PackageList, error) {
var result PackageList
err := c.client.Get().
Namespace(c.namespace).
Resource("packages").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (c *packageClient) List(opts api.ListOptions) (*PackageList, error) {
return &result, nil
}
func (c *packageClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (c *packageClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return c.client.Get().
Prefix("watch").
Namespace(c.namespace).
Resource("packages").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
+28 -27
View File
@@ -14,39 +14,40 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tpr
package crd
import (
"k8s.io/client-go/1.5/pkg/api"
"k8s.io/client-go/1.5/pkg/watch"
"k8s.io/client-go/1.5/rest"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
)
type (
TimetriggerInterface interface {
Create(*Timetrigger) (*Timetrigger, error)
Get(name string) (*Timetrigger, error)
Update(*Timetrigger) (*Timetrigger, error)
Delete(name string, options *api.DeleteOptions) error
List(opts api.ListOptions) (*TimetriggerList, error)
Watch(opts api.ListOptions) (watch.Interface, error)
TimeTriggerInterface interface {
Create(*TimeTrigger) (*TimeTrigger, error)
Get(name string) (*TimeTrigger, error)
Update(*TimeTrigger) (*TimeTrigger, error)
Delete(name string, options *metav1.DeleteOptions) error
List(opts metav1.ListOptions) (*TimeTriggerList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
}
timetriggerClient struct {
timeTriggerClient struct {
client *rest.RESTClient
namespace string
}
)
func MakeTimetriggerInterface(tprClient *rest.RESTClient, namespace string) TimetriggerInterface {
return &timetriggerClient{
client: tprClient,
func MakeTimeTriggerInterface(crdClient *rest.RESTClient, namespace string) TimeTriggerInterface {
return &timeTriggerClient{
client: crdClient,
namespace: namespace,
}
}
func (fc *timetriggerClient) Create(f *Timetrigger) (*Timetrigger, error) {
var result Timetrigger
func (fc *timeTriggerClient) Create(f *TimeTrigger) (*TimeTrigger, error) {
var result TimeTrigger
err := fc.client.Post().
Resource("timetriggers").
Namespace(fc.namespace).
@@ -58,8 +59,8 @@ func (fc *timetriggerClient) Create(f *Timetrigger) (*Timetrigger, error) {
return &result, nil
}
func (fc *timetriggerClient) Get(name string) (*Timetrigger, error) {
var result Timetrigger
func (fc *timeTriggerClient) Get(name string) (*TimeTrigger, error) {
var result TimeTrigger
err := fc.client.Get().
Resource("timetriggers").
Namespace(fc.namespace).
@@ -71,8 +72,8 @@ func (fc *timetriggerClient) Get(name string) (*Timetrigger, error) {
return &result, nil
}
func (fc *timetriggerClient) Update(f *Timetrigger) (*Timetrigger, error) {
var result Timetrigger
func (fc *timeTriggerClient) Update(f *TimeTrigger) (*TimeTrigger, error) {
var result TimeTrigger
err := fc.client.Put().
Resource("timetriggers").
Namespace(fc.namespace).
@@ -85,7 +86,7 @@ func (fc *timetriggerClient) Update(f *Timetrigger) (*Timetrigger, error) {
return &result, nil
}
func (fc *timetriggerClient) Delete(name string, opts *api.DeleteOptions) error {
func (fc *timeTriggerClient) Delete(name string, opts *metav1.DeleteOptions) error {
return fc.client.Delete().
Namespace(fc.namespace).
Resource("timetriggers").
@@ -95,12 +96,12 @@ func (fc *timetriggerClient) Delete(name string, opts *api.DeleteOptions) error
Error()
}
func (fc *timetriggerClient) List(opts api.ListOptions) (*TimetriggerList, error) {
var result TimetriggerList
func (fc *timeTriggerClient) List(opts metav1.ListOptions) (*TimeTriggerList, error) {
var result TimeTriggerList
err := fc.client.Get().
Namespace(fc.namespace).
Resource("timetriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Do().
Into(&result)
if err != nil {
@@ -109,11 +110,11 @@ func (fc *timetriggerClient) List(opts api.ListOptions) (*TimetriggerList, error
return &result, nil
}
func (fc *timetriggerClient) Watch(opts api.ListOptions) (watch.Interface, error) {
func (fc *timeTriggerClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return fc.client.Get().
Prefix("watch").
Namespace(fc.namespace).
Resource("timetriggers").
VersionedParams(&opts, api.ParameterCodec).
VersionedParams(&opts, scheme.ParameterCodec).
Watch()
}
+228
View File
@@ -0,0 +1,228 @@
/*
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 crd
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/fission/fission"
)
//
// To add a Fission CRD type:
// 1. Create a "spec" type, for everything in the type except metadata
// 2. Create the type with metadata + the spec
// 3. Create a list type (for example see FunctionList and Function, below)
// 4. Add methods at the bottom of this file for satisfying Object and List interfaces
// 5. Add the type to configureClient in client.go
// 6. Add the type to EnsureFissionCRDs in crd.go
// 7. Add tests to crd_test.go
// 8. Add a CRUD Interface type (analogous to FunctionInterface in function.go)
// 9. Add a getter method for your interface type to FissionClient in client.go
//
type (
// Packages. Think of these as function-level images.
Package struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.PackageSpec `json:"spec"`
Status fission.PackageStatus `json:"status"`
}
PackageList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []Package `json:"items"`
}
// Functions.
Function struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.FunctionSpec `json:"spec"`
}
FunctionList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []Function `json:"items"`
}
// Environments.
Environment struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.EnvironmentSpec `json:"spec"`
}
EnvironmentList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []Environment `json:"items"`
}
HTTPTrigger struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.HTTPTriggerSpec `json:"spec"`
}
HTTPTriggerList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []HTTPTrigger `json:"items"`
}
// Kubernetes Watches as triggers
KubernetesWatchTrigger struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.KubernetesWatchTriggerSpec `json:"spec"`
}
KubernetesWatchTriggerList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []KubernetesWatchTrigger `json:"items"`
}
// Time triggers
TimeTrigger struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.TimeTriggerSpec `json:"spec"`
}
TimeTriggerList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []TimeTrigger `json:"items"`
}
// Message Queue triggers
MessageQueueTrigger struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ObjectMeta `json:"metadata"`
Spec fission.MessageQueueTriggerSpec `json:"spec"`
}
MessageQueueTriggerList struct {
metav1.TypeMeta `json:",inline"`
Metadata metav1.ListMeta `json:"metadata"`
Items []MessageQueueTrigger `json:"items"`
}
)
// Each CRD type needs:
// GetObjectKind (to satisfy the Object interface)
//
// In addition, each singular CRD type needs:
// GetObjectMeta (to satisfy the ObjectMetaAccessor interface)
//
// And each list CRD type needs:
// GetListMeta (to satisfy the ListMetaAccessor interface)
func (f *Function) GetObjectKind() schema.ObjectKind {
return &f.TypeMeta
}
func (e *Environment) GetObjectKind() schema.ObjectKind {
return &e.TypeMeta
}
func (ht *HTTPTrigger) GetObjectKind() schema.ObjectKind {
return &ht.TypeMeta
}
func (w *KubernetesWatchTrigger) GetObjectKind() schema.ObjectKind {
return &w.TypeMeta
}
func (w *TimeTrigger) GetObjectKind() schema.ObjectKind {
return &w.TypeMeta
}
func (w *MessageQueueTrigger) GetObjectKind() schema.ObjectKind {
return &w.TypeMeta
}
func (w *Package) GetObjectKind() schema.ObjectKind {
return &w.TypeMeta
}
func (f *Function) GetObjectMeta() metav1.Object {
return &f.Metadata
}
func (e *Environment) GetObjectMeta() metav1.Object {
return &e.Metadata
}
func (ht *HTTPTrigger) GetObjectMeta() metav1.Object {
return &ht.Metadata
}
func (w *KubernetesWatchTrigger) GetObjectMeta() metav1.Object {
return &w.Metadata
}
func (w *TimeTrigger) GetObjectMeta() metav1.Object {
return &w.Metadata
}
func (w *MessageQueueTrigger) GetObjectMeta() metav1.Object {
return &w.Metadata
}
func (w *Package) GetObjectMeta() metav1.Object {
return &w.Metadata
}
func (fl *FunctionList) GetObjectKind() schema.ObjectKind {
return &fl.TypeMeta
}
func (el *EnvironmentList) GetObjectKind() schema.ObjectKind {
return &el.TypeMeta
}
func (hl *HTTPTriggerList) GetObjectKind() schema.ObjectKind {
return &hl.TypeMeta
}
func (wl *KubernetesWatchTriggerList) GetObjectKind() schema.ObjectKind {
return &wl.TypeMeta
}
func (wl *TimeTriggerList) GetObjectKind() schema.ObjectKind {
return &wl.TypeMeta
}
func (wl *MessageQueueTriggerList) GetObjectKind() schema.ObjectKind {
return &wl.TypeMeta
}
func (wl *PackageList) GetObjectKind() schema.ObjectKind {
return &wl.TypeMeta
}
func (fl *FunctionList) GetListMeta() metav1.List {
return &fl.Metadata
}
func (el *EnvironmentList) GetListMeta() metav1.List {
return &el.Metadata
}
func (hl *HTTPTriggerList) GetListMeta() metav1.List {
return &hl.Metadata
}
func (wl *KubernetesWatchTriggerList) GetListMeta() metav1.List {
return &wl.Metadata
}
func (wl *TimeTriggerList) GetListMeta() metav1.List {
return &wl.Metadata
}
func (wl *MessageQueueTriggerList) GetListMeta() metav1.List {
return &wl.Metadata
}
func (wl *PackageList) GetListMeta() metav1.List {
return &wl.Metadata
}
+2 -22
View File
@@ -37,10 +37,6 @@ function maybe_first_prompt() {
fi
}
# After a `run` this variable will hold the stdout of the command that was run.
# If the command was interactive, this will likely be garbage.
#DEMO_RUN_STDOUT=""
function run() {
maybe_first_prompt
rate=25
@@ -52,27 +48,11 @@ function run() {
sleep 0.5
fi
$1
echo; echo -n ">"
echo
echo -n ">"
read -s
echo -e "\b "
# OFILE="$(mktemp -t $(basename $0).XXXXXX)"
# script -q -t0 "$OFILE" $1 # [removed -e,-c options -soam]
# r=$?
# read -d '' -t "${timeout}" -n 10000 # clear stdin
# prompt
# if [ -z "$DEMO_AUTO_RUN" ]; then
# read -s
# fi
# DEMO_RUN_STDOUT="$(tail -n +2 $OFILE | sed 's/\r//g')"
# return $r
}
function relative() {
for arg; do
echo "$(realpath $(dirname $(which $0)))/$arg" | sed "s|$(realpath $(pwd))|.|"
done
}
SSH_NODE=$(kubectl get nodes | tail -1 | cut -f1 -d' ')
#trap "echo" EXIT
+1 -1
View File
@@ -63,7 +63,7 @@ Move to the build directory inside the container and restore the packages:
```
cd /build
dotnet restore
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.
+5 -3
View File
@@ -1,4 +1,6 @@
#!/bin/sh
dotnet restore
dotnet publish -c Release -o out
docker build -t fission/dotnet20-env .
THIS_DIR=$(realpath $(dirname $0))
docker run -v $THIS_DIR:/proj microsoft/dotnet:2.0.0-sdk sh -c "cd /proj && ./project-build.sh"
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
dotnet restore fission-dotnet20.csproj
dotnet publish fission-dotnet20.csproj -c Release -o out
+31 -18
View File
@@ -5,12 +5,13 @@ import (
"encoding/json"
"io/ioutil"
"log"
"net"
"net/http"
//"time"
"net/url"
"time"
"github.com/fission/fission"
"github.com/fission/fission/environments/fetcher"
//"github.com/fission/fission/router"
)
type (
@@ -31,21 +32,35 @@ func (c *Client) Fetch(fr *fetcher.FetchRequest) error {
return err
}
// client := http.Client{
// Transport: router.MakeRetryingRoundTripper(10, 50*time.Millisecond),
// }
maxRetries := 20
var resp *http.Response
resp, err := http.Post(c.url, "application/json", bytes.NewReader(body))
if err != nil {
return err
}
defer resp.Body.Close()
for i := 0; i < maxRetries; i++ {
resp, err = http.Post(c.url, "application/json", bytes.NewReader(body))
if resp.StatusCode != 200 {
return fission.MakeErrorFromHTTP(resp)
if err == nil && resp.StatusCode == 200 {
defer resp.Body.Close()
return nil
}
// Only retry for the specific case of a connection error.
if urlErr, ok := err.(*url.Error); ok {
if netErr, ok := urlErr.Err.(*net.OpError); ok {
if netErr.Op == "dial" {
if i < maxRetries-1 {
time.Sleep(50 * time.Duration(2*i) * time.Millisecond)
continue
}
}
}
}
}
return nil
if err == nil {
err = fission.MakeErrorFromHTTP(resp)
}
log.Printf("Failed to fetch: %v", err)
return err
}
func (c *Client) Upload(fr *fetcher.UploadRequest) (*fetcher.UploadResponse, error) {
@@ -68,13 +83,11 @@ func (c *Client) Upload(fr *fetcher.UploadRequest) (*fetcher.UploadResponse, err
return nil, err
}
log.Printf("Received upload response: %v", string(rBody))
uploadReq := fetcher.UploadResponse{}
err = json.Unmarshal([]byte(rBody), &uploadReq)
uploadResp := fetcher.UploadResponse{}
err = json.Unmarshal([]byte(rBody), &uploadResp)
if err != nil {
return nil, err
}
return &uploadReq, nil
return &uploadResp, nil
}
+19 -20
View File
@@ -16,23 +16,22 @@ import (
"github.com/mholt/archiver"
"github.com/satori/go.uuid"
"k8s.io/client-go/1.5/kubernetes"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/crd"
storageSvcClient "github.com/fission/fission/storagesvc/client"
"github.com/fission/fission/tpr"
)
type (
FetchRequestType int
FetchRequest struct {
FetchType FetchRequestType `json:"fetchType"`
Package api.ObjectMeta `json:"package"`
Url string `json:"url"`
StorageSvcUrl string `json:"storagesvcurl"`
Filename string `json:"filename"`
FetchType FetchRequestType `json:"fetchType"`
Package metav1.ObjectMeta `json:"package"`
Url string `json:"url"`
StorageSvcUrl string `json:"storagesvcurl"`
Filename string `json:"filename"`
}
// UploadRequest send from builder manager describes which
@@ -51,8 +50,7 @@ type (
Fetcher struct {
sharedVolumePath string
fissionClient *tpr.FissionClient
kubeClient *kubernetes.Clientset
fissionClient *crd.FissionClient
}
)
@@ -63,14 +61,13 @@ const (
)
func MakeFetcher(sharedVolumePath string) *Fetcher {
fissionClient, kubeClient, err := tpr.MakeFissionClient()
fissionClient, _, _, err := crd.MakeFissionClient()
if err != nil {
return nil
}
return &Fetcher{
sharedVolumePath: sharedVolumePath,
fissionClient: fissionClient,
kubeClient: kubeClient,
}
}
@@ -81,12 +78,15 @@ func downloadUrl(url string, localPath string) error {
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
w, err := os.Create(localPath)
if err != nil {
return err
}
err = ioutil.WriteFile(localPath, body, 0600)
_, err = io.Copy(w, resp.Body)
if err != nil {
return err
}
err = os.Chmod(localPath, 0600)
if err != nil {
return err
}
@@ -155,13 +155,11 @@ func (fetcher *Fetcher) FetchHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), 400)
return
}
log.Printf("fetcher received fetch request: %v", req)
log.Printf("fetcher received fetch request and started downloading: %v", req)
tmpFile := req.Filename + ".tmp"
tmpPath := filepath.Join(fetcher.sharedVolumePath, tmpFile)
log.Printf("Start downloading...")
if req.FetchType == FETCH_URL {
// fetch the file and save it to the tmp path
err := downloadUrl(req.Url, tmpPath)
@@ -286,7 +284,7 @@ func (fetcher *Fetcher) UploadHandler(w http.ResponseWriter, r *http.Request) {
return
}
log.Println("Start uploading...")
log.Println("Starting upload...")
ssClient := storageSvcClient.MakeClient(req.StorageSvcUrl)
fileID, err := ssClient.Upload(dstFilepath, nil)
@@ -332,7 +330,8 @@ func (fetcher *Fetcher) rename(src string, dst string) error {
return nil
}
// archive is a function that zips directory into a zip file
// archive zips the contents of directory at src into a new zip file
// at dst (note that the contents are zipped, not the directory itself).
func (fetcher *Fetcher) archive(src string, dst string) error {
var files []string
target, err := os.Stat(src)
+3 -1
View File
@@ -1,4 +1,6 @@
FROM golang:1.8.1
ARG GO_VERSION=1.9.2
FROM golang:${GO_VERSION}
ENV GOPATH /usr
ENV APP ${GOPATH}/src/github.com/fission/fission/environments/go
+10 -1
View File
@@ -1,5 +1,14 @@
FROM golang:1.8.1
ARG BUILDER_IMAGE=fission/builder
ARG GO_VERSION=1.9.2
FROM ${BUILDER_IMAGE}
FROM golang:${GO_VERSION}
COPY --from=0 /builder /builder
ENV GOPATH /usr
RUN go get github.com/fission/fission
ADD build.sh /usr/local/bin/build
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
cd ${SRC_PKG}
go build -buildmode=plugin -i -o ${DEPLOY_PKG} .
-11
View File
@@ -1,11 +0,0 @@
#!/bin/sh
if [ $# -eq 0 ]
then
echo "No arguments, building current dir"
filename='.'
else
filename=$1
fi
docker run --rm -v $(pwd):/build -w /build fission/go-builder:1.8.1 go build -buildmode=plugin -o function.so $filename && echo "Compiled plugin: function.so. Use 'fission function create' to upload to fission."
+82 -5
View File
@@ -1,9 +1,12 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"plugin"
"github.com/fission/fission/environments/go/context"
@@ -13,14 +16,52 @@ const (
CODE_PATH = "/userfunc/user"
)
type (
FunctionLoadRequest struct {
// FilePath is an absolute filesystem path to the
// function. What exactly is stored here is
// env-specific. Optional.
FilePath string `json:"filepath"`
// FunctionName has an environment-specific meaning;
// usually, it defines a function within a module
// containing multiple functions. Optional; default is
// environment-specific.
FunctionName string `json:"functionName"`
// URL to expose this function at. Optional; defaults
// to "/".
URL string `json:"url"`
}
)
var userFunc http.HandlerFunc
func loadPlugin() http.HandlerFunc {
p, err := plugin.Open(CODE_PATH)
func loadPlugin(codePath, entrypoint string) http.HandlerFunc {
// if codepath's a directory, load the file inside it
info, err := os.Stat(codePath)
if err != nil {
panic(err)
}
sym, err := p.Lookup("Handler")
if info.IsDir() {
files, err := ioutil.ReadDir(codePath)
if err != nil {
panic(err)
}
if len(files) == 0 {
panic("No files to load")
}
fi := files[0]
codePath = filepath.Join(codePath, fi.Name())
}
fmt.Printf("loading plugin from %v\n", codePath)
p, err := plugin.Open(codePath)
if err != nil {
panic(err)
}
sym, err := p.Lookup(entrypoint)
if err != nil {
panic("Entry point not found")
}
@@ -44,7 +85,7 @@ func loadPlugin() http.HandlerFunc {
func specializeHandler(w http.ResponseWriter, r *http.Request) {
if userFunc != nil {
w.WriteHeader(400)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Not a generic container"))
return
}
@@ -61,12 +102,48 @@ func specializeHandler(w http.ResponseWriter, r *http.Request) {
}
fmt.Println("Specializing ...")
userFunc = loadPlugin()
userFunc = loadPlugin(CODE_PATH, "Handler")
fmt.Println("Done")
}
func specializeHandlerV2(w http.ResponseWriter, r *http.Request) {
if userFunc != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Not a generic container"))
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
var loadreq FunctionLoadRequest
err = json.Unmarshal(body, &loadreq)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
_, err = os.Stat(loadreq.FilePath)
if err != nil {
if os.IsNotExist(err) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(CODE_PATH + ": not found"))
return
} else {
panic(err)
}
}
fmt.Println("Specializing ...")
userFunc = loadPlugin(loadreq.FilePath, loadreq.FunctionName)
fmt.Println("Done")
}
func main() {
http.HandleFunc("/specialize", specializeHandler)
http.HandleFunc("/v2/specialize", specializeHandlerV2)
// Generic route -- all http requests go to the user function.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+14 -3
View File
@@ -1,7 +1,18 @@
# A docker image for the func container.
FROM node:8-onbuild
# default variant is the official alpine node image (much smaller than the standard image)
FROM node:8-alpine
ADD server.js /usr/src/app/server.js
ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
EXPOSE 8888
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN npm install && npm cache clean --force
COPY server.js /usr/src/app/server.js
CMD [ "npm", "start" ]
EXPOSE 8888
+18
View File
@@ -0,0 +1,18 @@
# A docker image for the func container.
# debian variant is the official standard node image (larger than the alpine image)
FROM node:8
ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN npm install && npm cache clean --force
COPY server.js /usr/src/app/server.js
CMD [ "npm", "start" ]
EXPOSE 8888
+14
View File
@@ -0,0 +1,14 @@
FROM alpine:3.5
RUN apk update
RUN apk add --no-cache python python-dev build-base py-pip
RUN pip install --upgrade pip
RUN rm -r /root/.cache
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["server.py"]
@@ -1,4 +1,5 @@
FROM alpine:3.5
ARG BUILDER_IMAGE=fission/builder:latest
FROM ${BUILDER_IMAGE}
RUN apk update
RUN apk add --no-cache python3 python3-dev build-base
@@ -6,6 +7,5 @@ RUN pip3 install --upgrade pip
RUN rm -r /root/.cache
ADD defaultBuildCmd /usr/local/bin/build
ADD builder /builder
EXPOSE 8001
@@ -24,12 +24,41 @@ 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)
handler = body['functionName']
# The value of "functionName" is consist of `<module-name>.<function-name>`.
moduleName, funcName = handler.split(".")
# check whether the destination is a directory or a file
if os.path.isdir(filepath):
# add package directory path into module search path
sys.path.append(filepath)
# find module from package path we append previously.
# Python will try to find module from the same name file under
# the package directory. If search is successful, the return
# value is a 3-element tuple; otherwise, an exception "ImportError"
# is raised.
# Second parameter of find_module enforces python to find same
# name module from the given list of directories to prevent name
# confliction with built-in modules.
f, path, desc = imp.find_module(moduleName, [filepath])
# load module
# Return module object is the load is successful; otherwise,
# an exception is raised.
try:
mod = imp.load_module(moduleName, f, path, desc)
finally:
if f:
f.close()
else:
# load source from destination python file
mod = imp.load_source(moduleName, filepath)
# load user function from module
userfunc = getattr(mod, funcName)
return ""
@app.route('/', methods=['GET', 'POST', 'PUT', 'HEAD', 'OPTIONS', 'DELETE'])
@@ -66,4 +95,4 @@ def setup_logger(loglevel):
#
setup_logger(logging.DEBUG)
app.logger.info("Starting server")
app.run(host='0.0.0.0', port='8888')
app.run(host='0.0.0.0', port=8888)
+27 -1
View File
@@ -2,12 +2,19 @@
This directory contains several examples to get you started using Node.js with Fission.
## Environment
Before running any of these functions, make sure you have created a `nodejs` Fission environment:
```
$ fission env create --name nodejs --image fission/node-env
```
Note: The default `fission/node-env` image is based on Alpine, which is much smaller than the main Debian Node image (65MB vs 680MB) while still being suitable for most use cases.
If you need to use the full Debian image use the `fission/node-env-debian` image instead.
See the [official Node docker hub repo](https://hub.docker.com/_/node/) for considerations
relating to this choice.
## Function signature
Every Node.js function has the same basic form:
@@ -75,7 +82,7 @@ This is a basic example of how you can easily use asynchronous requests in your
$ fission function create --name stock --env nodejs --code stock.js
# Map GET /stock to your new function
$ fission route create --method GET --url /stock --function stock
$ fission route create --method POST --url /stock --function stock
# Run the function.
$ curl -H "Content-Type: application/json" -X POST -d '{"symbol":"AAPL"}' http://$FISSION_ROUTER/stock
@@ -96,3 +103,22 @@ $ fission fn create --name kubeEventsSlack --env nodejs --code kubeEventsSlack.j
# Watch all services in the default namespace:
$ fission watch create --function kubeEventsSlack --type service --ns default
```
## weather.js
In this example, the Yahoo Weather API is used to current weather at a given location.
### Usage
```bash
# Upload your function code to fission
$ fission function create --name weather --env nodejs --code weather.js
# Map GET /stock to your new function
$ fission route create --method POST --url /weather --function weather
# Run the function.
$ curl -H "Content-Type: application/json" -X POST -d '{"location":"Sieteiglesias, Spain"}' http://$FISSION_ROUTER/weather
{"text":"It is 2 celsius degrees in Sieteiglesias, Spain and Mostly Clear"}
```
+40
View File
@@ -0,0 +1,40 @@
'use strict';
const rp = require('request-promise-native');
module.exports = async function (context) {
const stringBody = JSON.stringify(context.request.body);
const body = JSON.parse(stringBody);
const location = body.location;
if (!location) {
return {
status: 400,
body: {
text: 'You must provide a location.'
}
};
}
try {
const response = await rp(`https://query.yahooapis.com/v1/public/yql?q=select item.condition from weather.forecast where woeid in (select woeid from geo.places(1) where text="${location}") and u="c"&format=json`);
const condition = JSON.parse(response).query.results.channel.item.condition;
const text = condition.text;
const temperature = condition.temp;
return {
status: 200,
body: {
text: `It is ${temperature} celsius degrees in ${location} and ${text}`
},
headers: {
'Content-Type': 'application/json'
}
};
} catch (e) {
console.error(e);
return {
status: 500,
body: e
};
}
}
+62
View File
@@ -0,0 +1,62 @@
This is an example of creating a deployment package with multiple
files including some static data in text file.
### Create an environment
```
fission env create --name python --image fission/python-env:0.4.0rc --version 2
```
### Create a zip file with all your files
```
zip -jr multifile.zip *.py *.txt
```
### Create a function
Since there are multiple files, you have to specify an _entrypoint_ to
for the function. Its format is `<file name>.<function name>`. In our
example, that's `main.main`, to run function `main` in `main.py`.
```
fission function create --name multifile --env python --code multifile.zip --entrypoint main.main
```
### Test it
```
fission function test --name multifile
```
You should see the "Hello, world" message.
## Updating the function
### Edit a file
```
echo "I said hellooooo!" > message.txt
```
### Update the deployment package
```
zip -jr multifile.zip *.py *.txt
```
### Update the function
```
fission function update --name multifile --code multifile.zip
```
### Test it
```
fission function test --name multifile
```
You should now see your new, edited message.
+11
View File
@@ -0,0 +1,11 @@
from flask import current_app
import sys
import readfile
import os
def main():
current_app.logger.info("Hi")
current_dir = os.path.dirname(__file__)
return readfile.readFile(os.path.join(current_dir, "message.txt"))
+1
View File
@@ -0,0 +1 @@
Hello, world!
+3
View File
@@ -0,0 +1,3 @@
def readFile(name):
with open(name) as f:
return f.read()
+4
View File
@@ -0,0 +1,4 @@
def main():
# You can return any http status code you like, simply place a comma after
# your return statement, and typing in the status code.
return "Not Found\n", 404
+108
View File
@@ -0,0 +1,108 @@
/*
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 executor
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
)
func (executor *Executor) getServiceForFunctionApi(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request", 500)
return
}
// get function metadata
m := metav1.ObjectMeta{}
err = json.Unmarshal(body, &m)
if err != nil {
http.Error(w, "Failed to parse request", 400)
return
}
serviceName, err := executor.getServiceForFunction(&m)
if err != nil {
code, msg := fission.GetHTTPError(err)
log.Printf("Error: %v: %v", code, msg)
http.Error(w, msg, code)
return
}
w.Write([]byte(serviceName))
}
func (executor *Executor) getServiceForFunction(m *metav1.ObjectMeta) (string, error) {
// Check function -> svc cache
log.Printf("[%v] Checking for cached function service", m.Name)
fsvc, err := executor.fsCache.GetByFunction(m)
if err == nil {
// Cached, return svc address
return fsvc.Address, nil
}
respChan := make(chan *createFuncServiceResponse)
executor.requestChan <- &createFuncServiceRequest{
funcMeta: m,
respChan: respChan,
}
resp := <-respChan
if resp.err != nil {
return "", resp.err
}
return resp.funcSvc.Address, resp.err
}
// find funcSvc and update its atime
func (executor *Executor) tapService(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request", 500)
return
}
svcName := string(body)
svcHost := strings.TrimPrefix(svcName, "http://")
err = executor.fsCache.TouchByAddress(svcHost)
if err != nil {
log.Printf("funcSvc tap error: %v", err)
http.Error(w, "Not found", 404)
return
}
w.WriteHeader(http.StatusOK)
}
func (executor *Executor) Serve(port int) {
r := mux.NewRouter()
r.HandleFunc("/v2/getServiceForFunction", executor.getServiceForFunctionApi).Methods("POST")
r.HandleFunc("/v2/tapService", executor.tapService).Methods("POST")
address := fmt.Sprintf(":%v", port)
log.Printf("starting executor at port %v", port)
log.Fatal(http.ListenAndServe(address, handlers.LoggingHandler(os.Stdout, r)))
}
@@ -26,20 +26,20 @@ import (
"strings"
"time"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
)
type Client struct {
poolmgrUrl string
executorUrl string
tappedByUrl map[string]bool
requestChan chan string
}
func MakeClient(poolmgrUrl string) *Client {
func MakeClient(executorUrl string) *Client {
c := &Client{
poolmgrUrl: strings.TrimSuffix(poolmgrUrl, "/"),
executorUrl: strings.TrimSuffix(executorUrl, "/"),
tappedByUrl: make(map[string]bool),
requestChan: make(chan string),
}
@@ -47,15 +47,15 @@ func MakeClient(poolmgrUrl string) *Client {
return c
}
func (c *Client) GetServiceForFunction(metadata *api.ObjectMeta) (string, error) {
poolmgrUrl := c.poolmgrUrl + "/v2/getServiceForFunction"
func (c *Client) GetServiceForFunction(metadata *metav1.ObjectMeta) (string, error) {
executorUrl := c.executorUrl + "/v2/getServiceForFunction"
body, err := json.Marshal(metadata)
if err != nil {
return "", err
}
resp, err := http.Post(poolmgrUrl, "application/json", bytes.NewReader(body))
resp, err := http.Post(executorUrl, "application/json", bytes.NewReader(body))
if err != nil {
return "", err
}
@@ -100,9 +100,9 @@ func (c *Client) TapService(serviceUrl *url.URL) {
}
func (c *Client) _tapService(serviceUrlStr string) error {
poolmgrUrl := c.poolmgrUrl + "/v2/tapService"
executorUrl := c.executorUrl + "/v2/tapService"
resp, err := http.Post(poolmgrUrl, "application/octet-stream", bytes.NewReader([]byte(serviceUrlStr)))
resp, err := http.Post(executorUrl, "application/octet-stream", bytes.NewReader([]byte(serviceUrlStr)))
if err != nil {
return err
}
+22
View File
@@ -0,0 +1,22 @@
/*
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 deploymgr
func GetFuncSvc() (*funcSvc, error) {
return nil, nil
}
+195
View File
@@ -0,0 +1,195 @@
/*
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 executor
import (
"log"
"os"
"sync"
"time"
"github.com/dchest/uniuri"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission/cache"
"github.com/fission/fission/crd"
"github.com/fission/fission/executor/fscache"
"github.com/fission/fission/executor/poolmgr"
)
type (
Executor struct {
gpm *poolmgr.GenericPoolManager
functionEnv *cache.Cache
fissionClient *crd.FissionClient
fsCache *fscache.FunctionServiceCache
requestChan chan *createFuncServiceRequest
fsCreateWg map[string]*sync.WaitGroup
}
createFuncServiceRequest struct {
funcMeta *metav1.ObjectMeta
respChan chan *createFuncServiceResponse
}
createFuncServiceResponse struct {
funcSvc *fscache.FuncSvc
err error
}
)
func MakeExecutor(gpm *poolmgr.GenericPoolManager, fissionClient *crd.FissionClient, fsCache *fscache.FunctionServiceCache) *Executor {
executor := &Executor{
gpm: gpm,
functionEnv: cache.MakeCache(10*time.Second, 0),
fissionClient: fissionClient,
fsCache: fsCache,
requestChan: make(chan *createFuncServiceRequest),
fsCreateWg: make(map[string]*sync.WaitGroup),
}
go executor.serveCreateFuncServices()
return executor
}
// All non-cached function service requests go through this goroutine
// serially. It parallelizes requests for different functions, and
// ensures that for a given function, only one request causes a pod to
// get specialized. In other words, it ensures that when there's an
// ongoing request for a certain function, all other requests wait for
// that request to complete.
func (executor *Executor) serveCreateFuncServices() {
for {
req := <-executor.requestChan
m := req.funcMeta
// Cache miss -- is this first one to request the func?
wg, found := executor.fsCreateWg[crd.CacheKey(m)]
if !found {
// create a waitgroup for other requests for
// the same function to wait on
wg := &sync.WaitGroup{}
wg.Add(1)
executor.fsCreateWg[crd.CacheKey(m)] = wg
// launch a goroutine for each request, to parallelize
// the specialization of different functions
go func() {
fsvc, err := executor.createServiceForFunction(m)
req.respChan <- &createFuncServiceResponse{
funcSvc: fsvc,
err: err,
}
delete(executor.fsCreateWg, crd.CacheKey(m))
wg.Done()
}()
} else {
// There's an existing request for this function, wait for it to finish
go func() {
log.Printf("Waiting for concurrent request for the same function: %v", m)
wg.Wait()
// get the function service from the cache
fsvc, err := executor.fsCache.GetByFunction(m)
req.respChan <- &createFuncServiceResponse{
funcSvc: fsvc,
err: err,
}
}()
}
}
}
func (executor *Executor) createServiceForFunction(m *metav1.ObjectMeta) (*fscache.FuncSvc, error) {
log.Printf("[%v] No cached function service found, creating one", m.Name)
env, err := executor.getFunctionEnv(m)
if err != nil {
return nil, err
}
// Appropriate backend handles the service creation
backend := os.Getenv("EXECUTOR_BACKEND")
switch backend {
case "DEPLOY":
return nil, nil
default:
pool, err := executor.gpm.GetPool(env)
if err != nil {
return nil, err
}
// from GenericPool -> get one function container
// (this also adds to the cache)
log.Printf("[%v] getting function service from pool", m.Name)
fsvc, err := pool.GetFuncSvc(m)
if err != nil {
return nil, err
}
return fsvc, nil
}
}
func (executor *Executor) getFunctionEnv(m *metav1.ObjectMeta) (*crd.Environment, error) {
var env *crd.Environment
// Cached ?
result, err := executor.functionEnv.Get(crd.CacheKey(m))
if err == nil {
env = result.(*crd.Environment)
return env, nil
}
// Cache miss -- get func from controller
f, err := executor.fissionClient.Functions(m.Namespace).Get(m.Name)
if err != nil {
return nil, err
}
// Get env from metadata
log.Printf("[%v] getting env", m)
env, err = executor.fissionClient.Environments(f.Spec.Environment.Namespace).Get(f.Spec.Environment.Name)
if err != nil {
return nil, err
}
// cache for future lookups
executor.functionEnv.Set(crd.CacheKey(m), env)
return env, nil
}
// StartExecutor Starts executor and the backend components that executor uses such as Poolmgr,
// deploymgr and potential future backends
func StartExecutor(fissionNamespace string, functionNamespace string, port int) error {
fissionClient, kubernetesClient, _, err := crd.MakeFissionClient()
if err != nil {
log.Printf("Failed to get kubernetes client: %v", err)
return err
}
instanceID := uniuri.NewLen(8)
poolmgr.CleanupOldPoolmgrResources(kubernetesClient, functionNamespace, instanceID)
fsCache := fscache.MakeFunctionServiceCache()
gpm := poolmgr.MakeGenericPoolManager(
fissionClient, kubernetesClient, fissionNamespace,
functionNamespace, fsCache, instanceID)
api := MakeExecutor(gpm, fissionClient, fsCache)
go api.Serve(port)
return nil
}
@@ -20,10 +20,11 @@
// Here's how I run this on my setup, with minikube:
// TEST_SPECIALIZE_URL=http://192.168.99.100:30002/specialize TEST_FETCHER_URL=http://192.168.99.100:30001 FETCHER_IMAGE=minikube/fetcher:testing KUBECONFIG=/Users/soam/.kube/config go test -v .
package poolmgr
package executor
import (
"fmt"
"io/ioutil"
"log"
"math/rand"
"net/http"
@@ -31,22 +32,21 @@ import (
"testing"
"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/labels"
"k8s.io/client-go/1.5/pkg/util/intstr"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
apiv1 "k8s.io/client-go/pkg/api/v1"
"github.com/fission/fission"
"github.com/fission/fission/poolmgr/client"
"github.com/fission/fission/tpr"
"io/ioutil"
"github.com/fission/fission/crd"
"github.com/fission/fission/executor/client"
)
// return the number of pods in the given namespace matching the given labels
func countPods(kubeClient *kubernetes.Clientset, ns string, labelz map[string]string) int {
pods, err := kubeClient.Pods(ns).List(api.ListOptions{
LabelSelector: labels.Set(labelz).AsSelector(),
pods, err := kubeClient.Pods(ns).List(metav1.ListOptions{
LabelSelector: labels.Set(labelz).AsSelector().String(),
})
if err != nil {
log.Panicf("Failed to list pods: %v", err)
@@ -55,8 +55,8 @@ func countPods(kubeClient *kubernetes.Clientset, ns string, labelz map[string]st
}
func createTestNamespace(kubeClient *kubernetes.Clientset, ns string) {
_, err := kubeClient.Namespaces().Create(&v1.Namespace{
ObjectMeta: v1.ObjectMeta{
_, err := kubeClient.Namespaces().Create(&apiv1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: ns,
},
})
@@ -67,16 +67,16 @@ func createTestNamespace(kubeClient *kubernetes.Clientset, ns string) {
}
// create a nodeport service
func createSvc(kubeClient *kubernetes.Clientset, ns string, name string, targetPort int, nodePort int32, labels map[string]string) *v1.Service {
svc, err := kubeClient.Services(ns).Create(&v1.Service{
ObjectMeta: v1.ObjectMeta{
func createSvc(kubeClient *kubernetes.Clientset, ns string, name string, targetPort int, nodePort int32, labels map[string]string) *apiv1.Service {
svc, err := kubeClient.Services(ns).Create(&apiv1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
Ports: []v1.ServicePort{
Spec: apiv1.ServiceSpec{
Type: apiv1.ServiceTypeNodePort,
Ports: []apiv1.ServicePort{
{
Protocol: v1.ProtocolTCP,
Protocol: apiv1.ProtocolTCP,
Port: 80,
TargetPort: intstr.FromInt(targetPort),
NodePort: nodePort,
@@ -104,7 +104,7 @@ func httpGet(url string) string {
return string(body)
}
func TestPoolmgr(t *testing.T) {
func TestExecutor(t *testing.T) {
// run in a random namespace so we can have concurrent tests
// on a given cluster
rand.Seed(time.Now().UTC().UnixNano())
@@ -120,8 +120,8 @@ func TestPoolmgr(t *testing.T) {
}
// connect to k8s
// and get TPR client
fissionClient, kubeClient, err := tpr.MakeFissionClient()
// and get CRD client
fissionClient, kubeClient, apiExtClient, err := crd.MakeFissionClient()
if err != nil {
log.Panicf("failed to connect: %v", err)
}
@@ -133,16 +133,16 @@ func TestPoolmgr(t *testing.T) {
createTestNamespace(kubeClient, functionNs)
defer kubeClient.Namespaces().Delete(functionNs, nil)
// make sure TPR types exist on cluster
err = tpr.EnsureFissionTPRs(kubeClient)
// make sure CRD types exist on cluster
err = crd.EnsureFissionCRDs(apiExtClient)
if err != nil {
log.Panicf("failed to ensure tprs: %v", err)
log.Panicf("failed to ensure crds: %v", err)
}
fissionClient.WaitForTPRs()
fissionClient.WaitForCRDs()
// create an env on the cluster
env, err := fissionClient.Environments(fissionNs).Create(&tpr.Environment{
Metadata: api.ObjectMeta{
env, err := fissionClient.Environments(fissionNs).Create(&crd.Environment{
Metadata: metav1.ObjectMeta{
Name: "nodejs",
Namespace: fissionNs,
},
@@ -160,7 +160,7 @@ func TestPoolmgr(t *testing.T) {
// create poolmgr
port := 9999
err = StartPoolmgr(fissionNs, functionNs, port)
err = StartExecutor(fissionNs, functionNs, port)
if err != nil {
log.Panicf("failed to start poolmgr: %v", err)
}
@@ -173,37 +173,47 @@ func TestPoolmgr(t *testing.T) {
// waitForPool(functionNs, "nodejs")
time.Sleep(6 * time.Second)
envRef := fission.EnvironmentReference{
Namespace: env.Metadata.Namespace,
Name: env.Metadata.Name,
}
deployment := fission.Archive{
Type: fission.ArchiveTypeLiteral,
Literal: []byte(`module.exports = async function(context) { return { status: 200, body: "Hello, world!\n" }; }`),
}
// create a package
p := &tpr.Package{
Metadata: api.ObjectMeta{
p := &crd.Package{
Metadata: metav1.ObjectMeta{
Name: "hello",
Namespace: fissionNs,
},
Spec: fission.PackageSpec{
Type: fission.PackageTypeLiteral,
Literal: []byte(`module.exports = async function(context) { return { status: 200, body: "Hello, world!\n" }; }`),
Environment: envRef,
Deployment: deployment,
},
}
_, err = fissionClient.Packages(fissionNs).Create(p)
p, err = fissionClient.Packages(fissionNs).Create(p)
if err != nil {
log.Panicf("failed to create package: %v", err)
}
// create a function
f := &tpr.Function{
Metadata: api.ObjectMeta{
f := &crd.Function{
Metadata: metav1.ObjectMeta{
Name: "hello",
Namespace: fissionNs,
},
Spec: fission.FunctionSpec{
Source: fission.FunctionPackageRef{},
Deployment: fission.FunctionPackageRef{
Environment: envRef,
Package: fission.FunctionPackageRef{
PackageRef: fission.PackageRef{
Name: p.Metadata.Name,
Namespace: p.Metadata.Namespace,
Namespace: p.Metadata.Namespace,
Name: p.Metadata.Name,
ResourceVersion: p.Metadata.ResourceVersion,
},
},
EnvironmentName: env.Metadata.Name,
},
}
_, err = fissionClient.Functions(fissionNs).Create(f)
+230
View File
@@ -0,0 +1,230 @@
/*
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 fscache
import (
"log"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api"
"github.com/fission/fission"
"github.com/fission/fission/cache"
"github.com/fission/fission/crd"
)
type fscRequestType int
type backendType int
const (
TOUCH fscRequestType = iota
LISTOLD
LOG
)
const (
POOLMGR backendType = iota
NEWDEPLOY
)
type (
FuncSvc struct {
Function *metav1.ObjectMeta // function this pod/service is for
Environment *crd.Environment // function's environment
Address string // Host:Port or IP:Port that the function's service can be reached at.
KubernetesObjects []api.ObjectReference // Kubernetes Objects (within the function namespace)
Backend backendType
Ctime time.Time
Atime time.Time
}
FunctionServiceCache struct {
byFunction *cache.Cache // function-key -> funcSvc : map[string]*funcSvc
byAddress *cache.Cache // address -> function : map[string]metav1.ObjectMeta
requestChannel chan *fscRequest
}
fscRequest struct {
requestType fscRequestType
address string
kubernetesObjects []api.ObjectReference
age time.Duration
env *metav1.ObjectMeta // used for ListOld
responseChannel chan *fscResponse
}
fscResponse struct {
objects []*FuncSvc
deleted bool
error
}
)
func MakeFunctionServiceCache() *FunctionServiceCache {
fsc := &FunctionServiceCache{
byFunction: cache.MakeCache(0, 0),
byAddress: cache.MakeCache(0, 0),
requestChannel: make(chan *fscRequest),
}
go fsc.service()
return fsc
}
func (fsc *FunctionServiceCache) service() {
for {
req := <-fsc.requestChannel
resp := &fscResponse{}
switch req.requestType {
case TOUCH:
// update atime for this function svc
resp.error = fsc._touchByAddress(req.address)
case LISTOLD:
// get svcs idle for > req.age
fscs := fsc.byFunction.Copy()
funcObjects := make([]*FuncSvc, 0)
for _, funcSvc := range fscs {
fsvc := funcSvc.(*FuncSvc)
if fsvc.Environment.Metadata.UID == req.env.UID &&
time.Now().Sub(fsvc.Atime) > req.age {
funcObjects = append(funcObjects, fsvc)
}
}
resp.objects = funcObjects
case LOG:
funcCopy := fsc.byFunction.Copy()
log.Printf("Cache has %v entries", len(funcCopy))
for key, fsvcI := range funcCopy {
fsvc := fsvcI.(*FuncSvc)
for _, kubeObj := range fsvc.KubernetesObjects {
log.Printf("%v\t%v\t%v", key, kubeObj.Kind, kubeObj.Name)
}
}
}
req.responseChannel <- resp
}
}
func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc, error) {
key := crd.CacheKey(m)
fsvcI, err := fsc.byFunction.Get(key)
if err != nil {
return nil, err
}
// update atime
fsvc := fsvcI.(*FuncSvc)
fsvc.Atime = time.Now()
fsvcCopy := *fsvc
return &fsvcCopy, nil
}
// TODO: error should be second return
func (fsc *FunctionServiceCache) Add(fsvc FuncSvc) (error, *FuncSvc) {
err, existing := fsc.byFunction.Set(crd.CacheKey(fsvc.Function), &fsvc)
if err != nil {
if existing != nil {
f := existing.(*FuncSvc)
err2 := fsc.TouchByAddress(f.Address)
if err2 != nil {
return err2, nil
}
fCopy := *f
return err, &fCopy
}
return err, nil
}
now := time.Now()
fsvc.Ctime = now
fsvc.Atime = now
// Add to byAddress cache. Ignore NameExists errors
// because of multiple-specialization. See issue #331.
err, _ = fsc.byAddress.Set(fsvc.Address, *fsvc.Function)
if err != nil {
if fe, ok := err.(fission.Error); ok {
if fe.Code == fission.ErrorNameExists {
err = nil
}
}
log.Printf("error caching fsvc: %v", err)
return err, nil
}
return nil, nil
}
func (fsc *FunctionServiceCache) TouchByAddress(address string) error {
responseChannel := make(chan *fscResponse)
fsc.requestChannel <- &fscRequest{
requestType: TOUCH,
address: address,
responseChannel: responseChannel,
}
resp := <-responseChannel
return resp.error
}
func (fsc *FunctionServiceCache) _touchByAddress(address string) error {
mI, err := fsc.byAddress.Get(address)
if err != nil {
return err
}
m := mI.(metav1.ObjectMeta)
fsvcI, err := fsc.byFunction.Get(crd.CacheKey(&m))
if err != nil {
return err
}
fsvc := fsvcI.(*FuncSvc)
fsvc.Atime = time.Now()
return nil
}
func (fsc *FunctionServiceCache) DeleteOld(fsvc *FuncSvc, minAge time.Duration) (bool, error) {
if time.Now().Sub(fsvc.Atime) < minAge {
return false, nil
}
fsc.byFunction.Delete(crd.CacheKey(fsvc.Function))
fsc.byAddress.Delete(fsvc.Address)
return true, nil
}
func (fsc *FunctionServiceCache) ListOld(env *metav1.ObjectMeta, age time.Duration) ([]*FuncSvc, error) {
responseChannel := make(chan *fscResponse)
fsc.requestChannel <- &fscRequest{
requestType: LISTOLD,
age: age,
env: env,
responseChannel: responseChannel,
}
resp := <-responseChannel
return resp.objects, resp.error
}
func (fsc *FunctionServiceCache) Log() {
log.Printf("--- FunctionService Cache Contents")
responseChannel := make(chan *fscResponse)
fsc.requestChannel <- &fscRequest{
requestType: LOG,
responseChannel: responseChannel,
}
<-responseChannel
log.Printf("--- FunctionService Cache Contents End")
}
@@ -1,14 +1,15 @@
package poolmgr
package fscache
import (
"log"
"testing"
"time"
"k8s.io/client-go/1.5/pkg/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api"
"github.com/fission/fission"
"github.com/fission/fission/tpr"
"github.com/fission/fission/crd"
)
func TestFunctionServiceCache(t *testing.T) {
@@ -17,16 +18,31 @@ func TestFunctionServiceCache(t *testing.T) {
log.Panicf("error creating cache")
}
var fsvc *funcSvc
var fsvc *FuncSvc
now := time.Now()
fsvc = &funcSvc{
function: &api.ObjectMeta{
objects := []api.ObjectReference{
{
Kind: "pod",
Name: "xxx",
APIVersion: "v1",
Namespace: "fission-function",
},
{
Kind: "pod",
Name: "xxx2",
APIVersion: "v1",
Namespace: "fission-function",
},
}
fsvc = &FuncSvc{
Function: &metav1.ObjectMeta{
Name: "foo",
UID: "1212",
},
environment: &tpr.Environment{
Metadata: api.ObjectMeta{
Environment: &crd.Environment{
Metadata: metav1.ObjectMeta{
Name: "foo-env",
UID: "2323",
},
@@ -38,10 +54,10 @@ func TestFunctionServiceCache(t *testing.T) {
Builder: fission.Builder{},
},
},
address: "xxx",
podName: "yyy",
ctime: now,
atime: now,
Address: "xxx",
KubernetesObjects: objects,
Ctime: now,
Atime: now,
}
err, _ := fsc.Add(*fsvc)
if err != nil {
@@ -49,25 +65,25 @@ func TestFunctionServiceCache(t *testing.T) {
log.Panicf("Failed to add fsvc: %v", err)
}
f, err := fsc.GetByFunction(fsvc.function)
f, err := fsc.GetByFunction(fsvc.Function)
if err != nil {
fsc.Log()
log.Panicf("Failed to get fsvc: %v", err)
}
fsvc.atime = f.atime
fsvc.ctime = f.ctime
if *f != *fsvc {
fsvc.Atime = f.Atime
fsvc.Ctime = f.Ctime
if f.Address != fsvc.Address {
fsc.Log()
log.Panicf("Incorrect fsvc \n(expected: %#v)\n (found: %#v)", fsvc, f)
}
err = fsc.TouchByAddress(fsvc.address)
err = fsc.TouchByAddress(fsvc.Address)
if err != nil {
fsc.Log()
log.Panicf("Failed to touch fsvc: %v", err)
}
deleted, err := fsc.DeleteByPod(fsvc.podName, 0)
deleted, err := fsc.DeleteOld(fsvc, 0)
if err != nil {
fsc.Log()
log.Panicf("Failed to delete fsvc: %v", err)
@@ -77,7 +93,7 @@ func TestFunctionServiceCache(t *testing.T) {
log.Panicf("Did not delete fsvc")
}
_, err = fsc.GetByFunction(fsvc.function)
_, err = fsc.GetByFunction(fsvc.Function)
if err == nil {
fsc.Log()
log.Panicf("found fsvc while expecting empty cache: %v", err)

Some files were not shown because too many files have changed in this diff Show More