Compare commits

...
40 Commits
Author SHA1 Message Date
Shubham BansalandGitHub f955d1182a update chart version to v1.19.0 (#2798)
Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-05-18 15:18:04 +05:30
AmborandGitHub 1cbc0ba9ff fix: passthrough the build log error (#2795)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-05-18 13:47:54 +05:30
Shubham BansalandGitHub 0936c6a2d7 Update dependencies (#2796)
* updated dependencies

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

* updated depencies related to otel and few other

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

* revert changes for go version

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

* revert changes for k8s dependencies

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

---------

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-05-18 13:44:51 +05:30
Shubham BansalandGitHub f0ec328d24 Changed prometheus version from latest to 45.28.0 (#2797)
* updated prometheus version for CI failure

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

* updated prometheus version for CI failure

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

---------

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-05-18 12:44:20 +05:30
Shubham BansalandGitHub 2b1ac28300 updating all direct dependencies (#2793)
Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-05-17 12:17:23 +05:30
Shubham BansalandGitHub 0fb2096788 security upgrade for alpine to 3.18 (#2792) 2023-05-16 17:45:36 +05:30
Scott CôtéandGitHub 6e375629e7 Configure router deployment replicas (#2782) 2023-05-16 16:20:29 +05:30
Shubham BansalandGitHub 1133386ce9 update chart version to v1.19.0-rc2 (#2791)
Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-05-12 10:33:51 +05:30
f99f10134c Executor: Dump function service cache for pool manager functions (#2789)
* dump function service cache for executor
* fix lint issue
* code refactor and lint fixes

---------

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
Co-authored-by: Sanket Sudake <sanketsudake@gmail.com>
2023-05-12 09:49:54 +05:30
6c431e4d9b Ensure handling for specialization failure in pool manager (#2788)
* Add fixes for failure in specialization
* reduce specialization in progress and remove expired requests from queue when specialization is timed out
* rename markSpecializationFailure and remove logger from the queue
* refactor clean up code in api.go and add test case for queue

Details:

- Cleanup svc waiting for the counter in the pool manager if specialization fails
- Cleanup active requests counter in pool manager if client exists the demand for function service while we have allocated function service
- Consider specialization timeout if pod ready timeout > specialization timeout in waiting for ready pod. We also consider if the request to choosePod is cancelled.
- We ensure if we have requests waiting for service requests but if there is no pod in the specialization we clean up those.
---------

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
Co-authored-by: Pranoy Kundu <pranoy1998k@gmail.com>
2023-05-11 21:03:57 +05:30
31c81e132e fix: lose cold start error counter for the poolmgr functions (#2755)
* fix: lose cold start error counter for the poolmgr functions

Co-authored-by: ZhengHe-MD <ranchardzheng@gmail.com>
Co-authored-by: gw123 <iamakillerforyou@gmail.com>
Signed-off-by: saltbo <saltbo@foxmail.com>

* fix: miss code for the metric

Signed-off-by: saltbo <saltbo@foxmail.com>

---------

Signed-off-by: saltbo <saltbo@foxmail.com>
Co-authored-by: ZhengHe-MD <ranchardzheng@gmail.com>
Co-authored-by: gw123 <iamakillerforyou@gmail.com>
2023-05-09 12:37:58 +05:30
Nikhil SharmaandGitHub a5f3402dbc add functionality to update spec of fission custom resources (#2701)
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
2023-05-08 13:36:05 +05:30
AmborandGitHub 784bd82ec7 fix: panic for the builder/client (#2780)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-04-13 10:40:45 +05:30
AmborandGitHub cd742a6d18 fix: error port for the pprof server (#2766)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-04-11 08:43:36 +05:30
AmborandGitHub 32530ac474 fix: add flush to support chunked for the metric middleware (#2772)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-04-11 08:40:58 +05:30
AmborandGitHub 117c383fac style: typo for the BuilderNamespace (#2776)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-04-11 08:39:42 +05:30
Shubham BansalandGitHub 3a1db58066 update chart version to v1.19.0-rc1 (#2761)
Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-03-31 15:07:20 +05:30
AmborandGitHub ce42dbc647 refactor: update the client retry by the pkg retryablehttp (#2752)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-03-31 13:20:22 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3840a90b54 Bump github.com/opencontainers/runc from 1.1.2 to 1.1.5 (#2757)
Bumps [github.com/opencontainers/runc](https://github.com/opencontainers/runc) from 1.1.2 to 1.1.5.
- [Release notes](https://github.com/opencontainers/runc/releases)
- [Changelog](https://github.com/opencontainers/runc/blob/v1.1.5/CHANGELOG.md)
- [Commits](https://github.com/opencontainers/runc/compare/v1.1.2...v1.1.5)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/runc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-31 13:06:55 +05:30
AmborandGitHub 77d4745242 fix: invalid error unwrap for the httperror (#2753)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-03-31 12:23:37 +05:30
715ef8267e Improve poolmanager concurrency handling with virtual capacity (#2737)
* add functionality to wait for specialization by keeping track of incoming requests
* format executor package
* fix required capacity to specialise new pod condition
* move handling concurrency logic into pool cache from executor
* remove unused methods and structs
* implement queue in to store the svc wait
* create a queue struct and its methods to handle concurrent inputs
* use newly created queue to store waiting for svc requests
* add waiting requests in queue and use them when a svc is ready
* set function to request in queue if the context is still alive
* remove concurrency approach to set svc for waiting requests
* update the active requests whenever requests from pool are assigned a svc
* add doc to define why the conditions exist
* remove unwanted params in strcut and clean up code
* set error while getting svc value if sum of specialization in progress and specialized is only more than concurrency limit
* remove duplicate functions and unnecessary values in struct
* close svc channel on set value and create constants for default concurrency and rpp
* get next value in queue in case context is timed out for fetched value
* remove specializationInProgress counter from pool cache
* return in case the queue is empty wihle setting func to svc
* test getSvcVaue and setSvcValue in poolcache
* add unit tests for GetConcurrent and GetRequestsPerPod methods
* reorder imports
* add fuzzy testing for getSVCValue and setSVCValue in poolcache
* restructure go mod file and update pool cache test cases
* Add tests and bug fixes
* refactor code and add test cases
* add svcWaiting check while setting svc value

---------

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
Co-authored-by: Sanket Sudake <sanketsudake@gmail.com>
2023-03-30 20:19:51 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b622f13ab6 Bump golang.org/x/image from 0.0.0-20190802002840-cff245a6509b to 0.5.0 (#2735)
Bumps [golang.org/x/image](https://github.com/golang/image) from 0.0.0-20190802002840-cff245a6509b to 0.5.0.
- [Release notes](https://github.com/golang/image/releases)
- [Commits](https://github.com/golang/image/commits/v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-30 11:26:34 +05:30
2213ebc637 feat: add trace and timeout support for the timer (#2750)
* feat: add trace and timeout support for the timer

Co-authored-by: gw123 <iamakillerforyou@gmail.com>
Signed-off-by: saltbo <saltbo@foxmail.com>

* fix: add error check for the lint

Signed-off-by: saltbo <saltbo@foxmail.com>

---------

Signed-off-by: saltbo <saltbo@foxmail.com>
Co-authored-by: gw123 <iamakillerforyou@gmail.com>
2023-03-29 09:27:55 +05:30
Nikhil SharmaandGitHub 1f138d03fa handle addr when port is passed in host:port format in the StartServer func (#2747)
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
2023-03-23 16:38:17 +05:30
a8e8cfb72d fix: websocket event listener (#2745)
Co-authored-by: 李霖 <lee@lilindeMacBook-Pro.local>
2023-03-23 11:52:20 +05:30
AmborandGitHub 963081e096 fix: ending retry loop when the request canceled for the choosePod (#2731)
Signed-off-by: saltbo <saltbo@foxmail.com>
2023-03-21 14:38:45 +05:30
Sanket SudakeandGitHub a96b92f41f Update Go version 1.20 (#2740)
* Update Go version 1.20
* Update golangci-lint version v1.51.1

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2023-03-12 08:45:43 +05:30
Nikhil SharmaandGitHub a93e9b4074 poolmgr: stop pod specialization when pod namespace and cm/secret namespace is mismatched (#2703)
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
2023-03-11 16:24:52 +05:30
Pranoy Kumar KunduandGitHub 0de8923ea8 Add funcSvcGroup type in pool cache for grouping of function services (#2728)
* add specfic structs for function svc and group

* remove unused var in funcSvcGroup

* format poolcache
2023-02-28 09:06:16 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1cb18a78a6 Bump golang.org/x/net from 0.4.0 to 0.7.0 (#2724)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.4.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.4.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-26 11:02:47 +05:30
Shubham BansalandGitHub 4ebdb16623 security upgrade for alpine to 3.17 (#2723) 2023-02-17 21:10:02 +05:30
Shubham BansalandGitHub 3c0c96e98e CLI: Use fntimeout to stop terminating of function in middle (#2709)
* use flag FnExecutionTimeout instead of FnTestTimeout

* use flag FnExecutionTimeout instead of FnTestTimeout

* keep FnTestTimeout and FunctionTimeout both

* code review changes

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>

---------

Signed-off-by: Shubham Bansal <shubhambansaliimtgn@gmail.com>
2023-02-09 13:57:57 +05:30
Shubham BansalandGitHub e462f9ab71 Allow permission to router for ingress resource (#2710) 2023-02-02 10:20:46 +05:30
Shubham BansalandGitHub d025022042 Make ghcr.io to default container registry (#2711)
* changed default container registry from docker.io to ghcr.io
* user ghcr.io in CI test
* use ghcr.io in reporter image
* revert skaffold changes
2023-02-02 10:19:59 +05:30
Shubham BansalandGitHub c4ed12d9c5 Push docker images to github container registry (#2705)
* changes to push images in github container registry

* reverting changes for helm chart to pass CI test

* use gitURL instead of whole URL

* use gitURL instead of whole URL

* added release process for docker.io

* removed trailing spaces

* added support for multi arch images in GHCR
2023-01-30 17:26:06 +05:30
Shubham BansalandGitHub d3a615211f router pod fails to run if authentication is enabled during helm upgrade (#2700) 2023-01-19 09:20:54 +05:30
Shubham BansalandGitHub 2b017f810a Fission version failed if authentication.enabled is set to true (#2697)
* set authorization header for fission version and check command

* display warning if response status is unauthorize or forbidden

* passing context to http request
2023-01-18 16:26:06 +05:30
Nikhil SharmaandGitHub 5c3c55d52f allow users to set envGracePeriod to 0 (#2696)
Signed-off-by: Nikhl Sharma <nikhilsharma230303@gmail.com>

Signed-off-by: Nikhl Sharma <nikhilsharma230303@gmail.com>
2023-01-18 10:57:30 +05:30
Shubham BansalandGitHub 5db09a899a Create roles for custom resource in function and builder namespace (#2695)
* create roles for custom resource in function and builder namespace
* Create roles for CR for builder in function and builder namespace
* convert warn to info to remove error stack trace
2023-01-17 22:15:04 +05:30
Sanket SudakeandGitHub 0edf2640b1 internal: Making poolcache typed and merged into fscache (#2693)
Merged pool cache package into fscache to avoid import cycle.
Also changed all types in pool cache from interface to specific
types.

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2023-01-15 23:50:05 +05:30
85 changed files with 2045 additions and 1003 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.18.5 go-version-file: "go.mod"
- name: Install dashboard linter - name: Install dashboard linter
run: | run: |
+1 -1
View File
@@ -18,7 +18,7 @@ on:
workflow_dispatch: workflow_dispatch:
env: env:
GOLANGCI_LINT_VERSION: v1.50.1 GOLANGCI_LINT_VERSION: v1.51.1
GOLANGCI_LINT_TIMEOUT: 5m GOLANGCI_LINT_TIMEOUT: 5m
jobs: jobs:
+2 -2
View File
@@ -92,7 +92,7 @@ jobs:
helm repo update helm repo update
kubectl create ns monitoring kubectl create ns monitoring
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring \ helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring \
--set grafana.enabled=false --set alertmanager.enabled=false --version 45.28.0 --set grafana.enabled=false --set alertmanager.enabled=false
- name: Build and Install Fission CLI - name: Build and Install Fission CLI
run: | run: |
@@ -234,7 +234,7 @@ jobs:
helm repo update helm repo update
kubectl create ns monitoring kubectl create ns monitoring
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring \ helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring \
--set grafana.enabled=false --set alertmanager.enabled=false --version 45.28.0 --set grafana.enabled=false --set alertmanager.enabled=false
- name: Build and Install Fission CLI - name: Build and Install Fission CLI
run: | run: |
+8 -1
View File
@@ -43,7 +43,14 @@ jobs:
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
- name: Docker Login - name: Login to ghcr.io
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to docker.io
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
+156 -1
View File
@@ -84,8 +84,11 @@ dockers:
image_templates: image_templates:
- "fission/builder:latest-amd64" - "fission/builder:latest-amd64"
- "fission/builder:{{ .Tag }}-amd64" - "fission/builder:{{ .Tag }}-amd64"
- "ghcr.io/fission/builder:latest-amd64"
- "ghcr.io/fission/builder:{{ .Tag }}-amd64"
dockerfile: cmd/builder/Dockerfile dockerfile: cmd/builder/Dockerfile
build_flag_templates: build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64" - "--platform=linux/amd64"
- "--label=org.opencontainers.image.created={{.Date}}" - "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}" - "--label=org.opencontainers.image.revision={{.FullCommit}}"
@@ -96,28 +99,60 @@ dockers:
image_templates: image_templates:
- "fission/fetcher:latest-amd64" - "fission/fetcher:latest-amd64"
- "fission/fetcher:{{ .Tag }}-amd64" - "fission/fetcher:{{ .Tag }}-amd64"
- "ghcr.io/fission/fetcher:latest-amd64"
- "ghcr.io/fission/fetcher:{{ .Tag }}-amd64"
dockerfile: cmd/fetcher/Dockerfile dockerfile: cmd/fetcher/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-amd64 - <<: *docker-amd64
ids: ids:
- fission-bundle - fission-bundle
image_templates: image_templates:
- "fission/fission-bundle:latest-amd64" - "fission/fission-bundle:latest-amd64"
- "fission/fission-bundle:{{ .Tag }}-amd64" - "fission/fission-bundle:{{ .Tag }}-amd64"
- "ghcr.io/fission/fission-bundle:latest-amd64"
- "ghcr.io/fission/fission-bundle:{{ .Tag }}-amd64"
dockerfile: cmd/fission-bundle/Dockerfile dockerfile: cmd/fission-bundle/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-amd64 - <<: *docker-amd64
ids: ids:
- pre-upgrade-checks - pre-upgrade-checks
image_templates: image_templates:
- "fission/pre-upgrade-checks:latest-amd64" - "fission/pre-upgrade-checks:latest-amd64"
- "fission/pre-upgrade-checks:{{ .Tag }}-amd64" - "fission/pre-upgrade-checks:{{ .Tag }}-amd64"
- "ghcr.io/fission/pre-upgrade-checks:latest-amd64"
- "ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}-amd64"
dockerfile: cmd/preupgradechecks/Dockerfile dockerfile: cmd/preupgradechecks/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-amd64 - <<: *docker-amd64
ids: ids:
- reporter - reporter
image_templates: image_templates:
- "fission/reporter:latest-amd64" - "fission/reporter:latest-amd64"
- "fission/reporter:{{ .Tag }}-amd64" - "fission/reporter:{{ .Tag }}-amd64"
- "ghcr.io/fission/reporter:latest-amd64"
- "ghcr.io/fission/reporter:{{ .Tag }}-amd64"
dockerfile: cmd/reporter/Dockerfile dockerfile: cmd/reporter/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/amd64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- &docker-arm64 - &docker-arm64
use: buildx use: buildx
goos: linux goos: linux
@@ -127,8 +162,11 @@ dockers:
image_templates: image_templates:
- "fission/builder:latest-arm64" - "fission/builder:latest-arm64"
- "fission/builder:{{ .Tag }}-arm64" - "fission/builder:{{ .Tag }}-arm64"
- "ghcr.io/fission/builder:latest-arm64"
- "ghcr.io/fission/builder:{{ .Tag }}-arm64"
dockerfile: cmd/builder/Dockerfile dockerfile: cmd/builder/Dockerfile
build_flag_templates: build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64" - "--platform=linux/arm64"
- "--label=org.opencontainers.image.created={{.Date}}" - "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}" - "--label=org.opencontainers.image.revision={{.FullCommit}}"
@@ -139,28 +177,60 @@ dockers:
image_templates: image_templates:
- "fission/fetcher:latest-arm64" - "fission/fetcher:latest-arm64"
- "fission/fetcher:{{ .Tag }}-arm64" - "fission/fetcher:{{ .Tag }}-arm64"
- "ghcr.io/fission/fetcher:latest-arm64"
- "ghcr.io/fission/fetcher:{{ .Tag }}-arm64"
dockerfile: cmd/fetcher/Dockerfile dockerfile: cmd/fetcher/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-arm64 - <<: *docker-arm64
ids: ids:
- fission-bundle - fission-bundle
image_templates: image_templates:
- "fission/fission-bundle:latest-arm64" - "fission/fission-bundle:latest-arm64"
- "fission/fission-bundle:{{ .Tag }}-arm64" - "fission/fission-bundle:{{ .Tag }}-arm64"
- "ghcr.io/fission/fission-bundle:latest-arm64"
- "ghcr.io/fission/fission-bundle:{{ .Tag }}-arm64"
dockerfile: cmd/fission-bundle/Dockerfile dockerfile: cmd/fission-bundle/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-arm64 - <<: *docker-arm64
ids: ids:
- pre-upgrade-checks - pre-upgrade-checks
image_templates: image_templates:
- "fission/pre-upgrade-checks:latest-arm64" - "fission/pre-upgrade-checks:latest-arm64"
- "fission/pre-upgrade-checks:{{ .Tag }}-arm64" - "fission/pre-upgrade-checks:{{ .Tag }}-arm64"
- "ghcr.io/fission/pre-upgrade-checks:latest-arm64"
- "ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}-arm64"
dockerfile: cmd/preupgradechecks/Dockerfile dockerfile: cmd/preupgradechecks/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-arm64 - <<: *docker-arm64
ids: ids:
- reporter - reporter
image_templates: image_templates:
- "fission/reporter:latest-arm64" - "fission/reporter:latest-arm64"
- "fission/reporter:{{ .Tag }}-arm64" - "fission/reporter:{{ .Tag }}-arm64"
- "ghcr.io/fission/reporter:latest-arm64"
- "ghcr.io/fission/reporter:{{ .Tag }}-arm64"
dockerfile: cmd/reporter/Dockerfile dockerfile: cmd/reporter/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- &docker-armv7 - &docker-armv7
use: buildx use: buildx
goos: linux goos: linux
@@ -171,8 +241,11 @@ dockers:
image_templates: image_templates:
- "fission/builder:latest-armv7" - "fission/builder:latest-armv7"
- "fission/builder:{{ .Tag }}-armv7" - "fission/builder:{{ .Tag }}-armv7"
- "ghcr.io/fission/builder:latest-armv7"
- "ghcr.io/fission/builder:{{ .Tag }}-armv7"
dockerfile: cmd/builder/Dockerfile dockerfile: cmd/builder/Dockerfile
build_flag_templates: build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v7" - "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.created={{.Date}}" - "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}" - "--label=org.opencontainers.image.revision={{.FullCommit}}"
@@ -183,74 +256,156 @@ dockers:
image_templates: image_templates:
- "fission/fetcher:latest-armv7" - "fission/fetcher:latest-armv7"
- "fission/fetcher:{{ .Tag }}-armv7" - "fission/fetcher:{{ .Tag }}-armv7"
- "ghcr.io/fission/fetcher:latest-armv7"
- "ghcr.io/fission/fetcher:{{ .Tag }}-armv7"
dockerfile: cmd/fetcher/Dockerfile dockerfile: cmd/fetcher/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-armv7 - <<: *docker-armv7
ids: ids:
- fission-bundle - fission-bundle
image_templates: image_templates:
- "fission/fission-bundle:latest-armv7" - "fission/fission-bundle:latest-armv7"
- "fission/fission-bundle:{{ .Tag }}-armv7" - "fission/fission-bundle:{{ .Tag }}-armv7"
- "ghcr.io/fission/fission-bundle:latest-armv7"
- "ghcr.io/fission/fission-bundle:{{ .Tag }}-armv7"
dockerfile: cmd/fission-bundle/Dockerfile dockerfile: cmd/fission-bundle/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-armv7 - <<: *docker-armv7
ids: ids:
- pre-upgrade-checks - pre-upgrade-checks
image_templates: image_templates:
- "fission/pre-upgrade-checks:latest-armv7" - "fission/pre-upgrade-checks:latest-armv7"
- "fission/pre-upgrade-checks:{{ .Tag }}-armv7" - "fission/pre-upgrade-checks:{{ .Tag }}-armv7"
- "ghcr.io/fission/pre-upgrade-checks:latest-armv7"
- "ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}-armv7"
dockerfile: cmd/preupgradechecks/Dockerfile dockerfile: cmd/preupgradechecks/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
- <<: *docker-armv7 - <<: *docker-armv7
ids: ids:
- reporter - reporter
image_templates: image_templates:
- "fission/reporter:latest-armv7" - "fission/reporter:latest-armv7"
- "fission/reporter:{{ .Tag }}-armv7" - "fission/reporter:{{ .Tag }}-armv7"
- "ghcr.io/fission/reporter:latest-armv7"
- "ghcr.io/fission/reporter:{{ .Tag }}-armv7"
dockerfile: cmd/reporter/Dockerfile dockerfile: cmd/reporter/Dockerfile
build_flag_templates:
- "--label=org.opencontainers.image.source={{.GitURL}}"
- "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Tag}}"
docker_manifests: docker_manifests:
- name_template: ghcr.io/fission/builder:{{ .Tag }}
image_templates:
- ghcr.io/fission/builder:{{ .Tag }}-amd64
- ghcr.io/fission/builder:{{ .Tag }}-arm64
- ghcr.io/fission/builder:{{ .Tag }}-armv7
- name_template: fission/builder:{{ .Tag }} - name_template: fission/builder:{{ .Tag }}
image_templates: image_templates:
- fission/builder:{{ .Tag }}-amd64 - fission/builder:{{ .Tag }}-amd64
- fission/builder:{{ .Tag }}-arm64 - fission/builder:{{ .Tag }}-arm64
- fission/builder:{{ .Tag }}-armv7 - fission/builder:{{ .Tag }}-armv7
- name_template: ghcr.io/fission/fetcher:{{ .Tag }}
image_templates:
- ghcr.io/fission/fetcher:{{ .Tag }}-amd64
- ghcr.io/fission/fetcher:{{ .Tag }}-arm64
- ghcr.io/fission/fetcher:{{ .Tag }}-armv7
- name_template: fission/fetcher:{{ .Tag }} - name_template: fission/fetcher:{{ .Tag }}
image_templates: image_templates:
- fission/fetcher:{{ .Tag }}-amd64 - fission/fetcher:{{ .Tag }}-amd64
- fission/fetcher:{{ .Tag }}-arm64 - fission/fetcher:{{ .Tag }}-arm64
- fission/fetcher:{{ .Tag }}-armv7 - fission/fetcher:{{ .Tag }}-armv7
- name_template: ghcr.io/fission/fission-bundle:{{ .Tag }}
image_templates:
- ghcr.io/fission/fission-bundle:{{ .Tag }}-amd64
- ghcr.io/fission/fission-bundle:{{ .Tag }}-arm64
- ghcr.io/fission/fission-bundle:{{ .Tag }}-armv7
- name_template: fission/fission-bundle:{{ .Tag }} - name_template: fission/fission-bundle:{{ .Tag }}
image_templates: image_templates:
- fission/fission-bundle:{{ .Tag }}-amd64 - fission/fission-bundle:{{ .Tag }}-amd64
- fission/fission-bundle:{{ .Tag }}-arm64 - fission/fission-bundle:{{ .Tag }}-arm64
- fission/fission-bundle:{{ .Tag }}-armv7 - fission/fission-bundle:{{ .Tag }}-armv7
- name_template: ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}
image_templates:
- ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}-amd64
- ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}-arm64
- ghcr.io/fission/pre-upgrade-checks:{{ .Tag }}-armv7
- name_template: fission/pre-upgrade-checks:{{ .Tag }} - name_template: fission/pre-upgrade-checks:{{ .Tag }}
image_templates: image_templates:
- fission/pre-upgrade-checks:{{ .Tag }}-amd64 - fission/pre-upgrade-checks:{{ .Tag }}-amd64
- fission/pre-upgrade-checks:{{ .Tag }}-arm64 - fission/pre-upgrade-checks:{{ .Tag }}-arm64
- fission/pre-upgrade-checks:{{ .Tag }}-armv7 - fission/pre-upgrade-checks:{{ .Tag }}-armv7
- name_template: ghcr.io/fission/reporter:{{ .Tag }}
image_templates:
- ghcr.io/fission/reporter:{{ .Tag }}-amd64
- ghcr.io/fission/reporter:{{ .Tag }}-arm64
- ghcr.io/fission/reporter:{{ .Tag }}-armv7
- name_template: fission/reporter:{{ .Tag }} - name_template: fission/reporter:{{ .Tag }}
image_templates: image_templates:
- fission/reporter:{{ .Tag }}-amd64 - fission/reporter:{{ .Tag }}-amd64
- fission/reporter:{{ .Tag }}-arm64 - fission/reporter:{{ .Tag }}-arm64
- fission/reporter:{{ .Tag }}-armv7 - fission/reporter:{{ .Tag }}-armv7
- name_template: ghcr.io/fission/builder:latest
image_templates:
- ghcr.io/fission/builder:latest-amd64
- ghcr.io/fission/builder:latest-arm64
- ghcr.io/fission/builder:latest-armv7
- name_template: fission/builder:latest - name_template: fission/builder:latest
image_templates: image_templates:
- fission/builder:latest-amd64 - fission/builder:latest-amd64
- fission/builder:latest-arm64 - fission/builder:latest-arm64
- fission/builder:latest-armv7 - fission/builder:latest-armv7
- name_template: ghcr.io/fission/fetcher:latest
image_templates:
- ghcr.io/fission/fetcher:latest-amd64
- ghcr.io/fission/fetcher:latest-arm64
- ghcr.io/fission/fetcher:latest-armv7
- name_template: fission/fetcher:latest - name_template: fission/fetcher:latest
image_templates: image_templates:
- fission/fetcher:latest-amd64 - fission/fetcher:latest-amd64
- fission/fetcher:latest-arm64 - fission/fetcher:latest-arm64
- fission/fetcher:latest-armv7 - fission/fetcher:latest-armv7
- name_template: ghcr.io/fission/fission-bundle:latest
image_templates:
- ghcr.io/fission/fission-bundle:latest-amd64
- ghcr.io/fission/fission-bundle:latest-arm64
- ghcr.io/fission/fission-bundle:latest-armv7
- name_template: fission/fission-bundle:latest - name_template: fission/fission-bundle:latest
image_templates: image_templates:
- fission/fission-bundle:latest-amd64 - fission/fission-bundle:latest-amd64
- fission/fission-bundle:latest-arm64 - fission/fission-bundle:latest-arm64
- fission/fission-bundle:latest-armv7 - fission/fission-bundle:latest-armv7
- name_template: ghcr.io/fission/pre-upgrade-checks:latest
image_templates:
- ghcr.io/fission/pre-upgrade-checks:latest-amd64
- ghcr.io/fission/pre-upgrade-checks:latest-arm64
- ghcr.io/fission/pre-upgrade-checks:latest-armv7
- name_template: fission/pre-upgrade-checks:latest - name_template: fission/pre-upgrade-checks:latest
image_templates: image_templates:
- fission/pre-upgrade-checks:latest-amd64 - fission/pre-upgrade-checks:latest-amd64
- fission/pre-upgrade-checks:latest-arm64 - fission/pre-upgrade-checks:latest-arm64
- fission/pre-upgrade-checks:latest-armv7 - fission/pre-upgrade-checks:latest-armv7
- name_template: ghcr.io/fission/reporter:latest
image_templates:
- ghcr.io/fission/reporter:latest-amd64
- ghcr.io/fission/reporter:latest-arm64
- ghcr.io/fission/reporter:latest-armv7
- name_template: fission/reporter:latest - name_template: fission/reporter:latest
image_templates: image_templates:
- fission/reporter:latest-amd64 - fission/reporter:latest-amd64
+2 -2
View File
@@ -1,7 +1,7 @@
apiVersion: v2 apiVersion: v2
name: fission-all name: fission-all
version: v1.18.0 version: v1.19.0
appVersion: v1.18.0 appVersion: v1.19.0
description: Fission is a fast serverless framework for Kubernetes. description: Fission is a fast serverless framework for Kubernetes.
home: https://fission.io/ home: https://fission.io/
icon: https://fission.io/images/fission-logo-white.svg icon: https://fission.io/images/fission-logo-white.svg
@@ -12,6 +12,15 @@ rules:
- list - list
- watch - watch
- patch - patch
- apiGroups:
- ""
resources:
- configmaps
- secrets
verbs:
- get
- list
- watch
- apiGroups: - apiGroups:
- apps - apps
resources: resources:
+16
View File
@@ -55,6 +55,22 @@ This template generates the image name for the deployment depending on the value
{{- end }} {{- end }}
{{- end -}} {{- end -}}
{{- define "reporterImage" -}}
{{- if .Values.repository -}}
{{- if eq .Values.imageTag "" -}}
{{ .Values.repository }}/{{ .Values.postInstallReportImage }}
{{- else -}}
{{ .Values.repository }}/{{ .Values.postInstallReportImage }}:{{ .Values.imageTag }}
{{- end }}
{{- else -}}
{{- if eq .Values.imageTag "" -}}
{{ .Values.postInstallReportImage }}
{{- else -}}
{{ .Values.postInstallReportImage }}:{{ .Values.imageTag }}
{{- end }}
{{- end }}
{{- end -}}
{{- define "opentelemtry.envs" }} {{- define "opentelemtry.envs" }}
- name: OTEL_EXPORTER_OTLP_ENDPOINT - name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.openTelemetry.otlpCollectorEndpoint }}" value: "{{ .Values.openTelemetry.otlpCollectorEndpoint }}"
@@ -26,11 +26,7 @@ spec:
restartPolicy: Never restartPolicy: Never
containers: containers:
- name: post-install-job - name: post-install-job
{{- if .Values.imageTag }} image: {{ include "reporterImage" . | quote }}
image: {{ .Values.postInstallReportImage }}:{{ .Values.imageTag }}
{{- else }}
image: {{ .Values.postInstallReportImage }}
{{- end }}
imagePullPolicy: {{ .Values.pullPolicy }} imagePullPolicy: {{ .Values.pullPolicy }}
command: [ "/reporter" ] command: [ "/reporter" ]
args: ["event", "-c", "fission-use", "-a", "yaml-post-install", "-l", "{{ .Chart.Name }}-{{ .Chart.Version }}"] args: ["event", "-c", "fission-use", "-a", "yaml-post-install", "-l", "{{ .Chart.Name }}-{{ .Chart.Version }}"]
@@ -30,11 +30,7 @@ spec:
restartPolicy: Never restartPolicy: Never
containers: containers:
- name: post-install-job - name: post-install-job
{{- if .Values.imageTag }} image: {{ include "reporterImage" . | quote }}
image: {{ .Values.postInstallReportImage }}:{{ .Values.imageTag }}
{{- else }}
image: {{ .Values.postInstallReportImage }}
{{- end }}
imagePullPolicy: {{ .Values.pullPolicy }} imagePullPolicy: {{ .Values.pullPolicy }}
command: [ "/reporter" ] command: [ "/reporter" ]
args: ["event", "-c", "fission-use", "-a", "helm-post-install", "-l", "{{ .Chart.Name }}-{{ .Chart.Version }}"] args: ["event", "-c", "fission-use", "-a", "helm-post-install", "-l", "{{ .Chart.Name }}-{{ .Chart.Version }}"]
@@ -30,11 +30,7 @@ spec:
restartPolicy: Never restartPolicy: Never
containers: containers:
- name: post-upgrade-job - name: post-upgrade-job
{{- if .Values.imageTag }} image: {{ include "reporterImage" . | quote }}
image: {{ .Values.postInstallReportImage }}:{{ .Values.imageTag }}
{{- else }}
image: {{ .Values.postInstallReportImage }}
{{- end }}
imagePullPolicy: {{ .Values.pullPolicy }} imagePullPolicy: {{ .Values.pullPolicy }}
command: [ "/reporter" ] command: [ "/reporter" ]
args: ["event", "-c", "fission-use", "-a", "helm-post-upgrade", "-l", "{{ .Chart.Name }}-{{ .Chart.Version }}"] args: ["event", "-c", "fission-use", "-a", "helm-post-upgrade", "-l", "{{ .Chart.Name }}-{{ .Chart.Version }}"]
@@ -5,3 +5,9 @@
{{ include "fission-role-generator" (merge (dict "namespace" $namespace "component" "buildermgr") $) }} {{ include "fission-role-generator" (merge (dict "namespace" $namespace "component" "buildermgr") $) }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if .Values.builderNamespace -}}
{{ include "fission-role-generator" (merge (dict "namespace" .Values.builderNamespace "component" "buildermgr") $) }}
{{- end }}
{{- if .Values.functionNamespace -}}
{{ include "fission-role-generator" (merge (dict "namespace" .Values.functionNamespace "component" "buildermgr") $) }}
{{- end }}
@@ -5,3 +5,9 @@
{{ include "fission-role-generator" (merge (dict "namespace" $namespace "component" "executor") $) }} {{ include "fission-role-generator" (merge (dict "namespace" $namespace "component" "executor") $) }}
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- if .Values.builderNamespace -}}
{{ include "fission-role-generator" (merge (dict "namespace" .Values.builderNamespace "component" "executor") $) }}
{{- end }}
{{- if .Values.functionNamespace -}}
{{ include "fission-role-generator" (merge (dict "namespace" .Values.functionNamespace "component" "executor") $) }}
{{- end }}
@@ -25,11 +25,7 @@ spec:
spec: spec:
containers: containers:
- name: mqtrigger - name: mqtrigger
{{- if eq .Values.imageTag "" }} image: {{ include "fission-bundleImage" . | quote }}
image: "{{ .Values.image }}"
{{- else }}
image: "{{ .Values.image }}:{{ .Values.imageTag }}"
{{- end }}
imagePullPolicy: {{ .Values.pullPolicy }} imagePullPolicy: {{ .Values.pullPolicy }}
command: ["/fission-bundle"] command: ["/fission-bundle"]
args: ["--mqt", "--routerUrl", "http://router.{{ .Release.Namespace }}"] args: ["--mqt", "--routerUrl", "http://router.{{ .Release.Namespace }}"]
@@ -12,7 +12,7 @@ metadata:
application: fission-router application: fission-router
spec: spec:
{{- if not .Values.router.deployAsDaemonSet }} {{- if not .Values.router.deployAsDaemonSet }}
replicas: 1 replicas: {{ .Values.router.replicas | default 1 }}
{{- end }} {{- end }}
selector: selector:
matchLabels: matchLabels:
@@ -1,4 +1,5 @@
{{- include "kubernetes-role-generator" (merge (dict "namespace" .Values.defaultNamespace "component" "router") .) }} {{- include "kubernetes-role-generator" (merge (dict "namespace" .Values.defaultNamespace "component" "router") .) }}
{{- include "kubernetes-role-generator" (merge (dict "namespace" .Release.Namespace "component" "router") .) }}
{{- if gt (len .Values.additionalFissionNamespaces) 0 }} {{- if gt (len .Values.additionalFissionNamespaces) 0 }}
{{- range $namespace := $.Values.additionalFissionNamespaces }} {{- range $namespace := $.Values.additionalFissionNamespaces }}
@@ -6,7 +6,7 @@ metadata:
labels: labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
annotations: annotations:
"helm.sh/hook": pre-install "helm.sh/hook": pre-install,pre-upgrade
data: data:
username: {{ .Values.authentication.authUsername | b64enc | quote }} username: {{ .Values.authentication.authUsername | b64enc | quote }}
password: {{ randAlphaNum 20 | b64enc | quote }} password: {{ randAlphaNum 20 | b64enc | quote }}
+13 -11
View File
@@ -14,7 +14,7 @@ routerServiceType: LoadBalancer
## repository represents base repository for images used in the chart. ## repository represents base repository for images used in the chart.
## Keep it empty for using existing local image ## Keep it empty for using existing local image
## ##
repository: index.docker.io repository: ghcr.io
## image represents the base image fission-bundle used by multiple Fission components. ## image represents the base image fission-bundle used by multiple Fission components.
## We alter arguments to the image to run a particular component. ## We alter arguments to the image to run a particular component.
@@ -25,7 +25,7 @@ image: fission/fission-bundle
## It is also used by the chart to identify version of the few more images apart from fission-bundle. ## It is also used by the chart to identify version of the few more images apart from fission-bundle.
## Keep it empty for using latest tag. ## Keep it empty for using latest tag.
## ##
imageTag: v1.18.0 imageTag: v1.19.0
## pullPolicy represents the pull policy to use for images in the chart. ## pullPolicy represents the pull policy to use for images in the chart.
## ##
@@ -63,8 +63,7 @@ routerPort: 31314
## defaultNamespace represents the namespace in which Fission custom resources will be created by the Fission user. ## defaultNamespace represents the namespace in which Fission custom resources will be created by the Fission user.
## This is different from the release namespace. ## This is different from the release namespace.
## Please consider setting `singleDefaultNamespace` and `additionalFissionNamespaces` if you want ## Please consider setting `additionalFissionNamespaces` if you want more than one namespace to be used for Fission custom resources.
## more than one namespace to be used for Fission custom resources.
## ##
defaultNamespace: default defaultNamespace: default
@@ -104,7 +103,7 @@ fetcher:
## image represents the image of the fetcher component. ## image represents the image of the fetcher component.
image: fission/fetcher image: fission/fetcher
## imageTag represents the tag of the image of the fetcher component. ## imageTag represents the tag of the image of the fetcher component.
imageTag: v1.18.0 imageTag: v1.19.0
## Fetcher is only for to downloading or uploading archive. ## Fetcher is only for to downloading or uploading archive.
## Normally, you don't need to change the value here, unless necessary. ## Normally, you don't need to change the value here, unless necessary.
@@ -212,6 +211,9 @@ router:
## deployAsDaemonSet decides whether to deploy router as a DaemonSet or a Deployment. ## deployAsDaemonSet decides whether to deploy router as a DaemonSet or a Deployment.
## ##
deployAsDaemonSet: false deployAsDaemonSet: false
## replicas decides how many router pods to deploy. Only used when deployAsDaemonSet is false.
##
replicas: 1
## svcAddressMaxRetries is the max times for router to retry with a specific function service address ## svcAddressMaxRetries is the max times for router to retry with a specific function service address
## ##
svcAddressMaxRetries: 5 svcAddressMaxRetries: 5
@@ -686,7 +688,7 @@ preUpgradeChecks:
image: fission/pre-upgrade-checks image: fission/pre-upgrade-checks
## pre-install/pre-upgrade checks image version ## pre-install/pre-upgrade checks image version
## ##
imageTag: v1.18.0 imageTag: v1.19.0
## Fission post-install/post-upgrade reporting live in this image ## Fission post-install/post-upgrade reporting live in this image
## ##
@@ -818,7 +820,7 @@ mqt_keda:
connector_images: connector_images:
kafka: kafka:
image: fission/keda-kafka-http-connector image: fission/keda-kafka-http-connector
tag: v0.11 tag: v0.12
rabbitmq: rabbitmq:
image: fission/keda-rabbitmq-http-connector image: fission/keda-rabbitmq-http-connector
tag: v0.10 tag: v0.10
@@ -827,16 +829,16 @@ mqt_keda:
tag: v0.10 tag: v0.10
aws_sqs: aws_sqs:
image: fission/keda-aws-sqs-http-connector image: fission/keda-aws-sqs-http-connector
tag: v0.10 tag: v0.11
nats_steaming: nats_steaming:
image: fission/keda-nats-streaming-http-connector image: fission/keda-nats-streaming-http-connector
tag: v0.12 tag: v0.13
nats_jetstream: nats_jetstream:
image: fission/keda-nats-jetstream-http-connector image: fission/keda-nats-jetstream-http-connector
tag: v0.2 tag: v0.4
gcp_pubsub: gcp_pubsub:
image: fission/keda-gcp-pubsub-http-connector image: fission/keda-gcp-pubsub-http-connector
tag: v0.5 tag: v0.6
redis: redis:
image: fission/keda-redis-http-connector image: fission/keda-redis-http-connector
tag: v0.3 tag: v0.3
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.18
RUN apk add --update ca-certificates RUN apk add --update ca-certificates
COPY builder /builder COPY builder /builder
ENTRYPOINT ["/builder"] ENTRYPOINT ["/builder"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.18
RUN apk add --update ca-certificates RUN apk add --update ca-certificates
COPY fetcher / COPY fetcher /
ENTRYPOINT ["/fetcher"] ENTRYPOINT ["/fetcher"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.18
RUN apk add --update ca-certificates RUN apk add --update ca-certificates
COPY fission-bundle / COPY fission-bundle /
ENTRYPOINT ["/fission-bundle"] ENTRYPOINT ["/fission-bundle"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.18
RUN apk add --update ca-certificates RUN apk add --update ca-certificates
COPY pre-upgrade-checks / COPY pre-upgrade-checks /
ENTRYPOINT ["/pre-upgrade-checks"] ENTRYPOINT ["/pre-upgrade-checks"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.16 FROM alpine:3.18
RUN apk add --update ca-certificates RUN apk add --update ca-certificates
COPY reporter / COPY reporter /
ENTRYPOINT ["/reporter"] ENTRYPOINT ["/reporter"]
+76 -74
View File
@@ -1,51 +1,51 @@
module github.com/fission/fission module github.com/fission/fission
go 1.19 go 1.20
require ( require (
github.com/Shopify/sarama v1.37.2 github.com/Shopify/sarama v1.37.2
github.com/bep/debounce v1.2.1 github.com/bep/debounce v1.2.1
github.com/dchest/uniuri v1.2.0 github.com/dchest/uniuri v1.2.0
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/dustin/go-humanize v1.0.0 github.com/dustin/go-humanize v1.0.1
github.com/elastic/crd-ref-docs v0.0.8 github.com/elastic/crd-ref-docs v0.0.8
github.com/emicklei/go-restful-openapi/v2 v2.9.1 github.com/emicklei/go-restful-openapi/v2 v2.9.1
github.com/emicklei/go-restful/v3 v3.10.1 github.com/emicklei/go-restful/v3 v3.10.2
github.com/fatih/color v1.13.0 github.com/fatih/color v1.15.0
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/go-git/go-git/v5 v5.4.2 github.com/go-git/go-git/v5 v5.6.1
github.com/go-openapi/spec v0.20.7 github.com/go-openapi/spec v0.20.9
github.com/golang-jwt/jwt/v4 v4.4.3 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/graymeta/stow v0.2.8 github.com/graymeta/stow v0.2.8
github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.1 github.com/hashicorp/go-retryablehttp v0.7.2
github.com/imdario/mergo v0.3.13 github.com/imdario/mergo v0.3.15
github.com/influxdata/influxdb v1.11.0 github.com/influxdata/influxdb v1.11.1
github.com/mholt/archiver/v3 v3.5.1 github.com/mholt/archiver/v3 v3.5.1
github.com/minio/minio-go v6.0.14+incompatible github.com/minio/minio-go v6.0.14+incompatible
github.com/ory/dockertest v3.3.5+incompatible github.com/ory/dockertest v3.3.5+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.15.1
github.com/prometheus/common v0.37.0 github.com/prometheus/common v0.43.0
github.com/robfig/cron/v3 v3.0.0 github.com/robfig/cron/v3 v3.0.1
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
github.com/spf13/cobra v1.6.1 github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.2
github.com/wcharczuk/go-chart v2.0.1+incompatible github.com/wcharczuk/go-chart v2.0.1+incompatible
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.41.1
go.opentelemetry.io/contrib/propagators/autoprop v0.37.0 go.opentelemetry.io/contrib/propagators/autoprop v0.41.1
go.opentelemetry.io/otel v1.11.2 go.opentelemetry.io/otel v1.15.1
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.2 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.15.1
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.2 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.15.1
go.opentelemetry.io/otel/sdk v1.11.2 go.opentelemetry.io/otel/sdk v1.15.1
go.opentelemetry.io/otel/trace v1.11.2 go.opentelemetry.io/otel/trace v1.15.1
go.uber.org/zap v1.24.0 go.uber.org/zap v1.24.0
golang.org/x/net v0.4.0 golang.org/x/net v0.10.0
google.golang.org/grpc v1.51.0 google.golang.org/grpc v1.55.0
k8s.io/api v0.25.4 k8s.io/api v0.25.4
k8s.io/apiextensions-apiserver v0.25.4 k8s.io/apiextensions-apiserver v0.25.4
k8s.io/apimachinery v0.25.4 k8s.io/apimachinery v0.25.4
@@ -57,7 +57,8 @@ require (
) )
require ( require (
cloud.google.com/go v0.99.0 // indirect cloud.google.com/go/compute v1.18.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.27 // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect
@@ -70,15 +71,15 @@ require (
github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/andybalholm/brotli v1.0.1 // indirect github.com/andybalholm/brotli v1.0.1 // indirect
github.com/aws/aws-sdk-go v1.42.34 // indirect github.com/aws/aws-sdk-go v1.42.34 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/blend/go-sdk v1.20220112.5 // indirect github.com/blend/go-sdk v1.20220112.5 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.1.0 // indirect github.com/cloudflare/circl v1.1.0 // indirect
github.com/containerd/continuity v0.2.2 // indirect github.com/containerd/continuity v0.2.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
@@ -94,20 +95,20 @@ require (
github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-ini/ini v1.66.4 // indirect github.com/go-ini/ini v1.66.4 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.2.3 // indirect github.com/go-logr/zapr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect
github.com/go-openapi/swag v0.19.15 // indirect github.com/go-openapi/swag v0.22.3 // indirect
github.com/gobuffalo/flect v0.2.5 // indirect github.com/gobuffalo/flect v0.3.0 // indirect
github.com/goccy/go-yaml v1.1.5 // indirect github.com/goccy/go-yaml v1.11.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.1.0 // indirect github.com/google/gofuzz v1.1.0 // indirect
@@ -115,10 +116,10 @@ require (
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/huandu/xstrings v1.2.1 // indirect github.com/huandu/xstrings v1.3.3 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
@@ -132,13 +133,13 @@ require (
github.com/klauspost/compress v1.15.11 // indirect github.com/klauspost/compress v1.15.11 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect github.com/klauspost/pgzip v1.2.5 // indirect
github.com/lib/pq v1.10.4 // indirect github.com/lib/pq v1.10.4 // indirect
github.com/mailru/easyjson v0.7.6 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/spdystream v0.2.0 // indirect github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -146,51 +147,52 @@ require (
github.com/nwaples/rardecode v1.1.0 // indirect github.com/nwaples/rardecode v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.2 // indirect github.com/opencontainers/runc v1.1.5 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/ulikunitz/xz v0.5.9 // indirect github.com/ulikunitz/xz v0.5.9 // indirect
github.com/xanzy/ssh-agent v0.3.2 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
go.opentelemetry.io/contrib/propagators/aws v1.12.0 // indirect go.opentelemetry.io/contrib/propagators/aws v1.16.1 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.12.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.16.1 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.12.0 // indirect go.opentelemetry.io/contrib/propagators/jaeger v1.16.1 // indirect
go.opentelemetry.io/contrib/propagators/ot v1.12.0 // indirect go.opentelemetry.io/contrib/propagators/ot v1.16.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.2 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.15.1 // indirect
go.opentelemetry.io/otel/metric v0.34.0 // indirect go.opentelemetry.io/otel/metric v0.38.1 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.3.0 // indirect golang.org/x/crypto v0.7.0 // indirect
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect golang.org/x/image v0.5.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.10.0 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sys v0.3.0 // indirect golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.3.0 // indirect golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.5.0 // indirect golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.8.0 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools v2.2.0+incompatible // indirect gotest.tools v2.2.0+incompatible // indirect
k8s.io/component-base v0.25.4 // indirect k8s.io/component-base v0.25.4 // indirect
k8s.io/klog/v2 v2.70.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
) )
+191 -366
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -22,6 +22,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
const (
DefaultConcurrency = 500
DefaultRequestsPerPod = 1
)
// //
// To add a Fission CRD type: // To add a Fission CRD type:
// 1. Create a "spec" type, for everything in the type except metadata // 1. Create a "spec" type, for everything in the type except metadata
@@ -863,3 +868,17 @@ type (
func (a Archive) IsEmpty() bool { func (a Archive) IsEmpty() bool {
return len(a.Literal) == 0 && len(a.URL) == 0 return len(a.Literal) == 0 && len(a.URL) == 0
} }
func (fn Function) GetConcurrency() int {
if fn.Spec.Concurrency == 0 {
return DefaultConcurrency
}
return fn.Spec.Concurrency
}
func (fn Function) GetRequestPerPod() int {
if fn.Spec.RequestsPerPod == 0 {
return DefaultRequestsPerPod
}
return fn.Spec.RequestsPerPod
}
+7 -23
View File
@@ -21,10 +21,9 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"io" "io"
"net/http"
"strings" "strings"
"time"
"github.com/hashicorp/go-retryablehttp"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.uber.org/zap" "go.uber.org/zap"
@@ -39,12 +38,14 @@ type (
Client struct { Client struct {
logger *zap.Logger logger *zap.Logger
url string url string
httpClient *http.Client httpClient *retryablehttp.Client
} }
) )
func MakeClient(logger *zap.Logger, builderUrl string) *Client { func MakeClient(logger *zap.Logger, builderUrl string) *Client {
hc := &http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)} hc := retryablehttp.NewClient()
hc.ErrorHandler = retryablehttp.PassthroughErrorHandler
hc.HTTPClient.Transport = otelhttp.NewTransport(hc.HTTPClient.Transport)
return &Client{ return &Client{
logger: logger.Named("builder_client"), logger: logger.Named("builder_client"),
url: strings.TrimSuffix(builderUrl, "/"), url: strings.TrimSuffix(builderUrl, "/"),
@@ -60,27 +61,10 @@ func (c *Client) Build(ctx context.Context, req *builder.PackageBuildRequest) (*
return nil, errors.Wrap(err, "error marshaling json") return nil, errors.Wrap(err, "error marshaling json")
} }
maxRetries := 20 resp, err := ctxhttp.Post(ctx, c.httpClient.StandardClient(), c.url, "application/json", bytes.NewReader(body))
var resp *http.Response if err != nil {
for i := 0; i < maxRetries; i++ {
resp, err = ctxhttp.Post(ctx, c.httpClient, c.url, "application/json", bytes.NewReader(body))
if err == nil {
if resp.StatusCode == 200 {
break
}
err = ferror.MakeErrorFromHTTP(resp)
}
if i < maxRetries-1 {
time.Sleep(50 * time.Duration(2*i) * time.Millisecond)
logger.Error("error building package, retrying", zap.Error(err))
continue
}
return nil, err return nil, err
} }
defer resp.Body.Close() defer resp.Body.Close()
rBody, err := io.ReadAll(resp.Body) rBody, err := io.ReadAll(resp.Body)
+6 -4
View File
@@ -17,6 +17,7 @@ limitations under the License.
package error package error
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@@ -106,8 +107,8 @@ func (err Error) Description() string {
func GetHTTPError(err error) (int, string) { func GetHTTPError(err error) (int, string) {
var msg string var msg string
var code int var code int
fe, ok := err.(Error) var fe Error
if ok { if errors.As(err, &fe) {
code = fe.HTTPStatus() code = fe.HTTPStatus()
msg = fe.Message msg = fe.Message
} else { } else {
@@ -118,10 +119,11 @@ func GetHTTPError(err error) (int, string) {
} }
func IsNotFound(err error) bool { func IsNotFound(err error) bool {
fe, ok := err.(Error) var fe Error
if !ok { if !errors.As(err, &fe) {
return false return false
} }
return fe.Code == ErrorNotFound return fe.Code == ErrorNotFound
} }
+36
View File
@@ -0,0 +1,36 @@
package error
import (
"net/http"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestIsNotFound(t *testing.T) {
errs := map[error]bool{
nil: false,
MakeError(ErrorNotFound, "someone not found"): true,
MakeError(ErrorTooManyRequests, "too many requests"): false,
errors.Wrap(MakeError(ErrorNotFound, "someone not found"), "other information"): true,
errors.Wrap(MakeError(ErrorTooManyRequests, "too many requests"), "other information"): false,
}
for err, want := range errs {
assert.Equal(t, want, IsNotFound(err))
}
}
func TestGetHTTPError(t *testing.T) {
errs := map[int]error{
http.StatusBadRequest: MakeError(ErrorInvalidArgument, ""),
http.StatusConflict: errors.Wrap(MakeError(ErrorNameExists, ""), ""),
http.StatusNotFound: errors.Wrap(MakeError(ErrorNotFound, ""), ""),
http.StatusTooManyRequests: errors.Wrap(MakeError(ErrorTooManyRequests, "too many requests"), "other information"),
}
for want, err := range errs {
code, _ := GetHTTPError(err)
assert.Equal(t, want, code)
}
}
+45 -17
View File
@@ -31,8 +31,10 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/crd"
ferror "github.com/fission/fission/pkg/error" ferror "github.com/fission/fission/pkg/error"
"github.com/fission/fission/pkg/executor/client" "github.com/fission/fission/pkg/executor/client"
"github.com/fission/fission/pkg/executor/fscache"
"github.com/fission/fission/pkg/utils/httpserver" "github.com/fission/fission/pkg/utils/httpserver"
"github.com/fission/fission/pkg/utils/metrics" "github.com/fission/fission/pkg/utils/metrics"
otelUtils "github.com/fission/fission/pkg/utils/otel" otelUtils "github.com/fission/fission/pkg/utils/otel"
@@ -63,19 +65,10 @@ func (executor *Executor) getServiceForFunctionAPI(w http.ResponseWriter, r *htt
zap.String("function_name", fn.ObjectMeta.Name), zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", fn.ObjectMeta.Namespace)) zap.String("function_namespace", fn.ObjectMeta.Namespace))
if t == fv1.ExecutorTypePoolmgr && !fn.Spec.OnceOnly { if t == fv1.ExecutorTypePoolmgr && !fn.Spec.OnceOnly {
concurrency := fn.Spec.Concurrency fsvc, err := et.GetFuncSvcFromCache(ctx, fn)
if concurrency == 0 {
concurrency = 500
}
requestsPerpod := fn.Spec.RequestsPerPod
if requestsPerpod == 0 {
requestsPerpod = 1
}
fsvc, active, err := et.GetFuncSvcFromPoolCache(ctx, fn, requestsPerpod)
// check if its a cache hit (check if there is already specialized function pod that can serve another request) // check if its a cache hit (check if there is already specialized function pod that can serve another request)
if err == nil { if err == nil {
// if a pod is already serving request then it already exists else validated // if a pod is already serving request then it already exists else validated
logger.Debug("from cache", zap.Int("active", active))
if et.IsValid(ctx, fsvc) { if et.IsValid(ctx, fsvc) {
// Cached, return svc address // Cached, return svc address
logger.Debug("served from cache", zap.String("name", fsvc.Name), zap.String("address", fsvc.Address)) logger.Debug("served from cache", zap.String("name", fsvc.Name), zap.String("address", fsvc.Address))
@@ -87,15 +80,19 @@ func (executor *Executor) getServiceForFunctionAPI(w http.ResponseWriter, r *htt
zap.String("function_namespace", fn.ObjectMeta.Namespace), zap.String("function_namespace", fn.ObjectMeta.Namespace),
zap.String("address", fsvc.Address)) zap.String("address", fsvc.Address))
et.DeleteFuncSvcFromCache(ctx, fsvc) et.DeleteFuncSvcFromCache(ctx, fsvc)
active-- } else {
code, msg := ferror.GetHTTPError(err)
if code == http.StatusNotFound {
logger.Debug("cache miss", zap.String("function_name", fn.ObjectMeta.Name))
} else {
logger.Error("error getting service for function",
zap.Error(err),
zap.String("function_name", fn.ObjectMeta.Name))
http.Error(w, msg, code)
return
}
} }
if active >= concurrency {
errMsg := fmt.Sprintf("max concurrency reached for %v. All %v instance are active", fn.ObjectMeta.Name, concurrency)
logger.Error("error occurred", zap.String("error", errMsg))
http.Error(w, html.EscapeString(errMsg), http.StatusTooManyRequests)
return
}
} else if t == fv1.ExecutorTypeNewdeploy || t == fv1.ExecutorTypeContainer { } else if t == fv1.ExecutorTypeNewdeploy || t == fv1.ExecutorTypeContainer {
fsvc, err := et.GetFuncSvcFromCache(ctx, fn) fsvc, err := et.GetFuncSvcFromCache(ctx, fn)
if err == nil { if err == nil {
@@ -153,7 +150,24 @@ func (executor *Executor) getServiceForFunction(ctx context.Context, fn *fv1.Fun
respChan: respChan, respChan: respChan,
} }
resp := <-respChan resp := <-respChan
cleanUp := func(funcSvc *fscache.FuncSvc) {
et, ok := executor.executorTypes[fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType]
if !ok {
executor.logger.Error("unknown executor type received in function service", zap.Any("executor", funcSvc.Executor))
return
}
if funcSvc != nil {
et.UnTapService(ctx, crd.CacheKey(funcSvc.Function), resp.funcSvc.Address)
} else {
et.MarkSpecializationFailure(ctx, crd.CacheKey(&fn.ObjectMeta))
}
}
if errors.Is(ctx.Err(), context.Canceled) {
cleanUp(resp.funcSvc)
return "", ferror.MakeError(499, "client leave early in the process of getServiceForFunction")
}
if resp.err != nil { if resp.err != nil {
cleanUp(resp.funcSvc)
return "", resp.err return "", resp.err
} }
return resp.funcSvc.Address, resp.err return resp.funcSvc.Address, resp.err
@@ -249,6 +263,19 @@ func (executor *Executor) unTapService(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// dumpDebugInfo => dump function service for pool cache
func (executor *Executor) dumpDebugInfo(w http.ResponseWriter, r *http.Request) {
// currently we are considering dumping function only for pool manager
et := executor.executorTypes[fv1.ExecutorTypePoolmgr]
if err := et.DumpDebugInfo(r.Context()); err != nil {
code, msg := ferror.GetHTTPError(err)
http.Error(w, msg, code)
return
}
w.WriteHeader(http.StatusOK)
}
// GetHandler returns an http.Handler. // GetHandler returns an http.Handler.
func (executor *Executor) GetHandler() http.Handler { func (executor *Executor) GetHandler() http.Handler {
r := mux.NewRouter() r := mux.NewRouter()
@@ -258,6 +285,7 @@ func (executor *Executor) GetHandler() http.Handler {
r.HandleFunc("/v2/tapServices", executor.tapServices).Methods("POST") r.HandleFunc("/v2/tapServices", executor.tapServices).Methods("POST")
r.HandleFunc("/healthz", executor.healthHandler).Methods("GET") r.HandleFunc("/healthz", executor.healthHandler).Methods("GET")
r.HandleFunc("/v2/unTapService", executor.unTapService).Methods("POST") r.HandleFunc("/v2/unTapService", executor.unTapService).Methods("POST")
r.HandleFunc("/v2/debugInfo", executor.dumpDebugInfo).Methods("GET")
return r return r
} }
-1
View File
@@ -60,7 +60,6 @@ type (
requestChan chan *createFuncServiceRequest requestChan chan *createFuncServiceRequest
fsCreateWg sync.Map fsCreateWg sync.Map
} }
createFuncServiceRequest struct { createFuncServiceRequest struct {
context context.Context context context.Context
function *fv1.Function function *fv1.Function
-1
View File
@@ -101,7 +101,6 @@ func createSvc(ctx context.Context, kubeClient kubernetes.Interface, ns string,
func TestExecutor(t *testing.T) { func TestExecutor(t *testing.T) {
// run in a random namespace so we can have concurrent tests // run in a random namespace so we can have concurrent tests
// on a given cluster // on a given cluster
rand.Seed(time.Now().UTC().UnixNano())
testID := rand.Intn(999) testID := rand.Intn(999)
fissionNs := fmt.Sprintf("test-%v", testID) fissionNs := fmt.Sprintf("test-%v", testID)
functionNs := fmt.Sprintf("test-function-%v", testID) functionNs := fmt.Sprintf("test-function-%v", testID)
@@ -177,6 +177,11 @@ func (caaf *Container) UnTapService(ctx context.Context, key string, svcHost str
// Not Implemented for CaaF. // Not Implemented for CaaF.
} }
// MarkSpecializationFailure has not been implemented for CaaF.
func (caaf *Container) MarkSpecializationFailure(ctx context.Context, key string) {
// Not Implemented for CaaF.
}
// GetFuncSvc returns a function service; error otherwise. // GetFuncSvc returns a function service; error otherwise.
func (caaf *Container) GetFuncSvc(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) { func (caaf *Container) GetFuncSvc(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
return caaf.createFunction(ctx, fn) return caaf.createFunction(ctx, fn)
@@ -193,12 +198,6 @@ func (caaf *Container) DeleteFuncSvcFromCache(ctx context.Context, fsvc *fscache
caaf.fsCache.DeleteEntry(fsvc) caaf.fsCache.DeleteEntry(fsvc)
} }
// GetFuncSvcFromPoolCache has not been implemented for Container Functions
func (caaf *Container) GetFuncSvcFromPoolCache(ctx context.Context, fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error) {
// Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added.
return nil, 0, nil
}
// TapService makes a TouchByAddress request to the cache. // TapService makes a TouchByAddress request to the cache.
func (caaf *Container) TapService(ctx context.Context, svcHost string) error { func (caaf *Container) TapService(ctx context.Context, svcHost string) error {
err := caaf.fsCache.TouchByAddress(svcHost) err := caaf.fsCache.TouchByAddress(svcHost)
@@ -463,7 +462,7 @@ func (caaf *Container) fnCreate(ctx context.Context, fn *fv1.Function) (*fscache
_, err = caaf.fsCache.Add(*fsvc) _, err = caaf.fsCache.Add(*fsvc)
if err != nil { if err != nil {
caaf.logger.Error("error adding function to cache", zap.Error(err), zap.Any("function", fsvc.Function)) caaf.logger.Error("error adding function to cache", zap.Error(err), zap.Any("function", fsvc.Function))
metrics.FuncError.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc() metrics.ColdStartsError.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc()
return fsvc, err return fsvc, err
} }
@@ -788,3 +787,7 @@ func getDeploymentObj(kubeobjs []apiv1.ObjectReference) *apiv1.ObjectReference {
} }
return nil return nil
} }
func (caaf *Container) DumpDebugInfo(ctx context.Context) error {
return nil
}
+5 -2
View File
@@ -38,8 +38,8 @@ type ExecutorType interface {
// GetFuncSvcFromCache retrieves function service from cache. // GetFuncSvcFromCache retrieves function service from cache.
GetFuncSvcFromCache(context.Context, *fv1.Function) (*fscache.FuncSvc, error) GetFuncSvcFromCache(context.Context, *fv1.Function) (*fscache.FuncSvc, error)
// GetFuncSvcFromPoolCache retrieves function service and number of active instances after filtering on requestsPerPod and CPULimit // DumpDebugInfo dump function service cache to temporary directory of executor pod.
GetFuncSvcFromPoolCache(ctx context.Context, fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error) DumpDebugInfo(context.Context) error
// DeleteFuncSvcFromCache deletes function service entry in cache. // DeleteFuncSvcFromCache deletes function service entry in cache.
DeleteFuncSvcFromCache(context.Context, *fscache.FuncSvc) DeleteFuncSvcFromCache(context.Context, *fscache.FuncSvc)
@@ -51,6 +51,9 @@ type ExecutorType interface {
// UnTapService updates the isActive to false // UnTapService updates the isActive to false
UnTapService(ctx context.Context, key string, svcHost string) UnTapService(ctx context.Context, key string, svcHost string)
// ReduceSpecializationInProgress updates the svcWaiting count in funcSvcGroup
MarkSpecializationFailure(ctx context.Context, key string)
// IsValid returns true if a function service is valid. Different executor types // IsValid returns true if a function service is valid. Different executor types
// use distinct ways to examine the function service. // use distinct ways to examine the function service.
IsValid(context.Context, *fscache.FuncSvc) bool IsValid(context.Context, *fscache.FuncSvc) bool
@@ -136,7 +136,7 @@ func (deploy *NewDeploy) getDeploymentSpec(ctx context.Context, fn *fv1.Function
} }
gracePeriodSeconds := int64(6 * 60) gracePeriodSeconds := int64(6 * 60)
if env.Spec.TerminationGracePeriod > 0 { if env.Spec.TerminationGracePeriod >= 0 {
gracePeriodSeconds = env.Spec.TerminationGracePeriod gracePeriodSeconds = env.Spec.TerminationGracePeriod
} }
@@ -199,10 +199,9 @@ func (deploy *NewDeploy) UnTapService(ctx context.Context, key string, svcHost s
// Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added. // Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added.
} }
// GetFuncSvcFromPoolCache has not been implemented for NewDeployment // MarkSpecializationFailure has not been implemented for NewDeployment.
func (deploy *NewDeploy) GetFuncSvcFromPoolCache(ctx context.Context, fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error) { func (deploy *NewDeploy) MarkSpecializationFailure(ctx context.Context, key string) {
// Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added. // Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added.
return nil, 0, nil
} }
// TapService makes a TouchByAddress request to the cache. // TapService makes a TouchByAddress request to the cache.
@@ -506,7 +505,7 @@ func (deploy *NewDeploy) fnCreate(ctx context.Context, fn *fv1.Function) (*fscac
_, err = deploy.fsCache.Add(*fsvc) _, err = deploy.fsCache.Add(*fsvc)
if err != nil { if err != nil {
deploy.logger.Error("error adding function to cache", zap.Error(err), zap.Any("function", fsvc.Function)) deploy.logger.Error("error adding function to cache", zap.Error(err), zap.Any("function", fsvc.Function))
metrics.FuncError.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc() metrics.ColdStartsError.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc()
return fsvc, err return fsvc, err
} }
@@ -890,3 +889,7 @@ func (deploy *NewDeploy) scaleDeployment(ctx context.Context, deplNS string, dep
}, metav1.UpdateOptions{}) }, metav1.UpdateOptions{})
return err return err
} }
func (deploy *NewDeploy) DumpDebugInfo(ctx context.Context) error {
return nil
}
@@ -66,7 +66,7 @@ func TestRefreshFuncPods(t *testing.T) {
nsResolver := utils.NamespaceResolver{ nsResolver := utils.NamespaceResolver{
FunctionNamespace: functionNamespace, FunctionNamespace: functionNamespace,
BuiderNamespace: builderNamespace, BuilderNamespace: builderNamespace,
DefaultNamespace: defaultNamespace, DefaultNamespace: defaultNamespace,
} }
ndm.nsResolver = &nsResolver ndm.nsResolver = &nsResolver
+67 -21
View File
@@ -32,6 +32,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
apiv1 "k8s.io/api/core/v1" apiv1 "k8s.io/api/core/v1"
k8s_err "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
@@ -46,7 +47,6 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/crd" "github.com/fission/fission/pkg/crd"
"github.com/fission/fission/pkg/executor/fscache" "github.com/fission/fission/pkg/executor/fscache"
"github.com/fission/fission/pkg/executor/metrics"
fetcherClient "github.com/fission/fission/pkg/fetcher/client" fetcherClient "github.com/fission/fission/pkg/fetcher/client"
fetcherConfig "github.com/fission/fission/pkg/fetcher/config" fetcherConfig "github.com/fission/fission/pkg/fetcher/config"
"github.com/fission/fission/pkg/generated/clientset/versioned" "github.com/fission/fission/pkg/generated/clientset/versioned"
@@ -61,7 +61,7 @@ type (
logger *zap.Logger logger *zap.Logger
env *fv1.Environment env *fv1.Environment
deployment *appsv1.Deployment // kubernetes deployment deployment *appsv1.Deployment // kubernetes deployment
namespace string // namespace to keep our resources fnNamespace string // namespace to keep our resources
podReadyTimeout time.Duration // timeout for generic pods to become ready podReadyTimeout time.Duration // timeout for generic pods to become ready
fsCache *fscache.FunctionServiceCache // cache funcSvc's by function, address and podname fsCache *fscache.FunctionServiceCache // cache funcSvc's by function, address and podname
useSvc bool // create k8s service for specialized pods useSvc bool // create k8s service for specialized pods
@@ -90,7 +90,7 @@ func MakeGenericPool(
kubernetesClient kubernetes.Interface, kubernetesClient kubernetes.Interface,
metricsClient metricsclient.Interface, metricsClient metricsclient.Interface,
env *fv1.Environment, env *fv1.Environment,
namespace string, fnNamespace string,
fsCache *fscache.FunctionServiceCache, fsCache *fscache.FunctionServiceCache,
fetcherConfig *fetcherConfig.Config, fetcherConfig *fetcherConfig.Config,
instanceID string, instanceID string,
@@ -119,7 +119,7 @@ func MakeGenericPool(
fissionClient: fissionClient, fissionClient: fissionClient,
kubernetesClient: kubernetesClient, kubernetesClient: kubernetesClient,
metricsClient: metricsClient, metricsClient: metricsClient,
namespace: namespace, fnNamespace: fnNamespace,
podReadyTimeout: podReadyTimeout, podReadyTimeout: podReadyTimeout,
fsCache: fsCache, fsCache: fsCache,
fetcherConfig: fetcherConfig, fetcherConfig: fetcherConfig,
@@ -186,7 +186,7 @@ func (gp *GenericPool) updateCPUUtilizationSvc(ctx context.Context) {
} }
serviceFunc := func(ctx context.Context) { serviceFunc := func(ctx context.Context) {
podMetricsList, err := gp.metricsClient.MetricsV1beta1().PodMetricses(gp.namespace).List(ctx, metav1.ListOptions{ podMetricsList, err := gp.metricsClient.MetricsV1beta1().PodMetricses(gp.fnNamespace).List(ctx, metav1.ListOptions{
LabelSelector: "managed=false", LabelSelector: "managed=false",
}) })
if err != nil { if err != nil {
@@ -226,6 +226,14 @@ func (gp *GenericPool) updateCPUUtilizationSvc(ctx context.Context) {
// returns the key and pod API object. // returns the key and pod API object.
func (gp *GenericPool) choosePod(ctx context.Context, newLabels map[string]string) (string, *apiv1.Pod, error) { func (gp *GenericPool) choosePod(ctx context.Context, newLabels map[string]string) (string, *apiv1.Pod, error) {
startTime := time.Now() startTime := time.Now()
podTimeout := startTime.Add(gp.podReadyTimeout)
deadline, ok := ctx.Deadline()
if ok {
deadline = deadline.Add(-1 * time.Second)
if deadline.Before(podTimeout) {
podTimeout = deadline
}
}
expoDelay := 100 * time.Millisecond expoDelay := 100 * time.Millisecond
logger := otelUtils.LoggerWithTraceID(ctx, gp.logger) logger := otelUtils.LoggerWithTraceID(ctx, gp.logger)
if !cache.WaitForCacheSync(ctx.Done(), gp.readyPodListerSynced) { if !cache.WaitForCacheSync(ctx.Done(), gp.readyPodListerSynced) {
@@ -234,10 +242,14 @@ func (gp *GenericPool) choosePod(ctx context.Context, newLabels map[string]strin
} }
for { for {
// Retries took too long, error out. // Retries took too long, error out.
if time.Since(startTime) > gp.podReadyTimeout { if time.Now().After(podTimeout) {
logger.Error("timed out waiting for pod", zap.Any("labels", newLabels), zap.Duration("timeout", gp.podReadyTimeout)) logger.Error("timed out waiting for pod", zap.Any("labels", newLabels), zap.Duration("timeout", podTimeout.Sub(startTime)))
return "", nil, errors.New("timeout: waited too long to get a ready pod") return "", nil, errors.New("timeout: waited too long to get a ready pod")
} }
if ctx.Err() != nil {
logger.Error("context canceled while waiting for pod", zap.Any("labels", newLabels), zap.Duration("timeout", podTimeout.Sub(startTime)))
return "", nil, fmt.Errorf("context canceled while waiting for pod: %w", ctx.Err())
}
var chosenPod *apiv1.Pod var chosenPod *apiv1.Pod
var key string var key string
@@ -291,7 +303,12 @@ func (gp *GenericPool) choosePod(ctx context.Context, newLabels map[string]strin
patch := fmt.Sprintf(`{"metadata":{"annotations":%v, "labels":%v}}`, string(annotationPatch), string(labelPatch)) patch := fmt.Sprintf(`{"metadata":{"annotations":%v, "labels":%v}}`, string(annotationPatch), string(labelPatch))
logger.Info("relabel pod", zap.String("pod", patch)) logger.Info("relabel pod", zap.String("pod", patch))
newPod, err := gp.kubernetesClient.CoreV1().Pods(chosenPod.Namespace).Patch(ctx, chosenPod.Name, k8sTypes.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{}) newPod, err := gp.kubernetesClient.CoreV1().Pods(chosenPod.Namespace).Patch(ctx, chosenPod.Name, k8sTypes.StrategicMergePatchType, []byte(patch), metav1.PatchOptions{})
if err != nil { if err != nil && errors.Is(err, context.Canceled) {
// ending retry loop when the request canceled
gp.readyPodQueue.Done(key)
gp.readyPodQueue.AddAfter(key, expoDelay)
return "", nil, errors.Errorf("failed to relabel pod: %s", err)
} else if err != nil {
logger.Error("failed to relabel pod", zap.Error(err), zap.String("pod", chosenPod.Name), zap.Duration("delay", expoDelay)) logger.Error("failed to relabel pod", zap.Error(err), zap.String("pod", chosenPod.Name), zap.Duration("delay", expoDelay))
gp.readyPodQueue.Done(key) gp.readyPodQueue.Done(key)
gp.readyPodQueue.AddAfter(key, expoDelay) gp.readyPodQueue.AddAfter(key, expoDelay)
@@ -338,12 +355,12 @@ func (gp *GenericPool) scheduleDeletePod(ctx context.Context, name string) {
// cleaned up. (We need a better solutions for both those things; log // cleaned up. (We need a better solutions for both those things; log
// aggregation and storage will help.) // aggregation and storage will help.)
gp.logger.Error("error in pod - scheduling cleanup", zap.String("pod", name)) gp.logger.Error("error in pod - scheduling cleanup", zap.String("pod", name))
err := gp.kubernetesClient.CoreV1().Pods(gp.namespace).Delete(ctx, name, metav1.DeleteOptions{}) err := gp.kubernetesClient.CoreV1().Pods(gp.fnNamespace).Delete(ctx, name, metav1.DeleteOptions{})
if err != nil { if err != nil {
gp.logger.Error( gp.logger.Error(
"error deleting pod", "error deleting pod",
zap.String("name", name), zap.String("name", name),
zap.String("namespace", gp.namespace), zap.String("namespace", gp.fnNamespace),
zap.Error(err), zap.Error(err),
) )
} }
@@ -387,10 +404,41 @@ func (gp *GenericPool) specializePod(ctx context.Context, pod *apiv1.Pod, fn *fv
if len(podIP) == 0 { if len(podIP) == 0 {
return errors.Errorf("Pod %s in namespace %s has no IP", pod.ObjectMeta.Name, pod.ObjectMeta.Namespace) return errors.Errorf("Pod %s in namespace %s has no IP", pod.ObjectMeta.Name, pod.ObjectMeta.Namespace)
} }
for _, cm := range fn.Spec.ConfigMaps {
_, err := gp.kubernetesClient.CoreV1().ConfigMaps(gp.fnNamespace).Get(ctx, cm.Name, metav1.GetOptions{})
if err != nil {
if k8s_err.IsNotFound(err) {
logger.Error("configmap namespace mismatch", zap.String("error", "configmap must be in same namespace as function namespace"),
zap.String("configmap_name", cm.Name),
zap.String("configmap_namespace", cm.Namespace),
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", gp.fnNamespace))
return fmt.Errorf(fmt.Sprintf("configmap %s must be in same namespace as function namespace", cm.Name))
} else {
return err
}
}
}
for _, sec := range fn.Spec.Secrets {
_, err := gp.kubernetesClient.CoreV1().Secrets(gp.fnNamespace).Get(ctx, sec.Name, metav1.GetOptions{})
if err != nil {
if k8s_err.IsNotFound(err) {
logger.Error("secret namespace mismatch", zap.String("error", "secret must be in same namespace as function namespace"),
zap.String("secret_name", sec.Name),
zap.String("secret_namespace", sec.Namespace),
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", gp.fnNamespace))
return fmt.Errorf(fmt.Sprintf("secret %s must be in same namespace as function namespace", sec.Name))
} else {
return err
}
}
}
// specialize pod with service // specialize pod with service
if gp.useIstio { if gp.useIstio {
svc := utils.GetFunctionIstioServiceName(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace) svc := utils.GetFunctionIstioServiceName(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace)
podIP = fmt.Sprintf("%v.%v", svc, gp.namespace) podIP = fmt.Sprintf("%v.%v", svc, gp.fnNamespace)
} }
// tell fetcher to get the function. // tell fetcher to get the function.
@@ -432,7 +480,7 @@ func (gp *GenericPool) createSvc(ctx context.Context, name string, labels map[st
Selector: labels, Selector: labels,
}, },
} }
svc, err := gp.kubernetesClient.CoreV1().Services(gp.namespace).Create(ctx, &service, metav1.CreateOptions{}) svc, err := gp.kubernetesClient.CoreV1().Services(gp.fnNamespace).Create(ctx, &service, metav1.CreateOptions{})
return svc, err return svc, err
} }
@@ -470,7 +518,7 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
"functionName": fn.ObjectMeta.Name, "functionName": fn.ObjectMeta.Name,
"functionUid": string(fn.ObjectMeta.UID), "functionUid": string(fn.ObjectMeta.UID),
} }
podList, err := gp.kubernetesClient.CoreV1().Pods(gp.namespace).List(ctx, metav1.ListOptions{ podList, err := gp.kubernetesClient.CoreV1().Pods(gp.fnNamespace).List(ctx, metav1.ListOptions{
LabelSelector: labels.Set(sel).AsSelector().String(), LabelSelector: labels.Set(sel).AsSelector().String(),
}) })
if err != nil { if err != nil {
@@ -480,7 +528,7 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
// Remove old versions function pods // Remove old versions function pods
for _, pod := range podList.Items { for _, pod := range podList.Items {
// Delete pod no matter what status it is // Delete pod no matter what status it is
gp.kubernetesClient.CoreV1().Pods(gp.namespace).Delete(ctx, pod.ObjectMeta.Name, metav1.DeleteOptions{}) //nolint errcheck gp.kubernetesClient.CoreV1().Pods(gp.fnNamespace).Delete(ctx, pod.ObjectMeta.Name, metav1.DeleteOptions{}) // nolint errcheck
} }
} }
@@ -515,10 +563,10 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
// the fission router isn't in the same namespace, so return a // the fission router isn't in the same namespace, so return a
// namespace-qualified hostname // namespace-qualified hostname
svcHost = fmt.Sprintf("%v.%v:8888", svcName, gp.namespace) svcHost = fmt.Sprintf("%v.%v:8888", svcName, gp.fnNamespace)
} else if gp.useIstio { } else if gp.useIstio {
svc := utils.GetFunctionIstioServiceName(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace) svc := utils.GetFunctionIstioServiceName(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace)
svcHost = fmt.Sprintf("%v.%v:8888", svc, gp.namespace) svcHost = fmt.Sprintf("%v.%v:8888", svc, gp.fnNamespace)
} else { } else {
svcHost = fmt.Sprintf("%v:8888", pod.Status.PodIP) svcHost = fmt.Sprintf("%v:8888", pod.Status.PodIP)
} }
@@ -575,9 +623,7 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
gp.fsCache.PodToFsvc.Store(pod.GetObjectMeta().GetName(), fsvc) gp.fsCache.PodToFsvc.Store(pod.GetObjectMeta().GetName(), fsvc)
gp.podFSVCMap.Store(pod.ObjectMeta.Name, []interface{}{crd.CacheKey(fsvc.Function), fsvc.Address}) gp.podFSVCMap.Store(pod.ObjectMeta.Name, []interface{}{crd.CacheKey(fsvc.Function), fsvc.Address})
gp.fsCache.AddFunc(ctx, *fsvc) gp.fsCache.AddFunc(ctx, *fsvc, fn.GetRequestPerPod())
metrics.ColdStarts.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc()
logger.Info("added function service", logger.Info("added function service",
zap.String("pod", pod.ObjectMeta.Name), zap.String("pod", pod.ObjectMeta.Name),
@@ -605,12 +651,12 @@ func (gp *GenericPool) destroy(ctx context.Context) error {
} }
err := gp.kubernetesClient.AppsV1(). err := gp.kubernetesClient.AppsV1().
Deployments(gp.namespace).Delete(ctx, gp.deployment.ObjectMeta.Name, delOpt) Deployments(gp.fnNamespace).Delete(ctx, gp.deployment.ObjectMeta.Name, delOpt)
if err != nil { if err != nil {
gp.logger.Error("error destroying deployment", gp.logger.Error("error destroying deployment",
zap.Error(err), zap.Error(err),
zap.String("deployment_name", gp.deployment.ObjectMeta.Name), zap.String("deployment_name", gp.deployment.ObjectMeta.Name),
zap.String("deployment_namespace", gp.namespace)) zap.String("deployment_namespace", gp.fnNamespace))
return err return err
} }
return nil return nil
@@ -70,7 +70,7 @@ func (gp *GenericPool) genDeploymentSpec(env *fv1.Environment) (*appsv1.Deployme
// Use long terminationGracePeriodSeconds for connection draining in case that // Use long terminationGracePeriodSeconds for connection draining in case that
// pod still runs user functions. // pod still runs user functions.
gracePeriodSeconds := int64(6 * 60) gracePeriodSeconds := int64(6 * 60)
if env.Spec.TerminationGracePeriod > 0 { if env.Spec.TerminationGracePeriod >= 0 {
gracePeriodSeconds = env.Spec.TerminationGracePeriod gracePeriodSeconds = env.Spec.TerminationGracePeriod
} }
@@ -205,13 +205,13 @@ func (gp *GenericPool) createPoolDeployment(ctx context.Context, env *fv1.Enviro
ObjectMeta: deploymentMeta, ObjectMeta: deploymentMeta,
Spec: *deploymentSpec, Spec: *deploymentSpec,
} }
depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Get(ctx, deployment.Name, metav1.GetOptions{}) depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.fnNamespace).Get(ctx, deployment.Name, metav1.GetOptions{})
if err == nil { if err == nil {
if depl.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] != gp.instanceID { if depl.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] != gp.instanceID {
deployment.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] = gp.instanceID deployment.Annotations[fv1.EXECUTOR_INSTANCEID_LABEL] = gp.instanceID
// Update with the latest deployment spec. Kubernetes will trigger // Update with the latest deployment spec. Kubernetes will trigger
// rolling update if spec is different from the one in the cluster. // rolling update if spec is different from the one in the cluster.
depl, err = gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Update(ctx, deployment, metav1.UpdateOptions{}) depl, err = gp.kubernetesClient.AppsV1().Deployments(gp.fnNamespace).Update(ctx, deployment, metav1.UpdateOptions{})
} }
gp.deployment = depl gp.deployment = depl
return err return err
@@ -220,7 +220,7 @@ func (gp *GenericPool) createPoolDeployment(ctx context.Context, env *fv1.Enviro
return err return err
} }
depl, err = gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Create(ctx, deployment, metav1.CreateOptions{}) depl, err = gp.kubernetesClient.AppsV1().Deployments(gp.fnNamespace).Create(ctx, deployment, metav1.CreateOptions{})
if err != nil { if err != nil {
gp.logger.Error("error creating deployment in kubernetes", zap.Error(err), zap.String("deployment", deployment.Name)) gp.logger.Error("error creating deployment in kubernetes", zap.Error(err), zap.String("deployment", deployment.Name))
return err return err
@@ -256,7 +256,7 @@ func (gp *GenericPool) updatePoolDeployment(ctx context.Context, env *fv1.Enviro
} }
newDeployment.Spec.Replicas = &poolsize newDeployment.Spec.Replicas = &poolsize
depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.namespace).Update(ctx, newDeployment, metav1.UpdateOptions{}) depl, err := gp.kubernetesClient.AppsV1().Deployments(gp.fnNamespace).Update(ctx, newDeployment, metav1.UpdateOptions{})
if err != nil { if err != nil {
logger.Error("error updating deployment in kubernetes", zap.Error(err), zap.String("deployment", depl.Name)) logger.Error("error updating deployment in kubernetes", zap.Error(err), zap.String("deployment", depl.Name))
return err return err
+33 -11
View File
@@ -26,6 +26,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/fission/fission/pkg/executor/metrics"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
"go.uber.org/zap" "go.uber.org/zap"
@@ -186,19 +187,31 @@ func (gpm *GenericPoolManager) GetTypeName(ctx context.Context) fv1.ExecutorType
return fv1.ExecutorTypePoolmgr return fv1.ExecutorTypePoolmgr
} }
func (gpm *GenericPoolManager) GetFuncSvc(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) { func (gpm *GenericPoolManager) GetFuncSvc(ctx context.Context, fn *fv1.Function) (fnSvc *fscache.FuncSvc, fErr error) {
defer func() {
if fErr != nil {
metrics.ColdStartsError.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc()
return
}
metrics.ColdStarts.WithLabelValues(fn.ObjectMeta.Name, fn.ObjectMeta.Namespace).Inc()
}()
otelUtils.SpanTrackEvent(ctx, "GetFuncSvc", otelUtils.GetAttributesForFunction(fn)...) otelUtils.SpanTrackEvent(ctx, "GetFuncSvc", otelUtils.GetAttributesForFunction(fn)...)
logger := otelUtils.LoggerWithTraceID(ctx, gpm.logger) logger := otelUtils.LoggerWithTraceID(ctx, gpm.logger)
// from Func -> get Env // from Func -> get Env
logger.Debug("getting environment for function", zap.String("function", fn.ObjectMeta.Name)) logger.Debug("getting environment for function", zap.String("function", fn.ObjectMeta.Name))
env, err := gpm.getFunctionEnv(ctx, fn) env, err := gpm.getFunctionEnv(ctx, fn)
if err != nil { if err != nil {
return nil, err fErr = err
return
} }
pool, created, err := gpm.getPool(ctx, env) pool, created, err := gpm.getPool(ctx, env)
if err != nil { if err != nil {
return nil, err fErr = err
return
} }
if created { if created {
@@ -208,16 +221,13 @@ func (gpm *GenericPoolManager) GetFuncSvc(ctx context.Context, fn *fv1.Function)
// from GenericPool -> get one function container // from GenericPool -> get one function container
// (this also adds to the cache) // (this also adds to the cache)
logger.Debug("getting function service from pool", zap.String("function", fn.ObjectMeta.Name)) logger.Debug("getting function service from pool", zap.String("function", fn.ObjectMeta.Name))
return pool.getFuncSvc(ctx, fn) fnSvc, fErr = pool.getFuncSvc(ctx, fn)
return fnSvc, fErr
} }
func (gpm *GenericPoolManager) GetFuncSvcFromCache(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) { func (gpm *GenericPoolManager) GetFuncSvcFromCache(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
return nil, nil otelUtils.SpanTrackEvent(ctx, "GetFuncSvcFromCache", otelUtils.GetAttributesForFunction(fn)...)
} return gpm.fsCache.GetFuncSvc(ctx, &fn.ObjectMeta, fn.GetRequestPerPod(), fn.GetConcurrency())
func (gpm *GenericPoolManager) GetFuncSvcFromPoolCache(ctx context.Context, fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error) {
otelUtils.SpanTrackEvent(ctx, "GetFuncSvcFromPoolCache", otelUtils.GetAttributesForFunction(fn)...)
return gpm.fsCache.GetFuncSvc(ctx, &fn.ObjectMeta, requestsPerPod)
} }
func (gpm *GenericPoolManager) DeleteFuncSvcFromCache(ctx context.Context, fsvc *fscache.FuncSvc) { func (gpm *GenericPoolManager) DeleteFuncSvcFromCache(ctx context.Context, fsvc *fscache.FuncSvc) {
@@ -242,6 +252,14 @@ func (gpm *GenericPoolManager) TapService(ctx context.Context, svcHost string) e
return nil return nil
} }
func (gpm *GenericPoolManager) MarkSpecializationFailure(ctx context.Context, key string) {
otelUtils.SpanTrackEvent(ctx, "MarkSpecializationFailure",
attribute.KeyValue{Key: "key", Value: attribute.StringValue(key)})
logger := otelUtils.LoggerWithTraceID(ctx, gpm.logger)
logger.Info("marking specialization failure", zap.Any("key", key))
gpm.fsCache.MarkSpecializationFailure(key)
}
// IsValid checks if pod is not deleted and that it has the address passed as the argument. Also checks that all the // IsValid checks if pod is not deleted and that it has the address passed as the argument. Also checks that all the
// containers in it are reporting a ready status for the healthCheck. // containers in it are reporting a ready status for the healthCheck.
func (gpm *GenericPoolManager) IsValid(ctx context.Context, fsvc *fscache.FuncSvc) bool { func (gpm *GenericPoolManager) IsValid(ctx context.Context, fsvc *fscache.FuncSvc) bool {
@@ -711,7 +729,7 @@ func (gpm *GenericPoolManager) NoActiveConnectionEventChecker(ctx context.Contex
defer close(stopper) defer close(stopper)
var wg wait.Group var wg wait.Group
for _, informer := range utils.GetInformerEventChecker(ctx, kubeClient, "WsConnectionStarted") { for _, informer := range utils.GetInformerEventChecker(ctx, kubeClient, "NoActiveConnections") {
informer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{ informer.AddEventHandler(k8sCache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) { AddFunc: func(obj interface{}) {
mObj := obj.(metav1.Object) mObj := obj.(metav1.Object)
@@ -744,3 +762,7 @@ func (gpm *GenericPoolManager) NoActiveConnectionEventChecker(ctx context.Contex
} }
wg.Wait() wg.Wait()
} }
func (gpm *GenericPoolManager) DumpDebugInfo(ctx context.Context) error {
return gpm.fsCache.DumpDebugInfo(ctx)
}
@@ -31,7 +31,7 @@ func (gp *GenericPool) readyPodEventHandlers() k8sCache.ResourceEventHandlerFunc
func (gp *GenericPool) setupReadyPodController() error { func (gp *GenericPool) setupReadyPodController() error {
gp.readyPodQueue = workqueue.NewDelayingQueue() gp.readyPodQueue = workqueue.NewDelayingQueue()
informerFactory, err := utils.GetInformerFactoryByReadyPod(gp.kubernetesClient, gp.namespace, gp.deployment.Spec.Selector) informerFactory, err := utils.GetInformerFactoryByReadyPod(gp.kubernetesClient, gp.fnNamespace, gp.deployment.Spec.Selector)
if err != nil { if err != nil {
return err return err
} }
+41 -17
View File
@@ -35,7 +35,7 @@ import (
"github.com/fission/fission/pkg/crd" "github.com/fission/fission/pkg/crd"
ferror "github.com/fission/fission/pkg/error" ferror "github.com/fission/fission/pkg/error"
"github.com/fission/fission/pkg/executor/metrics" "github.com/fission/fission/pkg/executor/metrics"
"github.com/fission/fission/pkg/poolcache" "github.com/fission/fission/pkg/executor/util"
) )
type fscRequestType int type fscRequestType int
@@ -68,12 +68,12 @@ type (
// FunctionServiceCache represents the function service cache // FunctionServiceCache represents the function service cache
FunctionServiceCache struct { FunctionServiceCache struct {
logger *zap.Logger logger *zap.Logger
byFunction *cache.Cache // function-key -> funcSvc : map[string]*funcSvc byFunction *cache.Cache // function-key -> funcSvc : map[string]*funcSvc
byAddress *cache.Cache // address -> function : map[string]metav1.ObjectMeta byAddress *cache.Cache // address -> function : map[string]metav1.ObjectMeta
byFunctionUID *cache.Cache // function uid -> function : map[string]metav1.ObjectMeta byFunctionUID *cache.Cache // function uid -> function : map[string]metav1.ObjectMeta
connFunctionCache *poolcache.Cache // function-key -> funcSvc : map[string]*funcSvc connFunctionCache *PoolCache // function-key -> funcSvc : map[string]*funcSvc
PodToFsvc sync.Map // pod-name -> funcSvc: map[string]*FuncSvc PodToFsvc sync.Map // pod-name -> funcSvc: map[string]*FuncSvc
WebsocketFsvc sync.Map // funcSvc-name -> bool: map[string]bool WebsocketFsvc sync.Map // funcSvc-name -> bool: map[string]bool
requestChannel chan *fscRequest requestChannel chan *fscRequest
} }
@@ -113,7 +113,7 @@ func MakeFunctionServiceCache(logger *zap.Logger) *FunctionServiceCache {
byFunction: cache.MakeCache(0, 0), byFunction: cache.MakeCache(0, 0),
byAddress: cache.MakeCache(0, 0), byAddress: cache.MakeCache(0, 0),
byFunctionUID: cache.MakeCache(0, 0), byFunctionUID: cache.MakeCache(0, 0),
connFunctionCache: poolcache.NewPoolCache(logger.Named("conn_function_cache")), connFunctionCache: NewPoolCache(logger.Named("conn_function_cache")),
requestChannel: make(chan *fscRequest), requestChannel: make(chan *fscRequest),
} }
go fsc.service() go fsc.service()
@@ -159,8 +159,8 @@ func (fsc *FunctionServiceCache) service() {
case LISTOLDPOOL: case LISTOLDPOOL:
fscs := fsc.connFunctionCache.ListAvailableValue() fscs := fsc.connFunctionCache.ListAvailableValue()
funcObjects := make([]*FuncSvc, 0) funcObjects := make([]*FuncSvc, 0)
for _, funcSvc := range fscs { for _, fsvc := range fscs {
if fsvc, ok := funcSvc.(*FuncSvc); ok && time.Since(fsvc.Atime) > req.age { if time.Since(fsvc.Atime) > req.age {
funcObjects = append(funcObjects, fsvc) funcObjects = append(funcObjects, fsvc)
} }
} }
@@ -171,6 +171,27 @@ func (fsc *FunctionServiceCache) service() {
} }
} }
// DumpDebugInfo => dump function service cache data to temporary directory of executor pod.
func (fsc *FunctionServiceCache) DumpDebugInfo(ctx context.Context) error {
fsc.logger.Info("dumping function service")
file, err := util.CreateDumpFile(fsc.logger)
if err != nil {
fsc.logger.Error("error while creating file/dir", zap.String("error", err.Error()))
return err
}
defer file.Close()
err = fsc.connFunctionCache.LogFnSvcGroup(ctx, file)
if err != nil {
fsc.logger.Error("error while logging function service group", zap.String("error", err.Error()))
return err
}
fsc.logger.Info("dumped function service")
return nil
}
// GetByFunction gets a function service from cache using function key. // GetByFunction gets a function service from cache using function key.
func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc, error) { func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc, error) {
key := crd.CacheKey(m) key := crd.CacheKey(m)
@@ -189,21 +210,20 @@ func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc,
} }
// GetFuncSvc gets a function service from pool cache using function key and returns number of active instances of function pod // GetFuncSvc gets a function service from pool cache using function key and returns number of active instances of function pod
func (fsc *FunctionServiceCache) GetFuncSvc(ctx context.Context, m *metav1.ObjectMeta, requestsPerPod int) (*FuncSvc, int, error) { func (fsc *FunctionServiceCache) GetFuncSvc(ctx context.Context, m *metav1.ObjectMeta, requestsPerPod int, concurrency int) (*FuncSvc, error) {
key := crd.CacheKey(m) key := crd.CacheKey(m)
fsvcI, active, err := fsc.connFunctionCache.GetValue(ctx, key, requestsPerPod) fsvc, err := fsc.connFunctionCache.GetSvcValue(ctx, key, requestsPerPod, concurrency)
if err != nil { if err != nil {
fsc.logger.Info("Not found in Cache") fsc.logger.Info("Not found in Cache")
return nil, active, err return nil, err
} }
// update atime // update atime
fsvc := fsvcI.(*FuncSvc)
fsvc.Atime = time.Now() fsvc.Atime = time.Now()
fsvcCopy := *fsvc fsvcCopy := *fsvc
return &fsvcCopy, active, nil return &fsvcCopy, nil
} }
// GetByFunctionUID gets a function service from cache using function UUID. // GetByFunctionUID gets a function service from cache using function UUID.
@@ -229,8 +249,8 @@ func (fsc *FunctionServiceCache) GetByFunctionUID(uid types.UID) (*FuncSvc, erro
} }
// AddFunc adds a function service to pool cache. // AddFunc adds a function service to pool cache.
func (fsc *FunctionServiceCache) AddFunc(ctx context.Context, fsvc FuncSvc) { func (fsc *FunctionServiceCache) AddFunc(ctx context.Context, fsvc FuncSvc, requestsPerPod int) {
fsc.connFunctionCache.SetValue(ctx, crd.CacheKey(fsvc.Function), fsvc.Address, &fsvc, fsvc.CPULimit) fsc.connFunctionCache.SetSvcValue(ctx, crd.CacheKey(fsvc.Function), fsvc.Address, &fsvc, fsvc.CPULimit, requestsPerPod)
now := time.Now() now := time.Now()
fsvc.Ctime = now fsvc.Ctime = now
fsvc.Atime = now fsvc.Atime = now
@@ -246,6 +266,10 @@ func (fsc *FunctionServiceCache) MarkAvailable(key string, svcHost string) {
fsc.connFunctionCache.MarkAvailable(key, svcHost) fsc.connFunctionCache.MarkAvailable(key, svcHost)
} }
func (fsc *FunctionServiceCache) MarkSpecializationFailure(key string) {
fsc.connFunctionCache.MarkSpecializationFailure(key)
}
// Add adds a function service to cache if it does not exist already. // Add adds a function service to cache if it does not exist already.
func (fsc *FunctionServiceCache) Add(fsvc FuncSvc) (*FuncSvc, error) { func (fsc *FunctionServiceCache) Add(fsvc FuncSvc) (*FuncSvc, error) {
existing, err := fsc.byFunction.Set(crd.CacheKey(fsvc.Function), &fsvc) existing, err := fsc.byFunction.Set(crd.CacheKey(fsvc.Function), &fsvc)
@@ -187,19 +187,17 @@ func TestFunctionServiceNewCache(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
fsc.AddFunc(ctx, *fsvc) fsc.AddFunc(ctx, *fsvc, 10)
_, active, err := fsc.GetFuncSvc(ctx, fsvc.Function, 5) concurrency := 10
_, err = fsc.GetFuncSvc(ctx, fsvc.Function, 5, concurrency)
if err != nil { if err != nil {
logger.Panic("received error while retrieving value from cache") logger.Panic("received error while retrieving value from cache")
} }
if active != 1 {
logger.Panic(fmt.Sprintln("active instances not matched expected 1, found ", active))
}
key := fmt.Sprintf("%v_%v", fn.ObjectMeta.UID, fn.ObjectMeta.ResourceVersion) key := fmt.Sprintf("%v_%v", fn.ObjectMeta.UID, fn.ObjectMeta.ResourceVersion)
fsc.MarkAvailable(key, fsvc.Address) fsc.MarkAvailable(key, fsvc.Address)
_, _, err = fsc.GetFuncSvc(ctx, fsvc.Function, 5) _, err = fsc.GetFuncSvc(ctx, fsvc.Function, 5, concurrency)
if err != nil { if err != nil {
logger.Panic("received error while retrieving value from cache") logger.Panic("received error while retrieving value from cache")
} }
+405
View File
@@ -0,0 +1,405 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fscache
import (
"bufio"
"context"
"fmt"
"io"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/api/resource"
ferror "github.com/fission/fission/pkg/error"
otelUtils "github.com/fission/fission/pkg/utils/otel"
)
type requestType int
const (
getValue requestType = iota
listAvailableValue
setValue
markAvailable
deleteValue
setCPUUtilization
markSpecializationFailure
logFuncSvc
)
type (
funcSvcInfo struct {
val *FuncSvc
activeRequests int // number of requests served by function pod
currentCPUUsage resource.Quantity // current cpu usage of the specialized function pod
cpuLimit resource.Quantity // if currentCPUUsage is more than cpuLimit cache miss occurs in getValue request
}
funcSvcGroup struct {
svcWaiting int
svcs map[string]*funcSvcInfo
queue *Queue
}
// PoolCache implements a simple cache implementation having values mapped by two keys [function][address].
// As of now PoolCache is only used by poolmanager executor
PoolCache struct {
cache map[string]*funcSvcGroup
requestChannel chan *request
logger *zap.Logger
}
request struct {
requestType
ctx context.Context
function string
address string
dumpWriter io.Writer
value *FuncSvc
requestsPerPod int
cpuUsage resource.Quantity
responseChannel chan *response
concurrency int
}
response struct {
error
allValues []*FuncSvc
value *FuncSvc
svcWaitValue *svcWait
}
svcWait struct {
svcChannel chan *FuncSvc
ctx context.Context
}
)
// NewPoolCache create a Cache object
func NewPoolCache(logger *zap.Logger) *PoolCache {
c := &PoolCache{
cache: make(map[string]*funcSvcGroup),
requestChannel: make(chan *request),
logger: logger,
}
go c.service()
return c
}
func NewFuncSvcGroup() *funcSvcGroup {
return &funcSvcGroup{
svcs: make(map[string]*funcSvcInfo),
queue: NewQueue(),
}
}
func (c *PoolCache) service() {
for {
req := <-c.requestChannel
resp := &response{}
switch req.requestType {
case getValue:
funcSvcGroup, ok := c.cache[req.function]
if !ok {
c.cache[req.function] = NewFuncSvcGroup()
c.cache[req.function].svcWaiting++
resp.error = ferror.MakeError(ferror.ErrorNotFound,
fmt.Sprintf("function Name '%v' not found", req.function))
req.responseChannel <- resp
continue
}
found := false
totalActiveRequests := 0
for addr := range funcSvcGroup.svcs {
totalActiveRequests += funcSvcGroup.svcs[addr].activeRequests
if funcSvcGroup.svcs[addr].activeRequests < req.requestsPerPod &&
funcSvcGroup.svcs[addr].currentCPUUsage.Cmp(funcSvcGroup.svcs[addr].cpuLimit) < 1 {
// mark active
funcSvcGroup.svcs[addr].activeRequests++
if c.logger.Core().Enabled(zap.DebugLevel) {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Increase active requests with getValue", zap.String("function", req.function), zap.String("address", addr), zap.Int("activeRequests", funcSvcGroup.svcs[addr].activeRequests))
}
resp.value = funcSvcGroup.svcs[addr].val
found = true
break
}
}
if found {
req.responseChannel <- resp
continue
}
specializationInProgress := funcSvcGroup.svcWaiting - funcSvcGroup.queue.Len()
capacity := ((specializationInProgress + len(funcSvcGroup.svcs)) * req.requestsPerPod) - (totalActiveRequests + funcSvcGroup.svcWaiting)
if capacity > 0 {
funcSvcGroup.svcWaiting++
svcWait := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: req.ctx,
}
resp.svcWaitValue = svcWait
funcSvcGroup.queue.Push(svcWait)
req.responseChannel <- resp
continue
}
// concurrency should not be set to zero and
//sum of specialization in progress and specialized pods should be less then req.concurrency
if req.concurrency > 0 && (specializationInProgress+len(funcSvcGroup.svcs)) >= req.concurrency {
resp.error = ferror.MakeError(ferror.ErrorTooManyRequests, fmt.Sprintf("function '%s' concurrency '%d' limit reached.", req.function, req.concurrency))
} else {
funcSvcGroup.svcWaiting++
resp.error = ferror.MakeError(ferror.ErrorNotFound, fmt.Sprintf("function '%s' all functions are busy", req.function))
}
req.responseChannel <- resp
case setValue:
if _, ok := c.cache[req.function]; !ok {
c.cache[req.function] = NewFuncSvcGroup()
}
if _, ok := c.cache[req.function].svcs[req.address]; !ok {
c.cache[req.function].svcs[req.address] = &funcSvcInfo{}
}
c.cache[req.function].svcs[req.address].val = req.value
c.cache[req.function].svcs[req.address].activeRequests++
if c.cache[req.function].svcWaiting > 0 {
c.cache[req.function].svcWaiting--
svcCapacity := req.requestsPerPod - c.cache[req.function].svcs[req.address].activeRequests
queueLen := c.cache[req.function].queue.Len()
if svcCapacity > queueLen {
svcCapacity = queueLen
}
for i := 0; i <= svcCapacity; {
popped := c.cache[req.function].queue.Pop()
if popped == nil {
break
}
if popped.ctx.Err() == nil {
popped.svcChannel <- req.value
c.cache[req.function].svcs[req.address].activeRequests++
i++
}
close(popped.svcChannel)
c.cache[req.function].svcWaiting--
}
}
if c.logger.Core().Enabled(zap.DebugLevel) {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Increase active requests with setValue", zap.String("function", req.function), zap.String("address", req.address), zap.Int("activeRequests", c.cache[req.function].svcs[req.address].activeRequests))
}
c.cache[req.function].svcs[req.address].cpuLimit = req.cpuUsage
case listAvailableValue:
vals := make([]*FuncSvc, 0)
for key1, values := range c.cache {
for key2, value := range values.svcs {
debugLevel := c.logger.Core().Enabled(zap.DebugLevel)
if debugLevel {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Reading active requests", zap.String("function", key1), zap.String("address", key2), zap.Int("activeRequests", value.activeRequests))
}
if value.activeRequests == 0 {
if debugLevel {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Function service with no active requests", zap.String("function", key1), zap.String("address", key2), zap.Int("activeRequests", value.activeRequests))
}
vals = append(vals, value.val)
}
}
}
resp.allValues = vals
req.responseChannel <- resp
case setCPUUtilization:
if _, ok := c.cache[req.function]; !ok {
c.cache[req.function] = NewFuncSvcGroup()
}
if _, ok := c.cache[req.function].svcs[req.address]; ok {
c.cache[req.function].svcs[req.address].currentCPUUsage = req.cpuUsage
}
case markAvailable:
if _, ok := c.cache[req.function]; ok {
if _, ok = c.cache[req.function].svcs[req.address]; ok {
if c.cache[req.function].svcs[req.address].activeRequests > 0 {
c.cache[req.function].svcs[req.address].activeRequests--
if c.logger.Core().Enabled(zap.DebugLevel) {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Decrease active requests", zap.String("function", req.function), zap.String("address", req.address), zap.Int("activeRequests", c.cache[req.function].svcs[req.address].activeRequests))
}
} else {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Error("Invalid request to decrease active requests", zap.String("function", req.function), zap.String("address", req.address), zap.Int("activeRequests", c.cache[req.function].svcs[req.address].activeRequests))
}
}
}
case markSpecializationFailure:
if c.cache[req.function].svcWaiting > c.cache[req.function].queue.Len() {
c.cache[req.function].svcWaiting--
if c.cache[req.function].svcWaiting == c.cache[req.function].queue.Len() {
expiredRequests := c.cache[req.function].queue.Expired()
c.cache[req.function].svcWaiting = c.cache[req.function].svcWaiting - expiredRequests
}
}
case deleteValue:
delete(c.cache[req.function].svcs, req.address)
req.responseChannel <- resp
case logFuncSvc:
datawriter := bufio.NewWriter(req.dumpWriter)
writefnSvcGrp := func(svcGrp *funcSvcGroup) error {
_, err := datawriter.WriteString(fmt.Sprintf("svc_waiting:%d\tqueue_len:%d", svcGrp.svcWaiting, svcGrp.queue.Len()))
if err != nil {
return err
}
if len(svcGrp.svcs) == 0 {
_, err := datawriter.WriteString("\n")
if err != nil {
return err
}
}
for addr, fnSvc := range svcGrp.svcs {
_, err := datawriter.WriteString(fmt.Sprintf("\tfunction_name:%s\tfn_svc_address:%s\tactive_req:%d\tcurrent_cpu_usage:%v\tcpu_limit:%v\n",
fnSvc.val.Function.Name, addr, fnSvc.activeRequests, fnSvc.currentCPUUsage, fnSvc.cpuLimit))
if err != nil {
return err
}
}
return nil
}
for _, fnSvcGrp := range c.cache {
err := writefnSvcGrp(fnSvcGrp)
if err != nil {
resp.error = err
break
}
}
err := datawriter.Flush()
if err != nil {
if resp.error == nil {
resp.error = err
} else {
resp.error = fmt.Errorf("%v, %v", resp.error, err)
}
}
req.responseChannel <- resp
default:
resp.error = ferror.MakeError(ferror.ErrorInvalidArgument,
fmt.Sprintf("invalid request type: %v", req.requestType))
req.responseChannel <- resp
}
}
}
// GetValue returns a function service with status in Active else return error
func (c *PoolCache) GetSvcValue(ctx context.Context, function string, requestsPerPod int, concurrency int) (*FuncSvc, error) {
respChannel := make(chan *response)
c.requestChannel <- &request{
ctx: ctx,
requestType: getValue,
function: function,
concurrency: concurrency,
requestsPerPod: requestsPerPod,
responseChannel: respChannel,
}
resp := <-respChannel
if resp.svcWaitValue != nil {
select {
case <-ctx.Done():
return resp.value, ctx.Err()
case funcSvc := <-resp.svcWaitValue.svcChannel:
return funcSvc, nil
}
}
return resp.value, resp.error
}
// ListAvailableValue returns a list of the available function services stored in the Cache
func (c *PoolCache) ListAvailableValue() []*FuncSvc {
respChannel := make(chan *response)
c.requestChannel <- &request{
requestType: listAvailableValue,
responseChannel: respChannel,
}
resp := <-respChannel
return resp.allValues
}
// SetValue marks the value at key [function][address] as active(begin used)
func (c *PoolCache) SetSvcValue(ctx context.Context, function, address string, value *FuncSvc, cpuLimit resource.Quantity, requestsPerPod int) {
respChannel := make(chan *response)
c.requestChannel <- &request{
ctx: ctx,
requestType: setValue,
function: function,
address: address,
value: value,
cpuUsage: cpuLimit,
requestsPerPod: requestsPerPod,
responseChannel: respChannel,
}
}
// SetCPUUtilization updates/sets the CPU utilization limit for the pod
func (c *PoolCache) SetCPUUtilization(function, address string, cpuUsage resource.Quantity) {
c.requestChannel <- &request{
requestType: setCPUUtilization,
function: function,
address: address,
cpuUsage: cpuUsage,
responseChannel: make(chan *response),
}
}
// MarkAvailable marks the value at key [function][address] as available
func (c *PoolCache) MarkAvailable(function, address string) {
respChannel := make(chan *response)
c.requestChannel <- &request{
requestType: markAvailable,
function: function,
address: address,
responseChannel: respChannel,
}
}
// DeleteValue deletes the value at key composed of [function][address]
func (c *PoolCache) DeleteValue(ctx context.Context, function, address string) error {
respChannel := make(chan *response)
c.requestChannel <- &request{
ctx: ctx,
requestType: deleteValue,
function: function,
address: address,
responseChannel: respChannel,
}
resp := <-respChannel
return resp.error
}
// ReduceSpecializationInProgress reduces the svcWaiting count
func (c *PoolCache) MarkSpecializationFailure(function string) {
c.requestChannel <- &request{
requestType: markSpecializationFailure,
function: function,
responseChannel: make(chan *response),
}
}
func (c *PoolCache) LogFnSvcGroup(ctx context.Context, file io.Writer) error {
respChannel := make(chan *response)
c.requestChannel <- &request{
requestType: logFuncSvc,
dumpWriter: file,
responseChannel: respChannel,
}
resp := <-respChannel
return resp.error
}
+200
View File
@@ -0,0 +1,200 @@
package fscache
import (
"context"
"fmt"
"log"
"net/http"
"sync"
"sync/atomic"
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/api/resource"
ferror "github.com/fission/fission/pkg/error"
"github.com/fission/fission/pkg/utils/loggerfactory"
)
func checkErr(err error) {
if err != nil {
log.Panicf("err: %v", err)
}
}
func TestPoolCache(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger := loggerfactory.GetLogger()
c := NewPoolCache(logger)
concurrency := 5
requestsPerPod := 2
// should return err since no svc is present
_, err := c.GetSvcValue(ctx, "func", requestsPerPod, concurrency)
if err == nil {
log.Panicf("found value when expected it to be nil")
}
c.SetSvcValue(ctx, "func", "ip", &FuncSvc{
Name: "value",
}, resource.MustParse("45m"), 10)
// should not return any error since we added a svc
_, err = c.GetSvcValue(ctx, "func", requestsPerPod, concurrency)
checkErr(err)
c.SetSvcValue(ctx, "func", "ip", &FuncSvc{
Name: "value",
}, resource.MustParse("45m"), 10)
// should return err since all functions are busy
_, err = c.GetSvcValue(ctx, "func", requestsPerPod, concurrency)
if err == nil {
log.Panicf("found value when expected it to be nil")
}
c.SetSvcValue(ctx, "func", "ip", &FuncSvc{
Name: "value",
}, resource.MustParse("45m"), 10)
c.SetSvcValue(ctx, "func2", "ip2", &FuncSvc{
Name: "value2",
}, resource.MustParse("50m"), 10)
c.SetSvcValue(ctx, "func2", "ip22", &FuncSvc{
Name: "value22",
}, resource.MustParse("33m"), 10)
checkErr(c.DeleteValue(ctx, "func2", "ip2"))
cc := c.ListAvailableValue()
if len(cc) != 0 {
log.Panicf("expected 0 available items")
}
c.MarkAvailable("func", "ip")
checkErr(c.DeleteValue(ctx, "func", "ip"))
_, err = c.GetSvcValue(ctx, "func", requestsPerPod, concurrency)
if err == nil {
log.Panicf("found deleted element")
}
c.SetSvcValue(ctx, "cpulimit", "100", &FuncSvc{
Name: "value",
}, resource.MustParse("3m"), 10)
c.SetCPUUtilization("cpulimit", "100", resource.MustParse("4m"))
}
func TestPoolCacheRequests(t *testing.T) {
type structForTest struct {
name string
requests int
concurrency int
rpp int
simultaneous int
failedRequests int
}
for _, tt := range []structForTest{
{
name: "test1",
requests: 1,
concurrency: 1,
rpp: 1,
},
{
name: "test2",
requests: 2,
concurrency: 2,
rpp: 1,
},
{
name: "test3",
requests: 300,
concurrency: 5,
rpp: 60,
},
{
name: "test4",
requests: 6,
concurrency: 1,
rpp: 5,
failedRequests: 1,
},
{
name: "test5",
requests: 6,
concurrency: 5,
rpp: 1,
failedRequests: 1,
},
{
name: "test6",
requests: 300,
concurrency: 5,
rpp: 60,
simultaneous: 30,
},
{
name: "test7",
requests: 310,
concurrency: 5,
rpp: 60,
simultaneous: 30,
failedRequests: 10,
},
{
name: "test8",
requests: 10,
concurrency: 10,
rpp: 1,
simultaneous: 10,
},
} {
t.Run(fmt.Sprintf("scenario-%s", tt.name), func(t *testing.T) {
var failedRequests, svcCounter uint64
p := NewPoolCache(loggerfactory.GetLogger())
wg := sync.WaitGroup{}
simultaneous := tt.simultaneous
if simultaneous == 0 {
simultaneous = 1
}
for i := 1; i <= tt.requests; i++ {
wg.Add(1)
go func(reqno int) {
defer wg.Done()
svc, err := p.GetSvcValue(context.Background(), "func", tt.rpp, tt.concurrency)
if err != nil {
code, _ := ferror.GetHTTPError(err)
if code == http.StatusNotFound {
p.SetSvcValue(context.Background(), "func", fmt.Sprintf("svc-%d", svcCounter), &FuncSvc{
Name: "value",
}, resource.MustParse("45m"), tt.rpp)
atomic.AddUint64(&svcCounter, 1)
} else {
t.Log(reqno, "=>", err)
atomic.AddUint64(&failedRequests, 1)
}
} else {
if svc == nil {
t.Log(reqno, "=>", "svc is nil")
atomic.AddUint64(&failedRequests, 1)
}
}
}(i)
if i%simultaneous == 0 {
wg.Wait()
}
}
wg.Wait()
require.Equal(t, tt.failedRequests, int(atomic.LoadUint64(&failedRequests)))
require.Equal(t, tt.concurrency, int(atomic.LoadUint64(&svcCounter)))
})
}
}
+70
View File
@@ -0,0 +1,70 @@
package fscache
import (
"container/list"
"sync"
)
type Queue struct {
items *list.List
mutex sync.Mutex
}
func NewQueue() *Queue {
return &Queue{
items: list.New(),
}
}
func (q *Queue) Push(item *svcWait) {
q.mutex.Lock()
defer q.mutex.Unlock()
q.items.PushBack(item)
}
func (q *Queue) Pop() *svcWait {
q.mutex.Lock()
defer q.mutex.Unlock()
item := q.items.Front()
if item == nil {
return nil
}
q.items.Remove(item)
svcWait, ok := item.Value.(*svcWait)
if !ok {
return nil
}
return svcWait
}
func (q *Queue) Expired() int {
q.mutex.Lock()
defer q.mutex.Unlock()
expired := 0
svcExpired := []*list.Element{}
for item := q.items.Front(); item != nil; item = item.Next() {
svcWait, ok := item.Value.(*svcWait)
if !ok {
continue
}
if svcWait.ctx.Err() != nil {
close(svcWait.svcChannel)
svcExpired = append(svcExpired, item)
expired = expired + 1
}
}
for _, item := range svcExpired {
q.items.Remove(item)
}
return expired
}
func (q *Queue) Len() int {
q.mutex.Lock()
defer q.mutex.Unlock()
return q.items.Len()
}
+191
View File
@@ -0,0 +1,191 @@
package fscache
import (
"context"
"sync"
"testing"
)
func TestNewQueue(t *testing.T) {
q := NewQueue()
if q == nil {
t.Error("NewQueue returned nil")
}
}
func TestQueuePushWithSingleRequest(t *testing.T) {
q := NewQueue()
item := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: nil,
}
q.Push(item)
if q.Len() != 1 {
t.Errorf("Expected queue length to be 1, got %d", q.Len())
}
}
func TestQueuePopWithSingleRequest(t *testing.T) {
q := NewQueue()
item := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: nil,
}
q.Push(item)
popped := q.Pop()
if popped == nil {
t.Error("Expected Pop to return a non-nil value")
}
if popped != item {
t.Error("Expected Pop to return the same element that was pushed")
}
if q.Len() != 0 {
t.Errorf("Expected queue length to be 0, got %d", q.Len())
}
}
func TestQueuePushWithConcurrentRequest(t *testing.T) {
q := NewQueue()
noOfRequests := 20
var wg sync.WaitGroup
wg.Add(noOfRequests)
for i := 0; i < noOfRequests; i++ {
go func() {
defer wg.Done()
item := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: nil,
}
q.Push(item)
}()
}
wg.Wait()
if q.Len() != noOfRequests {
t.Errorf("Expected queue length to be 20, got %d", q.Len())
}
}
func TestQueuePopWithConcurrentRequest(t *testing.T) {
q := NewQueue()
noOfPush := 20
noOfPop := 15
var wg sync.WaitGroup
wg.Add(noOfPush + noOfPop)
for i := 0; i < noOfPush; i++ {
go func() {
defer wg.Done()
item := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: nil,
}
q.Push(item)
}()
}
for i := 0; i < noOfPop; i++ {
go func() {
defer wg.Done()
q.Pop()
}()
}
wg.Wait()
if q.Len() != 5 {
t.Errorf("Expected queue length to be 5, got %d", q.Len())
}
}
func TestQueueLen(t *testing.T) {
q := NewQueue()
if q.Len() != 0 {
t.Errorf("Expected queue length to be 0, got %d", q.Len())
}
item := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: nil,
}
q.Push(item)
if q.Len() != 1 {
t.Errorf("Expected queue length to be 1, got %d", q.Len())
}
}
func TestExpiredWhenAllItemsExpired(t *testing.T) {
q := NewQueue()
if q.Expired() != 0 {
t.Errorf("Expected Expired to return 0, got %d", q.Expired())
}
ctx, cancel := context.WithCancel(context.Background())
item := &svcWait{
svcChannel: make(chan *FuncSvc),
ctx: ctx,
}
q.Push(item)
if q.Len() != 1 {
t.Errorf("Expected queue length to be 1, got %d", q.Len())
}
cancel()
if q.Expired() != 1 {
t.Errorf("Expected Expired to return 1, got %d", q.Expired())
}
if q.Len() != 0 {
t.Errorf("Expected queue length to be 0, got %d", q.Len())
}
}
func TestExpiredWhenFewItemsExpired(t *testing.T) {
q := NewQueue()
if q.Expired() != 0 {
t.Errorf("Expected Expired to return 0, got %d", q.Expired())
}
ctx, cancel := context.WithCancel(context.Background())
q.Push(&svcWait{
svcChannel: make(chan *FuncSvc),
ctx: ctx,
})
q.Push(&svcWait{
svcChannel: make(chan *FuncSvc),
ctx: context.Background(),
})
if q.Len() != 2 {
t.Errorf("Expected queue length to be 1, got %d", q.Len())
}
cancel()
if q.Expired() != 1 {
t.Errorf("Expected Expired to return 1, got %d", q.Expired())
}
if q.Len() != 1 {
t.Errorf("Expected queue length to be 0, got %d", q.Len())
}
}
func TestExpiredWhenNoItemsExpired(t *testing.T) {
q := NewQueue()
if q.Expired() != 0 {
t.Errorf("Expected Expired to return 0, got %d", q.Expired())
}
q.Push(&svcWait{
svcChannel: make(chan *FuncSvc),
ctx: context.Background(),
})
q.Push(&svcWait{
svcChannel: make(chan *FuncSvc),
ctx: context.Background(),
})
if q.Len() != 2 {
t.Errorf("Expected queue length to be 1, got %d", q.Len())
}
if q.Expired() != 0 {
t.Errorf("Expected Expired to return 1, got %d", q.Expired())
}
if q.Len() != 2 {
t.Errorf("Expected queue length to be 0, got %d", q.Len())
}
}
+2 -2
View File
@@ -41,7 +41,7 @@ var (
}, },
functionLabels, functionLabels,
) )
FuncError = prometheus.NewCounterVec( ColdStartsError = prometheus.NewCounterVec(
prometheus.CounterOpts{ prometheus.CounterOpts{
Name: "fission_function_cold_start_errors_total", Name: "fission_function_cold_start_errors_total",
Help: "Count of fission cold start errors", Help: "Count of fission cold start errors",
@@ -54,5 +54,5 @@ func init() {
registry := metrics.Registry registry := metrics.Registry
registry.MustRegister(ColdStarts) registry.MustRegister(ColdStarts)
registry.MustRegister(FuncRunningSummary) registry.MustRegister(FuncRunningSummary)
registry.MustRegister(FuncError) registry.MustRegister(ColdStartsError)
} }
+12
View File
@@ -35,6 +35,10 @@ import (
"github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils"
) )
const (
dumpFileName string = "fission-dump"
)
// ApplyImagePullSecret applies image pull secret to the give pod spec. // ApplyImagePullSecret applies image pull secret to the give pod spec.
// It's intentional not to check the existence of secret here. // It's intentional not to check the existence of secret here.
// First, Kubernetes will set Pod status to "ImagePullBackOff" once // First, Kubernetes will set Pod status to "ImagePullBackOff" once
@@ -152,3 +156,11 @@ func GetObjectReaperInterval(logger *zap.Logger, executorType fv1.ExecutorType,
func getExecutorEnvVarName(executor fv1.ExecutorType) string { func getExecutorEnvVarName(executor fv1.ExecutorType) string {
return strings.ToUpper(string(executor)) + "_OBJECT_REAPER_INTERVAL" return strings.ToUpper(string(executor)) + "_OBJECT_REAPER_INTERVAL"
} }
// CreateDumpFile => create dump file inside temp directory
func CreateDumpFile(logger *zap.Logger) (*os.File, error) {
dumpPath := os.TempDir()
logger.Info("creating dump file", zap.String("dump_path", dumpPath))
return os.Create(fmt.Sprintf("%s/%s-%d.txt", dumpPath, dumpFileName, time.Now().Unix()))
}
+1 -1
View File
@@ -100,7 +100,7 @@ func (opts *CreateSubCommand) run(input cli.Input) (err error) {
} }
specFile := fmt.Sprintf("env-%v.yaml", m.Name) specFile := fmt.Sprintf("env-%v.yaml", m.Name)
err = spec.SpecSave(*opts.env, specFile) err = spec.SpecSave(*opts.env, specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving environment spec") return errors.Wrap(err, "error saving environment spec")
} }
+14
View File
@@ -29,6 +29,7 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/console" "github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
@@ -78,7 +79,20 @@ func (opts *UpdateSubCommand) complete(input cli.Input) (err error) {
} }
func (opts *UpdateSubCommand) run(input cli.Input) error { func (opts *UpdateSubCommand) run(input cli.Input) error {
m := opts.env.ObjectMeta
if input.Bool(flagkey.SpecSave) {
err := opts.env.Validate()
if err != nil {
return fv1.AggregateValidationErrors("Environment", err)
}
specFile := fmt.Sprintf("env-%s.yaml", m.Name)
err = spec.SpecSave(*opts.env, specFile, true)
if err != nil {
return errors.Wrap(err, "error saving environment spec")
}
return nil
}
enew, err := opts.Client().FissionClientSet.CoreV1().Environments(opts.env.ObjectMeta.Namespace).Update(input.Context(), opts.env, metav1.UpdateOptions{}) enew, err := opts.Client().FissionClientSet.CoreV1().Environments(opts.env.ObjectMeta.Namespace).Update(input.Context(), opts.env, metav1.UpdateOptions{})
if err != nil { if err != nil {
return errors.Wrap(err, "error updating environment") return errors.Wrap(err, "error updating environment")
+1 -1
View File
@@ -363,7 +363,7 @@ func (opts *CreateSubCommand) run(input cli.Input) error {
} }
if input.Bool(flagkey.SpecSave) { if input.Bool(flagkey.SpecSave) {
err := spec.SpecSave(*opts.function, opts.specFile) err := spec.SpecSave(*opts.function, opts.specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving function spec") return errors.Wrap(err, "error saving function spec")
} }
@@ -226,7 +226,7 @@ func (opts *RunContainerSubCommand) run(input cli.Input) error {
} }
if input.Bool(flagkey.SpecSave) { if input.Bool(flagkey.SpecSave) {
err := spec.SpecSave(*opts.function, opts.specFile) err := spec.SpecSave(*opts.function, opts.specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving function spec") return errors.Wrap(err, "error saving function spec")
} }
+23 -6
View File
@@ -50,14 +50,19 @@ func Test(input cli.Input) error {
} }
func (opts *TestSubCommand) do(input cli.Input) error { func (opts *TestSubCommand) do(input cli.Input) error {
fnName := input.String(flagkey.FnName)
_, namespace, err := opts.GetResourceNamespace(input, flagkey.NamespaceFunction) _, namespace, err := opts.GetResourceNamespace(input, flagkey.NamespaceFunction)
if err != nil { if err != nil {
return errors.Wrap(err, "error in testing function ") return errors.Wrap(err, "error in testing function ")
} }
function, err := opts.Client().FissionClientSet.CoreV1().Functions(namespace).Get(input.Context(), fnName, metav1.GetOptions{})
if err != nil {
return errors.Wrap(err, fmt.Sprintf("read function '%s'", fnName))
}
m := &metav1.ObjectMeta{ m := &metav1.ObjectMeta{
Name: input.String(flagkey.FnName), Name: fnName,
Namespace: namespace, Namespace: namespace,
} }
routerURL := os.Getenv("FISSION_ROUTER") routerURL := os.Getenv("FISSION_ROUTER")
@@ -107,14 +112,26 @@ func (opts *TestSubCommand) do(input cli.Input) error {
functionUrl.RawQuery = query.Encode() functionUrl.RawQuery = query.Encode()
} }
var ctx context.Context var (
ctx context.Context
reqTimeout time.Duration
)
testTimeout := input.Duration(flagkey.FnTestTimeout) fnTestTimeout := input.Duration(flagkey.FnTestTimeout)
if testTimeout <= 0*time.Second { fnSpecTimeout := time.Duration(function.Spec.FunctionTimeout)
if input.IsSet(flagkey.FnTestTimeout) && (fnTestTimeout < fnSpecTimeout) {
reqTimeout = fnTestTimeout
console.Warn(fmt.Sprintf("timeout specified is less than functionTimeout %d Overriding value to %d", fnTestTimeout, fnSpecTimeout))
} else {
reqTimeout = fnSpecTimeout
}
if reqTimeout <= 0*time.Second {
ctx = input.Context() ctx = input.Context()
} else { } else {
var closeCtx context.CancelFunc var closeCtx context.CancelFunc
ctx, closeCtx = context.WithTimeout(input.Context(), input.Duration(flagkey.FnTestTimeout)) ctx, closeCtx = context.WithTimeout(input.Context(), reqTimeout*time.Second)
defer closeCtx() defer closeCtx()
} }
+17 -1
View File
@@ -27,6 +27,7 @@ import (
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/cmd"
_package "github.com/fission/fission/pkg/fission-cli/cmd/package" _package "github.com/fission/fission/pkg/fission-cli/cmd/package"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/console" "github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
@@ -35,6 +36,7 @@ import (
type UpdateSubCommand struct { type UpdateSubCommand struct {
cmd.CommandActioner cmd.CommandActioner
function *fv1.Function function *fv1.Function
specFile string
} }
func Update(input cli.Input) error { func Update(input cli.Input) error {
@@ -55,6 +57,9 @@ func (opts *UpdateSubCommand) complete(input cli.Input) error {
if err != nil { if err != nil {
return errors.Wrap(err, "error in updating function ") return errors.Wrap(err, "error in updating function ")
} }
if input.Bool(flagkey.SpecSave) {
opts.specFile = fmt.Sprintf("function-%s.yaml", fnName)
}
function, err := opts.Client().FissionClientSet.CoreV1().Functions(fnNamespace).Get(input.Context(), input.String(flagkey.FnName), metav1.GetOptions{}) function, err := opts.Client().FissionClientSet.CoreV1().Functions(fnNamespace).Get(input.Context(), input.String(flagkey.FnName), metav1.GetOptions{})
if err != nil { if err != nil {
@@ -193,7 +198,7 @@ func (opts *UpdateSubCommand) complete(input cli.Input) error {
return errors.Errorf("Package is used by multiple functions, use --%v to force update", flagkey.PkgForce) return errors.Errorf("Package is used by multiple functions, use --%v to force update", flagkey.PkgForce)
} }
newPkgMeta, err := _package.UpdatePackage(input, opts.Client(), pkg) newPkgMeta, err := _package.UpdatePackage(input, opts.Client(), opts.specFile, pkg)
if err != nil { if err != nil {
return errors.Wrap(err, fmt.Sprintf("error updating package '%v'", pkgName)) return errors.Wrap(err, fmt.Sprintf("error updating package '%v'", pkgName))
} }
@@ -243,6 +248,17 @@ func (opts *UpdateSubCommand) complete(input cli.Input) error {
} }
func (opts *UpdateSubCommand) run(input cli.Input) error { func (opts *UpdateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) {
err := opts.function.Validate()
if err != nil {
return fv1.AggregateValidationErrors("Function", err)
}
err = spec.SpecSave(*opts.function, opts.specFile, false)
if err != nil {
return errors.Wrap(err, "error saving function spec")
}
return nil
}
_, err := opts.Client().FissionClientSet.CoreV1().Functions(opts.function.Namespace).Update(input.Context(), opts.function, metav1.UpdateOptions{}) _, err := opts.Client().FissionClientSet.CoreV1().Functions(opts.function.Namespace).Update(input.Context(), opts.function, metav1.UpdateOptions{})
if err != nil { if err != nil {
return errors.Wrap(err, "error updating function") return errors.Wrap(err, "error updating function")
+1 -1
View File
@@ -219,7 +219,7 @@ func (opts *CreateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) { if input.Bool(flagkey.SpecSave) {
specFile := fmt.Sprintf("route-%v.yaml", opts.trigger.ObjectMeta.Name) specFile := fmt.Sprintf("route-%v.yaml", opts.trigger.ObjectMeta.Name)
err := spec.SpecSave(*opts.trigger, specFile) err := spec.SpecSave(*opts.trigger, specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving HTTP trigger spec") return errors.Wrap(err, "error saving HTTP trigger spec")
} }
+13 -1
View File
@@ -26,6 +26,7 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/console" "github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
@@ -148,7 +149,18 @@ func (opts *UpdateSubCommand) complete(input cli.Input) (err error) {
} }
func (opts *UpdateSubCommand) run(input cli.Input) error { func (opts *UpdateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) {
err := opts.trigger.Validate()
if err != nil {
return fv1.AggregateValidationErrors("HTTPTrigger", err)
}
specFile := fmt.Sprintf("route-%s.yaml", opts.trigger.ObjectMeta.Name)
err = spec.SpecSave(*opts.trigger, specFile, true)
if err != nil {
return errors.Wrap(err, "error saving HTTP trigger spec")
}
return nil
}
err := util.CheckHTTPTriggerDuplicates(input.Context(), opts.Client(), opts.trigger) err := util.CheckHTTPTriggerDuplicates(input.Context(), opts.Client(), opts.trigger)
if err != nil { if err != nil {
return errors.Wrap(err, "Error while creating HTTP Trigger") return errors.Wrap(err, "Error while creating HTTP Trigger")
+1 -1
View File
@@ -119,7 +119,7 @@ func (opts *CreateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) { if input.Bool(flagkey.SpecSave) {
specFile := fmt.Sprintf("kubewatch-%v.yaml", opts.watcher.ObjectMeta.Name) specFile := fmt.Sprintf("kubewatch-%v.yaml", opts.watcher.ObjectMeta.Name)
err := spec.SpecSave(*opts.watcher, specFile) err := spec.SpecSave(*opts.watcher, specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving kubewatch spec") return errors.Wrap(err, "error saving kubewatch spec")
} }
+1 -1
View File
@@ -203,7 +203,7 @@ func (opts *CreateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) { if input.Bool(flagkey.SpecSave) {
specFile := fmt.Sprintf("mqtrigger-%v.yaml", opts.trigger.ObjectMeta.Name) specFile := fmt.Sprintf("mqtrigger-%v.yaml", opts.trigger.ObjectMeta.Name)
err := spec.SpecSave(*opts.trigger, specFile) err := spec.SpecSave(*opts.trigger, specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving message queue trigger spec") return errors.Wrap(err, "error saving message queue trigger spec")
} }
+13
View File
@@ -25,6 +25,7 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/console" "github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
@@ -148,6 +149,18 @@ func (opts *UpdateSubCommand) complete(input cli.Input) (err error) {
} }
func (opts *UpdateSubCommand) run(input cli.Input) error { func (opts *UpdateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) {
err := opts.trigger.Validate()
if err != nil {
return fv1.AggregateValidationErrors("MessageQueueTrigger", err)
}
specFile := fmt.Sprintf("mqtrigger-%s.yaml", opts.trigger.ObjectMeta.Name)
err = spec.SpecSave(*opts.trigger, specFile, true)
if err != nil {
return errors.Wrap(err, "error saving message queue trigger spec")
}
return nil
}
_, err := opts.Client().FissionClientSet.CoreV1().MessageQueueTriggers(opts.trigger.ObjectMeta.Namespace).Update(input.Context(), opts.trigger, metav1.UpdateOptions{}) _, err := opts.Client().FissionClientSet.CoreV1().MessageQueueTriggers(opts.trigger.ObjectMeta.Namespace).Update(input.Context(), opts.trigger, metav1.UpdateOptions{})
if err != nil { if err != nil {
return errors.Wrap(err, "error updating message queue trigger") return errors.Wrap(err, "error updating message queue trigger")
+1 -1
View File
@@ -216,7 +216,7 @@ func CreatePackage(input cli.Input, client cmd.Client, pkgName string, pkgNamesp
return &pkg.ObjectMeta, nil return &pkg.ObjectMeta, nil
} }
err = spec.SpecSave(*pkg, specFile) err = spec.SpecSave(*pkg, specFile, false)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error saving package spec") return nil, errors.Wrap(err, "error saving package spec")
} }
+1 -1
View File
@@ -174,7 +174,7 @@ func CreateArchive(client cmd.Client, input cli.Input, includeFiles []string, no
aus.Name = oldAus.Name aus.Name = oldAus.Name
} else { } else {
// save the uploadspec // save the uploadspec
err := spec.SpecSave(*aus, specFile) err := spec.SpecSave(*aus, specFile, false)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error saving archive spec") return nil, errors.Wrap(err, "error saving archive spec")
} }
+27 -3
View File
@@ -28,7 +28,9 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
) )
type UpdateSubCommand struct { type UpdateSubCommand struct {
@@ -61,6 +63,7 @@ func (opts *UpdateSubCommand) complete(input cli.Input) (err error) {
} }
func (opts *UpdateSubCommand) run(input cli.Input) error { func (opts *UpdateSubCommand) run(input cli.Input) error {
pkgName := input.String(flagkey.PkgName)
pkg, err := opts.Client().FissionClientSet.CoreV1().Packages(opts.pkgNamespace).Get(input.Context(), opts.pkgName, metav1.GetOptions{}) pkg, err := opts.Client().FissionClientSet.CoreV1().Packages(opts.pkgNamespace).Get(input.Context(), opts.pkgName, metav1.GetOptions{})
if err != nil { if err != nil {
return err return err
@@ -79,8 +82,8 @@ func (opts *UpdateSubCommand) run(input cli.Input) error {
if !forceUpdate && len(fnList) > 1 { if !forceUpdate && len(fnList) > 1 {
return errors.Errorf("package is used by multiple functions, use --%v to force update", flagkey.PkgForce) return errors.Errorf("package is used by multiple functions, use --%v to force update", flagkey.PkgForce)
} }
specFile := fmt.Sprintf("package-%s.yaml", pkgName)
newPkgMeta, err := UpdatePackage(input, opts.Client(), pkg) newPkgMeta, err := UpdatePackage(input, opts.Client(), specFile, pkg)
if err != nil { if err != nil {
return errors.Wrap(err, "error updating package") return errors.Wrap(err, "error updating package")
} }
@@ -95,7 +98,7 @@ func (opts *UpdateSubCommand) run(input cli.Input) error {
return nil return nil
} }
func UpdatePackage(input cli.Input, client cmd.Client, pkg *fv1.Package) (*metav1.ObjectMeta, error) { func UpdatePackage(input cli.Input, client cmd.Client, specFile string, pkg *fv1.Package) (*metav1.ObjectMeta, error) {
envName := input.String(flagkey.PkgEnvironment) envName := input.String(flagkey.PkgEnvironment)
srcArchiveFiles := input.StringSlice(flagkey.PkgSrcArchive) srcArchiveFiles := input.StringSlice(flagkey.PkgSrcArchive)
deployArchiveFiles := input.StringSlice(flagkey.PkgDeployArchive) deployArchiveFiles := input.StringSlice(flagkey.PkgDeployArchive)
@@ -174,6 +177,27 @@ func UpdatePackage(input cli.Input, client cmd.Client, pkg *fv1.Package) (*metav
} }
} }
if input.Bool(flagkey.SpecSave) {
// if a package with the same spec exists, don't create a new spec file
fr, err := spec.ReadSpecs(util.GetSpecDir(input), util.GetSpecIgnore(input), false)
if err != nil {
return nil, errors.Wrap(err, "error reading specs")
}
obj := fr.SpecExists(pkg, true, true)
if obj != nil {
pkg := obj.(*fv1.Package)
fmt.Printf("Re-using previously created package %s\n", pkg.ObjectMeta.Name)
return &pkg.ObjectMeta, nil
}
err = spec.SpecSave(*pkg, specFile, true)
if err != nil {
return nil, errors.Wrap(err, "error saving package spec")
}
return &pkg.ObjectMeta, nil
}
newPkgMeta, err := client.FissionClientSet.CoreV1().Packages(pkg.ObjectMeta.Namespace).Update(input.Context(), pkg, metav1.UpdateOptions{}) newPkgMeta, err := client.FissionClientSet.CoreV1().Packages(pkg.ObjectMeta.Namespace).Update(input.Context(), pkg, metav1.UpdateOptions{})
if err != nil { if err != nil {
return nil, errors.Wrap(err, "update package") return nil, errors.Wrap(err, "update package")
+22 -7
View File
@@ -127,7 +127,7 @@ func MapKey(m *metav1.ObjectMeta) string {
} }
// save saves object encoded value to spec file under given spec directory // save saves object encoded value to spec file under given spec directory
func save(data []byte, specDir string, specFile string) error { func save(data []byte, specDir string, specFile string, truncate bool) error {
// verify // verify
if _, err := os.Stat(filepath.Join(specDir, "fission-deployment-config.yaml")); os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(specDir, "fission-deployment-config.yaml")); os.IsNotExist(err) {
return errors.Wrap(err, "Couldn't find specs, run `fission spec init` first") return errors.Wrap(err, "Couldn't find specs, run `fission spec init` first")
@@ -137,6 +137,9 @@ func save(data []byte, specDir string, specFile string) error {
// check if the file is new // check if the file is new
newFile := false newFile := false
if _, err := os.Stat(filename); os.IsNotExist(err) { if _, err := os.Stat(filename); os.IsNotExist(err) {
if truncate {
return errors.Errorf("spec file does not exists")
}
newFile = true newFile = true
} }
@@ -147,11 +150,19 @@ func save(data []byte, specDir string, specFile string) error {
} }
defer f.Close() defer f.Close()
// if we're appending, add a yaml document separator if truncate {
if !newFile { err = f.Truncate(0)
_, err = f.Write([]byte("\n---\n"))
if err != nil { if err != nil {
return errors.Wrap(err, "couldn't write to spec file") return errors.Wrap(err, "couldn't truncate the spec file")
}
} else {
// if we're appending, add a yaml document separator
if !newFile {
_, err = f.Write([]byte("\n---\n"))
if err != nil {
return errors.Wrap(err, "couldn't write to spec file")
}
} }
} }
@@ -164,7 +175,7 @@ func save(data []byte, specDir string, specFile string) error {
} }
// called from `fission * create --spec` // called from `fission * create --spec`
func SpecSave(resource interface{}, specFile string) error { func SpecSave(resource interface{}, specFile string, update bool) error {
var specDir = "specs" var specDir = "specs"
meta, kind, data, err := crdToYaml(resource) meta, kind, data, err := crdToYaml(resource)
@@ -186,7 +197,11 @@ func SpecSave(resource interface{}, specFile string) error {
return errors.Errorf("same name resource (%v) already exists in namespace (%v)", meta.Name, meta.Namespace) return errors.Errorf("same name resource (%v) already exists in namespace (%v)", meta.Name, meta.Namespace)
} }
err = save(data, specDir, specFile) truncate := false
if update {
truncate = true
}
err = save(data, specDir, specFile, truncate)
if err != nil { if err != nil {
return err return err
} }
+1 -1
View File
@@ -135,7 +135,7 @@ func (opts *CreateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) { if input.Bool(flagkey.SpecSave) {
specFile := fmt.Sprintf("timetrigger-%v.yaml", opts.trigger.ObjectMeta.Name) specFile := fmt.Sprintf("timetrigger-%v.yaml", opts.trigger.ObjectMeta.Name)
err := spec.SpecSave(*opts.trigger, specFile) err := spec.SpecSave(*opts.trigger, specFile, false)
if err != nil { if err != nil {
return errors.Wrap(err, "error saving time trigger spec") return errors.Wrap(err, "error saving time trigger spec")
} }
+13
View File
@@ -25,6 +25,7 @@ import (
fv1 "github.com/fission/fission/pkg/apis/core/v1" fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli" "github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd" "github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/cmd/spec"
"github.com/fission/fission/pkg/fission-cli/console" "github.com/fission/fission/pkg/fission-cli/console"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key" flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util" "github.com/fission/fission/pkg/fission-cli/util"
@@ -86,6 +87,18 @@ func (opts *UpdateSubCommand) complete(input cli.Input) error {
} }
func (opts *UpdateSubCommand) run(input cli.Input) error { func (opts *UpdateSubCommand) run(input cli.Input) error {
if input.Bool(flagkey.SpecSave) {
err := opts.trigger.Validate()
if err != nil {
return fv1.AggregateValidationErrors("TimeTrigger", err)
}
specFile := fmt.Sprintf("timetrigger-%s.yaml", opts.trigger.ObjectMeta.Name)
err = spec.SpecSave(*opts.trigger, specFile, true)
if err != nil {
return errors.Wrap(err, "error saving time trigger spec")
}
return nil
}
_, err := opts.Client().FissionClientSet.CoreV1().TimeTriggers(opts.trigger.ObjectMeta.Namespace).Update(input.Context(), opts.trigger, metav1.UpdateOptions{}) _, err := opts.Client().FissionClientSet.CoreV1().TimeTriggers(opts.trigger.ObjectMeta.Namespace).Update(input.Context(), opts.trigger, metav1.UpdateOptions{})
if err != nil { if err != nil {
return errors.Wrap(err, "error updating Time trigger") return errors.Wrap(err, "error updating Time trigger")
+2 -2
View File
@@ -133,7 +133,7 @@ var (
FnSubPath = Flag{Type: String, Name: flagkey.FnSubPath, Usage: "Sub Path to check if function internally supports routing"} FnSubPath = Flag{Type: String, Name: flagkey.FnSubPath, Usage: "Sub Path to check if function internally supports routing"}
FnLogAllPods = Flag{Type: Bool, Name: flagkey.FnLogAllPods, Usage: "Get all pod's logs in the function."} FnLogAllPods = Flag{Type: Bool, Name: flagkey.FnLogAllPods, Usage: "Get all pod's logs in the function."}
// Termination Grace Period configurable at function creation/update only for container functions // Termination Grace Period configurable at function creation/update only for container functions
FnTerminationGracePeriod = Flag{Type: Int64, Name: flagkey.FnGracePeriod, Usage: "Grace time (in seconds) for pod to perform connection draining before termination (default value will be used if negative value is given)", DefaultValue: 360} FnTerminationGracePeriod = Flag{Type: Int64, Name: flagkey.FnGracePeriod, Usage: "Grace time (in seconds) for pod to perform connection draining before termination (only non-negative values considered)", DefaultValue: 360}
HtName = Flag{Type: String, Name: flagkey.HtName, Usage: "HTTP trigger name"} HtName = Flag{Type: String, Name: flagkey.HtName, Usage: "HTTP trigger name"}
HtMethod = Flag{Type: StringSlice, Name: flagkey.HtMethod, Usage: "HTTP Methods: GET,POST,PUT,DELETE,HEAD. To mention single method: --method GET and for multiple methods --method GET --method POST. [DEPRECATED for 'fn create', use 'route create' instead]", DefaultValue: []string{http.MethodGet}} HtMethod = Flag{Type: StringSlice, Name: flagkey.HtMethod, Usage: "HTTP Methods: GET,POST,PUT,DELETE,HEAD. To mention single method: --method GET and for multiple methods --method GET --method POST. [DEPRECATED for 'fn create', use 'route create' instead]", DefaultValue: []string{http.MethodGet}}
@@ -181,7 +181,7 @@ var (
EnvBuildCmd = Flag{Type: String, Name: flagkey.EnvBuildcommand, Usage: "Build command for environment builder to build source package"} EnvBuildCmd = Flag{Type: String, Name: flagkey.EnvBuildcommand, Usage: "Build command for environment builder to build source package"}
EnvKeepArchive = Flag{Type: Bool, Name: flagkey.EnvKeeparchive, Usage: "Keep the archive instead of extracting it into a directory (mainly for the JVM environment because .jar is one kind of zip archive)"} EnvKeepArchive = Flag{Type: Bool, Name: flagkey.EnvKeeparchive, Usage: "Keep the archive instead of extracting it into a directory (mainly for the JVM environment because .jar is one kind of zip archive)"}
EnvExternalNetwork = Flag{Type: Bool, Name: flagkey.EnvExternalNetwork, Usage: "Allow pod to access external network (only works when istio feature is enabled)"} EnvExternalNetwork = Flag{Type: Bool, Name: flagkey.EnvExternalNetwork, Usage: "Allow pod to access external network (only works when istio feature is enabled)"}
EnvTerminationGracePeriod = Flag{Type: Int64, Name: flagkey.EnvGracePeriod, Aliases: []string{"period"}, Usage: "Grace time (in seconds) for pod to perform connection draining before termination (default value will be used if 0 is given)", DefaultValue: 360} EnvTerminationGracePeriod = Flag{Type: Int64, Name: flagkey.EnvGracePeriod, Aliases: []string{"period"}, Usage: "Grace time (in seconds) for pod to perform connection draining before termination (only non-negative values considered)", DefaultValue: 360}
EnvVersion = Flag{Type: Int, Name: flagkey.EnvVersion, Usage: "Environment API version (1 means v1 interface)", DefaultValue: 1} EnvVersion = Flag{Type: Int, Name: flagkey.EnvVersion, Usage: "Environment API version (1 means v1 interface)", DefaultValue: 1}
EnvImagePullSecret = Flag{Type: String, Name: flagkey.EnvImagePullSecret, Usage: "Secret for Kubernetes to pull an image from a private registry"} EnvImagePullSecret = Flag{Type: String, Name: flagkey.EnvImagePullSecret, Usage: "Secret for Kubernetes to pull an image from a private registry"}
EnvExecutorType = Flag{Type: String, Name: flagkey.EnvExecutorType, Usage: "Executor type of pod in environment; one of 'poolmgr', 'newdeploy', 'container'"} EnvExecutorType = Flag{Type: String, Name: flagkey.EnvExecutorType, Usage: "Executor type of pod in environment; one of 'poolmgr', 'newdeploy', 'container'"}
+29 -6
View File
@@ -50,8 +50,17 @@ import (
"github.com/fission/fission/pkg/utils" "github.com/fission/fission/pkg/utils"
) )
const (
ENV_FISSION_NAMESPACE string = "FISSION_NAMESPACE"
ENV_FISSION_URL string = "FISSION_URL"
ENV_FISSION_AUTH_TOKEN string = "FISSION_AUTH_TOKEN"
localhostURL string = "http://127.0.0.1:"
authHeader string = "Authorization"
tokenType string = "Bearer"
)
func GetFissionNamespace() string { func GetFissionNamespace() string {
fissionNamespace := os.Getenv("FISSION_NAMESPACE") fissionNamespace := os.Getenv(ENV_FISSION_NAMESPACE)
return fissionNamespace return fissionNamespace
} }
@@ -68,14 +77,14 @@ func ResolveFunctionNS(namespace string) string {
func GetApplicationUrl(ctx context.Context, client cmd.Client, selector string) (string, error) { func GetApplicationUrl(ctx context.Context, client cmd.Client, selector string) (string, error) {
var serverUrl string var serverUrl string
// Use FISSION_URL env variable if set; otherwise, port-forward to controller. // Use FISSION_URL env variable if set; otherwise, port-forward to controller.
fissionUrl := os.Getenv("FISSION_URL") fissionUrl := os.Getenv(ENV_FISSION_URL)
if len(fissionUrl) == 0 { if len(fissionUrl) == 0 {
fissionNamespace := GetFissionNamespace() fissionNamespace := GetFissionNamespace()
localPort, err := SetupPortForward(ctx, client, fissionNamespace, selector) localPort, err := SetupPortForward(ctx, client, fissionNamespace, selector)
if err != nil { if err != nil {
return "", err return "", err
} }
serverUrl = "http://127.0.0.1:" + localPort serverUrl = fmt.Sprintf("%s%s", localhostURL, localPort)
} else { } else {
serverUrl = fissionUrl serverUrl = fissionUrl
} }
@@ -167,13 +176,27 @@ func GetServerInfo(input cli.Input, cmdClient cmd.Client) *info.ServerInfo {
return &serverInfo return &serverInfo
} }
// make request // make request
resp, err := http.Get(serverURL.String() + "/_version") req, err := http.NewRequestWithContext(input.Context(), "GET", fmt.Sprintf("%s%s", serverURL.String(), "/_version"), nil)
if err != nil {
console.Warn("could not create http request")
return &serverInfo
}
req.Header.Add(authHeader, fmt.Sprintf("%s %s", tokenType, os.Getenv(ENV_FISSION_AUTH_TOKEN)))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil { if err != nil {
console.Warn("could not get data from server") console.Warn("could not get data from server")
return &serverInfo return &serverInfo
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusUnauthorized {
// display user a warning message to set environment variable FISSION_AUTH_TOKEN
if len(os.Getenv(ENV_FISSION_AUTH_TOKEN)) <= 0 {
console.Warn(fmt.Sprintf("Please consider setting %s as environment variable, if authentication is enabled", ENV_FISSION_AUTH_TOKEN))
}
}
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
msg := fmt.Sprintf("HTTP error %v", resp.StatusCode) msg := fmt.Sprintf("HTTP error %v", resp.StatusCode)
console.Warn(msg) console.Warn(msg)
@@ -196,7 +219,7 @@ func getRouterURL(ctx context.Context, cmdClient cmd.Client) (serverURL *url.URL
return serverURL, err return serverURL, err
} }
serverURL, err = url.Parse("http://127.0.0.1:" + localRouterPort) serverURL, err = url.Parse(fmt.Sprintf("%s%s", localhostURL, localRouterPort))
if err != nil { if err != nil {
return serverURL, err return serverURL, err
} }
@@ -445,7 +468,7 @@ func GetStorageURL(ctx context.Context, client cmd.Client) (*url.URL, error) {
return nil, err return nil, err
} }
serverURL, err := url.Parse("http://127.0.0.1:" + storageLocalPort) serverURL, err := url.Parse(fmt.Sprintf("%s%s", localhostURL, storageLocalPort))
if err != nil { if err != nil {
return nil, err return nil, err
} }
+1 -1
View File
@@ -268,7 +268,7 @@ func (ws *watchSubscription) eventDispatchLoop(ctx context.Context) {
// the triggers can only be created in the same namespace as the function. // the triggers can only be created in the same namespace as the function.
// so essentially, function namespace = trigger namespace. // so essentially, function namespace = trigger namespace.
url := utils.UrlForFunction(ws.watch.Spec.FunctionReference.Name, ws.watch.ObjectMeta.Namespace) url := utils.UrlForFunction(ws.watch.Spec.FunctionReference.Name, ws.watch.ObjectMeta.Namespace)
ws.publisher.Publish(buf.String(), headers, url) ws.publisher.Publish(ctx, buf.String(), headers, url)
} }
} }
-252
View File
@@ -1,252 +0,0 @@
/*
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 poolcache implements a simple cache implementation having values mapped by two keys.
// As of now this package is only used by poolmanager executor
package poolcache
import (
"context"
"fmt"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/api/resource"
ferror "github.com/fission/fission/pkg/error"
otelUtils "github.com/fission/fission/pkg/utils/otel"
)
type requestType int
const (
getValue requestType = iota
listAvailableValue
setValue
markAvailable
deleteValue
setCPUUtilization
)
type (
// value used as "value" in cache
value struct {
val interface{}
activeRequests int // number of requests served by function pod
currentCPUUsage resource.Quantity // current cpu usage of the specialized function pod
cpuLimit resource.Quantity // if currentCPUUsage is more than cpuLimit cache miss occurs in getValue request
}
// Cache is simple cache having two keys [function][address] mapped to value and requestChannel for operation on it
Cache struct {
cache map[interface{}]map[interface{}]*value
requestChannel chan *request
logger *zap.Logger
}
request struct {
requestType
ctx context.Context
function interface{}
address interface{}
value interface{}
requestsPerPod int
cpuUsage resource.Quantity
responseChannel chan *response
}
response struct {
error
allValues []interface{}
value interface{}
totalActive int
}
)
// NewPoolCache create a Cache object
func NewPoolCache(logger *zap.Logger) *Cache {
c := &Cache{
cache: make(map[interface{}]map[interface{}]*value),
requestChannel: make(chan *request),
logger: logger,
}
go c.service()
return c
}
func (c *Cache) service() {
for {
req := <-c.requestChannel
resp := &response{}
switch req.requestType {
case getValue:
values, ok := c.cache[req.function]
found := false
if !ok {
resp.error = ferror.MakeError(ferror.ErrorNotFound,
fmt.Sprintf("function Name '%v' not found", req.function))
} else {
for addr := range values {
if values[addr].activeRequests < req.requestsPerPod && values[addr].currentCPUUsage.Cmp(values[addr].cpuLimit) < 1 {
// mark active
values[addr].activeRequests++
if c.logger.Core().Enabled(zap.DebugLevel) {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Increase active requests with getValue", zap.String("function", req.function.(string)), zap.String("address", addr.(string)), zap.Int("activeRequests", values[addr].activeRequests))
}
resp.value = values[addr].val
found = true
break
}
}
if !found {
resp.error = ferror.MakeError(ferror.ErrorNotFound, fmt.Sprintf("function '%v' all functions are busy", req.function))
}
resp.totalActive = len(values)
}
req.responseChannel <- resp
case setValue:
if _, ok := c.cache[req.function]; !ok {
c.cache[req.function] = make(map[interface{}]*value)
}
if _, ok := c.cache[req.function][req.address]; !ok {
c.cache[req.function][req.address] = &value{}
}
c.cache[req.function][req.address].val = req.value
c.cache[req.function][req.address].activeRequests++
if c.logger.Core().Enabled(zap.DebugLevel) {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Increase active requests with setValue", zap.String("function", req.function.(string)), zap.String("address", req.address.(string)), zap.Int("activeRequests", c.cache[req.function][req.address].activeRequests))
}
c.cache[req.function][req.address].cpuLimit = req.cpuUsage
case listAvailableValue:
vals := make([]interface{}, 0)
for key1, values := range c.cache {
for key2, value := range values {
debugLevel := c.logger.Core().Enabled(zap.DebugLevel)
if debugLevel {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Reading active requests", zap.String("function", key1.(string)), zap.String("address", key2.(string)), zap.Int("activeRequests", value.activeRequests))
}
if value.activeRequests == 0 {
if debugLevel {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Function service with no active requests", zap.String("function", key1.(string)), zap.String("address", key2.(string)), zap.Int("activeRequests", value.activeRequests))
}
vals = append(vals, value.val)
}
}
}
resp.allValues = vals
req.responseChannel <- resp
case setCPUUtilization:
if _, ok := c.cache[req.function]; !ok {
c.cache[req.function] = make(map[interface{}]*value)
}
if _, ok := c.cache[req.function][req.address]; ok {
c.cache[req.function][req.address].currentCPUUsage = req.cpuUsage
}
case markAvailable:
if _, ok := c.cache[req.function]; ok {
if _, ok = c.cache[req.function][req.address]; ok {
if c.cache[req.function][req.address].activeRequests > 0 {
c.cache[req.function][req.address].activeRequests--
if c.logger.Core().Enabled(zap.DebugLevel) {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Debug("Decrease active requests", zap.String("function", req.function.(string)), zap.String("address", req.address.(string)), zap.Int("activeRequests", c.cache[req.function][req.address].activeRequests))
}
} else {
otelUtils.LoggerWithTraceID(req.ctx, c.logger).Error("Invalid request to decrease active requests", zap.String("function", req.function.(string)), zap.String("address", req.address.(string)), zap.Int("activeRequests", c.cache[req.function][req.address].activeRequests))
}
}
}
case deleteValue:
delete(c.cache[req.function], req.address)
req.responseChannel <- resp
default:
resp.error = ferror.MakeError(ferror.ErrorInvalidArgument,
fmt.Sprintf("invalid request type: %v", req.requestType))
req.responseChannel <- resp
}
}
}
// GetValue returns a value interface with status inActive else return error
func (c *Cache) GetValue(ctx context.Context, function interface{}, requestsPerPod int) (interface{}, int, error) {
respChannel := make(chan *response)
c.requestChannel <- &request{
ctx: ctx,
requestType: getValue,
function: function,
requestsPerPod: requestsPerPod,
responseChannel: respChannel,
}
resp := <-respChannel
return resp.value, resp.totalActive, resp.error
}
// ListAvailableValue returns a list of the available function services stored in the Cache
func (c *Cache) ListAvailableValue() []interface{} {
respChannel := make(chan *response)
c.requestChannel <- &request{
requestType: listAvailableValue,
responseChannel: respChannel,
}
resp := <-respChannel
return resp.allValues
}
// SetValue marks the value at key [function][address] as active(begin used)
func (c *Cache) SetValue(ctx context.Context, function, address, value interface{}, cpuLimit resource.Quantity) {
respChannel := make(chan *response)
c.requestChannel <- &request{
ctx: ctx,
requestType: setValue,
function: function,
address: address,
value: value,
cpuUsage: cpuLimit,
responseChannel: respChannel,
}
}
// SetCPUUtilization updates/sets the CPU utilization limit for the pod
func (c *Cache) SetCPUUtilization(function, address interface{}, cpuUsage resource.Quantity) {
c.requestChannel <- &request{
requestType: setCPUUtilization,
function: function,
address: address,
cpuUsage: cpuUsage,
responseChannel: make(chan *response),
}
}
// MarkAvailable marks the value at key [function][address] as available
func (c *Cache) MarkAvailable(function, address interface{}) {
respChannel := make(chan *response)
c.requestChannel <- &request{
requestType: markAvailable,
function: function,
address: address,
responseChannel: respChannel,
}
}
// DeleteValue deletes the value at key composed of [function][address]
func (c *Cache) DeleteValue(ctx context.Context, function, address interface{}) error {
respChannel := make(chan *response)
c.requestChannel <- &request{
ctx: ctx,
requestType: deleteValue,
function: function,
address: address,
responseChannel: respChannel,
}
resp := <-respChannel
return resp.error
}
-64
View File
@@ -1,64 +0,0 @@
package poolcache
import (
"context"
"log"
"testing"
"k8s.io/apimachinery/pkg/api/resource"
"github.com/fission/fission/pkg/utils/loggerfactory"
)
func checkErr(err error) {
if err != nil {
log.Panicf("err: %v", err)
}
}
func TestPoolCache(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
logger := loggerfactory.GetLogger()
c := NewPoolCache(logger)
c.SetValue(ctx, "func", "ip", "value", resource.MustParse("45m"))
c.SetValue(ctx, "func2", "ip2", "value2", resource.MustParse("50m"))
c.SetValue(ctx, "func2", "ip22", "value22", resource.MustParse("33m"))
checkErr(c.DeleteValue(ctx, "func2", "ip2"))
cc := c.ListAvailableValue()
if len(cc) != 0 {
log.Panicf("expected 0 available items")
}
c.MarkAvailable("func", "ip")
_, active, err := c.GetValue(ctx, "func", 5)
if active != 1 {
log.Panicln("Expected 1 active, found", active)
}
checkErr(err)
checkErr(c.DeleteValue(ctx, "func", "ip"))
_, _, err = c.GetValue(ctx, "func", 5)
if err == nil {
log.Panicf("found deleted element")
}
c.SetValue(ctx, "cpulimit", "100", "value", resource.MustParse("3m"))
c.SetCPUUtilization("cpulimit", "100", resource.MustParse("4m"))
_, _, err = c.GetValue(ctx, "cpulimit", 5)
if err == nil {
log.Panicf("received pod address with higher CPU usage than limit")
}
c.SetCPUUtilization("cpulimit", "100", resource.MustParse("2m"))
_, _, err = c.GetValue(ctx, "cpulimit", 5)
checkErr(err)
}
+4 -2
View File
@@ -16,13 +16,15 @@ limitations under the License.
package publisher package publisher
import "context"
type ( type (
// Publisher interface wraps the Publish method that publishes an request // Publisher interface wraps the Publish method that publishes an request
// with given "body" and "headers" to given "target" // with given "body" and "headers" to given "target"
Publisher interface { Publisher interface {
// Publish an request to a "target". Target's meaning depends on the // Publish a request to a "target". Target's meaning depends on the
// publisher: it's a URL in the case of a webhook publisher, or a queue // publisher: it's a URL in the case of a webhook publisher, or a queue
// name in a queue-based publisher such as NATS. // name in a queue-based publisher such as NATS.
Publish(body string, headers map[string]string, target string) Publish(ctx context.Context, body string, headers map[string]string, target string)
} }
) )
+34
View File
@@ -0,0 +1,34 @@
package publisher
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/fission/fission/pkg/utils/loggerfactory"
otelUtils "github.com/fission/fission/pkg/utils/otel"
"github.com/stretchr/testify/assert"
)
func TestPublisher(t *testing.T) {
fnName := "test-fn"
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/"+fnName, r.URL.Path)
assert.Equal(t, "aaa", r.Header.Get("X-Fission-Test"))
assert.Contains(t, r.Header, "Traceparent")
}))
ctx := context.Background()
logger := loggerfactory.GetLogger()
shutdown, err := otelUtils.InitProvider(ctx, logger, fnName)
assert.NoError(t, err)
if shutdown != nil {
defer shutdown(ctx)
}
wp := MakeWebhookPublisher(logger, s.URL)
wp.Publish(ctx, "", map[string]string{"X-Fission-Test": "aaa"}, fnName)
time.Sleep(time.Second * 1)
}
+19 -3
View File
@@ -18,12 +18,17 @@ package publisher
import ( import (
"bytes" "bytes"
"context"
"io" "io"
"net/http" "net/http"
"strings" "strings"
"time" "time"
otelUtils "github.com/fission/fission/pkg/utils/otel"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/net/context/ctxhttp"
) )
type ( type (
@@ -37,8 +42,10 @@ type (
retryDelay time.Duration retryDelay time.Duration
baseURL string baseURL string
timeout time.Duration
} }
publishRequest struct { publishRequest struct {
ctx context.Context
body string body string
headers map[string]string headers map[string]string
target string target string
@@ -54,6 +61,8 @@ func MakeWebhookPublisher(logger *zap.Logger, baseURL string) *WebhookPublisher
baseURL: baseURL, baseURL: baseURL,
requestChannel: make(chan *publishRequest, 32), // buffered channel requestChannel: make(chan *publishRequest, 32), // buffered channel
// TODO make this configurable // TODO make this configurable
timeout: 60 * time.Minute,
// TODO make this configurable
maxRetries: 10, maxRetries: 10,
retryDelay: 500 * time.Millisecond, retryDelay: 500 * time.Millisecond,
} }
@@ -62,9 +71,14 @@ func MakeWebhookPublisher(logger *zap.Logger, baseURL string) *WebhookPublisher
} }
// Publish sends a request to the target with payload having given body and headers // Publish sends a request to the target with payload having given body and headers
func (p *WebhookPublisher) Publish(body string, headers map[string]string, target string) { func (p *WebhookPublisher) Publish(ctx context.Context, body string, headers map[string]string, target string) {
tracer := otel.Tracer("WebhookPublisher")
ctx, span := tracer.Start(ctx, "WebhookPublisher/Publish")
defer span.End()
// serializing the request gives user a guarantee that the request is sent in sequence order // serializing the request gives user a guarantee that the request is sent in sequence order
p.requestChannel <- &publishRequest{ p.requestChannel <- &publishRequest{
ctx: ctx,
body: body, body: body,
headers: headers, headers: headers,
target: target, target: target,
@@ -89,7 +103,7 @@ func (p *WebhookPublisher) makeHTTPRequest(r *publishRequest) {
// log once for this request // log once for this request
defer func() { defer func() {
if ce := p.logger.Check(level, msg); ce != nil { if ce := otelUtils.LoggerWithTraceID(r.ctx, p.logger).Check(level, msg); ce != nil {
ce.Write(fields...) ce.Write(fields...)
} }
}() }()
@@ -107,7 +121,9 @@ func (p *WebhookPublisher) makeHTTPRequest(r *publishRequest) {
req.Header.Set(k, v) req.Header.Set(k, v)
} }
// Make the request // Make the request
resp, err := http.DefaultClient.Do(req) ctx, cancel := context.WithTimeout(r.ctx, p.timeout)
defer cancel()
resp, err := ctxhttp.Do(ctx, otelhttp.DefaultClient, req)
if err != nil { if err != nil {
fields = append(fields, zap.Error(err), zap.Any("request", r)) fields = append(fields, zap.Error(err), zap.Any("request", r))
} else { } else {
-5
View File
@@ -111,11 +111,6 @@ type (
} }
) )
func init() {
// just seeding the random number for getting the canary function
rand.Seed(time.Now().UnixNano())
}
func (w *fakeCloseReadCloser) Close() error { func (w *fakeCloseReadCloser) Close() error {
return nil return nil
} }
+3 -1
View File
@@ -17,6 +17,8 @@ limitations under the License.
package timer package timer
import ( import (
"context"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"go.uber.org/zap" "go.uber.org/zap"
@@ -66,7 +68,7 @@ func (timer *Timer) newCron(t fv1.TimeTrigger) *cron.Cron {
// with the addition of multi-tenancy, the users can create functions in any namespace. however, // with the addition of multi-tenancy, the users can create functions in any namespace. however,
// the triggers can only be created in the same namespace as the function. // the triggers can only be created in the same namespace as the function.
// so essentially, function namespace = trigger namespace. // so essentially, function namespace = trigger namespace.
(*timer.publisher).Publish("", headers, utils.UrlForFunction(t.Spec.FunctionReference.Name, t.Namespace)) (*timer.publisher).Publish(context.Background(), "", headers, utils.UrlForFunction(t.Spec.FunctionReference.Name, t.Namespace))
}) })
c.Start() c.Start()
timer.logger.Info("started cron for time trigger", zap.String("trigger_name", t.Name), zap.String("trigger_namespace", t.Namespace), zap.String("cron", t.Spec.Cron)) timer.logger.Info("started cron for time trigger", zap.String("trigger_name", t.Name), zap.String("trigger_namespace", t.Namespace), zap.String("cron", t.Spec.Cron))
+5 -1
View File
@@ -4,13 +4,17 @@ import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"go.uber.org/zap" "go.uber.org/zap"
) )
func StartServer(ctx context.Context, log *zap.Logger, svc string, port string, handler http.Handler) { func StartServer(ctx context.Context, log *zap.Logger, svc string, port string, handler http.Handler) {
if !strings.Contains(port, ":") {
port = fmt.Sprintf(":%s", port)
}
server := http.Server{ server := http.Server{
Addr: fmt.Sprintf(":%s", port), Addr: port,
Handler: handler, Handler: handler,
} }
l := log.With(zap.String("service", svc), zap.String("addr", server.Addr)) l := log.With(zap.String("service", svc), zap.String("addr", server.Addr))
+6
View File
@@ -67,6 +67,12 @@ func (rw *ResponseWriterWrapper) WriteHeader(statuscode int) {
rw.ResponseWriter.WriteHeader(statuscode) rw.ResponseWriter.WriteHeader(statuscode)
} }
func (rw *ResponseWriterWrapper) Flush() {
if f, ok := rw.ResponseWriter.(http.Flusher); ok {
f.Flush()
}
}
func HTTPMetricMiddleware(next http.Handler) http.Handler { func HTTPMetricMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if util.IsWebsocketRequest(r) { if util.IsWebsocketRequest(r) {
+98
View File
@@ -0,0 +1,98 @@
package metrics
import (
"bufio"
"context"
"fmt"
"io"
"log"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"
"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var dataRow = []byte("I'm the data Row\n")
func chunkedHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(r.Context())
ticker := time.NewTicker(time.Second) // We may set it to 10 secs
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ticker.C:
_, _ = w.Write(dataRow)
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
case <-ctx.Done():
return
}
}
}()
// Emulate some work
time.Sleep(5 * time.Second)
// Telling the loop that keeps the connection alive to end
cancel()
// Waiting until the loop ends
wg.Wait()
}
func TestChunked(t *testing.T) {
mr := mux.NewRouter()
mr.Use(HTTPMetricMiddleware)
mr.Handle("/", http.HandlerFunc(chunkedHandler))
s := httptest.NewServer(mr)
defer s.Close()
resp, err := http.Get(s.URL)
require.NoError(t, err)
assert.Contains(t, resp.TransferEncoding, "chunked")
defer resp.Body.Close()
r := bufio.NewReader(resp.Body)
for {
line, err := readChunkedResponseLine(r)
if err != nil {
if err == io.EOF {
return
}
log.Fatal(err.Error())
}
if len(line) == 0 {
log.Println("Alive!")
continue
}
fmt.Println(string(line)) // we got the final response
assert.Equal(t, dataRow, append(line, '\n'))
}
}
func readChunkedResponseLine(r *bufio.Reader) ([]byte, error) {
line, isPrefix, err := r.ReadLine()
if err != nil {
return nil, err
}
if isPrefix {
rest, err := readChunkedResponseLine(r)
if err != nil {
return nil, err
}
line = append(line, rest...)
}
return line, nil
}
+9 -9
View File
@@ -20,7 +20,7 @@ const (
type ( type (
NamespaceResolver struct { NamespaceResolver struct {
FunctionNamespace string FunctionNamespace string
BuiderNamespace string BuilderNamespace string
DefaultNamespace string DefaultNamespace string
FissionResourceNS map[string]string FissionResourceNS map[string]string
Logger *zap.Logger Logger *zap.Logger
@@ -40,14 +40,14 @@ var nsResolver *NamespaceResolver
func init() { func init() {
nsResolver = &NamespaceResolver{ nsResolver = &NamespaceResolver{
FunctionNamespace: os.Getenv(ENV_FUNCTION_NAMESPACE), FunctionNamespace: os.Getenv(ENV_FUNCTION_NAMESPACE),
BuiderNamespace: os.Getenv(ENV_BUILDER_NAMESPACE), BuilderNamespace: os.Getenv(ENV_BUILDER_NAMESPACE),
DefaultNamespace: os.Getenv(ENV_DEFAULT_NAMESPACE), DefaultNamespace: os.Getenv(ENV_DEFAULT_NAMESPACE),
FissionResourceNS: GetNamespaces(), FissionResourceNS: GetNamespaces(),
Logger: loggerfactory.GetLogger(), Logger: loggerfactory.GetLogger(),
} }
nsResolver.Logger.Debug("namespaces", zap.String("function_namespace", nsResolver.FunctionNamespace), nsResolver.Logger.Debug("namespaces", zap.String("function_namespace", nsResolver.FunctionNamespace),
zap.String("builder_namespace", nsResolver.BuiderNamespace), zap.String("builder_namespace", nsResolver.BuilderNamespace),
zap.String("default_namespace", nsResolver.DefaultNamespace), zap.String("default_namespace", nsResolver.DefaultNamespace),
zap.Any("fission_resource_namespace", listNamespaces(nsResolver.FissionResourceNS))) zap.Any("fission_resource_namespace", listNamespaces(nsResolver.FissionResourceNS)))
} }
@@ -96,8 +96,8 @@ func (nsr *NamespaceResolver) FissionNSWithOptions(option ...option) map[string]
if options.functionNS && nsr.FunctionNamespace != "" { if options.functionNS && nsr.FunctionNamespace != "" {
fissionResourceNS[nsr.FunctionNamespace] = nsr.FunctionNamespace fissionResourceNS[nsr.FunctionNamespace] = nsr.FunctionNamespace
} }
if options.builderNS && nsr.BuiderNamespace != "" { if options.builderNS && nsr.BuilderNamespace != "" {
fissionResourceNS[nsr.BuiderNamespace] = nsr.BuiderNamespace fissionResourceNS[nsr.BuilderNamespace] = nsr.BuilderNamespace
} }
if options.defaultNs && nsr.DefaultNamespace != "" { if options.defaultNs && nsr.DefaultNamespace != "" {
fissionResourceNS[nsr.DefaultNamespace] = nsr.DefaultNamespace fissionResourceNS[nsr.DefaultNamespace] = nsr.DefaultNamespace
@@ -118,7 +118,7 @@ func GetNamespaces() map[string]string {
if len(envValue) > 0 { if len(envValue) > 0 {
lstNamespaces := strings.Split(envValue, ",") lstNamespaces := strings.Split(envValue, ",")
for _, namespace := range lstNamespaces { for _, namespace := range lstNamespaces {
//check to handle string with additional comma at the end of string. eg- ns1,ns2, // check to handle string with additional comma at the end of string. eg- ns1,ns2,
if namespace != "" { if namespace != "" {
namespaces[namespace] = namespace namespaces[namespace] = namespace
} }
@@ -132,14 +132,14 @@ func GetNamespaces() map[string]string {
} }
func (nsr *NamespaceResolver) GetBuilderNS(namespace string) string { func (nsr *NamespaceResolver) GetBuilderNS(namespace string) string {
if nsr.BuiderNamespace == "" { if nsr.BuilderNamespace == "" {
return namespace return namespace
} }
if namespace != metav1.NamespaceDefault { if namespace != metav1.NamespaceDefault {
return namespace return namespace
} }
return nsr.BuiderNamespace return nsr.BuilderNamespace
} }
func (nsr *NamespaceResolver) GetFunctionNS(namespace string) string { func (nsr *NamespaceResolver) GetFunctionNS(namespace string) string {
@@ -154,7 +154,7 @@ func (nsr *NamespaceResolver) GetFunctionNS(namespace string) string {
} }
func (nsr *NamespaceResolver) ResolveNamespace(namespace string) string { func (nsr *NamespaceResolver) ResolveNamespace(namespace string) string {
if nsr.FunctionNamespace == "" || nsr.BuiderNamespace == "" { if nsr.FunctionNamespace == "" || nsr.BuilderNamespace == "" {
return nsr.DefaultNamespace return nsr.DefaultNamespace
} }
return namespace return namespace
+1 -1
View File
@@ -226,7 +226,7 @@ func TestNamespaceResolver(t *testing.T) {
func getFissionNamespaces(builderNS, functionNS, defaultNS string) *NamespaceResolver { func getFissionNamespaces(builderNS, functionNS, defaultNS string) *NamespaceResolver {
return &NamespaceResolver{ return &NamespaceResolver{
FunctionNamespace: functionNS, FunctionNamespace: functionNS,
BuiderNamespace: builderNS, BuilderNamespace: builderNS,
DefaultNamespace: defaultNS, DefaultNamespace: defaultNS,
} }
} }
+5 -14
View File
@@ -25,7 +25,6 @@ package profile
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
"os" "os"
@@ -35,26 +34,18 @@ import (
"github.com/fission/fission/pkg/utils/httpserver" "github.com/fission/fission/pkg/utils/httpserver"
) )
func getPprofAddr() string {
pprofHost := os.Getenv("PPROF_HOST")
if pprofHost == "" {
pprofHost = "localhost"
}
pprofPort := os.Getenv("PPROF_PORT")
if pprofPort == "" {
pprofPort = "6060"
}
return fmt.Sprintf("%s:%s", pprofHost, pprofPort)
}
func ProfileIfEnabled(ctx context.Context, logger *zap.Logger) { func ProfileIfEnabled(ctx context.Context, logger *zap.Logger) {
enablePprof := os.Getenv("PPROF_ENABLED") enablePprof := os.Getenv("PPROF_ENABLED")
if enablePprof != "true" { if enablePprof != "true" {
return return
} }
pprofPort := os.Getenv("PPROF_PORT")
if pprofPort == "" {
pprofPort = "6060"
}
pprofMux := http.DefaultServeMux pprofMux := http.DefaultServeMux
http.DefaultServeMux = http.NewServeMux() http.DefaultServeMux = http.NewServeMux()
go httpserver.StartServer(ctx, logger, "pprof", getPprofAddr(), pprofMux) go httpserver.StartServer(ctx, logger, "pprof", pprofPort, pprofMux)
} }
+9 -3
View File
@@ -145,11 +145,17 @@ func setupSAAndRoleBindings(ctx context.Context, client kubernetes.Interface, lo
for _, permission := range ps.permissions { for _, permission := range ps.permissions {
permission.exists, err = checkPermission(ctx, client, SAObj, permission.gvr, permission.verb) permission.exists, err = checkPermission(ctx, client, SAObj, permission.gvr, permission.verb)
if err != nil { if err != nil {
// some error occurred while checking permission // some error occurred while checking permission, log error as warning message and continue to create new permissions
// now assume permission not exists and will add this permission in rules, insted of return logger.Info(err.Error())
logger.Error("error while checking permission", zap.Error(err))
} }
if !permission.exists { if !permission.exists {
logger.Info("creating new permission",
zap.String("service_account", SAObj.Name),
zap.String("namespace", SAObj.Namespace),
zap.String("group", permission.gvr.Group),
zap.String("resource", permission.gvr.Resource),
zap.String("verb", permission.verb))
rules = append(rules, rbac.PolicyRule{ rules = append(rules, rbac.PolicyRule{
APIGroups: []string{permission.gvr.Group}, APIGroups: []string{permission.gvr.Group},
Resources: []string{permission.gvr.Resource}, Resources: []string{permission.gvr.Resource},
+1 -1
View File
@@ -61,7 +61,7 @@ manifests:
preUpgradeChecks.imageTag: "" preUpgradeChecks.imageTag: ""
priorityClassName: system-cluster-critical priorityClassName: system-cluster-critical
prometheus.serviceEndpoint: "" prometheus.serviceEndpoint: ""
repository: index.docker.io repository: ghcr.io
routerServiceType: LoadBalancer routerServiceType: LoadBalancer
runtimePodSpec.enabled: "false" runtimePodSpec.enabled: "false"
serviceMonitor.additionalServiceMonitorLabels.release: prometheus serviceMonitor.additionalServiceMonitorLabels.release: prometheus
+1 -1
View File
@@ -5,7 +5,7 @@ ns="fission"
ROOT=$(pwd) ROOT=$(pwd)
PREV_STABLE_VERSION=v1.16.3 PREV_STABLE_VERSION=v1.16.3
HELM_VARS_PREV_RELEASE="routerServiceType=NodePort,analytics=false" HELM_VARS_PREV_RELEASE="routerServiceType=NodePort,analytics=false"
HELM_VARS_LATEST_RELEASE="routerServiceType=NodePort,repository=docker.io/library,image=fission-bundle,pullPolicy=IfNotPresent,imageTag=latest,fetcher.image=docker.io/library/fetcher,fetcher.imageTag=latest,postInstallReportImage=reporter,preUpgradeChecks.image=preupgradechecks,preUpgradeChecks.imageTag=latest,analytics=false" HELM_VARS_LATEST_RELEASE="routerServiceType=NodePort,repository=ghcr.io,image=fission/fission-bundle,pullPolicy=IfNotPresent,imageTag=latest,fetcher.image=fission/fetcher,fetcher.imageTag=latest,postInstallReportImage=fission/reporter,preUpgradeChecks.image=fission/pre-upgrade-checks,preUpgradeChecks.imageTag=latest,analytics=false"
doit() { doit() {
echo "! $*" echo "! $*"