Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2699aa6069 | ||
|
|
f0c0936b87 | ||
|
|
314e16a88e | ||
|
|
72faa927de | ||
|
|
19b52938c3 | ||
|
|
7cedf8d580 | ||
|
|
17cbc5baad | ||
|
|
c2bcbb06a9 | ||
|
|
152c899e8b | ||
|
|
c476f54a6c | ||
|
|
4b5ab0ad93 | ||
|
|
82af0e554a | ||
|
|
b456dec138 | ||
|
|
4a8c200c37 | ||
|
|
52b736c892 | ||
|
|
d9eee058ce | ||
|
|
3676602fa2 | ||
|
|
4f3b7de04a | ||
|
|
cdf5838420 | ||
|
|
a714983c28 | ||
|
|
b9547160b5 | ||
|
|
bfa8e6a45f | ||
|
|
9764eff05d | ||
|
|
253e44fdbe | ||
|
|
585d86448f | ||
|
|
dad7b6632e | ||
|
|
4e9e025ca4 | ||
|
|
b6ea85e353 | ||
|
|
29aabaabda | ||
|
|
394c5b13f4 | ||
|
|
0a8c6e97a6 | ||
|
|
e7f1d4564a | ||
|
|
619b390af3 | ||
|
|
1488d0ca2d | ||
|
|
dd35750482 | ||
|
|
5aeba59b75 | ||
|
|
8329ef36b3 | ||
|
|
4cc42fb216 | ||
|
|
d23b210f4e | ||
|
|
803dbd6d39 | ||
|
|
e4213f6eb6 | ||
|
|
2d2576cf2d | ||
|
|
96cbee185d | ||
|
|
9f83d70b63 | ||
|
|
7deb45bed2 | ||
|
|
12d3a04bf9 | ||
|
|
fa565b75ae | ||
|
|
437d4dc04d | ||
|
|
188138ccd8 | ||
|
|
6b49c194ca | ||
|
|
a86c9431d3 | ||
|
|
6f60f3eef8 | ||
|
|
d18777bed4 | ||
|
|
82d23b9bf8 | ||
|
|
a4f58fbf10 | ||
|
|
2dbae32f20 | ||
|
|
21b0a1d852 | ||
|
|
f8535be7da | ||
|
|
95eef49cf8 | ||
|
|
2d01382a82 | ||
|
|
d443f8b2ef | ||
|
|
dffb5cdf8b | ||
|
|
5c1d8bc90c | ||
|
|
ad28922871 | ||
|
|
9d7355cbaa | ||
|
|
74a3a54543 | ||
|
|
07ca5df8d0 | ||
|
|
e730376e3e | ||
|
|
ee61c8c333 | ||
|
|
27b74a7cf2 | ||
|
|
088e665d28 | ||
|
|
9438f3c4ec | ||
|
|
b5a906b2f4 | ||
|
|
0e40cb5f4f | ||
|
|
1a1ac49ce0 | ||
|
|
4356378301 | ||
|
|
6123873d2a | ||
|
|
9a7ffc2f5b | ||
|
|
f3857abdf5 | ||
|
|
e977c7caca | ||
|
|
f40688435d | ||
|
|
e8b2a26a3b | ||
|
|
27c3a50d23 | ||
|
|
ec495fbd1d | ||
|
|
80fadcc7b8 | ||
|
|
4b37b9ac03 | ||
|
|
16d0f6a94f | ||
|
|
cc40d1ed2e | ||
|
|
425e447e5c | ||
|
|
3707b95edb | ||
|
|
2982efebb8 | ||
|
|
14db705891 | ||
|
|
9c885ef6f5 | ||
|
|
34e8d0ee3d | ||
|
|
728979636f | ||
|
|
462db2f00c | ||
|
|
2504408803 | ||
|
|
61569d1c38 | ||
|
|
5b6582698c | ||
|
|
81f0f1df6d | ||
|
|
44be0f6859 | ||
|
|
9daf97a9ab | ||
|
|
032d1a8b9a | ||
|
|
65fd1d9fbb | ||
|
|
a35cd7f4a4 | ||
|
|
74212f1810 | ||
|
|
1ed59f0789 | ||
|
|
71d8b769d5 | ||
|
|
c863616b38 | ||
|
|
09b62e514e | ||
|
|
c705ba355e | ||
|
|
7642dcf05f | ||
|
|
58a5f1cb0b | ||
|
|
1b86c367a0 | ||
|
|
6d08e6e0bc | ||
|
|
ef7d4ae385 | ||
|
|
cf1f944069 | ||
|
|
ddff7100e9 | ||
|
|
a5bc2a6d4c | ||
|
|
952b48bd68 | ||
|
|
2ad07d68b6 | ||
|
|
8c96d9c6a0 | ||
|
|
46d9808173 | ||
|
|
2e37611da8 | ||
|
|
0057270551 | ||
|
|
7a7d15b50c | ||
|
|
202cc3cb7e | ||
|
|
a761393816 | ||
|
|
fedf6b6e5b | ||
|
|
6eec55223d | ||
|
|
940b9adabd | ||
|
|
8984e4916e | ||
|
|
c9d2757760 | ||
|
|
d846aed612 | ||
|
|
d9b5b9b8a8 | ||
|
|
9c91f00cb4 | ||
|
|
0a648d1d75 |
@@ -1,5 +1,6 @@
|
||||
fission-bundle/fission-bundle
|
||||
fission/fission
|
||||
environments/fetcher/cmd/fetcher
|
||||
|
||||
# Pycharm IDE
|
||||
.idea
|
||||
|
||||
+10
-4
@@ -9,7 +9,7 @@ branches:
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8
|
||||
- 1.11.x
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -22,6 +22,7 @@ services:
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||
- sudo apt-get -y install apache2-utils
|
||||
- sudo sysctl net.ipv6.conf.all.disable_ipv6=0
|
||||
|
||||
install:
|
||||
@@ -31,13 +32,18 @@ install:
|
||||
env:
|
||||
- KUBECONFIG=${HOME}/.kube/config PATH=$HOME/k8scli:${PATH}
|
||||
|
||||
script:
|
||||
before_script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- glide install -v
|
||||
- ./fission-bundle/build.sh
|
||||
- hack/verify-gofmt.sh
|
||||
- hack/verify-govet.sh
|
||||
- helm lint charts/fission-all/ charts/fission-core/
|
||||
- glide install -v
|
||||
- go build -o fission/fission fission/*.go
|
||||
- ./fission-bundle/build.sh
|
||||
- hack/runtests.sh
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- test/build_and_test.sh
|
||||
- test/upgrade/fission_upgrade_test.sh
|
||||
|
||||
|
||||
+211
-30
@@ -1,18 +1,202 @@
|
||||
# 0.7.1
|
||||
[Documentation](http://fission.io/docs/0.7.1/)
|
||||
## Downloads for 0.7.1
|
||||
# 0.12.0
|
||||
[Documentation](https://docs.fission.io/0.12.0/)
|
||||
## Downloads for 0.12.0
|
||||
|
||||
|
||||
filename | sha256 hash
|
||||
-------- | -----------
|
||||
[fission-core-0.7.1.tgz](https://github.com/fission/fission/releases/download/0.7.1/fission-core-0.7.1.tgz) | `5d5606c79b5d83c2e88c371b6bea4a49a599f1a1e26674db3388a63278a47c2c`
|
||||
[fission-all-0.7.1.tgz](https://github.com/fission/fission/releases/download/0.7.1/fission-all-0.7.1.tgz) | `0ea6887f39c0f59463b49e632294152c926b62b5afc65202c80045ff71735b05`
|
||||
[fission-cli-osx](https://github.com/fission/fission/releases/download/0.7.1/fission-cli-osx) | `765b35bd1e4565b9819bed157ca0206a0e5217394d0b253a0cdd9a318ef4d9a5`
|
||||
[fission-cli-linux](https://github.com/fission/fission/releases/download/0.7.1/fission-cli-linux) | `5eacdff0a0f3d6d3a1c2aa8d6164bc6524b1f001298cb2e82b60cf1c762a5a9e`
|
||||
[fission-cli-windows.exe](https://github.com/fission/fission/releases/download/0.7.1/fission-cli-windows.exe) | `c237b1ee1a8f2b26038555388a438e4fff5725c90d4128baaa32a77ccf990d2e`
|
||||
[fission-all-0.12.0.yaml](https://github.com/fission/fission/releases/download/0.12.0/fission-all-0.12.0.yaml) | `1cee07f922849fb41830e2bf32d02f3999ef8c60b49fce8c244c870274c732e3`
|
||||
[fission-core-0.12.0.yaml](https://github.com/fission/fission/releases/download/0.12.0/fission-core-0.12.0.yaml) | `c8d41e62b939f39a69280360015a71d9bab0301c50ea6c3755f16bb5dbc7aa1d`
|
||||
[fission-core-0.12.0-minikube.yaml](https://github.com/fission/fission/releases/download/0.12.0/fission-core-0.12.0-minikube.yaml) | `54b64b6363ba267d768bff4f68379d835467efd99ceab6410ff6900839b6185f`
|
||||
[fission-all-0.12.0-minikube.yaml](https://github.com/fission/fission/releases/download/0.12.0/fission-all-0.12.0-minikube.yaml) | `0044d5d2ecbebae2c8252d96949de9bcd348c8de76d013fbdf7fee5c9fe757af`
|
||||
[fission-core-0.12.0.tgz](https://github.com/fission/fission/releases/download/0.12.0/fission-core-0.12.0.tgz) | `c93949fe0428951ffe5b2fef7133f48d23b82d7b045129bb57ee2de2bd9d9257`
|
||||
[fission-all-0.12.0.tgz](https://github.com/fission/fission/releases/download/0.12.0/fission-all-0.12.0.tgz) | `7b9b739abde387bd96689e709ed25ebae879e30575036b0e4fb54544b1c9f10b`
|
||||
[fission-cli-osx](https://github.com/fission/fission/releases/download/0.12.0/fission-cli-osx) | `54f3b0bf64d57b1996d3871415f540506c5aa9f65227d27be086dfe568a945ce`
|
||||
[fission-cli-linux](https://github.com/fission/fission/releases/download/0.12.0/fission-cli-linux) | `c04e077c79b9211f116bb16341028f0bae2d6a8d89ddb59bb3ce1b4a2ad57364`
|
||||
[fission-cli-windows.exe](https://github.com/fission/fission/releases/download/0.12.0/fission-cli-windows.exe) | `987c62899fb5c26599b14bf08d713d036c18f12e74abb903665e52c41a14f9a6`
|
||||
|
||||
# Change Log
|
||||
|
||||
## [0.12.0](https://github.com/fission/fission/tree/0.12.0) (2018-11-01)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.11.0...0.12.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Keep prometheus and canary deploy set to false in fission-core [\#964](https://github.com/fission/fission/pull/964) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Update readme to include JVM [\#953](https://github.com/fission/fission/pull/953) ([david-mcgillicuddy-ovo](https://github.com/david-mcgillicuddy-ovo))
|
||||
- Bump flask version [\#942](https://github.com/fission/fission/pull/942) ([life1347](https://github.com/life1347))
|
||||
- Adding JVM heap options to environment [\#936](https://github.com/fission/fission/pull/936) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Demo script updates [\#934](https://github.com/fission/fission/pull/934) ([soamvasani](https://github.com/soamvasani))
|
||||
- Fix flag not found problem when running canary demo scripts [\#914](https://github.com/fission/fission/pull/914) ([life1347](https://github.com/life1347))
|
||||
- V0.11.0 [\#913](https://github.com/fission/fission/pull/913) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fix failed to pull influxdb image from dockerhub [\#957](https://github.com/fission/fission/pull/957) ([life1347](https://github.com/life1347))
|
||||
- Kafka tests [\#944](https://github.com/fission/fission/pull/944) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- fix a few canary deployment issues [\#943](https://github.com/fission/fission/pull/943) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Support for full url \(base on aalubin 882 changes\) [\#941](https://github.com/fission/fission/pull/941) ([life1347](https://github.com/life1347))
|
||||
- Remove version from release name since it contains illegal chars for names [\#939](https://github.com/fission/fission/pull/939) ([soamvasani](https://github.com/soamvasani))
|
||||
- Feature flag to enable/disable canary + optional prometheus install [\#937](https://github.com/fission/fission/pull/937) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Return the error on failed specializations with `fn test --debug` [\#917](https://github.com/fission/fission/pull/917) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Added build and push procedures for Nodejs builder environment [\#916](https://github.com/fission/fission/pull/916) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Add X-Forwarded-Host to request header [\#890](https://github.com/fission/fission/pull/890) ([life1347](https://github.com/life1347))
|
||||
- Optimize function latency when cache expired/invalid under high concurrency [\#856](https://github.com/fission/fission/pull/856) ([life1347](https://github.com/life1347))
|
||||
|
||||
## [0.11.0](https://github.com/fission/fission/tree/0.11.0) (2018-10-01)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.10.0...0.11.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Print status with the get option. [\#907](https://github.com/fission/fission/pull/907) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Fixed the spec validation UX issue [\#898](https://github.com/fission/fission/pull/898) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Check CRD creation error instead of doing return directly [\#897](https://github.com/fission/fission/pull/897) ([life1347](https://github.com/life1347))
|
||||
- Fix failed to find release-builder dockerfile & push specific tag [\#870](https://github.com/fission/fission/pull/870) ([life1347](https://github.com/life1347))
|
||||
- V0.10.0 [\#868](https://github.com/fission/fission/pull/868) ([life1347](https://github.com/life1347))
|
||||
- Fixes \#758, uses v2 specialize for env versions 2 or higher [\#911](https://github.com/fission/fission/pull/911) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Java env test - Maven verbosity reduction [\#902](https://github.com/fission/fission/pull/902) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Canary deployments for fission functions. [\#892](https://github.com/fission/fission/pull/892) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Fix fetcher not close file descriptor correctly [\#889](https://github.com/fission/fission/pull/889) ([life1347](https://github.com/life1347))
|
||||
- Removes the spec helm command for now to fix \#881 [\#886](https://github.com/fission/fission/pull/886) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- FIX CleanupOldExecutorObjects in all namespaces [\#879](https://github.com/fission/fission/pull/879) ([ajbouh](https://github.com/ajbouh))
|
||||
- Check pod container ready state [\#861](https://github.com/fission/fission/pull/861) ([life1347](https://github.com/life1347))
|
||||
- Configurable namespace creation [\#855](https://github.com/fission/fission/pull/855) ([michaelgaida](https://github.com/michaelgaida))
|
||||
- Add v2 interface support for nodes env [\#836](https://github.com/fission/fission/pull/836) ([garyyeap](https://github.com/garyyeap))
|
||||
- Kafka integration [\#831](https://github.com/fission/fission/pull/831) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fission supportability: Add dump command to dump information for debugging [\#754](https://github.com/fission/fission/pull/754) ([life1347](https://github.com/life1347))
|
||||
|
||||
## [0.10.0](https://github.com/fission/fission/tree/0.10.0) (2018-08-17)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.9.2...0.10.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix CLI failed to setup port-forward caused by \#712 [\#867](https://github.com/fission/fission/pull/867) ([life1347](https://github.com/life1347))
|
||||
- Replay recorded requests by ReqUID [\#864](https://github.com/fission/fission/pull/864) ([Amusement](https://github.com/Amusement))
|
||||
- Add cleanup function to test scripts [\#863](https://github.com/fission/fission/pull/863) ([life1347](https://github.com/life1347))
|
||||
- Fix newdeploy fail to update HPA, deployment of a function after function update [\#862](https://github.com/fission/fission/pull/862) ([life1347](https://github.com/life1347))
|
||||
- Fix router not taps function services [\#860](https://github.com/fission/fission/pull/860) ([life1347](https://github.com/life1347))
|
||||
- Do resources validation when validate spec files [\#840](https://github.com/fission/fission/pull/840) ([life1347](https://github.com/life1347))
|
||||
- Fixed the name of JVM builder image name [\#824](https://github.com/fission/fission/pull/824) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- V0.9.2 [\#817](https://github.com/fission/fission/pull/817) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Add retry subcommand to pkg command [\#808](https://github.com/fission/fission/pull/808) ([life1347](https://github.com/life1347))
|
||||
- add gevent based Python server to benchmark test cases [\#794](https://github.com/fission/fission/pull/794) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Add more meaningful error messages to executor when getServiceForFunction [\#752](https://github.com/fission/fission/pull/752) ([life1347](https://github.com/life1347))
|
||||
- Fix for \#662: avoid unnecessary builds [\#866](https://github.com/fission/fission/pull/866) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Fix newdeploy not updates deployment after function's entrypoint changed [\#838](https://github.com/fission/fission/pull/838) ([life1347](https://github.com/life1347))
|
||||
- Fix spec failed to archive single directory [\#837](https://github.com/fission/fission/pull/837) ([life1347](https://github.com/life1347))
|
||||
- Uses a real go project to showcase vendor example so glide works [\#828](https://github.com/fission/fission/pull/828) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Recorder CRD, Records API, Redis deployment [\#818](https://github.com/fission/fission/pull/818) ([Amusement](https://github.com/Amusement))
|
||||
- Fix router panic when trying to update route [\#811](https://github.com/fission/fission/pull/811) ([life1347](https://github.com/life1347))
|
||||
- Add query options to `fission function test` [\#782](https://github.com/fission/fission/pull/782) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
- Add go environment vendor directory support [\#781](https://github.com/fission/fission/pull/781) ([life1347](https://github.com/life1347))
|
||||
- Scale deployment to zero when function is in idle state [\#775](https://github.com/fission/fission/pull/775) ([life1347](https://github.com/life1347))
|
||||
- Update binary environment readme [\#773](https://github.com/fission/fission/pull/773) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
- Added readme for JVM environment [\#768](https://github.com/fission/fission/pull/768) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fix spec command overrides existing archive's url of a package [\#764](https://github.com/fission/fission/pull/764) ([life1347](https://github.com/life1347))
|
||||
- Fixed typos from from goreportcard [\#760](https://github.com/fission/fission/pull/760) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Extensible Fission CLI [\#743](https://github.com/fission/fission/pull/743) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
- Updating releasing notes with details and structure [\#738](https://github.com/fission/fission/pull/738) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Update route without providing function reference [\#718](https://github.com/fission/fission/pull/718) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Allow router round-trip to be configurable [\#713](https://github.com/fission/fission/pull/713) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Fix CLI failed to set up port-forwarding when multiple controller pods exist in the same namespace [\#712](https://github.com/fission/fission/pull/712) ([life1347](https://github.com/life1347))
|
||||
|
||||
## [0.9.2](https://github.com/fission/fission/tree/0.9.2) (2018-07-25)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.9.1...0.9.2)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Helm lint check in Travis CI [\#799](https://github.com/fission/fission/pull/799) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
- Spelling. [\#797](https://github.com/fission/fission/pull/797) ([WrathZA](https://github.com/WrathZA))
|
||||
- change image pull policy of builder manager [\#793](https://github.com/fission/fission/pull/793) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Delete namespace in background to reduce build time [\#791](https://github.com/fission/fission/pull/791) ([life1347](https://github.com/life1347))
|
||||
- Break & Stop the build immediately if a non-zero exit code was returned [\#790](https://github.com/fission/fission/pull/790) ([life1347](https://github.com/life1347))
|
||||
- Add changelog. [\#789](https://github.com/fission/fission/pull/789) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- changes needed for 0.9.1 [\#788](https://github.com/fission/fission/pull/788) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Working version of Java builder with Maven [\#783](https://github.com/fission/fission/pull/783) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
|
||||
## [0.9.1](https://github.com/fission/fission/tree/0.9.1) (2018-07-07)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.9.0...0.9.1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Committing changelog. [\#780](https://github.com/fission/fission/pull/780) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Changes in charts for release 0.9.0 [\#778](https://github.com/fission/fission/pull/778) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Change flag name to KeepArchive for backward compatibility [\#787](https://github.com/fission/fission/pull/787) ([life1347](https://github.com/life1347))
|
||||
- Fix go env plugin [\#784](https://github.com/fission/fission/pull/784) ([life1347](https://github.com/life1347))
|
||||
- Fix “rm: missing operand” in release script [\#779](https://github.com/fission/fission/pull/779) ([life1347](https://github.com/life1347))
|
||||
|
||||
## [0.9.0](https://github.com/fission/fission/tree/0.9.0) (2018-07-04)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.8.0...0.9.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix executor wrongly passes loop variable reference to function [\#751](https://github.com/fission/fission/pull/751) ([life1347](https://github.com/life1347))
|
||||
- Python Environment: add gevent based WSGI server framework [\#750](https://github.com/fission/fission/pull/750) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Temporarily disabling the tests so that other PRs can be worked on [\#737](https://github.com/fission/fission/pull/737) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- add build exe to gitignore [\#736](https://github.com/fission/fission/pull/736) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- ArchiveLiteralSizeLimit: Use Constant Instead Hard Code [\#731](https://github.com/fission/fission/pull/731) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Environment warning message bugfix [\#725](https://github.com/fission/fission/pull/725) ([soamvasani](https://github.com/soamvasani))
|
||||
- V0.8.0 [\#722](https://github.com/fission/fission/pull/722) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Make fetcher resource requests and limits configurable [\#708](https://github.com/fission/fission/pull/708) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Add steps to render & upload fission installation YAML [\#745](https://github.com/fission/fission/pull/745) ([life1347](https://github.com/life1347))
|
||||
- Fix executor not reaps idle function pods for functions with executortype newdeploy [\#744](https://github.com/fission/fission/pull/744) ([life1347](https://github.com/life1347))
|
||||
- Testing with keep alive settings for connections [\#742](https://github.com/fission/fission/pull/742) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- instead hard code by variable in error message [\#735](https://github.com/fission/fission/pull/735) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- envns should be availabe in message line [\#734](https://github.com/fission/fission/pull/734) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Support annotations in environment specs [\#733](https://github.com/fission/fission/pull/733) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
- Extract portforward to separate package [\#728](https://github.com/fission/fission/pull/728) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
- Push NATS error messages to error queue [\#724](https://github.com/fission/fission/pull/724) ([Amusement](https://github.com/Amusement))
|
||||
- Fix for Windows CLI Port Forwarding [\#715](https://github.com/fission/fission/pull/715) ([thejosephstevens](https://github.com/thejosephstevens))
|
||||
- Router liveness [\#701](https://github.com/fission/fission/pull/701) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Archives bigger than 256K size need env variable for uploading [\#697](https://github.com/fission/fission/pull/697) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Convert go-env Dockerfile into a multi-stage build [\#683](https://github.com/fission/fission/pull/683) ([jgall](https://github.com/jgall))
|
||||
- Move build process from host to docker container during release process [\#682](https://github.com/fission/fission/pull/682) ([life1347](https://github.com/life1347))
|
||||
- Added a flag to control the extraction of archive based on user input [\#675](https://github.com/fission/fission/pull/675) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Java env alpha [\#656](https://github.com/fission/fission/pull/656) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
|
||||
## [0.8.0](https://github.com/fission/fission/tree/0.8.0) (2018-06-05)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.7.2...0.8.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Pre-install/pre-upgrade hooks to verify func references and assign restricted role bindings [\#717](https://github.com/fission/fission/pull/717) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Logger daemonset's update strategy [\#714](https://github.com/fission/fission/pull/714) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Check spec directory exists before reading spec files [\#709](https://github.com/fission/fission/pull/709) ([life1347](https://github.com/life1347))
|
||||
- Formatted specifiers are not compatible with variables [\#706](https://github.com/fission/fission/pull/706) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- Indicate HTTP status code by library const [\#703](https://github.com/fission/fission/pull/703) ([xiekeyang](https://github.com/xiekeyang))
|
||||
- docker-distribution version bump for windows compatibility [\#691](https://github.com/fission/fission/pull/691) ([thejosephstevens](https://github.com/thejosephstevens))
|
||||
- Version -\> 0.7.2 [\#670](https://github.com/fission/fission/pull/670) ([life1347](https://github.com/life1347))
|
||||
- Java environment Design & considerations [\#642](https://github.com/fission/fission/pull/642) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Working version of Ingress integration [\#688](https://github.com/fission/fission/pull/688) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Update k8s dependencies to 1.10 [\#687](https://github.com/fission/fission/pull/687) ([life1347](https://github.com/life1347))
|
||||
- Add time trigger cron spec examination tool [\#680](https://github.com/fission/fission/pull/680) ([life1347](https://github.com/life1347))
|
||||
- Fission metrics integration [\#677](https://github.com/fission/fission/pull/677) ([soamvasani](https://github.com/soamvasani))
|
||||
- Replace Werkzeug with Bjoern as underlying WSGI server [\#672](https://github.com/fission/fission/pull/672) ([life1347](https://github.com/life1347))
|
||||
- Enabling multi-tenancy for fission objects. [\#655](https://github.com/fission/fission/pull/655) ([smruthi2187](https://github.com/smruthi2187))
|
||||
|
||||
## [0.7.2](https://github.com/fission/fission/tree/0.7.2) (2018-05-05)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.7.1...0.7.2)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add benchmark script [\#666](https://github.com/fission/fission/pull/666) ([life1347](https://github.com/life1347))
|
||||
- Fixed the issue with update wiping values [\#663](https://github.com/fission/fission/pull/663) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fix newdeploy backend failed to delete deployment due to incorrect resource version [\#657](https://github.com/fission/fission/pull/657) ([life1347](https://github.com/life1347))
|
||||
- Function update should be possible without change to code [\#652](https://github.com/fission/fission/pull/652) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fixes the issue with fn test and adds relevant test cases, fixes \#650 [\#651](https://github.com/fission/fission/pull/651) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fix test cases occasional failure [\#647](https://github.com/fission/fission/pull/647) ([life1347](https://github.com/life1347))
|
||||
- Change time precision for fluentd influxdb plugin to nano second [\#646](https://github.com/fission/fission/pull/646) ([life1347](https://github.com/life1347))
|
||||
- Setting buildStatus to pending when function's source archive is updated. [\#637](https://github.com/fission/fission/pull/637) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Fix SEGFAULT issue when buildmgr failed to update package [\#635](https://github.com/fission/fission/pull/635) ([life1347](https://github.com/life1347))
|
||||
- Fix executor does not reap specialized function pod when env no longer exists [\#633](https://github.com/fission/fission/pull/633) ([life1347](https://github.com/life1347))
|
||||
- Update readme to point to the proper link [\#628](https://github.com/fission/fission/pull/628) ([jgall](https://github.com/jgall))
|
||||
- Changes needed for release 0.7.1 [\#622](https://github.com/fission/fission/pull/622) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Add default value to cli flag [\#619](https://github.com/fission/fission/pull/619) ([life1347](https://github.com/life1347))
|
||||
- Remove port forward in tests for router, controller and nats pods [\#611](https://github.com/fission/fission/pull/611) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- meaningful error message when fetch request is received for a package when build is not successful. [\#661](https://github.com/fission/fission/pull/661) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Delete deployment with proper delete propagation policy [\#630](https://github.com/fission/fission/pull/630) ([life1347](https://github.com/life1347))
|
||||
- Fix buildmgr SEGFAULT when it failed to update package [\#626](https://github.com/fission/fission/pull/626) ([life1347](https://github.com/life1347))
|
||||
- Fission upgrade tests [\#605](https://github.com/fission/fission/pull/605) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Removed the fn pods functionality [\#594](https://github.com/fission/fission/pull/594) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Testing proposal: Requirements and frameworks exploration [\#581](https://github.com/fission/fission/pull/581) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
|
||||
## [0.7.1](https://github.com/fission/fission/tree/0.7.1) (2018-04-10)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.7.0...0.7.1)
|
||||
|
||||
@@ -50,11 +234,11 @@ filename | sha256 hash
|
||||
- Show fission deployment version with cli [\#538](https://github.com/fission/fission/pull/538) ([life1347](https://github.com/life1347))
|
||||
|
||||
## [0.6.1](https://github.com/fission/fission/tree/0.6.1) (2018-03-22)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.6.0...0.6.1)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/latest...0.6.1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- This change fixes an error in a yaml file in the fission-core chart. [\#563](https://github.com/fission/fission/pull/563) ([yiqunding](https://github.com/yiqunding))
|
||||
- This change fixes an error in a yaml file in the fission-core chart. [\#563](https://github.com/fission/fission/pull/563) ([smartding](https://github.com/smartding))
|
||||
- \[ci skip\] update release number [\#561](https://github.com/fission/fission/pull/561) ([appleboy](https://github.com/appleboy))
|
||||
- Fixes \#537 - warning should not be given when updating to newdeploy [\#545](https://github.com/fission/fission/pull/545) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Docs update [\#542](https://github.com/fission/fission/pull/542) ([soamvasani](https://github.com/soamvasani))
|
||||
@@ -66,27 +250,11 @@ filename | sha256 hash
|
||||
- Fix executor tries to create a new deployment when a function is updated [\#524](https://github.com/fission/fission/pull/524) ([life1347](https://github.com/life1347))
|
||||
- Add container spec config options to \(build\) environments [\#413](https://github.com/fission/fission/pull/413) ([erwinvaneyk](https://github.com/erwinvaneyk))
|
||||
|
||||
## [0.6.0](https://github.com/fission/fission/tree/0.6.0) (2018-03-01)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/latest...0.6.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Detect fission namespace in cli [\#519](https://github.com/fission/fission/pull/519) ([soamvasani](https://github.com/soamvasani))
|
||||
- Default values for FISSION\_\* env vars [\#518](https://github.com/fission/fission/pull/518) ([soamvasani](https://github.com/soamvasani))
|
||||
- Add chart version to job name [\#516](https://github.com/fission/fission/pull/516) ([soamvasani](https://github.com/soamvasani))
|
||||
- Fix CLI not update function's secret/configmap correctly [\#512](https://github.com/fission/fission/pull/512) ([life1347](https://github.com/life1347))
|
||||
- Adds latest tags and pushes to dockerhub for fetcher and fission-bundle [\#509](https://github.com/fission/fission/pull/509) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fixes the backward compatibility with older environment versions [\#508](https://github.com/fission/fission/pull/508) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Update Fn: Executor New Deployment [\#504](https://github.com/fission/fission/pull/504) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Adds default resources for fetcher pod [\#500](https://github.com/fission/fission/pull/500) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Documentation Revamp [\#496](https://github.com/fission/fission/pull/496) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Delete and list orphan pkgs [\#468](https://github.com/fission/fission/pull/468) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Service type ClusterIP - Controller port forward through CLI [\#431](https://github.com/fission/fission/pull/431) ([prithviramesh](https://github.com/prithviramesh))
|
||||
- Istio integration [\#421](https://github.com/fission/fission/pull/421) ([life1347](https://github.com/life1347))
|
||||
- Implement support for Azure storage message queue triggers [\#371](https://github.com/fission/fission/pull/371) ([peterhuene](https://github.com/peterhuene))
|
||||
|
||||
## [latest](https://github.com/fission/fission/tree/latest) (2018-03-01)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.5.0...latest)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.6.0...latest)
|
||||
|
||||
## [0.6.0](https://github.com/fission/fission/tree/0.6.0) (2018-03-01)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.5.0...0.6.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
@@ -101,6 +269,19 @@ filename | sha256 hash
|
||||
- CI modifications [\#491](https://github.com/fission/fission/pull/491) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Add upgrade guide from 0.4.x to 0.5.0 [\#490](https://github.com/fission/fission/pull/490) ([life1347](https://github.com/life1347))
|
||||
- Version -\> 0.5.0 [\#489](https://github.com/fission/fission/pull/489) ([life1347](https://github.com/life1347))
|
||||
- Detect fission namespace in cli [\#519](https://github.com/fission/fission/pull/519) ([soamvasani](https://github.com/soamvasani))
|
||||
- Default values for FISSION\_\* env vars [\#518](https://github.com/fission/fission/pull/518) ([soamvasani](https://github.com/soamvasani))
|
||||
- Add chart version to job name [\#516](https://github.com/fission/fission/pull/516) ([soamvasani](https://github.com/soamvasani))
|
||||
- Fix CLI not update function's secret/configmap correctly [\#512](https://github.com/fission/fission/pull/512) ([life1347](https://github.com/life1347))
|
||||
- Adds latest tags and pushes to dockerhub for fetcher and fission-bundle [\#509](https://github.com/fission/fission/pull/509) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Fixes the backward compatibility with older environment versions [\#508](https://github.com/fission/fission/pull/508) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Update Fn: Executor New Deployment [\#504](https://github.com/fission/fission/pull/504) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Adds default resources for fetcher pod [\#500](https://github.com/fission/fission/pull/500) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Documentation Revamp [\#496](https://github.com/fission/fission/pull/496) ([vishal-biyani](https://github.com/vishal-biyani))
|
||||
- Delete and list orphan pkgs [\#468](https://github.com/fission/fission/pull/468) ([smruthi2187](https://github.com/smruthi2187))
|
||||
- Service type ClusterIP - Controller port forward through CLI [\#431](https://github.com/fission/fission/pull/431) ([prithviramesh](https://github.com/prithviramesh))
|
||||
- Istio integration [\#421](https://github.com/fission/fission/pull/421) ([life1347](https://github.com/life1347))
|
||||
- Implement support for Azure storage message queue triggers [\#371](https://github.com/fission/fission/pull/371) ([peterhuene](https://github.com/peterhuene))
|
||||
|
||||
## [0.5.0](https://github.com/fission/fission/tree/0.5.0) (2018-02-07)
|
||||
[Full Changelog](https://github.com/fission/fission/compare/0.4.1...0.5.0)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# Multi-tenancy in Fission
|
||||
|
||||
Multi-tenancy in Fission allows users to create Fission objects, i.e functions, packages, environments and triggers in different namespaces.
|
||||
It mandates that a function reference secrets, configmaps and its package (if explicity referenced during function creation/updation) to be present in the same namespace as the function.
|
||||
This allows user separation and prevents in-advertent access to sensitive data of other users sharing the same cluster.
|
||||
However, users are allowed and encouraged to share environments to ensure optimal utilization of cluster resources. To achieve this, users can create all the necessary environments in a ns, say ns1 and then go on to create functions in different namespaces and refer to env in ns1.
|
||||
Users that prefer complete isolation can create their env, functions in the same ns.
|
||||
|
||||
## Roles and privileges
|
||||
|
||||
1. Cluster-Admin Role : Fission's services need cluster-admin privileges to monitor, create, update and delete resources across namespaces.
|
||||
2. Package-getter Role : This role has privileges to do a get, watch and list on fission package objects.
|
||||
3. Secret-Configmap-getter Role : This role has privileges to do a get, watch and list on secrets and configmaps.
|
||||
|
||||
## Service Accounts
|
||||
|
||||
1. fission-fetcher
|
||||
|
||||
This SA is created in every namespace that a user creates runtime environments in.
|
||||
Also created in function namespaces where a user creates functions that use NewDeploy executor backend.
|
||||
|
||||
2. fission-builder
|
||||
|
||||
This SA is created in every namespace that a user creates builder environments in.
|
||||
|
||||
## Role-bindings
|
||||
|
||||
1. Package-getter-binding
|
||||
|
||||
Every time a user creates a package explicity in a namespace, this rolebinding is created in package's namespace (which is also function's namespace). This grants package-getter role to fission-fetcher SA present in the referenced environment's namespace.
|
||||
If the package is a source package, then, fission-builder SA present in the environment namespace is also added to this rolebinding.
|
||||
|
||||
Next when the user creates a function in the same namespace, if the function's executor type is newdeploy, then, the fission-fetcher SA present in function namespace is also added to the same rolebinding.
|
||||
|
||||
Note : For functions that have executor type poolmgr, the env pods are created in the namespace that env object is created. Whereas, for those functions that have executor type New deploy mgr, the function pods are created in the namespace that function object is created in.
|
||||
|
||||
This is because, poolmgr allows env sharing and optimal resource utilization. so generic env pools are created in a different namespace and all functions that prefer sharing this env pool can reference these pools.
|
||||
If users require strict isolation, they can either create functions with new deploy backend, or, create env's in different namespaces and not share them across functions.
|
||||
|
||||
2. Secret-Configmap-getter-binding
|
||||
|
||||
Every time a user creates a function in a namespace, Secret-Configmap-getter-binding is created in the same namespace, granting secret-configmap-getter role to fission-fetcher SA present in the referenced environment's namespace in case the executor type is poolmgr.
|
||||
If the executor type is newdeploymgr, then the same rolebinding is created in the same namespace as the function, granting the same secret-configmap-getter role to fission-fetcher SA present in the function namespace.
|
||||
|
||||
## Examples
|
||||
|
||||
1. create a generic python runtime env in ns 1 and function with poolmgr executor type in ns 2 that references it.
|
||||
|
||||
```bash
|
||||
$ fission env create --name python --image fission/python-env --envns ns1
|
||||
$ fission function create --name func1 --env python --code hello.py --fns ns2
|
||||
```
|
||||
|
||||
2. create a builder and runtime environment in ns3, a source pkg in ns3 and a function referring to this src pkg also in ns3. (for complete isolation, all objs are in ns3)
|
||||
|
||||
```bash
|
||||
$ fission env create --name python-builder-env --builder fission/python-builder --image fission/python-env --ns3
|
||||
$ fission package create --src src-pkg.zip --env python-builder-env --buildcmd "./build.sh" --pkgns ns3
|
||||
$ fission fn create --name func3 --fns ns3 --pkg $pkg --entrypoint "user.main"
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
1. To maintain backward compatibility, fission objects that are created without the ns flags are created in default namespace. Also, the run time env pods in such a case will continue to live in fission-function ns and builder env pods in fission-builder ns
|
||||
2. Since all envs in a namespace have the same fission-fetcher SA mounted in them, even though multiple envs are created in a namespace and referenced by functions in different namespaces, the SA will have previleges to view those function's secrets if any.
|
||||
3. Similarly, if there are multiple functions in different namespaces but all sharing an env in one namespace, the fission-fetcher SA in that namespace will have previleges to see all of their secrets.
|
||||
@@ -0,0 +1,128 @@
|
||||
# Fission CLI Extensibility
|
||||
|
||||
### Approach
|
||||
To sum up the approach: git-style plugins.
|
||||
|
||||
Plugins are named with the fission prefix `fission-*`. When fission is invoked with an undefined/non-core subcommand
|
||||
is called (like `fission foo`). Fission will look in the PATH
|
||||
|
||||
**Installing Fission**
|
||||
```bash
|
||||
# The same as before
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.7.2/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||
```
|
||||
|
||||
**Installing Fission Workflows**
|
||||
```bash
|
||||
# The same process as Fission cli itself
|
||||
$ curl -Lo fission https://github.com/fission/fission-workflows/releases/download/0.4.0/fission-workflows-osx && chmod +x fission-workflows && sudo mv fission-workflows /usr/local/bin/
|
||||
```
|
||||
|
||||
**Invoking Fission Workflows**
|
||||
```bash
|
||||
$ fission workflows invocation get b1278e802a
|
||||
# Which is equivalent to:
|
||||
$ fission-workflows invocation get b1278e802a
|
||||
```
|
||||
General flow:
|
||||
1. fission does not recognize `workflows` subcommand
|
||||
2. fission checks the path for a binary called `fission-workflows`
|
||||
3. fission finds the binary.
|
||||
4. fission invokes the `fission-workflows`, passing the remainder of the arguments.
|
||||
|
||||
**Discoverability: fission --help**
|
||||
```bash
|
||||
$ fission --help
|
||||
USAGE:
|
||||
fission [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
0.6.0
|
||||
|
||||
COMMANDS:
|
||||
function, fn Create, update and manage functions
|
||||
httptrigger, ht, route Manage HTTP triggers (routes) for functions
|
||||
timetrigger, tt, timer Manage Time triggers (timers) for functions
|
||||
mqtrigger, mqt, messagequeue Manage message queue triggers for functions
|
||||
environment, env Manage environments
|
||||
watch, w Manage watches
|
||||
package, pkg Manage packages
|
||||
spec, specs Manage a declarative app specification
|
||||
upgrade Upgrade tool from fission v0.1
|
||||
tpr2crd Migrate tool for TPR to CRD
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
PLUGINS:
|
||||
workflows, wf Inspect and manage workflow executions
|
||||
ui Start the user interface
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--server value Fission server URL (default: "http://127.0.0.1:65356")
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
Of course Fission needs to be able to find all plugins for this. There are several ways in which we can provide discoverability. The simplest one is for Fission to look in the path for all binaries starting with the `fission-*` prefix. Optionally, fission could invoke a specific command on the subcommand to get info about the plugin (such as version, help text, aliases...)
|
||||
|
||||
With Fission Workflows this info would look something like this:
|
||||
```bash
|
||||
$ fission-workflows --plugin
|
||||
name: workflows
|
||||
version: 0.4.0
|
||||
help: Inspect and manage workflow executions
|
||||
```
|
||||
The idea is that this plugin info is all completely optional.
|
||||
If it is not available, we simply degrade the results to user.
|
||||
This way users/we can easily prototype or add plugins without having to worry about adhering to some interface.
|
||||
|
||||
**List version**
|
||||
```bash
|
||||
$ fission --version
|
||||
client:
|
||||
fission: 0.8.0
|
||||
fission-workflows: 0.4.0
|
||||
server:
|
||||
fission: 0.8.1
|
||||
fission-workflows: 0.3.0
|
||||
```
|
||||
Again, versioning info for fission-workflows is taken from the plugin info of the commands.
|
||||
Note: a related issue is to have some more formalized plugin support/discoverability on the server-side,
|
||||
but that is out of the scope of this issue.
|
||||
|
||||
### Other (optional) extensions and notes
|
||||
- Like git we could setup a preferred binary path, where fission looks first when searching for the subcommand.
|
||||
This could optionally be defined with a `FISSION_EXEC_PATH`.
|
||||
- With the current approach we cannot have aliases for commands---fission will not be able to find fission-workflows
|
||||
when the user calls `fission wf`. This might be UX issue, with these long path names. One option is let the user fix
|
||||
it themselves by symlinking `fission-wf` to `fission-workflows`; using the plugin info Fission can recognize and
|
||||
merge aliases together.
|
||||
- To help detect versioning conflicts (old version of fission, too new version of fission workflows). We could add
|
||||
a `requires` field to the fission-workflows plugin info. Then we could throw a warning or error, when two out of sync
|
||||
versions are being used.
|
||||
- To avoid unhelpful errors to the user when they have not installed a plugin, we could add a heuristic to check
|
||||
`https://github.com/fission/SUBCOMMAND` to see if the subcommand might be an uninstalled plugin.
|
||||
OR, we could lookup a simple text file that contains common plugins `https://github.com/fission/fission/plugins.txt`
|
||||
and list them as suggestions to the user. OR we could of course just default to a bit help text that says something
|
||||
like `unknown subcommand 'foo'. If this is a plugin, ensure that it is present on your PATH`.
|
||||
|
||||
---
|
||||
|
||||
### Motivation
|
||||
|
||||
The proposed approach is to use the git-based plugin system for now. Reasons for this approach over a sophisticated,
|
||||
integrated plugin-based approach:
|
||||
- It is low effort to implement.
|
||||
- It is easy to extend with minimal to no required interface.
|
||||
- The binaries remain standalone, allowing users to separate them if needed and make independent development on the
|
||||
binaries easy.
|
||||
|
||||
Limitations of the proposed approach:
|
||||
- The user still has to do some work, adding binaries to the PATH; ensuring that permissions are correct; ensuring
|
||||
that the binary is executable; how to deal with duplicate binaries on the PATH. All this makes this approach assume
|
||||
basic/intermediate knowledge of the OS from the user.
|
||||
- I have to admit: I am not entirely sure if this approach requires any changes for Windows. Probably not.
|
||||
- Upgrading fission with many plugins could be cumbersome, as you would need to upgrade each binary one by one.
|
||||
Improving this is probably best left to future work.
|
||||
|
||||
|
||||
The more heavyweight solution solves some of these limitations to an extent, but these do not way up to the increased
|
||||
development and maintainance cost IMO. If needed we could explore this option (or some hybrid option) in the future.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Java Environment : Design & considerations
|
||||
|
||||
This document documents the design and thoughts that lead to design of Java environment. Before we dive deeper, some important points:
|
||||
|
||||
- When we say Java, we really mean JVM. That does not mean that all languages will work seamlessly, so support will be added gradually based on validation. Some of popular languages as of today are:
|
||||
- Scala
|
||||
- Groovy
|
||||
- Kotlin (Server side with Spring)
|
||||
|
||||
- In Java there are a few prominent frameworks which have a ecosystem of their own (See list below). How these framework fit in the environment will be detailed later, but it is important to understand their place in ecosystem and design for it.
|
||||
- A large percentage of entertprise developers use [Spring framework](https://spring.io/) as has been shown by multiple surveys
|
||||
- Reactive has taken up recently with data intensive operations [Reactive extensions for JVM](https://github.com/ReactiveX/RxJava)
|
||||
- [Spark](http://sparkjava.com/) is a micro web framework
|
||||
|
||||
A draft implementation of the Java environment design is in the branch [java_env_alpha](https://github.com/fission/fission/tree/java_env_alpha). Also a earlier implementation based on Vort.x framework [can be found here](https://github.com/tobias/fission-java-env/)
|
||||
|
||||
## Function interface
|
||||
|
||||
The goal is here is to minimize the lock in for the user into any framework as much as possible. Java 8 introduced an interface called ```Function``` which could be a great fit here. The user has to implement the ```Function<T, R>``` class and to meet the contract implement the apply method:
|
||||
|
||||
```
|
||||
public class HelloWorld implements Function<T, R> {
|
||||
|
||||
public R apply(T str) {
|
||||
|
||||
```
|
||||
|
||||
Now - the T & R could be different things and we discuss some options below:
|
||||
|
||||
### Body in request and response
|
||||
|
||||
From the early implementation in the branch mentioned above, the environment extracts the body and send it as a JSON string. The JSON then can be transformed into the appropriate object by the function.
|
||||
|
||||
This works well, but has one major limitation: the function does not get access to other things like headers etc. The same thing applies to the reponse: function can send the body but looses control over status code etc.
|
||||
|
||||
### HttpServletRequest and HttpServletResponse
|
||||
|
||||
It is possible to send the [HttpServeletRequest](https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html) request object as it is to the function class but then the interface becomes a bit too low level. For example the function user has to retrieve the body of request using ```getInputStream``` which gives raw input stream and needs additional work.
|
||||
|
||||
Also most enterprise applications today use a framework of some sort for web applications instead of dealing with the raw HttpServlet
|
||||
|
||||
### Custom/Context Object
|
||||
|
||||
A custom object which encapsulates all needed fields etc. can be used to pass the data from environment to the function. But this means the user has to import a Fission object/library for this object in the application code.
|
||||
|
||||
This approach has been taken in the implementation done earlier for a Java environment in Fission and [object interface can be found here](https://github.com/tobias/fission-java-env/blob/master/src/main/java/io/fission/api/Context.java). Related discussion is in the [issue](https://github.com/fission/fission/issues/91)
|
||||
|
||||
AWS Lambda also uses a context object, but the purpose is very different, [details of context object here](https://docs.aws.amazon.com/lambda/latest/dg/java-context-object.html).
|
||||
|
||||
### Spring's HttpEntity
|
||||
|
||||
If we have to depend on a class/library, it is probably better to depend on a class which is part of ecosystem. So instead of using the low level interface of Servlet, we can use [HttpEntity's subclasses RequestEntity and ResponseEntity](https://docs.spring.io/spring/docs/5.0.5.RELEASE/javadoc-api/org/springframework/http/HttpEntity.html). This ensures that the function user is not locked in the Fission object contract, but also gets the full access to request/response object.
|
||||
|
||||
The Spring cloud function project also discusses the issue of not having access to other things in request and [related issues are here](https://github.com/spring-cloud/spring-cloud-function/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+header)
|
||||
|
||||
### Thoughts
|
||||
|
||||
- If we only intend to pass request/response object to function - then using HttpEntity might be a good choice
|
||||
|
||||
- If there is a need for additional exchange of information between the environment and function execution in future, then a custom/context object is a better option. We can wrap the HttpEntity's fields and additional fields in the custom context object
|
||||
|
||||
## Environment Design
|
||||
|
||||
JVM environment design is based on Spring boot and Spring MVC frameworks. The details can be found in branch, but here are some key points:
|
||||
|
||||
- All classes in the function and dependent classes are loaded into JVM. Which means the user should supply the uber/fat jar for execution.
|
||||
- The entrypoint class is specified by the user as ```entrypoint``` flag on the class. The method is by convention (```apply``` as per the Function interface contract)
|
||||
@@ -0,0 +1,62 @@
|
||||
# Fission Support Tool
|
||||
Fission now has rich functionality supported by multiple services, however, it brings the complexity of troubleshooting.
|
||||
This proposal tends to give a picture of fission support tool that can help both user and developer to locate the problem in short time.
|
||||
To achieve this, the support tool will dump related kubernetes objects, fission resources and pod logs from the given cluster.
|
||||
|
||||
# Functionality
|
||||
|
||||
## Environment Information Collection
|
||||
|
||||
Before troubleshooting, some of the basic information is needed to give others an overview of kubernetes/fission user test with so that we can locate the problem in short time.
|
||||
|
||||
* Fission version
|
||||
* Client/Server version
|
||||
|
||||
* Kubernetes cluster version
|
||||
* Cluster version (i.e v1.9.7-gke.0)
|
||||
* Running environment (i.e GKE, AKS and minikube)
|
||||
* Nodes version and other information
|
||||
|
||||
## Service Logs Collection
|
||||
|
||||
The component logs and the logs of interaction between components are important for people to understand what really happened in cluster. Following are components need to collect logs from.
|
||||
|
||||
* All fission component pods
|
||||
* Function pods
|
||||
* Builder pods
|
||||
* Environment pods
|
||||
|
||||
## Object dumping
|
||||
|
||||
Fission is deeply coupled with Kubernetes, most of the objects are created and maintained by it. There is two major type of objects need to be dumped from kubernetes:
|
||||
|
||||
* K8S objects
|
||||
* CRD resources
|
||||
|
||||
All objects should be dumped into a readable file format. It will be great if people can reproduce similar environment with these files.
|
||||
|
||||
## Information upload
|
||||
|
||||
Upload dump files to the specific backend server for support channel to analysis
|
||||
|
||||
# CLI Interface
|
||||
|
||||
```
|
||||
$ fission support collect
|
||||
NAME:
|
||||
fission support collect - Collect pod logs, fission resources and related kubernetes objects for troubleshooting
|
||||
|
||||
USAGE:
|
||||
fission support collect [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--dumpdir value Directory to save dump kubernetes objects and fission resources (default: "fission-dump")
|
||||
--fissionns value Namespace of fission installation (default: "fission")
|
||||
--builderns value Namespace of fission package builder (default: "fission-builder")
|
||||
--funcns value Namespace of fission function pod (default: "fission-function")
|
||||
```
|
||||
|
||||
# Thoughts?
|
||||
|
||||
1. What to do with sensitive objects like secrets and configmap? Ignore the dump for such objects?
|
||||
2. The functionality is necessary but not listed above?
|
||||
@@ -53,6 +53,7 @@ The following environments are currently available:
|
||||
| ------------------------------------ | ------------------------- |
|
||||
| Binary (for executables or scripts) | `fission/binary-env` |
|
||||
| Go | `fission/go-env` |
|
||||
| JVM | `fission/jvm-env` |
|
||||
| .NET | `fission/dotnet-env` |
|
||||
| .NET 2.0 | `fission/dotnet20-env` |
|
||||
| NodeJS (Alpine) | `fission/node-env` |
|
||||
@@ -97,12 +98,12 @@ See the [examples](examples) directory for more.
|
||||
Running Fission on your Cluster
|
||||
===============================
|
||||
|
||||
See the [installation guide](http://docs.fission.io/latest/installation).
|
||||
See the [installation guide](https://docs.fission.io/latest/installation).
|
||||
|
||||
Compiling Fission
|
||||
=================
|
||||
|
||||
See the [compilation guide](http://docs.fission.io/latest/contributing/compiling/).
|
||||
See the [compilation guide](https://docs.fission.io/latest/contributing/).
|
||||
|
||||
Status
|
||||
======
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ func MakeBuilder(sharedVolumePath string) *Builder {
|
||||
|
||||
func (builder *Builder) VersionHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
fmt.Fprintf(w, fission.VersionInfo().String())
|
||||
fmt.Fprintf(w, fission.BuildInfo().String())
|
||||
}
|
||||
|
||||
func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -40,8 +40,8 @@ func Start(storageSvcUrl string, envBuilderNamespace string) error {
|
||||
go envWatcher.watchEnvironments()
|
||||
|
||||
pkgWatcher := makePackageWatcher(fissionClient,
|
||||
kubernetesClient.CoreV1().RESTClient(), envBuilderNamespace, storageSvcUrl)
|
||||
go pkgWatcher.watchPackages()
|
||||
kubernetesClient, envBuilderNamespace, storageSvcUrl)
|
||||
go pkgWatcher.watchPackages(fissionClient, kubernetesClient, envBuilderNamespace)
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
+13
-11
@@ -22,8 +22,6 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/dchest/uniuri"
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/builder"
|
||||
@@ -40,25 +38,26 @@ import (
|
||||
// 3. Send upload request to fetcher to upload deployment package.
|
||||
// 4. Return upload response and build logs.
|
||||
// *. Return build logs and error if any one of steps above failed.
|
||||
func buildPackage(fissionClient *crd.FissionClient, builderNamespace string,
|
||||
func buildPackage(fissionClient *crd.FissionClient, envBuilderNamespace string,
|
||||
storageSvcUrl string, pkg *crd.Package) (uploadResp *fetcher.UploadResponse, buildLogs string, err error) {
|
||||
|
||||
env, err := fissionClient.Environments(metav1.NamespaceDefault).Get(pkg.Spec.Environment.Name)
|
||||
env, err := fissionClient.Environments(pkg.Spec.Environment.Namespace).Get(pkg.Spec.Environment.Name)
|
||||
if err != nil {
|
||||
e := fmt.Sprintf("Error getting environment CRD info: %v", err)
|
||||
log.Println(e)
|
||||
return nil, e, fission.MakeError(http.StatusInternalServerError, e)
|
||||
}
|
||||
|
||||
svcName := fmt.Sprintf("%v-%v.%v", env.Metadata.Name, env.Metadata.ResourceVersion, builderNamespace)
|
||||
svcName := fmt.Sprintf("%v-%v.%v", env.Metadata.Name, env.Metadata.ResourceVersion, envBuilderNamespace)
|
||||
srcPkgFilename := fmt.Sprintf("%v-%v", pkg.Metadata.Name, strings.ToLower(uniuri.NewLen(6)))
|
||||
fetcherC := fetcherClient.MakeClient(fmt.Sprintf("http://%v:8000", svcName))
|
||||
builderC := builderClient.MakeClient(fmt.Sprintf("http://%v:8001", svcName))
|
||||
|
||||
fetchReq := &fetcher.FetchRequest{
|
||||
FetchType: fetcher.FETCH_SOURCE,
|
||||
Package: pkg.Metadata,
|
||||
Filename: srcPkgFilename,
|
||||
FetchType: fetcher.FETCH_SOURCE,
|
||||
Package: pkg.Metadata,
|
||||
Filename: srcPkgFilename,
|
||||
KeepArchive: false,
|
||||
}
|
||||
|
||||
// send fetch request to fetcher
|
||||
@@ -95,9 +94,12 @@ func buildPackage(fissionClient *crd.FissionClient, builderNamespace string,
|
||||
|
||||
log.Printf("Build succeed, source package: %v, deployment package: %v", srcPkgFilename, buildResp.ArtifactFilename)
|
||||
|
||||
archivePackage := !env.Spec.KeepArchive
|
||||
|
||||
uploadReq := &fetcher.UploadRequest{
|
||||
Filename: buildResp.ArtifactFilename,
|
||||
StorageSvcUrl: storageSvcUrl,
|
||||
Filename: buildResp.ArtifactFilename,
|
||||
StorageSvcUrl: storageSvcUrl,
|
||||
ArchivePackage: archivePackage,
|
||||
}
|
||||
|
||||
log.Printf("Start uploading deployment package: %v", buildResp.ArtifactFilename)
|
||||
@@ -131,7 +133,7 @@ func updatePackage(fissionClient *crd.FissionClient,
|
||||
}
|
||||
|
||||
// update package spec
|
||||
pkg, err := fissionClient.Packages(metav1.NamespaceDefault).Update(pkg)
|
||||
pkg, err := fissionClient.Packages(pkg.Metadata.Namespace).Update(pkg)
|
||||
if err != nil {
|
||||
log.Printf("Error updating package: %v", err)
|
||||
return nil, err
|
||||
|
||||
+106
-49
@@ -23,13 +23,13 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
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"
|
||||
"github.com/fission/fission/crd"
|
||||
@@ -42,7 +42,10 @@ const (
|
||||
CLEANUP_BUILDERS
|
||||
|
||||
LABEL_ENV_NAME = "envName"
|
||||
LABEL_ENV_NAMESPACE = "envNamespace"
|
||||
LABEL_ENV_RESOURCEVERSION = "envResourceVersion"
|
||||
LABEL_DEPLOYMENT_OWNER = "owner"
|
||||
BUILDER_MGR = "buildermgr"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -130,14 +133,22 @@ func makeEnvironmentWatcher(fissionClient *crd.FissionClient,
|
||||
return envWatcher
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) getCacheKey(envName string, envResourceVersion string) string {
|
||||
return fmt.Sprintf("%v-%v", envName, envResourceVersion)
|
||||
func (envw *environmentWatcher) getCacheKey(envName string, envNamespace string, envResourceVersion string) string {
|
||||
return fmt.Sprintf("%v-%v-%v", envName, envNamespace, envResourceVersion)
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) getLabels(envName string, envResourceVersion string) map[string]string {
|
||||
func (env *environmentWatcher) getLabelForDeploymentOwner() map[string]string {
|
||||
return map[string]string{
|
||||
LABEL_DEPLOYMENT_OWNER: BUILDER_MGR,
|
||||
}
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) getLabels(envName string, envNamespace string, envResourceVersion string) map[string]string {
|
||||
return map[string]string{
|
||||
LABEL_ENV_NAME: envName,
|
||||
LABEL_ENV_NAMESPACE: envNamespace,
|
||||
LABEL_ENV_RESOURCEVERSION: envResourceVersion,
|
||||
LABEL_DEPLOYMENT_OWNER: BUILDER_MGR,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,10 +224,17 @@ func (envw *environmentWatcher) service() {
|
||||
req := <-envw.requestChan
|
||||
switch req.requestType {
|
||||
case GET_BUILDER:
|
||||
key := envw.getCacheKey(req.env.Metadata.Name, req.env.Metadata.ResourceVersion)
|
||||
// In order to support backward compatibility, for all environments with builder image created in default env,
|
||||
// the pods will be created in fission-builder namespace
|
||||
ns := envw.builderNamespace
|
||||
if req.env.Metadata.Namespace != metav1.NamespaceDefault {
|
||||
ns = req.env.Metadata.Namespace
|
||||
}
|
||||
|
||||
key := envw.getCacheKey(req.env.Metadata.Name, ns, req.env.Metadata.ResourceVersion)
|
||||
builderInfo, ok := envw.cache[key]
|
||||
if !ok {
|
||||
builderInfo, err := envw.createBuilder(req.env)
|
||||
builderInfo, err := envw.createBuilder(req.env, ns)
|
||||
if err != nil {
|
||||
req.respChan <- envwResponse{err: err}
|
||||
continue
|
||||
@@ -229,7 +247,13 @@ func (envw *environmentWatcher) service() {
|
||||
latestEnvList := make(map[string]*crd.Environment)
|
||||
for i := range req.envList {
|
||||
env := req.envList[i]
|
||||
key := envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||
// In order to support backward compatibility, for all builder images created in default
|
||||
// env, the pods are created in fission-builder namespace
|
||||
ns := envw.builderNamespace
|
||||
if env.Metadata.Namespace != metav1.NamespaceDefault {
|
||||
ns = env.Metadata.Namespace
|
||||
}
|
||||
key := envw.getCacheKey(env.Metadata.Name, ns, env.Metadata.ResourceVersion)
|
||||
latestEnvList[key] = &env
|
||||
}
|
||||
|
||||
@@ -239,38 +263,40 @@ func (envw *environmentWatcher) service() {
|
||||
// cache and CRD. We need to iterate over the services &
|
||||
// deployments to remove both normal and orphan builders.
|
||||
|
||||
svcList, err := envw.getBuilderServiceList(nil)
|
||||
svcList, err := envw.getBuilderServiceList(envw.getLabelForDeploymentOwner(), metav1.NamespaceAll)
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
for _, svc := range svcList {
|
||||
envName := svc.ObjectMeta.Labels[LABEL_ENV_NAME]
|
||||
envNamespace := svc.ObjectMeta.Labels[LABEL_ENV_NAMESPACE]
|
||||
envResourceVersion := svc.ObjectMeta.Labels[LABEL_ENV_RESOURCEVERSION]
|
||||
key := envw.getCacheKey(envName, envResourceVersion)
|
||||
key := envw.getCacheKey(envName, envNamespace, envResourceVersion)
|
||||
if _, ok := latestEnvList[key]; !ok {
|
||||
err := envw.deleteBuilderService(svc.ObjectMeta.Labels)
|
||||
err := envw.deleteBuilderServiceByName(svc.ObjectMeta.Name, svc.ObjectMeta.Namespace)
|
||||
if err != nil {
|
||||
log.Printf("Error removing builder service: %v", err)
|
||||
}
|
||||
}
|
||||
delete(envw.cache, svc.ObjectMeta.Name)
|
||||
delete(envw.cache, key)
|
||||
}
|
||||
|
||||
deployList, err := envw.getBuilderDeploymentList(nil)
|
||||
deployList, err := envw.getBuilderDeploymentList(envw.getLabelForDeploymentOwner(), metav1.NamespaceAll)
|
||||
if err != nil {
|
||||
log.Printf(err.Error())
|
||||
}
|
||||
for _, deploy := range deployList {
|
||||
envName := deploy.ObjectMeta.Labels[LABEL_ENV_NAME]
|
||||
envNamespace := deploy.ObjectMeta.Labels[LABEL_ENV_NAMESPACE]
|
||||
envResourceVersion := deploy.ObjectMeta.Labels[LABEL_ENV_RESOURCEVERSION]
|
||||
key := envw.getCacheKey(envName, envResourceVersion)
|
||||
key := envw.getCacheKey(envName, envNamespace, envResourceVersion)
|
||||
if _, ok := latestEnvList[key]; !ok {
|
||||
err := envw.deleteBuilderDeployment(deploy.ObjectMeta.Labels)
|
||||
err := envw.deleteBuilderDeploymentByName(deploy.ObjectMeta.Name, deploy.ObjectMeta.Namespace)
|
||||
if err != nil {
|
||||
log.Printf("Error removing builder deployment: %v", err)
|
||||
}
|
||||
}
|
||||
delete(envw.cache, deploy.ObjectMeta.Name)
|
||||
delete(envw.cache, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,19 +320,19 @@ func (envw *environmentWatcher) cleanupEnvBuilders(envs []crd.Environment) {
|
||||
}
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) createBuilder(env *crd.Environment) (*builderInfo, error) {
|
||||
func (envw *environmentWatcher) createBuilder(env *crd.Environment, ns string) (*builderInfo, error) {
|
||||
var svc *apiv1.Service
|
||||
var deploy *v1beta1.Deployment
|
||||
|
||||
sel := envw.getLabels(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||
sel := envw.getLabels(env.Metadata.Name, ns, env.Metadata.ResourceVersion)
|
||||
|
||||
svcList, err := envw.getBuilderServiceList(sel)
|
||||
svcList, err := envw.getBuilderServiceList(sel, ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// there should be only one service in svcList
|
||||
if len(svcList) == 0 {
|
||||
svc, err = envw.createBuilderService(env)
|
||||
svc, err = envw.createBuilderService(env, ns)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error creating builder service: %v", err)
|
||||
}
|
||||
@@ -316,13 +342,20 @@ func (envw *environmentWatcher) createBuilder(env *crd.Environment) (*builderInf
|
||||
return nil, fmt.Errorf("Found more than one builder service for environment %v", env.Metadata.Name)
|
||||
}
|
||||
|
||||
deployList, err := envw.getBuilderDeploymentList(sel)
|
||||
deployList, err := envw.getBuilderDeploymentList(sel, ns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// there should be only one deploy in deployList
|
||||
if len(deployList) == 0 {
|
||||
deploy, err = envw.createBuilderDeployment(env)
|
||||
// create builder SA in this ns, if not already created
|
||||
_, err := fission.SetupSA(envw.kubernetesClient, fission.FissionBuilderSA, ns)
|
||||
if err != nil {
|
||||
log.Printf("Error : %v creating %s in ns : %s", err, fission.FissionBuilderSA, ns)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deploy, err = envw.createBuilderDeployment(env, ns)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error creating builder deployment: %v", err)
|
||||
}
|
||||
@@ -339,16 +372,36 @@ func (envw *environmentWatcher) createBuilder(env *crd.Environment) (*builderInf
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) deleteBuilderService(sel map[string]string) error {
|
||||
svcList, err := envw.getBuilderServiceList(sel)
|
||||
func (envw *environmentWatcher) deleteBuilderServiceByName(name, namespace string) error {
|
||||
err := envw.kubernetesClient.CoreV1().
|
||||
Services(namespace).
|
||||
Delete(name, &delOpt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting builder service %s.%s: %v", name, namespace, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) deleteBuilderDeploymentByName(name, namespace string) error {
|
||||
err := envw.kubernetesClient.ExtensionsV1beta1().
|
||||
Deployments(namespace).
|
||||
Delete(name, &delOpt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting builder deployment %s.%s: %v", name, namespace, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) deleteBuilderService(sel map[string]string, ns string) error {
|
||||
svcList, err := envw.getBuilderServiceList(sel, ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, svc := range svcList {
|
||||
log.Printf("Removing builder service: %v", svc.ObjectMeta.Name)
|
||||
err = envw.kubernetesClient.
|
||||
Services(envw.builderNamespace).
|
||||
Delete(svc.ObjectMeta.Name, nil)
|
||||
err = envw.kubernetesClient.CoreV1().
|
||||
Services(ns).
|
||||
Delete(svc.ObjectMeta.Name, &delOpt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting builder service: %v", err)
|
||||
}
|
||||
@@ -356,15 +409,15 @@ func (envw *environmentWatcher) deleteBuilderService(sel map[string]string) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) deleteBuilderDeployment(sel map[string]string) error {
|
||||
deployList, err := envw.getBuilderDeploymentList(sel)
|
||||
func (envw *environmentWatcher) deleteBuilderDeployment(sel map[string]string, ns string) error {
|
||||
deployList, err := envw.getBuilderDeploymentList(sel, ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, deploy := range deployList {
|
||||
log.Printf("Removing builder deployment: %v", deploy.ObjectMeta.Name)
|
||||
err = envw.kubernetesClient.ExtensionsV1beta1().
|
||||
Deployments(envw.builderNamespace).
|
||||
Deployments(ns).
|
||||
Delete(deploy.ObjectMeta.Name, &delOpt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleteing builder deployment: %v", err)
|
||||
@@ -373,8 +426,8 @@ func (envw *environmentWatcher) deleteBuilderDeployment(sel map[string]string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string) ([]apiv1.Service, error) {
|
||||
svcList, err := envw.kubernetesClient.Services(envw.builderNamespace).List(
|
||||
func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string, ns string) ([]apiv1.Service, error) {
|
||||
svcList, err := envw.kubernetesClient.CoreV1().Services(ns).List(
|
||||
metav1.ListOptions{
|
||||
LabelSelector: labels.Set(sel).AsSelector().String(),
|
||||
})
|
||||
@@ -384,12 +437,12 @@ func (envw *environmentWatcher) getBuilderServiceList(sel map[string]string) ([]
|
||||
return svcList.Items, nil
|
||||
}
|
||||
|
||||
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)
|
||||
func (envw *environmentWatcher) createBuilderService(env *crd.Environment, ns string) (*apiv1.Service, error) {
|
||||
name := fmt.Sprintf("%v-%v", env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||
sel := envw.getLabels(env.Metadata.Name, ns, env.Metadata.ResourceVersion)
|
||||
service := apiv1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: envw.builderNamespace,
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
Labels: sel,
|
||||
},
|
||||
@@ -419,15 +472,15 @@ func (envw *environmentWatcher) createBuilderService(env *crd.Environment) (*api
|
||||
},
|
||||
}
|
||||
log.Printf("Creating builder service: %v", name)
|
||||
_, err := envw.kubernetesClient.Services(envw.builderNamespace).Create(&service)
|
||||
_, err := envw.kubernetesClient.CoreV1().Services(ns).Create(&service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &service, nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) getBuilderDeploymentList(sel map[string]string) ([]v1beta1.Deployment, error) {
|
||||
deployList, err := envw.kubernetesClient.ExtensionsV1beta1().Deployments(envw.builderNamespace).List(
|
||||
func (envw *environmentWatcher) getBuilderDeploymentList(sel map[string]string, ns string) ([]v1beta1.Deployment, error) {
|
||||
deployList, err := envw.kubernetesClient.ExtensionsV1beta1().Deployments(ns).List(
|
||||
metav1.ListOptions{
|
||||
LabelSelector: labels.Set(sel).AsSelector().String(),
|
||||
})
|
||||
@@ -437,22 +490,25 @@ func (envw *environmentWatcher) getBuilderDeploymentList(sel map[string]string)
|
||||
return deployList.Items, nil
|
||||
}
|
||||
|
||||
func (envw *environmentWatcher) createBuilderDeployment(env *crd.Environment) (*v1beta1.Deployment, error) {
|
||||
func (envw *environmentWatcher) createBuilderDeployment(env *crd.Environment, ns string) (*v1beta1.Deployment, error) {
|
||||
sharedMountPath := "/packages"
|
||||
sharedCfgMapPath := "/configs"
|
||||
sharedSecretPath := "/secrets"
|
||||
name := envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||
sel := envw.getLabels(env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||
name := fmt.Sprintf("%v-%v", env.Metadata.Name, env.Metadata.ResourceVersion)
|
||||
sel := envw.getLabels(env.Metadata.Name, ns, env.Metadata.ResourceVersion)
|
||||
var replicas int32 = 1
|
||||
|
||||
podAnnotation := make(map[string]string)
|
||||
podAnnotations := env.Metadata.Annotations
|
||||
if podAnnotations == nil {
|
||||
podAnnotations = make(map[string]string)
|
||||
}
|
||||
if envw.useIstio && env.Spec.AllowAccessToExternalNetwork {
|
||||
podAnnotation["sidecar.istio.io/inject"] = "false"
|
||||
podAnnotations["sidecar.istio.io/inject"] = "false"
|
||||
}
|
||||
|
||||
deployment := &v1beta1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: envw.builderNamespace,
|
||||
Namespace: ns,
|
||||
Name: name,
|
||||
Labels: sel,
|
||||
},
|
||||
@@ -464,7 +520,7 @@ func (envw *environmentWatcher) createBuilderDeployment(env *crd.Environment) (*
|
||||
Template: apiv1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: sel,
|
||||
Annotations: podAnnotation,
|
||||
Annotations: podAnnotations,
|
||||
},
|
||||
Spec: apiv1.PodSpec{
|
||||
Volumes: []apiv1.Volume{
|
||||
@@ -491,7 +547,7 @@ func (envw *environmentWatcher) createBuilderDeployment(env *crd.Environment) (*
|
||||
fission.MergeContainerSpecs(&apiv1.Container{
|
||||
Name: "builder",
|
||||
Image: env.Spec.Builder.Image,
|
||||
ImagePullPolicy: apiv1.PullAlways,
|
||||
ImagePullPolicy: apiv1.PullIfNotPresent,
|
||||
TerminationMessagePath: "/dev/termination-log",
|
||||
VolumeMounts: []apiv1.VolumeMount{
|
||||
{
|
||||
@@ -565,10 +621,11 @@ func (envw *environmentWatcher) createBuilderDeployment(env *crd.Environment) (*
|
||||
},
|
||||
},
|
||||
}
|
||||
log.Printf("Creating builder deployment: %v", envw.getCacheKey(env.Metadata.Name, env.Metadata.ResourceVersion))
|
||||
_, err := envw.kubernetesClient.ExtensionsV1beta1().Deployments(envw.builderNamespace).Create(deployment)
|
||||
log.Printf("Creating builder deployment: %v", fmt.Sprintf("%v-%v", env.Metadata.Name, env.Metadata.ResourceVersion))
|
||||
_, err := envw.kubernetesClient.ExtensionsV1beta1().Deployments(ns).Create(deployment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return deployment, nil
|
||||
}
|
||||
|
||||
+37
-10
@@ -21,35 +21,38 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
k8sCache "k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/cache"
|
||||
"github.com/fission/fission/crd"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
type (
|
||||
packageWatcher struct {
|
||||
fissionClient *crd.FissionClient
|
||||
k8sClient *kubernetes.Clientset
|
||||
podStore k8sCache.Store
|
||||
pkgStore k8sCache.Store
|
||||
builderNamespace string
|
||||
storageSvcUrl string
|
||||
}
|
||||
)
|
||||
|
||||
func makePackageWatcher(fissionClient *crd.FissionClient, getter k8sCache.Getter,
|
||||
func makePackageWatcher(fissionClient *crd.FissionClient, k8sClientSet *kubernetes.Clientset,
|
||||
builderNamespace string, storageSvcUrl string) *packageWatcher {
|
||||
|
||||
lw := k8sCache.NewListWatchFromClient(getter, "pods", builderNamespace, fields.Everything())
|
||||
lw := k8sCache.NewListWatchFromClient(k8sClientSet.CoreV1().RESTClient(), "pods", metav1.NamespaceAll, fields.Everything())
|
||||
store, controller := k8sCache.NewInformer(lw, &apiv1.Pod{}, 30*time.Second, k8sCache.ResourceEventHandlerFuncs{})
|
||||
go controller.Run(make(chan struct{}))
|
||||
|
||||
pkgw := &packageWatcher{
|
||||
fissionClient: fissionClient,
|
||||
k8sClient: k8sClientSet,
|
||||
podStore: store,
|
||||
builderNamespace: builderNamespace,
|
||||
storageSvcUrl: storageSvcUrl,
|
||||
@@ -118,8 +121,16 @@ func (pkgw *packageWatcher) build(buildCache *cache.Cache, srcpkg *crd.Package)
|
||||
for _, item := range items {
|
||||
pod := item.(*apiv1.Pod)
|
||||
|
||||
// In order to support backward compatibility, for all builder images created in default env,
|
||||
// the pods will be created in fission-builder namespace
|
||||
builderNs := pkgw.builderNamespace
|
||||
if env.Metadata.Namespace != metav1.NamespaceDefault {
|
||||
builderNs = env.Metadata.Namespace
|
||||
}
|
||||
|
||||
// Filter non-matching pods
|
||||
if pod.ObjectMeta.Labels[LABEL_ENV_NAME] != env.Metadata.Name ||
|
||||
pod.ObjectMeta.Labels[LABEL_ENV_NAMESPACE] != builderNs ||
|
||||
pod.ObjectMeta.Labels[LABEL_ENV_RESOURCEVERSION] != env.Metadata.ResourceVersion {
|
||||
continue
|
||||
}
|
||||
@@ -138,8 +149,18 @@ func (pkgw *packageWatcher) build(buildCache *cache.Cache, srcpkg *crd.Package)
|
||||
break
|
||||
}
|
||||
|
||||
uploadResp, buildLogs, err := buildPackage(pkgw.fissionClient,
|
||||
pkgw.builderNamespace, pkgw.storageSvcUrl, pkg)
|
||||
// Add the package getter rolebinding to builder sa
|
||||
// we continue here if role binding was not setup succeesffully. this is because without this, the fetcher wont be able to fetch the source pkg into the container and
|
||||
// the build will fail eventually
|
||||
err := fission.SetupRoleBinding(pkgw.k8sClient, fission.PackageGetterRB, pkg.Metadata.Namespace, fission.PackageGetterCR, fission.ClusterRole, fission.FissionBuilderSA, builderNs)
|
||||
if err != nil {
|
||||
log.Printf("Error : %v in setting up the role binding %s for pkg : %s.%s", err, fission.PackageGetterRB, pkg.Metadata.Name, pkg.Metadata.Namespace)
|
||||
continue
|
||||
} else {
|
||||
log.Printf("Setup rolebinding for sa : %s.%s for pkg : %s.%s", fission.FissionBuilderSA, builderNs, pkg.Metadata.Name, pkg.Metadata.Namespace)
|
||||
}
|
||||
|
||||
uploadResp, buildLogs, err := buildPackage(pkgw.fissionClient, builderNs, pkgw.storageSvcUrl, pkg)
|
||||
if err != nil {
|
||||
log.Printf("Error building package %v: %v", pkg.Metadata.Name, err)
|
||||
updatePackage(pkgw.fissionClient, pkg, fission.BuildStatusFailed, buildLogs, nil)
|
||||
@@ -149,7 +170,7 @@ func (pkgw *packageWatcher) build(buildCache *cache.Cache, srcpkg *crd.Package)
|
||||
log.Printf("Start updating info of package: %v", pkg.Metadata.Name)
|
||||
|
||||
fnList, err := pkgw.fissionClient.
|
||||
Functions(metav1.NamespaceDefault).List(metav1.ListOptions{})
|
||||
Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
e := fmt.Sprintf("Error getting function list: %v", err)
|
||||
log.Println(e)
|
||||
@@ -191,13 +212,18 @@ func (pkgw *packageWatcher) build(buildCache *cache.Cache, srcpkg *crd.Package)
|
||||
// build timeout
|
||||
updatePackage(pkgw.fissionClient, pkg,
|
||||
fission.BuildStatusFailed, "Build timeout due to environment builder not ready", nil)
|
||||
|
||||
log.Printf("Max retries exceeded in building the source pkg : %s.%s, timeout due to environment builder not ready",
|
||||
pkg.Metadata.Name, pkg.Metadata.Namespace)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (pkgw *packageWatcher) watchPackages() {
|
||||
func (pkgw *packageWatcher) watchPackages(fissionClient *crd.FissionClient,
|
||||
kubernetesClient *kubernetes.Clientset, builderNamespace string) {
|
||||
buildCache := cache.MakeCache(0, 0)
|
||||
lw := k8sCache.NewListWatchFromClient(pkgw.fissionClient.GetCrdClient(), "packages", apiv1.NamespaceDefault, fields.Everything())
|
||||
_, controller := k8sCache.NewInformer(lw, &crd.Package{}, 60*time.Second, k8sCache.ResourceEventHandlerFuncs{
|
||||
lw := k8sCache.NewListWatchFromClient(pkgw.fissionClient.GetCrdClient(), "packages", apiv1.NamespaceAll, fields.Everything())
|
||||
pkgStore, controller := k8sCache.NewInformer(lw, &crd.Package{}, 60*time.Second, k8sCache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
pkg := obj.(*crd.Package)
|
||||
go pkgw.build(buildCache, pkg)
|
||||
@@ -207,5 +233,6 @@ func (pkgw *packageWatcher) watchPackages() {
|
||||
go pkgw.build(buildCache, pkg)
|
||||
},
|
||||
})
|
||||
pkgw.pkgStore = pkgStore
|
||||
controller.Run(make(chan struct{}))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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 canaryconfigmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission/cache"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
canaryConfigCancelFuncMap struct {
|
||||
cache *cache.Cache // map[metadataKey]*context.Context
|
||||
}
|
||||
|
||||
// metav1.ObjectMeta is not hashable, so we make a hashable copy
|
||||
// of the subset of its fields that are identifiable.
|
||||
metadataKey struct {
|
||||
Name string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
CanaryProcessingInfo struct {
|
||||
CancelFunc *context.CancelFunc
|
||||
Ticker *time.Ticker
|
||||
}
|
||||
)
|
||||
|
||||
func makecanaryConfigCancelFuncMap() *canaryConfigCancelFuncMap {
|
||||
return &canaryConfigCancelFuncMap{
|
||||
cache: cache.MakeCache(0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func keyFromMetadata(m *metav1.ObjectMeta) metadataKey {
|
||||
return metadataKey{
|
||||
Name: m.Name,
|
||||
Namespace: m.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (cancelFuncMap *canaryConfigCancelFuncMap) lookup(f *metav1.ObjectMeta) (*CanaryProcessingInfo, error) {
|
||||
mk := keyFromMetadata(f)
|
||||
item, err := cancelFuncMap.cache.Get(mk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := item.(*CanaryProcessingInfo)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (cancelFuncMap *canaryConfigCancelFuncMap) assign(f *metav1.ObjectMeta, value *CanaryProcessingInfo) error {
|
||||
mk := keyFromMetadata(f)
|
||||
err, _ := cancelFuncMap.cache.Set(mk, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (cancelFuncMap *canaryConfigCancelFuncMap) remove(f *metav1.ObjectMeta) error {
|
||||
mk := keyFromMetadata(f)
|
||||
return cancelFuncMap.cache.Delete(mk)
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
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 canaryconfigmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
k8sCache "k8s.io/client-go/tools/cache"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
)
|
||||
|
||||
type canaryConfigMgr struct {
|
||||
fissionClient *crd.FissionClient
|
||||
kubeClient *kubernetes.Clientset
|
||||
canaryConfigStore k8sCache.Store
|
||||
canaryConfigController k8sCache.Controller
|
||||
promClient *PrometheusApiClient
|
||||
crdClient *rest.RESTClient
|
||||
canaryCfgCancelFuncMap *canaryConfigCancelFuncMap
|
||||
}
|
||||
|
||||
func MakeCanaryConfigMgr(fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset, crdClient *rest.RESTClient, prometheusSvc string) (*canaryConfigMgr, error) {
|
||||
if prometheusSvc == "" {
|
||||
// handle a case where there is a prometheus server is already installed, try to find the service from env variable
|
||||
envVars := os.Environ()
|
||||
for _, envVar := range envVars {
|
||||
if strings.Contains(envVar, "PROMETHEUS_SERVER_SERVICE_HOST") {
|
||||
envVarSplit := strings.Split(envVar, "=")
|
||||
prometheusSvc = envVarSplit[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if prometheusSvc == "" {
|
||||
return nil, fmt.Errorf("prometheus service not found, cant create canary config manager")
|
||||
}
|
||||
}
|
||||
|
||||
configMgr := &canaryConfigMgr{
|
||||
fissionClient: fissionClient,
|
||||
kubeClient: kubeClient,
|
||||
crdClient: crdClient,
|
||||
promClient: MakePrometheusClient(prometheusSvc),
|
||||
canaryCfgCancelFuncMap: makecanaryConfigCancelFuncMap(),
|
||||
}
|
||||
|
||||
store, controller := configMgr.initCanaryConfigController()
|
||||
configMgr.canaryConfigStore = store
|
||||
configMgr.canaryConfigController = controller
|
||||
|
||||
return configMgr, nil
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) initCanaryConfigController() (k8sCache.Store, k8sCache.Controller) {
|
||||
resyncPeriod := 30 * time.Second
|
||||
listWatch := k8sCache.NewListWatchFromClient(canaryCfgMgr.crdClient, "canaryconfigs", metav1.NamespaceAll, fields.Everything())
|
||||
store, controller := k8sCache.NewInformer(listWatch, &crd.CanaryConfig{}, resyncPeriod,
|
||||
k8sCache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
canaryConfig := obj.(*crd.CanaryConfig)
|
||||
if canaryConfig.Status.Status == fission.CanaryConfigStatusPending {
|
||||
go canaryCfgMgr.addCanaryConfig(canaryConfig)
|
||||
}
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
canaryConfig := obj.(*crd.CanaryConfig)
|
||||
go canaryCfgMgr.deleteCanaryConfig(canaryConfig)
|
||||
},
|
||||
UpdateFunc: func(oldObj interface{}, newObj interface{}) {
|
||||
oldConfig := oldObj.(*crd.CanaryConfig)
|
||||
newConfig := newObj.(*crd.CanaryConfig)
|
||||
if oldConfig.Metadata.ResourceVersion != newConfig.Metadata.ResourceVersion &&
|
||||
newConfig.Status.Status == fission.CanaryConfigStatusPending {
|
||||
log.Printf("update canary config invoked for : %s.%s, newConfig.Status.Status=%s", newConfig.Metadata.Name, newConfig.Metadata.Namespace, newConfig.Status.Status)
|
||||
go canaryCfgMgr.updateCanaryConfig(oldConfig, newConfig)
|
||||
}
|
||||
go canaryCfgMgr.reSyncCanaryConfigs()
|
||||
|
||||
},
|
||||
})
|
||||
|
||||
return store, controller
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) Run(ctx context.Context) {
|
||||
go canaryCfgMgr.canaryConfigController.Run(ctx.Done())
|
||||
log.Printf("started Canary configmgr controller")
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) addCanaryConfig(canaryConfig *crd.CanaryConfig) {
|
||||
log.Printf("addCanaryConfig called for %s", canaryConfig.Metadata.Name)
|
||||
|
||||
// for each canary config, create a ticker with increment interval
|
||||
interval, err := time.ParseDuration(canaryConfig.Spec.WeightIncrementDuration)
|
||||
if err != nil {
|
||||
log.Printf("Error parsing duration: %v, cant proceed with this canaryConfig : %v.%v", err,
|
||||
canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace)
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(interval)
|
||||
|
||||
// create a context cancel func for each canary config. this will be used to cancel the processing of this canary
|
||||
// config in the event that it's deleted
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
cacheValue := &CanaryProcessingInfo{
|
||||
CancelFunc: &cancel,
|
||||
Ticker: ticker,
|
||||
}
|
||||
err = canaryCfgMgr.canaryCfgCancelFuncMap.assign(&canaryConfig.Metadata, cacheValue)
|
||||
if err != nil {
|
||||
log.Printf("Error caching canary config : %s.%s. err : %v", canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace, err)
|
||||
return
|
||||
}
|
||||
canaryCfgMgr.processCanaryConfig(&ctx, canaryConfig, ticker)
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) processCanaryConfig(ctx *context.Context, canaryConfig *crd.CanaryConfig, ticker *time.Ticker) {
|
||||
quit := make(chan struct{})
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-(*ctx).Done():
|
||||
// this case when someone deleted their canary config in the middle of it being processed
|
||||
log.Printf("Cancel Func called for canary config : %s", canaryConfig.Metadata.Name)
|
||||
err := canaryCfgMgr.canaryCfgCancelFuncMap.remove(&canaryConfig.Metadata)
|
||||
if err != nil {
|
||||
log.Printf("error removing canary config: %s from map, err : %v", canaryConfig.Metadata.Name, err)
|
||||
}
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
// every weightIncrementDuration, check if failureThreshold has reached.
|
||||
// if yes, rollback.
|
||||
// else, increment the weight of new function and decrement old function by `weightIncrement`
|
||||
log.Printf("Processing canary config : %s.%s", canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace)
|
||||
canaryCfgMgr.RollForwardOrBack(canaryConfig, quit, ticker)
|
||||
|
||||
case <-quit:
|
||||
// we're done processing this canary config either because the new function receives 100% of the traffic
|
||||
// or we rolled back to send all 100% traffic to old function
|
||||
log.Printf("Quit processing canaryConfig : %s", canaryConfig.Metadata.Name)
|
||||
err := canaryCfgMgr.canaryCfgCancelFuncMap.remove(&canaryConfig.Metadata)
|
||||
if err != nil {
|
||||
log.Printf("error removing canary config: %s from map, err : %v", canaryConfig.Metadata.Name, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) RollForwardOrBack(canaryConfig *crd.CanaryConfig, quit chan struct{}, ticker *time.Ticker) {
|
||||
// handle race between delete event and notification on ticker.C
|
||||
_, err := canaryCfgMgr.canaryCfgCancelFuncMap.lookup(&canaryConfig.Metadata)
|
||||
if err != nil {
|
||||
log.Printf("No need of processing the config, not in cache anymore")
|
||||
return
|
||||
}
|
||||
|
||||
// get the http trigger object associated with this canary config
|
||||
triggerObj, err := canaryCfgMgr.fissionClient.HTTPTriggers(canaryConfig.Metadata.Namespace).Get(canaryConfig.Spec.Trigger)
|
||||
if err != nil {
|
||||
// if the http trigger is not found, then give up processing this config.
|
||||
if k8serrors.IsNotFound(err) {
|
||||
log.Printf("Http trigger object : %v.%v missing", canaryConfig.Spec.Trigger, canaryConfig.Metadata.Namespace)
|
||||
close(quit)
|
||||
return
|
||||
}
|
||||
|
||||
// just silently ignore. wait for next window to increment weight
|
||||
log.Printf("Error fetching http trigger object, err : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// handle a race between ticker.Stop and receiving a notification on ticker.C
|
||||
if canaryConfig.Status.Status != fission.CanaryConfigStatusPending {
|
||||
log.Printf("No need of processing the config, not pending anymore")
|
||||
return
|
||||
}
|
||||
|
||||
if triggerObj.Spec.FunctionReference.Type == fission.FunctionReferenceTypeFunctionWeights &&
|
||||
triggerObj.Spec.FunctionReference.FunctionWeights[canaryConfig.Spec.NewFunction] != 0 {
|
||||
failurePercent, err := canaryCfgMgr.promClient.GetFunctionFailurePercentage(triggerObj.Spec.RelativeURL, triggerObj.Spec.Method,
|
||||
canaryConfig.Spec.NewFunction, canaryConfig.Metadata.Namespace, canaryConfig.Spec.WeightIncrementDuration)
|
||||
|
||||
if err != nil {
|
||||
// silently ignore. wait for next window to increment weight
|
||||
log.Printf("Error calculating failure percentage, err : %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Failure percentage calculated : %v for canaryConfig %s", failurePercent, canaryConfig.Metadata.Name)
|
||||
if failurePercent == -1 {
|
||||
// this means there were no requests triggered to this url during this window. return here and check back
|
||||
// during next iteration
|
||||
log.Printf("Total requests received for url : %v is 0", triggerObj.Spec.RelativeURL)
|
||||
return
|
||||
}
|
||||
|
||||
if int(failurePercent) > canaryConfig.Spec.FailureThreshold {
|
||||
log.Printf("Failure percent %v crossed the threshold %v, so rolling back", failurePercent, canaryConfig.Spec.FailureThreshold)
|
||||
ticker.Stop()
|
||||
canaryCfgMgr.rollback(canaryConfig, triggerObj)
|
||||
close(quit)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
doneProcessingCanaryConfig, err := canaryCfgMgr.rollForward(canaryConfig, triggerObj)
|
||||
if err != nil {
|
||||
// just log the error and hope that next iteration will succeed
|
||||
log.Printf("Error incrementing weights for triggerObj : %v, err : %v", triggerObj.Metadata.Name, err)
|
||||
return
|
||||
}
|
||||
|
||||
if doneProcessingCanaryConfig {
|
||||
ticker.Stop()
|
||||
// update the status of canary config as done processing, we dont care if we arent able to update because
|
||||
// resync takes care of the update
|
||||
err = canaryCfgMgr.updateCanaryConfigStatusWithRetries(canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace,
|
||||
fission.CanaryConfigStatusSucceeded)
|
||||
if err != nil {
|
||||
// cant do much after max retries other than logging it.
|
||||
log.Printf("Error updating canary config : %s.%s after max retries, err :%v", canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace,
|
||||
err)
|
||||
}
|
||||
|
||||
log.Printf("We're done processing canary config : %s. The new function is receiving all the traffic", canaryConfig.Metadata.Name)
|
||||
close(quit)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) updateHttpTriggerWithRetries(triggerName, triggerNamespace string, fnWeights map[string]int) (err error) {
|
||||
for i := 0; i < fission.MaxRetries; i++ {
|
||||
triggerObj, err := canaryCfgMgr.fissionClient.HTTPTriggers(triggerNamespace).Get(triggerName)
|
||||
if err != nil {
|
||||
log.Printf("Error getting http trigger object : %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
triggerObj.Spec.FunctionReference.FunctionWeights = fnWeights
|
||||
|
||||
_, err = canaryCfgMgr.fissionClient.HTTPTriggers(triggerNamespace).Update(triggerObj)
|
||||
switch {
|
||||
case err == nil:
|
||||
log.Printf("Updated Http trigger : %s.%s", triggerName, triggerNamespace)
|
||||
return nil
|
||||
case k8serrors.IsConflict(err):
|
||||
log.Printf("Conflict in updating http trigger : %s.%s, retrying", triggerName, triggerNamespace)
|
||||
continue
|
||||
default:
|
||||
log.Printf("Error updating trigger : %s.%s = %v", triggerName, triggerNamespace, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) updateCanaryConfigStatusWithRetries(cfgName, cfgNamespace string, status string) (err error) {
|
||||
for i := 0; i < fission.MaxRetries; i++ {
|
||||
canaryCfgObj, err := canaryCfgMgr.fissionClient.CanaryConfigs(cfgNamespace).Get(cfgName)
|
||||
if err != nil {
|
||||
log.Printf("Error getting http Canary Config object : %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Updating status of canaryCfg : %s.%s to %s", cfgName, cfgNamespace, status)
|
||||
canaryCfgObj.Status.Status = status
|
||||
|
||||
_, err = canaryCfgMgr.fissionClient.CanaryConfigs(cfgNamespace).Update(canaryCfgObj)
|
||||
switch {
|
||||
case err == nil:
|
||||
log.Printf("Updated Canary Config : %s.%s", cfgName, cfgNamespace)
|
||||
return nil
|
||||
case k8serrors.IsConflict(err):
|
||||
log.Printf("Conflict in updating Canary Config : %s.%s, retrying", cfgName, cfgNamespace)
|
||||
continue
|
||||
default:
|
||||
log.Printf("Error updating Canary Config : %s.%s = %v", cfgName, cfgNamespace, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) rollback(canaryConfig *crd.CanaryConfig, trigger *crd.HTTPTrigger) error {
|
||||
functionWeights := trigger.Spec.FunctionReference.FunctionWeights
|
||||
functionWeights[canaryConfig.Spec.NewFunction] = 0
|
||||
functionWeights[canaryConfig.Spec.OldFunction] = 100
|
||||
|
||||
err := canaryCfgMgr.updateHttpTriggerWithRetries(trigger.Metadata.Name, trigger.Metadata.Namespace, functionWeights)
|
||||
|
||||
err = canaryCfgMgr.updateCanaryConfigStatusWithRetries(canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace,
|
||||
fission.CanaryConfigStatusFailed)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) rollForward(canaryConfig *crd.CanaryConfig, trigger *crd.HTTPTrigger) (bool, error) {
|
||||
doneProcessingCanaryConfig := false
|
||||
|
||||
functionWeights := trigger.Spec.FunctionReference.FunctionWeights
|
||||
if functionWeights[canaryConfig.Spec.NewFunction]+canaryConfig.Spec.WeightIncrement >= 100 {
|
||||
doneProcessingCanaryConfig = true
|
||||
functionWeights[canaryConfig.Spec.NewFunction] = 100
|
||||
functionWeights[canaryConfig.Spec.OldFunction] = 0
|
||||
} else {
|
||||
functionWeights[canaryConfig.Spec.NewFunction] += canaryConfig.Spec.WeightIncrement
|
||||
if functionWeights[canaryConfig.Spec.OldFunction]-canaryConfig.Spec.WeightIncrement < 0 {
|
||||
functionWeights[canaryConfig.Spec.OldFunction] = 0
|
||||
} else {
|
||||
functionWeights[canaryConfig.Spec.OldFunction] -= canaryConfig.Spec.WeightIncrement
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Incremented functionWeights : %v", functionWeights)
|
||||
|
||||
err := canaryCfgMgr.updateHttpTriggerWithRetries(trigger.Metadata.Name, trigger.Metadata.Namespace, functionWeights)
|
||||
return doneProcessingCanaryConfig, err
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) reSyncCanaryConfigs() {
|
||||
for _, obj := range canaryCfgMgr.canaryConfigStore.List() {
|
||||
canaryConfig := obj.(*crd.CanaryConfig)
|
||||
_, err := canaryCfgMgr.canaryCfgCancelFuncMap.lookup(&canaryConfig.Metadata)
|
||||
if err != nil && canaryConfig.Status.Status == fission.CanaryConfigStatusPending {
|
||||
log.Printf("Adding canary config : %s.%s from resync loop", canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace)
|
||||
|
||||
// new canaryConfig detected, add it to our cache and start processing it
|
||||
go canaryCfgMgr.addCanaryConfig(canaryConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) deleteCanaryConfig(canaryConfig *crd.CanaryConfig) {
|
||||
log.Printf("Delete event received for canary config : %v, %v, %v", canaryConfig.Metadata.Name, canaryConfig.Metadata.Namespace, canaryConfig.Metadata.ResourceVersion)
|
||||
canaryProcessingInfo, err := canaryCfgMgr.canaryCfgCancelFuncMap.lookup(&canaryConfig.Metadata)
|
||||
if err != nil {
|
||||
log.Printf("lookup of canaryConfig failed, err : %v", err)
|
||||
return
|
||||
}
|
||||
// first stop the ticker
|
||||
canaryProcessingInfo.Ticker.Stop()
|
||||
// call cancel func so that the ctx.Done returns inside processCanaryConfig function and processing gets stopped
|
||||
(*canaryProcessingInfo.CancelFunc)()
|
||||
}
|
||||
|
||||
func (canaryCfgMgr *canaryConfigMgr) updateCanaryConfig(oldCanaryConfig *crd.CanaryConfig, newCanaryConfig *crd.CanaryConfig) {
|
||||
// before removing the object from cache, we need to get it's cancel func and cancel it
|
||||
canaryCfgMgr.deleteCanaryConfig(oldCanaryConfig)
|
||||
|
||||
err := canaryCfgMgr.canaryCfgCancelFuncMap.remove(&oldCanaryConfig.Metadata)
|
||||
if err != nil {
|
||||
log.Printf("error removing canary config: %s from map, err : %v", oldCanaryConfig.Metadata.Name, err)
|
||||
return
|
||||
}
|
||||
canaryCfgMgr.addCanaryConfig(newCanaryConfig)
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
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 canaryconfigmgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/net/context"
|
||||
"time"
|
||||
|
||||
promClient "github.com/prometheus/client_golang/api/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type PrometheusApiClient struct {
|
||||
client promClient.QueryAPI
|
||||
}
|
||||
|
||||
func MakePrometheusClient(prometheusSvc string) *PrometheusApiClient {
|
||||
promApiConfig := promClient.Config{
|
||||
Address: prometheusSvc,
|
||||
}
|
||||
|
||||
promApiClient, err := promClient.New(promApiConfig)
|
||||
if err != nil {
|
||||
log.Errorf("Error creating prometheus api client for svc : %s, err : %v", prometheusSvc, err)
|
||||
}
|
||||
|
||||
apiQueryClient := promClient.NewQueryAPI(promApiClient)
|
||||
|
||||
log.Printf("Successfully made prometheus client with service : %s", prometheusSvc)
|
||||
return &PrometheusApiClient{
|
||||
client: apiQueryClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (promApiClient *PrometheusApiClient) GetFunctionFailurePercentage(path, method, funcName, funcNs string, window string) (float64, error) {
|
||||
// first get a total count of requests to this url in a time window
|
||||
reqs, err := promApiClient.GetRequestsToFuncInWindow(path, method, funcName, funcNs, window)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if reqs <= 0 {
|
||||
return -1, fmt.Errorf("no requests to this url %v and method %v in the window : %v", path, method, window)
|
||||
}
|
||||
|
||||
// next, get a total count of errored out requests to this function in the same window
|
||||
failedReqs, err := promApiClient.GetTotalFailedRequestsToFuncInWindow(funcName, funcNs, path, method, window)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// calculate the failure percentage of the function
|
||||
failurePercentForFunc := (failedReqs / reqs) * 100
|
||||
|
||||
return failurePercentForFunc, nil
|
||||
}
|
||||
|
||||
func (promApiClient *PrometheusApiClient) GetRequestsToFuncInWindow(path string, method string, funcName string, funcNs string, window string) (float64, error) {
|
||||
queryString := fmt.Sprintf("fission_function_calls_total{path=\"%s\",method=\"%s\",name=\"%s\",namespace=\"%s\"}[%v]", path, method, funcName, funcNs, window)
|
||||
|
||||
reqs, err := promApiClient.executeQuery(queryString)
|
||||
if err != nil {
|
||||
log.Printf("Error executing query : %s, err : %v", queryString, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
queryString = fmt.Sprintf("fission_function_calls_total{path=\"%s\",method=\"%s\",name=\"%s\",namespace=\"%s\"} offset %v", path, method, funcName, funcNs, window)
|
||||
|
||||
reqsInPrevWindow, err := promApiClient.executeQuery(queryString)
|
||||
if err != nil {
|
||||
log.Printf("Error executing query : %s, err : %v", queryString, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
reqsInCurrentWindow := reqs - reqsInPrevWindow
|
||||
log.Printf("reqs : %v, reqsInPrevWindow : %v, reqsInCurrentWindow : %v to function %v", reqs, reqsInPrevWindow, reqsInCurrentWindow, funcName)
|
||||
|
||||
return reqsInCurrentWindow, nil
|
||||
}
|
||||
|
||||
func (promApiClient *PrometheusApiClient) GetTotalFailedRequestsToFuncInWindow(funcName string, funcNs string, path string, method string, window string) (float64, error) {
|
||||
queryString := fmt.Sprintf("fission_function_errors_total{name=\"%s\",namespace=\"%s\",path=\"%s\", method=\"%s\"}[%v]", funcName, funcNs, path, method, window)
|
||||
|
||||
failedRequests, err := promApiClient.executeQuery(queryString)
|
||||
if err != nil {
|
||||
log.Printf("Error executing query : %s, err : %v", queryString, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
queryString = fmt.Sprintf("fission_function_errors_total{name=\"%s\",namespace=\"%s\",path=\"%s\", method=\"%s\"} offset %v", funcName, funcNs, path, method, window)
|
||||
|
||||
failedReqsInPrevWindow, err := promApiClient.executeQuery(queryString)
|
||||
if err != nil {
|
||||
log.Printf("Error executing query : %s, err : %v", queryString, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
failedReqsInCurrentWindow := failedRequests - failedReqsInPrevWindow
|
||||
log.Printf("failedReqs : %v, failedReqsInPrevWindow : %v, failedReqsInCurrentWindow : %v to function : %v", failedRequests, failedReqsInPrevWindow, failedReqsInCurrentWindow, funcName)
|
||||
|
||||
return failedReqsInCurrentWindow, nil
|
||||
}
|
||||
|
||||
func (promApiClient *PrometheusApiClient) executeQuery(queryString string) (float64, error) {
|
||||
val, err := promApiClient.client.Query(context.Background(), queryString, time.Now())
|
||||
if err != nil {
|
||||
log.Errorf("Error querying prometheus qs : %v, err : %v", queryString, err)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case val.Type() == model.ValScalar:
|
||||
scalarVal := val.(*model.Scalar)
|
||||
return float64(scalarVal.Value), nil
|
||||
|
||||
case val.Type() == model.ValVector:
|
||||
vectorVal := val.(model.Vector)
|
||||
total := float64(0)
|
||||
for _, elem := range vectorVal {
|
||||
total = total + float64(elem.Value)
|
||||
}
|
||||
return total, nil
|
||||
|
||||
case val.Type() == model.ValMatrix:
|
||||
matrixVal := val.(model.Matrix)
|
||||
total := float64(0)
|
||||
for _, elem := range matrixVal {
|
||||
//log.Printf("Only one value, so taking the 0th elem")
|
||||
total += float64(elem.Values[len(elem.Values)-1].Value)
|
||||
}
|
||||
return total, nil
|
||||
|
||||
default:
|
||||
log.Printf("type unrecognized")
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
func addInterval(window string) string {
|
||||
timeDuration, _ := time.ParseDuration(window)
|
||||
log.Println("window in seconds", int64(timeDuration/time.Second))
|
||||
|
||||
timeInStr := fmt.Sprintf("%ds", int64((timeDuration+timeDuration)/time.Second))
|
||||
fmt.Println(timeInStr)
|
||||
|
||||
return timeInStr
|
||||
}
|
||||
+10
-5
@@ -56,11 +56,16 @@ The following table lists the configurable parameters of the Fission chart and t
|
||||
| `logger.influxdbAdmin` | Log database admin username | `admin` |
|
||||
| `logger.fluentdImage` | Logger fluentd image | `fission/fluentd` |
|
||||
| `fissionUiImage` | Fission ui image | `fission/fission-ui:0.1.0` |
|
||||
| `messageQueue` | Message queue type | `nats-streaming` |
|
||||
| `nats.authToken` | Nats streaming auth token | `defaultFissionAuthToken` |
|
||||
| `nats.clusterID` | Nats streaming clusterID | `fissionMQTrigger` |
|
||||
| `azureStorageQueue.accountName` | Azure storage account name | None (required if `messageQueue` is `azure-storage-queue`) |
|
||||
| `azureStorageQueue.key` | Azure storage access key | None (required if `messageQueue` is `azure-storage-queue`) |
|
||||
| `nats.enabled` | Nats streaming enabled | `true` |
|
||||
| `nats.authToken` | Nats streaming auth token | `defaultFissionAuthToken`(required if `nats.enabled` is `true`) |
|
||||
| `nats.clusterID` | Nats streaming clusterID | `fissionMQTrigger`(required if `nats.enabled` is `true`) |
|
||||
| `azureStorageQueue.enabled` * | Azure storage account name | false |
|
||||
| `azureStorageQueue.accountName` | Azure storage account name | None (required if `azureStorageQueue.enabled` is `true`) |
|
||||
| `azureStorageQueue.key` | Azure storage access key | None (required if `azureStorageQueue.enabled` is `true`) |
|
||||
| `kafka.enabled` * | Kafka trigger enabled | `false` |
|
||||
| `kafka.brokers` | Kafka brokers uri | `broker.kafka:9092` (required if `kafka.enabled` is `true`) |
|
||||
|
||||
* - Please note that deploying of Azure Storage Queue or Kafka is not done by Fission chart and you will have to explicitly deploy them.
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
name: fission-all
|
||||
version: 0.7.1
|
||||
version: 0.12.0
|
||||
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.7.1
|
||||
appVersion: 0.12.0
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
- name: prometheus
|
||||
version: 7.1.0
|
||||
repository: https://kubernetes-charts.storage.googleapis.com
|
||||
condition: prometheusDeploy
|
||||
@@ -1,13 +1,13 @@
|
||||
1. Install the client CLI.
|
||||
|
||||
Mac:
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.7.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.12.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.7.1/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.12.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: https://github.com/fission/fission/releases/download/0.7.1/fission-cli-windows.exe
|
||||
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.12.0/fission-cli-windows.exe
|
||||
|
||||
2. You're ready to use Fission!
|
||||
|
||||
|
||||
@@ -14,3 +14,20 @@ We truncate at 24 chars because some Kubernetes name fields are limited to this
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
{{/*
|
||||
This is a template with config parameters for optional features in fission. This gets mounted on to the controller pod
|
||||
as a config map.
|
||||
To add new features with config parameters, create a yaml block below with the feature name and define a corresponding struct in
|
||||
controller/config.go
|
||||
*/}}
|
||||
{{- define "config" -}}
|
||||
canary:
|
||||
enabled: {{ .Values.canaryDeployment.enabled }}
|
||||
{{- if .Values.prometheusDeploy }}
|
||||
prometheusSvc: "http://{{ .Release.Name }}-prometheus-server.{{ .Release.Namespace }}"
|
||||
{{- end }}
|
||||
{{- printf "\n" -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
{{- if .Values.createNamespace }}
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
@@ -21,6 +22,37 @@ metadata:
|
||||
{{- if .Values.enableIstio }}
|
||||
istio-injection: enabled
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: secret-configmap-getter
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- list
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: package-getter
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- packages
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- list
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
@@ -44,21 +76,6 @@ roleRef:
|
||||
name: admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: fission-function-admin
|
||||
namespace: {{ .Values.functionNamespace }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: fission-svc
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
@@ -79,21 +96,6 @@ kind: ServiceAccount
|
||||
metadata:
|
||||
name: fission-fetcher
|
||||
namespace: {{ .Values.functionNamespace }}
|
||||
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: fission-fetcher-crd
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: fission-fetcher
|
||||
namespace: {{ .Values.functionNamespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
@@ -102,18 +104,13 @@ metadata:
|
||||
namespace: {{ .Values.builderNamespace }}
|
||||
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: fission-builder-crd
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: fission-builder
|
||||
namespace: {{ .Values.builderNamespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: feature-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
"config.yaml": {{ include "config" . | b64enc }}
|
||||
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
@@ -132,13 +129,17 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: controller
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--controllerPort", "8888"]
|
||||
env:
|
||||
- name: FISSION_FUNCTION_NAMESPACE
|
||||
value: "{{ .Values.functionNamespace }}"
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: "/healthz"
|
||||
@@ -152,8 +153,15 @@ spec:
|
||||
port: 8888
|
||||
initialDelaySeconds: 35
|
||||
periodSeconds: 5
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/config/config.yaml
|
||||
subPath: config.yaml
|
||||
serviceAccount: fission-svc
|
||||
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: feature-config
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
@@ -168,13 +176,36 @@ spec:
|
||||
labels:
|
||||
application: fission-router
|
||||
svc: router
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/path: "/metrics"
|
||||
prometheus.io/port: "8080"
|
||||
spec:
|
||||
containers:
|
||||
- name: router
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--routerPort", "8888", "--executorUrl", "http://executor.{{ .Release.Namespace }}"]
|
||||
env:
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: ROUTER_ROUND_TRIP_TIMEOUT
|
||||
value: {{ .Values.routerRoundTripTimeout | default "50ms" | quote }}
|
||||
- name: ROUTER_ROUNDTRIP_TIMEOUT_EXPONENT
|
||||
value: {{ .Values.routerRoundTripTimeoutExponent | default 2 | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_KEEP_ALIVE_TIME
|
||||
value: {{ .Values.routerRoundTripKeepAliveTime | default "30s" | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_MAX_RETRIES
|
||||
value: {{ .Values.routerRoundTripMaxRetries | default 10 | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_SVC_ADDRESS_MAX_RETRIES
|
||||
value: {{ .Values.routerRoundTripSvcAddressMaxRetries | default 5 | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_SVC_ADDRESS_UPDATE_TIMEOUT
|
||||
value: {{ .Values.routerRoundTripSvcAddressUpdateTimeout | default 30 | quote }}
|
||||
- name: DEBUG_ENV
|
||||
value: {{ .Values.debugEnv | quote }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: "/router-healthz"
|
||||
@@ -188,6 +219,11 @@ spec:
|
||||
port: 8888
|
||||
initialDelaySeconds: 35
|
||||
periodSeconds: 5
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: metrics
|
||||
- containerPort: 8888
|
||||
name: http
|
||||
serviceAccount: fission-svc
|
||||
|
||||
---
|
||||
@@ -219,10 +255,14 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
svc: executor
|
||||
annotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/path: "/metrics"
|
||||
prometheus.io/port: "8080"
|
||||
spec:
|
||||
containers:
|
||||
- name: executor
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--executorPort", "8888", "--namespace", "{{ .Values.functionNamespace }}", "--fission-namespace", "{{ .Release.Namespace }}"]
|
||||
@@ -235,6 +275,14 @@ spec:
|
||||
value: "{{ .Values.pullPolicy }}"
|
||||
- name: ENABLE_ISTIO
|
||||
value: "{{ .Values.enableIstio }}"
|
||||
- name: FETCHER_MINCPU
|
||||
value: {{ .Values.fetcherMinCpu | default "10m" | quote }}
|
||||
- name: FETCHER_MINMEM
|
||||
value: {{ .Values.fetcherMinMem | default "16Mi" | quote }}
|
||||
- name: FETCHER_MAXCPU
|
||||
value: {{ .Values.fetcherMaxCpu | default "40m" | quote }}
|
||||
- name: FETCHER_MAXMEM
|
||||
value: {{ .Values.fetcherMaxMem | default "128Mi" | quote }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: "/healthz"
|
||||
@@ -248,6 +296,11 @@ spec:
|
||||
port: 8888
|
||||
initialDelaySeconds: 35
|
||||
periodSeconds: 5
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: metrics
|
||||
- containerPort: 8888
|
||||
name: http
|
||||
serviceAccount: fission-svc
|
||||
|
||||
---
|
||||
@@ -266,7 +319,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: buildermgr
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--builderMgr", "--storageSvcUrl", "http://storagesvc.{{ .Release.Namespace }}", "--envbuilder-namespace", "{{ .Values.builderNamespace }}"]
|
||||
@@ -295,7 +348,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: kubewatcher
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--kubewatcher", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
|
||||
@@ -310,7 +363,7 @@ metadata:
|
||||
svc: influxdb
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
type: ClusterIP
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8086
|
||||
targetPort: 8086
|
||||
@@ -333,7 +386,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: influxdb
|
||||
image: tutum/influxdb
|
||||
image: fission/influxdb
|
||||
env:
|
||||
- name: PRE_CREATE_DB
|
||||
value: fissionFunctionLog
|
||||
@@ -389,8 +442,9 @@ spec:
|
||||
- /heapster
|
||||
- --source=kubernetes:https://kubernetes.default
|
||||
serviceAccount: {{ .Release.Namespace }}/fission-svc
|
||||
---
|
||||
{{- end -}}
|
||||
|
||||
---
|
||||
{{- end }}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
@@ -405,7 +459,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: fluentd
|
||||
image: "{{ .Values.logger.fluentdImage }}:{{ .Values.logger.fluentdImageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.logger.fluentdImage }}:{{ .Values.logger.fluentdImageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
env:
|
||||
- name: INFLUXDB_ADDRESS
|
||||
@@ -447,7 +501,8 @@ spec:
|
||||
- name: fission-log
|
||||
hostPath:
|
||||
path: /var/log/fission
|
||||
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
@@ -464,7 +519,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: timer
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--timer", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
|
||||
@@ -491,14 +546,14 @@ spec:
|
||||
# spec:
|
||||
# containers:
|
||||
# - name: nginx
|
||||
# image: {{ .Values.fissionUiImage }}
|
||||
# image: {{ .Values.repository }}/{{ .Values.fissionUiImage }}
|
||||
# - name: kubectl-proxy
|
||||
# image: lachlanevenson/k8s-kubectl
|
||||
# image: {{ .Values.repository }}/lachlanevenson/k8s-kubectl
|
||||
# args: ["proxy", "--port", "8001", "--address", "127.0.0.1"]
|
||||
# serviceAccount: fission-svc
|
||||
|
||||
---
|
||||
{{- if eq .Values.messageQueue.type "nats-streaming" }}
|
||||
{{- if .Values.nats.enabled }}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -520,17 +575,16 @@ spec:
|
||||
"--auth", "{{ .Values.nats.authToken }}",
|
||||
"--max_channels", "0"
|
||||
]
|
||||
|
||||
ports:
|
||||
- containerPort: 4222
|
||||
hostPort: 4222
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mqtrigger
|
||||
name: mqtrigger-nats-streaming
|
||||
labels:
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
@@ -539,6 +593,65 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
svc: mqtrigger
|
||||
messagequeue: nats-streaming
|
||||
spec:
|
||||
containers:
|
||||
- name: mqtrigger
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--mqt", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
|
||||
env:
|
||||
- name: MESSAGE_QUEUE_TYPE
|
||||
value: nats-streaming
|
||||
- name: MESSAGE_QUEUE_URL
|
||||
value: nats://{{ .Values.nats.authToken }}@nats-streaming:4222
|
||||
serviceAccount: fission-svc
|
||||
{{- end }}
|
||||
---
|
||||
{{- if .Values.kafka.enabled }}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mqtrigger-kafka
|
||||
labels:
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
svc: mqtrigger
|
||||
messagequeue: kafka
|
||||
spec:
|
||||
containers:
|
||||
- name: mqtrigger
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--mqt"]
|
||||
env:
|
||||
- name: MESSAGE_QUEUE_TYPE
|
||||
value: kafka
|
||||
- name: MESSAGE_QUEUE_URL
|
||||
value: "{{.Values.kafka.brokers}}"
|
||||
serviceAccount: fission-svc
|
||||
{{- end }}
|
||||
---
|
||||
{{- if .Values.azureStorageQueue.enabled }}
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mqtrigger-azure-storage-queue
|
||||
labels:
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
svc: mqtrigger
|
||||
messagequeue: azure-storage-queue
|
||||
spec:
|
||||
containers:
|
||||
- name: mqtrigger
|
||||
@@ -548,11 +661,7 @@ spec:
|
||||
args: ["--mqt", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
|
||||
env:
|
||||
- name: MESSAGE_QUEUE_TYPE
|
||||
value: {{ .Values.messageQueue.type }}
|
||||
{{- if eq .Values.messageQueue.type "nats-streaming" }}
|
||||
- name: MESSAGE_QUEUE_URL
|
||||
value: nats://{{ .Values.nats.authToken }}@nats-streaming:4222
|
||||
{{- else if eq .Values.messageQueue.type "azure-storage-queue" }}
|
||||
value: azure-storage-queue
|
||||
- name: AZURE_STORAGE_ACCOUNT_NAME
|
||||
value: {{ required "An Azure storage account name is required." .Values.azureStorageQueue.accountName }}
|
||||
- name: AZURE_STORAGE_ACCOUNT_KEY
|
||||
@@ -560,9 +669,8 @@ spec:
|
||||
secretKeyRef:
|
||||
name: azure-storage-account-key
|
||||
key: key
|
||||
{{- end }}
|
||||
serviceAccount: fission-svc
|
||||
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
@@ -576,10 +684,11 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
svc: storagesvc
|
||||
application: fission-storage
|
||||
spec:
|
||||
containers:
|
||||
- name: storagesvc
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--storageServicePort", "8000", "--filePath", "/fission"]
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
{{ if .Values.analyticsNonHelmInstall }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}-{{ .Chart.Version }}-{{ randNumeric 3 }}
|
||||
labels:
|
||||
# The "release" convention makes it easy to tie a release to all of the
|
||||
# Kubernetes resources that were created as part of that release.
|
||||
release: {{ .Release.Name }}
|
||||
# This makes it easy to audit chart usage.
|
||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app: {{ template "name" . }}
|
||||
spec:
|
||||
#ttlSecondsAfterFinished: 120
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}
|
||||
labels:
|
||||
release: {{ .Release.Name }}
|
||||
app: {{ template "name" . }}
|
||||
annotations:
|
||||
{{- if .Values.enableIstio }}
|
||||
"sidecar.istio.io/inject": "false"
|
||||
{{- end }}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: post-install-job
|
||||
image: "fission/alpinecurl"
|
||||
command: ["sh", "-c", "/usr/bin/curl -m 5 -H \"Content-Type: application/json\" -X POST -d '{\"type\": \"yaml-post-install\", \"chartName\": \"{{ .Chart.Name }}\", \"chartVersion\": \"{{ .Chart.Version }}\"}' https://g.fission.sh/analytics || true"]
|
||||
{{ end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}-{{ .Chart.Version }}-{{ randNumeric 3 }}
|
||||
labels:
|
||||
# The "release" convention makes it easy to tie a release to all of the
|
||||
# Kubernetes resources that were created as part of that release.
|
||||
release: "{{ .Release.Name }}"
|
||||
# This makes it easy to audit chart usage.
|
||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app: {{ template "name" . }}
|
||||
annotations:
|
||||
# This is what defines this resource as a hook. Without this line, the
|
||||
# job is considered part of the release.
|
||||
"helm.sh/hook": pre-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded
|
||||
spec:
|
||||
backoffLimit: 0
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}
|
||||
labels:
|
||||
release: "{{ .Release.Name }}"
|
||||
app: {{ template "name" . }}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: pre-upgrade-job
|
||||
image: {{ .Values.preUpgradeChecksImage }}:{{ .Values.imageTag }}
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: [ "/pre-upgrade-checks" ]
|
||||
args: ["--fn-pod-namespace", "{{ .Values.functionNamespace }}", "--envbuilder-namespace", "{{ .Values.builderNamespace }}"]
|
||||
serviceAccount: fission-svc
|
||||
@@ -0,0 +1,39 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis
|
||||
labels:
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
ports:
|
||||
- port: 6379
|
||||
targetPort: 6379
|
||||
protocol: TCP
|
||||
name: redis
|
||||
selector:
|
||||
app: redis
|
||||
---
|
||||
apiVersion: apps/v1beta2
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis
|
||||
labels:
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
serviceName: redis
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:3.2-alpine
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
@@ -10,7 +10,7 @@ data:
|
||||
password: {{ randAlphaNum 20 | b64enc | quote }}
|
||||
|
||||
---
|
||||
{{- if eq .Values.messageQueue.type "azure-storage-queue" }}
|
||||
{{- if .Values.azureStorageQueue.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
|
||||
@@ -38,7 +38,7 @@ spec:
|
||||
svc: controller
|
||||
|
||||
---
|
||||
{{- if eq .Values.messageQueue.type "nats-streaming" }}
|
||||
{{- if .Values.nats.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -57,7 +57,6 @@ spec:
|
||||
selector:
|
||||
svc: nats-streaming
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -65,6 +64,7 @@ metadata:
|
||||
name: storagesvc
|
||||
labels:
|
||||
svc: storagesvc
|
||||
application: fission-storage
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
type: ClusterIP
|
||||
@@ -72,4 +72,4 @@ spec:
|
||||
- port: 80
|
||||
targetPort: 8000
|
||||
selector:
|
||||
svc: storagesvc
|
||||
svc: storagesvc
|
||||
@@ -9,6 +9,9 @@ serviceType: ClusterIP
|
||||
## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP.
|
||||
routerServiceType: LoadBalancer
|
||||
|
||||
## Image base repository
|
||||
repository: index.docker.io
|
||||
|
||||
## Fission image repository
|
||||
image: fission/fission-bundle
|
||||
|
||||
@@ -16,13 +19,13 @@ image: fission/fission-bundle
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
## Fission image version
|
||||
imageTag: 0.7.1
|
||||
imageTag: 0.12.0
|
||||
|
||||
## Fission fetcher repository
|
||||
fetcherImage: fission/fetcher
|
||||
|
||||
## Fission fetcher image version
|
||||
fetcherImageTag: 0.7.1
|
||||
fetcherImageTag: 0.12.0
|
||||
|
||||
## Port at which Fission controller service should be exposed
|
||||
controllerPort: 31313
|
||||
@@ -33,6 +36,9 @@ routerPort: 31314
|
||||
## Port at which NATS streaming service should be exposed
|
||||
natsStreamingPort: 31316
|
||||
|
||||
## Set to false if you create the namespaces manually
|
||||
createNamespace: true
|
||||
|
||||
## Namespace in which to run fission functions (this is different from
|
||||
## the release namespace)
|
||||
functionNamespace: fission-function
|
||||
@@ -48,23 +54,25 @@ enableIstio: false
|
||||
logger:
|
||||
influxdbAdmin: "admin"
|
||||
fluentdImage: fission/fluentd
|
||||
fluentdImageTag: 0.7.1
|
||||
|
||||
## Type of Queue you would like to use
|
||||
## currently supports nats-streaming, azure-storage-queue
|
||||
messageQueue:
|
||||
type: nats-streaming
|
||||
fluentdImageTag: 0.12.0
|
||||
|
||||
## Message queue trigger config
|
||||
### NATS Streaming
|
||||
### NATS Streaming, enabled by default
|
||||
nats:
|
||||
enabled: true
|
||||
authToken: "defaultFissionAuthToken"
|
||||
clusterID: "fissionMQTrigger"
|
||||
|
||||
## Required if messageQueue type is azure-storage-queue
|
||||
## Azure-storage-queue: enable and configure the details
|
||||
azureStorageQueue:
|
||||
enabled: false
|
||||
key: ""
|
||||
accountName: ""
|
||||
|
||||
## Kafka: enable and configure the details
|
||||
kafka:
|
||||
enabled: false
|
||||
brokers: 'broker.kafka:9092'
|
||||
|
||||
## Persist data to a persistent volume.
|
||||
persistence:
|
||||
@@ -83,6 +91,8 @@ persistence:
|
||||
## false to disable analytics.
|
||||
analytics: true
|
||||
|
||||
## Internally used for generating an analytics job for non-helm installs
|
||||
analyticsNonHelmInstall: false
|
||||
|
||||
## Enable Heapster only in clusters where heapster does not exist already
|
||||
heapster: false
|
||||
@@ -91,3 +101,17 @@ heapster: false
|
||||
## This interval configures the frequency at which it runs inside the storagesvc pod.
|
||||
## The value is in minutes.
|
||||
pruneInterval: 60
|
||||
|
||||
## Fission pre-install/pre-upgrade checks live in this image
|
||||
preUpgradeChecksImage: fission/pre-upgrade-checks
|
||||
|
||||
## if there are any pod specialization errors when a function is triggered and this flag is set to true, the error
|
||||
## summary is returned as part of http response
|
||||
debugEnv: true
|
||||
|
||||
## set this flag to true if prometheus needs to be deployed along with fission
|
||||
prometheusDeploy: true
|
||||
|
||||
## set this flag to false if you dont need canary deployment feature
|
||||
canaryDeployment:
|
||||
enabled: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
name: fission-core
|
||||
version: 0.7.1
|
||||
version: 0.12.0
|
||||
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.7.1
|
||||
appVersion: 0.12.0
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
- name: prometheus
|
||||
version: 7.1.0
|
||||
repository: https://kubernetes-charts.storage.googleapis.com
|
||||
condition: prometheusDeploy
|
||||
@@ -1,13 +1,13 @@
|
||||
1. Install the client CLI.
|
||||
|
||||
Mac:
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.7.1/fission-cli-osx && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.12.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.7.1/fission-cli-linux && chmod +x fission && sudo mv fission /usr/local/bin/
|
||||
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.12.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: https://github.com/fission/fission/releases/download/0.7.1/fission-cli-windows.exe
|
||||
For Windows, you can use the linux binary on WSL. Or you can download this windows executable: https://github.com/fission/fission/releases/download/0.12.0/fission-cli-windows.exe
|
||||
|
||||
2. You're ready to use Fission!
|
||||
|
||||
|
||||
@@ -14,3 +14,18 @@ We truncate at 24 chars because some Kubernetes name fields are limited to this
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
This is a template with config parameters for optional features in fission. This gets mounted on to the controller pod
|
||||
as a config map.
|
||||
To add new features with config parameters, create a yaml block below with the feature name and define a corresponding struct in
|
||||
controller/config.go
|
||||
*/}}
|
||||
{{- define "config" -}}
|
||||
canary:
|
||||
enabled: {{ .Values.canaryDeployment.enabled }}
|
||||
{{- if .Values.prometheusDeploy }}
|
||||
prometheusSvc: "http://{{ .Release.Name }}-prometheus-server.{{ .Release.Namespace }}"
|
||||
{{- end }}
|
||||
{{- printf "\n" -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -22,6 +22,37 @@ metadata:
|
||||
istio-injection: enabled
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: secret-configmap-getter
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- list
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: package-getter
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- packages
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- list
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
@@ -44,21 +75,6 @@ roleRef:
|
||||
name: admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: fission-function-admin
|
||||
namespace: {{ .Values.functionNamespace }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: fission-svc
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
@@ -80,20 +96,6 @@ metadata:
|
||||
name: fission-fetcher
|
||||
namespace: {{ .Values.functionNamespace }}
|
||||
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: fission-fetcher-crd
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: fission-fetcher
|
||||
namespace: {{ .Values.functionNamespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
@@ -102,18 +104,13 @@ metadata:
|
||||
namespace: {{ .Values.builderNamespace }}
|
||||
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: fission-builder-crd
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: fission-builder
|
||||
namespace: {{ .Values.builderNamespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
name: feature-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
"config.yaml": {{ include "config" . | b64enc }}
|
||||
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
@@ -132,13 +129,17 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: controller
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--controllerPort", "8888"]
|
||||
env:
|
||||
- name: FISSION_FUNCTION_NAMESPACE
|
||||
value: "{{ .Values.functionNamespace }}"
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: "/healthz"
|
||||
@@ -152,7 +153,15 @@ spec:
|
||||
port: 8888
|
||||
initialDelaySeconds: 35
|
||||
periodSeconds: 5
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/config/config.yaml
|
||||
subPath: config.yaml
|
||||
serviceAccount: fission-svc
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: feature-config
|
||||
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
@@ -171,10 +180,29 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: router
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--routerPort", "8888", "--executorUrl", "http://executor.{{ .Release.Namespace }}"]
|
||||
env:
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: ROUTER_ROUND_TRIP_TIMEOUT
|
||||
value: {{ .Values.routerRoundTripTimeout | default "50ms" | quote }}
|
||||
- name: ROUTER_ROUNDTRIP_TIMEOUT_EXPONENT
|
||||
value: {{ .Values.routerRoundTripTimeoutExponent | default 2 | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_KEEP_ALIVE_TIME
|
||||
value: {{ .Values.routerRoundTripKeepAliveTime | default "30s" | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_MAX_RETRIES
|
||||
value: {{ .Values.routerRoundTripMaxRetries | default 10 | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_SVC_ADDRESS_MAX_RETRIES
|
||||
value: {{ .Values.routerRoundTripSvcAddressMaxRetries | default 5 | quote }}
|
||||
- name: ROUTER_ROUND_TRIP_SVC_ADDRESS_UPDATE_TIMEOUT
|
||||
value: {{ .Values.routerRoundTripSvcAddressUpdateTimeout | default 30 | quote }}
|
||||
- name: DEBUG_ENV
|
||||
value: {{ .Values.debugEnv | quote }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: "/router-healthz"
|
||||
@@ -222,7 +250,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: executor
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--executorPort", "8888", "--namespace", "{{ .Values.functionNamespace }}", "--fission-namespace", "{{ .Release.Namespace }}"]
|
||||
@@ -233,6 +261,14 @@ spec:
|
||||
value: "{{ .Values.pullPolicy }}"
|
||||
- name: ENABLE_ISTIO
|
||||
value: "{{ .Values.enableIstio }}"
|
||||
- name: FETCHER_MINCPU
|
||||
value: {{ .Values.fetcherMinCpu | default "10m" | quote }}
|
||||
- name: FETCHER_MINMEM
|
||||
value: {{ .Values.fetcherMinMem | default "16Mi" | quote }}
|
||||
- name: FETCHER_MAXCPU
|
||||
value: {{ .Values.fetcherMaxCpu | default "40m" | quote }}
|
||||
- name: FETCHER_MAXMEM
|
||||
value: {{ .Values.fetcherMaxMem | default "128Mi" | quote }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: "/healthz"
|
||||
@@ -264,7 +300,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: buildermgr
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--builderMgr", "--storageSvcUrl", "http://storagesvc.{{ .Release.Namespace }}", "--envbuilder-namespace", "{{ .Values.builderNamespace }}"]
|
||||
@@ -293,7 +329,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: kubewatcher
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--kubewatcher", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
|
||||
@@ -315,7 +351,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: timer
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--timer", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
|
||||
@@ -334,10 +370,11 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
svc: storagesvc
|
||||
application: fission-storage
|
||||
spec:
|
||||
containers:
|
||||
- name: storagesvc
|
||||
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
image: "{{ .Values.repository }}/{{ .Values.image }}:{{ .Values.imageTag }}"
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: ["/fission-bundle"]
|
||||
args: ["--storageServicePort", "8000", "--filePath", "/fission"]
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
{{ if .Values.analyticsNonHelmInstall }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}-{{ .Chart.Version }}-{{ randNumeric 3 }}
|
||||
labels:
|
||||
# The "release" convention makes it easy to tie a release to all of the
|
||||
# Kubernetes resources that were created as part of that release.
|
||||
release: {{ .Release.Name }}
|
||||
# This makes it easy to audit chart usage.
|
||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app: {{ template "name" . }}
|
||||
spec:
|
||||
#ttlSecondsAfterFinished: 120
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}
|
||||
labels:
|
||||
release: {{ .Release.Name }}
|
||||
app: {{ template "name" . }}
|
||||
annotations:
|
||||
{{- if .Values.enableIstio }}
|
||||
"sidecar.istio.io/inject": "false"
|
||||
{{- end }}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: post-install-job
|
||||
image: "fission/alpinecurl"
|
||||
command: ["sh", "-c", "/usr/bin/curl -m 5 -H \"Content-Type: application/json\" -X POST -d '{\"type\": \"yaml-post-install\", \"chartName\": \"{{ .Chart.Name }}\", \"chartVersion\": \"{{ .Chart.Version }}\"}' https://g.fission.sh/analytics || true"]
|
||||
{{ end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}-{{ .Chart.Version }}-{{ randNumeric 3 }}
|
||||
labels:
|
||||
# The "release" convention makes it easy to tie a release to all of the
|
||||
# Kubernetes resources that were created as part of that release.
|
||||
release: "{{ .Release.Name }}"
|
||||
# This makes it easy to audit chart usage.
|
||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app: {{ template "name" . }}
|
||||
annotations:
|
||||
# This is what defines this resource as a hook. Without this line, the
|
||||
# job is considered part of the release.
|
||||
"helm.sh/hook": pre-upgrade
|
||||
"helm.sh/hook-delete-policy": hook-succeeded
|
||||
spec:
|
||||
backoffLimit: 0
|
||||
template:
|
||||
metadata:
|
||||
name: {{ template "fullname" . }}
|
||||
labels:
|
||||
release: "{{ .Release.Name }}"
|
||||
app: {{ template "name" . }}
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: pre-upgrade-job
|
||||
image: {{ .Values.preUpgradeChecksImage }}:{{ .Values.imageTag }}
|
||||
imagePullPolicy: {{ .Values.pullPolicy }}
|
||||
command: [ "/pre-upgrade-checks" ]
|
||||
args: ["--fn-pod-namespace", "{{ .Values.functionNamespace }}", "--envbuilder-namespace", "{{ .Values.builderNamespace }}"]
|
||||
serviceAccount: fission-svc
|
||||
@@ -44,6 +44,7 @@ metadata:
|
||||
name: storagesvc
|
||||
labels:
|
||||
svc: storagesvc
|
||||
application: fission-storage
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
spec:
|
||||
type: ClusterIP
|
||||
|
||||
@@ -9,11 +9,14 @@ serviceType: ClusterIP
|
||||
## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP.
|
||||
routerServiceType: LoadBalancer
|
||||
|
||||
## Image base repository
|
||||
repository: index.docker.io
|
||||
|
||||
## Fission image repository
|
||||
image: fission/fission-bundle
|
||||
|
||||
## Fission image version
|
||||
imageTag: 0.7.1
|
||||
imageTag: 0.12.0
|
||||
|
||||
## Image pull policy
|
||||
pullPolicy: IfNotPresent
|
||||
@@ -22,7 +25,7 @@ pullPolicy: IfNotPresent
|
||||
fetcherImage: fission/fetcher
|
||||
|
||||
## Fission fetcher image version
|
||||
fetcherImageTag: 0.7.1
|
||||
fetcherImageTag: 0.12.0
|
||||
|
||||
## Port at which Fission controller service should be exposed
|
||||
controllerPort: 31313
|
||||
@@ -58,7 +61,24 @@ persistence:
|
||||
## false to disable analytics.
|
||||
analytics: true
|
||||
|
||||
## Internally used for generating an analytics job for non-helm installs
|
||||
analyticsNonHelmInstall: false
|
||||
|
||||
## Archive pruner is a garbage collector for archives on the fission storage service.
|
||||
## This interval configures the frequency at which it runs inside the storagesvc pod.
|
||||
## The value is in minutes.
|
||||
pruneInterval: 60
|
||||
|
||||
## Fission pre-install/pre-upgrade checks live in this image
|
||||
preUpgradeChecksImage: fission/pre-upgrade-checks
|
||||
|
||||
## if there are any pod specialization errors when a function is triggered and this flag is set to true, the error
|
||||
## summary is returned as part of http response
|
||||
debugEnv: true
|
||||
|
||||
## set this flag to true if prometheus needs to be deployed along with fission
|
||||
prometheusDeploy: false
|
||||
|
||||
## set this flag to false if you dont need canary deployment feature
|
||||
canaryDeployment:
|
||||
enabled: false
|
||||
|
||||
@@ -18,21 +18,29 @@ package fission
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/imdario/mergo"
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
"github.com/mholt/archiver"
|
||||
"github.com/satori/go.uuid"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func UrlForFunction(name string) string {
|
||||
func UrlForFunction(name, namespace string) string {
|
||||
prefix := "/fission-function"
|
||||
if namespace != metav1.NamespaceDefault {
|
||||
prefix = fmt.Sprintf("/fission-function/%s", namespace)
|
||||
}
|
||||
return fmt.Sprintf("%v/%v", prefix, name)
|
||||
}
|
||||
|
||||
@@ -104,13 +112,20 @@ func IsNetworkDialError(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsReadyPod checks that all containers in a pod are ready and returns true if so
|
||||
// IsReadyPod checks both all containers in a pod are ready and whether
|
||||
// the .metadata.DeletionTimestamp is nil.
|
||||
func IsReadyPod(pod *apiv1.Pod) bool {
|
||||
// since its a utility function, just ensuring there is no nil pointer exception
|
||||
if pod == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// pod is in "Terminating" status if deletionTimestamp is not nil
|
||||
// https://github.com/kubernetes/kubernetes/issues/61376
|
||||
if pod.ObjectMeta.DeletionTimestamp != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, cStatus := range pod.Status.ContainerStatuses {
|
||||
if !cStatus.Ready {
|
||||
return false
|
||||
@@ -119,3 +134,53 @@ func IsReadyPod(pod *apiv1.Pod) bool {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GetTempDir creates and return a temporary directory
|
||||
func GetTempDir() (string, error) {
|
||||
tmpDir := uuid.NewV4().String()
|
||||
dir, err := ioutil.TempDir("", tmpDir)
|
||||
return dir, err
|
||||
}
|
||||
|
||||
// FindAllGlobs returns a list of globs of input list.
|
||||
func FindAllGlobs(inputList []string) ([]string, error) {
|
||||
files := make([]string, 0)
|
||||
for _, glob := range inputList {
|
||||
f, err := filepath.Glob(glob)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid glob %v: %v", glob, err)
|
||||
}
|
||||
files = append(files, f...)
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func MakeArchive(targetName string, globs ...string) (string, error) {
|
||||
files, err := FindAllGlobs(globs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// zip up the file list
|
||||
err = archiver.Zip.Make(targetName, files)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Abs(targetName)
|
||||
}
|
||||
|
||||
// RemoveZeroBytes remove empty byte(\x00) from input byte slice and return a new byte slice
|
||||
// This function is trying to fix the problem that empty byte will fail os.Openfile
|
||||
// For more information, please visit:
|
||||
// 1. https://github.com/golang/go/issues/24195
|
||||
// 2. https://play.golang.org/p/5F9ykC2tlbc
|
||||
func RemoveZeroBytes(src []byte) []byte {
|
||||
var bs []byte
|
||||
for _, v := range src {
|
||||
if v != 0 {
|
||||
bs = append(bs, v)
|
||||
}
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
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 fission
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1beta1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// This file has util functions needed for setting up and cleaning up RBAC objects.
|
||||
|
||||
const (
|
||||
MaxRetries = 10
|
||||
)
|
||||
|
||||
// MakeSAObj returns a ServiceAccount object with the given SA name and namespace
|
||||
func MakeSAObj(sa, ns string) *apiv1.ServiceAccount {
|
||||
return &apiv1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: ns,
|
||||
Name: sa,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SetupSA checks if a service account is present in the namespace, if not creates it.
|
||||
func SetupSA(k8sClient *kubernetes.Clientset, sa, ns string) (*apiv1.ServiceAccount, error) {
|
||||
saObj, err := k8sClient.CoreV1().ServiceAccounts(ns).Get(sa, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return saObj, nil
|
||||
}
|
||||
|
||||
if k8serrors.IsNotFound(err) {
|
||||
saObj = MakeSAObj(sa, ns)
|
||||
saObj, err = k8sClient.CoreV1().ServiceAccounts(ns).Create(saObj)
|
||||
}
|
||||
|
||||
return saObj, err
|
||||
}
|
||||
|
||||
// makeRoleBindingObj is a helper function called from other functions in this file only.
|
||||
// given a rolebinging name and namespace, it makes a rolebinding object mapping the role to the SA of the namespace.
|
||||
func makeRoleBindingObj(roleBinding, roleBindingNs, role, roleKind, sa, saNamespace string) *rbac.RoleBinding {
|
||||
return &rbac.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: roleBinding,
|
||||
Namespace: roleBindingNs,
|
||||
},
|
||||
Subjects: []rbac.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: sa,
|
||||
Namespace: saNamespace,
|
||||
},
|
||||
},
|
||||
RoleRef: rbac.RoleRef{
|
||||
Kind: roleKind,
|
||||
Name: role,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// isSAInRoleBinding checkis if a service account is present in the rolebinding object
|
||||
func isSAInRoleBinding(rbObj *rbac.RoleBinding, sa, ns string) bool {
|
||||
for _, subject := range rbObj.Subjects {
|
||||
if subject.Name == sa && subject.Namespace == ns {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// PatchSpec is a standard struct needed for JSON merge.
|
||||
type PatchSpec struct {
|
||||
Op string `json:"op"`
|
||||
Path string `json:"path"`
|
||||
Value rbac.Subject `json:"value"`
|
||||
}
|
||||
|
||||
// AddSaToRoleBindingWithRetries adds a service account to a rolebinding object. IT retries on already exists and conflict errors.
|
||||
func AddSaToRoleBindingWithRetries(k8sClient *kubernetes.Clientset, roleBinding, roleBindingNs, sa, saNamespace, role, roleKind string) (err error) {
|
||||
patch := PatchSpec{}
|
||||
patch.Op = "add"
|
||||
patch.Path = "/subjects/-"
|
||||
patch.Value = rbac.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Name: sa,
|
||||
Namespace: saNamespace,
|
||||
}
|
||||
|
||||
patchJson, err := json.Marshal([]PatchSpec{patch})
|
||||
if err != nil {
|
||||
log.Printf("Error marshalling patch into json")
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < MaxRetries; i++ {
|
||||
_, err = k8sClient.RbacV1beta1().RoleBindings(roleBindingNs).Patch(roleBinding, types.JSONPatchType, patchJson)
|
||||
if err == nil {
|
||||
log.Printf("Patched rolebinding : %s.%s", roleBinding, roleBindingNs)
|
||||
return err
|
||||
}
|
||||
|
||||
if k8serrors.IsNotFound(err) {
|
||||
// someone may have deleted the object between us checking if the object is present and deciding to patch
|
||||
// so just create the object again
|
||||
rbObj := makeRoleBindingObj(roleBinding, roleBindingNs, role, roleKind, sa, saNamespace)
|
||||
rbObj, err = k8sClient.RbacV1beta1().RoleBindings(roleBindingNs).Create(rbObj)
|
||||
if err == nil {
|
||||
log.Printf("Created rolebinding : %s.%s", roleBinding, roleBindingNs)
|
||||
return err
|
||||
}
|
||||
|
||||
if k8serrors.IsAlreadyExists(err) {
|
||||
log.Printf("rolebinding object : %s.%s already exists, retrying patch, err: %v", roleBinding, roleBindingNs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Error returned by rolebinding create, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if k8serrors.IsConflict(err) {
|
||||
// TODO : Need to test this out, not able to simulate conflicts yet.
|
||||
// Initially, my understanding was that patch can never error on conflict because Api server will handle the conflicts for us.
|
||||
// but one CI run did show patch errored out on conflict : https://api.travis-ci.org/v3/job/373161490/log.txt, look for :
|
||||
// Error returned by rolebinding patch : <some more text> there is a meaningful conflict (firstResourceVersion: "35482724", currentResourceVersion: "35482849")
|
||||
// so, m guessing retrying patch should help. will watch out for any such conflicts and fix the issue if any
|
||||
log.Printf("Conflict reported on patch of rolebinding : %s.%s. Retrying patch operation, err : %v", roleBinding, roleBindingNs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Error returned by rolebinding patch : %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Exceeded maxretries : %d adding SA: %s.%s to rolebinding : %s.%s, giving up, err: %v", MaxRetries, sa, saNamespace, roleBinding, roleBindingNs, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveSAFromRoleBindingWithRetries removes an SA from the rolebinding passed as parameter. If this is the only SA in
|
||||
// the rolebinding, then it deletes the rolebinding object.
|
||||
func RemoveSAFromRoleBindingWithRetries(k8sClient *kubernetes.Clientset, roleBinding, roleBindingNs string, saToRemove map[string]bool) (err error) {
|
||||
for i := 0; i < MaxRetries; i++ {
|
||||
rbObj, err := k8sClient.RbacV1beta1().RoleBindings(roleBindingNs).Get(
|
||||
roleBinding, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
// silently ignoring the error. there's no need for us to remove sa anymore.
|
||||
log.Printf("rolebinding %s.%s not found, but ignoring the error since we're cleaning up", roleBinding, roleBindingNs)
|
||||
return nil
|
||||
}
|
||||
|
||||
subjects := rbObj.Subjects
|
||||
newSubjects := make([]rbac.Subject, 0)
|
||||
|
||||
// TODO : optimize it.
|
||||
for _, item := range subjects {
|
||||
if _, ok := saToRemove[MakeSAMapKey(item.Name, item.Namespace)]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
newSubjects = append(newSubjects, rbac.Subject{
|
||||
Kind: "ServiceAccount",
|
||||
Name: item.Name,
|
||||
Namespace: item.Namespace,
|
||||
})
|
||||
}
|
||||
if len(newSubjects) == 0 {
|
||||
return DeleteRoleBinding(k8sClient, roleBinding, roleBindingNs)
|
||||
}
|
||||
|
||||
rbObj.Subjects = newSubjects
|
||||
|
||||
// cant use patch for deletes, the results become in-deterministic, so using update.
|
||||
_, err = k8sClient.RbacV1beta1().RoleBindings(rbObj.Namespace).Update(rbObj)
|
||||
switch {
|
||||
case err == nil:
|
||||
log.Printf("Removed sa's : %v from rolebinding : %s.%s", saToRemove, roleBinding, roleBindingNs)
|
||||
return nil
|
||||
case k8serrors.IsConflict(err):
|
||||
log.Printf("Conflict in update of rolebinding: %s.%s, retrying", roleBinding, roleBindingNs)
|
||||
continue
|
||||
default:
|
||||
log.Printf("Rolebinding Update Errored out : %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Maxretries : %d exceeded for removing SA's : %v from rolebinding %s.%s, giving up, err: %v", MaxRetries, saToRemove, roleBinding, roleBindingNs, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetupRoleBinding adds a role to a service account if the rolebinding object is already present in the namespace.
|
||||
// if not, it creates a rolebinding object granting the role to the SA in the namespace.
|
||||
func SetupRoleBinding(k8sClient *kubernetes.Clientset, roleBinding, roleBindingNs, role, roleKind, sa, saNamespace string) error {
|
||||
// get the role binding object
|
||||
rbObj, err := k8sClient.RbacV1beta1().RoleBindings(roleBindingNs).Get(
|
||||
roleBinding, metav1.GetOptions{})
|
||||
|
||||
if err == nil {
|
||||
if !isSAInRoleBinding(rbObj, sa, saNamespace) {
|
||||
return AddSaToRoleBindingWithRetries(k8sClient, roleBinding, roleBindingNs, sa, saNamespace, role, roleKind)
|
||||
}
|
||||
log.Printf("SA : %s.%s already present in rolebinding : %s.%s, so nothing to add", sa, saNamespace, roleBinding, roleBindingNs)
|
||||
return nil
|
||||
}
|
||||
|
||||
// if role binding is missing, create it. also add this sa to the binding.
|
||||
if k8serrors.IsNotFound(err) {
|
||||
log.Printf("Rolebinding %s does NOT exist in ns %s. Creating it", roleBinding, roleBindingNs)
|
||||
rbObj = makeRoleBindingObj(roleBinding, roleBindingNs, role, roleKind, sa, saNamespace)
|
||||
rbObj, err = k8sClient.RbacV1beta1().RoleBindings(roleBindingNs).Create(rbObj)
|
||||
if k8serrors.IsAlreadyExists(err) {
|
||||
err = AddSaToRoleBindingWithRetries(k8sClient, roleBinding, roleBindingNs, sa, saNamespace, role, roleKind)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteRoleBinding deletes a rolebinding object. if k8s throws an error that the rolebinding is not there, it just
|
||||
// returns silently.
|
||||
func DeleteRoleBinding(k8sClient *kubernetes.Clientset, roleBinding, roleBindingNs string) error {
|
||||
// if deleteRoleBinding is invoked by 2 fission services at the same time for the same rolebinding,
|
||||
// the first call will succeed while the 2nd will fail with isNotFound. but we dont want to error out then.
|
||||
err := k8sClient.RbacV1beta1().RoleBindings(roleBindingNs).Delete(roleBinding, &metav1.DeleteOptions{})
|
||||
if err == nil || k8serrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func MakeSAMapKey(saName, saNamespace string) string {
|
||||
return fmt.Sprintf("%s-%s", saName, saNamespace)
|
||||
}
|
||||
+76
-3
@@ -25,14 +25,26 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
config "github.com/fission/fission/featureconfig"
|
||||
"github.com/fission/fission/fission/logdb"
|
||||
)
|
||||
|
||||
var podNamespace string
|
||||
|
||||
func init() {
|
||||
podNamespace = os.Getenv("POD_NAMESPACE")
|
||||
if podNamespace == "" {
|
||||
podNamespace = "fission"
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
API struct {
|
||||
fissionClient *crd.FissionClient
|
||||
@@ -42,6 +54,7 @@ type (
|
||||
workflowApiUrl string
|
||||
functionNamespace string
|
||||
useIstio bool
|
||||
featureConfig *config.FeatureConfig
|
||||
}
|
||||
|
||||
logDBConfig struct {
|
||||
@@ -51,7 +64,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func MakeAPI() (*API, error) {
|
||||
func MakeAPI(featureConfig *config.FeatureConfig) (*API, error) {
|
||||
api, err := makeCRDBackedAPI()
|
||||
|
||||
u := os.Getenv("STORAGE_SERVICE_URL")
|
||||
@@ -82,6 +95,8 @@ func MakeAPI() (*API, error) {
|
||||
api.functionNamespace = "fission-function"
|
||||
}
|
||||
|
||||
api.featureConfig = featureConfig
|
||||
|
||||
return api, err
|
||||
}
|
||||
|
||||
@@ -109,6 +124,31 @@ func (api *API) respondWithError(w http.ResponseWriter, err error) {
|
||||
http.Error(w, msg, code)
|
||||
}
|
||||
|
||||
func (api *API) extractQueryParamFromRequest(r *http.Request, queryParam string) string {
|
||||
values := r.URL.Query()
|
||||
return values.Get(queryParam)
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
func (api *API) createNsIfNotExists(ns string) error {
|
||||
if ns == metav1.NamespaceDefault {
|
||||
// we dont have to create default ns
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := api.kubernetesClient.CoreV1().Namespaces().Get(ns, metav1.GetOptions{})
|
||||
if err != nil && kerrors.IsNotFound(err) {
|
||||
ns := &apiv1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ns,
|
||||
},
|
||||
}
|
||||
_, err = api.kubernetesClient.CoreV1().Namespaces().Create(ns)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (api *API) getLogDBConfig(dbType string) logDBConfig {
|
||||
dbType = strings.ToUpper(dbType)
|
||||
// retrieve db auth config from the env
|
||||
@@ -128,7 +168,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, fission.VersionInfo().String())
|
||||
fmt.Fprintf(w, fission.ApiInfo().String())
|
||||
}
|
||||
|
||||
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -140,6 +180,18 @@ func (api *API) HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (api *API) GetSvcName(w http.ResponseWriter, r *http.Request) {
|
||||
appLabelSelector := "application=" + r.URL.Query().Get("application")
|
||||
services, err := api.kubernetesClient.CoreV1().Services(podNamespace).List(metav1.ListOptions{
|
||||
LabelSelector: appLabelSelector,
|
||||
})
|
||||
if err != nil || len(services.Items) > 1 || len(services.Items) == 0 {
|
||||
api.respondWithError(w, err)
|
||||
}
|
||||
service := services.Items[0]
|
||||
fmt.Fprintf(w, service.Name+"."+podNamespace)
|
||||
}
|
||||
|
||||
func (api *API) Serve(port int) {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/healthz", api.HealthHandler).Methods("GET")
|
||||
@@ -189,12 +241,33 @@ 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("/v2/recorders", api.RecorderApiList).Methods("GET")
|
||||
r.HandleFunc("/v2/recorders", api.RecorderApiCreate).Methods("POST")
|
||||
r.HandleFunc("/v2/recorders/{recorder}", api.RecorderApiGet).Methods("GET")
|
||||
r.HandleFunc("/v2/recorders/{recorder}", api.RecorderApiUpdate).Methods("PUT")
|
||||
r.HandleFunc("/v2/recorders/{recorder}", api.RecorderApiDelete).Methods("DELETE")
|
||||
|
||||
r.HandleFunc("/v2/records", api.RecordsApiListAll).Methods("GET")
|
||||
r.HandleFunc("/v2/records/function/{function}", api.RecordsApiFilterByFunction).Methods("GET")
|
||||
r.HandleFunc("/v2/records/trigger/{trigger}", api.RecordsApiFilterByTrigger).Methods("GET")
|
||||
r.HandleFunc("/v2/records/time", api.RecordsApiFilterByTime).Methods("GET")
|
||||
|
||||
r.HandleFunc("/v2/replay/{reqUID}", api.ReplayByReqUID).Methods("GET")
|
||||
|
||||
r.HandleFunc("/v2/secrets/{secret}", api.SecretGet).Methods("GET")
|
||||
r.HandleFunc("/v2/configmaps/{configmap}", api.ConfigMapGet).Methods("GET")
|
||||
|
||||
r.HandleFunc("/v2/canaryconfigs", api.CanaryConfigApiCreate).Methods("POST")
|
||||
r.HandleFunc("/v2/canaryconfigs/{canaryConfig}", api.CanaryConfigApiGet).Methods("GET")
|
||||
r.HandleFunc("/v2/canaryconfigs/{canaryConfig}", api.CanaryConfigApiUpdate).Methods("PUT")
|
||||
r.HandleFunc("/v2/canaryconfigs/{canaryConfig}", api.CanaryConfigApiDelete).Methods("DELETE")
|
||||
r.HandleFunc("/v2/canaryconfigs", api.CanaryConfigApiList).Methods("GET")
|
||||
|
||||
r.HandleFunc("/proxy/{dbType}", api.FunctionLogsApiPost).Methods("POST")
|
||||
r.HandleFunc("/proxy/storage/v1/archive", api.StorageServiceProxy)
|
||||
r.HandleFunc("/proxy/logs/{function}", api.FunctionPodLogs).Methods("POST")
|
||||
r.HandleFunc("/proxy/workflows-apiserver/{path:.*}", api.WorkflowApiserverProxy)
|
||||
r.HandleFunc("/proxy/svcname", api.GetSvcName).Queries("application", "").Methods("GET")
|
||||
|
||||
address := fmt.Sprintf(":%v", port)
|
||||
|
||||
|
||||
+16
-10
@@ -28,8 +28,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/controller/client"
|
||||
@@ -122,7 +122,7 @@ func TestFunctionApi(t *testing.T) {
|
||||
panicIf(err)
|
||||
defer g.client.FunctionDelete(m2)
|
||||
|
||||
funcs, err := g.client.FunctionList()
|
||||
funcs, err := g.client.FunctionList(metav1.NamespaceDefault)
|
||||
panicIf(err)
|
||||
assert(len(funcs) == 2, fmt.Sprintf("created two functions, but found %v", len(funcs)))
|
||||
|
||||
@@ -171,7 +171,10 @@ func TestHTTPTriggerApi(t *testing.T) {
|
||||
|
||||
tr, err := g.client.HTTPTriggerGet(m)
|
||||
panicIf(err)
|
||||
assert(testTrigger.Spec == tr.Spec, "trigger should match after reading")
|
||||
assert(testTrigger.Spec.Method == tr.Spec.Method &&
|
||||
testTrigger.Spec.RelativeURL == tr.Spec.RelativeURL &&
|
||||
testTrigger.Spec.FunctionReference.Type == tr.Spec.FunctionReference.Type &&
|
||||
testTrigger.Spec.FunctionReference.Name == tr.Spec.FunctionReference.Name, "trigger should match after reading")
|
||||
|
||||
testTrigger.Metadata.ResourceVersion = m.ResourceVersion
|
||||
testTrigger.Spec.RelativeURL = "/hi"
|
||||
@@ -188,7 +191,7 @@ func TestHTTPTriggerApi(t *testing.T) {
|
||||
panicIf(err)
|
||||
defer g.client.HTTPTriggerDelete(m2)
|
||||
|
||||
ts, err := g.client.HTTPTriggerList()
|
||||
ts, err := g.client.HTTPTriggerList(metav1.NamespaceDefault)
|
||||
panicIf(err)
|
||||
assert(len(ts) == 2, fmt.Sprintf("created two triggers, but found %v", len(ts)))
|
||||
}
|
||||
@@ -235,7 +238,7 @@ func TestEnvironmentApi(t *testing.T) {
|
||||
panicIf(err)
|
||||
defer g.client.EnvironmentDelete(m2)
|
||||
|
||||
ts, err := g.client.EnvironmentList()
|
||||
ts, err := g.client.EnvironmentList(metav1.NamespaceDefault)
|
||||
panicIf(err)
|
||||
assert(len(ts) == 2, fmt.Sprintf("created two envs, but found %v", len(ts)))
|
||||
}
|
||||
@@ -272,14 +275,15 @@ func TestWatchApi(t *testing.T) {
|
||||
panicIf(err)
|
||||
assert(testWatch.Spec.Namespace == w.Spec.Namespace &&
|
||||
testWatch.Spec.Type == w.Spec.Type &&
|
||||
testWatch.Spec.FunctionReference == w.Spec.FunctionReference, "watch should match after reading")
|
||||
testWatch.Spec.FunctionReference.Type == w.Spec.FunctionReference.Type &&
|
||||
testWatch.Spec.FunctionReference.Name == w.Spec.FunctionReference.Name, "watch should match after reading")
|
||||
|
||||
testWatch.Metadata.Name = "yyy"
|
||||
m2, err := g.client.WatchCreate(testWatch)
|
||||
panicIf(err)
|
||||
defer g.client.WatchDelete(m2)
|
||||
|
||||
ws, err := g.client.WatchList()
|
||||
ws, err := g.client.WatchList(metav1.NamespaceDefault)
|
||||
panicIf(err)
|
||||
assert(len(ws) == 2, fmt.Sprintf("created two watches, but found %v", len(ws)))
|
||||
}
|
||||
@@ -310,7 +314,9 @@ func TestTimeTriggerApi(t *testing.T) {
|
||||
|
||||
tr, err := g.client.TimeTriggerGet(m)
|
||||
panicIf(err)
|
||||
assert(testTrigger.Spec == tr.Spec, "trigger should match after reading")
|
||||
assert(testTrigger.Spec.Cron == tr.Spec.Cron &&
|
||||
testTrigger.Spec.FunctionReference.Type == tr.Spec.FunctionReference.Type &&
|
||||
testTrigger.Spec.FunctionReference.Name == tr.Spec.FunctionReference.Name, "trigger should match after reading")
|
||||
|
||||
testTrigger.Metadata.ResourceVersion = m.ResourceVersion
|
||||
testTrigger.Spec.Cron = "@hourly"
|
||||
@@ -323,7 +329,7 @@ func TestTimeTriggerApi(t *testing.T) {
|
||||
_, err = g.client.TimeTriggerCreate(testTrigger)
|
||||
assertCronSpecFails(err)
|
||||
|
||||
ts, err := g.client.TimeTriggerList()
|
||||
ts, err := g.client.TimeTriggerList(metav1.NamespaceDefault)
|
||||
panicIf(err)
|
||||
assert(len(ts) == 1, fmt.Sprintf("created two time triggers, but found %v", len(ts)))
|
||||
}
|
||||
@@ -338,7 +344,7 @@ func TestMain(m *testing.M) {
|
||||
return
|
||||
}
|
||||
|
||||
go Start(8888)
|
||||
go Start(8888, true)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
g.client = client.MakeClient("http://localhost:8888")
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
)
|
||||
|
||||
func (a *API) CanaryConfigApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
if !a.featureConfig.CanaryConfig.IsEnabled {
|
||||
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission"))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
var canaryCfg crd.CanaryConfig
|
||||
err = json.Unmarshal(body, &canaryCfg)
|
||||
if err != nil {
|
||||
log.Printf("Failed to unmarshal request body: [%v]", body)
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
canaryCfgNew, err := a.fissionClient.CanaryConfigs(canaryCfg.Metadata.Namespace).Create(&canaryCfg)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(canaryCfgNew.Metadata)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) CanaryConfigApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
if !a.featureConfig.CanaryConfig.IsEnabled {
|
||||
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission"))
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
name := vars["canaryConfig"]
|
||||
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
canaryCfg, err := a.fissionClient.CanaryConfigs(ns).Get(name)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(canaryCfg)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) CanaryConfigApiList(w http.ResponseWriter, r *http.Request) {
|
||||
if !a.featureConfig.CanaryConfig.IsEnabled {
|
||||
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission"))
|
||||
return
|
||||
}
|
||||
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
canaryCfgs, err := a.fissionClient.CanaryConfigs(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(canaryCfgs.Items)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) CanaryConfigApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
if !a.featureConfig.CanaryConfig.IsEnabled {
|
||||
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission"))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
var c crd.CanaryConfig
|
||||
err = json.Unmarshal(body, &c)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
canayCfgNew, err := a.fissionClient.CanaryConfigs(c.Metadata.Namespace).Update(&c)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(canayCfgNew.Metadata)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) CanaryConfigApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
if !a.featureConfig.CanaryConfig.IsEnabled {
|
||||
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission"))
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
name := vars["canaryConfig"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
err := a.fissionClient.CanaryConfigs(ns).Delete(name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.respondWithSuccess(w, []byte(""))
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
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 client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission/crd"
|
||||
)
|
||||
|
||||
func (c *Client) CanaryConfigCreate(canaryConf *crd.CanaryConfig) (*metav1.ObjectMeta, error) {
|
||||
reqbody, err := json.Marshal(canaryConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := http.Post(c.url("canaryconfigs"), "application/json", bytes.NewReader(reqbody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleCreateResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var m metav1.ObjectMeta
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (c *Client) CanaryConfigGet(m *metav1.ObjectMeta) (*crd.CanaryConfig, error) {
|
||||
relativeUrl := fmt.Sprintf("canaryconfigs/%v", m.Name)
|
||||
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var canaryCfg crd.CanaryConfig
|
||||
err = json.Unmarshal(body, &canaryCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &canaryCfg, nil
|
||||
}
|
||||
|
||||
func (c *Client) CanaryConfigUpdate(canaryConf *crd.CanaryConfig) (*metav1.ObjectMeta, error) {
|
||||
reqbody, err := json.Marshal(canaryConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
relativeUrl := fmt.Sprintf("canaryconfigs/%v", canaryConf.Metadata.Name)
|
||||
|
||||
resp, err := c.put(relativeUrl, "application/json", reqbody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var m metav1.ObjectMeta
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (c *Client) CanaryConfigDelete(m *metav1.ObjectMeta) error {
|
||||
relativeUrl := fmt.Sprintf("canaryconfigs/%v", m.Name)
|
||||
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
|
||||
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) CanaryConfigList(ns string) ([]crd.CanaryConfig, error) {
|
||||
relativeUrl := fmt.Sprintf("canaryconfigs?namespace=%v", ns)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
canaryCfgs := make([]crd.CanaryConfig, 0)
|
||||
err = json.Unmarshal(body, &canaryCfgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return canaryCfgs, nil
|
||||
}
|
||||
@@ -18,7 +18,9 @@ package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -88,3 +90,25 @@ func (c *Client) handleCreateResponse(resp *http.Response) ([]byte, error) {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
return body, err
|
||||
}
|
||||
|
||||
func (c *Client) ServerInfo() (*fission.ServerInfo, error) {
|
||||
url := fmt.Sprintf(c.Url)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := &fission.ServerInfo{}
|
||||
err = json.Unmarshal(body, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
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 client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (c *Client) SecretGet(m *metav1.ObjectMeta) (*apiv1.Secret, error) {
|
||||
relativeUrl := fmt.Sprintf("secrets/%v", m.Name)
|
||||
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var secret apiv1.Secret
|
||||
err = json.Unmarshal(body, &secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &secret, nil
|
||||
}
|
||||
|
||||
func (c *Client) ConfigMapGet(m *metav1.ObjectMeta) (*apiv1.ConfigMap, error) {
|
||||
relativeUrl := fmt.Sprintf("configmaps/%v", m.Name)
|
||||
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var configMap apiv1.ConfigMap
|
||||
err = json.Unmarshal(body, &configMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &configMap, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetSvcURL(label string) (string, error) {
|
||||
url := fmt.Sprintf("%s/proxy/svcname?"+label, c.Url)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
return "", fmt.Errorf("Failed to find service for given label: %v", label)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
storageSvc := string(body)
|
||||
|
||||
return storageSvc, err
|
||||
}
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) EnvironmentCreate(env *crd.Environment) (*metav1.ObjectMeta, error) {
|
||||
err := env.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("Environment", err)
|
||||
return nil, fv1.AggregateValidationErrors("Environment", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(env)
|
||||
@@ -86,7 +86,7 @@ func (c *Client) EnvironmentGet(m *metav1.ObjectMeta) (*crd.Environment, error)
|
||||
func (c *Client) EnvironmentUpdate(env *crd.Environment) (*metav1.ObjectMeta, error) {
|
||||
err := env.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("Environment", err)
|
||||
return nil, fv1.AggregateValidationErrors("Environment", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(env)
|
||||
@@ -121,8 +121,9 @@ func (c *Client) EnvironmentDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) EnvironmentList() ([]crd.Environment, error) {
|
||||
resp, err := http.Get(c.url("environments"))
|
||||
func (c *Client) EnvironmentList(ns string) ([]crd.Environment, error) {
|
||||
relativeUrl := fmt.Sprintf("environments?namespace=%v", ns)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) FunctionCreate(f *crd.Function) (*metav1.ObjectMeta, error) {
|
||||
err := f.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("Function", err)
|
||||
return nil, fv1.AggregateValidationErrors("Function", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(f)
|
||||
@@ -100,7 +100,7 @@ func (c *Client) FunctionGetRawDeployment(m *metav1.ObjectMeta) ([]byte, error)
|
||||
func (c *Client) FunctionUpdate(f *crd.Function) (*metav1.ObjectMeta, error) {
|
||||
err := f.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("Function", err)
|
||||
return nil, fv1.AggregateValidationErrors("Function", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(f)
|
||||
@@ -134,8 +134,9 @@ func (c *Client) FunctionDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) FunctionList() ([]crd.Function, error) {
|
||||
resp, err := http.Get(c.url("functions"))
|
||||
func (c *Client) FunctionList(functionNamespace string) ([]crd.Function, error) {
|
||||
relativeUrl := fmt.Sprintf("functions?namespace=%v", functionNamespace)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) HTTPTriggerCreate(t *crd.HTTPTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := t.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("HTTPTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("HTTPTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(t)
|
||||
@@ -86,7 +86,7 @@ func (c *Client) HTTPTriggerGet(m *metav1.ObjectMeta) (*crd.HTTPTrigger, error)
|
||||
func (c *Client) HTTPTriggerUpdate(t *crd.HTTPTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := t.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("HTTPTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("HTTPTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(t)
|
||||
@@ -120,8 +120,9 @@ func (c *Client) HTTPTriggerDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) HTTPTriggerList() ([]crd.HTTPTrigger, error) {
|
||||
resp, err := http.Get(c.url("triggers/http"))
|
||||
func (c *Client) HTTPTriggerList(triggerNamespace string) ([]crd.HTTPTrigger, error) {
|
||||
relativeUrl := fmt.Sprintf("triggers/http?namespace=%v", triggerNamespace)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -26,12 +26,13 @@ import (
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) WatchCreate(w *crd.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := w.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("KubernetesWatchTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("KubernetesWatchTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(w)
|
||||
@@ -94,8 +95,9 @@ func (c *Client) WatchDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) WatchList() ([]crd.KubernetesWatchTrigger, error) {
|
||||
resp, err := http.Get(c.url("watches"))
|
||||
func (c *Client) WatchList(ns string) ([]crd.KubernetesWatchTrigger, error) {
|
||||
relativeUrl := fmt.Sprintf("watches?namespace=%v", ns)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) MessageQueueTriggerCreate(t *crd.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := t.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("MessageQueueTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("MessageQueueTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(t)
|
||||
@@ -86,7 +86,7 @@ func (c *Client) MessageQueueTriggerGet(m *metav1.ObjectMeta) (*crd.MessageQueue
|
||||
func (c *Client) MessageQueueTriggerUpdate(mqTrigger *crd.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := mqTrigger.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("MessageQueueTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("MessageQueueTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(mqTrigger)
|
||||
@@ -120,11 +120,11 @@ func (c *Client) MessageQueueTriggerDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) MessageQueueTriggerList(mqType string) ([]crd.MessageQueueTrigger, error) {
|
||||
func (c *Client) MessageQueueTriggerList(mqType string, ns string) ([]crd.MessageQueueTrigger, error) {
|
||||
relativeUrl := "triggers/messagequeue"
|
||||
if len(mqType) > 0 {
|
||||
// TODO remove this, replace with field selector
|
||||
relativeUrl += fmt.Sprintf("?mqtype=%v", mqType)
|
||||
relativeUrl += fmt.Sprintf("?mqtype=%v&namespace=%v", mqType, ns)
|
||||
}
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) PackageCreate(f *crd.Package) (*metav1.ObjectMeta, error) {
|
||||
err := f.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("Package", err)
|
||||
return nil, fv1.AggregateValidationErrors("Package", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(f)
|
||||
@@ -86,7 +86,7 @@ func (c *Client) PackageGet(m *metav1.ObjectMeta) (*crd.Package, error) {
|
||||
func (c *Client) PackageUpdate(f *crd.Package) (*metav1.ObjectMeta, error) {
|
||||
err := f.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("Package", err)
|
||||
return nil, fv1.AggregateValidationErrors("Package", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(f)
|
||||
@@ -120,8 +120,9 @@ func (c *Client) PackageDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) PackageList() ([]crd.Package, error) {
|
||||
resp, err := http.Get(c.url("packages"))
|
||||
func (c *Client) PackageList(pkgNamespace string) ([]crd.Package, error) {
|
||||
relativeUrl := fmt.Sprintf("packages?namespace=%v", pkgNamespace)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
Copyright 2018 The Fission Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
"github.com/fission/fission/redis/build/gen"
|
||||
)
|
||||
|
||||
func (c *Client) RecorderCreate(r *crd.Recorder) (*metav1.ObjectMeta, error) {
|
||||
err := r.Validate()
|
||||
if err != nil {
|
||||
return nil, fv1.AggregateValidationErrors("Recorder", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := http.Post(c.url("recorders"), "application/json", bytes.NewReader(reqbody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleCreateResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var m metav1.ObjectMeta
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecorderGet(m *metav1.ObjectMeta) (*crd.Recorder, error) {
|
||||
relativeUrl := fmt.Sprintf("recorders/%v", m.Name)
|
||||
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var r crd.Recorder
|
||||
err = json.Unmarshal(body, &r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecorderUpdate(recorder *crd.Recorder) (*metav1.ObjectMeta, error) {
|
||||
err := recorder.Validate()
|
||||
if err != nil {
|
||||
return nil, fv1.AggregateValidationErrors("Recorder", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(recorder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
relativeUrl := fmt.Sprintf("recorders/%v", recorder.Metadata.Name)
|
||||
|
||||
resp, err := c.put(relativeUrl, "application/json", reqbody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var m metav1.ObjectMeta
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecorderDelete(m *metav1.ObjectMeta) error {
|
||||
relativeUrl := fmt.Sprintf("recorders/%v", m.Name)
|
||||
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) RecorderList(ns string) ([]crd.Recorder, error) {
|
||||
relativeUrl := "recorders"
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
recorders := make([]crd.Recorder, 0)
|
||||
err = json.Unmarshal(body, &recorders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return recorders, nil
|
||||
}
|
||||
|
||||
// TODO: Move to different file?
|
||||
func (c *Client) RecordsByFunction(function string) ([]*redisCache.RecordedEntry, error) {
|
||||
relativeUrl := fmt.Sprintf("records/function/%v", function)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := make([]*redisCache.RecordedEntry, 0)
|
||||
err = json.Unmarshal(body, &records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecordsAll() ([]*redisCache.RecordedEntry, error) {
|
||||
relativeUrl := "records"
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := make([]*redisCache.RecordedEntry, 0)
|
||||
err = json.Unmarshal(body, &records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecordsByTrigger(trigger string) ([]*redisCache.RecordedEntry, error) {
|
||||
relativeUrl := fmt.Sprintf("records/trigger/%v", trigger)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := make([]*redisCache.RecordedEntry, 0)
|
||||
err = json.Unmarshal(body, &records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecordsByTime(from string, to string) ([]*redisCache.RecordedEntry, error) {
|
||||
relativeUrl := "records/time"
|
||||
relativeUrl += fmt.Sprintf("?from=%v&to=%v", from, to)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records := make([]*redisCache.RecordedEntry, 0)
|
||||
err = json.Unmarshal(body, &records)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2018 The Fission Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (c *Client) ReplayByReqUID(reqUID string) ([]string, error) {
|
||||
relativeUrl := fmt.Sprintf("replay/%v", reqUID)
|
||||
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := c.handleResponse(resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
replayed := make([]string, 0)
|
||||
|
||||
err = json.Unmarshal(body, &replayed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return replayed, nil
|
||||
}
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
func (c *Client) TimeTriggerCreate(t *crd.TimeTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := t.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("TimeTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("TimeTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(t)
|
||||
@@ -86,7 +86,7 @@ func (c *Client) TimeTriggerGet(m *metav1.ObjectMeta) (*crd.TimeTrigger, error)
|
||||
func (c *Client) TimeTriggerUpdate(t *crd.TimeTrigger) (*metav1.ObjectMeta, error) {
|
||||
err := t.Validate()
|
||||
if err != nil {
|
||||
return nil, fission.AggregateValidationErrors("TimeTrigger", err)
|
||||
return nil, fv1.AggregateValidationErrors("TimeTrigger", err)
|
||||
}
|
||||
|
||||
reqbody, err := json.Marshal(t)
|
||||
@@ -120,8 +120,9 @@ func (c *Client) TimeTriggerDelete(m *metav1.ObjectMeta) error {
|
||||
return c.delete(relativeUrl)
|
||||
}
|
||||
|
||||
func (c *Client) TimeTriggerList() ([]crd.TimeTrigger, error) {
|
||||
resp, err := http.Get(c.url("triggers/time"))
|
||||
func (c *Client) TimeTriggerList(ns string) ([]crd.TimeTrigger, error) {
|
||||
relativeUrl := fmt.Sprintf("triggers/time?namespace=%v", ns)
|
||||
resp, err := http.Get(c.url(relativeUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2018 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 (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/fission/fission/canaryconfigmgr"
|
||||
"github.com/fission/fission/crd"
|
||||
config "github.com/fission/fission/featureconfig"
|
||||
)
|
||||
|
||||
func ConfigCanaryFeature(context context.Context, fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset, featureConfig *config.FeatureConfig) error {
|
||||
// start the appropriate controller
|
||||
if featureConfig.CanaryConfig.IsEnabled {
|
||||
canaryCfgMgr, err := canaryconfigmgr.MakeCanaryConfigMgr(fissionClient, kubeClient, fissionClient.GetCrdClient(),
|
||||
featureConfig.CanaryConfig.PrometheusSvc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start canary config manager: %v", err)
|
||||
}
|
||||
canaryCfgMgr.Run(context)
|
||||
log.Printf("Started canary config manager")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureFeatures gets the feature config and configures the features that are enabled
|
||||
func ConfigureFeatures(context context.Context, unitTestMode bool, fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset) (*config.FeatureConfig, error) {
|
||||
// set feature enabled to false if unitTestMode
|
||||
if unitTestMode {
|
||||
featureConfig := &config.FeatureConfig{}
|
||||
return featureConfig, nil
|
||||
}
|
||||
|
||||
// get the featureConfig from config map mounted onto the file system
|
||||
featureConfig, err := config.GetFeatureConfig()
|
||||
if err != nil {
|
||||
log.Printf("Error getting feature config : %v", err)
|
||||
return featureConfig, err
|
||||
}
|
||||
|
||||
// configure respective features
|
||||
// in the future when new optional features are added, we need to add corresponding feature handlers and invoke them here
|
||||
err = ConfigCanaryFeature(context, fissionClient, kubeClient, featureConfig)
|
||||
return featureConfig, err
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (a *API) ConfigMapGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["configmap"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
configMap, err := a.kubernetesClient.CoreV1().ConfigMaps(ns).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Error getting config map: %s from ns: %s", name, ns)
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(configMap)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
@@ -17,17 +17,18 @@ limitations under the License.
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
)
|
||||
|
||||
func Start(port int) {
|
||||
func Start(port int, unitTestFlag bool) {
|
||||
// setup a signal handler for SIGTERM
|
||||
fission.SetupStackTraceHandler()
|
||||
|
||||
fc, _, apiExtClient, err := crd.MakeFissionClient()
|
||||
fc, kc, apiExtClient, err := crd.MakeFissionClient()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to K8s API: %v", err)
|
||||
}
|
||||
@@ -42,7 +43,16 @@ func Start(port int) {
|
||||
log.Fatalf("Error waiting for CRDs: %v", err)
|
||||
}
|
||||
|
||||
api, err := MakeAPI()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
featureConfig, err := ConfigureFeatures(ctx, unitTestFlag, fc, kc)
|
||||
if err != nil {
|
||||
log.Printf("Error configuring features : %v. Proceeding without optional features", err.Error())
|
||||
// set all features to false for the MakeApi call below
|
||||
featureConfig.CanaryConfig.IsEnabled = false
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
api, err := MakeAPI(featureConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start controller: %v", err)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,12 @@ import (
|
||||
)
|
||||
|
||||
func (a *API) EnvironmentApiList(w http.ResponseWriter, r *http.Request) {
|
||||
envs, err := a.fissionClient.Environments(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
|
||||
envs, err := a.fissionClient.Environments(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -60,6 +65,13 @@ func (a *API) EnvironmentApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(env.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
enew, err := a.fissionClient.Environments(env.Metadata.Namespace).Create(&env)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
@@ -79,7 +91,8 @@ func (a *API) EnvironmentApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) EnvironmentApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["environment"]
|
||||
ns := vars["namespace"]
|
||||
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -140,7 +153,8 @@ func (a *API) EnvironmentApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) EnvironmentApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["environment"]
|
||||
ns := vars["namespace"]
|
||||
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
@@ -28,9 +28,8 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/pkg/api"
|
||||
apiv1 "k8s.io/client-go/pkg/api/v1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
|
||||
"github.com/fission/fission"
|
||||
@@ -44,7 +43,12 @@ func (a *API) getIstioServiceLabels(fnName string) map[string]string {
|
||||
}
|
||||
|
||||
func (a *API) FunctionApiList(w http.ResponseWriter, r *http.Request) {
|
||||
funcs, err := a.fissionClient.Functions(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
|
||||
funcs, err := a.fissionClient.Functions(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -73,6 +77,13 @@ func (a *API) FunctionApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(f.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
fnew, err := a.fissionClient.Functions(f.Metadata.Namespace).Create(&f)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
@@ -92,7 +103,7 @@ func (a *API) FunctionApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) FunctionApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["function"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -151,7 +162,7 @@ func (a *API) FunctionApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) FunctionApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["function"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -205,7 +216,7 @@ func (a *API) FunctionPodLogs(w http.ResponseWriter, r *http.Request) {
|
||||
ns = "fission-function"
|
||||
}
|
||||
|
||||
f, err := a.fissionClient.Functions(api.NamespaceDefault).Get(fnName)
|
||||
f, err := a.fissionClient.Functions(ns).Get(fnName)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
|
||||
@@ -30,7 +30,12 @@ import (
|
||||
)
|
||||
|
||||
func (a *API) HTTPTriggerApiList(w http.ResponseWriter, r *http.Request) {
|
||||
triggers, err := a.fissionClient.HTTPTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
|
||||
triggers, err := a.fissionClient.HTTPTriggers(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -81,6 +86,13 @@ func (a *API) HTTPTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(t.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
tnew, err := a.fissionClient.HTTPTriggers(t.Metadata.Namespace).Create(&t)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
@@ -100,7 +112,7 @@ func (a *API) HTTPTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) HTTPTriggerApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["httpTrigger"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -166,7 +178,7 @@ func (a *API) HTTPTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) HTTPTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["httpTrigger"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
@@ -30,7 +30,12 @@ import (
|
||||
|
||||
func (a *API) MessageQueueTriggerApiList(w http.ResponseWriter, r *http.Request) {
|
||||
//mqType := r.FormValue("mqtype") // ignored for now
|
||||
triggers, err := a.fissionClient.MessageQueueTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
|
||||
triggers, err := a.fissionClient.MessageQueueTriggers(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -57,6 +62,13 @@ func (a *API) MessageQueueTriggerApiCreate(w http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(mqTrigger.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
tnew, err := a.fissionClient.MessageQueueTriggers(mqTrigger.Metadata.Namespace).Create(&mqTrigger)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
@@ -75,7 +87,7 @@ func (a *API) MessageQueueTriggerApiCreate(w http.ResponseWriter, r *http.Reques
|
||||
func (a *API) MessageQueueTriggerApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["mqTrigger"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -133,7 +145,7 @@ func (a *API) MessageQueueTriggerApiUpdate(w http.ResponseWriter, r *http.Reques
|
||||
func (a *API) MessageQueueTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["mqTrigger"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/gorilla/mux"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@@ -29,7 +31,11 @@ import (
|
||||
)
|
||||
|
||||
func (a *API) PackageApiList(w http.ResponseWriter, r *http.Request) {
|
||||
funcs, err := a.fissionClient.Packages(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
funcs, err := a.fissionClient.Packages(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -59,13 +65,22 @@ func (a *API) PackageApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Ensure size limits
|
||||
if len(f.Spec.Source.Literal) > 256*1024 {
|
||||
err := fission.MakeError(fission.ErrorInvalidArgument, "Package literal larger than 256K")
|
||||
if len(f.Spec.Source.Literal) > int(fission.ArchiveLiteralSizeLimit) {
|
||||
err := fission.MakeError(fission.ErrorInvalidArgument,
|
||||
fmt.Sprintf("Package literal larger than %s", humanize.Bytes(uint64(fission.ArchiveLiteralSizeLimit))))
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
if len(f.Spec.Deployment.Literal) > 256*1024 {
|
||||
err := fission.MakeError(fission.ErrorInvalidArgument, "Package literal larger than 256K")
|
||||
if len(f.Spec.Deployment.Literal) > int(fission.ArchiveLiteralSizeLimit) {
|
||||
err := fission.MakeError(fission.ErrorInvalidArgument,
|
||||
fmt.Sprintf("Package literal larger than %s", humanize.Bytes(uint64(fission.ArchiveLiteralSizeLimit))))
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(f.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
@@ -89,7 +104,7 @@ func (a *API) PackageApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) PackageApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["package"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -154,7 +169,7 @@ func (a *API) PackageApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) PackageApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["package"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Copyright 2018 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 (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission"
|
||||
"github.com/fission/fission/crd"
|
||||
)
|
||||
|
||||
func (a *API) RecorderApiList(w http.ResponseWriter, r *http.Request) {
|
||||
recorders, err := a.fissionClient.Recorders(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
resp, err := json.Marshal(recorders.Items)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecorderApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
var recorder crd.Recorder
|
||||
err = json.Unmarshal(body, &recorder)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
tnew, err := a.fissionClient.Recorders(recorder.Metadata.Namespace).Create(&recorder)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(tnew.Metadata)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecorderApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["recorder"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
recorder, err := a.fissionClient.Recorders(ns).Get(name)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
resp, err := json.Marshal(recorder)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecorderApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["recorder"]
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
var recorder crd.Recorder
|
||||
err = json.Unmarshal(body, &recorder)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if name != recorder.Metadata.Name {
|
||||
err = fission.MakeError(fission.ErrorInvalidArgument, "Recorder name doesn't match URL")
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
rnew, err := a.fissionClient.Recorders(recorder.Metadata.Namespace).Update(&recorder)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(rnew.Metadata)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecorderApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["recorder"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
err := a.fissionClient.Recorders(ns).Delete(name, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, []byte(""))
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2018 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"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/fission/fission/redis"
|
||||
)
|
||||
|
||||
func (a *API) RecordsApiListAll(w http.ResponseWriter, r *http.Request) {
|
||||
resp, err := redis.RecordsListAll()
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecordsApiFilterByFunction(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
query := vars["function"]
|
||||
|
||||
recorders, err := a.fissionClient.Recorders(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
triggers, err := a.fissionClient.HTTPTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := redis.RecordsFilterByFunction(query, recorders, triggers)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecordsApiFilterByTrigger(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
query := vars["trigger"]
|
||||
|
||||
recorders, err := a.fissionClient.Recorders(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
triggers, err := a.fissionClient.HTTPTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := redis.RecordsFilterByTrigger(query, recorders, triggers)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
|
||||
func (a *API) RecordsApiFilterByTime(w http.ResponseWriter, r *http.Request) {
|
||||
from := r.FormValue("from")
|
||||
to := r.FormValue("to")
|
||||
|
||||
resp, err := redis.RecordsFilterByTime(from, to)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2018 The Fission Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/fission/fission/redis"
|
||||
)
|
||||
|
||||
func (a *API) ReplayByReqUID(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
queriedID := vars["reqUID"]
|
||||
|
||||
routerUrl := fmt.Sprintf("http://router.%v", podNamespace)
|
||||
|
||||
resp, err := redis.ReplayByReqUID(routerUrl, queriedID)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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 controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (a *API) SecretGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["secret"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
secret, err := a.kubernetesClient.CoreV1().Secrets(ns).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Printf("Error getting secret: %s from ns: %s", name, ns)
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := json.Marshal(secret)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
a.respondWithSuccess(w, resp)
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (api *API) StorageServiceProxy(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error parsing url %v: %v", u, err)
|
||||
log.Println(msg)
|
||||
http.Error(w, msg, 500)
|
||||
http.Error(w, msg, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
director := func(req *http.Request) {
|
||||
|
||||
@@ -30,7 +30,12 @@ import (
|
||||
)
|
||||
|
||||
func (a *API) TimeTriggerApiList(w http.ResponseWriter, r *http.Request) {
|
||||
triggers, err := a.fissionClient.TimeTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
|
||||
triggers, err := a.fissionClient.TimeTriggers(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -67,6 +72,13 @@ func (a *API) TimeTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(t.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
tnew, err := a.fissionClient.TimeTriggers(t.Metadata.Namespace).Create(&t)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
@@ -86,7 +98,7 @@ func (a *API) TimeTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) TimeTriggerApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["timeTrigger"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -153,7 +165,7 @@ func (a *API) TimeTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) TimeTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["timeTrigger"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
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)
|
||||
}
|
||||
+15
-3
@@ -29,7 +29,12 @@ import (
|
||||
)
|
||||
|
||||
func (a *API) WatchApiList(w http.ResponseWriter, r *http.Request) {
|
||||
watches, err := a.fissionClient.KubernetesWatchTriggers(metav1.NamespaceAll).List(metav1.ListOptions{})
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceAll
|
||||
}
|
||||
|
||||
watches, err := a.fissionClient.KubernetesWatchTriggers(ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
@@ -59,6 +64,13 @@ func (a *API) WatchApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// TODO check for duplicate watches
|
||||
// TODO check for duplicate watches -> we probably wont need it?
|
||||
// check if namespace exists, if not create it.
|
||||
err = a.createNsIfNotExists(watch.Metadata.Namespace)
|
||||
if err != nil {
|
||||
a.respondWithError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
wnew, err := a.fissionClient.KubernetesWatchTriggers(watch.Metadata.Namespace).Create(&watch)
|
||||
if err != nil {
|
||||
@@ -79,7 +91,7 @@ func (a *API) WatchApiCreate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) WatchApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["watch"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
@@ -107,7 +119,7 @@ func (a *API) WatchApiUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) WatchApiDelete(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["watch"]
|
||||
ns := vars["namespace"]
|
||||
ns := a.extractQueryParamFromRequest(r, "namespace")
|
||||
if len(ns) == 0 {
|
||||
ns = metav1.NamespaceDefault
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ func (api *API) WorkflowApiserverProxy(w http.ResponseWriter, r *http.Request) {
|
||||
ssUrl, err := url.Parse(u)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error parsing url %v: %v", u, err)
|
||||
http.Error(w, msg, 500)
|
||||
http.Error(w, msg, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
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/watch"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type (
|
||||
CanaryConfigInterface interface {
|
||||
Create(*CanaryConfig) (*CanaryConfig, error)
|
||||
Get(name string) (*CanaryConfig, error)
|
||||
Update(*CanaryConfig) (*CanaryConfig, error)
|
||||
Delete(name string, options *metav1.DeleteOptions) error
|
||||
List(opts metav1.ListOptions) (*CanaryConfigList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
canaryConfigClient struct {
|
||||
client *rest.RESTClient
|
||||
namespace string
|
||||
}
|
||||
)
|
||||
|
||||
func MakeCanaryConfigInterface(crdClient *rest.RESTClient, namespace string) CanaryConfigInterface {
|
||||
return &canaryConfigClient{
|
||||
client: crdClient,
|
||||
namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *canaryConfigClient) Create(f *CanaryConfig) (*CanaryConfig, error) {
|
||||
var result CanaryConfig
|
||||
err := c.client.Post().
|
||||
Resource("canaryconfigs").
|
||||
Namespace(c.namespace).
|
||||
Body(f).
|
||||
Do().Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *canaryConfigClient) Get(name string) (*CanaryConfig, error) {
|
||||
var result CanaryConfig
|
||||
err := c.client.Get().
|
||||
Resource("canaryconfigs").
|
||||
Namespace(c.namespace).
|
||||
Name(name).
|
||||
Do().Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *canaryConfigClient) Update(f *CanaryConfig) (*CanaryConfig, error) {
|
||||
var result CanaryConfig
|
||||
err := c.client.Put().
|
||||
Resource("canaryconfigs").
|
||||
Namespace(c.namespace).
|
||||
Name(f.Metadata.Name).
|
||||
Body(f).
|
||||
Do().Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *canaryConfigClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.namespace).
|
||||
Resource("canaryconfigs").
|
||||
Name(name).
|
||||
Body(opts).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (c *canaryConfigClient) List(opts metav1.ListOptions) (*CanaryConfigList, error) {
|
||||
var result CanaryConfigList
|
||||
err := c.client.Get().
|
||||
Namespace(c.namespace).
|
||||
Resource("canaryconfigs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *canaryConfigClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return c.client.Get().
|
||||
Prefix("watch").
|
||||
Namespace(c.namespace).
|
||||
Resource("canaryconfigs").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+20
-1
@@ -153,6 +153,20 @@ func configureClient(config *rest.Config) {
|
||||
&metav1.ListOptions{},
|
||||
&metav1.DeleteOptions{},
|
||||
)
|
||||
scheme.AddKnownTypes(
|
||||
groupversion,
|
||||
&Recorder{},
|
||||
&RecorderList{},
|
||||
&metav1.ListOptions{},
|
||||
&metav1.DeleteOptions{},
|
||||
)
|
||||
scheme.AddKnownTypes(
|
||||
groupversion,
|
||||
&CanaryConfig{},
|
||||
&CanaryConfigList{},
|
||||
&metav1.ListOptions{},
|
||||
&metav1.DeleteOptions{},
|
||||
)
|
||||
return nil
|
||||
})
|
||||
schemeBuilder.AddToScheme(scheme.Scheme)
|
||||
@@ -208,10 +222,15 @@ func (fc *FissionClient) TimeTriggers(ns string) TimeTriggerInterface {
|
||||
func (fc *FissionClient) MessageQueueTriggers(ns string) MessageQueueTriggerInterface {
|
||||
return MakeMessageQueueTriggerInterface(fc.crdClient, ns)
|
||||
}
|
||||
func (fc *FissionClient) Recorders(ns string) RecorderInterface {
|
||||
return MakeRecorderInterface(fc.crdClient, ns)
|
||||
}
|
||||
func (fc *FissionClient) Packages(ns string) PackageInterface {
|
||||
return MakePackageInterface(fc.crdClient, ns)
|
||||
}
|
||||
|
||||
func (fc *FissionClient) CanaryConfigs(ns string) CanaryConfigInterface {
|
||||
return MakeCanaryConfigInterface(fc.crdClient, ns)
|
||||
}
|
||||
func (fc *FissionClient) WaitForCRDs() error {
|
||||
return waitForCRDs(fc.crdClient)
|
||||
}
|
||||
|
||||
+36
-7
@@ -38,17 +38,14 @@ func ensureCRD(clientset *apiextensionsclient.Clientset, crd *apiextensionsv1bet
|
||||
maxRetries := 5
|
||||
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
_, err = clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Get(crd.ObjectMeta.Name, metav1.GetOptions{})
|
||||
_, err = clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if errors.IsNotFound(err) {
|
||||
// crd resource not found error
|
||||
_, err = clientset.ApiextensionsV1beta1().CustomResourceDefinitions().Create(crd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// return if the resource already exists
|
||||
if errors.IsAlreadyExists(err) {
|
||||
return nil
|
||||
} else {
|
||||
// The requests fail to connect to k8s api server before
|
||||
// istio-prxoy is ready to serve traffic. Retry again.
|
||||
@@ -160,6 +157,22 @@ func EnsureFissionCRDs(clientset *apiextensionsclient.Clientset) error {
|
||||
},
|
||||
},
|
||||
},
|
||||
// Recorders
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "recorders.fission.io",
|
||||
},
|
||||
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
|
||||
Group: crdGroupName,
|
||||
Version: crdVersion,
|
||||
Scope: apiextensionsv1beta1.NamespaceScoped,
|
||||
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
|
||||
Kind: "Recorder",
|
||||
Plural: "recorders",
|
||||
Singular: "recorder",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Packages: archives containing source or binaries for one or more functions
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -176,6 +189,22 @@ func EnsureFissionCRDs(clientset *apiextensionsclient.Clientset) error {
|
||||
},
|
||||
},
|
||||
},
|
||||
// CanaryConfig: configuration for canary deployment of functions
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "canaryconfigs.fission.io",
|
||||
},
|
||||
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
|
||||
Group: crdGroupName,
|
||||
Version: crdVersion,
|
||||
Scope: apiextensionsv1beta1.NamespaceScoped,
|
||||
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
|
||||
Kind: "CanaryConfig",
|
||||
Plural: "canaryconfigs",
|
||||
Singular: "canaryconfig",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, crd := range crds {
|
||||
err := ensureCRD(clientset, &crd)
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
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/watch"
|
||||
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type (
|
||||
RecorderInterface interface {
|
||||
Create(*Recorder) (*Recorder, error)
|
||||
Get(name string) (*Recorder, error)
|
||||
Update(*Recorder) (*Recorder, error)
|
||||
Delete(name string, opts *metav1.DeleteOptions) error
|
||||
List(opts metav1.ListOptions) (*RecorderList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
recorderClient struct {
|
||||
client *rest.RESTClient
|
||||
namespace string
|
||||
}
|
||||
)
|
||||
|
||||
func MakeRecorderInterface(crdClient *rest.RESTClient, namespace string) RecorderInterface {
|
||||
return &recorderClient{
|
||||
client: crdClient,
|
||||
namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *recorderClient) Create(r *Recorder) (*Recorder, error) {
|
||||
var result Recorder
|
||||
err := rc.client.Post().
|
||||
Resource("recorders").
|
||||
Namespace("default").
|
||||
Body(r).
|
||||
Do().Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (rc *recorderClient) Get(name string) (*Recorder, error) {
|
||||
var result Recorder
|
||||
err := rc.client.Get().
|
||||
Resource("recorders").
|
||||
Namespace(rc.namespace).
|
||||
Name(name).
|
||||
Do().Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (rc *recorderClient) Update(r *Recorder) (*Recorder, error) {
|
||||
var result Recorder
|
||||
err := rc.client.Put().
|
||||
Resource("recorders").
|
||||
Namespace(rc.namespace).
|
||||
Name(r.Metadata.Name).
|
||||
Body(r).
|
||||
Do().Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (rc *recorderClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
return rc.client.Delete().
|
||||
Namespace(rc.namespace).
|
||||
Resource("recorders").
|
||||
Name(name).
|
||||
Body(opts).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
func (rc *recorderClient) List(opts metav1.ListOptions) (*RecorderList, error) {
|
||||
var result RecorderList
|
||||
err := rc.client.Get().
|
||||
Namespace(rc.namespace).
|
||||
Resource("recorders").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (rc *recorderClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return rc.client.Get().
|
||||
Prefix("watch").
|
||||
Namespace(rc.namespace).
|
||||
Resource("recorders").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Watch()
|
||||
}
|
||||
+19
-338
@@ -17,345 +17,26 @@ limitations under the License.
|
||||
package crd
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/fission/fission"
|
||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||
)
|
||||
|
||||
//
|
||||
// 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"`
|
||||
}
|
||||
Package = fv1.Package
|
||||
PackageList = fv1.PackageList
|
||||
Function = fv1.Function
|
||||
FunctionList = fv1.FunctionList
|
||||
Environment = fv1.Environment
|
||||
EnvironmentList = fv1.EnvironmentList
|
||||
HTTPTrigger = fv1.HTTPTrigger
|
||||
HTTPTriggerList = fv1.HTTPTriggerList
|
||||
KubernetesWatchTrigger = fv1.KubernetesWatchTrigger
|
||||
KubernetesWatchTriggerList = fv1.KubernetesWatchTriggerList
|
||||
TimeTrigger = fv1.TimeTrigger
|
||||
TimeTriggerList = fv1.TimeTriggerList
|
||||
MessageQueueTrigger = fv1.MessageQueueTrigger
|
||||
MessageQueueTriggerList = fv1.MessageQueueTriggerList
|
||||
Recorder = fv1.Recorder
|
||||
RecorderList = fv1.RecorderList
|
||||
CanaryConfig = fv1.CanaryConfig
|
||||
CanaryConfigList = fv1.CanaryConfigList
|
||||
)
|
||||
|
||||
// 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 (t *TimeTrigger) GetObjectKind() schema.ObjectKind {
|
||||
return &t.TypeMeta
|
||||
}
|
||||
func (m *MessageQueueTrigger) GetObjectKind() schema.ObjectKind {
|
||||
return &m.TypeMeta
|
||||
}
|
||||
func (p *Package) GetObjectKind() schema.ObjectKind {
|
||||
return &p.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 (t *TimeTrigger) GetObjectMeta() metav1.Object {
|
||||
return &t.Metadata
|
||||
}
|
||||
func (m *MessageQueueTrigger) GetObjectMeta() metav1.Object {
|
||||
return &m.Metadata
|
||||
}
|
||||
func (p *Package) GetObjectMeta() metav1.Object {
|
||||
return &p.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 (ml *MessageQueueTriggerList) GetObjectKind() schema.ObjectKind {
|
||||
return &ml.TypeMeta
|
||||
}
|
||||
func (pl *PackageList) GetObjectKind() schema.ObjectKind {
|
||||
return &pl.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 (ml *MessageQueueTriggerList) GetListMeta() metav1.List {
|
||||
return &ml.Metadata
|
||||
}
|
||||
func (pl *PackageList) GetListMeta() metav1.List {
|
||||
return &pl.Metadata
|
||||
}
|
||||
|
||||
func validateMetadata(field string, m metav1.ObjectMeta) error {
|
||||
return fission.ValidateKubeReference(field, m.Name, m.Namespace)
|
||||
}
|
||||
|
||||
func (p *Package) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("Package", p.Metadata),
|
||||
p.Spec.Validate(),
|
||||
p.Status.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (pl *PackageList) Validate() error {
|
||||
var result *multierror.Error
|
||||
// not validate ListMeta
|
||||
for _, p := range pl.Items {
|
||||
result = multierror.Append(result, p.Validate())
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (f *Function) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("Function", f.Metadata),
|
||||
f.Spec.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (fl *FunctionList) Validate() error {
|
||||
var result *multierror.Error
|
||||
for _, f := range fl.Items {
|
||||
result = multierror.Append(result, f.Validate())
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (e *Environment) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("Environment", e.Metadata),
|
||||
e.Spec.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (el *EnvironmentList) Validate() error {
|
||||
var result *multierror.Error
|
||||
for _, e := range el.Items {
|
||||
result = multierror.Append(result, e.Validate())
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (h *HTTPTrigger) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("HTTPTrigger", h.Metadata),
|
||||
h.Spec.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (hl *HTTPTriggerList) Validate() error {
|
||||
var result *multierror.Error
|
||||
for _, h := range hl.Items {
|
||||
result = multierror.Append(result, h.Validate())
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (k *KubernetesWatchTrigger) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("KubernetesWatchTrigger", k.Metadata),
|
||||
k.Spec.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (kl *KubernetesWatchTriggerList) Validate() error {
|
||||
var result *multierror.Error
|
||||
for _, k := range kl.Items {
|
||||
result = multierror.Append(result, k.Validate())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (t *TimeTrigger) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("TimeTrigger", t.Metadata),
|
||||
t.Spec.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (tl *TimeTriggerList) Validate() error {
|
||||
var result *multierror.Error
|
||||
for _, t := range tl.Items {
|
||||
result = multierror.Append(result, t.Validate())
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (m *MessageQueueTrigger) Validate() error {
|
||||
var result *multierror.Error
|
||||
|
||||
result = multierror.Append(result,
|
||||
validateMetadata("MessageQueueTrigger", m.Metadata),
|
||||
m.Spec.Validate())
|
||||
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (ml *MessageQueueTriggerList) Validate() error {
|
||||
var result *multierror.Error
|
||||
for _, m := range ml.Items {
|
||||
result = multierror.Append(result, m.Validate())
|
||||
}
|
||||
return result.ErrorOrNil()
|
||||
}
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
kubectl delete canaryconfig canary-2
|
||||
kubectl delete httptrigger route-fail
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# this script is useful to demo canary deployment when the latest function starts receiving 100% of the traffic
|
||||
|
||||
DEMO_RUN_FAST=1
|
||||
ROOT_DIR=$(dirname $0)/..
|
||||
. $ROOT_DIR/util.sh
|
||||
|
||||
|
||||
desc "Function version-1"
|
||||
run "fission function get --name fn1-v6"
|
||||
|
||||
desc "Function version-2"
|
||||
run "fission function get --name fn1-v7"
|
||||
|
||||
desc "Create a route \(HTTP trigger\) the version-1 of the function with weight 100% and version-2 with weight 0%"
|
||||
run "fission route create --name route-fail --method GET --url /fail --function fn1-v6 --weight 100 --function fn1-v7 --weight 0"
|
||||
|
||||
desc "Create a canary config to gradually increment the weight of version-2 by a step of 20 every 1 minute"
|
||||
run "fission canary-config create --name canary-2 --newfunction fn1-v7 --oldfunction fn1-v6 --httptrigger route-fail --increment-step 30 --increment-interval 30s --failure-threshold 10"
|
||||
|
||||
desc "Fire requests to the route"
|
||||
run "ab -n 10000 -c 1 http://$FISSION_ROUTER/fail"
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
kubectl delete canaryconfig canary-1
|
||||
kubectl delete httptrigger route-canary
|
||||
|
||||
fission fn delete --name func-v1
|
||||
fission fn delete --name func-v2
|
||||
fission package delete --orphan
|
||||
|
||||
# bug in canary config cache when you re-create a config with the same name, restart controller
|
||||
kubectl -n fission get pod -l application=fission-api -o name | xargs -n1 kubectl -n fission delete
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
module.exports = async function(context) {
|
||||
return {
|
||||
status: 200,
|
||||
body: "This is Version One!\n"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
module.exports = async function(context) {
|
||||
return {
|
||||
status: 200,
|
||||
body: "This is Version Two!\n"
|
||||
};
|
||||
}
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
# this script is useful to demo canary deployment when the latest function starts receiving 100% of the traffic
|
||||
|
||||
DEMO_RUN_FAST=1
|
||||
ROOT_DIR=$(dirname $0)/..
|
||||
. $ROOT_DIR/util.sh
|
||||
|
||||
desc "Kubernetes cluster"
|
||||
run "kubectl get nodes"
|
||||
|
||||
desc "Fission installed"
|
||||
run "kubectl --namespace fission get deployment"
|
||||
|
||||
clear
|
||||
|
||||
desc "NodeJS environment pods"
|
||||
run "kubectl --namespace fission-function get pod -l environmentName=nodejs"
|
||||
|
||||
# set up functions
|
||||
fission fn create --name func-v1 --env nodejs --code func-v1.js
|
||||
desc "Function version 1"
|
||||
run "fission function get --name func-v1"
|
||||
|
||||
fission fn create --name func-v2 --env nodejs --code func-v2.js
|
||||
desc "Function version 2"
|
||||
run "fission function get --name func-v2"
|
||||
|
||||
desc "Create a route \(HTTP trigger\) the version-1 of the function with weight 100% and version-2 with weight 0%"
|
||||
run "fission route create --name route-canary --method GET --url /canary --function func-v2 --weight 0 --function func-v1 --weight 100"
|
||||
|
||||
desc "Start sending requests to the route"
|
||||
run_bg "hey -n 100000 -c 1 http://$FISSION_ROUTER/canary"
|
||||
|
||||
desc "Create a canary config: with an increment of 10 percent, every 1 minute, rolling back if 10% of requests fail"
|
||||
run "fission canary-config create --name canary-1 --newfunction func-v2 --oldfunction func-v1 --httptrigger route-canary --increment-step 10 --increment-interval 30s --failure-threshold 10"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
fission fn delete --name hello
|
||||
fission route delete --name $(fission route list|grep hello|cut -f1 -d' ')
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
module.exports = async function(context) {
|
||||
return {
|
||||
status: 200,
|
||||
body: "This is Version One!\n"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
module.exports = async function(context) {
|
||||
return {
|
||||
status: 200,
|
||||
body: "This is Version Two!\n"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
module.exports = async function(context) {
|
||||
return {
|
||||
status: 200,
|
||||
body: "Hello, world!\n"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEMO_RUN_FAST=1
|
||||
ROOT_DIR=$(dirname $0)/..
|
||||
. $ROOT_DIR/util.sh
|
||||
|
||||
|
||||
#
|
||||
# General setup intro
|
||||
#
|
||||
desc "Our Kubernetes cluster"
|
||||
run "kubectl get nodes"
|
||||
|
||||
desc "Fission is installed"
|
||||
run "kubectl --namespace fission get deployment"
|
||||
|
||||
clear
|
||||
|
||||
#
|
||||
# Hello world, environments, cold starts
|
||||
#
|
||||
|
||||
desc "Hello world function"
|
||||
run "cat hello.js"
|
||||
|
||||
desc "Add the NodeJS environment to fission"
|
||||
run "fission env create --name nodejs --image fission/node-env"
|
||||
|
||||
desc "NodeJS environment pods"
|
||||
run "kubectl --namespace fission-function get pod -l environmentName=nodejs"
|
||||
|
||||
desc "Upload our function to fission"
|
||||
run "fission function create --name hello --env nodejs --code hello.js"
|
||||
|
||||
desc "Set up a route (aka HTTP Trigger) for the function"
|
||||
run "fission route create --method GET --url /hello --function hello"
|
||||
|
||||
sleep 2
|
||||
|
||||
desc "Finally, run the function"
|
||||
run "time -p curl http://$FISSION_ROUTER/hello"
|
||||
|
||||
desc "Run the function again"
|
||||
run "time -p curl http://$FISSION_ROUTER/hello"
|
||||
run "time -p curl http://$FISSION_ROUTER/hello"
|
||||
|
||||
desc "The pod is now labeled by the function name"
|
||||
run "kubectl --namespace fission-function get pod -l functionName=hello"
|
||||
|
||||
#
|
||||
# Declarative Specs.
|
||||
#
|
||||
# Use go for this one to show off the fact that we can do builds.
|
||||
#
|
||||
clear
|
||||
|
||||
pushd declarative
|
||||
|
||||
desc "Declaratively specified app"
|
||||
run "ls"
|
||||
|
||||
desc "Declaratively specified app"
|
||||
run "ls specs"
|
||||
|
||||
desc "Validate configs"
|
||||
run "fission spec validate"
|
||||
|
||||
desc "Deploy application, wait for build to finish"
|
||||
run "fission spec apply --wait"
|
||||
|
||||
desc "Invoke our new function"
|
||||
run "fission function test --name hello-go"
|
||||
|
||||
#
|
||||
# Live Reload (still in the same app)
|
||||
#
|
||||
clear
|
||||
|
||||
|
||||
|
||||
|
||||
popd
|
||||
|
||||
#
|
||||
# Record replay
|
||||
#
|
||||
clear
|
||||
|
||||
#
|
||||
# Canary Deployments
|
||||
#
|
||||
clear
|
||||
|
||||
# set up functions
|
||||
fission fn create --name func-v1 --env nodejs --code func-v1.js
|
||||
desc "Function version 1"
|
||||
run "fission function get --name func-v1"
|
||||
|
||||
fission fn create --name func-v2 --env nodejs --code func-v2.js
|
||||
desc "Function version 2"
|
||||
run "fission function get --name func-v2"
|
||||
|
||||
desc "Create a route \(HTTP trigger\) the version-1 of the function with weight 100% and version-2 with weight 0%"
|
||||
run "fission route create --name route-canary --method GET --url /canary --function func-v2 --weight 0 --function func-v1 --weight 100"
|
||||
|
||||
desc "Start sending requests to the route"
|
||||
run_bg "hey -n 100000 -c 1 http://$FISSION_ROUTER/canary"
|
||||
|
||||
desc "Create a canary config: with an increment of 10 percent, every 1 minute, rolling back if 10% of requests fail"
|
||||
run "fission canary-config create --name canary-1 --newfunction func-v2 --oldfunction func-v1 --httptrigger route-canary --increment-step 10 --increment-interval 30s --failure-threshold 10"
|
||||
|
||||
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEMO_RUN_FAST=1
|
||||
ROOT_DIR=$(dirname $0)/..
|
||||
. $ROOT_DIR/util.sh
|
||||
|
||||
|
||||
desc "one"
|
||||
run "sleep 30"
|
||||
|
||||
desc "two"
|
||||
run "echo hi"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
fission spec destroy
|
||||
|
||||
# this one is generated in run.sh
|
||||
rm specs/function-hello-go.yaml
|
||||
|
||||
rm *.~?~
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Handler is the entry point for this fission function
|
||||
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
msg := "Hello, CNCF Webinar!\n"
|
||||
w.Write([]byte(msg))
|
||||
}
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEMO_RUN_FAST=1
|
||||
ROOT_DIR=$(dirname $0)/..
|
||||
. $ROOT_DIR/util.sh
|
||||
|
||||
desc "Declaratively specified app"
|
||||
run "ls specs"
|
||||
|
||||
desc "Generate initial YAML, so we don't have to write it by hand"
|
||||
run "fission function create --spec --name hello-go --env go --src hello.go --entrypoint Handler"
|
||||
|
||||
desc "Generated function YAML"
|
||||
run "tail -25 specs/function-hello-go.yaml"
|
||||
|
||||
desc "Deploy on cluster, and wait for build result"
|
||||
run "fission spec apply --wait"
|
||||
|
||||
desc "Invoke the function"
|
||||
run "fission function test --name hello-go"
|
||||
|
||||
desc "Live-reload: auto build + deploy on save"
|
||||
run "fission spec apply --watch"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
Fission Specs
|
||||
=============
|
||||
|
||||
This is a set of specifications for a Fission app. This includes functions,
|
||||
environments, and triggers; we collectively call these things "resources".
|
||||
|
||||
How to use these specs
|
||||
----------------------
|
||||
|
||||
These specs are handled with the 'fission spec' command. See 'fission spec --help'.
|
||||
|
||||
'fission spec apply' will "apply" all resources specified in this directory to your
|
||||
cluster. That means it checks what resources exist on your cluster, what resources are
|
||||
specified in the specs directory, and reconciles the difference by creating, updating or
|
||||
deleting resources on the cluster.
|
||||
|
||||
'fission spec apply' will also package up your source code (or compiled binaries) and
|
||||
upload the archives to the cluster if needed. It uses 'ArchiveUploadSpec' resources in
|
||||
this directory to figure out which files to archive.
|
||||
|
||||
You can use 'fission spec apply --watch' to watch for file changes and continuously keep
|
||||
the cluster updated.
|
||||
|
||||
You can add YAMLs to this directory by writing them manually, but it's easier to generate
|
||||
them. Use 'fission function create --spec' to generate a function spec,
|
||||
'fission environment create --spec' to generate an environment spec, and so on.
|
||||
|
||||
You can edit any of the files in this directory, except 'fission-deployment-config.yaml',
|
||||
which contains a UID that you should never change. To apply your changes simply use
|
||||
'fission spec apply'.
|
||||
|
||||
fission-deployment-config.yaml
|
||||
------------------------------
|
||||
|
||||
fission-deployment-config.yaml contains a UID. This UID is what fission uses to correlate
|
||||
resources on the cluster to resources in this directory.
|
||||
|
||||
All resources created by 'fission spec apply' are annotated with this UID. Resources on
|
||||
the cluster that are _not_ annotated with this UID are never modified or deleted by
|
||||
fission.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file is generated by the 'fission spec init' command.
|
||||
# See the README in this directory for background and usage information.
|
||||
# Do not edit the UID below: that will break 'fission spec apply'
|
||||
apiVersion: fission.io/v1
|
||||
kind: DeploymentConfig
|
||||
name: declarative-specs
|
||||
uid: e20fe7b4-b012-4ae0-98bd-0f968d21d397
|
||||
@@ -0,0 +1,51 @@
|
||||
include:
|
||||
- hello.go
|
||||
kind: ArchiveUploadSpec
|
||||
name: hello-go
|
||||
|
||||
---
|
||||
apiVersion: fission.io/v1
|
||||
kind: Package
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: hello-go-xfxy
|
||||
namespace: default
|
||||
spec:
|
||||
deployment:
|
||||
checksum: {}
|
||||
environment:
|
||||
name: go
|
||||
namespace: default
|
||||
source:
|
||||
checksum: {}
|
||||
type: url
|
||||
url: archive://hello-go
|
||||
status:
|
||||
buildstatus: pending
|
||||
|
||||
---
|
||||
apiVersion: fission.io/v1
|
||||
kind: Function
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: hello-go
|
||||
namespace: default
|
||||
spec:
|
||||
InvokeStrategy:
|
||||
ExecutionStrategy:
|
||||
ExecutorType: poolmgr
|
||||
MaxScale: 1
|
||||
MinScale: 0
|
||||
TargetCPUPercent: 80
|
||||
StrategyType: execution
|
||||
configmaps: null
|
||||
environment:
|
||||
name: go
|
||||
namespace: default
|
||||
package:
|
||||
functionName: Handler
|
||||
packageref:
|
||||
name: hello-go-xfxy
|
||||
namespace: default
|
||||
resources: {}
|
||||
secrets: null
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
fission fn delete --name hi-py
|
||||
fission route delete --name $(fission route list|grep hi|cut -f1 -d' ')
|
||||
fission recorder delete --name my-recorder
|
||||
kubectl -n fission delete pod redis-0
|
||||
@@ -0,0 +1,7 @@
|
||||
from flask import request
|
||||
from flask import current_app
|
||||
|
||||
|
||||
def main():
|
||||
name=request.args["name"]
|
||||
return "Hello, %s" % name
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEMO_RUN_FAST=1
|
||||
ROOT_DIR=$(dirname $0)/..
|
||||
. $ROOT_DIR/util.sh
|
||||
|
||||
desc "A simple function that takes inputs"
|
||||
run "cat hi.py"
|
||||
|
||||
desc "Set up function"
|
||||
run "fission function create --name hi-py --env python --code hi.py --entrypoint hi.main"
|
||||
|
||||
desc "Set up route"
|
||||
run "fission route create --function hi-py --url /hi --method GET"
|
||||
|
||||
desc "Set up recorder"
|
||||
run "fission recorder create --name my-recorder --function hi-py"
|
||||
|
||||
desc "Run function"
|
||||
run "curl http://$FISSION_ROUTER/hi?name=world"
|
||||
|
||||
desc "View recording"
|
||||
run "fission records view -v"
|
||||
|
||||
requid=$(fission records view -v|tail -1|cut -f1 -d' ')
|
||||
|
||||
desc "Replay recording"
|
||||
run "fission replay --reqUID $requid"
|
||||
@@ -54,5 +54,23 @@ function run() {
|
||||
echo -e "\b "
|
||||
}
|
||||
|
||||
function run_bg() {
|
||||
maybe_first_prompt
|
||||
rate=25
|
||||
if [ -n "$DEMO_RUN_FAST" ]; then
|
||||
rate=1000
|
||||
fi
|
||||
echo "$green$1$reset" | pv -qL $rate
|
||||
if [ -n "$DEMO_RUN_FAST" ]; then
|
||||
sleep 0.5
|
||||
fi
|
||||
$1 &
|
||||
echo
|
||||
echo -n ">"
|
||||
read -s
|
||||
echo -e "\b "
|
||||
}
|
||||
|
||||
|
||||
SSH_NODE=$(kubectl get nodes | tail -1 | cut -f1 -d' ')
|
||||
|
||||
|
||||
@@ -4,22 +4,30 @@ The `binary` runtime is a go server that uses a subprocess to invoke executables
|
||||
|
||||
Use Cases
|
||||
- Execute bash scripts
|
||||
- Run executables of languages that have no dedicated environment yet.
|
||||
- Execute arbitrary binaries (such as common sysadmin tools)
|
||||
- Get support in _any_ programming language by executing the generated executable.
|
||||
|
||||
## Words of Caution
|
||||
The environment runs on an alpine image with some additional utilty commandline tools installed, such as 'grep'.
|
||||
However, in case you want to make use of more ecsoteric commandline tools, you should add the relevant apk to the
|
||||
⚠️ **Words of Caution** ⚠️
|
||||
|
||||
The environment runs on an alpine image with some additional utility commandline tools installed, such as 'grep'.
|
||||
However, in case you want to make use of more esoteric commandline tools, you should add the relevant apk to the
|
||||
Dockerfile and build a new binary environment. See 'Compiling' for instructions.
|
||||
|
||||
When executing functions using binaries, **ensure that the executable is built for the right architecture**.
|
||||
Using the default binary environment this means that the binary should be build for Linux.
|
||||
|
||||
## Usage
|
||||
To get started with the latest binary environment:
|
||||
|
||||
```bash
|
||||
fission env create --name binary --image fission/binary-env --builder fission/binary-builder
|
||||
```
|
||||
|
||||
The interface to the executable used by this environment is somewhat similar to a [CGI interface](https://en.wikipedia.org/wiki/Common_Gateway_Interface).
|
||||
This means that any HTTP headers are converted to environment variables of the form "HTTP_<header-name>". For example these
|
||||
are some of frequently occurring headers:
|
||||
|
||||
```
|
||||
```bash
|
||||
# Request Metadata
|
||||
CONTENT_LENGTH
|
||||
REQUEST_URI
|
||||
@@ -28,18 +36,23 @@ REQUEST_METHOD
|
||||
# HTTP Headers
|
||||
HTTP_ACCEPT
|
||||
HTTP_USER-AGENT
|
||||
...
|
||||
HTTP_CONTENT-TYPE
|
||||
# ...
|
||||
```
|
||||
|
||||
The body of HTTP piped over the STDIN to the executable.
|
||||
All output that is provided to the server over the STDOUT will be transformed into the HTTP response.
|
||||
|
||||
See the [README](../../examples/binary/README.md) in the binary examples directory for additional usage instructions.
|
||||
|
||||
## Compiling
|
||||
|
||||
Build the Dockerfile:
|
||||
To build the runtime environment:
|
||||
```bash
|
||||
docker build --tag=${USER}/binary-env .
|
||||
```
|
||||
|
||||
See the [README](../../examples/binary/README.md) in the binary examples directory for usage instructions.
|
||||
To build the builder environment:
|
||||
```bash
|
||||
(cd builder/ && docker build --tag=${USER}/binary-builder .)
|
||||
```
|
||||
@@ -46,7 +46,7 @@ type (
|
||||
|
||||
func (bs *BinaryServer) SpecializeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if specialized {
|
||||
w.WriteHeader(400)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("Not a generic container"))
|
||||
return
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user