Compare commits
19
Commits
v1.16.0
...
v1.17.0-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
770c19a27b | ||
|
|
613062549d | ||
|
|
f3a45b6549 | ||
|
|
c71867169b | ||
|
|
473acc4e2b | ||
|
|
21ea35b02a | ||
|
|
7f21b708e7 | ||
|
|
b80b41e1fd | ||
|
|
fe8f53375e | ||
|
|
a2b6f95656 | ||
|
|
fa3347077a | ||
|
|
5d010fe1fa | ||
|
|
979880ae2d | ||
|
|
7be3e4f410 | ||
|
|
709af6e432 | ||
|
|
ac3307bd91 | ||
|
|
063209dc9e | ||
|
|
83303471c5 | ||
|
|
8bcc9503d1 |
@@ -1,5 +1,13 @@
|
||||
# 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 — 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.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: v2
|
||||
name: fission-all
|
||||
version: v1.16.0
|
||||
appVersion: v1.16.0
|
||||
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 }}
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
imageTag: v1.17.0-rc1
|
||||
|
||||
## Fission post-install/post-upgrade reporting live in this image
|
||||
##
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: []
|
||||
|
||||
+9176
-2153
File diff suppressed because it is too large
Load Diff
+4022
-991
File diff suppressed because it is too large
Load Diff
@@ -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: []
|
||||
|
||||
@@ -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
@@ -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: []
|
||||
|
||||
@@ -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: []
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -66,6 +66,11 @@ const (
|
||||
StrategyTypeExecution = "execution"
|
||||
)
|
||||
|
||||
const (
|
||||
RuntimePodSpecConfigmap = "runtime-podspec-patch"
|
||||
BuilderPodSpecConfigmap = "builder-podspec-patch"
|
||||
)
|
||||
|
||||
const (
|
||||
SharedVolumeUserfunc = "userfunc"
|
||||
SharedVolumePackages = "packages"
|
||||
|
||||
+26
-19
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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: ""}
|
||||
)
|
||||
|
||||
@@ -178,5 +178,9 @@ const (
|
||||
CanaryIncrementInterval = "increment-interval"
|
||||
CanaryFailureThreshold = "failure-threshold"
|
||||
|
||||
ArchiveName = resourceName
|
||||
ArchiveID = "id"
|
||||
ArchiveOutput = Output
|
||||
|
||||
DefaultSpecOutputDir = "fission-dump"
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Executable
+63
@@ -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."
|
||||
Reference in New Issue
Block a user