Compare commits

...
137 Commits
Author SHA1 Message Date
Soam VasaniandTa-Ching Chen 2699aa6069 Handle duplicate archive and package specs; handle multifile archives better (#1018)
Archives with multiple files should have all files in the inputs.
Also clean up some inconsistent variable naming -- archive name,
archive file path, and archive input files were all stored in
incorrectly-named variables.
2018-12-11 16:35:31 +08:00
Ta-Ching ChenandGitHub f0c0936b87 Validate command flag input by adding cli hook (#1017) 2018-12-10 23:48:33 +08:00
Ta-Ching ChenandVishal 314e16a88e Pre-create kubernetes resources for function with minScale=0 (#976)
Pre-create Kubernetes resources if functions has MinScale=0 and then scale when first function is called.
2018-12-03 15:52:07 +05:30
Ta-Ching ChenandGitHub 72faa927de Use executor type as a delimiter to prevent deploy name conflict (#1009) 2018-11-30 13:04:44 +08:00
VishalandTa-Ching Chen 19b52938c3 Improve archive package user experience (#927) 2018-11-29 23:00:38 +08:00
Ta-Ching ChenandGitHub 7cedf8d580 Fix issues when specifying resources/scales during updating/creation process (#970) 2018-11-29 20:46:48 +08:00
Ta-Ching ChenandGitHub 17cbc5baad Upgrade environment dependencies for security alert (#1006) 2018-11-29 16:38:38 +08:00
Ta-Ching ChenandGitHub c2bcbb06a9 Rename canary flag name from funcN/funcN-1 to newfunction/oldfunction (#1003) 2018-11-28 16:27:29 +08:00
VishalandTa-Ching Chen 152c899e8b Added warning when package env and environment env mismatched (#996)
Fix issue #946
2018-11-26 19:05:00 +08:00
Ta-Ching ChenandGitHub c476f54a6c Fix MQ trigger (NATS) wrongly sends error message to response topic (#1002) 2018-11-25 10:07:46 +08:00
Ta-Ching ChenandGitHub 4b5ab0ad93 Shorten executor kubernetes objects name (#975) 2018-11-24 20:41:38 +08:00
smruthi2187andTa-Ching Chen 82af0e554a Fix Read on Closed body error (#963) 2018-11-21 14:27:52 +08:00
Harald NordgrenandTa-Ching Chen b456dec138 Update formatting directive logic to unbreak tests 2018-11-20 17:24:41 +08:00
Ta-Ching Chen 4a8c200c37 Fix helm command not found issue when kubeconfig is not provided. 2018-11-20 17:24:37 +08:00
VishalandTa-Ching Chen 52b736c892 Package info error should warn user (#995) 2018-11-20 00:44:20 +08:00
Ta-Ching ChenandVishal d9eee058ce Newdeploy - change only in minscale should not restart deployment 2018-11-15 15:31:28 +05:30
Soam VasaniandVishal 3676602fa2 Specs for JVM example (#825) 2018-11-15 00:00:26 +05:30
Ta-Ching ChenandGitHub 4f3b7de04a Fix release script failed to generate yaml for nonhelm installation (#978) 2018-11-14 15:02:43 +08:00
VishalandTa-Ching Chen cdf5838420 Upgrade OpenJDK8 to latest available version (#985) 2018-11-13 18:00:38 +08:00
Soam VasaniandTa-Ching Chen a714983c28 Fix the analytics jobs in the YAMLs (remove duplicates) (#977) 2018-11-08 14:39:37 +08:00
Steven DakeandSoam Vasani b9547160b5 Properly render Helm charts (#969)
* Properly render Helm charts

Fixes: https://github.com/fission/fission/issues/968

* Addres reviewier comments
2018-11-06 13:27:17 -08:00
Ta-Ching ChenandGitHub bfa8e6a45f Show builder image when list all envs (#971) 2018-11-05 23:18:37 +08:00
Ta-Ching ChenandGitHub 9764eff05d Fix CLI not shows package name when creating a function (#966) 2018-11-05 17:19:05 +08:00
Ganesh GuttikondaandTa-Ching Chen 253e44fdbe Updating the compile documentation link (#965)
* Updating the compile documentation link
* Changing the protocol to https
2018-11-05 15:41:22 +08:00
smruthi2187andGitHub 585d86448f V0.12.0 (#967) 2018-11-01 15:57:25 -07:00
smruthi2187andGitHub dad7b6632e Keep prometheus and canary deploy set to false in fission-core (#964) 2018-11-01 13:02:46 -07:00
Soam VasaniandGitHub 4e9e025ca4 Remove version from release name since it contains illegal chars for names (#939)
* Remove version from release name since it contains illegal chars for names

* Put version in release name for uniqueness, but remove invalid chars

* Remove prometheus=false yaml
2018-10-31 14:54:25 -07:00
Ta-Ching ChenandGitHub b6ea85e353 Fix failed to pull influxdb image from dockerhub (#957)
* Fix failed to pull influxdb image from dockerhub
* Disable jvm test temporarily (issue 958)
2018-10-31 16:32:45 +08:00
Ta-Ching ChenandGitHub 29aabaabda Optimize function latency when cache expired/invalid under high concurrency (#856)
* Optimize router response time by adding update lock

In 0.9.2, the router sends multiple GetServiceForFunction requests to executor
to get the service URL. However, the response time of executor will increase
under high-concurrency situation due to too many requests are waiting for
processing.

To solve the problem, an update lock was added to the router. All of goroutines belongs
to the same function need to grab the update lock before sending the request.
Only the first goroutine which gets the update lock is allowed to send request.
In this way, we reduce the burden of executor and lower the failure rate.
2018-10-27 23:35:00 +08:00
David McGillicuddyandSoam Vasani 394c5b13f4 Update readme to include JVM (#953) 2018-10-24 09:03:27 -07:00
smruthi2187andGitHub 0a8c6e97a6 Feature flag to enable/disable canary + optional prometheus install (#937) 2018-10-22 15:24:43 -07:00
VishalandGitHub e7f1d4564a Kafka tests (#944)
A simple test for Kafka integration which runs locally provided cluster has Kafka and Fission install has Kafka integratiom enabled (mqtrigger-kafka deployment present).
2018-10-22 20:07:51 +05:30
Ta-Ching ChenandGitHub 619b390af3 Support for full url (base on aalubin changes) (#941) 2018-10-21 04:04:07 +08:00
smruthi2187andGitHub 1488d0ca2d fix a few canary deployment issues (#943) 2018-10-19 14:56:40 -07:00
smruthi2187andGitHub dd35750482 Return the error on failed specializations with fn test --debug (#917) 2018-10-19 11:17:58 -07:00
Ta-Ching ChenandGitHub 5aeba59b75 Bump flask version (#942) 2018-10-18 22:56:04 +08:00
Soam VasaniandGitHub 8329ef36b3 demo script updates (#934)
Demo script updates.  Record-replay, a bugfix in the canary demo script, etc.
2018-10-15 14:48:01 -07:00
VishalandGitHub 4cc42fb216 Adding JVM heap options to environment (#936) 2018-10-15 23:01:43 +05:30
Ta-Ching ChenandGitHub d23b210f4e Add X-Forwarded-Host to request header (#890) 2018-10-15 14:17:18 +08:00
VishalandGitHub 803dbd6d39 Added build and push procedures for Nodejs builder environment (#916) 2018-10-03 08:07:23 +05:30
Ta-Ching ChenandGitHub e4213f6eb6 Fix flag not found problem when running canary demo scripts (#914) 2018-10-02 22:07:03 +08:00
VishalandGitHub 2d2576cf2d V0.11.0 (#913)
Release v0.11.0
2018-10-02 00:08:29 +05:30
VishalandGitHub 96cbee185d Kafka integration (#831)
Kafka integration with Fission enables invoking a function when a message arrives in a Kafka topic
2018-10-01 18:03:31 +05:30
VishalandGitHub 9f83d70b63 Fixes #758, uses v2 specialize for env versions 2 or higher (#911) 2018-10-01 10:07:49 +05:30
VishalandGitHub 7deb45bed2 Making the Maven build quite for Java env test, right now it is too verbose for CI (#902) 2018-10-01 08:00:45 +05:30
smruthi2187andVishal 12d3a04bf9 Print status with the get option. (#907) 2018-09-28 22:19:24 +05:30
smruthi2187andGitHub fa565b75ae Canary deployments for fission functions. (#892) 2018-09-25 18:26:26 -07:00
Michael GaidaandVishal 437d4dc04d Configurable namespace creation (#855)
Configurable namespace creation defaulting to true (backward compatible)
2018-09-25 13:49:08 +05:30
VishalandGitHub 188138ccd8 Fixed the spec validation UX issue (#898)
Improved some of warnings/messages shown to the user when using `fission spec` command. The `spec validate` command now shows appropriate warnings instead
2018-09-21 14:52:49 +05:30
Ta-Ching ChenandGitHub 6b49c194ca Fission supportability: Add dump command to dump information for debugging (#754)
* Add v1 support tool proposal
* Fission supportability: Add dump command to dump information for debugging
2018-09-19 14:35:51 +08:00
Ta-Ching ChenandGitHub a86c9431d3 Check CRD creation error instead of doing return directly (#897) 2018-09-18 16:30:56 +08:00
Gary YeapandTa-Ching Chen 6f60f3eef8 Add v2 interface support for nodes env (#836) 2018-09-14 14:28:04 +08:00
VishalandGitHub d18777bed4 Used hidden flag instead of removing command completely (#886)
The `fission spec helm` is now a hidden command since it is not implemented yet.
2018-09-13 15:27:22 +05:30
Ta-Ching ChenandGitHub 82d23b9bf8 Fix fetcher not close file descriptor correctly (#889)
* Fix fetcher not close file descriptor correctly
* Call Sync() before chmod
2018-09-11 14:15:56 +08:00
Ta-Ching ChenandGitHub a4f58fbf10 Check pod container ready state (#861)
Ensure pod is ready by checking pod’s containers state and deletionTimestamp
2018-09-07 22:17:07 +08:00
Adam BouhenguelandSoam Vasani 2dbae32f20 FIX CleanupOldExecutorObjects in all namespaces (#879)
Don't just look in functionNamespace anymore
2018-08-29 15:12:31 -07:00
Ta-Ching ChenandGitHub 21b0a1d852 Fix failed to find release-builder dockerfile & push specific tag (#870) 2018-08-26 23:02:07 +08:00
Ta-Ching ChenandGitHub f8535be7da V0.10.0 (#868) 2018-08-19 19:05:19 +08:00
Nafisa Shaziaandsmruthi2187 95eef49cf8 Replay recorded requests by ReqUID (#864) 2018-08-17 13:17:54 -07:00
Ta-Ching ChenandGitHub 2d01382a82 Add cleanup function to test scripts (#863) 2018-08-18 02:11:08 +08:00
Ta-Ching ChenandGitHub d443f8b2ef Scale deployment to zero when function is in idle state (#775) 2018-08-17 23:03:34 +08:00
Ta-Ching ChenandGitHub dffb5cdf8b Fix CLI failed to setup port-forward caused by #712 (#867) 2018-08-17 16:05:13 +08:00
Erwin van EykandTa-Ching Chen 5c1d8bc90c Extensible Fission CLI (#743)
This PR introduces extensibility to the Fission CLI. The principle behind the design of this extensibility is taken from the approach git uses: the main binary (fission) calls other binaries (fission-workflows) - which it discovers using simple prefix-rules - based on specific commands (fission workflow <command>).
2018-08-17 15:20:46 +08:00
smruthi2187andTa-Ching Chen ad28922871 Fix for #662: avoid unnecessary builds (#866) 2018-08-17 13:53:37 +08:00
Ta-Ching ChenandGitHub 9d7355cbaa Fix newdeploy fail to update HPA, deployment of a function after function update (#862) 2018-08-15 19:56:30 +08:00
Nafisa ShaziaandTa-Ching Chen 74a3a54543 Recorder CRD, Records API, Redis deployment (#818) 2018-08-15 05:28:40 +08:00
Ta-Ching ChenandGitHub 07ca5df8d0 Fix router not taps function services (#860) 2018-08-13 19:45:49 +08:00
Ta-Ching ChenandGitHub e730376e3e Add rebuild subcommand to pkg command (#808) 2018-08-12 04:13:25 +08:00
VishalandTa-Ching Chen ee61c8c333 Update route without providing function reference (#718) 2018-08-06 11:31:05 +08:00
Ta-Ching ChenandGitHub 27b74a7cf2 Fix router panic when trying to update route (#811) 2018-08-05 01:06:47 +08:00
Ta-Ching ChenandGitHub 088e665d28 Fix spec failed to archive single directory (#837) 2018-08-03 21:26:19 +08:00
Erwin van EykandTa-Ching Chen 9438f3c4ec Updated binary environment README (#773)
- Added usage instructions for getting started quickly.
- Added instructions for using the builder
2018-08-03 15:07:08 +08:00
Ta-Ching ChenandGitHub b5a906b2f4 Do resources validation when validate spec files (#840) 2018-08-03 13:00:29 +08:00
Ta-Ching ChenandGitHub 0e40cb5f4f Fix newdeploy not updates deployment after function's entrypoint changed (#838) 2018-08-02 21:00:27 +08:00
Ta-Ching ChenandGitHub 1a1ac49ce0 Fix CLI failed to set up port-forwarding when multiple controller pods exist in the same namespace (#712)
* Fix CLI failed to set up port-forwarding when multiple controller pods exist in the same namespace
* Check pod healthy state before establishing the connection
2018-08-02 17:20:53 +08:00
VishalandTa-Ching Chen 4356378301 Uses a real go project to showcase vendor example so glide works (#828) 2018-08-01 23:55:54 +08:00
xiekeyangandTa-Ching Chen 6123873d2a Add gevent based Python server to benchmark test cases (#794)
This add the benchmark test cases, which is using gevent based on wsgi
framework.
2018-08-01 21:22:03 +08:00
Ta-Ching ChenandGitHub 9a7ffc2f5b Add more meaningful error messages to executor when getServiceForFunction (#752) 2018-07-30 09:10:48 +08:00
VishalandGitHub f3857abdf5 Fixed the name of JVM builder image name (#824) 2018-07-27 23:28:11 +05:30
VishalandSoam Vasani e977c7caca V0.9.2 (#817)
* Release 0.9.2

* Added changelog
2018-07-25 12:59:30 -07:00
VishalandGitHub f40688435d Added readme for JVM environment & examples (#768)
Instructions for JVM environment and examples
2018-07-25 09:26:01 +05:30
Erwin van EykandTa-Ching Chen e8b2a26a3b Add query options to function test (#782) 2018-07-24 23:00:08 +08:00
VishalandGitHub 27c3a50d23 Java env builder with Maven (#783)
Java environment builder with support for Maven builds. Default build comman runs `mvn clean package` and picks up target/*with-dependencies.jar for function.
2018-07-24 15:16:21 +05:30
Erwin van EykandTa-Ching Chen ec495fbd1d Added Helm lint check (#799) 2018-07-19 11:49:28 +08:00
WrathZAandVishal 80fadcc7b8 Typo correction (#797) 2018-07-17 18:18:10 +05:30
VishalandGitHub 4b37b9ac03 Fixed typos from from goreportcard (#760) 2018-07-16 16:24:05 +05:30
VishalandGitHub 16d0f6a94f Updating release notes with details and structure (#738) 2018-07-16 14:41:28 +05:30
xiekeyangandTa-Ching Chen cc40d1ed2e change image pull policy of builder manager (#793)
This changes image pull policy from Always to IfNotPresent. The previous
policy forbid customer to use the exact image existing on K8S Node.
And it should be OK to use fixed policy here. Customer need not set policy by
their own.
2018-07-16 10:48:47 +08:00
Ta-Ching ChenandGitHub 425e447e5c Add go environment vendor directory support (#781)
* Add go environment vendor directory support
* Use symbolink instead of copying files to gopath
* Add go vendor example package & test
2018-07-13 13:16:22 +08:00
xiekeyangandSoam Vasani 3707b95edb Round Tripper of Fission Router: parameters be configurable (#713)
The Round Tripper parameters of timeout, keep alive time and Max retry
times is configured in router system environment.

And they are set to Round Tripper when router service initializing.

This setup new nested structure `tsRoundTripperParams` to transfer them.
2018-07-12 12:08:52 -07:00
Ta-Ching ChenandGitHub 2982efebb8 Delete namespace in background to reduce build time (#791)
* Delete namespace in background
* TPR is no longer exists
2018-07-12 11:00:19 +08:00
Ta-Ching ChenandGitHub 14db705891 Break & Stop the build immediately if a non-zero exit code was returned (#790) 2018-07-11 20:15:03 +08:00
Ta-Ching ChenandGitHub 9c885ef6f5 Fix spec command overrides existing archive's url of a package (#764) 2018-07-11 13:03:45 +08:00
smruthi2187andGitHub 34e8d0ee3d Add changelog. (#789) 2018-07-06 22:00:14 -07:00
smruthi2187andGitHub 728979636f Updating charts to version 0.9.1 (#788) 2018-07-06 19:11:35 -07:00
Ta-Ching ChenandGitHub 462db2f00c Fix “rm: missing operand” in release script (#779) 2018-07-06 14:15:20 +08:00
Ta-Ching ChenandGitHub 2504408803 Fix go env panic “plugin: not implemented” (#784) 2018-07-06 12:24:46 +08:00
Ta-Ching ChenandGitHub 61569d1c38 Change flag name to KeepArchive for backward compatibility (#787) 2018-07-06 03:13:07 +08:00
smruthi2187andGitHub 5b6582698c changelog for release 0.9.0. (#780) 2018-07-04 02:08:47 -07:00
smruthi2187andGitHub 81f0f1df6d Changes in charts for release 0.9.0 (#778) 2018-07-04 00:27:47 -07:00
Ta-Ching Chenandsmruthi2187 44be0f6859 Move build process from host to docker container during release process (#682) 2018-07-03 21:14:06 -07:00
smruthi2187andGitHub 9daf97a9ab router tracks function liveness before forwarding request (#701) 2018-07-03 15:51:52 -07:00
Erwin van EykandTa-Ching Chen 032d1a8b9a Support annotations in environment specs (#733)
* Added annotations to runtime and builder environment specs
* Use crd annotations for env pod
2018-06-30 05:38:22 +08:00
VishalandGitHub 65fd1d9fbb Java env alpha (#656)
This change adds support for JVM based environment for running Java functions. This is alpha release of JVM environment and might undergo changes.
2018-06-27 21:39:24 +05:30
John GallagherandSoam Vasani a35cd7f4a4 Convert go-env Dockerfile into a multi-stage build (#683)
Converting to a multi-stage build reduces the size of the final image from ~750MB to ~15MB.
2018-06-26 13:21:36 -07:00
xiekeyangandSoam Vasani 74212f1810 envns should be availabe in message line (#734)
This line warns the user that dependent environment doesn’t exist, and presents the command line
for creating an environment.

When the variable `envNamespace` is specified, the `envns` option should be available as well.
2018-06-26 11:15:41 -07:00
Nafisa ShaziaandTa-Ching Chen 1ed59f0789 Push error messages to error topic when NATS mqtrigger fail (#724) 2018-06-27 00:27:57 +08:00
xiekeyangandTa-Ching Chen 71d8b769d5 Python Environment: add gevent based WSGI server framework (#750)
* Python Environment: add gevent based WSGI server framework

This supply gevent based WSGI server framework to Python Environment, to
allow customer to run their functions under multi-threads.

* classify the flask based application

This set up the flask based application as individual class, to make
sure the consistent and integrity.

* Add instruction of WSGI server selection applied in Python Environment

* Python Environment starting logger: provide framework name
2018-06-26 15:50:06 +08:00
Ta-Ching ChenandGitHub c863616b38 Add release steps to render & upload fission installation YAML (#745) 2018-06-26 13:41:43 +08:00
xiekeyangandsmruthi2187 09b62e514e Replace the hard-coded archive size from error message with actual value (#735) 2018-06-25 17:48:43 -07:00
Ta-Ching ChenandGitHub c705ba355e Fix executor not reaps idle function pods for functions with executortype newdeploy (#744) 2018-06-21 17:54:42 +08:00
VishalandGitHub 7642dcf05f Disable caching of connections from router to function pods (#742)
A temporary fix for #723 which needs to be optimized in future. Disables caching of connections from the router to function pod/service.
2018-06-21 12:45:11 +05:30
Ta-Ching ChenandGitHub 58a5f1cb0b Fix executor wrongly passes loop variable reference to function (#751) 2018-06-19 09:55:41 +08:00
VishalandGitHub 1b86c367a0 Added a flag to control the extraction of archive based on user input (#675)
For certain environments, the archive should not be extracted and kept as it is (For ex. for Java the jar file should not be extracted). This change enables an environment level flag to control this behaviour.
2018-06-14 12:32:40 +05:30
VishalandGitHub 6d08e6e0bc Archives bigger than 256K size need env variable for uploading (#697)
For archives bigger than 256K, the Storage service was called from the client side, this needed few environment variables to be set. This change uses port forwarding to achieve the same and does not need environment variables to be set.
2018-06-14 01:12:06 +05:30
xiekeyangandVishal ef7d4ae385 Make fetcher resource requests and limits configurable (#708)
This change allows fetcher container resource requests and limits to be configurable.
2018-06-13 16:12:55 +05:30
Erwin van EykandTa-Ching Chen cf1f944069 Extract portforward to separate package (#728)
* Extract port-forward from CLI to own package (for reuseability)
* Extract CLI logging to subpackage
2018-06-13 11:26:39 +08:00
VishalandSoam Vasani ddff7100e9 Temporarily disabling the tests so that other PRs can be worked on, will enable after closure on #723 (#737) 2018-06-08 15:07:50 -07:00
xiekeyangandSoam Vasani a5bc2a6d4c add build exe to gitignore (#736)
This is a built binary, should be ignore when git committion.
2018-06-08 10:46:17 -07:00
Soam VasaniandGitHub 952b48bd68 Environment warning message bugfix (#725) 2018-06-07 14:17:27 -07:00
Joe StevensandTa-Ching Chen 2ad07d68b6 Fix for Windows CLI Port Forwarding (#715) 2018-06-07 16:37:37 +08:00
xiekeyangandTa-Ching Chen 8c96d9c6a0 ArchiveLiteralSizeLimit: Use Constant Instead Hard Code (#731)
This use constant to instead hard code for ArchiveLiteralSizeLimit. That ensure if the limitation
value is changed in cli, the controller server can follow it. Otherwise, the condition will return
error, and make error HTTP response.

Later, we should delete it in fission-cli, and make it configurable it chart, to work in fission-
servers only.
2018-06-07 15:45:32 +08:00
VishalandGitHub 46d9808173 V0.8.0 (#722)
Release v0.8.0
2018-06-06 00:01:00 +05:30
smruthi2187andGitHub 2e37611da8 pre-upgrade job to verify function references and restricted privileges for fetcher and builder SA (#717)
It is mandatory (from this release onwards) for function to refer to secrets, config-maps and packages in its own namespace to ensure isolation of users sharing the same cluster.
This change runs a pre-upgrade job to verify function references for all functions created prior to this release and fails the upgrade by printing a list of functions that violate this restriction.
2018-06-04 19:30:27 -07:00
Ta-Ching ChenandGitHub 0057270551 Add time trigger cron spec examination tool (#680) 2018-06-04 19:02:54 +08:00
Ta-Ching ChenandGitHub 7a7d15b50c Update k8s dependencies to 1.10 (#687) 2018-06-01 15:43:19 +08:00
VishalandGitHub 202cc3cb7e Changing the logger daemonset's update strategy (#714)
Changing the logger daemonset's update strategy from OnDelete to RollingUpdate (Ref: https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#daemonset-update-strategy)
2018-05-31 23:42:23 +05:30
VishalandGitHub a761393816 Ingress integration (#688)
Ingress integration to allow the optional creation of ingress for a given route. The ingress controller needs to be set up by the user separately so that ingress path is accessible outside the cluster.
2018-05-31 11:27:55 +05:30
Ta-Ching ChenandGitHub fedf6b6e5b Check spec directory exists before reading spec files (#709)
* Check spec directory exists before reading spec files
* Fix spec example
2018-05-31 03:01:40 +08:00
xiekeyangandSoam Vasani 6eec55223d Formatted specifiers are not compatible with variables (#706)
It missed specifier for namespace
2018-05-29 09:08:38 -07:00
xiekeyangandTa-Ching Chen 940b9adabd Indicate HTTP status code by library const (#703) 2018-05-24 19:10:45 +08:00
smruthi2187andGitHub 8984e4916e Enabling multi-tenancy for fission objects. (#655)
This feature allows creation of fission objects in different namespaces, in addition to retaining the existing behavior of creating fission objects in default namespace if user doesnt provide one. 
It also removes cluster admin roles for fission-fetcher and fission-builder Service Accounts and grants them only those privileges that they need.
2018-05-23 13:22:46 -07:00
Joe StevensandSoam Vasani c9d2757760 docker-distribution version bump for windows compatibility (#691) 2018-05-21 18:41:53 -07:00
Soam VasaniandGitHub d846aed612 Fission metrics integration (#677)
Add prometheus metrics collection endpoints to router and executor. Add prometheus annotations to router and executor pods.
2018-05-21 13:57:18 -07:00
VishalandGitHub d9b5b9b8a8 Java Environment Design proposal
Java environment design decisions and considerations.
2018-05-14 13:45:01 +05:30
Ta-Ching ChenandGitHub 9c91f00cb4 Replace Werkzeug with Bjoern as underlying WSGI server (#672) 2018-05-09 14:00:40 +08:00
Ta-Ching ChenandGitHub 0a648d1d75 Version -> 0.7.2 (#670) 2018-05-05 20:01:23 +08:00
379 changed files with 29161 additions and 4262 deletions
+1
View File
@@ -1,5 +1,6 @@
fission-bundle/fission-bundle
fission/fission
environments/fetcher/cmd/fetcher
# Pycharm IDE
.idea
+10 -4
View File
@@ -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
View File
@@ -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)
+66
View File
@@ -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.
+128
View File
@@ -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.
+67
View File
@@ -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)
+62
View File
@@ -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?
+3 -2
View File
@@ -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
View File
@@ -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) {
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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{}))
}
+78
View File
@@ -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)
}
+387
View File
@@ -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)
}
+163
View File
@@ -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
View File
@@ -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,
+2 -2
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
dependencies:
- name: prometheus
version: 7.1.0
repository: https://kubernetes-charts.storage.googleapis.com
condition: prometheusDeploy
+3 -3
View File
@@ -1,13 +1,13 @@
1. Install the client CLI.
Mac:
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.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!
+17
View File
@@ -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 -}}
+177 -68
View File
@@ -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
+39
View File
@@ -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
+1 -1
View File
@@ -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:
+3 -3
View File
@@ -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
+34 -10
View File
@@ -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
+2 -2
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
dependencies:
- name: prometheus
version: 7.1.0
repository: https://kubernetes-charts.storage.googleapis.com
condition: prometheusDeploy
+3 -3
View File
@@ -1,13 +1,13 @@
1. Install the client CLI.
Mac:
$ curl -Lo fission https://github.com/fission/fission/releases/download/0.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 -}}
+84 -47
View File
@@ -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
+1
View File
@@ -44,6 +44,7 @@ metadata:
name: storagesvc
labels:
svc: storagesvc
application: fission-storage
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: ClusterIP
+22 -2
View File
@@ -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
+68 -3
View File
@@ -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
}
+258
View File
@@ -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
View File
@@ -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
View File
@@ -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")
+177
View File
@@ -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(""))
}
+133
View File
@@ -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
}
+24
View File
@@ -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
}
+99
View File
@@ -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
}
+6 -5
View File
@@ -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
}
+6 -5
View File
@@ -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
}
+6 -5
View File
@@ -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
}
+5 -3
View File
@@ -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
}
+5 -5
View File
@@ -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))
+6 -5
View File
@@ -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
}
+239
View File
@@ -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
}
+47
View File
@@ -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
}
+6 -5
View File
@@ -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
}
+65
View File
@@ -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
}
+49
View File
@@ -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)
}
+13 -3
View File
@@ -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)
}
+17 -3
View File
@@ -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
}
+17 -6
View File
@@ -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
+15 -3
View File
@@ -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
}
+15 -3
View File
@@ -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
}
+22 -7
View File
@@ -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
}
+148
View File
@@ -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(""))
}
+95
View File
@@ -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)
}
+40
View File
@@ -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)
}
+49
View File
@@ -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)
}
+1 -1
View File
@@ -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) {
+15 -3
View File
@@ -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
}
-64
View File
@@ -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
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+120
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()
}
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
kubectl delete canaryconfig canary-2
kubectl delete httptrigger route-fail
+23
View File
@@ -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"
+11
View File
@@ -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"
};
}
+37
View File
@@ -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"
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
fission fn delete --name hello
fission route delete --name $(fission route list|grep hello|cut -f1 -d' ')
+7
View File
@@ -0,0 +1,7 @@
module.exports = async function(context) {
return {
status: 200,
body: "This is Version One!\n"
};
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = async function(context) {
return {
status: 200,
body: "This is Version Two!\n"
};
}
+7
View File
@@ -0,0 +1,7 @@
module.exports = async function(context) {
return {
status: 200,
body: "Hello, world!\n"
};
}
+113
View File
@@ -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"
+12
View File
@@ -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"
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
fission spec destroy
# this one is generated in run.sh
rm specs/function-hello-go.yaml
rm *.~?~
+12
View File
@@ -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))
}
+24
View File
@@ -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"
+42
View File
@@ -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
+6
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
from flask import request
from flask import current_app
def main():
name=request.args["name"]
return "Hello, %s" % name
+28
View File
@@ -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"
+18
View File
@@ -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' ')
+21 -8
View File
@@ -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 .)
```
+1 -1
View File
@@ -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