Compare commits

...
22 Commits
Author SHA1 Message Date
Sanket SudakeandGitHub 770c19a27b Update release version v1.17.0-rc1 (#2470)
Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2022-07-06 15:01:39 +05:30
Sanket SudakeandGitHub 613062549d Update controller-tools to v0.9.2 (#2467)
Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2022-07-04 16:48:32 +05:30
Shubham BansalandGitHub f3a45b6549 OpenTelemetry package update to v1.7.0 (#2466) 2022-06-30 16:40:50 +05:30
Shubham BansalandGitHub c71867169b Pods immediately terminate for idletimeout in new deployment and container executer type (#2459)
* added waitgroup to handle multiple goroutine scenario
* changes for cache service
* changes to get function service from cache by UID
2022-06-29 11:49:34 +05:30
Ankit ChawlaandGitHub 473acc4e2b Added support to set builder and fn pod specs via helm chart (#2461)
The users can now set the pod spec for builder and fn pods via helm chart.
Currently we have set some default securitycontext for the pods. Before there were no permissions set and the user would by default enter root when kubectl exec into pod. Now the permissions have been set and the user will not be able to access root directory in poolmgr and newdeploy pods.
2022-06-27 16:52:28 +05:30
21ea35b02a CLI to operate archives managed by Storage Service (#2450)
* Add API for listing storage service archives
If id is mentioned we allow user to download specific
archive. If id is not mentioned we list all archives
present with storage service.
This will allow us to build CLI with storage service
and help users to debug storage service.
* Added commands for storagesvc cli and functionalities
* Reusing code and added geturl and download.
* Fixed geturl for localstorage.
* Fixed description of fission archive command
* Added unit tests for function getstorageurl
* Added integration test for archive cli




Co-authored-by: Sanket Sudake <sanketsudake@gmail.com>
2022-06-15 18:53:36 +05:30
Shubham BansalandGitHub 7f21b708e7 Avoid fission installation failure due to analytics connection error (#2457) 2022-06-15 11:32:06 +05:30
Ankit ChawlaandGitHub b80b41e1fd Added variable to enable or disable archivePruner (#2458)
* Added variable to enable or disable archivePruner

* Made fixes according to code review comments

* Minor changes
2022-06-15 10:48:24 +05:30
fe8f53375e builder: Allow command with arguments via custom build options (#2453)
* allow buildcmd command to process arguments
* Add unit tests for builder with different scenarios

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
Co-authored-by: Sanket Sudake <sanketsudake@gmail.com>
2022-06-13 19:26:05 +05:30
Ankit ChawlaandGitHub a2b6f95656 Fix for issue in poolmgr fns caused by skipping address validation (#2441) 2022-06-13 15:09:29 +05:30
Ankit ChawlaandGitHub fa3347077a Fix for archivepruner to delete files only from subdir (#2456) 2022-06-13 12:35:49 +05:30
Shubham NazareandGitHub 5d010fe1fa Fix pre-check failure during new fission installation (#2437)
* Add pre-check flag to root cmd
* Make precheck flag optional
* Remove pre from global optional flag

Signed-off-by: Shubham Nazare <shubham4443@gmail.com>
2022-06-13 11:48:26 +05:30
Sanket SudakeandGitHub 979880ae2d Upgraded controller-gen to remove status from fission CRDs (#2454)
Updated controller-gen to 0.9.0 and regenerated CRDs to
remove status from all Fission CRDs.
2022-06-10 10:01:56 +05:30
Yatish SharmaandGitHub 7be3e4f410 [issue-2401] Added pod security context for Fission Components (#2449)
Following component has been updated with securityContext -
1. buildermgr
2. controller
3. executor
4. kubewatcher
5. router
6. timer
7. storagesvc

* Removed the security context from fetcher as per the offline discussion
2022-06-09 16:25:09 +05:30
Ankit ChawlaandGitHub 709af6e432 Update github.com/opencontainers/runc dependency to 1.1.2 (#2448) 2022-06-06 13:49:22 +05:30
Ankit ChawlaandGitHub ac3307bd91 Fixed help for ColdStarts metric in executor according to new labels (#2446) 2022-06-02 12:26:05 +05:30
VishalandGitHub 063209dc9e More users added (#2440) 2022-05-26 18:21:53 +05:30
83303471c5 Adding users of Fission (#2439)
Co-authored-by: Sanket Sudake <sanketsudake@gmail.com>
2022-05-26 18:09:51 +05:30
Sanket SudakeandGitHub 8bcc9503d1 Add changelog for 1.16.0 release (#2434)
Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2022-05-24 14:24:13 +05:30
Ankit ChawlaandGitHub ed1e4a5cf0 Updated keda image versions (#2433) 2022-05-24 12:51:02 +05:30
Sanket SudakeandGitHub 3cf7dc89b9 Update helm chart version to v1.16.0 (#2432)
Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2022-05-24 12:34:21 +05:30
Sanket SudakeandGitHub 69c1aab14a Update changelog for 1.16.0-rc2 (#2427)
Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
2022-05-11 15:23:21 +05:30
67 changed files with 18828 additions and 4521 deletions
+44 -1
View File
@@ -1,5 +1,48 @@
# Changelog
## [v1.16.0](https://github.com/fission/fission/tree/v1.16.0) (2022-05-24)
[Full Changelog](https://github.com/fission/fission/compare/v1.16.0-rc2...v1.16.0)
**Merged pull requests:**
- Updated keda image versions [\#2433](https://github.com/fission/fission/pull/2433) ([blackfly19](https://github.com/blackfly19))
## [v1.16.0-rc2](https://github.com/fission/fission/tree/v1.16.0-rc2) (2022-05-11)
[Full Changelog](https://github.com/fission/fission/compare/v1.16.0-rc1...v1.16.0-rc2)
**Merged pull requests:**
- Added service monitors for components whose metrics are exposed [\#2424](https://github.com/fission/fission/pull/2424) ([blackfly19](https://github.com/blackfly19))
- Add support for custom metrics for HPA [\#2423](https://github.com/fission/fission/pull/2423) ([sanketsudake](https://github.com/sanketsudake))
- Migrate HPA v1 to v2beta2 [\#2421](https://github.com/fission/fission/pull/2421) ([sanketsudake](https://github.com/sanketsudake))
- feat: 🎸 add runtime-env flags to the env update cmd [\#2420](https://github.com/fission/fission/pull/2420) ([AetheWu](https://github.com/AetheWu))
- Use Clientset interface instead of type for Fission/kubernetes clients [\#2416](https://github.com/fission/fission/pull/2416) ([sanketsudake](https://github.com/sanketsudake))
- Fix namespace used in speciallized pod cleanup [\#2415](https://github.com/fission/fission/pull/2415) ([sanketsudake](https://github.com/sanketsudake))
- Add http retries in executor client with go-retryablehttp [\#2414](https://github.com/fission/fission/pull/2414) ([sanketsudake](https://github.com/sanketsudake))
- Check active request before decrease in functionCache [\#2413](https://github.com/fission/fission/pull/2413) ([sanketsudake](https://github.com/sanketsudake))
- Removed demo, documentations & updated Readme [\#2411](https://github.com/fission/fission/pull/2411) ([techmaharaj](https://github.com/techmaharaj))
- Created separate file for authmiddleware fn [\#2410](https://github.com/fission/fission/pull/2410) ([blackfly19](https://github.com/blackfly19))
- Use common httpserver across fission [\#2409](https://github.com/fission/fission/pull/2409) ([sanketsudake](https://github.com/sanketsudake))
- Optimize port forward in fission CLI by waiting on ready channel [\#2405](https://github.com/fission/fission/pull/2405) ([sanketsudake](https://github.com/sanketsudake))
- Remove deprecated Fission Azure Storage Queue connector [\#2404](https://github.com/fission/fission/pull/2404) ([sanketsudake](https://github.com/sanketsudake))
- Remove deprecated Fission Nats connector [\#2403](https://github.com/fission/fission/pull/2403) ([sanketsudake](https://github.com/sanketsudake))
- Avoid tapservice call to executor with empty URL [\#2402](https://github.com/fission/fission/pull/2402) ([sanketsudake](https://github.com/sanketsudake))
- Added metrics for fission mqtrigger and optimizations in trigger subscriptions [\#2399](https://github.com/fission/fission/pull/2399) ([blackfly19](https://github.com/blackfly19))
- Prometheus metrics improvements [\#2398](https://github.com/fission/fission/pull/2398) ([blackfly19](https://github.com/blackfly19))
- Go version 1.18 update [\#2395](https://github.com/fission/fission/pull/2395) ([sanketsudake](https://github.com/sanketsudake))
- Fixing gcp connector name typo [\#2393](https://github.com/fission/fission/pull/2393) ([blackfly19](https://github.com/blackfly19))
- Upgraded alpine version to 3.15 [\#2391](https://github.com/fission/fission/pull/2391) ([blackfly19](https://github.com/blackfly19))
- Fixed poolmgr pod naming error [\#2385](https://github.com/fission/fission/pull/2385) ([blackfly19](https://github.com/blackfly19))
- Go1.17 [\#2381](https://github.com/fission/fission/pull/2381) ([sanketsudake](https://github.com/sanketsudake))
- Upgraded archiver [\#2378](https://github.com/fission/fission/pull/2378) ([blackfly19](https://github.com/blackfly19))
- Refactoring prometheus metrics and labels [\#2375](https://github.com/fission/fission/pull/2375) ([sanketsudake](https://github.com/sanketsudake))
- \[helm chart\] Remove prometheus chart dependency from Fission [\#2371](https://github.com/fission/fission/pull/2371) ([sanketsudake](https://github.com/sanketsudake))
- \[helm chart\] fission deployments resources [\#2370](https://github.com/fission/fission/pull/2370) ([carlosrmendes](https://github.com/carlosrmendes))
- feature: Added commandline flags to set env var on the runtime and builder containers [\#2369](https://github.com/fission/fission/pull/2369) ([praddy26](https://github.com/praddy26))
- Added imagepullsecrets to helm [\#2364](https://github.com/fission/fission/pull/2364) ([blackfly19](https://github.com/blackfly19))
## [v1.16.0-rc1](https://github.com/fission/fission/tree/v1.16.0-rc1) (2022-02-12)
[Full Changelog](https://github.com/fission/fission/compare/v1.15.1...v1.16.0-rc1)
@@ -239,7 +282,7 @@
- For fixing staticcheck issue [\#1652](https://github.com/fission/fission/pull/1652) ([vishal-biyani](https://github.com/vishal-biyani))
- Allow user to override nats-streaming image [\#1645](https://github.com/fission/fission/pull/1645) ([funkypenguin](https://github.com/funkypenguin))
- Allow user to define busybox image [\#1643](https://github.com/fission/fission/pull/1643) ([funkypenguin](https://github.com/funkypenguin))
- Python env changes for pip3 [\#1633](https://github.com/fission/fission/pull/1633) ([agiwalpooja20](https://github.com/agiwalpooja20))
- Python env changes for pip3 [\#1633](https://github.com/fission/fission/pull/1633) ([agiwalpooja20-zz](https://github.com/agiwalpooja20-zz))
- S3 backend for storage service [\#1629](https://github.com/fission/fission/pull/1629) ([vishal-biyani](https://github.com/vishal-biyani))
- Fixing verify-staticcheck.sh [\#1622](https://github.com/fission/fission/pull/1622) ([rajalokan](https://github.com/rajalokan))
- Added support for setting bodyParser limit param via environment variable [\#1618](https://github.com/fission/fission/pull/1618) ([therahulbhati](https://github.com/therahulbhati))
+5 -2
View File
@@ -64,8 +64,11 @@ codegen:
@./hack/update-codegen.sh
### CRDs
generate-crds:
controller-gen crd:trivialVersions=false,preserveUnknownFields=false \
controller-gen-install:
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2
generate-crds: controller-gen-install
controller-gen crd \
paths=./pkg/apis/core/v1 \
output:crd:artifacts:config=crds/v1
+16
View File
@@ -60,6 +60,7 @@ Table of Contents
- [Getting Started](#getting-started)
- [Learn More](#learn-more)
- [Contributing](#contributing)
- [Who is using Fission?](#who-is-using-fission)
- [Sponsors](#sponsors)
- [License](#license)
@@ -108,6 +109,21 @@ aggregation &mdash; also helps with ops on your Fission deployment.
Check out the [contributing guide](CONTRIBUTING.md).
## Who is using Fission?
- [Fareye](https://www.getfareye.com)
- Apple
- [iQuanti](https://www.iquanti.com)
- A large telecom CSP
- [Gadget](https://gadget.dev)
- [CinnamonAI](https://cinnamon.is/en)
- [Armo](https://www.armosec.io/)
- [The Social Audience](https://thesocialaudience.com/)
- [KubeML](https://github.com/DiegoStock12/kubeml)
- Unilever
- [BD](https://www.bd.com/en-in)
- [Biofourmis](https://biofourmis.com/)
- [Babylon](https://www.babylonhealth.com/en-gb)
## Sponsors
The following companies, organizations, and individuals support Fission's ongoing maintenance and development. If you are using/contributing to Fission, we would be happy to list you here, please raise a Pull request.
+2 -2
View File
@@ -1,7 +1,7 @@
apiVersion: v2
name: fission-all
version: v1.16.0-rc2
appVersion: v1.16.0-rc2
version: v1.17.0-rc1
appVersion: v1.17.0-rc1
description: Fission is a fast serverless framework for Kubernetes.
home: https://fission.io/
icon: https://fission.io/images/fission-logo-white.svg
@@ -0,0 +1,9 @@
{{- if .Values.builderPodSpec.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: builder-podspec-patch
data:
spec: |
{{- toYaml .Values.builderPodSpec.podSpec | nindent 4 }}
{{- end -}}
@@ -19,6 +19,9 @@ spec:
prometheus.io/path: "/metrics"
prometheus.io/port: "8080"
spec:
{{- if .Values.buildermgr.securityContext.enabled }}
securityContext: {{- omit .Values.buildermgr.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: buildermgr
image: {{ include "fission-bundleImage" . | quote }}
@@ -22,6 +22,9 @@ spec:
prometheus.io/path: "/metrics"
prometheus.io/port: "8080"
spec:
{{- if .Values.controller.securityContext.enabled }}
securityContext: {{- omit .Values.controller.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: controller
image: {{ include "fission-bundleImage" . | quote }}
@@ -0,0 +1,9 @@
{{- if .Values.runtimePodSpec.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: runtime-podspec-patch
data:
spec: |
{{- toYaml .Values.runtimePodSpec.podSpec | nindent 4 }}
{{- end -}}
@@ -19,6 +19,9 @@ spec:
prometheus.io/path: "/metrics"
prometheus.io/port: "8080"
spec:
{{- if .Values.executor.securityContext.enabled }}
securityContext: {{- omit .Values.executor.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: executor
image: {{ include "fission-bundleImage" . | quote }}
@@ -15,6 +15,9 @@ spec:
labels:
svc: kubewatcher
spec:
{{- if .Values.kubewatcher.securityContext.enabled }}
securityContext: {{- omit .Values.kubewatcher.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: kubewatcher
image: {{ include "fission-bundleImage" . | quote }}
@@ -28,6 +28,9 @@ spec:
prometheus.io/path: "/metrics"
prometheus.io/port: "8080"
spec:
{{- if .Values.router.securityContext.enabled }}
securityContext: {{- omit .Values.router.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: router
image: {{ include "fission-bundleImage" . | quote }}
@@ -22,6 +22,9 @@ spec:
prometheus.io/path: "/metrics"
prometheus.io/port: "8080"
spec:
{{- if .Values.storagesvc.securityContext.enabled }}
securityContext: {{- omit .Values.storagesvc.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: storagesvc
image: {{ include "fission-bundleImage" . | quote }}
@@ -33,8 +36,12 @@ spec:
args: ["--storageServicePort", "8000", "--storageType", "local"]
{{- end }}
env:
- name: PRUNE_ENABLED
value: "{{.Values.storagesvc.archivePruner.enabled}}"
{{- if .Values.storagesvc.archivePruner.enabled }}
- name: PRUNE_INTERVAL
value: "{{.Values.pruneInterval}}"
value: "{{.Values.storagesvc.archivePruner.interval}}"
{{- end }}
- name: DEBUG_ENV
value: {{ .Values.debugEnv | quote }}
- name: PPROF_ENABLED
@@ -15,6 +15,9 @@ spec:
labels:
svc: timer
spec:
{{- if .Values.timer.securityContext.enabled }}
securityContext: {{- omit .Values.timer.securityContext "enabled" | toYaml | nindent 8 }}
{{- end }}
containers:
- name: timer
image: {{ include "fission-bundleImage" . | quote }}
+141 -11
View File
@@ -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.
## Keep it empty for using latest tag.
##
imageTag: v1.16.0-rc2
imageTag: v1.17.0-rc1
## pullPolicy represents the pull policy to use for images in the chart.
##
@@ -92,7 +92,7 @@ fetcher:
## image represents the image of the fetcher component.
image: fission/fetcher
## imageTag represents the tag of the image of the fetcher component.
imageTag: v1.16.0-rc2
imageTag: v1.17.0-rc1
## Fetcher is only for to downloading or uploading archive.
## Normally, you don't need to change the value here, unless necessary.
@@ -143,6 +143,18 @@ executor:
##
resources: {}
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## router is responsible for routing function calls to the appropriate function.
##
router:
@@ -248,6 +260,18 @@ router:
##
resources: {}
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## The builder manager watches the package & environments CRD changes and manages the builds of function source code.
##
buildermgr:
@@ -262,6 +286,18 @@ buildermgr:
##
resources: {}
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## controller is the component that the client talks to.
## It contains CRUD APIs for functions, triggers, environments, Kubernetes event watches, etc. and proxy APIs to internal 3rd-party services.
##
@@ -277,6 +313,18 @@ controller:
##
resources: {}
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## kubewatcher watches the Kubernetes API and invokes functions associated with watches, sending the watch event to the function.
##
kubewatcher:
@@ -291,6 +339,18 @@ kubewatcher:
##
resources: {}
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## The storage service is the home for all archives of packages with sizes larger than 256KB.
##
storagesvc:
@@ -305,6 +365,24 @@ storagesvc:
##
resources: {}
## Archive pruner removes archives from storage which are not referenced by any package.
archivePruner:
enabled: true
## Run prune routine at interval (in minutes)
interval: 60
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## The timer works like kubernetes CronJob but instead of creating a pod to do the task
## It sends a request to router to invoke the function.
##
@@ -320,6 +398,18 @@ timer:
##
resources: {}
## Security Context
## It holds pod-level and container level security configuration.
## This is an experimental section, please verify before enabling in production.
## Ref: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#security-context-1
securityContext:
enabled: false
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## Kafka: enable and configure the details
##
kafka:
@@ -483,7 +573,6 @@ busyboxImage: busybox
## This interval configures the frequency at which it runs inside the storagesvc pod.
## The value is in minutes.
##
pruneInterval: 60
preUpgradeChecks:
## Run pre-install/pre-upgrade checks if true
@@ -494,7 +583,7 @@ preUpgradeChecks:
image: fission/pre-upgrade-checks
## pre-install/pre-upgrade checks image version
##
imageTag: v1.16.0-rc2
imageTag: v1.17.0-rc1
## Fission post-install/post-upgrade reporting live in this image
##
@@ -617,25 +706,25 @@ mqt_keda:
connector_images:
kafka:
image: fission/keda-kafka-http-connector
tag: v0.9
tag: v0.10
rabbitmq:
image: fission/keda-rabbitmq-http-connector
tag: v0.8
tag: v0.9
awskinesis:
image: fission/keda-aws-kinesis-http-connector
tag: v0.8
tag: v0.9
aws_sqs:
image: fission/keda-aws-sqs-http-connector
tag: v0.8
tag: v0.9
nats_steaming:
image: fission/keda-nats-streaming-http-connector
tag: v0.9
tag: v0.11
gcp_pubsub:
image: fission/keda-gcp-pubsub-http-connector
tag: v0.3
tag: v0.4
redis:
image: fission/keda-redis-http-connector
tag: v0.1
tag: v0.2
## Pod resources as:
## resources:
@@ -652,3 +741,44 @@ mqt_keda:
##
pprof:
enabled: false
## Enable runtimePodSpec and add spec to your poolmgr or newdeploy pods
##
runtimePodSpec:
## Setting it false by default so that integration tests pass
##
enabled: false
## Checkout PodSpec in https://fission.io/docs/reference/crd-reference/#runtime
##
podSpec:
## Default podspec to improve security of the pods
##
securityContext:
fsGroup: 10001
runAsGroup: 10001
runAsNonRoot: true
runAsUser: 10001
## Enable builderPodSpec and add spec to your env builder pods
##
builderPodSpec:
## Setting it false by default so that integration tests pass
##
enabled: false
## Checkout PodSpec in https://fission.io/docs/reference/crd-reference/#builder
##
podSpec:
## Default podspec to improve security of the pods
##
securityContext:
fsGroup: 10001
runAsGroup: 10001
runAsNonRoot: true
runAsUser: 10001
+3 -2
View File
@@ -22,6 +22,7 @@ import (
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra/helptemplate"
"github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/cmd/archive"
"github.com/fission/fission/pkg/fission-cli/cmd/canaryconfig"
"github.com/fission/fission/pkg/fission-cli/cmd/check"
"github.com/fission/fission/pkg/fission-cli/cmd/environment"
@@ -61,7 +62,7 @@ func App() *cobra.Command {
func(input cli.Input) error {
console.Verbosity = input.Int(flagkey.Verbosity)
if input.IsSet(flagkey.ClientOnly) {
if input.IsSet(flagkey.ClientOnly) || input.IsSet(flagkey.PreCheckOnly) {
// TODO: use fake rest client for offline spec generation
cmd.SetClientset(client.MakeFakeClientset(nil))
} else {
@@ -91,7 +92,7 @@ func App() *cobra.Command {
groups := helptemplate.CommandGroups{}
groups = append(groups, helptemplate.CreateCmdGroup("Auth Commands(Note: Authentication should be enabled to use a command in this group.)", token.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Basic Commands", environment.Commands(), _package.Commands(), function.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Basic Commands", environment.Commands(), _package.Commands(), function.Commands(), archive.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Trigger Commands", httptrigger.Commands(), mqtrigger.Commands(), timetrigger.Commands(), kubewatch.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Deploy Strategies Commands", canaryconfig.Commands()))
groups = append(groups, helptemplate.CreateCmdGroup("Declarative Application Commands", spec.Commands()))
+6 -1
View File
@@ -51,7 +51,12 @@ func eventCommandHandler(cmd *cobra.Command, args []string) error {
}
ctx := context.Background()
return tracker.Tracker.SendEvent(ctx, event)
t, err := tracker.NewTracker()
if err != nil {
return err
}
return t.SendEvent(ctx, event)
}
//EventCommand reports an event to analytics
+6 -2
View File
@@ -17,14 +17,18 @@ limitations under the License.
package main
import (
"log"
"go.uber.org/zap"
"github.com/fission/fission/cmd/reporter/app"
"github.com/fission/fission/pkg/utils/loggerfactory"
)
func main() {
logger := loggerfactory.GetLogger()
defer logger.Sync()
err := app.App().Execute()
if err != nil {
log.Fatal(err)
logger.Error("error occurred during analytics reporting", zap.Error(err))
}
}
+11 -12
View File
@@ -1,10 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.5.0
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: canaryconfigs.fission.io
spec:
@@ -22,10 +21,14 @@ spec:
description: CanaryConfig is for canary deployment of two functions.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -33,13 +36,15 @@ spec:
description: CanaryConfigSpec defines the canary configuration spec
properties:
duration:
description: 'Weight increment interval, string representation of time.Duration, ex : 1m, 2h, 2d (default: "2m")'
description: 'Weight increment interval, string representation of
time.Duration, ex : 1m, 2h, 2d (default: "2m")'
type: string
failureType:
description: FailureType refers to the type of failure
type: string
failurethreshold:
description: Threshold in percentage beyond which the new version of the function is considered unstable
description: Threshold in percentage beyond which the new version
of the function is considered unstable
type: integer
newfunction:
description: New version of the function
@@ -73,9 +78,3 @@ spec:
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+46 -25
View File
@@ -1,10 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.5.0
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: httptriggers.fission.io
spec:
@@ -19,21 +18,28 @@ spec:
- name: v1
schema:
openAPIV3Schema:
description: HTTPTrigger is the trigger invokes user functions when receiving HTTP requests.
description: HTTPTrigger is the trigger invokes user functions when receiving
HTTP requests.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: HTTPTriggerSpec is for router to expose user functions at the given URL path.
description: HTTPTriggerSpec is for router to expose user functions at
the given URL path.
properties:
createingress:
description: If CreateIngress is true, router will create an ingress definition.
description: If CreateIngress is true, router will create an ingress
definition.
type: boolean
functionref:
description: FunctionReference is a reference to the target function.
@@ -41,46 +47,64 @@ spec:
functionweights:
additionalProperties:
type: integer
description: Function Reference by weight. this map contains function name as key and its weight as the value. This is for canary upgrade purpose.
description: Function Reference by weight. this map contains function
name as key and its weight as the value. This is for canary
upgrade purpose.
nullable: true
type: object
name:
description: Name of the function.
type: string
type:
description: 'Type indicates whether this function reference is by name or selector. For now, the only supported reference type is by "name". Future reference types: * Function by label or annotation * Branch or tag of a versioned function * A "rolling upgrade" from one version of a function to another Available value: - name - function-weights'
description: 'Type indicates whether this function reference is
by name or selector. For now, the only supported reference type
is by "name". Future reference types: * Function by label or
annotation * Branch or tag of a versioned function * A "rolling
upgrade" from one version of a function to another Available
value: - name - function-weights'
type: string
required:
- name
- type
type: object
host:
description: 'TODO: remove this field since we have IngressConfig already Deprecated: the original idea of this field is not for setting Ingress. Since we have IngressConfig now, remove Host after couple releases.'
description: 'TODO: remove this field since we have IngressConfig
already Deprecated: the original idea of this field is not for setting
Ingress. Since we have IngressConfig now, remove Host after couple
releases.'
type: string
ingressconfig:
description: 'TODO: make IngressConfig an independent Fission resource IngressConfig for router to set up Ingress.'
description: 'TODO: make IngressConfig an independent Fission resource
IngressConfig for router to set up Ingress.'
properties:
annotations:
additionalProperties:
type: string
description: Annotations will be added to metadata when creating Ingress.
description: Annotations will be added to metadata when creating
Ingress.
nullable: true
type: object
host:
description: Host is for ingress controller to apply rules. If host is empty or "*", the rule applies to all inbound HTTP traffic.
description: Host is for ingress controller to apply rules. If
host is empty or "*", the rule applies to all inbound HTTP traffic.
type: string
path:
description: Path is for path matching. The format of path depends on what ingress controller you used.
description: Path is for path matching. The format of path depends
on what ingress controller you used.
type: string
tls:
description: TLS is for user to specify a Secret that contains TLS key and certificate. The domain name in the key and crt must match the value of Host field.
description: TLS is for user to specify a Secret that contains
TLS key and certificate. The domain name in the key and crt
must match the value of Host field.
type: string
type: object
keepPrefix:
description: When function is exposed with Prefix based path, keepPrefix decides whether to keep or trim prefix in URL while invoking function.
description: When function is exposed with Prefix based path, keepPrefix
decides whether to keep or trim prefix in URL while invoking function.
type: boolean
method:
description: Use Methods instead of Method. This field is going to be deprecated in a future release HTTP method to access a function.
description: Use Methods instead of Method. This field is going to
be deprecated in a future release HTTP method to access a function.
type: string
methods:
description: HTTP methods to access a function
@@ -88,10 +112,13 @@ spec:
type: string
type: array
prefix:
description: 'Prefix with which functions are exposed. NOTE: Prefix takes precedence over URL/RelativeURL. Note that it does not treat slashes specially ("/foobar/" will be matched by the prefix "/foobar").'
description: 'Prefix with which functions are exposed. NOTE: Prefix
takes precedence over URL/RelativeURL. Note that it does not treat
slashes specially ("/foobar/" will be matched by the prefix "/foobar").'
type: string
relativeurl:
description: RelativeURL is the exposed URL for external client to access a function with.
description: RelativeURL is the exposed URL for external client to
access a function with.
type: string
required:
- functionref
@@ -104,9 +131,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
+20 -14
View File
@@ -1,10 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.5.0
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: kuberneteswatchtriggers.fission.io
spec:
@@ -19,13 +18,18 @@ spec:
- name: v1
schema:
openAPIV3Schema:
description: KubernetesWatchTrigger watches kubernetes resource events and invokes functions.
description: KubernetesWatchTrigger watches kubernetes resource events and
invokes functions.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -33,19 +37,27 @@ spec:
description: KubernetesWatchTriggerSpec defines spec of KuberenetesWatchTrigger
properties:
functionref:
description: The reference to a function for kubewatcher to invoke with when receiving events.
description: The reference to a function for kubewatcher to invoke
with when receiving events.
properties:
functionweights:
additionalProperties:
type: integer
description: Function Reference by weight. this map contains function name as key and its weight as the value. This is for canary upgrade purpose.
description: Function Reference by weight. this map contains function
name as key and its weight as the value. This is for canary
upgrade purpose.
nullable: true
type: object
name:
description: Name of the function.
type: string
type:
description: 'Type indicates whether this function reference is by name or selector. For now, the only supported reference type is by "name". Future reference types: * Function by label or annotation * Branch or tag of a versioned function * A "rolling upgrade" from one version of a function to another Available value: - name - function-weights'
description: 'Type indicates whether this function reference is
by name or selector. For now, the only supported reference type
is by "name". Future reference types: * Function by label or
annotation * Branch or tag of a versioned function * A "rolling
upgrade" from one version of a function to another Available
value: - name - function-weights'
type: string
required:
- name
@@ -74,9 +86,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
File diff suppressed because it is too large Load Diff
+38 -24
View File
@@ -1,10 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.5.0
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: packages.fission.io
spec:
@@ -24,44 +23,56 @@ spec:
description: Package Think of these as function-level images.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: PackageSpec includes source/deploy archives and the reference of environment to build the package.
description: PackageSpec includes source/deploy archives and the reference
of environment to build the package.
properties:
buildcmd:
description: BuildCommand is a custom build command that builder used to build the source archive.
description: BuildCommand is a custom build command that builder used
to build the source archive.
type: string
deployment:
description: Deployment is the deployable archive that environment runtime used to run user function.
description: Deployment is the deployable archive that environment
runtime used to run user function.
properties:
checksum:
description: Checksum ensures the integrity of packages referenced by URL. Ignored for literals.
description: Checksum ensures the integrity of packages referenced
by URL. Ignored for literals.
properties:
sum:
type: string
type:
description: ChecksumType specifies the checksum algorithm, such as sha256, used for a checksum.
description: ChecksumType specifies the checksum algorithm,
such as sha256, used for a checksum.
type: string
type: object
literal:
description: Literal contents of the package. Can be used for encoding packages below TODO (256 KB?) size.
description: Literal contents of the package. Can be used for
encoding packages below TODO (256 KB?) size.
format: byte
type: string
type:
description: 'Type defines how the package is specified: literal or URL. Available value: - literal - url'
description: 'Type defines how the package is specified: literal
or URL. Available value: - literal - url'
type: string
url:
description: URL references a package.
type: string
type: object
environment:
description: Environment is a reference to the environment for building source archive.
description: Environment is a reference to the environment for building
source archive.
properties:
name:
type: string
@@ -72,23 +83,30 @@ spec:
- namespace
type: object
source:
description: Source is the archive contains source code and dependencies file. If the package status is in PENDING state, builder manager will then notify builder to compile source and save the result as deployable archive.
description: Source is the archive contains source code and dependencies
file. If the package status is in PENDING state, builder manager
will then notify builder to compile source and save the result as
deployable archive.
properties:
checksum:
description: Checksum ensures the integrity of packages referenced by URL. Ignored for literals.
description: Checksum ensures the integrity of packages referenced
by URL. Ignored for literals.
properties:
sum:
type: string
type:
description: ChecksumType specifies the checksum algorithm, such as sha256, used for a checksum.
description: ChecksumType specifies the checksum algorithm,
such as sha256, used for a checksum.
type: string
type: object
literal:
description: Literal contents of the package. Can be used for encoding packages below TODO (256 KB?) size.
description: Literal contents of the package. Can be used for
encoding packages below TODO (256 KB?) size.
format: byte
type: string
type:
description: 'Type defines how the package is specified: literal or URL. Available value: - literal - url'
description: 'Type defines how the package is specified: literal
or URL. Available value: - literal - url'
type: string
url:
description: URL references a package.
@@ -108,7 +126,9 @@ spec:
description: BuildStatus is the package build status.
type: string
lastUpdateTimestamp:
description: LastUpdateTimestamp will store the timestamp the package was last updated metav1.Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. https://github.com/kubernetes/apimachinery/blob/44bd77c24ef93cd3a5eb6fef64e514025d10d44e/pkg/apis/meta/v1/time.go#L26-L35
description: LastUpdateTimestamp will store the timestamp the package
was last updated metav1.Time is a wrapper around time.Time which
supports correct marshaling to YAML and JSON. https://github.com/kubernetes/apimachinery/blob/44bd77c24ef93cd3a5eb6fef64e514025d10d44e/pkg/apis/meta/v1/time.go#L26-L35
format: date-time
nullable: true
type: string
@@ -119,9 +139,3 @@ spec:
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
+18 -13
View File
@@ -1,10 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.5.0
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: timetriggers.fission.io
spec:
@@ -22,15 +21,20 @@ spec:
description: TimeTrigger invokes functions based on given cron schedule.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: TimeTriggerSpec invokes the specific function at a time or times specified by a cron string.
description: TimeTriggerSpec invokes the specific function at a time or
times specified by a cron string.
properties:
cron:
description: Cron schedule
@@ -41,14 +45,21 @@ spec:
functionweights:
additionalProperties:
type: integer
description: Function Reference by weight. this map contains function name as key and its weight as the value. This is for canary upgrade purpose.
description: Function Reference by weight. this map contains function
name as key and its weight as the value. This is for canary
upgrade purpose.
nullable: true
type: object
name:
description: Name of the function.
type: string
type:
description: 'Type indicates whether this function reference is by name or selector. For now, the only supported reference type is by "name". Future reference types: * Function by label or annotation * Branch or tag of a versioned function * A "rolling upgrade" from one version of a function to another Available value: - name - function-weights'
description: 'Type indicates whether this function reference is
by name or selector. For now, the only supported reference type
is by "name". Future reference types: * Function by label or
annotation * Branch or tag of a versioned function * A "rolling
upgrade" from one version of a function to another Available
value: - name - function-weights'
type: string
required:
- name
@@ -66,9 +77,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
+28 -28
View File
@@ -33,28 +33,29 @@ require (
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.7.1
github.com/wcharczuk/go-chart v2.0.1+incompatible
go.opencensus.io v0.23.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0
go.opentelemetry.io/contrib/propagators/aws v1.4.0
go.opentelemetry.io/contrib/propagators/b3 v1.4.0
go.opentelemetry.io/contrib/propagators/jaeger v1.4.0
go.opentelemetry.io/contrib/propagators/ot v1.4.0
go.opentelemetry.io/otel v1.4.1
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1
go.opentelemetry.io/otel/sdk v1.4.1
go.opentelemetry.io/otel/trace v1.4.1
go.opentelemetry.io/contrib/propagators/aws v1.7.0
go.opentelemetry.io/contrib/propagators/b3 v1.7.0
go.opentelemetry.io/contrib/propagators/jaeger v1.7.0
go.opentelemetry.io/contrib/propagators/ot v1.7.0
go.opentelemetry.io/otel v1.7.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0
go.opentelemetry.io/otel/sdk v1.7.0
go.opentelemetry.io/otel/trace v1.7.0
go.uber.org/zap v1.21.0
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
google.golang.org/grpc v1.45.0
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
google.golang.org/grpc v1.47.0
k8s.io/api v0.23.4
k8s.io/apiextensions-apiserver v0.23.4
k8s.io/apimachinery v0.23.4
k8s.io/client-go v0.23.4
k8s.io/metrics v0.23.4
sigs.k8s.io/controller-runtime v0.10.2
sigs.k8s.io/yaml v1.2.0
)
require (
@@ -75,9 +76,9 @@ require (
github.com/andybalholm/brotli v1.0.1 // indirect
github.com/aws/aws-sdk-go v1.42.34 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blend/go-sdk v1.20220212.5 // indirect
github.com/blend/go-sdk v1.20220112.5 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/containerd/continuity v0.2.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
@@ -95,7 +96,7 @@ require (
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/go-ini/ini v1.66.4 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
@@ -106,11 +107,11 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
@@ -139,7 +140,7 @@ require (
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.0 // indirect
github.com/opencontainers/runc v1.1.2 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -153,33 +154,32 @@ require (
github.com/ulikunitz/xz v0.5.9 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
go.opentelemetry.io/otel/metric v0.27.0 // indirect
go.opentelemetry.io/proto/otlp v0.12.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.opentelemetry.io/proto/otlp v0.18.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 // indirect
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 // indirect
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
google.golang.org/api v0.62.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/protobuf v1.27.1 // indirect
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools v2.2.0+incompatible // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
+61 -49
View File
@@ -132,12 +132,12 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blend/go-sdk v1.20220212.5 h1:5+B+CCz8W5l3kHnBRfi5MyJAR0fYwEs2GzasYwNHPMU=
github.com/blend/go-sdk v1.20220212.5/go.mod h1:PGU9Tj6gMz5ow+tSoKSo6fdUSMRpgY4gucFQQyWCWx0=
github.com/blend/go-sdk v1.20220112.5 h1:M1H3KB++HyPAek31WH2HNut1Xg1SI7LyT9giNE2fcPQ=
github.com/blend/go-sdk v1.20220112.5/go.mod h1:STLiO8ZA8doHtRV7QfW2mXgH/8U+85GHY9ge3phM3dY=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -160,6 +160,7 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
@@ -227,6 +228,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -281,8 +283,9 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
@@ -319,6 +322,7 @@ github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -374,8 +378,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -425,8 +430,10 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3 h1:BGNSrTRW4rwfhJiFwvwF4XQ0Y72Jj9YEgxVrtovbD5o=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.3/go.mod h1:VHn7KgNsRriXa4mcgtkpR00OXyQY6g67JWMvn+R27A4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -610,8 +617,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v1.1.0 h1:O9+X96OcDjkmmZyfaG996kV7yq8HsoU2h1XRRQcefG8=
github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw=
github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
@@ -727,8 +734,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -784,25 +792,25 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0 h1:SLme4Porm+UwX0DdHMxlwRt7FzPSE0sys81bet2o0pU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII=
go.opentelemetry.io/contrib/propagators/aws v1.4.0 h1:NalFeGVKlXawC/9g+9Mu/FPngL1L8YdAiZrcN4sLzGs=
go.opentelemetry.io/contrib/propagators/aws v1.4.0/go.mod h1:JM5vN0iG8tDbrX6hIzcm/NKfzHs2qU2rsbl4YuZxTlU=
go.opentelemetry.io/contrib/propagators/b3 v1.4.0 h1:wDb2ct7xMzossYpx44w81skxkEyeT2IRnBgYKqyEork=
go.opentelemetry.io/contrib/propagators/b3 v1.4.0/go.mod h1:K399DN23drp0RQGXCbSPOt9075HopQigMgUL99oR8hc=
go.opentelemetry.io/contrib/propagators/jaeger v1.4.0 h1:nZZrtAz9Z0bXXJPB/p0uHIuk4am7LvkUUiuhulrhnjI=
go.opentelemetry.io/contrib/propagators/jaeger v1.4.0/go.mod h1:C6Tffii02q1NrEzJxpawJH1pyU3ZQ1520gCrxpNg7X4=
go.opentelemetry.io/contrib/propagators/ot v1.4.0 h1:sHp8P5+xmMORvsgKjIPPX4U97JUgSqY4xPWa6ncF1PA=
go.opentelemetry.io/contrib/propagators/ot v1.4.0/go.mod h1:FivzsGJqC7ND++UUOifWfkiuEOFXtVQ3fh2ZkqIJ9X4=
go.opentelemetry.io/contrib/propagators/aws v1.7.0 h1:hzLtX+K4YhsrBabA35uBYxCENb5rS/9Z9X8MToTlA3k=
go.opentelemetry.io/contrib/propagators/aws v1.7.0/go.mod h1:h/ql5T6e1XLRFplWNNdzLHp8eb0dkBu+xYOCYxerh0Q=
go.opentelemetry.io/contrib/propagators/b3 v1.7.0 h1:oRAenUhj+GFttfIp3gj7HYVzBhPOHgq/dWPDSmLCXSY=
go.opentelemetry.io/contrib/propagators/b3 v1.7.0/go.mod h1:gXx7AhL4xXCF42gpm9dQvdohoDa2qeyEx4eIIxqK+h4=
go.opentelemetry.io/contrib/propagators/jaeger v1.7.0 h1:x2mXKtONfOJFfNFSx4QXFx1fms6bKIPVvWvgdiaPdRI=
go.opentelemetry.io/contrib/propagators/jaeger v1.7.0/go.mod h1:kt2lNImfxV6dETRsDCENd6jU6G0mPRS+P0qlNuvtkTE=
go.opentelemetry.io/contrib/propagators/ot v1.7.0 h1:KPPToDRxyY/HI3qD4RqwWRbaQ65RIpF8uKWDqWkFHDA=
go.opentelemetry.io/contrib/propagators/ot v1.7.0/go.mod h1:5qxBZR730yb71uXc3bazxt2Si8o8LQK3iJTnSLca/BU=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
go.opentelemetry.io/otel v1.4.1 h1:QbINgGDDcoQUoMJa2mMaWno49lja9sHwp6aoa2n3a4g=
go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4=
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1 h1:imIM3vRDMyZK1ypQlQlO+brE22I9lRhJsBDXpDWjlz8=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.4.1/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1 h1:WPpPsAAs8I2rA47v5u0558meKmmwm1Dj99ZbqCV8sZ8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.4.1/go.mod h1:o5RW5o2pKpJLD5dNTCmjF1DorYwMeFJmb/rKr5sLaa8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1 h1:AxqDiGk8CorEXStMDZF5Hz9vo9Z7ZZ+I5m8JRl/ko40=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.4.1/go.mod h1:c6E4V3/U+miqjs/8l950wggHGL1qzlp0Ypj9xoGrPqo=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 h1:7Yxsak1q4XrJ5y7XBnNwqWx9amMZvoidCctv62XOQ6Y=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 h1:cMDtmgJ5FpRvqx9x2Aq+Mm0O6K/zcUkH73SFz20TuBw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 h1:MFAyzUPrTwLOwCi+cltN0ZVyy4phU41lwH+lyMyQTS4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o=
go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
@@ -810,28 +818,30 @@ go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1s
go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g=
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/sdk v1.4.0/go.mod h1:71GJPNJh4Qju6zJuYl1CrYtXbrgfau/M9UAggqiy1UE=
go.opentelemetry.io/otel/sdk v1.4.1 h1:J7EaW71E0v87qflB4cDolaqq3AcujGrtyIPGQoZOB0Y=
go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE=
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
go.opentelemetry.io/otel/trace v1.4.1 h1:O+16qcdTrT7zxv2J6GejTPFinSwA++cYerC5iSiF8EQ=
go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc=
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.12.0 h1:CMJ/3Wp7iOWES+CYLfnBv+DVmPbB+kmy9PJ92XvlR6c=
go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ=
go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80=
go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
@@ -951,8 +961,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -969,8 +979,9 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1070,8 +1081,8 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 h1:8IVLkfbr2cLhv0a/vKq4UFUcJym8RmDoDboxCFWEjYE=
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1160,7 +1171,6 @@ golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpd
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@@ -1267,8 +1277,8 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 h1:W70HjnmXFJm+8RNjOpIDYW2nKsSi/af0VvIZUtYkwuU=
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1296,10 +1306,10 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1313,8 +1323,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1348,8 +1359,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+5
View File
@@ -66,6 +66,11 @@ const (
StrategyTypeExecution = "execution"
)
const (
RuntimePodSpecConfigmap = "runtime-podspec-patch"
BuilderPodSpecConfigmap = "builder-podspec-patch"
)
const (
SharedVolumeUserfunc = "userfunc"
SharedVolumePackages = "packages"
+26 -19
View File
@@ -38,8 +38,8 @@ import (
const (
// supported environment variables
envSrcPkg = "SRC_PKG"
envDeployPkg = "DEPLOY_PKG"
envSrcPkg string = "SRC_PKG"
envDeployPkg string = "DEPLOY_PKG"
)
type (
@@ -114,16 +114,27 @@ func (builder *Builder) Handler(w http.ResponseWriter, r *http.Request) {
}
builder.logger.Info("builder received request", zap.Any("request", req))
builder.logger.Info("starting build")
builder.logger.Debug("starting build")
srcPkgPath := filepath.Join(builder.sharedVolumePath, req.SrcPkgFilename)
deployPkgFilename := fmt.Sprintf("%v-%v", req.SrcPkgFilename, strings.ToLower(uniuri.NewLen(6)))
deployPkgFilename := fmt.Sprintf("%s-%s", req.SrcPkgFilename, strings.ToLower(uniuri.NewLen(6)))
deployPkgPath := filepath.Join(builder.sharedVolumePath, deployPkgFilename)
var buildArgs []string
buildCmd := req.BuildCommand
if len(buildCmd) == 0 {
// use default build command
buildCmd = "/build"
} else {
// split executable command and arguments
args := strings.Split(buildCmd, " ")
buildCmd = args[0] // get the executable command, executable command will always be on Zero index
// get all the arguments
for i := 1; i < len(args); i++ {
buildArgs = append(buildArgs, args[i])
}
}
buildLogs, err := builder.build(buildCmd, srcPkgPath, deployPkgPath)
buildLogs, err := builder.build(buildCmd, buildArgs, srcPkgPath, deployPkgPath)
if err != nil {
e := "error building source package"
builder.logger.Error(e, zap.Error(err))
@@ -146,7 +157,7 @@ func (builder *Builder) reply(w http.ResponseWriter, pkgFilename string, buildLo
rBody, err := json.Marshal(resp)
if err != nil {
e := errors.Wrap(err, "error encoding response body")
rBody = []byte(fmt.Sprintf(`{"buildLogs": "%v"}`, e.Error()))
rBody = []byte(fmt.Sprintf(`{"buildLogs": "%s"}`, e.Error()))
statusCode = http.StatusInternalServerError
}
@@ -163,8 +174,8 @@ func (builder *Builder) reply(w http.ResponseWriter, pkgFilename string, buildLo
}
}
func (builder *Builder) build(command string, srcPkgPath string, deployPkgPath string) (string, error) {
cmd := exec.Command(command)
func (builder *Builder) build(command string, args []string, srcPkgPath string, deployPkgPath string) (string, error) {
cmd := exec.Command(command, args...)
fi, err := os.Stat(srcPkgPath)
if err != nil {
@@ -178,8 +189,8 @@ func (builder *Builder) build(command string, srcPkgPath string, deployPkgPath s
// set env variables for build command
cmd.Env = append(os.Environ(),
fmt.Sprintf("%v=%v", envSrcPkg, srcPkgPath),
fmt.Sprintf("%v=%v", envDeployPkg, deployPkgPath),
fmt.Sprintf("%s=%s", envSrcPkg, srcPkgPath),
fmt.Sprintf("%s=%s", envDeployPkg, deployPkgPath),
)
stdout, err := cmd.StdoutPipe()
@@ -192,12 +203,8 @@ func (builder *Builder) build(command string, srcPkgPath string, deployPkgPath s
return "", errors.Wrap(err, "error creating stderr pipe for cmd")
}
var buildLogs string
fmt.Printf("\n=== Build Logs ===")
// Init logs
fmt.Printf("command=%v\n", command)
fmt.Printf("env=%v\n", cmd.Env)
builder.logger.Info("building source package", zap.String("command", command), zap.Strings("args", args), zap.Strings("env", cmd.Env))
out := io.MultiReader(stdout, stderr)
scanner := bufio.NewScanner(out)
@@ -206,12 +213,14 @@ func (builder *Builder) build(command string, srcPkgPath string, deployPkgPath s
if err != nil {
return "", errors.Wrap(err, "error starting cmd")
}
fmt.Printf("========= START =========\n")
defer fmt.Printf("========= END ===========\n")
var buildLogs string
// Runtime logs
for scanner.Scan() {
output := scanner.Text()
fmt.Println(output)
buildLogs += fmt.Sprintf("%v\n", output)
buildLogs += fmt.Sprintf("%s\n", output)
}
if err := scanner.Err(); err != nil {
@@ -226,7 +235,5 @@ func (builder *Builder) build(command string, srcPkgPath string, deployPkgPath s
fmt.Println(cmdErr)
return buildLogs, cmdErr
}
fmt.Printf("==================\n")
return buildLogs, nil
}
+171
View File
@@ -0,0 +1,171 @@
/*
Copyright 2022 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 builder
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/fission/fission/pkg/utils/loggerfactory"
)
func TestBuilder(t *testing.T) {
logger := loggerfactory.GetLogger()
dir, err := os.MkdirTemp("/tmp", "fission-builder-test")
if err != nil {
t.Fatal(err)
}
builder := MakeBuilder(logger, dir)
// Test VersionHandler
t.Run("VersionHandler", func(t *testing.T) {
t.Run("should return version", func(t *testing.T) {
w := &httptest.ResponseRecorder{}
r := &http.Request{}
builder.VersionHandler(w, r)
if w.Result().StatusCode != http.StatusOK {
t.Errorf("expected status code %d, got %d", http.StatusOK, w.Result().StatusCode)
}
if w.Result().Body == nil {
t.Error("expected body, got nil")
}
})
})
// Test BuildHandler
t.Run("BuildHandler", func(t *testing.T) {
for _, test := range []struct {
name string
buildRequest *PackageBuildRequest
expected *PackageBuildResponse
status int
}{
{
name: "should work with build command without argument",
buildRequest: &PackageBuildRequest{
SrcPkgFilename: "test",
BuildCommand: "ls",
},
expected: &PackageBuildResponse{
ArtifactFilename: "test",
BuildLogs: "",
},
status: http.StatusOK,
},
{
name: "should work with build command with argument",
buildRequest: &PackageBuildRequest{
SrcPkgFilename: "test1",
BuildCommand: "ls -la",
},
expected: &PackageBuildResponse{
ArtifactFilename: "test1",
BuildLogs: "",
},
status: http.StatusOK,
},
{
name: "should fail with argument and pipe",
buildRequest: &PackageBuildRequest{
SrcPkgFilename: "test2",
BuildCommand: "ps -ef | grep fission",
},
expected: &PackageBuildResponse{
ArtifactFilename: "test2",
BuildLogs: "",
},
status: http.StatusInternalServerError,
},
{
name: "should fail with invalid build command",
buildRequest: &PackageBuildRequest{
SrcPkgFilename: "test3",
BuildCommand: "lsalas -la",
},
expected: &PackageBuildResponse{
ArtifactFilename: "test3",
BuildLogs: "",
},
status: http.StatusInternalServerError,
},
{
name: "should fail with valid command and invalid argument",
buildRequest: &PackageBuildRequest{
SrcPkgFilename: "test3",
BuildCommand: "ls --la",
},
expected: &PackageBuildResponse{
ArtifactFilename: "test3",
BuildLogs: "",
},
status: http.StatusInternalServerError,
},
} {
t.Run(test.name, func(t *testing.T) {
srcFile, err := os.Create(dir + "/" + test.buildRequest.SrcPkgFilename)
if err != nil {
t.Fatal(err)
}
defer srcFile.Close()
body, err := json.Marshal(test.buildRequest)
if err != nil {
t.Fatal(err)
}
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(body))
builder.Handler(w, r)
resp := w.Result()
if resp.StatusCode != test.status {
t.Errorf("expected status code %d, got %d", test.status, resp.StatusCode)
}
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
var buildResp PackageBuildResponse
err = json.Unmarshal(body, &buildResp)
if err != nil {
t.Fatal(err)
}
if test.status == http.StatusOK {
if strings.Contains(buildResp.BuildLogs, "error") {
t.Errorf("expected build logs to not contain error, got %s", buildResp.BuildLogs)
}
artifacts := strings.Split(buildResp.ArtifactFilename, "-")
if len(artifacts) != 2 {
t.Errorf("expected artifact filename to be of the form <pkgname>-<build-id>, got %s", buildResp.ArtifactFilename)
}
if artifacts[0] != test.expected.ArtifactFilename {
t.Errorf("expected artifact filename to be %s, got %s", test.expected.ArtifactFilename, artifacts[0])
}
} else {
if !strings.Contains(buildResp.BuildLogs, "error") {
t.Errorf("expected build logs to contain error, got %s", buildResp.BuildLogs)
}
}
})
}
})
}
+16 -1
View File
@@ -22,11 +22,15 @@ import (
"github.com/pkg/errors"
"go.uber.org/zap"
apiv1 "k8s.io/api/core/v1"
k8sInformers "k8s.io/client-go/informers"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/crd"
"github.com/fission/fission/pkg/executor/util"
fetcherConfig "github.com/fission/fission/pkg/fetcher/config"
genInformer "github.com/fission/fission/pkg/generated/informers/externalversions"
"github.com/fission/fission/pkg/utils"
)
// Start the buildermgr service.
@@ -48,7 +52,18 @@ func Start(ctx context.Context, logger *zap.Logger, storageSvcUrl string, envBui
return errors.Wrap(err, "error making fetcher config")
}
envWatcher := makeEnvironmentWatcher(bmLogger, fissionClient, kubernetesClient, fetcherConfig, envBuilderNamespace)
var podSpecPatch *apiv1.PodSpec
namespace, err := utils.GetCurrentNamespace()
if err != nil {
logger.Warn("Current namespace not found %v", zap.Error(err))
} else {
podSpecPatch, err = util.GetSpecFromConfigMap(ctx, kubernetesClient, fv1.BuilderPodSpecConfigmap, namespace)
if err != nil {
logger.Warn("Either configmap is not found or error reading data %v", zap.Error(err))
}
}
envWatcher := makeEnvironmentWatcher(bmLogger, fissionClient, kubernetesClient, fetcherConfig, envBuilderNamespace, podSpecPatch)
go envWatcher.watchEnvironments()
k8sInformerFactory := k8sInformers.NewSharedInformerFactory(kubernetesClient, time.Minute*30)
+14 -1
View File
@@ -87,6 +87,7 @@ type (
fetcherConfig *fetcherConfig.Config
builderImagePullPolicy apiv1.PullPolicy
useIstio bool
podSpecPatch *apiv1.PodSpec
}
)
@@ -95,7 +96,8 @@ func makeEnvironmentWatcher(
fissionClient versioned.Interface,
kubernetesClient kubernetes.Interface,
fetcherConfig *fetcherConfig.Config,
builderNamespace string) *environmentWatcher {
builderNamespace string,
podSpecPatch *apiv1.PodSpec) *environmentWatcher {
useIstio := false
enableIstio := os.Getenv("ENABLE_ISTIO")
@@ -119,6 +121,7 @@ func makeEnvironmentWatcher(
builderImagePullPolicy: builderImagePullPolicy,
useIstio: useIstio,
fetcherConfig: fetcherConfig,
podSpecPatch: podSpecPatch,
}
go envWatcher.service()
@@ -503,6 +506,16 @@ func (envw *environmentWatcher) createBuilderDeployment(env *fv1.Environment, ns
},
}
if envw.podSpecPatch != nil {
updatedPodSpec, err := util.MergePodSpec(&pod.Spec, envw.podSpecPatch)
if err == nil {
pod.Spec = *updatedPodSpec
} else {
envw.logger.Warn("Failed to merge the specs: %v", zap.Error(err))
}
}
pod.Spec = *(util.ApplyImagePullSecret(env.Spec.ImagePullSecret, pod.Spec))
deployment := &appsv1.Deployment{
+1 -1
View File
@@ -77,7 +77,7 @@ func (executor *Executor) getServiceForFunctionAPI(w http.ResponseWriter, r *htt
if err == nil {
// if a pod is already serving request then it already exists else validated
logger.Debug("from cache", zap.Int("active", active))
if active > 1 || et.IsValid(ctx, fsvc) {
if et.IsValid(ctx, fsvc) {
// Cached, return svc address
logger.Debug("served from cache", zap.String("name", fsvc.Name), zap.String("address", fsvc.Address))
executor.writeResponse(w, fsvc.Address, fn.ObjectMeta.Name)
+14 -2
View File
@@ -28,6 +28,7 @@ import (
"github.com/dchest/uniuri"
"github.com/pkg/errors"
"go.uber.org/zap"
apiv1 "k8s.io/api/core/v1"
k8sInformers "k8s.io/client-go/informers"
k8sCache "k8s.io/client-go/tools/cache"
@@ -270,6 +271,17 @@ func StartExecutor(ctx context.Context, logger *zap.Logger, functionNamespace st
executorInstanceID := strings.ToLower(uniuri.NewLen(8))
var podSpecPatch *apiv1.PodSpec
namespace, err := utils.GetCurrentNamespace()
if err != nil {
logger.Warn("Current namespace not found %s", zap.Error(err))
} else {
podSpecPatch, err = util.GetSpecFromConfigMap(ctx, kubernetesClient, fv1.RuntimePodSpecConfigmap, namespace)
if err != nil {
logger.Warn("Either configmap is not found or error reading data %v", zap.Error(err))
}
}
logger.Info("Starting executor", zap.String("instanceID", executorInstanceID))
informerFactory := genInformer.NewSharedInformerFactory(fissionClient, time.Minute*30)
@@ -288,7 +300,7 @@ func StartExecutor(ctx context.Context, logger *zap.Logger, functionNamespace st
fissionClient, kubernetesClient, metricsClient,
functionNamespace, fetcherConfig, executorInstanceID,
funcInformer, pkgInformer, envInformer,
gpmPodInformer, gpmRsInformer)
gpmPodInformer, gpmRsInformer, podSpecPatch)
if err != nil {
return errors.Wrap(err, "pool manager creation failed")
}
@@ -304,7 +316,7 @@ func StartExecutor(ctx context.Context, logger *zap.Logger, functionNamespace st
fissionClient, kubernetesClient,
functionNamespace, fetcherConfig, executorInstanceID,
funcInformer, envInformer,
ndmDeplInformer, ndmSvcInformer)
ndmDeplInformer, ndmSvcInformer, podSpecPatch)
if err != nil {
return errors.Wrap(err, "new deploy manager creation failed")
}
@@ -34,6 +34,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
k8sTypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
appsinformers "k8s.io/client-go/informers/apps/v1"
coreinformers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
@@ -141,7 +142,7 @@ func (caaf *Container) Run(ctx context.Context) {
if ok := k8sCache.WaitForCacheSync(ctx.Done(), caaf.deplListerSynced, caaf.svcListerSynced); !ok {
caaf.logger.Fatal("failed to wait for caches to sync")
}
go caaf.idleObjectReaper()
go caaf.idleObjectReaper(ctx)
}
// GetTypeName returns the executor type name.
@@ -168,7 +169,7 @@ func (caaf *Container) GetFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
// GetFuncSvcFromCache returns a function service from cache; error otherwise.
func (caaf *Container) GetFuncSvcFromCache(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
otelUtils.SpanTrackEvent(ctx, "GetFuncSvcFromCache", otelUtils.GetAttributesForFunction(fn)...)
return caaf.fsCache.GetByFunction(&fn.ObjectMeta)
return caaf.fsCache.GetByFunctionUID(fn.UID)
}
// DeleteFuncSvcFromCache deletes a function service from cache.
@@ -703,73 +704,71 @@ func (caaf *Container) updateStatus(fn *fv1.Function, err error, message string)
}
// idleObjectReaper reaps objects after certain idle time
func (caaf *Container) idleObjectReaper() {
ctx := context.Background()
func (caaf *Container) idleObjectReaper(ctx context.Context) {
// calling function doIdleObjectReaper() repeatedly at given interval of time
wait.UntilWithContext(ctx, caaf.doIdleObjectReaper, time.Second*5)
}
pollSleep := 5 * time.Second
for {
time.Sleep(pollSleep)
func (caaf *Container) doIdleObjectReaper(ctx context.Context) {
funcSvcs, err := caaf.fsCache.ListOld(time.Second * 5)
if err != nil {
caaf.logger.Error("error reaping idle pods", zap.Error(err))
return
}
funcSvcs, err := caaf.fsCache.ListOld(pollSleep)
if err != nil {
caaf.logger.Error("error reaping idle pods", zap.Error(err))
for i := range funcSvcs {
fsvc := funcSvcs[i]
if fsvc.Executor != fv1.ExecutorTypeContainer {
continue
}
for i := range funcSvcs {
fsvc := funcSvcs[i]
if fsvc.Executor != fv1.ExecutorTypeContainer {
fn, err := caaf.fissionClient.CoreV1().Functions(fsvc.Function.Namespace).Get(ctx, fsvc.Function.Name, metav1.GetOptions{})
if err != nil {
// CaaF manager handles the function delete event and clean cache/kubeobjs itself,
// so we ignore the not found error for functions with CaaF executor type here.
if k8sErrs.IsNotFound(err) && fsvc.Executor == fv1.ExecutorTypeContainer {
continue
}
fn, err := caaf.fissionClient.CoreV1().Functions(fsvc.Function.Namespace).Get(ctx, fsvc.Function.Name, metav1.GetOptions{})
if err != nil {
// CaaF manager handles the function delete event and clean cache/kubeobjs itself,
// so we ignore the not found error for functions with CaaF executor type here.
if k8sErrs.IsNotFound(err) && fsvc.Executor == fv1.ExecutorTypeContainer {
continue
}
caaf.logger.Error("error getting function", zap.Error(err), zap.String("function", fsvc.Function.Name))
continue
}
idlePodReapTime := caaf.defaultIdlePodReapTime
if fn.Spec.IdleTimeout != nil {
idlePodReapTime = time.Duration(*fn.Spec.IdleTimeout) * time.Second
}
if time.Since(fsvc.Atime) < idlePodReapTime {
continue
}
go func() {
deployObj := getDeploymentObj(fsvc.KubernetesObjects)
if deployObj == nil {
caaf.logger.Error("error finding function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
currentDeploy, err := caaf.kubernetesClient.AppsV1().
Deployments(deployObj.Namespace).Get(ctx, deployObj.Name, metav1.GetOptions{})
if err != nil {
caaf.logger.Error("error getting function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
minScale := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
// do nothing if the current replicas is already lower than minScale
if *currentDeploy.Spec.Replicas <= minScale {
return
}
err = caaf.scaleDeployment(ctx, deployObj.Namespace, deployObj.Name, minScale)
if err != nil {
caaf.logger.Error("error scaling down function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
}
}()
caaf.logger.Error("error getting function", zap.Error(err), zap.String("function", fsvc.Function.Name))
continue
}
idlePodReapTime := caaf.defaultIdlePodReapTime
if fn.Spec.IdleTimeout != nil {
idlePodReapTime = time.Duration(*fn.Spec.IdleTimeout) * time.Second
}
if time.Since(fsvc.Atime) < idlePodReapTime {
continue
}
go func() {
deployObj := getDeploymentObj(fsvc.KubernetesObjects)
if deployObj == nil {
caaf.logger.Error("error finding function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
currentDeploy, err := caaf.kubernetesClient.AppsV1().
Deployments(deployObj.Namespace).Get(ctx, deployObj.Name, metav1.GetOptions{})
if err != nil {
caaf.logger.Error("error getting function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
minScale := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
// do nothing if the current replicas is already lower than minScale
if *currentDeploy.Spec.Replicas <= minScale {
return
}
err = caaf.scaleDeployment(ctx, deployObj.Namespace, deployObj.Name, minScale)
if err != nil {
caaf.logger.Error("error scaling down function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
}
}()
}
}
@@ -278,6 +278,16 @@ func (deploy *NewDeploy) getDeploymentSpec(ctx context.Context, fn *fv1.Function
},
}
if deploy.podSpecPatch != nil {
updatedPodSpec, err := util.MergePodSpec(&pod.Spec, deploy.podSpecPatch)
if err == nil {
pod.Spec = *updatedPodSpec
} else {
deploy.logger.Warn("Failed to merge the specs: %v", zap.Error(err))
}
}
pod.Spec = *(util.ApplyImagePullSecret(env.Spec.ImagePullSecret, pod.Spec))
deployment := &appsv1.Deployment{
@@ -35,6 +35,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
k8sTypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
appsinformers "k8s.io/client-go/informers/apps/v1"
coreinformers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
@@ -86,6 +87,8 @@ type (
svcListerSynced k8sCache.InformerSynced
hpaops *hpautils.HpaOperations
podSpecPatch *apiv1.PodSpec
}
)
@@ -101,6 +104,7 @@ func MakeNewDeploy(
envInformer finformerv1.EnvironmentInformer,
deplInformer appsinformers.DeploymentInformer,
svcInformer coreinformers.ServiceInformer,
podSpecPatch *apiv1.PodSpec,
) (executortype.ExecutorType, error) {
enableIstio := false
if len(os.Getenv("ENABLE_ISTIO")) > 0 {
@@ -129,6 +133,8 @@ func MakeNewDeploy(
defaultIdlePodReapTime: 2 * time.Minute,
hpaops: hpautils.NewHpaOperations(logger, kubernetesClient, instanceID),
podSpecPatch: podSpecPatch,
}
nd.deplLister = deplInformer.Lister()
@@ -164,7 +170,7 @@ func (deploy *NewDeploy) GetFuncSvc(ctx context.Context, fn *fv1.Function) (*fsc
// GetFuncSvcFromCache returns a function service from cache; error otherwise.
func (deploy *NewDeploy) GetFuncSvcFromCache(ctx context.Context, fn *fv1.Function) (*fscache.FuncSvc, error) {
otelUtils.SpanTrackEvent(ctx, "GetFuncSvcFromCache")
return deploy.fsCache.GetByFunction(&fn.ObjectMeta)
return deploy.fsCache.GetByFunctionUID(fn.UID)
}
// DeleteFuncSvcFromCache deletes a function service from cache.
@@ -588,6 +594,7 @@ func (deploy *NewDeploy) updateFunction(ctx context.Context, oldFn *fv1.Function
if oldFn.Spec.Environment != newFn.Spec.Environment ||
oldFn.Spec.Package.PackageRef != newFn.Spec.Package.PackageRef ||
oldFn.Spec.Package.FunctionName != newFn.Spec.Package.FunctionName {
deploy.logger.Debug("deployment changed", zap.String("msg", "deployment changed"))
deployChanged = true
}
@@ -761,88 +768,87 @@ func (deploy *NewDeploy) updateStatus(fn *fv1.Function, err error, message strin
// idleObjectReaper reaps objects after certain idle time
func (deploy *NewDeploy) idleObjectReaper(ctx context.Context) {
pollSleep := 5 * time.Second
for {
time.Sleep(pollSleep)
// calling function doIdleObjectReaper() repeatedly at given interval of time
wait.UntilWithContext(ctx, deploy.doIdleObjectReaper, time.Second*5)
}
envs, err := deploy.fissionClient.CoreV1().Environments(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
deploy.logger.Fatal("failed to get environment list", zap.Error(err))
}
func (deploy *NewDeploy) doIdleObjectReaper(ctx context.Context) {
envs, err := deploy.fissionClient.CoreV1().Environments(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
deploy.logger.Fatal("failed to get environment list", zap.Error(err))
}
envList := make(map[k8sTypes.UID]struct{})
for _, env := range envs.Items {
envList[env.ObjectMeta.UID] = struct{}{}
}
envList := make(map[k8sTypes.UID]struct{})
for _, env := range envs.Items {
envList[env.ObjectMeta.UID] = struct{}{}
}
funcSvcs, err := deploy.fsCache.ListOld(pollSleep)
if err != nil {
deploy.logger.Error("error reaping idle pods", zap.Error(err))
funcSvcs, err := deploy.fsCache.ListOld(time.Second * 5)
if err != nil {
deploy.logger.Error("error reaping idle pods", zap.Error(err))
return
}
for i := range funcSvcs {
fsvc := funcSvcs[i]
if fsvc.Executor != fv1.ExecutorTypeNewdeploy {
continue
}
for i := range funcSvcs {
fsvc := funcSvcs[i]
if fsvc.Executor != fv1.ExecutorTypeNewdeploy {
continue
}
// For function with the environment that no longer exists, executor
// scales down the deployment as usual and prints log to notify user.
if _, ok := envList[fsvc.Environment.ObjectMeta.UID]; !ok {
deploy.logger.Warn("function environment no longer exists",
zap.String("environment", fsvc.Environment.ObjectMeta.Name),
zap.String("function", fsvc.Name))
}
fn, err := deploy.fissionClient.CoreV1().Functions(fsvc.Function.Namespace).Get(ctx, fsvc.Function.Name, metav1.GetOptions{})
if err != nil {
// Newdeploy manager handles the function delete event and clean cache/kubeobjs itself,
// so we ignore the not found error for functions with newdeploy executor type here.
if k8sErrs.IsNotFound(err) && fsvc.Executor == fv1.ExecutorTypeNewdeploy {
continue
}
deploy.logger.Error("error getting function", zap.Error(err), zap.String("function", fsvc.Function.Name))
continue
}
idlePodReapTime := deploy.defaultIdlePodReapTime
if fn.Spec.IdleTimeout != nil {
idlePodReapTime = time.Duration(*fn.Spec.IdleTimeout) * time.Second
}
if time.Since(fsvc.Atime) < idlePodReapTime {
continue
}
go func() {
deployObj := getDeploymentObj(fsvc.KubernetesObjects)
if deployObj == nil {
deploy.logger.Error("error finding function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
currentDeploy, err := deploy.kubernetesClient.AppsV1().
Deployments(deployObj.Namespace).Get(ctx, deployObj.Name, metav1.GetOptions{})
if err != nil {
deploy.logger.Error("error getting function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
minScale := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
// do nothing if the current replicas is already lower than minScale
if *currentDeploy.Spec.Replicas <= minScale {
return
}
err = deploy.scaleDeployment(ctx, deployObj.Namespace, deployObj.Name, minScale)
if err != nil {
deploy.logger.Error("error scaling down function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
}
}()
// For function with the environment that no longer exists, executor
// scales down the deployment as usual and prints log to notify user.
if _, ok := envList[fsvc.Environment.ObjectMeta.UID]; !ok {
deploy.logger.Warn("function environment no longer exists",
zap.String("environment", fsvc.Environment.ObjectMeta.Name),
zap.String("function", fsvc.Name))
}
fn, err := deploy.fissionClient.CoreV1().Functions(fsvc.Function.Namespace).Get(ctx, fsvc.Function.Name, metav1.GetOptions{})
if err != nil {
// Newdeploy manager handles the function delete event and clean cache/kubeobjs itself,
// so we ignore the not found error for functions with newdeploy executor type here.
if k8sErrs.IsNotFound(err) && fsvc.Executor == fv1.ExecutorTypeNewdeploy {
continue
}
deploy.logger.Error("error getting function", zap.Error(err), zap.String("function", fsvc.Function.Name))
continue
}
idlePodReapTime := deploy.defaultIdlePodReapTime
if fn.Spec.IdleTimeout != nil {
idlePodReapTime = time.Duration(*fn.Spec.IdleTimeout) * time.Second
}
if time.Since(fsvc.Atime) < idlePodReapTime {
continue
}
go func() {
deployObj := getDeploymentObj(fsvc.KubernetesObjects)
if deployObj == nil {
deploy.logger.Error("error finding function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
currentDeploy, err := deploy.kubernetesClient.AppsV1().
Deployments(deployObj.Namespace).Get(ctx, deployObj.Name, metav1.GetOptions{})
if err != nil {
deploy.logger.Error("error getting function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
return
}
minScale := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale)
// do nothing if the current replicas is already lower than minScale
if *currentDeploy.Spec.Replicas <= minScale {
return
}
err = deploy.scaleDeployment(ctx, deployObj.Namespace, deployObj.Name, minScale)
if err != nil {
deploy.logger.Error("error scaling down function deployment", zap.Error(err), zap.String("function", fsvc.Function.Name))
}
}()
}
}
+4 -1
View File
@@ -78,6 +78,7 @@ type (
readyPodQueue workqueue.DelayingInterface
poolInstanceID string // small random string to uniquify pod names
instanceID string // poolmgr instance id
podSpecPatch *apiv1.PodSpec
// TODO: move this field into fsCache
podFSVCMap sync.Map
}
@@ -95,7 +96,8 @@ func MakeGenericPool(
fsCache *fscache.FunctionServiceCache,
fetcherConfig *fetcherConfig.Config,
instanceID string,
enableIstio bool) *GenericPool {
enableIstio bool,
podSpecPatch *apiv1.PodSpec) *GenericPool {
gpLogger := logger.Named("generic_pool")
@@ -130,6 +132,7 @@ func MakeGenericPool(
poolInstanceID: uniuri.NewLen(8),
instanceID: instanceID,
podFSVCMap: sync.Map{},
podSpecPatch: podSpecPatch,
}
gp.runtimeImagePullPolicy = utils.GetImagePullPolicy(os.Getenv("RUNTIME_IMAGE_PULL_POLICY"))
@@ -150,6 +150,16 @@ func (gp *GenericPool) genDeploymentSpec(env *fv1.Environment) (*appsv1.Deployme
},
}
if gp.podSpecPatch != nil {
updatedPodSpec, err := util.MergePodSpec(&pod.Spec, gp.podSpecPatch)
if err == nil {
pod.Spec = *updatedPodSpec
} else {
gp.logger.Warn("Failed to merge the specs: %v", zap.Error(err))
}
}
pod.Spec = *(util.ApplyImagePullSecret(env.Spec.ImagePullSecret, pod.Spec))
poolsize := getEnvPoolSize(env)
+76 -73
View File
@@ -35,6 +35,7 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
k8sTypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
appsinformers "k8s.io/client-go/informers/apps/v1"
coreinformers "k8s.io/client-go/informers/core/v1"
@@ -92,6 +93,8 @@ type (
defaultIdlePodReapTime time.Duration
poolPodC *PoolPodController
podSpecPatch *apiv1.PodSpec
}
request struct {
requestType
@@ -119,6 +122,7 @@ func MakeGenericPoolManager(
envInformer finformerv1.EnvironmentInformer,
podInformer coreinformers.PodInformer,
rsInformer appsinformers.ReplicaSetInformer,
podSpecPatch *apiv1.PodSpec,
) (executortype.ExecutorType, error) {
gpmLogger := logger.Named("generic_pool_manager")
@@ -150,6 +154,7 @@ func MakeGenericPoolManager(
fetcherConfig: fetcherConfig,
enableIstio: enableIstio,
poolPodC: poolPodC,
podSpecPatch: podSpecPatch,
}
gpm.podLister = podInformer.Lister()
gpm.podListerSynced = podInformer.Informer().HasSynced
@@ -165,7 +170,7 @@ func (gpm *GenericPoolManager) Run(ctx context.Context) {
gpm.poolPodC.InjectGpm(gpm)
go gpm.WebsocketStartEventChecker(gpm.kubernetesClient)
go gpm.NoActiveConnectionEventChecker(gpm.kubernetesClient)
go gpm.idleObjectReaper()
go gpm.idleObjectReaper(ctx)
go gpm.poolPodC.Run(ctx.Done())
}
@@ -476,7 +481,7 @@ func (gpm *GenericPoolManager) service() {
}
pool = MakeGenericPool(gpm.logger, gpm.fissionClient, gpm.kubernetesClient,
gpm.metricsClient, req.env, ns, gpm.namespace, gpm.fsCache,
gpm.fetcherConfig, gpm.instanceID, gpm.enableIstio)
gpm.fetcherConfig, gpm.instanceID, gpm.enableIstio, gpm.podSpecPatch)
err = pool.setup(req.ctx)
if err != nil {
req.responseChannel <- &response{error: err}
@@ -565,95 +570,93 @@ func (gpm *GenericPoolManager) getFunctionEnv(ctx context.Context, fn *fv1.Funct
}
// idleObjectReaper reaps objects after certain idle time
func (gpm *GenericPoolManager) idleObjectReaper() {
ctx := context.Background()
pollSleep := 5 * time.Second
func (gpm *GenericPoolManager) idleObjectReaper(ctx context.Context) {
// calling function doIdleObjectReaper() repeatedly at given interval of time
wait.UntilWithContext(ctx, gpm.doIdleObjectReaper, time.Second*5)
}
for {
time.Sleep(pollSleep)
func (gpm *GenericPoolManager) doIdleObjectReaper(ctx context.Context) {
envs, err := gpm.fissionClient.CoreV1().Environments(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
gpm.logger.Error("failed to get environment list", zap.Error(err))
return
}
envs, err := gpm.fissionClient.CoreV1().Environments(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
gpm.logger.Error("failed to get environment list", zap.Error(err))
envList := make(map[k8sTypes.UID]struct{})
for _, env := range envs.Items {
envList[env.ObjectMeta.UID] = struct{}{}
}
fns, err := gpm.fissionClient.CoreV1().Functions(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
gpm.logger.Error("failed to get environment list", zap.Error(err))
return
}
fnList := make(map[k8sTypes.UID]fv1.Function)
for i, fn := range fns.Items {
fnList[fn.ObjectMeta.UID] = fns.Items[i]
}
funcSvcs, err := gpm.fsCache.ListOldForPool(time.Second * 5)
if err != nil {
gpm.logger.Error("error reaping idle pods", zap.Error(err))
return
}
for i := range funcSvcs {
fsvc := funcSvcs[i]
if fsvc.Executor != fv1.ExecutorTypePoolmgr {
continue
}
envList := make(map[k8sTypes.UID]struct{})
for _, env := range envs.Items {
envList[env.ObjectMeta.UID] = struct{}{}
if _, ok := gpm.fsCache.WebsocketFsvc.Load(fsvc.Name); ok {
continue
}
// For function with the environment that no longer exists, executor
// cleanups the idle pod as usual and prints log to notify user.
if _, ok := envList[fsvc.Environment.ObjectMeta.UID]; !ok {
gpm.logger.Warn("function environment no longer exists",
zap.String("environment", fsvc.Environment.ObjectMeta.Name),
zap.String("function", fsvc.Name))
}
fns, err := gpm.fissionClient.CoreV1().Functions(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
gpm.logger.Error("failed to get environment list", zap.Error(err))
if fsvc.Environment.Spec.AllowedFunctionsPerContainer == fv1.AllowedFunctionsPerContainerInfinite {
continue
}
fnList := make(map[k8sTypes.UID]fv1.Function)
for i, fn := range fns.Items {
fnList[fn.ObjectMeta.UID] = fns.Items[i]
idlePodReapTime := gpm.defaultIdlePodReapTime
if fn, ok := fnList[fsvc.Function.UID]; ok {
if fn.Spec.IdleTimeout != nil {
idlePodReapTime = time.Duration(*fn.Spec.IdleTimeout) * time.Second
}
}
funcSvcs, err := gpm.fsCache.ListOldForPool(pollSleep)
if err != nil {
gpm.logger.Error("error reaping idle pods", zap.Error(err))
if time.Since(fsvc.Atime) < idlePodReapTime {
continue
}
for i := range funcSvcs {
fsvc := funcSvcs[i]
if fsvc.Executor != fv1.ExecutorTypePoolmgr {
continue
go func() {
deleted, err := gpm.fsCache.DeleteOldPoolCache(ctx, fsvc, idlePodReapTime)
if err != nil {
gpm.logger.Error("error deleting Kubernetes objects for function service",
zap.Error(err),
zap.Any("service", fsvc))
}
if _, ok := gpm.fsCache.WebsocketFsvc.Load(fsvc.Name); ok {
continue
}
// For function with the environment that no longer exists, executor
// cleanups the idle pod as usual and prints log to notify user.
if _, ok := envList[fsvc.Environment.ObjectMeta.UID]; !ok {
gpm.logger.Warn("function environment no longer exists",
zap.String("environment", fsvc.Environment.ObjectMeta.Name),
zap.String("function", fsvc.Name))
}
if fsvc.Environment.Spec.AllowedFunctionsPerContainer == fv1.AllowedFunctionsPerContainerInfinite {
continue
}
idlePodReapTime := gpm.defaultIdlePodReapTime
if fn, ok := fnList[fsvc.Function.UID]; ok {
if fn.Spec.IdleTimeout != nil {
idlePodReapTime = time.Duration(*fn.Spec.IdleTimeout) * time.Second
if deleted {
for i := range fsvc.KubernetesObjects {
gpm.logger.Info("release idle function resources",
zap.String("function", fsvc.Function.Name),
zap.String("address", fsvc.Address),
zap.String("executor", string(fsvc.Executor)),
zap.String("pod", fsvc.Name),
)
reaper.CleanupKubeObject(ctx, gpm.logger, gpm.kubernetesClient, &fsvc.KubernetesObjects[i])
time.Sleep(50 * time.Millisecond)
}
}
if time.Since(fsvc.Atime) < idlePodReapTime {
continue
}
go func() {
deleted, err := gpm.fsCache.DeleteOldPoolCache(ctx, fsvc, idlePodReapTime)
if err != nil {
gpm.logger.Error("error deleting Kubernetes objects for function service",
zap.Error(err),
zap.Any("service", fsvc))
}
if deleted {
for i := range fsvc.KubernetesObjects {
gpm.logger.Info("release idle function resources",
zap.String("function", fsvc.Function.Name),
zap.String("address", fsvc.Address),
zap.String("executor", string(fsvc.Executor)),
zap.String("pod", fsvc.Name),
)
reaper.CleanupKubeObject(ctx, gpm.logger, gpm.kubernetesClient, &fsvc.KubernetesObjects[i])
time.Sleep(50 * time.Millisecond)
}
}
}()
}
}()
}
}
@@ -78,7 +78,7 @@ func TestPoolPodControllerPodCleanup(t *testing.T) {
fissionClient, kubernetesClient, metricsClient,
fnNamespace, fetcherConfig, executorInstanceID,
funcInformer, pkgInformer, envInformer,
gpmPodInformer, gpmRsInformer)
gpmPodInformer, gpmRsInformer, nil)
if err != nil {
t.Fatalf("Error creating generic pool manager: %v", err)
}
+8 -2
View File
@@ -130,10 +130,16 @@ func (fsc *FunctionServiceCache) service() {
resp.error = fsc._touchByAddress(req.address)
case LISTOLD:
// get svcs idle for > req.age
fscs := fsc.byFunction.Copy()
fscs := fsc.byFunctionUID.Copy()
funcObjects := make([]*FuncSvc, 0)
for _, funcSvc := range fscs {
fsvc := funcSvc.(*FuncSvc)
mI := funcSvc.(metav1.ObjectMeta)
fsvcI, err := fsc.byFunction.Get(crd.CacheKey(&mI))
if err != nil {
fsc.logger.Error("error while getting service", zap.Any("error", err))
return
}
fsvc := fsvcI.(*FuncSvc)
if time.Since(fsvc.Atime) > req.age {
funcObjects = append(funcObjects, fsvc)
}
+1 -1
View File
@@ -29,7 +29,7 @@ var (
ColdStarts = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "fission_function_cold_starts_total",
Help: "How many cold starts are made by function_name, function_uid.",
Help: "How many cold starts are made by function_name, function_namespace.",
},
functionLabels,
)
+15
View File
@@ -25,6 +25,7 @@ import (
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/yaml"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
)
@@ -113,3 +114,17 @@ func ConvertConfigSecrets(ctx context.Context, fn *fv1.Function, kc kubernetes.I
}
return envFromSources, nil
}
func GetSpecFromConfigMap(ctx context.Context, kubeClient kubernetes.Interface, cm string, cmns string) (*apiv1.PodSpec, error) {
podSpecPatch, err := kubeClient.CoreV1().ConfigMaps(cmns).Get(ctx, cm, metav1.GetOptions{})
if err != nil {
return nil, err
}
var additionalSpec apiv1.PodSpec
err = yaml.Unmarshal([]byte(podSpecPatch.Data["spec"]), &additionalSpec)
return &additionalSpec, err
}
+114
View File
@@ -0,0 +1,114 @@
/*
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 util
import (
"context"
"reflect"
"testing"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
)
func TestGetSpecFromConfigMap(t *testing.T) {
kubeClient := fake.NewSimpleClientset()
var permissionNum int64 = 10001
var runAsNonRoot bool = true
configMapData := make(map[string]string, 0)
specPatch := `
securityContext:
fsGroup: 10001
runAsGroup: 10001
runAsNonRoot: true
runAsUser: 10001`
configMapData["spec"] = specPatch
testConfigMap := apiv1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-config-map",
Namespace: "fission",
},
Data: configMapData,
}
configmap, err := kubeClient.CoreV1().ConfigMaps("fission").Create(context.Background(), &testConfigMap, metav1.CreateOptions{})
if err != nil {
t.Errorf("Error creating configmap %v", err)
}
t.Logf("Configmap: %v", configmap.Data)
testSpecPatch := apiv1.PodSpec{
SecurityContext: &apiv1.PodSecurityContext{
FSGroup: &permissionNum,
RunAsGroup: &permissionNum,
RunAsNonRoot: &runAsNonRoot,
RunAsUser: &permissionNum,
},
}
tests := []struct {
name string
cm string
cmns string
want *apiv1.PodSpec
wantErr bool
}{
{
name: "Configmap exists",
cm: "test-config-map",
cmns: "fission",
want: &testSpecPatch,
wantErr: false,
},
{
name: "Configmap does not exists",
cm: "wrongname",
cmns: "fission",
want: nil,
wantErr: true,
},
{
name: "Wrong namespace",
cm: "test-config-map",
cmns: "fissio",
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetSpecFromConfigMap(context.Background(), kubeClient, tt.cm, tt.cmns)
if (err != nil) != tt.wantErr {
t.Errorf("GetSpecFromConfigMap() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetSpecFromConfigMap() got = %v, want %v", got, tt.want)
}
})
}
}
+85
View File
@@ -0,0 +1,85 @@
/*
Copyright 2022 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 archive
import (
"github.com/spf13/cobra"
wrapper "github.com/fission/fission/pkg/fission-cli/cliwrapper/driver/cobra"
"github.com/fission/fission/pkg/fission-cli/flag"
)
func Commands() *cobra.Command {
uploadCmd := &cobra.Command{
Use: "upload",
Short: "Upload an archive",
RunE: wrapper.Wrapper(Upload),
}
wrapper.SetFlags(uploadCmd, flag.FlagSet{
Required: []flag.Flag{flag.ArchiveName},
Optional: []flag.Flag{flag.KubeContext},
})
listCmd := &cobra.Command{
Use: "list",
Short: "List all uploaded archives",
RunE: wrapper.Wrapper(List),
}
wrapper.SetFlags(listCmd, flag.FlagSet{
Optional: []flag.Flag{flag.KubeContext},
})
deleteCmd := &cobra.Command{
Use: "delete",
Short: "Delete an archive",
RunE: wrapper.Wrapper(Delete),
}
wrapper.SetFlags(deleteCmd, flag.FlagSet{
Required: []flag.Flag{flag.ArchiveID},
Optional: []flag.Flag{flag.ArchiveOutput},
})
geturlCmd := &cobra.Command{
Use: "get-url",
Short: "Get URL of an uploaded archive",
RunE: wrapper.Wrapper(GetURL),
}
wrapper.SetFlags(geturlCmd, flag.FlagSet{
Required: []flag.Flag{flag.ArchiveID},
Optional: []flag.Flag{flag.KubeContext},
})
downloadCmd := &cobra.Command{
Use: "download",
Short: "Download an archive",
RunE: wrapper.Wrapper(Download),
}
wrapper.SetFlags(downloadCmd, flag.FlagSet{
Required: []flag.Flag{flag.ArchiveID},
Optional: []flag.Flag{flag.KubeContext, flag.ArchiveOutput},
})
command := &cobra.Command{
Use: "archive",
Short: "Manage archives stored with Fission Storage Service.",
Aliases: []string{"ar"},
}
command.AddCommand(uploadCmd, listCmd, deleteCmd, geturlCmd, downloadCmd)
return command
}
+58
View File
@@ -0,0 +1,58 @@
/*
Copyright 2022 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 archive
import (
"context"
"fmt"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
storagesvcClient "github.com/fission/fission/pkg/storagesvc/client"
)
type DeleteSubCommand struct {
cmd.CommandActioner
}
func Delete(input cli.Input) error {
return (&DeleteSubCommand{}).do(input)
}
func (opts *DeleteSubCommand) do(input cli.Input) error {
kubeContext := input.String(flagkey.KubeContext)
archiveID := input.String(flagkey.ArchiveID)
storagesvcURL, err := util.GetStorageURL(kubeContext)
if err != nil {
return err
}
client := storagesvcClient.MakeClient(storagesvcURL.String())
err = client.Delete(context.Background(), archiveID)
if err != nil {
return err
}
fmt.Printf("Deleted archive with id: %s", archiveID)
return nil
}
+62
View File
@@ -0,0 +1,62 @@
/*
Copyright 2022 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 archive
import (
"context"
"fmt"
"strings"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
storagesvcClient "github.com/fission/fission/pkg/storagesvc/client"
)
type DownloadSubCommand struct {
cmd.CommandActioner
}
func Download(input cli.Input) error {
return (&DownloadSubCommand{}).do(input)
}
func (opts *DownloadSubCommand) do(input cli.Input) error {
kubeContext := input.String(flagkey.KubeContext)
archiveID := input.String(flagkey.ArchiveID)
archiveOutput := input.String(flagkey.ArchiveOutput)
if len(archiveOutput) == 0 {
archiveOutput = strings.TrimPrefix(archiveID, "/fission/fission-functions/")
}
storageAccessURL, err := util.GetStorageURL(kubeContext)
if err != nil {
return err
}
client := storagesvcClient.MakeClient(storageAccessURL.String())
err = client.Download(context.Background(), archiveID, archiveOutput)
if err != nil {
return err
}
fmt.Printf("File download complete. File name: %s", archiveOutput)
return nil
}
+85
View File
@@ -0,0 +1,85 @@
/*
Copyright 2019 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 archive
import (
"fmt"
"net/http"
"net/url"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
storagesvcClient "github.com/fission/fission/pkg/storagesvc/client"
)
type GetURLSubCommand struct {
cmd.CommandActioner
}
func GetURL(input cli.Input) error {
return (&GetURLSubCommand{}).do(input)
}
func (opts *GetURLSubCommand) do(input cli.Input) error {
kubeContext := input.String(flagkey.KubeContext)
archiveID := input.String(flagkey.ArchiveID)
serverURL, err := util.GetStorageURL(kubeContext)
if err != nil {
return err
}
relativeURL, _ := url.Parse(util.FISSION_STORAGE_URI)
queryString := relativeURL.Query()
queryString.Set("id", archiveID)
relativeURL.RawQuery = queryString.Encode()
storageAccessURL := serverURL.ResolveReference(relativeURL)
resp, err := http.Head(storageAccessURL.String())
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Error getting URL. Exited with Status: %v", resp.Status)
}
archiveURL, err := url.Parse(resp.Header.Get("X-FISSION-ARCHIVEURL"))
if err != nil {
return err
}
if archiveURL.Scheme == "file" {
storageSvc, err := opts.Client().V1().Misc().GetSvcURL("application=fission-storage")
if err != nil {
return err
}
storagesvcURL := "http://" + storageSvc
client := storagesvcClient.MakeClient(storagesvcURL)
fmt.Printf("URL: %s", client.GetUrl(archiveID))
} else {
fmt.Printf("URL: %s", archiveURL.String())
}
return nil
}
+60
View File
@@ -0,0 +1,60 @@
/*
Copyright 2022 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 archive
import (
"context"
"fmt"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
storagesvcClient "github.com/fission/fission/pkg/storagesvc/client"
)
type ListSubCommand struct {
cmd.CommandActioner
}
func List(input cli.Input) error {
return (&ListSubCommand{}).do(input)
}
func (opts *ListSubCommand) do(input cli.Input) error {
kubeContext := input.String(flagkey.KubeContext)
storageAccessURL, err := util.GetStorageURL(kubeContext)
if err != nil {
return err
}
client := storagesvcClient.MakeClient(storageAccessURL.String())
files, err := client.List(context.Background())
if err != nil {
return err
}
fmt.Println("ARCHIVES")
for _, file := range files {
fmt.Println(file)
}
return nil
}
+57
View File
@@ -0,0 +1,57 @@
/*
Copyright 2022 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 archive
import (
"context"
"fmt"
"github.com/fission/fission/pkg/fission-cli/cliwrapper/cli"
"github.com/fission/fission/pkg/fission-cli/cmd"
flagkey "github.com/fission/fission/pkg/fission-cli/flag/key"
"github.com/fission/fission/pkg/fission-cli/util"
storagesvcClient "github.com/fission/fission/pkg/storagesvc/client"
)
type UploadSubCommand struct {
cmd.CommandActioner
}
func Upload(input cli.Input) error {
return (&UploadSubCommand{}).do(input)
}
func (opts *UploadSubCommand) do(input cli.Input) error {
kubeContext := input.String(flagkey.KubeContext)
archiveName := input.String(flagkey.ArchiveName)
storagesvcURL, err := util.GetStorageURL(kubeContext)
if err != nil {
return err
}
client := storagesvcClient.MakeClient(storagesvcURL.String())
archiveID, err := client.Upload(context.Background(), archiveName, nil)
if err != nil {
return err
}
fmt.Printf("File successfully uploaded with ID: %s ", archiveID)
return nil
}
+4
View File
@@ -227,4 +227,8 @@ var (
CanaryWeightIncrement = Flag{Type: Int, Name: flagkey.CanaryWeightIncrement, Aliases: []string{"step"}, Usage: "Weight increment step for function", DefaultValue: 20}
CanaryIncrementInterval = Flag{Type: String, Name: flagkey.CanaryIncrementInterval, Aliases: []string{"internal"}, Usage: "Weight increment interval, string representation of time.Duration, ex : 1m, 2h, 2d", DefaultValue: "2m"}
CanaryFailureThreshold = Flag{Type: Int, Name: flagkey.CanaryFailureThreshold, Aliases: []string{"threshold"}, Usage: "Threshold in percentage beyond which the new version of the function is considered unstable", DefaultValue: 10}
ArchiveName = Flag{Type: String, Name: flagkey.ArchiveName, Usage: "Name of the archive file"}
ArchiveID = Flag{Type: String, Name: flagkey.ArchiveID, Usage: "Id for the archive file"}
ArchiveOutput = Flag{Type: String, Name: flagkey.ArchiveOutput, Usage: "Download file with this name", Aliases: []string{"o"}, DefaultValue: ""}
)
+4
View File
@@ -178,5 +178,9 @@ const (
CanaryIncrementInterval = "increment-interval"
CanaryFailureThreshold = "failure-threshold"
ArchiveName = resourceName
ArchiveID = "id"
ArchiveOutput = Output
DefaultSpecOutputDir = "fission-dump"
)
+5 -4
View File
@@ -18,8 +18,9 @@ package util
// fission-cli options
const (
SPEC_IGNORE_FILE = ".specignore"
COMMIT_LABEL = "commit"
FISSION_AUTH_URI = "/auth/login"
FISSION_AUTH_TOKEN = "FISSION_AUTH_TOKEN"
SPEC_IGNORE_FILE = ".specignore"
COMMIT_LABEL = "commit"
FISSION_AUTH_URI = "/auth/login"
FISSION_AUTH_TOKEN = "FISSION_AUTH_TOKEN"
FISSION_STORAGE_URI = "/v1/archive"
)
+15
View File
@@ -18,6 +18,7 @@ package util
import (
"fmt"
"net/url"
"os"
"os/user"
"path/filepath"
@@ -443,3 +444,17 @@ func ApplyLabelsAndAnnotations(input cli.Input, objectMeta *metav1.ObjectMeta) e
}
return nil
}
func GetStorageURL(kubeContext string) (*url.URL, error) {
storageLocalPort, err := SetupPortForward(GetFissionNamespace(), "application=fission-storage", kubeContext)
if err != nil {
return nil, err
}
serverURL, err := url.Parse("http://127.0.0.1:" + storageLocalPort)
if err != nil {
return nil, err
}
return serverURL, nil
}
+27
View File
@@ -123,6 +123,33 @@ func (c *Client) GetUrl(id string) string {
return fmt.Sprintf("%v/archive?id=%v", c.url, url.PathEscape(id))
}
func (c *Client) List(ctx context.Context) ([]string, error) {
req, err := http.NewRequest(http.MethodGet, c.url+"/archive", nil)
if err != nil {
return []string{}, err
}
resp, err := ctxhttp.Do(ctx, c.httpClient, req)
if err != nil {
return []string{}, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return []string{}, err
}
if resp.StatusCode != http.StatusOK {
msg := fmt.Sprintf("List error %v", resp.Status)
return []string{}, errors.New(msg)
}
var ids []string
err = json.Unmarshal(body, &ids)
if err != nil {
return []string{}, err
}
return ids, nil
}
// Download fetches the file identified by ID to the local file path.
// filePath must not exist.
func (c *Client) Download(ctx context.Context, id string, filePath string) error {
+40 -25
View File
@@ -42,20 +42,25 @@ const (
minioRegion = "ap-south-1"
)
func panicIf(err error) {
func failTest(t *testing.T, err error) {
if err != nil {
log.Panicf("Error: %v", err)
t.Fatalf("%v", err)
}
}
func MakeTestFile(size int) *os.File {
func MakeTestFile(size int) (*os.File, error) {
f, err := os.CreateTemp("", "storagesvc_test_")
panicIf(err)
if err != nil {
return nil, err
}
_, err = f.Write(bytes.Repeat([]byte("."), size))
panicIf(err)
return f
if err != nil {
return nil, err
}
return f, nil
}
func runMinioDockerContainer(pool *dockertest.Pool) *dockertest.Resource {
@@ -120,7 +125,7 @@ func TestS3StorageService(t *testing.T) {
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
logger, err := config.Build()
panicIf(err)
failTest(t, err)
log.Println("starting storage svc")
os.Setenv("STORAGE_S3_ENDPOINT", endpoint)
@@ -139,27 +144,28 @@ func TestS3StorageService(t *testing.T) {
client := MakeClient(fmt.Sprintf("http://localhost:%v/", 8081))
// generate a test file
tmpfile := MakeTestFile(10 * 1024)
tmpfile, err := MakeTestFile(10 * 1024)
failTest(t, err)
defer os.Remove(tmpfile.Name())
// store it
metadata := make(map[string]string)
fileID, err := client.Upload(ctx, tmpfile.Name(), &metadata)
panicIf(err)
failTest(t, err)
time.Sleep(10 * time.Second)
// Retrieve file through minioClient
reader, err := minioClient.GetObject(bucketName, fileID, minio.GetObjectOptions{})
panicIf(err)
failTest(t, err)
defer reader.Close()
retThroughMinio, err := os.CreateTemp("", "storagesvc_verify_minio_")
panicIf(err)
failTest(t, err)
defer os.Remove(retThroughMinio.Name())
stat, err := reader.Stat()
panicIf(err)
failTest(t, err)
if _, err := io.CopyN(retThroughMinio, reader, stat.Size); err != nil {
log.Fatalln(err)
@@ -167,25 +173,25 @@ func TestS3StorageService(t *testing.T) {
// Retrieve file through API
retThroughAPI, err := os.CreateTemp("", "storagesvc_verify_")
panicIf(err)
failTest(t, err)
os.Remove(retThroughAPI.Name())
err = client.Download(ctx, fileID, retThroughAPI.Name())
panicIf(err)
failTest(t, err)
defer os.Remove(retThroughAPI.Name())
// compare contents
contentsMinio, err := os.ReadFile(retThroughMinio.Name())
panicIf(err)
failTest(t, err)
contentsAPI, err := os.ReadFile(retThroughAPI.Name())
panicIf(err)
failTest(t, err)
if !bytes.Equal(contentsMinio, contentsAPI) {
log.Panic("Contents don't match")
}
// delete uploaded file
err = client.Delete(ctx, fileID)
panicIf(err)
failTest(t, err)
// make sure download fails
err = client.Download(ctx, fileID, "xxx")
@@ -201,7 +207,7 @@ func TestLocalStorageService(t *testing.T) {
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
logger, err := config.Build()
panicIf(err)
failTest(t, err)
log.Println("starting storage svc")
localPath := fmt.Sprintf("/tmp/%v", testID)
@@ -216,36 +222,45 @@ func TestLocalStorageService(t *testing.T) {
client := MakeClient(fmt.Sprintf("http://localhost:%v/", port))
// generate a test file
tmpfile := MakeTestFile(10 * 1024)
tmpfile, err := MakeTestFile(10 * 1024)
failTest(t, err)
defer os.Remove(tmpfile.Name())
// store it
metadata := make(map[string]string)
fileID, err := client.Upload(ctx, tmpfile.Name(), &metadata)
panicIf(err)
failTest(t, err)
ids, err := client.List(ctx)
if err != nil {
t.Fatalf("Could not list files: %s", err)
}
if len(ids) != 1 {
t.Fatalf("Expected 1 file, got %v", len(ids))
}
// make a temp file for verification
retrievedfile, err := os.CreateTemp("", "storagesvc_verify_")
panicIf(err)
failTest(t, err)
os.Remove(retrievedfile.Name())
// retrieve uploaded file
err = client.Download(ctx, fileID, retrievedfile.Name())
panicIf(err)
failTest(t, err)
defer os.Remove(retrievedfile.Name())
// compare contents
contents1, err := os.ReadFile(tmpfile.Name())
panicIf(err)
failTest(t, err)
contents2, err := os.ReadFile(retrievedfile.Name())
panicIf(err)
failTest(t, err)
if !bytes.Equal(contents1, contents2) {
log.Panic("Contents don't match")
}
// delete uploaded file
err = client.Delete(ctx, fileID)
panicIf(err)
failTest(t, err)
// make sure download fails
err = client.Download(ctx, fileID, "xxx")
+4
View File
@@ -42,6 +42,10 @@ func (ls localStorage) getUploadFileName() (string, error) {
return id.String(), err
}
func (ls localStorage) getSubDir() string {
return ""
}
func (ls localStorage) getContainerName() string {
return ls.containerName
}
+4
View File
@@ -49,6 +49,10 @@ func (ss s3Storage) getContainerName() string {
return ss.bucketName
}
func (ss s3Storage) getSubDir() string {
return ss.subDir
}
func (ss s3Storage) getUploadFileName() (string, error) {
id, err := uuid.NewV4()
if err != nil {
+52 -3
View File
@@ -41,7 +41,7 @@ type (
Storage interface {
getStorageType() StorageType
dial() (stow.Location, error)
// getSubDir() string
getSubDir() string
getContainerName() string
getUploadFileName() (string, error)
}
@@ -67,6 +67,32 @@ func getStorageLocation(config *storageConfig) (stow.Location, error) {
return config.storage.dial()
}
func (ss *StorageService) listItems(w http.ResponseWriter, r *http.Request) {
// get all archives on storage
// out of them, there may be some just created but not referenced by packages yet.
// need to filter them out.
archivesInStorage, err := ss.storageClient.getItemIDsWithFilter(ss.storageClient.filterAllItems, false)
if err != nil {
ss.logger.Error("error getting items from storage", zap.Error(err))
return
}
ss.logger.Debug("archives in storage", zap.Strings("archives", archivesInStorage))
// respond with the list of items
resp, err := json.Marshal(archivesInStorage)
if err != nil {
http.Error(w, "error marshaling item list", http.StatusInternalServerError)
return
}
_, err = w.Write(resp)
if err != nil {
ss.logger.Error(
"error writing HTTP response",
zap.Error(err),
)
}
}
// Handle multipart file uploads.
func (ss *StorageService) uploadHandler(w http.ResponseWriter, r *http.Request) {
// handle upload
@@ -203,6 +229,23 @@ func (ss *StorageService) downloadHandler(w http.ResponseWriter, r *http.Request
}
}
func (ss *StorageService) infoHandler(w http.ResponseWriter, r *http.Request) {
fileId, err := ss.getIdFromRequest(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
itemURL, err := ss.storageClient.getURL(fileId)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
w.Header().Add("X-FISSION-ARCHIVEURL", itemURL.String())
}
func (ss *StorageService) healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
@@ -219,8 +262,10 @@ func (ss *StorageService) Start(ctx context.Context, port int, openTracingEnable
r := mux.NewRouter()
r.Use(metrics.HTTPMetricMiddleware)
r.HandleFunc("/v1/archive", ss.uploadHandler).Methods("POST")
r.HandleFunc("/v1/archive", ss.downloadHandler).Methods("GET")
r.HandleFunc("/v1/archive", ss.downloadHandler).Queries("id", "{id}").Methods("GET")
r.HandleFunc("/v1/archive", ss.listItems).Methods("GET")
r.HandleFunc("/v1/archive", ss.deleteHandler).Methods("DELETE")
r.HandleFunc("/v1/archive", ss.infoHandler).Methods("HEAD")
r.HandleFunc("/healthz", ss.healthHandler).Methods("GET")
var handler http.Handler
@@ -236,7 +281,11 @@ func (ss *StorageService) Start(ctx context.Context, port int, openTracingEnable
// Start runs storage service
func Start(ctx context.Context, logger *zap.Logger, storage Storage, port int, openTracingEnabled bool) error {
enablePruner := true
enablePruner, err := strconv.ParseBool(os.Getenv("PRUNE_ENABLED"))
if err != nil {
logger.Warn("PRUNE_ENABLED value not set. Enabling archive pruner by default.", zap.Error(err))
enablePruner = true
}
// create a storage client
storageClient, err := MakeStowClient(logger, storage)
if err != nil {
+23 -1
View File
@@ -20,6 +20,7 @@ import (
"fmt"
"io"
"mime/multipart"
"net/url"
"os"
"strings"
"time"
@@ -182,6 +183,18 @@ func (client *StowClient) removeFileByID(itemID string) error {
return client.container.RemoveItem(itemID)
}
func (client *StowClient) getURL(itemID string) (*url.URL, error) {
item, err := client.container.Item(itemID)
if err != nil {
if err == stow.ErrNotFound {
return nil, ErrNotFound
} else {
return nil, ErrRetrievingItem
}
}
return item.URL(), nil
}
func (client *StowClient) getFileSize(itemID string) (int64, error) {
item, err := client.container.Item(itemID)
if err != nil {
@@ -206,7 +219,7 @@ func (client *StowClient) getItemIDsWithFilter(filterFunc filter, filterFuncPara
archiveIDList := make([]string, 0)
for {
items, cursor, err = client.container.Items(stow.NoPrefix, cursor, PaginationSize)
items, cursor, err = client.container.Items(client.config.storage.getSubDir(), cursor, PaginationSize)
if err != nil {
return nil, errors.Wrap(err, "error getting items from container")
}
@@ -240,3 +253,12 @@ func (client StowClient) filterItemCreatedAMinuteAgo(item stow.Item, currentTime
}
return false
}
func (client StowClient) filterAllItems(item stow.Item, _ interface{}) bool {
itemLastModTime, _ := item.LastMod()
client.logger.Debug("item info",
zap.String("item", item.ID()),
zap.Time("last_modified_time", itemLastModTime))
return false
}
+29 -15
View File
@@ -19,6 +19,7 @@ import (
"bytes"
"context"
"errors"
"fmt"
"net/http"
"net/url"
"os"
@@ -27,16 +28,17 @@ import (
uuid "github.com/satori/go.uuid"
)
const HTTP_TIMEOUT = 5 * time.Second
const GA_API_URL = "https://www.google-analytics.com/collect"
const GA_TRACKING_ID = "GA_TRACKING_ID"
var Tracker *tracker
const (
HTTP_TIMEOUT time.Duration = 5 * time.Second
GA_TRACKING_ID string = "GA_TRACKING_ID"
GA_API_URL string = "GA_API_URL"
)
type (
tracker struct {
Tracker struct {
gaPropertyID string
cid string
gaAPIURL string
}
Event struct {
Category string
@@ -46,19 +48,31 @@ type (
}
)
func init() {
func NewTracker() (*Tracker, error) {
id, err := uuid.NewV4()
if err != nil {
panic(err)
return nil, fmt.Errorf("tracker.NewTracker: error generating UUID: %w", err)
}
Tracker = &tracker{gaPropertyID: os.Getenv(GA_TRACKING_ID), cid: id.String()}
gaTrackingID := os.Getenv(GA_TRACKING_ID)
if gaTrackingID == "" {
return nil, errors.New("tracker.NewTracker: GA_TRACKING_ID env not set")
}
gaAPIURL := os.Getenv(GA_API_URL)
if gaAPIURL == "" {
gaAPIURL = "https://www.google-analytics.com/collect"
}
tracker := &Tracker{
gaPropertyID: gaTrackingID,
cid: id.String(),
gaAPIURL: gaAPIURL,
}
return tracker, nil
}
func (t *tracker) SendEvent(ctx context.Context, e Event) error {
if t.gaPropertyID == "" {
return errors.New("tracker.SendEvent: GA_TRACKING_ID env not set")
}
func (t *Tracker) SendEvent(ctx context.Context, e Event) error {
if e.Action == "" || e.Category == "" {
return errors.New("tracker.SendEvent: category and action are required")
}
@@ -81,7 +95,7 @@ func (t *tracker) SendEvent(ctx context.Context, e Event) error {
}
buf := bytes.NewBufferString(v.Encode())
req, err := http.NewRequestWithContext(ctx, "POST", GA_API_URL, buf)
req, err := http.NewRequestWithContext(ctx, "POST", t.gaAPIURL, buf)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("User-Agent", "ga-tracker/1.0")
if err != nil {
+127
View File
@@ -0,0 +1,127 @@
package tracker
import (
"context"
"encoding/json"
"errors"
"log"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestTracker(t *testing.T) {
t.Run("NewTracker", func(test *testing.T) {
for _, test := range []struct {
name string
gaAPIURl string
expected error
}{
{
name: "GA Tracking ID should not be empty",
gaAPIURl: "",
expected: errors.New("tracker.NewTracker: GA_TRACKING_ID env not set"),
},
{
name: "Tracker should initialize properly",
gaAPIURl: "/",
expected: nil,
},
} {
t.Run(test.name, func(testing *testing.T) {
if test.expected == nil {
os.Setenv(GA_TRACKING_ID, "UA-000000-2")
t, err := NewTracker()
assert.Nil(testing, err)
assert.NotNil(testing, t)
} else {
t, err := NewTracker()
assert.Nil(testing, t)
assert.NotNil(testing, err)
assert.Equal(testing, err.Error(), test.expected.Error())
}
})
}
})
t.Run("SendEvent", func(test *testing.T) {
os.Setenv(GA_TRACKING_ID, "UA-000000-2")
tr, err := NewTracker()
if err != nil {
log.Fatal(err)
}
for _, test := range []struct {
name string
request *Event
expected error
status int
}{
{
name: "category and action should not be empty",
request: &Event{
Category: "",
Action: "",
Label: "play",
Value: "value",
},
expected: errors.New("tracker.SendEvent: category and action are required"),
status: http.StatusInternalServerError,
},
{
name: "Google Analytics response should not be OK",
request: &Event{
Category: "UI_action",
Action: "button_press",
Label: "play",
Value: "value",
},
expected: errors.New("tracker.SendEvent: analytics response status not ok"),
status: http.StatusInternalServerError,
},
{
name: "Google Analytics response should be OK",
request: &Event{
Category: "UI_action",
Action: "button_press",
Label: "play",
Value: "value",
},
expected: nil,
status: http.StatusOK,
},
} {
t.Run(test.name, func(testing *testing.T) {
server := MockHTTPServer(test.status, "")
defer server.Close()
tr.gaAPIURL = server.URL
t := tr.SendEvent(context.Background(), *test.request)
if test.status == http.StatusOK {
assert.Nil(testing, t, test.expected)
} else {
assert.NotNil(testing, t)
assert.Equal(testing, t.Error(), test.expected.Error())
}
})
}
})
}
func MockHTTPServer(status int, encodeValue interface{}) *httptest.Server {
f := func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(encodeValue)
if err != nil {
log.Fatal(err)
}
}
return httptest.NewServer(http.HandlerFunc(f))
}
+12
View File
@@ -22,6 +22,7 @@ import (
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"os"
@@ -214,3 +215,14 @@ func IsZip(filename string) (bool, error) {
defer f.Close()
return archiver.DefaultZip.Match(f)
}
// GetCurrentNamespace returns Kubernetes namespace of current Pod
func GetCurrentNamespace() (string, error) {
// This file contains the namespace and can be found in each container.
body, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
return "", err
}
return string(body), nil
}
+11 -2
View File
@@ -45,7 +45,10 @@ deploy:
pprof.enabled: false
canaryDeployment.enabled: false
influxdb.enabled: false
pruneInterval: "60"
storagesvc.archivePruner.enabled: true
storagesvc.archivePruner.interval: "60"
runtimePodSpec.enabled: false
builderPodSpec.enabled: false
repository: index.docker.io
routerServiceType: LoadBalancer
openTracing.enabled: false
@@ -56,6 +59,12 @@ deploy:
# Use /var/log directory for kind logs export
terminationMessagePath: /var/log/termination-log
terminationMessagePolicy: FallbackToLogsOnError
executor.securityContext.enabled: true
router.securityContext.enabled: true
buildermgr.securityContext.enabled: true
controller.securityContext.enabled: true
kubewatcher.securityContext.enabled: true
storagesvc.securityContext.enabled: true
wait: true
flags:
install:
@@ -96,7 +105,7 @@ profiles:
path: /deploy/helm/releases/0/setValues/repository
value: ""
- op: replace
path: /deploy/helm/releases/0/setValues/pruneInterval
path: /deploy/helm/releases/0/setValues/storagesvc.archivePruner.interval
value: 1
- op: replace
path: /deploy/helm/releases/0/setValues/routerServiceType
+1
View File
@@ -57,6 +57,7 @@ main() {
# run tests without newdeploy in parallel.
export JOBS=6
source $ROOT/test/run_test.sh \
$ROOT/test/tests/test_archive_cli.sh \
$ROOT/test/tests/test_canary.sh \
$ROOT/test/tests/test_fn_update/test_idle_objects_reaper.sh \
$ROOT/test/tests/mqtrigger/kafka/test_kafka.sh \
+63
View File
@@ -0,0 +1,63 @@
#!/bin/bash
set -euo pipefail
source "$(dirname $0)"/../utils.sh
TEST_ID=$(generate_test_id)
echo "TEST_ID = $TEST_ID"
tmp_dir="/tmp/test-$TEST_ID"
mkdir -p "$tmp_dir"
podname=$(kubectl get pods -n fission | grep "storagesvc" |awk '{print $1}')
cleanup() {
log "Cleaning up..."
clean_resource_by_id $TEST_ID
rm -rf $tmp_dir
}
if [ -z "${TEST_NOCLEANUP:-}" ]; then
trap cleanup EXIT
else
log "TEST_NOCLEANUP is set; not cleaning up test artifacts afterwards."
fi
create_archive() {
log "Creating an archive"
mkdir -p "$tmp_dir"/archive
dd if=/dev/urandom of="$tmp_dir"/archive/dynamically_generated_file bs=256k count=1
printf 'def main():\n return "Hello, world!"' > "$tmp_dir"/archive/hello.py
zip -jr "$tmp_dir"/test-deploy-pkg.zip "$tmp_dir"/archive/
}
# Test for upload
create_archive
uploadResp=$(fission ar upload --name "$tmp_dir"/test-deploy-pkg.zip)
filename=$(echo "$uploadResp" | cut -d':' -f2 | tr -d ' ')
kubectl exec -i "$podname" -n fission -- /bin/sh -c "ls $filename"
# Test for list
listResp=$(fission ar list)
echo "$listResp" | grep "$filename"
# Test for download
fission ar download --id "$filename"
fileID=$(echo "$filename" | cut -d'/' -f4)
ls | grep "$fileID"
# Test for get-url
getURLResp=$(fission ar get-url --id "$filename")
echo "$getURLResp" | grep "http://storagesvc.fission/v1/archive?id=%2Ffission%2Ffission-functions%2F$fileID"
# Test for delete
fission ar delete --id "$filename"
fission ar list | grep -v "$filename"
log "Archive CLI tests done."