Remove controller component from Fission (#2850)

* Remove controller component from Fission
* Cleanup at few more places

---------

Signed-off-by: Sanket Sudake <sanketsudake@gmail.com>
This commit is contained in:
Sanket Sudake
2023-10-17 09:29:13 +05:30
committed by GitHub
parent c09319ceb3
commit 703d757c29
60 changed files with 12 additions and 6129 deletions
-2
View File
@@ -113,7 +113,6 @@ jobs:
- name: Port-forward fission components
run: |
kubectl port-forward svc/router 8888:80 -nfission &
kubectl port-forward svc/controller 8889:80 -nfission &
- name: Get fission version
timeout-minutes: 10
@@ -256,7 +255,6 @@ jobs:
- name: Port-forward fission components
run: |
kubectl port-forward svc/router 8888:80 -nfission &
kubectl port-forward svc/controller 8889:80 -nfission &
- name: Get fission version
timeout-minutes: 10
@@ -15,28 +15,6 @@ rules:
- patch
- delete
{{- end }}
{{- define "controller-rules" }}
rules:
- apiGroups:
- fission.io
resources:
- canaryconfigs
- environments
- functions
- httptriggers
- kuberneteswatchtriggers
- messagequeuetriggers
- packages
- timetriggers
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
{{- end }}
{{- define "executor-rules" }}
rules:
- apiGroups:
@@ -63,44 +63,6 @@ rules:
- list
- watch
{{- end }}
{{- define "controller-kuberules" }}
rules:
- apiGroups:
- ""
resources:
- services
verbs:
- list
- apiGroups:
- ""
resources:
- configmaps
- secrets
verbs:
- get
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
{{- end }}
{{- define "executor-kuberules" }}
rules:
- apiGroups:
@@ -17,9 +17,6 @@ metadata:
{{- if eq "canaryconfig" .component }}
{{- include "canaryconfig-kuberules" . }}
{{- end }}
{{- if eq "controller" .component }}
{{- include "controller-kuberules" . }}
{{- end }}
{{- if eq "fluentbit" .component }}
{{- include "fluentbit-kuberules" . }}
{{- end }}
@@ -14,9 +14,6 @@ metadata:
{{- if eq "buildermgr" .component }}
{{- include "buildermgr-rules" . }}
{{- end }}
{{- if eq "controller" .component }}
{{- include "controller-rules" . }}
{{- end }}
{{- if eq "executor" .component }}
{{- include "executor-rules" . }}
{{- end }}
@@ -1,96 +0,0 @@
{{- if .Values.controller.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
svc: controller
application: fission-api
spec:
replicas: 1
selector:
matchLabels:
svc: controller
application: fission-api
template:
metadata:
labels:
svc: controller
application: fission-api
annotations:
prometheus.io/scrape: "true"
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 }}
imagePullPolicy: {{ .Values.pullPolicy }}
command: ["/fission-bundle"]
args: ["--controllerPort", "8888"]
env:
- name: DEBUG_ENV
value: {{ .Values.debugEnv | quote }}
- name: PPROF_ENABLED
value: {{ .Values.pprof.enabled | quote }}
{{- include "fission-resource-namespace.envs" . | indent 8 }}
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- include "opentelemtry.envs" . | indent 8 }}
resources:
{{- toYaml .Values.controller.resources | nindent 10 }}
{{- if .Values.terminationMessagePath }}
terminationMessagePath: {{ .Values.terminationMessagePath }}
{{- end }}
{{- if .Values.terminationMessagePolicy }}
terminationMessagePolicy: {{ .Values.terminationMessagePolicy }}
{{- end }}
readinessProbe:
httpGet:
path: "/healthz"
port: 8888
initialDelaySeconds: 1
periodSeconds: 1
failureThreshold: 30
livenessProbe:
httpGet:
path: "/healthz"
port: 8888
initialDelaySeconds: 35
periodSeconds: 5
volumeMounts:
- name: config-volume
mountPath: /etc/config/config.yaml
subPath: config.yaml
ports:
- containerPort: 8080
name: metrics
- containerPort: 8888
name: http
{{- if .Values.pprof.enabled }}
- containerPort: 6060
name: pprof
{{- end }}
serviceAccountName: fission-controller
volumes:
- name: config-volume
configMap:
name: feature-config
{{- if .Values.priorityClassName }}
priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.extraCoreComponentPodConfig }}
{{ toYaml .Values.extraCoreComponentPodConfig | indent 6 -}}
{{- end }}
{{- end -}}
@@ -1,9 +0,0 @@
{{- if .Values.controller.enabled }}
{{- include "fission-role-generator" (merge (dict "namespace" .Values.defaultNamespace "component" "controller") .) }}
{{- if gt (len .Values.additionalFissionNamespaces) 0 }}
{{- range $namespace := $.Values.additionalFissionNamespaces }}
{{ include "fission-role-generator" (merge (dict "namespace" $namespace "component" "controller") $) }}
{{- end }}
{{- end }}
{{- end -}}
@@ -1,13 +0,0 @@
{{- include "kubernetes-role-generator" (merge (dict "namespace" .Values.defaultNamespace "component" "controller") .) }}
{{- if gt (len .Values.additionalFissionNamespaces) 0 }}
{{- range $namespace := $.Values.additionalFissionNamespaces }}
{{ include "kubernetes-role-generator" (merge (dict "namespace" $namespace "component" "controller") $) }}
{{- end }}
{{- end }}
{{- if .Values.builderNamespace -}}
{{ include "kubernetes-role-generator" (merge (dict "namespace" .Values.builderNamespace "component" "controller") $) }}
{{- end }}
{{- if .Values.functionNamespace -}}
{{ include "kubernetes-role-generator" (merge (dict "namespace" .Values.functionNamespace "component" "controller") $) }}
{{- end }}
@@ -1,7 +0,0 @@
{{- if .Values.controller.enabled }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: fission-controller
namespace: {{ .Release.Namespace }}
{{- end -}}
@@ -1,24 +0,0 @@
{{- if .Values.controller.enabled }}
{{- if .Values.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: controller-monitor
{{- if .Values.serviceMonitor.namespace }}
namespace: {{ .Values.serviceMonitor.namespace }}
{{- end }}
{{- with .Values.serviceMonitor.additionalServiceMonitorLabels }}
labels:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
selector:
matchLabels:
svc: controller
endpoints:
- targetPort: 8080
{{- end -}}
{{- end -}}
@@ -1,20 +0,0 @@
{{- if .Values.controller.enabled }}
apiVersion: v1
kind: Service
metadata:
name: controller
labels:
svc: controller
application: fission-api
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
type: {{ .Values.serviceType }}
ports:
- port: 80
targetPort: 8888
{{- if eq .Values.serviceType "NodePort" }}
nodePort: {{ .Values.controllerPort }}
{{- end }}
selector:
svc: controller
{{- end -}}
+2 -34
View File
@@ -1,7 +1,7 @@
## Fission chart configuration
##
## serviceType to consider while creating Fission Controller service.
## serviceType to consider while creating Fission webhook service.
## For minikube/kind, set this to NodePort, elsewhere use LoadBalancer or ClusterIP.
##
serviceType: ClusterIP
@@ -53,10 +53,6 @@ terminationMessagePath: /dev/termination-log
##
terminationMessagePolicy: File
## controllerPort represents the port at which the Fission controller service should be exposed.
##
controllerPort: 31313
## routerPort represents the port at which the Fission Router service should be exposed.
##
routerPort: 31314
@@ -340,34 +336,6 @@ buildermgr:
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.
##
controller:
enabled: false
## Pod resources as:
## resources:
## limits:
## cpu: <tbd>
## memory: <tbd>
## requests:
## cpu: <tbd>
## memory: <tbd>
##
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: true
## Mark it false, if you want to stop the non root user validation
runAsNonRoot: true
fsGroup: 10001
runAsUser: 10001
runAsGroup: 10001
## webhook is the component that validates API calls.
## It contains validation and mutation for functions, triggers, environments, Kubernetes event watches, etc.
##
@@ -534,7 +502,7 @@ kafka:
# version: "0.11.2.0"
# The following components expose Prometheus metrics and have servicemonitors in this chart (disabled by default)
# Controller, router, executor, storage svc
# router, executor, storage svc
serviceMonitor:
enabled: false
##namespace in which you want to deploy servicemonitor
+3 -20
View File
@@ -30,7 +30,6 @@ import (
"github.com/fission/fission/cmd/fission-bundle/mqtrigger"
"github.com/fission/fission/pkg/buildermgr"
"github.com/fission/fission/pkg/canaryconfigmgr"
"github.com/fission/fission/pkg/controller"
"github.com/fission/fission/pkg/executor"
"github.com/fission/fission/pkg/info"
"github.com/fission/fission/pkg/kubewatcher"
@@ -50,10 +49,6 @@ func runWebhook(ctx context.Context, logger *zap.Logger, port int) error {
return webhook.Start(ctx, logger, port)
}
func runController(ctx context.Context, logger *zap.Logger, port int) {
controller.Start(ctx, logger, port, false)
}
func runCanaryConfigServer(ctx context.Context, logger *zap.Logger) error {
return canaryconfigmgr.StartCanaryServer(ctx, logger, false)
}
@@ -115,9 +110,7 @@ func getStringArgWithDefault(arg interface{}, defaultValue string) string {
func getServiceName(arguments map[string]interface{}) string {
serviceName := "Fission-Unknown"
if arguments["--controllerPort"] != nil {
serviceName = "Fission-Controller"
} else if arguments["--routerPort"] != nil {
if arguments["--routerPort"] != nil {
serviceName = "Fission-Router"
} else if arguments["--executorPort"] != nil {
serviceName = "Fission-Executor"
@@ -155,18 +148,17 @@ func main() {
// TODO: fix the lint error. Error checking here is causing all components to crash with error "logtostderr not found"
flag.Set("logtostderr", "true") //nolint: errcheck
usage := `fission-bundle: Package of all fission microservices: controller, router, executor.
usage := `fission-bundle: Package of all fission microservices: router, executor.
Use it to start one or more of the fission servers:
Controller is a stateless API frontend for fission resources.
Pool manager maintains a pool of generalized function containers, and
specializes them on-demand. Executor must be run from a pod in a
Kubernetes cluster.
Router implements HTTP triggers: it routes to running instances,
working with the controller and executor.
working with the executor.
Kubewatcher implements Kubernetes Watch triggers: it watches
Kubernetes resources and invokes functions described in the
@@ -177,7 +169,6 @@ Use it to start one or more of the fission servers:
backends.
Usage:
fission-bundle --controllerPort=<port>
fission-bundle --canaryConfig
fission-bundle --routerPort=<port> [--executorUrl=<url>]
fission-bundle --executorPort=<port> [--namespace=<namespace>] [--fission-namespace=<namespace>]
@@ -191,7 +182,6 @@ Usage:
fission-bundle --logger
fission-bundle --version
Options:
--controllerPort=<port> Port that the controller should listen on.
--canaryConfig Start canary config server.
--webhookPort=<port> Port that the webhook should listen on.
--routerPort=<port> Port that the router should listen on.
@@ -243,13 +233,6 @@ Options:
return
}
if arguments["--controllerPort"] != nil {
port := getPort(logger, arguments["--controllerPort"])
runController(ctx, logger, port)
logger.Error("controller exited")
return
}
if arguments["--canaryConfig"] == true {
err := runCanaryConfigServer(ctx, logger)
if err != nil {
+1 -3
View File
@@ -10,12 +10,9 @@ require (
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/dustin/go-humanize v1.0.1
github.com/elastic/crd-ref-docs v0.0.9
github.com/emicklei/go-restful-openapi/v2 v2.9.1
github.com/emicklei/go-restful/v3 v3.11.0
github.com/fatih/color v1.15.0
github.com/fsnotify/fsnotify v1.6.0
github.com/go-git/go-git/v5 v5.9.0
github.com/go-openapi/spec v0.20.9
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/go-cmp v0.6.0
github.com/gorilla/mux v1.8.0
@@ -83,6 +80,7 @@ require (
github.com/eapache/go-resiliency v1.4.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
-22
View File
@@ -34,8 +34,6 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -121,9 +119,6 @@ github.com/elastic/crd-ref-docs v0.0.9 h1:fkkjFPQMIH2U75Ma5AxQkW7NIydxx2tY2uo/A4
github.com/elastic/crd-ref-docs v0.0.9/go.mod h1:k7DCVDJCqaEozDFcnfhTQd/Foxd8Ip18qKNPAgMpzyo=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emicklei/go-restful-openapi/v2 v2.9.1 h1:Of8B1rXdG81il5TTiSY+9Qrh7pYOr8aLdynHIpvo7fM=
github.com/emicklei/go-restful-openapi/v2 v2.9.1/go.mod h1:VKNgZyYviM1hnyrjD9RDzP2RuE94xTXxV+u6MGN4v4k=
github.com/emicklei/go-restful/v3 v3.7.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@@ -166,19 +161,10 @@ 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 v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@@ -341,9 +327,6 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
@@ -383,7 +366,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ncw/swift v1.0.49/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@@ -600,7 +582,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -643,7 +624,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -738,7 +718,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
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=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
@@ -758,7 +737,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.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=
-271
View File
@@ -1,271 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"fmt"
"net/http"
"os"
"strings"
"github.com/gorilla/mux"
"go.uber.org/zap"
apiv1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
ferror "github.com/fission/fission/pkg/error"
"github.com/fission/fission/pkg/fission-cli/logdb"
"github.com/fission/fission/pkg/generated/clientset/versioned"
"github.com/fission/fission/pkg/info"
"github.com/fission/fission/pkg/utils"
"github.com/fission/fission/pkg/utils/httpserver"
"github.com/fission/fission/pkg/utils/metrics"
"github.com/fission/fission/pkg/utils/otel"
)
var podNamespace string
func init() {
podNamespace = os.Getenv("POD_NAMESPACE")
if podNamespace == "" {
podNamespace = "fission"
}
}
type (
API struct {
logger *zap.Logger
fissionClient versioned.Interface
kubernetesClient kubernetes.Interface
storageServiceUrl string
builderManagerUrl string
workflowApiUrl string
functionNamespace string
featureStatus map[string]string
}
logDBConfig struct {
httpURL string
username string
password string
}
)
func MakeAPI(logger *zap.Logger, fissionClient versioned.Interface, kubernetesClient kubernetes.Interface) (*API, error) {
api, err := makeCRDBackedAPI(logger, fissionClient, kubernetesClient)
u := os.Getenv("STORAGE_SERVICE_URL")
if len(u) > 0 {
api.storageServiceUrl = strings.TrimSuffix(u, "/")
} else {
api.storageServiceUrl = "http://storagesvc"
}
u = os.Getenv("BUILDER_MANAGER_URL")
if len(u) > 0 {
api.builderManagerUrl = strings.TrimSuffix(u, "/")
} else {
api.builderManagerUrl = "http://buildermgr"
}
wfEnv := os.Getenv("WORKFLOW_API_URL")
if len(u) > 0 {
api.workflowApiUrl = strings.TrimSuffix(wfEnv, "/")
} else {
api.workflowApiUrl = "http://workflows-apiserver"
}
nsResolver := utils.DefaultNSResolver()
api.functionNamespace = nsResolver.ResolveNamespace(os.Getenv(utils.ENV_FUNCTION_NAMESPACE))
return api, err
}
func (api *API) respondWithSuccess(w http.ResponseWriter, resp []byte) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_, err := w.Write(resp)
if err != nil {
// this will probably fail too, but try anyway
api.respondWithError(w, err)
}
}
func (api *API) respondWithError(w http.ResponseWriter, err error) {
// this error type comes with an HTTP code, so just use that
se, ok := err.(*kerrors.StatusError)
if ok {
api.logger.Error(err.Error(), zap.Int32("code", se.ErrStatus.Code))
http.Error(w, se.Error(), int(se.ErrStatus.Code))
return
}
code, msg := ferror.GetHTTPError(err)
api.logger.Error(msg, zap.Int("code", code))
http.Error(w, msg, code)
}
func (api *API) extractQueryParamFromRequest(r *http.Request, queryParam string) string {
values := r.URL.Query()
return values.Get(queryParam)
}
// check if namespace exists, if not create it.
func (api *API) createNsIfNotExists(ctx context.Context, ns string) error {
if ns == metav1.NamespaceDefault {
// we don't have to create default ns
return nil
}
_, err := api.kubernetesClient.CoreV1().Namespaces().Get(ctx, ns, metav1.GetOptions{})
if err != nil && kerrors.IsNotFound(err) {
ns := &apiv1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: ns,
},
}
_, err = api.kubernetesClient.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
}
return err
}
func (api *API) getLogDBConfig(dbType string) logDBConfig {
dbType = strings.ToUpper(dbType)
// retrieve db auth config from the env
url := os.Getenv(fmt.Sprintf("%s_URL", dbType))
if url == "" {
// set up default database url
url = logdb.INFLUXDB_URL
}
username := os.Getenv(fmt.Sprintf("%s_USERNAME", dbType))
password := os.Getenv(fmt.Sprintf("%s_PASSWORD", dbType))
return logDBConfig{
httpURL: url,
username: username,
password: password,
}
}
func (api *API) HomeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_, err := w.Write([]byte(info.ApiInfo().String()))
if err != nil {
api.respondWithError(w, err)
}
}
func (api *API) ApiVersionMismatchHandler(w http.ResponseWriter, r *http.Request) {
err := ferror.MakeError(ferror.ErrorNotFound, "Fission server supports API v2 only -- v1 is not supported. Please upgrade your Fission client/CLI.")
api.respondWithError(w, err)
}
func (api *API) HealthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func (api *API) GetSvcName(w http.ResponseWriter, r *http.Request) {
appLabelSelector := "application=" + r.URL.Query().Get("application")
services, err := api.kubernetesClient.CoreV1().Services(podNamespace).List(r.Context(), metav1.ListOptions{
LabelSelector: appLabelSelector,
})
if err != nil || len(services.Items) > 1 || len(services.Items) == 0 {
api.respondWithError(w, err)
}
service := services.Items[0]
fmt.Fprintf(w, service.Name+"."+podNamespace)
}
func (api *API) GetHandler() http.Handler {
r := mux.NewRouter()
r.Use(metrics.HTTPMetricMiddleware)
r.HandleFunc("/healthz", api.HealthHandler).Methods("GET")
// Give a useful error message if an older CLI attempts to make a request
r.HandleFunc(`/v1/{rest:[a-zA-Z0-9=\-\/]+}`, api.ApiVersionMismatchHandler)
r.HandleFunc("/", api.HomeHandler)
r.HandleFunc("/v2/packages", api.PackageApiList).Methods("GET")
r.HandleFunc("/v2/packages", api.PackageApiCreate).Methods("POST")
r.HandleFunc("/v2/packages/{package}", api.PackageApiGet).Methods("GET")
r.HandleFunc("/v2/packages/{package}", api.PackageApiUpdate).Methods("PUT")
r.HandleFunc("/v2/packages/{package}", api.PackageApiDelete).Methods("DELETE")
r.HandleFunc("/v2/functions", api.FunctionApiList).Methods("GET")
r.HandleFunc("/v2/functions", api.FunctionApiCreate).Methods("POST")
r.HandleFunc("/v2/functions/{function}", api.FunctionApiGet).Methods("GET")
r.HandleFunc("/v2/functions/{function}", api.FunctionApiUpdate).Methods("PUT")
r.HandleFunc("/v2/functions/{function}", api.FunctionApiDelete).Methods("DELETE")
r.HandleFunc("/v2/functions/{function}/pods", api.FunctionApiPodList).Methods("GET")
r.HandleFunc("/v2/triggers/http", api.HTTPTriggerApiList).Methods("GET")
r.HandleFunc("/v2/triggers/http", api.HTTPTriggerApiCreate).Methods("POST")
r.HandleFunc("/v2/triggers/http/{httpTrigger}", api.HTTPTriggerApiGet).Methods("GET")
r.HandleFunc("/v2/triggers/http/{httpTrigger}", api.HTTPTriggerApiUpdate).Methods("PUT")
r.HandleFunc("/v2/triggers/http/{httpTrigger}", api.HTTPTriggerApiDelete).Methods("DELETE")
r.HandleFunc("/v2/environments", api.EnvironmentApiList).Methods("GET")
r.HandleFunc("/v2/environments", api.EnvironmentApiCreate).Methods("POST")
r.HandleFunc("/v2/environments/{environment}", api.EnvironmentApiGet).Methods("GET")
r.HandleFunc("/v2/environments/{environment}", api.EnvironmentApiUpdate).Methods("PUT")
r.HandleFunc("/v2/environments/{environment}", api.EnvironmentApiDelete).Methods("DELETE")
r.HandleFunc("/v2/environments/{environment}/pods", api.EnvironmentApiPodList).Methods("GET")
r.HandleFunc("/v2/watches", api.WatchApiList).Methods("GET")
r.HandleFunc("/v2/watches", api.WatchApiCreate).Methods("POST")
r.HandleFunc("/v2/watches/{watch}", api.WatchApiGet).Methods("GET")
r.HandleFunc("/v2/watches/{watch}", api.WatchApiUpdate).Methods("PUT")
r.HandleFunc("/v2/watches/{watch}", api.WatchApiDelete).Methods("DELETE")
r.HandleFunc("/v2/triggers/time", api.TimeTriggerApiList).Methods("GET")
r.HandleFunc("/v2/triggers/time", api.TimeTriggerApiCreate).Methods("POST")
r.HandleFunc("/v2/triggers/time/{timeTrigger}", api.TimeTriggerApiGet).Methods("GET")
r.HandleFunc("/v2/triggers/time/{timeTrigger}", api.TimeTriggerApiUpdate).Methods("PUT")
r.HandleFunc("/v2/triggers/time/{timeTrigger}", api.TimeTriggerApiDelete).Methods("DELETE")
r.HandleFunc("/v2/triggers/messagequeue", api.MessageQueueTriggerApiList).Methods("GET")
r.HandleFunc("/v2/triggers/messagequeue", api.MessageQueueTriggerApiCreate).Methods("POST")
r.HandleFunc("/v2/triggers/messagequeue/{mqTrigger}", api.MessageQueueTriggerApiGet).Methods("GET")
r.HandleFunc("/v2/triggers/messagequeue/{mqTrigger}", api.MessageQueueTriggerApiUpdate).Methods("PUT")
r.HandleFunc("/v2/triggers/messagequeue/{mqTrigger}", api.MessageQueueTriggerApiDelete).Methods("DELETE")
r.HandleFunc("/v2/secrets/{secret}", api.SecretExists).Methods("GET")
r.HandleFunc("/v2/configmaps/{configmap}", api.ConfigMapExists).Methods("GET")
r.HandleFunc("/v2/canaryconfigs", api.CanaryConfigApiCreate).Methods("POST")
r.HandleFunc("/v2/canaryconfigs/{canaryConfig}", api.CanaryConfigApiGet).Methods("GET")
r.HandleFunc("/v2/canaryconfigs/{canaryConfig}", api.CanaryConfigApiUpdate).Methods("PUT")
r.HandleFunc("/v2/canaryconfigs/{canaryConfig}", api.CanaryConfigApiDelete).Methods("DELETE")
r.HandleFunc("/v2/canaryconfigs", api.CanaryConfigApiList).Methods("GET")
r.HandleFunc("/proxy/{dbType}", api.FunctionLogsApiPost).Methods("POST")
r.HandleFunc("/proxy/storage/v1/archive", api.StorageServiceProxy)
r.HandleFunc("/proxy/logs/{function}", api.FunctionPodLogs).Methods("POST")
r.HandleFunc("/proxy/workflows-apiserver/{path:.*}", api.WorkflowApiserverProxy) // Deprecated
r.HandleFunc("/proxy/svcname", api.GetSvcName).Queries("application", "").Methods("GET")
r.Handle("/v2/apidocs.json", openAPI()).Methods("GET")
return r
}
func (api *API) Serve(ctx context.Context, port int) {
handler := otel.GetHandlerWithOTEL(api.GetHandler(), "fission-controller", otel.UrlsToIgnore("/healthz"))
go metrics.ServeMetrics(ctx, api.logger)
httpserver.StartServer(ctx, api.logger, "controller", fmt.Sprintf("%d", port), handler)
}
-554
View File
@@ -1,554 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"reflect"
"strings"
"testing"
"time"
uuid "github.com/satori/go.uuid"
"go.uber.org/zap"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/controller/client/rest"
"github.com/fission/fission/pkg/crd"
ferror "github.com/fission/fission/pkg/error"
"github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/utils/loggerfactory"
)
var (
// g struct {
// cmd.CommandActioner
// }
testNS = metav1.NamespaceDefault
)
func panicIf(err error) {
if err != nil {
log.Panicf("err: %v", err)
}
}
func assert(c bool, msg string) {
if !c {
log.Fatalf("assert failed: %v", msg)
}
}
func assertNameReuseFailure(err error, name string) {
assert(err != nil, "recreating "+name+" with same name must fail")
fe, ok := err.(ferror.Error)
assert(ok, "error must be a fission Error")
assert(fe.Code == ferror.ErrorNameExists, "error must be a name exists error")
}
func assertNotFoundFailure(err error, name string) {
assert(err != nil, "requesting a non-existent "+name+" must fail")
fe, ok := err.(ferror.Error)
assert(ok, "error must be a fission Error")
if fe.Code != ferror.ErrorNotFound {
log.Fatalf("error must be a not found error: %v", fe)
}
}
func assertCronSpecFails(err error) {
assert(err != nil, "using an invalid cron spec must fail")
ok := strings.Contains(err.Error(), "not a valid cron spec")
assert(ok, "invalid cron spec must fail")
}
func TestFunctionApi(t *testing.T) {
testFunc := &fv1.Function{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: testNS,
},
Spec: fv1.FunctionSpec{
Environment: fv1.EnvironmentReference{
Name: "nodejs",
Namespace: testNS,
},
Package: fv1.FunctionPackageRef{
FunctionName: "xxx",
PackageRef: fv1.PackageRef{
Namespace: testNS,
Name: "xxx",
ResourceVersion: "12345",
},
},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
_, err := dClient.V1().Function().Get(&metav1.ObjectMeta{
Name: testFunc.ObjectMeta.Name,
Namespace: testNS,
})
assertNotFoundFailure(err, "function")
m, err := dClient.V1().Function().Create(testFunc)
panicIf(err)
defer func() {
err := dClient.V1().Function().Delete(m)
panicIf(err)
}()
_, err = dClient.V1().Function().Create(testFunc)
assertNameReuseFailure(err, "function")
testFunc.ObjectMeta.ResourceVersion = m.ResourceVersion
testFunc.Spec.Package.FunctionName = "yyy"
_, err = dClient.V1().Function().Update(testFunc)
panicIf(err)
testFunc.ObjectMeta.ResourceVersion = ""
testFunc.ObjectMeta.Name = "bar"
m2, err := dClient.V1().Function().Create(testFunc)
panicIf(err)
defer func() {
err := dClient.V1().Function().Delete(m2)
panicIf(err)
}()
funcs, err := dClient.V1().Function().List(testNS)
panicIf(err)
assert(len(funcs) == 2, fmt.Sprintf("created two functions, but found %v", len(funcs)))
funcs_url := dClient.ServerURL() + "/v2/functions"
resp, err := http.Get(funcs_url)
panicIf(err)
defer resp.Body.Close()
assert(resp.StatusCode == 200, "http get status code on /v1/functions")
var found bool = false
for _, b := range resp.Header["Content-Type"] {
if b == "application/json; charset=utf-8" {
found = true
}
}
assert(found, "incorrect response content type")
}
func TestHTTPTriggerApi(t *testing.T) {
testTrigger := &fv1.HTTPTrigger{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: testNS,
},
Spec: fv1.HTTPTriggerSpec{
Methods: []string{http.MethodGet},
RelativeURL: "/hello",
FunctionReference: fv1.FunctionReference{
Type: fv1.FunctionReferenceTypeFunctionName,
Name: "foo",
},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
_, err := dClient.V1().HTTPTrigger().Get(&metav1.ObjectMeta{
Name: testTrigger.ObjectMeta.Name,
Namespace: testNS,
})
assertNotFoundFailure(err, "httptrigger")
m, err := dClient.V1().HTTPTrigger().Create(testTrigger)
panicIf(err)
defer func() {
err := dClient.V1().HTTPTrigger().Delete(m)
panicIf(err)
}()
_, err = dClient.V1().HTTPTrigger().Create(testTrigger)
assertNameReuseFailure(err, "httptrigger")
tr, err := dClient.V1().HTTPTrigger().Get(m)
panicIf(err)
assert(len(testTrigger.Spec.Methods) == len(tr.Spec.Methods) &&
testTrigger.Spec.RelativeURL == tr.Spec.RelativeURL &&
testTrigger.Spec.FunctionReference.Type == tr.Spec.FunctionReference.Type &&
testTrigger.Spec.FunctionReference.Name == tr.Spec.FunctionReference.Name, "trigger should match after reading")
testTrigger.ObjectMeta.ResourceVersion = m.ResourceVersion
testTrigger.Spec.RelativeURL = "/hi"
_, err = dClient.V1().HTTPTrigger().Update(testTrigger)
panicIf(err)
testTrigger.ObjectMeta.ResourceVersion = ""
testTrigger.ObjectMeta.Name = "yyy"
_, err = dClient.V1().HTTPTrigger().Create(testTrigger)
assert(err != nil, "duplicate trigger should not be allowed")
testTrigger.Spec.RelativeURL = "/hi2"
m2, err := dClient.V1().HTTPTrigger().Create(testTrigger)
panicIf(err)
defer func() {
err = dClient.V1().HTTPTrigger().Delete(m2)
panicIf(err)
}()
ts, err := dClient.V1().HTTPTrigger().List(testNS)
panicIf(err)
assert(len(ts) == 2, fmt.Sprintf("created two triggers, but found %v", len(ts)))
}
func createFissionFnForMultipleTrigger() {
testFunc := &fv1.Function{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: testNS,
},
Spec: fv1.FunctionSpec{
Environment: fv1.EnvironmentReference{
Name: "nodejs",
Namespace: testNS,
},
Package: fv1.FunctionPackageRef{
FunctionName: "xxx",
PackageRef: fv1.PackageRef{
Namespace: testNS,
Name: "xxx",
ResourceVersion: "12345",
},
},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
_, err := dClient.V1().Function().Create(testFunc)
panicIf(err)
defer func() {
panicIf(err)
}()
testFunc.Name = "foo2"
_, err = dClient.V1().Function().Create(testFunc)
panicIf(err)
defer func() {
panicIf(err)
}()
}
func TestHTTPTriggerCreateMultipleTrigger(t *testing.T) {
logger := loggerfactory.GetLogger()
createFissionFnForMultipleTrigger()
prefix := "url_new"
testTrigger := &fv1.HTTPTrigger{
ObjectMeta: metav1.ObjectMeta{
Name: "foo1",
Namespace: testNS,
},
Spec: fv1.HTTPTriggerSpec{
Methods: []string{http.MethodGet},
Prefix: &prefix,
FunctionReference: fv1.FunctionReference{
Type: fv1.FunctionReferenceTypeFunctionName,
Name: "foo1",
},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
m, err := dClient.V1().HTTPTrigger().Create(testTrigger)
panicIf(err)
defer panicIf(dClient.V1().HTTPTrigger().Delete(m))
prefix_2 := "url_another"
testTrigger2 := &fv1.HTTPTrigger{
ObjectMeta: metav1.ObjectMeta{
Name: "foo2",
Namespace: testNS,
},
Spec: fv1.HTTPTriggerSpec{
Methods: []string{http.MethodGet},
Prefix: &prefix_2,
FunctionReference: fv1.FunctionReference{
Type: fv1.FunctionReferenceTypeFunctionName,
Name: "foo2",
},
},
}
m2, err := dClient.V1().HTTPTrigger().Create(testTrigger2)
if err != nil {
t.Fatal()
}
defer func() {
if m2 != nil {
err := dClient.V1().HTTPTrigger().Delete(m2)
if err != nil {
logger.Error("Error deleting http trigger", zap.String("name", m2.Name), zap.Error(err))
}
}
}()
}
func TestEnvironmentApi(t *testing.T) {
testEnv := &fv1.Environment{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: testNS,
},
Spec: fv1.EnvironmentSpec{
Version: 1,
Runtime: fv1.Runtime{
Image: "gcr.io/xyz",
},
Resources: v1.ResourceRequirements{},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
_, err := dClient.V1().Environment().Get(&metav1.ObjectMeta{
Name: testEnv.ObjectMeta.Name,
Namespace: testNS,
})
assertNotFoundFailure(err, "environment")
m, err := dClient.V1().Environment().Create(testEnv)
panicIf(err)
defer func() {
err := dClient.V1().Environment().Delete(m)
panicIf(err)
}()
_, err = dClient.V1().Environment().Create(testEnv)
assertNameReuseFailure(err, "environment")
e, err := dClient.V1().Environment().Get(m)
panicIf(err)
assert(reflect.DeepEqual(testEnv.Spec, e.Spec), "env should match after reading")
testEnv.ObjectMeta.ResourceVersion = m.ResourceVersion
testEnv.Spec.Runtime.Image = "another-img"
_, err = dClient.V1().Environment().Update(testEnv)
panicIf(err)
testEnv.ObjectMeta.ResourceVersion = ""
testEnv.ObjectMeta.Name = "bar"
m2, err := dClient.V1().Environment().Create(testEnv)
panicIf(err)
defer func() {
err := dClient.V1().Environment().Delete(m2)
panicIf(err)
}()
ts, err := dClient.V1().Environment().List(testNS)
panicIf(err)
assert(len(ts) == 2, fmt.Sprintf("created two envs, but found %v", len(ts)))
}
func TestWatchApi(t *testing.T) {
testWatch := &fv1.KubernetesWatchTrigger{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx",
Namespace: testNS,
},
Spec: fv1.KubernetesWatchTriggerSpec{
Namespace: "default",
Type: "pod",
FunctionReference: fv1.FunctionReference{
Type: fv1.FunctionReferenceTypeFunctionName,
Name: "foo",
},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
_, err := dClient.V1().KubeWatcher().Get(&metav1.ObjectMeta{
Name: testWatch.ObjectMeta.Name,
Namespace: testNS,
})
assertNotFoundFailure(err, "watch")
m, err := dClient.V1().KubeWatcher().Create(testWatch)
panicIf(err)
defer func() {
err := dClient.V1().KubeWatcher().Delete(m)
panicIf(err)
}()
_, err = dClient.V1().KubeWatcher().Create(testWatch)
assertNameReuseFailure(err, "watch")
w, err := dClient.V1().KubeWatcher().Get(m)
panicIf(err)
assert(testWatch.Spec.Namespace == w.Spec.Namespace &&
testWatch.Spec.Type == w.Spec.Type &&
testWatch.Spec.FunctionReference.Type == w.Spec.FunctionReference.Type &&
testWatch.Spec.FunctionReference.Name == w.Spec.FunctionReference.Name, "watch should match after reading")
testWatch.ObjectMeta.Name = "yyy"
m2, err := dClient.V1().KubeWatcher().Create(testWatch)
panicIf(err)
defer func() {
err := dClient.V1().KubeWatcher().Delete(m2)
panicIf(err)
}()
ws, err := dClient.V1().KubeWatcher().List(testNS)
panicIf(err)
assert(len(ws) == 2, fmt.Sprintf("created two watches, but found %v", len(ws)))
}
func TestTimeTriggerApi(t *testing.T) {
testTrigger := &fv1.TimeTrigger{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx",
Namespace: testNS,
},
Spec: fv1.TimeTriggerSpec{
Cron: "0 30 * * * *",
FunctionReference: fv1.FunctionReference{
Type: fv1.FunctionReferenceTypeFunctionName,
Name: "asdf",
},
},
}
restClient := rest.NewRESTClient("http://localhost:8888")
dClient := client.MakeClientset(restClient)
_, err := dClient.V1().TimeTrigger().Get(&metav1.ObjectMeta{Name: testTrigger.ObjectMeta.Name})
assertNotFoundFailure(err, "trigger")
m, err := dClient.V1().TimeTrigger().Create(testTrigger)
panicIf(err)
defer func() {
err := dClient.V1().TimeTrigger().Delete(m)
panicIf(err)
}()
_, err = dClient.V1().TimeTrigger().Create(testTrigger)
assertNameReuseFailure(err, "trigger")
tr, err := dClient.V1().TimeTrigger().Get(m)
panicIf(err)
assert(testTrigger.Spec.Cron == tr.Spec.Cron &&
testTrigger.Spec.FunctionReference.Type == tr.Spec.FunctionReference.Type &&
testTrigger.Spec.FunctionReference.Name == tr.Spec.FunctionReference.Name, "trigger should match after reading")
testTrigger.ObjectMeta.ResourceVersion = m.ResourceVersion
testTrigger.Spec.Cron = "@hourly"
_, err = dClient.V1().TimeTrigger().Update(testTrigger)
panicIf(err)
testTrigger.ObjectMeta.ResourceVersion = ""
testTrigger.ObjectMeta.Name = "yyy"
testTrigger.Spec.Cron = "Not valid cron spec"
_, err = dClient.V1().TimeTrigger().Create(testTrigger)
assertCronSpecFails(err)
ts, err := dClient.V1().TimeTrigger().List(testNS)
panicIf(err)
assert(len(ts) == 1, fmt.Sprintf("created two time triggers, but found %v", len(ts)))
}
func TestMain(m *testing.M) {
flag.Parse()
ctx, cancel := context.WithCancel(context.Background())
logger := loggerfactory.GetLogger()
// skip test if no cluster available for testing
kubeconfig := os.Getenv("KUBECONFIG")
if len(kubeconfig) == 0 {
log.Println("Skipping test, no kubernetes cluster")
cancel()
return
}
clientGen := crd.NewClientGenerator()
kubeClient, err := clientGen.GetKubernetesClient()
panicIf(err)
// testNS isolation for running multiple CI builds concurrently.
id, err := uuid.NewV4()
panicIf(err)
testNS = id.String()
_, err = kubeClient.CoreV1().Namespaces().Create(ctx, &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: testNS,
},
}, metav1.CreateOptions{})
panicIf(err)
go Start(ctx, logger, 8888, true)
time.Sleep(5 * time.Second)
client, err := cmd.NewClient(cmd.ClientOptions{})
panicIf(err)
// TODO: use fake rest client for offline spec generation
cmd.SetClientset(*client)
resp, err := http.Get("http://localhost:8888/")
panicIf(err)
assert(resp.StatusCode == 200, "http get status code on root")
var found bool = false
for _, b := range resp.Header["Content-Type"] {
if b == "application/json; charset=utf-8" {
found = true
}
}
assert(found, "incorrect response content type")
_, err = io.ReadAll(resp.Body)
panicIf(err)
exitVal := m.Run()
logger.Info("Deleting test namespace", zap.String("namespace", testNS))
gracePeriod := int64(0)
err = kubeClient.CoreV1().Namespaces().Delete(ctx, testNS, metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod})
if err != nil {
logger.Error("error deleting test namespace", zap.String("namespace", testNS), zap.Error(err))
}
cancel()
os.Exit(exitVal)
}
-254
View File
@@ -1,254 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"encoding/json"
"fmt"
"io"
"net/http"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
config "github.com/fission/fission/pkg/featureconfig"
)
func RegisterCanaryConfigRoute(ws *restful.WebService) {
tags := []string{"CanaryConfig"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "CanaryConfig", Description: "CanaryConfig Operation"}})
ws.Route(
ws.GET("/v2/canaryconfigs").
Doc("List all canary configs").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of canaryConfig").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.CanaryConfig{}).
Returns(http.StatusOK, "List of canaryConfigs", []fv1.CanaryConfig{}))
ws.Route(
ws.POST("/v2/canaryconfigs").
Doc("Create canary config").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.CanaryConfig{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created canaryConfig", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/canaryconfigs/{canaryConfig}").
Doc("Get detail of canary config").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("canaryConfig", "CanaryConfig name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of canaryConfig").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.CanaryConfig{}). // on the response
Returns(http.StatusOK, "A canaryConfig", fv1.CanaryConfig{}))
ws.Route(
ws.PUT("/v2/canaryconfigs/{canaryConfig}").
Doc("Update canary config").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("canaryConfig", "CanaryConfig name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.CanaryConfig{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated canaryConfig", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/canaryconfigs/{canaryConfig}").
Doc("Delete canary config").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("canaryConfig", "CanaryConfig name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of canaryConfig").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) CanaryConfigApiCreate(w http.ResponseWriter, r *http.Request) {
featureErr := a.featureStatus[config.CanaryFeature]
if len(featureErr) > 0 {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var canaryCfg fv1.CanaryConfig
err = json.Unmarshal(body, &canaryCfg)
if err != nil {
a.logger.Error("failed to unmarshal request body", zap.Error(err), zap.Binary("body", body))
a.respondWithError(w, err)
return
}
canaryCfgNew, err := a.fissionClient.CoreV1().CanaryConfigs(canaryCfg.ObjectMeta.Namespace).Create(r.Context(), &canaryCfg, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(canaryCfgNew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) CanaryConfigApiGet(w http.ResponseWriter, r *http.Request) {
featureErr := a.featureStatus[config.CanaryFeature]
if len(featureErr) > 0 {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return
}
vars := mux.Vars(r)
name := vars["canaryConfig"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
canaryCfg, err := a.fissionClient.CoreV1().CanaryConfigs(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(canaryCfg)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) CanaryConfigApiList(w http.ResponseWriter, r *http.Request) {
featureErr := a.featureStatus[config.CanaryFeature]
if len(featureErr) > 0 {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return
}
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
canaryCfgs, err := a.fissionClient.CoreV1().CanaryConfigs(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(canaryCfgs.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) CanaryConfigApiUpdate(w http.ResponseWriter, r *http.Request) {
featureErr := a.featureStatus[config.CanaryFeature]
if len(featureErr) > 0 {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var c fv1.CanaryConfig
err = json.Unmarshal(body, &c)
if err != nil {
a.respondWithError(w, err)
return
}
canayCfgNew, err := a.fissionClient.CoreV1().CanaryConfigs(c.ObjectMeta.Namespace).Update(r.Context(), &c, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(canayCfgNew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) CanaryConfigApiDelete(w http.ResponseWriter, r *http.Request) {
featureErr := a.featureStatus[config.CanaryFeature]
if len(featureErr) > 0 {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return
}
vars := mux.Vars(r)
name := vars["canaryConfig"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().CanaryConfigs(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
-49
View File
@@ -1,49 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"github.com/fission/fission/pkg/controller/client/rest"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
Interface interface {
V1() v1.V1Interface
ServerURL() string
}
Clientset struct {
restClient rest.Interface
v1 v1.V1Interface
}
)
func MakeClientset(restClient rest.Interface) Interface {
return &Clientset{
restClient: restClient,
v1: v1.MakeV1Client(restClient),
}
}
func (c *Clientset) V1() v1.V1Interface {
return c.v1
}
func (c *Clientset) ServerURL() string {
return c.restClient.ServerURL()
}
-43
View File
@@ -1,43 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"github.com/fission/fission/pkg/controller/client/rest"
v1 "github.com/fission/fission/pkg/controller/client/v1"
"github.com/fission/fission/pkg/controller/client/v1/fake"
)
type (
FakeClientset struct {
v1 v1.V1Interface
}
)
func MakeFakeClientset(restClient rest.Interface) Interface {
return &FakeClientset{
v1: fake.MakeV1Client(nil),
}
}
func (c *FakeClientset) V1() v1.V1Interface {
return c.v1
}
func (c *FakeClientset) ServerURL() string {
return ""
}
-128
View File
@@ -1,128 +0,0 @@
/*
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 rest
import (
"bytes"
"context"
"io"
"net/http"
"strings"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
type (
Interface interface {
Create(relativeUrl string, contentType string, payload []byte) (*http.Response, error)
Put(relativeUrl string, contentType string, payload []byte) (*http.Response, error)
Get(relativeUrl string) (*http.Response, error)
Delete(relativeUrl string) error
Proxy(method string, relativeUrl string, payload []byte) (*http.Response, error)
ServerInfo() (*http.Response, error)
ServerURL() string
}
RESTClient struct {
url string
HTTPClient *http.Client
}
)
func NewRESTClient(serverUrl string) Interface {
return &RESTClient{
url: strings.TrimSuffix(serverUrl, "/"),
HTTPClient: &http.Client{
Transport: otelhttp.NewTransport(http.DefaultTransport),
},
}
}
func (c *RESTClient) Create(relativeUrl string, contentType string, payload []byte) (*http.Response, error) {
var reader io.Reader
if len(payload) > 0 {
reader = bytes.NewReader(payload)
}
return c.sendRequest(context.TODO(), http.MethodPost, c.v2CrdUrl(relativeUrl), map[string]string{"Content-type": contentType}, reader)
}
func (c *RESTClient) Put(relativeUrl string, contentType string, payload []byte) (*http.Response, error) {
var reader io.Reader
if len(payload) > 0 {
reader = bytes.NewReader(payload)
}
return c.sendRequest(context.TODO(), http.MethodPut, c.v2CrdUrl(relativeUrl), map[string]string{"Content-type": contentType}, reader)
}
func (c *RESTClient) Get(relativeUrl string) (*http.Response, error) {
return c.sendRequest(context.TODO(), http.MethodGet, c.v2CrdUrl(relativeUrl), nil, nil)
}
func (c *RESTClient) Delete(relativeUrl string) error {
resp, err := c.sendRequest(context.TODO(), http.MethodDelete, c.v2CrdUrl(relativeUrl), nil, nil)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
body, err := io.ReadAll(resp.Body)
if err != nil {
return errors.Wrap(err, "error deleting")
} else {
return errors.Errorf("failed to delete: %v", string(body))
}
}
return nil
}
func (c *RESTClient) Proxy(method string, relativeUrl string, payload []byte) (*http.Response, error) {
var reader io.Reader
if len(payload) > 0 {
reader = bytes.NewReader(payload)
}
return c.sendRequest(context.TODO(), method, c.proxyUrl(relativeUrl), nil, reader)
}
func (c *RESTClient) ServerInfo() (*http.Response, error) {
return c.sendRequest(context.TODO(), http.MethodGet, c.url, nil, nil)
}
func (c *RESTClient) ServerURL() string {
return c.url
}
func (c *RESTClient) sendRequest(ctx context.Context, method string, relativeUrl string, headers map[string]string, reader io.Reader) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, method, relativeUrl, reader)
if err != nil {
return nil, err
}
for k, v := range headers {
req.Header.Set(k, v)
}
return c.HTTPClient.Do(req)
}
func (c *RESTClient) v2CrdUrl(relativeUrl string) string {
return c.url + "/v2/" + strings.TrimPrefix(relativeUrl, "/")
}
func (c *RESTClient) proxyUrl(relativeUrl string) string {
return c.url + "/proxy/" + strings.TrimPrefix(relativeUrl, "/")
}
-153
View File
@@ -1,153 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
)
type (
CanaryConfigGetter interface {
CanaryConfig() CanaryConfigInterface
}
CanaryConfigInterface interface {
Create(canaryConf *fv1.CanaryConfig) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.CanaryConfig, error)
Update(canaryConf *fv1.CanaryConfig) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(ns string) ([]fv1.CanaryConfig, error)
}
CanaryConfig struct {
client rest.Interface
}
)
func newCanaryConfigClient(c *V1) CanaryConfigInterface {
return &CanaryConfig{client: c.restClient}
}
func (c *CanaryConfig) Create(canaryConf *fv1.CanaryConfig) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(canaryConf)
if err != nil {
return nil, err
}
resp, err := c.client.Create("canaryconfigs", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *CanaryConfig) Get(m *metav1.ObjectMeta) (*fv1.CanaryConfig, error) {
relativeUrl := fmt.Sprintf("canaryconfigs/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var canaryCfg fv1.CanaryConfig
err = json.Unmarshal(body, &canaryCfg)
if err != nil {
return nil, err
}
return &canaryCfg, nil
}
func (c *CanaryConfig) Update(canaryConf *fv1.CanaryConfig) (*metav1.ObjectMeta, error) {
reqbody, err := json.Marshal(canaryConf)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("canaryconfigs/%v", canaryConf.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *CanaryConfig) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("canaryconfigs/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *CanaryConfig) List(ns string) ([]fv1.CanaryConfig, error) {
relativeUrl := fmt.Sprintf("canaryconfigs?namespace=%v", ns)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
canaryCfgs := make([]fv1.CanaryConfig, 0)
err = json.Unmarshal(body, &canaryCfgs)
if err != nil {
return nil, err
}
return canaryCfgs, nil
}
-202
View File
@@ -1,202 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
"net/url"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
"github.com/fission/fission/pkg/generator/encoder"
v1generator "github.com/fission/fission/pkg/generator/v1"
)
type (
EnvironmentGetter interface {
Environment() EnvironmentInterface
}
EnvironmentInterface interface {
Create(env *fv1.Environment) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.Environment, error)
Update(env *fv1.Environment) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(ns string) ([]fv1.Environment, error)
ListPods(m *metav1.ObjectMeta) ([]apiv1.Pod, error)
}
Environment struct {
client rest.Interface
}
)
func getEnvEncodingPayload(env *fv1.Environment) ([]byte, error) {
generator, err := v1generator.CreateEnvironmentGeneratorFromObj(env)
if err != nil {
return nil, err
}
return generator.StructuredGenerate(encoder.DefaultJSONEncoder())
}
func newEnvironmentClient(c *V1) EnvironmentInterface {
return &Environment{client: c.restClient}
}
func (c *Environment) Create(env *fv1.Environment) (*metav1.ObjectMeta, error) {
data, err := getEnvEncodingPayload(env)
if err != nil {
return nil, err
}
resp, err := c.client.Create("environments", "application/json", data)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *Environment) Get(m *metav1.ObjectMeta) (*fv1.Environment, error) {
relativeUrl := fmt.Sprintf("environments/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var env fv1.Environment
err = json.Unmarshal(body, &env)
if err != nil {
return nil, err
}
return &env, nil
}
func (c *Environment) Update(env *fv1.Environment) (*metav1.ObjectMeta, error) {
data, err := getEnvEncodingPayload(env)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("environments/%v", env.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", data)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *Environment) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("environments/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *Environment) List(ns string) ([]fv1.Environment, error) {
relativeUrl := fmt.Sprintf("environments?namespace=%v", ns)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
envs := make([]fv1.Environment, 0)
err = json.Unmarshal(body, &envs)
if err != nil {
return nil, err
}
return envs, nil
}
func (c *Environment) ListPods(m *metav1.ObjectMeta) ([]apiv1.Pod, error) {
relativeUrl := fmt.Sprintf("environments/%s/pods", m.Name)
values := url.Values{}
if len(m.Labels) != 0 {
if envns, ok := m.Labels[fv1.ENVIRONMENT_NAMESPACE]; ok && len(envns) != 0 {
values.Add(fv1.ENVIRONMENT_NAMESPACE, envns)
}
if extype, ok := m.Labels[fv1.EXECUTOR_TYPE]; ok && len(extype) != 0 {
values.Add(fv1.EXECUTOR_TYPE, extype)
}
}
relativeUrl = fmt.Sprintf("%s?%s", relativeUrl, values.Encode())
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
pods := make([]apiv1.Pod, 0)
err = json.Unmarshal(body, &pods)
if err != nil {
return nil, err
}
return pods, nil
}
@@ -1,52 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeCanaryConfig struct{}
)
func newCanaryConfigClient(c *v1.V1) v1.CanaryConfigInterface {
return &FakeCanaryConfig{}
}
func (c *FakeCanaryConfig) Create(canaryConf *fv1.CanaryConfig) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeCanaryConfig) Get(m *metav1.ObjectMeta) (*fv1.CanaryConfig, error) {
return nil, nil
}
func (c *FakeCanaryConfig) Update(canaryConf *fv1.CanaryConfig) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeCanaryConfig) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeCanaryConfig) List(ns string) ([]fv1.CanaryConfig, error) {
return nil, nil
}
@@ -1,57 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeEnvironment struct{}
)
func newEnvironmentClient(c *v1.V1) v1.EnvironmentInterface {
return &FakeEnvironment{}
}
func (c *FakeEnvironment) Create(env *fv1.Environment) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeEnvironment) Get(m *metav1.ObjectMeta) (*fv1.Environment, error) {
return nil, nil
}
func (c *FakeEnvironment) Update(env *fv1.Environment) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeEnvironment) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeEnvironment) List(ns string) ([]fv1.Environment, error) {
return nil, nil
}
func (c *FakeEnvironment) ListPods(m *metav1.ObjectMeta) ([]apiv1.Pod, error) {
return nil, nil
}
@@ -1,61 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeFunction struct{}
)
func newFunctionClient(c *v1.V1) v1.FunctionInterface {
return &FakeFunction{}
}
func (c *FakeFunction) Create(f *fv1.Function) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeFunction) Get(m *metav1.ObjectMeta) (*fv1.Function, error) {
return nil, nil
}
func (c *FakeFunction) GetRawDeployment(m *metav1.ObjectMeta) ([]byte, error) {
return nil, nil
}
func (c *FakeFunction) Update(f *fv1.Function) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeFunction) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeFunction) List(functionNamespace string) ([]fv1.Function, error) {
return nil, nil
}
func (c *FakeFunction) ListPods(m *metav1.ObjectMeta) ([]apiv1.Pod, error) {
return nil, nil
}
@@ -1,52 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeHTTPTrigger struct{}
)
func newHTTPTriggerClient(c *v1.V1) v1.HTTPTriggerInterface {
return &FakeHTTPTrigger{}
}
func (c *FakeHTTPTrigger) Create(t *fv1.HTTPTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeHTTPTrigger) Get(m *metav1.ObjectMeta) (*fv1.HTTPTrigger, error) {
return nil, nil
}
func (c *FakeHTTPTrigger) Update(t *fv1.HTTPTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeHTTPTrigger) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeHTTPTrigger) List(triggerNamespace string) ([]fv1.HTTPTrigger, error) {
return nil, nil
}
@@ -1,52 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeKubeWatcher struct{}
)
func newKubeWatcher(c *v1.V1) v1.KubeWatcherInterface {
return &FakeKubeWatcher{}
}
func (c *FakeKubeWatcher) Create(w *fv1.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeKubeWatcher) Get(m *metav1.ObjectMeta) (*fv1.KubernetesWatchTrigger, error) {
return nil, nil
}
func (c *FakeKubeWatcher) Update(w *fv1.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeKubeWatcher) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeKubeWatcher) List(ns string) ([]fv1.KubernetesWatchTrigger, error) {
return nil, nil
}
@@ -1,55 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
"io"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
"github.com/fission/fission/pkg/info"
)
// TODO: we should remove this interface, having this for now is for backward compatibility.
type (
FakeMisc struct{}
)
func newMiscClient(c *v1.V1) v1.MiscInterface {
return &FakeMisc{}
}
func (c *FakeMisc) SecretExists(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeMisc) ConfigMapExists(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeMisc) GetSvcURL(label string) (string, error) {
return "", nil
}
func (c *FakeMisc) ServerInfo() (*info.ServerInfo, error) {
return &info.ServerInfo{}, nil
}
func (c *FakeMisc) PodLogs(m *metav1.ObjectMeta) (io.ReadCloser, int, error) {
return nil, 0, nil
}
@@ -1,52 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeMessageQueueTrigger struct{}
)
func newMessageQueueTrigger(c *v1.V1) v1.MessageQueueTriggerInterface {
return &FakeMessageQueueTrigger{}
}
func (c *FakeMessageQueueTrigger) Create(t *fv1.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeMessageQueueTrigger) Get(m *metav1.ObjectMeta) (*fv1.MessageQueueTrigger, error) {
return nil, nil
}
func (c *FakeMessageQueueTrigger) Update(mqTrigger *fv1.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeMessageQueueTrigger) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeMessageQueueTrigger) List(mqType string, ns string) ([]fv1.MessageQueueTrigger, error) {
return nil, nil
}
@@ -1,52 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakePackage struct{}
)
func newPackageClient(c *v1.V1) v1.PackageInterface {
return &FakePackage{}
}
func (c *FakePackage) Create(f *fv1.Package) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakePackage) Get(m *metav1.ObjectMeta) (*fv1.Package, error) {
return nil, nil
}
func (c *FakePackage) Update(f *fv1.Package) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakePackage) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakePackage) List(pkgNamespace string) ([]fv1.Package, error) {
return nil, nil
}
@@ -1,52 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeTimeTrigger struct{}
)
func newTimeTriggerClient(c *v1.V1) v1.TimeTriggerInterface {
return &FakeTimeTrigger{}
}
func (c *FakeTimeTrigger) Create(t *fv1.TimeTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeTimeTrigger) Get(m *metav1.ObjectMeta) (*fv1.TimeTrigger, error) {
return nil, nil
}
func (c *FakeTimeTrigger) Update(t *fv1.TimeTrigger) (*metav1.ObjectMeta, error) {
return nil, nil
}
func (c *FakeTimeTrigger) Delete(m *metav1.ObjectMeta) error {
return nil
}
func (c *FakeTimeTrigger) List(ns string) ([]fv1.TimeTrigger, error) {
return nil, nil
}
-66
View File
@@ -1,66 +0,0 @@
/*
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 fake
import (
"github.com/fission/fission/pkg/controller/client/rest"
v1 "github.com/fission/fission/pkg/controller/client/v1"
)
type (
FakeV1 struct{}
)
func MakeV1Client(restClient rest.Interface) *FakeV1 {
return &FakeV1{}
}
func (c *FakeV1) Misc() v1.MiscInterface {
return newMiscClient(nil)
}
func (c *FakeV1) CanaryConfig() v1.CanaryConfigInterface {
return newCanaryConfigClient(nil)
}
func (c *FakeV1) Environment() v1.EnvironmentInterface {
return newEnvironmentClient(nil)
}
func (c *FakeV1) Function() v1.FunctionInterface {
return newFunctionClient(nil)
}
func (c *FakeV1) HTTPTrigger() v1.HTTPTriggerInterface {
return newHTTPTriggerClient(nil)
}
func (c *FakeV1) KubeWatcher() v1.KubeWatcherInterface {
return newKubeWatcher(nil)
}
func (c *FakeV1) MessageQueueTrigger() v1.MessageQueueTriggerInterface {
return newMessageQueueTrigger(nil)
}
func (c *FakeV1) Package() v1.PackageInterface {
return newPackageClient(nil)
}
func (c *FakeV1) TimeTrigger() v1.TimeTriggerInterface {
return newTimeTriggerClient(nil)
}
-212
View File
@@ -1,212 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
"net/url"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
)
type (
FunctionGetter interface {
Function() FunctionInterface
}
FunctionInterface interface {
Create(f *fv1.Function) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.Function, error)
GetRawDeployment(m *metav1.ObjectMeta) ([]byte, error)
Update(f *fv1.Function) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(functionNamespace string) ([]fv1.Function, error)
ListPods(m *metav1.ObjectMeta) ([]apiv1.Pod, error)
}
Function struct {
client rest.Interface
}
)
func newFunctionClient(c *V1) FunctionInterface {
return &Function{client: c.restClient}
}
func (c *Function) Create(f *fv1.Function) (*metav1.ObjectMeta, error) {
err := f.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("Function", err)
}
reqbody, err := json.Marshal(f)
if err != nil {
return nil, err
}
resp, err := c.client.Create("functions", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *Function) Get(m *metav1.ObjectMeta) (*fv1.Function, error) {
relativeUrl := fmt.Sprintf("functions/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var f fv1.Function
err = json.Unmarshal(body, &f)
if err != nil {
return nil, err
}
return &f, nil
}
func (c *Function) GetRawDeployment(m *metav1.ObjectMeta) ([]byte, error) {
relativeUrl := fmt.Sprintf("functions/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
relativeUrl += "&deploymentraw=1"
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return handleResponse(resp)
}
func (c *Function) Update(f *fv1.Function) (*metav1.ObjectMeta, error) {
err := f.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("Function", err)
}
reqbody, err := json.Marshal(f)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("functions/%v", f.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *Function) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("functions/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *Function) List(functionNamespace string) ([]fv1.Function, error) {
relativeUrl := fmt.Sprintf("functions?namespace=%v", functionNamespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
funcs := make([]fv1.Function, 0)
err = json.Unmarshal(body, &funcs)
if err != nil {
return nil, err
}
return funcs, nil
}
func (c *Function) ListPods(m *metav1.ObjectMeta) ([]apiv1.Pod, error) {
relativeUrl := fmt.Sprintf("functions/%s/pods", m.Name)
values := url.Values{}
if len(m.Labels) != 0 {
if fns, ok := m.Labels[fv1.FUNCTION_NAMESPACE]; ok && len(fns) != 0 {
values.Add(fv1.FUNCTION_NAMESPACE, fns)
}
}
relativeUrl = fmt.Sprintf("%s?%s", relativeUrl, values.Encode())
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
pods := make([]apiv1.Pod, 0)
err = json.Unmarshal(body, &pods)
if err != nil {
return nil, err
}
return pods, nil
}
-163
View File
@@ -1,163 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
)
type (
HTTPTriggerGetter interface {
HTTPTrigger() HTTPTriggerInterface
}
HTTPTriggerInterface interface {
Create(t *fv1.HTTPTrigger) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.HTTPTrigger, error)
Update(t *fv1.HTTPTrigger) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(triggerNamespace string) ([]fv1.HTTPTrigger, error)
}
HTTPTrigger struct {
client rest.Interface
}
)
func newHTTPTriggerClient(c *V1) HTTPTriggerInterface {
return &HTTPTrigger{client: c.restClient}
}
func (c *HTTPTrigger) Create(t *fv1.HTTPTrigger) (*metav1.ObjectMeta, error) {
err := t.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("HTTPTrigger", err)
}
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
}
resp, err := c.client.Create("triggers/http", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *HTTPTrigger) Get(m *metav1.ObjectMeta) (*fv1.HTTPTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/http/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var t fv1.HTTPTrigger
err = json.Unmarshal(body, &t)
if err != nil {
return nil, err
}
return &t, nil
}
func (c *HTTPTrigger) Update(t *fv1.HTTPTrigger) (*metav1.ObjectMeta, error) {
err := t.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("HTTPTrigger", err)
}
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("triggers/http/%v", t.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *HTTPTrigger) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("triggers/http/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *HTTPTrigger) List(triggerNamespace string) ([]fv1.HTTPTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/http?namespace=%v", triggerNamespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
triggers := make([]fv1.HTTPTrigger, 0)
err = json.Unmarshal(body, &triggers)
if err != nil {
return nil, err
}
return triggers, nil
}
@@ -1,137 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
ferror "github.com/fission/fission/pkg/error"
)
type (
KubeWatcherGetter interface {
KubeWatcher() KubeWatcherInterface
}
KubeWatcherInterface interface {
Create(w *fv1.KubernetesWatchTrigger) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.KubernetesWatchTrigger, error)
Update(w *fv1.KubernetesWatchTrigger) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(ns string) ([]fv1.KubernetesWatchTrigger, error)
}
KubeWatcher struct {
client rest.Interface
}
)
func newKubeWatcher(c *V1) KubeWatcherInterface {
return &KubeWatcher{client: c.restClient}
}
func (c *KubeWatcher) Create(w *fv1.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
err := w.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("KubernetesWatchTrigger", err)
}
reqbody, err := json.Marshal(w)
if err != nil {
return nil, err
}
resp, err := c.client.Create("watches", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *KubeWatcher) Get(m *metav1.ObjectMeta) (*fv1.KubernetesWatchTrigger, error) {
relativeUrl := fmt.Sprintf("watches/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var w fv1.KubernetesWatchTrigger
err = json.Unmarshal(body, &w)
if err != nil {
return nil, err
}
return &w, nil
}
func (c *KubeWatcher) Update(w *fv1.KubernetesWatchTrigger) (*metav1.ObjectMeta, error) {
return nil, ferror.MakeError(ferror.ErrorNotImplemented, "watch update not implemented")
}
func (c *KubeWatcher) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("watches/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *KubeWatcher) List(ns string) ([]fv1.KubernetesWatchTrigger, error) {
relativeUrl := fmt.Sprintf("watches?namespace=%v", ns)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
watches := make([]fv1.KubernetesWatchTrigger, 0)
err = json.Unmarshal(body, &watches)
if err != nil {
return nil, err
}
return watches, err
}
-137
View File
@@ -1,137 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/pkg/errors"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/fission/fission/pkg/controller/client/rest"
"github.com/fission/fission/pkg/fission-cli/console"
"github.com/fission/fission/pkg/info"
)
// TODO: we should remove this interface, having this for now is for backward compatibility.
type (
MiscGetter interface {
Misc() MiscInterface
}
MiscInterface interface {
SecretExists(m *metav1.ObjectMeta) error
ConfigMapExists(m *metav1.ObjectMeta) error
GetSvcURL(label string) (string, error)
ServerInfo() (*info.ServerInfo, error)
PodLogs(m *metav1.ObjectMeta) (io.ReadCloser, int, error)
}
Misc struct {
client rest.Interface
}
)
func newMiscClient(c *V1) MiscInterface {
return &Misc{client: c.restClient}
}
func (c *Misc) SecretExists(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("secrets/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return k8serrors.NewNotFound(schema.GroupResource{Group: "", Resource: "secret"}, m.Name)
}
return nil
}
func (c *Misc) ConfigMapExists(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("configmaps/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
return k8serrors.NewNotFound(schema.GroupResource{Group: "", Resource: "configmap"}, m.Name)
}
return nil
}
func (c *Misc) GetSvcURL(label string) (string, error) {
resp, err := c.client.Proxy(http.MethodGet, "svcname?"+label, nil)
if err != nil {
return "", err
}
if resp == nil {
return "", errors.Errorf("failed to find service for given label: %v", label)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
storageSvc := string(body)
return storageSvc, err
}
func (c *Misc) ServerInfo() (*info.ServerInfo, error) {
resp, err := c.client.ServerInfo()
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
info := &info.ServerInfo{}
err = json.Unmarshal(body, info)
if err != nil {
return nil, err
}
return info, nil
}
func (c *Misc) PodLogs(m *metav1.ObjectMeta) (io.ReadCloser, int, error) {
uri := fmt.Sprintf("logs/%s", m.Name)
console.Verbose(2, fmt.Sprintf("Try to get pod logs from controller '%v'", uri))
resp, err := c.client.Proxy(http.MethodPost, uri, nil)
if err != nil {
return nil, 0, errors.Wrap(err, "error executing get logs request")
}
return resp.Body, resp.StatusCode, nil
}
-168
View File
@@ -1,168 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
)
type (
MessageQueueTriggerGetter interface {
MessageQueueTrigger() MessageQueueTriggerInterface
}
MessageQueueTriggerInterface interface {
Create(t *fv1.MessageQueueTrigger) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.MessageQueueTrigger, error)
Update(mqTrigger *fv1.MessageQueueTrigger) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(mqType string, ns string) ([]fv1.MessageQueueTrigger, error)
}
MessageQueueTrigger struct {
client rest.Interface
}
)
func newMessageQueueTrigger(c *V1) MessageQueueTriggerInterface {
return &MessageQueueTrigger{client: c.restClient}
}
func (c *MessageQueueTrigger) Create(t *fv1.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
err := t.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("MessageQueueTrigger", err)
}
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
}
resp, err := c.client.Create("triggers/messagequeue", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *MessageQueueTrigger) Get(m *metav1.ObjectMeta) (*fv1.MessageQueueTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/messagequeue/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var t fv1.MessageQueueTrigger
err = json.Unmarshal(body, &t)
if err != nil {
return nil, err
}
return &t, nil
}
func (c *MessageQueueTrigger) Update(mqTrigger *fv1.MessageQueueTrigger) (*metav1.ObjectMeta, error) {
err := mqTrigger.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("MessageQueueTrigger", err)
}
reqbody, err := json.Marshal(mqTrigger)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("triggers/messagequeue/%v", mqTrigger.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *MessageQueueTrigger) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("triggers/messagequeue/%s", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%s", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *MessageQueueTrigger) List(mqType string, ns string) ([]fv1.MessageQueueTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/messagequeue?namespace=%s", ns)
if len(mqType) > 0 {
// TODO remove this, replace with field selector
relativeUrl += fmt.Sprintf("&mqtype=%s", mqType)
}
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
triggers := make([]fv1.MessageQueueTrigger, 0)
err = json.Unmarshal(body, &triggers)
if err != nil {
return nil, err
}
return triggers, nil
}
-163
View File
@@ -1,163 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
)
type (
PackageGetter interface {
Package() PackageInterface
}
PackageInterface interface {
Create(f *fv1.Package) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.Package, error)
Update(f *fv1.Package) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(pkgNamespace string) ([]fv1.Package, error)
}
Package struct {
client rest.Interface
}
)
func newPackageClient(c *V1) PackageInterface {
return &Package{client: c.restClient}
}
func (c *Package) Create(f *fv1.Package) (*metav1.ObjectMeta, error) {
err := f.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("Package", err)
}
reqbody, err := json.Marshal(f)
if err != nil {
return nil, err
}
resp, err := c.client.Create("packages", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *Package) Get(m *metav1.ObjectMeta) (*fv1.Package, error) {
relativeUrl := fmt.Sprintf("packages/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var f fv1.Package
err = json.Unmarshal(body, &f)
if err != nil {
return nil, err
}
return &f, nil
}
func (c *Package) Update(f *fv1.Package) (*metav1.ObjectMeta, error) {
err := f.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("Package", err)
}
reqbody, err := json.Marshal(f)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("packages/%v", f.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *Package) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("packages/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *Package) List(pkgNamespace string) ([]fv1.Package, error) {
relativeUrl := fmt.Sprintf("packages?namespace=%v", pkgNamespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
funcs := make([]fv1.Package, 0)
err = json.Unmarshal(body, &funcs)
if err != nil {
return nil, err
}
return funcs, nil
}
-163
View File
@@ -1,163 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client/rest"
)
type (
TimeTriggerGetter interface {
TimeTrigger() TimeTriggerInterface
}
TimeTriggerInterface interface {
Create(t *fv1.TimeTrigger) (*metav1.ObjectMeta, error)
Get(m *metav1.ObjectMeta) (*fv1.TimeTrigger, error)
Update(t *fv1.TimeTrigger) (*metav1.ObjectMeta, error)
Delete(m *metav1.ObjectMeta) error
List(ns string) ([]fv1.TimeTrigger, error)
}
TimeTrigger struct {
client rest.Interface
}
)
func newTimeTriggerClient(c *V1) TimeTriggerInterface {
return &TimeTrigger{client: c.restClient}
}
func (c *TimeTrigger) Create(t *fv1.TimeTrigger) (*metav1.ObjectMeta, error) {
err := t.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("TimeTrigger", err)
}
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
}
resp, err := c.client.Create("triggers/time", "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleCreateResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *TimeTrigger) Get(m *metav1.ObjectMeta) (*fv1.TimeTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/time/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var t fv1.TimeTrigger
err = json.Unmarshal(body, &t)
if err != nil {
return nil, err
}
return &t, nil
}
func (c *TimeTrigger) Update(t *fv1.TimeTrigger) (*metav1.ObjectMeta, error) {
err := t.Validate()
if err != nil {
return nil, fv1.AggregateValidationErrors("TimeTrigger", err)
}
reqbody, err := json.Marshal(t)
if err != nil {
return nil, err
}
relativeUrl := fmt.Sprintf("triggers/time/%v", t.ObjectMeta.Name)
resp, err := c.client.Put(relativeUrl, "application/json", reqbody)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
var m metav1.ObjectMeta
err = json.Unmarshal(body, &m)
if err != nil {
return nil, err
}
return &m, nil
}
func (c *TimeTrigger) Delete(m *metav1.ObjectMeta) error {
relativeUrl := fmt.Sprintf("triggers/time/%v", m.Name)
relativeUrl += fmt.Sprintf("?namespace=%v", m.Namespace)
return c.client.Delete(relativeUrl)
}
func (c *TimeTrigger) List(ns string) ([]fv1.TimeTrigger, error) {
relativeUrl := fmt.Sprintf("triggers/time?namespace=%v", ns)
resp, err := c.client.Get(relativeUrl)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := handleResponse(resp)
if err != nil {
return nil, err
}
triggers := make([]fv1.TimeTrigger, 0)
err = json.Unmarshal(body, &triggers)
if err != nil {
return nil, err
}
return triggers, nil
}
-99
View File
@@ -1,99 +0,0 @@
/*
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 v1
import (
"io"
"net/http"
"github.com/fission/fission/pkg/controller/client/rest"
ferror "github.com/fission/fission/pkg/error"
)
type (
V1Interface interface {
MiscGetter
CanaryConfigGetter
EnvironmentGetter
FunctionGetter
HTTPTriggerGetter
KubeWatcherGetter
MessageQueueTriggerGetter
PackageGetter
TimeTriggerGetter
}
V1 struct {
restClient rest.Interface
}
)
func MakeV1Client(restClient rest.Interface) *V1 {
return &V1{restClient: restClient}
}
func (c *V1) Misc() MiscInterface {
return newMiscClient(c)
}
func (c *V1) CanaryConfig() CanaryConfigInterface {
return newCanaryConfigClient(c)
}
func (c *V1) Environment() EnvironmentInterface {
return newEnvironmentClient(c)
}
func (c *V1) Function() FunctionInterface {
return newFunctionClient(c)
}
func (c *V1) HTTPTrigger() HTTPTriggerInterface {
return newHTTPTriggerClient(c)
}
func (c *V1) KubeWatcher() KubeWatcherInterface {
return newKubeWatcher(c)
}
func (c *V1) MessageQueueTrigger() MessageQueueTriggerInterface {
return newMessageQueueTrigger(c)
}
func (c *V1) Package() PackageInterface {
return newPackageClient(c)
}
func (c *V1) TimeTrigger() TimeTriggerInterface {
return newTimeTriggerClient(c)
}
func handleResponse(resp *http.Response) ([]byte, error) {
if resp.StatusCode != 200 {
return nil, ferror.MakeErrorFromHTTP(resp)
}
body, err := io.ReadAll(resp.Body)
return body, err
}
func handleCreateResponse(resp *http.Response) ([]byte, error) {
if resp.StatusCode != 201 {
return nil, ferror.MakeErrorFromHTTP(resp)
}
body, err := io.ReadAll(resp.Body)
return body, err
}
-66
View File
@@ -1,66 +0,0 @@
/*
Copyright 2018 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"github.com/pkg/errors"
"go.uber.org/zap"
"k8s.io/client-go/kubernetes"
"github.com/fission/fission/pkg/canaryconfigmgr"
config "github.com/fission/fission/pkg/featureconfig"
"github.com/fission/fission/pkg/generated/clientset/versioned"
)
func ConfigCanaryFeature(ctx context.Context, logger *zap.Logger, fissionClient versioned.Interface, kubeClient kubernetes.Interface, featureConfig *config.FeatureConfig, featureStatus map[string]string) error {
// start the appropriate controller
if featureConfig.CanaryConfig.IsEnabled {
canaryCfgMgr, err := canaryconfigmgr.MakeCanaryConfigMgr(ctx, logger, fissionClient, kubeClient, featureConfig.CanaryConfig.PrometheusSvc)
if err != nil {
featureStatus[config.CanaryFeature] = err.Error()
return errors.Wrap(err, "failed to start canary config manager")
}
canaryCfgMgr.Run(ctx)
logger.Info("started canary config manager")
}
return nil
}
// ConfigureFeatures gets the feature config and configures the features that are enabled
func ConfigureFeatures(ctx context.Context, logger *zap.Logger, unitTestMode bool, fissionClient versioned.Interface, kubeClient kubernetes.Interface) (map[string]string, error) {
// set feature enabled to false if unitTestMode
if unitTestMode {
return nil, nil
}
// get the featureConfig from config map mounted onto the file system
featureConfig, err := config.GetFeatureConfig()
if err != nil {
logger.Error("error getting feature config", zap.Error(err))
return nil, err
}
featureStatus := make(map[string]string)
// configure respective features
// in the future when new optional features are added, we need to add corresponding feature handlers and invoke them here
err = ConfigCanaryFeature(ctx, logger, fissionClient, kubeClient, featureConfig, featureStatus)
return featureStatus, err
}
-42
View File
@@ -1,42 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"net/http"
"github.com/gorilla/mux"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (a *API) ConfigMapExists(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["configmap"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
_, err := a.kubernetesClient.CoreV1().ConfigMaps(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.logger.Error("error getting config map", zap.Error(err), zap.String("config_map_name", name), zap.String("namespace", ns))
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, nil)
}
-59
View File
@@ -1,59 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"go.uber.org/zap"
"github.com/fission/fission/pkg/crd"
)
func Start(ctx context.Context, logger *zap.Logger, port int, unitTestFlag bool) {
cLogger := logger.Named("controller")
clientGen := crd.NewClientGenerator()
fissionClient, err := clientGen.GetFissionClient()
if err != nil {
cLogger.Fatal("failed to get fission client", zap.Error(err))
}
apiExtClient, err := clientGen.GetApiExtensionsClient()
if err != nil {
cLogger.Fatal("failed to get api extension client client", zap.Error(err))
}
kubeClient, err := clientGen.GetKubernetesClient()
if err != nil {
cLogger.Fatal("failed to get kubernetes client", zap.Error(err))
}
err = crd.EnsureFissionCRDs(ctx, cLogger, apiExtClient)
if err != nil {
cLogger.Fatal("failed to find fission CRDs", zap.Error(err))
}
err = crd.WaitForCRDs(ctx, logger, fissionClient)
if err != nil {
cLogger.Fatal("error waiting for CRDs", zap.Error(err))
}
api, err := MakeAPI(cLogger, fissionClient, kubeClient)
if err != nil {
cLogger.Fatal("failed to start controller", zap.Error(err))
}
api.Serve(ctx, port)
}
-32
View File
@@ -1,32 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"go.uber.org/zap"
"k8s.io/client-go/kubernetes"
"github.com/fission/fission/pkg/generated/clientset/versioned"
)
func makeCRDBackedAPI(logger *zap.Logger, fissionClient versioned.Interface, kubernetesClient kubernetes.Interface) (*API, error) {
return &API{
logger: logger.Named("api"),
fissionClient: fissionClient,
kubernetesClient: kubernetesClient,
}, nil
}
-281
View File
@@ -1,281 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"encoding/json"
"io"
"net/http"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterEnvironmentRoute(ws *restful.WebService) {
tags := []string{"Environment"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "Environment", Description: "Environment Operation"}})
ws.Route(
ws.GET("/v2/environments").
Doc("List all environments").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of environment").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.Environment{}).
Returns(http.StatusOK, "List of environments", []fv1.Environment{}))
ws.Route(
ws.POST("/v2/environments").
Doc("Create environment").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.Environment{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created environment", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/environments/{environment}").
Doc("Get detail of environment").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("environment", "Environment name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of environment").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.Environment{}). // on the response
Returns(http.StatusOK, "A environment", fv1.Environment{}))
ws.Route(
ws.PUT("/v2/environments/{environment}").
Doc("Update environment").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("environment", "Environment name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.Environment{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated environment", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/environments/{environment}").
Doc("Delete environment").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("environment", "Environment name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of environment").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) EnvironmentApiList(w http.ResponseWriter, r *http.Request) {
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
envs, err := a.fissionClient.CoreV1().Environments(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(envs.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) EnvironmentApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var env fv1.Environment
err = json.Unmarshal(body, &env)
if err != nil {
a.logger.Error("failed to unmarshal request body", zap.Error(err), zap.Binary("body", body))
a.respondWithError(w, err)
return
}
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), env.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
enew, err := a.fissionClient.CoreV1().Environments(env.ObjectMeta.Namespace).Create(r.Context(), &env, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(enew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) EnvironmentApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["environment"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
env, err := a.fissionClient.CoreV1().Environments(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(env)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) EnvironmentApiUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["environment"]
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var env fv1.Environment
err = json.Unmarshal(body, &env)
if err != nil {
a.respondWithError(w, err)
return
}
if name != env.ObjectMeta.Name {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "Environment name doesn't match URL")
a.respondWithError(w, err)
return
}
enew, err := a.fissionClient.CoreV1().Environments(env.ObjectMeta.Namespace).Update(r.Context(), &env, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(enew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) EnvironmentApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["environment"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().Environments(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
// EnvironmentApiPodList: Get list of pods currently available in environment
func (a *API) EnvironmentApiPodList(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
envName, ok := vars["environment"]
if !ok {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, "Error retrieving environment name"))
return
}
// label selector
selector := map[string]string{
fv1.ENVIRONMENT_NAME: envName,
}
ens := a.extractQueryParamFromRequest(r, fv1.ENVIRONMENT_NAMESPACE)
if len(ens) != 0 {
selector[fv1.ENVIRONMENT_NAMESPACE] = ens
}
et := a.extractQueryParamFromRequest(r, fv1.EXECUTOR_TYPE)
if len(et) != 0 {
selector[fv1.EXECUTOR_TYPE] = et
}
pods, err := a.kubernetesClient.CoreV1().Pods(metav1.NamespaceAll).List(r.Context(), metav1.ListOptions{
LabelSelector: labels.Set(selector).AsSelector().String(),
})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(pods.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
-406
View File
@@ -1,406 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
"sort"
"strconv"
"strings"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"go.uber.org/zap"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterFunctionRoute(ws *restful.WebService) {
tags := []string{"Function"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "Function", Description: "Function Operation"}})
ws.Route(
ws.GET("/v2/functions").
Doc("List all functions").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of function").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.Function{}).
Returns(http.StatusOK, "List of functions", []fv1.Function{}))
ws.Route(
ws.POST("/v2/functions").
Doc("Create function").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.Function{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusOK, "ObjectMeta of created function", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/functions/{function}").
Doc("Get detail of function").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("function", "Function name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of function").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.Function{}). // on the response
Returns(http.StatusOK, "A function", fv1.Function{}))
ws.Route(
ws.PUT("/v2/functions/{function}").
Doc("Update function").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("function", "Function name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.Function{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated function", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/functions/{function}").
Doc("Delete function").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("function", "Function name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of function").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) FunctionApiList(w http.ResponseWriter, r *http.Request) {
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
funcs, err := a.fissionClient.CoreV1().Functions(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(funcs.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) FunctionApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var f fv1.Function
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
return
}
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), f.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
fnew, err := a.fissionClient.CoreV1().Functions(f.ObjectMeta.Namespace).Create(r.Context(), &f, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(fnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) FunctionApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["function"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
f, err := a.fissionClient.CoreV1().Functions(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(f)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) FunctionApiUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["function"]
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var f fv1.Function
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
return
}
if name != f.ObjectMeta.Name {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "Function name doesn't match URL")
a.respondWithError(w, err)
return
}
fnew, err := a.fissionClient.CoreV1().Functions(f.ObjectMeta.Namespace).Update(r.Context(), &f, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(fnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) FunctionApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["function"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().Functions(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
// FunctionLogsApiPost establishes a proxy server to log database, and redirect
// query command send from client to database then proxy back the db response.
func (a *API) FunctionLogsApiPost(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
// get dbType from url
dbType := vars["dbType"]
// find correspond db http url
dbCnf := a.getLogDBConfig(dbType)
svcUrl, err := url.Parse(dbCnf.httpURL)
if err != nil {
msg := "failed parse url to establish proxy to database for function logs"
a.logger.Error(msg,
zap.Error(err),
zap.String("database_url", dbCnf.httpURL))
a.respondWithError(w, errors.Wrap(err, msg))
return
}
// set up proxy server director
director := func(req *http.Request) {
// only replace url Scheme and Host to remote influxDB
// and leave query string intact
req.URL.Scheme = svcUrl.Scheme
req.URL.Host = svcUrl.Host
req.URL.Path = svcUrl.Path
req.Host = svcUrl.Host
// set up http basic auth for database authentication
req.SetBasicAuth(dbCnf.username, dbCnf.password)
}
proxy := &httputil.ReverseProxy{
Director: director,
}
proxy.ServeHTTP(w, r)
}
// FunctionPodLogs : Get logs for a function directly from pod
func (a *API) FunctionPodLogs(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
fnName := vars["function"]
ns := a.extractQueryParamFromRequest(r, "namespace")
podNs := "fission-function"
if len(ns) == 0 {
ns = metav1.NamespaceDefault
} else if ns != metav1.NamespaceDefault {
// If the function namespace is "default", executor
// will create function pods under "fission-function".
// Otherwise, the function pod will be created under
// the same namespace of function.
podNs = ns
}
f, err := a.fissionClient.CoreV1().Functions(ns).Get(r.Context(), fnName, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
// Get function Pods first
selector := map[string]string{
fv1.FUNCTION_UID: string(f.ObjectMeta.UID),
fv1.ENVIRONMENT_NAME: f.Spec.Environment.Name,
fv1.ENVIRONMENT_NAMESPACE: f.Spec.Environment.Namespace,
}
podList, err := a.kubernetesClient.CoreV1().Pods(podNs).List(r.Context(), metav1.ListOptions{
LabelSelector: labels.Set(selector).AsSelector().String(),
})
if err != nil {
a.respondWithError(w, err)
return
}
// Get the logs for last Pod executed
pods := podList.Items
sort.Slice(pods, func(i, j int) bool {
rv1, _ := strconv.ParseInt(pods[i].ObjectMeta.ResourceVersion, 10, 32)
rv2, _ := strconv.ParseInt(pods[j].ObjectMeta.ResourceVersion, 10, 32)
return rv1 > rv2
})
if len(pods) <= 0 {
a.respondWithError(w, errors.New("no active pods found"))
return
}
// get the pod with highest resource version
err = getContainerLog(r.Context(), a.kubernetesClient, w, f, &pods[0])
if err != nil {
a.respondWithError(w, errors.Wrapf(err, "error getting container logs"))
return
}
}
func getContainerLog(ctx context.Context, kubernetesClient kubernetes.Interface, w http.ResponseWriter, fn *fv1.Function, pod *apiv1.Pod) error {
seq := strings.Repeat("=", 35)
for _, container := range pod.Spec.Containers {
podLogOpts := apiv1.PodLogOptions{Container: container.Name} // Only the env container, not fetcher
podLogsReq := kubernetesClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.ObjectMeta.Name, &podLogOpts)
podLogs, err := podLogsReq.Stream(ctx)
if err != nil {
return errors.Wrapf(err, "error streaming pod log")
}
msg := fmt.Sprintf("\n%v\nFunction: %v\nEnvironment: %v\nNamespace: %v\nPod: %v\nContainer: %v\nNode: %v\n%v\n", seq,
fn.ObjectMeta.Name, fn.Spec.Environment.Name, pod.Namespace, pod.Name, container.Name, pod.Spec.NodeName, seq)
_, err = w.Write([]byte(msg))
if err != nil {
return errors.Wrap(err, "error writing response")
}
_, err = io.Copy(w, podLogs)
if err != nil {
return errors.Wrapf(err, "error copying pod log")
}
podLogs.Close()
}
return nil
}
// FunctionApiPodList: Get list of pods currently used by function
func (a *API) FunctionApiPodList(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
fnName, ok := vars["function"]
if !ok {
a.respondWithError(w, ferror.MakeError(http.StatusInternalServerError, "Error retrieving function name"))
return
}
// label selector
selector := map[string]string{
fv1.FUNCTION_NAME: fnName,
}
fns := a.extractQueryParamFromRequest(r, fv1.FUNCTION_NAMESPACE)
if len(fns) != 0 {
selector[fv1.FUNCTION_NAMESPACE] = fns
}
pods, err := a.kubernetesClient.CoreV1().Pods(metav1.NamespaceAll).List(r.Context(), metav1.ListOptions{
LabelSelector: labels.Set(selector).AsSelector().String(),
})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(pods.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
-285
View File
@@ -1,285 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"sort"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterHTTPTriggerRoute(ws *restful.WebService) {
tags := []string{"HTTPTrigger"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "HTTPTrigger", Description: "HTTPTrigger Operation"}})
ws.Route(
ws.GET("/v2/triggers/http").
Doc("List all HTTP triggers").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of httpTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.HTTPTrigger{}).
Returns(http.StatusOK, "List of httpTriggers", []fv1.HTTPTrigger{}))
ws.Route(
ws.POST("/v2/triggers/http").
Doc("Create HTTP trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.HTTPTrigger{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created httpTrigger", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/triggers/http/{httpTrigger}").
Doc("Get detail of HTTP trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("httpTrigger", "HTTPTrigger name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of httpTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.HTTPTrigger{}). // on the response
Returns(http.StatusOK, "A httpTrigger", fv1.HTTPTrigger{}))
ws.Route(
ws.PUT("/v2/triggers/http/{httpTrigger}").
Doc("Update HTTP trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("httpTrigger", "HTTPTrigger name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.HTTPTrigger{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated httpTrigger", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/triggers/http/{httpTrigger}").
Doc("Delete HTTP trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("httpTrigger", "HTTPTrigger name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of httpTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) HTTPTriggerApiList(w http.ResponseWriter, r *http.Request) {
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
triggers, err := a.fissionClient.CoreV1().HTTPTriggers(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(triggers.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
// checkHTTPTriggerDuplicates checks whether the tuple (Method, Host, URL) is duplicate or not.
func (a *API) checkHTTPTriggerDuplicates(ctx context.Context, t *fv1.HTTPTrigger) error {
triggers, err := a.fissionClient.CoreV1().HTTPTriggers(metav1.NamespaceAll).List(ctx, metav1.ListOptions{})
if err != nil {
return err
}
for _, ht := range triggers.Items {
if ht.ObjectMeta.UID == t.ObjectMeta.UID {
// Same resource. No need to check.
continue
}
urlMatch := false
if (ht.Spec.RelativeURL != "" && ht.Spec.RelativeURL == t.Spec.RelativeURL) || (ht.Spec.Prefix != nil && t.Spec.Prefix != nil && *ht.Spec.Prefix != "" && *ht.Spec.Prefix == *t.Spec.Prefix) {
urlMatch = true
}
methodMatch := false
if ht.Spec.Method == t.Spec.Method && len(ht.Spec.Methods) == len(t.Spec.Methods) {
methodMatch = true
sort.Strings(ht.Spec.Methods)
sort.Strings(t.Spec.Methods)
for i, m1 := range ht.Spec.Methods {
if m1 != t.Spec.Methods[i] {
methodMatch = false
}
}
}
if urlMatch && methodMatch && ht.Spec.Method == t.Spec.Method && ht.Spec.Host == t.Spec.Host {
return ferror.MakeError(ferror.ErrorNameExists,
fmt.Sprintf("HTTPTrigger with same Host, URL & method already exists (%v)",
ht.ObjectMeta.Name))
}
}
return nil
}
func (a *API) HTTPTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var t fv1.HTTPTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
return
}
// Ensure we don't have a duplicate HTTP route defined (same URL and method)
err = a.checkHTTPTriggerDuplicates(r.Context(), &t)
if err != nil {
a.respondWithError(w, err)
return
}
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), t.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.CoreV1().HTTPTriggers(t.ObjectMeta.Namespace).Create(r.Context(), &t, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(tnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) HTTPTriggerApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["httpTrigger"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
t, err := a.fissionClient.CoreV1().HTTPTriggers(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(t)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) HTTPTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["httpTrigger"]
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var t fv1.HTTPTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
return
}
if name != t.ObjectMeta.Name {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "HTTPTrigger name doesn't match URL")
a.respondWithError(w, err)
return
}
err = a.checkHTTPTriggerDuplicates(r.Context(), &t)
if err != nil {
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.CoreV1().HTTPTriggers(t.ObjectMeta.Namespace).Update(r.Context(), &t, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(tnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) HTTPTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["httpTrigger"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().HTTPTriggers(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
-229
View File
@@ -1,229 +0,0 @@
/*
Copyright 2017 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"encoding/json"
"io"
"net/http"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterMessageQueueTriggerRoute(ws *restful.WebService) {
tags := []string{"MessageQueueTrigger"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "MessageQueueTrigger", Description: "MessageQueueTrigger Operation"}})
ws.Route(
ws.GET("/v2/triggers/messagequeue").
Doc("List all message queue triggers").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of messageQueueTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.MessageQueueTrigger{}).
Returns(http.StatusOK, "List of messageQueueTriggers", []fv1.MessageQueueTrigger{}))
ws.Route(
ws.POST("/v2/triggers/messagequeue").
Doc("Create message queue trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.MessageQueueTrigger{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created messageQueueTrigger", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/triggers/messagequeue/{mqTrigger}").
Doc("Get detail of message queue trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("mqTrigger", "MessageQueueTriggers name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of messageQueueTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.MessageQueueTrigger{}). // on the response
Returns(http.StatusOK, "A messageQueueTrigger", fv1.MessageQueueTrigger{}))
ws.Route(
ws.PUT("/v2/triggers/messagequeue/{mqTrigger}").
Doc("Update message queue trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("mqTrigger", "MessageQueueTrigger name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.MessageQueueTrigger{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated messageQueueTrigger", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/triggers/messagequeue/{mqTrigger}").
Doc("Delete message queue trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("mqTrigger", "MessageQueueTrigger name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of messageQueueTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) MessageQueueTriggerApiList(w http.ResponseWriter, r *http.Request) {
//mqType := r.FormValue("mqtype") // ignored for now
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
triggers, err := a.fissionClient.CoreV1().MessageQueueTriggers(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(triggers.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) MessageQueueTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var mqTrigger fv1.MessageQueueTrigger
err = json.Unmarshal(body, &mqTrigger)
if err != nil {
a.respondWithError(w, err)
return
}
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), mqTrigger.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.CoreV1().MessageQueueTriggers(mqTrigger.ObjectMeta.Namespace).Create(r.Context(), &mqTrigger, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(tnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) MessageQueueTriggerApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["mqTrigger"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
mqTrigger, err := a.fissionClient.CoreV1().MessageQueueTriggers(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(mqTrigger)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) MessageQueueTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["mqTrigger"]
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var mqTrigger fv1.MessageQueueTrigger
err = json.Unmarshal(body, &mqTrigger)
if err != nil {
a.respondWithError(w, err)
return
}
if name != mqTrigger.ObjectMeta.Name {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "Message queue trigger name doesn't match URL")
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.CoreV1().MessageQueueTriggers(mqTrigger.ObjectMeta.Namespace).Update(r.Context(), &mqTrigger, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(tnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) MessageQueueTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["mqTrigger"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().MessageQueueTriggers(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
-78
View File
@@ -1,78 +0,0 @@
/*
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 controller
import (
"net/http"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
)
var specTag []spec.Tag
func openAPI() http.Handler {
restful.DefaultContainer.Add(openAPIWebService())
config := restfulspec.Config{
WebServices: restful.RegisteredWebServices(),
APIPath: "/v2/apidocs.json",
PostBuildSwaggerObjectHandler: enrichSwaggerObject}
restful.DefaultContainer.Add(restfulspec.NewOpenAPIService(config))
return restful.DefaultContainer
}
func openAPIWebService() *restful.WebService {
ws := new(restful.WebService)
// CRD resource
RegisterEnvironmentRoute(ws)
RegisterFunctionRoute(ws)
RegisterHTTPTriggerRoute(ws)
RegisterMessageQueueTriggerRoute(ws)
RegisterPackageRoute(ws)
RegisterWatchRoute(ws)
RegisterTimeTriggerRoute(ws)
RegisterCanaryConfigRoute(ws)
// proxy
RegisterStorageServiceProxyRoute(ws)
return ws
}
func enrichSwaggerObject(swo *spec.Swagger) {
swo.Info = &spec.Info{
InfoProps: spec.InfoProps{
Title: "Fission OpenAPI 2.0",
Description: openapiDescription,
Version: "v1",
},
}
swo.Tags = specTag
}
var openapiDescription = `
OpenAPI 2.0 document for fission controller
* ObjectMeta (v1.ObjectMeta) should be empty when creating a CRD resource. Kubernetes will assign it automatically.
* Following semantic errors are known issues and won't affect the API accessibility.
- Operations must have unique operationIds.
- All scale semantic errors. (Due to go-restful exposes inner fields of k8s struct).
`
-254
View File
@@ -1,254 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/dustin/go-humanize"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterPackageRoute(ws *restful.WebService) {
tags := []string{"Package"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "Package", Description: "Package Operation"}})
ws.Route(
ws.GET("/v2/packages").
Doc("List all packages").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of package").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.Package{}).
Returns(http.StatusOK, "List of packages", []fv1.Package{}))
ws.Route(
ws.POST("/v2/packages").
Doc("Create package").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.Package{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created package", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/packages/{package}").
Doc("Get detail of package").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("package", "Package name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of package").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.Package{}). // on the response
Returns(http.StatusOK, "A package", fv1.Package{}))
ws.Route(
ws.PUT("/v2/packages/{package}").
Doc("Update package").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("package", "Package name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.Package{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated package", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/packages/{package}").
Doc("Delete package").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("package", "Package name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of package").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) PackageApiList(w http.ResponseWriter, r *http.Request) {
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
funcs, err := a.fissionClient.CoreV1().Packages(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(funcs.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) PackageApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var f fv1.Package
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
return
}
// Ensure size limits
if len(f.Spec.Source.Literal) > int(fv1.ArchiveLiteralSizeLimit) {
err := ferror.MakeError(ferror.ErrorInvalidArgument,
fmt.Sprintf("Package literal larger than %s", humanize.Bytes(uint64(fv1.ArchiveLiteralSizeLimit))))
a.respondWithError(w, err)
return
}
if len(f.Spec.Deployment.Literal) > int(fv1.ArchiveLiteralSizeLimit) {
err := ferror.MakeError(ferror.ErrorInvalidArgument,
fmt.Sprintf("Package literal larger than %s", humanize.Bytes(uint64(fv1.ArchiveLiteralSizeLimit))))
a.respondWithError(w, err)
return
}
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), f.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
fnew, err := a.fissionClient.CoreV1().Packages(f.ObjectMeta.Namespace).Create(r.Context(), &f, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(fnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) PackageApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["package"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
raw := r.FormValue("raw") // just the deployment pkg
f, err := a.fissionClient.CoreV1().Packages(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
var resp []byte
if raw != "" {
resp = f.Spec.Deployment.Literal
} else {
resp, err = json.Marshal(f)
if err != nil {
a.respondWithError(w, err)
return
}
}
a.respondWithSuccess(w, resp)
}
func (a *API) PackageApiUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["package"]
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var f fv1.Package
err = json.Unmarshal(body, &f)
if err != nil {
a.respondWithError(w, err)
return
}
if name != f.ObjectMeta.Name {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "Package name doesn't match URL")
a.respondWithError(w, err)
return
}
fnew, err := a.fissionClient.CoreV1().Packages(f.ObjectMeta.Namespace).Update(r.Context(), &f, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(fnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) PackageApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["package"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().Packages(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
-45
View File
@@ -1,45 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"net/http"
"github.com/gorilla/mux"
"go.uber.org/zap"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (a *API) SecretExists(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["secret"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
_, err := a.kubernetesClient.CoreV1().Secrets(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.logger.Error("error getting secret",
zap.Error(err),
zap.String("secret_name", name),
zap.String("namespace", ns))
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, nil)
}
-78
View File
@@ -1,78 +0,0 @@
/*
Copyright 2017 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"go.uber.org/zap"
)
func RegisterStorageServiceProxyRoute(ws *restful.WebService) {
tags := []string{"StorageServiceProxy"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "StorageServiceProxy", Description: "StorageServiceProxy Operation"}})
// workaround as go-restful has to set HTTP method explicitly.
ws.Route(
ws.POST("/proxy/storage/v1/archive").
Doc("Create archive").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}))
ws.Route(
ws.GET("/proxy/storage/v1/archive").
Doc("Get archive").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}))
ws.Route(
ws.DELETE("/proxy/storage/v1/archive").
Doc("Delete archive").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}))
}
func (api *API) StorageServiceProxy(w http.ResponseWriter, r *http.Request) {
u := api.storageServiceUrl
ssUrl, err := url.Parse(u)
if err != nil {
e := "error parsing url"
api.logger.Error(e, zap.Error(err), zap.String("url", u))
http.Error(w, fmt.Sprintf("%s %s: %v", e, u, err), http.StatusInternalServerError)
return
}
director := func(req *http.Request) {
req.URL.Scheme = ssUrl.Scheme
req.URL.Host = ssUrl.Host
req.URL.Path = "/v1/archive"
req.Host = ssUrl.Host
}
proxy := &httputil.ReverseProxy{
Director: director,
}
proxy.ServeHTTP(w, r)
}
-249
View File
@@ -1,249 +0,0 @@
/*
Copyright 2017 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"encoding/json"
"io"
"net/http"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterTimeTriggerRoute(ws *restful.WebService) {
tags := []string{"TimeTrigger"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "TimeTrigger", Description: "TimeTrigger Operation"}})
ws.Route(
ws.GET("/v2/triggers/time").
Doc("List all time trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of timeTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.TimeTrigger{}).
Returns(http.StatusOK, "List of timeTriggers", []fv1.TimeTrigger{}))
ws.Route(
ws.POST("/v2/triggers/time").
Doc("Create time trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.TimeTrigger{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created timeTrigger", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/triggers/time/{timeTrigger}").
Doc("Get detail of time trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("timeTrigger", "TimeTrigger name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of timeTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.TimeTrigger{}). // on the response
Returns(http.StatusOK, "A timeTrigger", fv1.TimeTrigger{}))
ws.Route(
ws.PUT("/v2/triggers/time/{timeTrigger}").
Doc("Update time trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("timeTrigger", "TimeTrigger name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.TimeTrigger{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated timeTrigger", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/triggers/time/{timeTrigger}").
Doc("Delete time trigger").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("timeTrigger", "TimeTrigger name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of timeTrigger").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) TimeTriggerApiList(w http.ResponseWriter, r *http.Request) {
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
triggers, err := a.fissionClient.CoreV1().TimeTriggers(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(triggers.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) TimeTriggerApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var t fv1.TimeTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
return
}
// validate
err = fv1.IsValidCronSpec(t.Spec.Cron)
if err != nil {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "TimeTrigger cron spec is not valid")
a.respondWithError(w, err)
return
}
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), t.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.CoreV1().TimeTriggers(t.ObjectMeta.Namespace).Create(r.Context(), &t, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(tnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) TimeTriggerApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["timeTrigger"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
t, err := a.fissionClient.CoreV1().TimeTriggers(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(t)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) TimeTriggerApiUpdate(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["timeTrigger"]
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var t fv1.TimeTrigger
err = json.Unmarshal(body, &t)
if err != nil {
a.respondWithError(w, err)
return
}
if name != t.ObjectMeta.Name {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "TimeTrigger name doesn't match URL")
a.respondWithError(w, err)
return
}
err = fv1.IsValidCronSpec(t.Spec.Cron)
if err != nil {
err = ferror.MakeError(ferror.ErrorInvalidArgument, "TimeTrigger cron spec is not valid")
a.respondWithError(w, err)
return
}
tnew, err := a.fissionClient.CoreV1().TimeTriggers(t.ObjectMeta.Namespace).Update(r.Context(), &t, metav1.UpdateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(tnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) TimeTriggerApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["timeTrigger"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().TimeTriggers(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
-204
View File
@@ -1,204 +0,0 @@
/*
Copyright 2016 The Fission Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"encoding/json"
"io"
"net/http"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
restful "github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
"github.com/gorilla/mux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
ferror "github.com/fission/fission/pkg/error"
)
func RegisterWatchRoute(ws *restful.WebService) {
tags := []string{"KubernetesWatch"}
specTag = append(specTag, spec.Tag{TagProps: spec.TagProps{Name: "KubernetesWatch", Description: "KubernetesWatch Operation"}})
ws.Route(
ws.GET("/v2/watches").
Doc("List all kubernetes watch").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.QueryParameter("namespace", "Namespace of kubernetesWatch").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes([]fv1.KubernetesWatchTrigger{}).
Returns(http.StatusOK, "List of kubernetesWatchs", []fv1.KubernetesWatchTrigger{}))
ws.Route(
ws.POST("/v2/watches").
Doc("Create kubernetes watch").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Produces(restful.MIME_JSON).
Reads(fv1.KubernetesWatchTrigger{}).
Writes(metav1.ObjectMeta{}).
Returns(http.StatusCreated, "ObjectMeta of created kubernetesWatch", metav1.ObjectMeta{}))
ws.Route(
ws.GET("/v2/watches/{watch}").
Doc("Get detail of kubernetes watch").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("watch", "KubernetesWatch name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of kubernetesWatch").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Writes(fv1.KubernetesWatchTrigger{}). // on the response
Returns(http.StatusOK, "A kubernetesWatch", fv1.KubernetesWatchTrigger{}))
ws.Route(
ws.PUT("/v2/watches/{watch}").
Doc("Update kubernetes watch").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("watch", "KubernetesWatch name").DataType("string").DefaultValue("").Required(true)).
Produces(restful.MIME_JSON).
Reads(fv1.KubernetesWatchTrigger{}).
Writes(metav1.ObjectMeta{}). // on the response
Returns(http.StatusOK, "ObjectMeta of updated kubernetesWatch", metav1.ObjectMeta{}))
ws.Route(
ws.DELETE("/v2/watches/{watch}").
Doc("Delete kubernetes watch").
Metadata(restfulspec.KeyOpenAPITags, tags).
To(func(req *restful.Request, resp *restful.Response) {
resp.ResponseWriter.WriteHeader(http.StatusOK)
}).
Param(ws.PathParameter("watch", "KubernetesWatch name").DataType("string").DefaultValue("").Required(true)).
Param(ws.QueryParameter("namespace", "Namespace of kubernetesWatch").DataType("string").DefaultValue(metav1.NamespaceAll).Required(false)).
Produces(restful.MIME_JSON).
Returns(http.StatusOK, "Only HTTP status returned", nil))
}
func (a *API) WatchApiList(w http.ResponseWriter, r *http.Request) {
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceAll
}
watches, err := a.fissionClient.CoreV1().KubernetesWatchTriggers(ns).List(r.Context(), metav1.ListOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(watches.Items)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) WatchApiCreate(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
a.respondWithError(w, err)
return
}
var watch fv1.KubernetesWatchTrigger
err = json.Unmarshal(body, &watch)
if err != nil {
a.respondWithError(w, err)
return
}
// TODO check for duplicate watches
// TODO check for duplicate watches -> we probably won't need it?
// check if namespace exists, if not create it.
err = a.createNsIfNotExists(r.Context(), watch.ObjectMeta.Namespace)
if err != nil {
a.respondWithError(w, err)
return
}
wnew, err := a.fissionClient.CoreV1().KubernetesWatchTriggers(watch.ObjectMeta.Namespace).Create(r.Context(), &watch, metav1.CreateOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(wnew.ObjectMeta)
if err != nil {
a.respondWithError(w, err)
return
}
w.WriteHeader(http.StatusCreated)
a.respondWithSuccess(w, resp)
}
func (a *API) WatchApiGet(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["watch"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
watch, err := a.fissionClient.CoreV1().KubernetesWatchTriggers(ns).Get(r.Context(), name, metav1.GetOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
resp, err := json.Marshal(watch)
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, resp)
}
func (a *API) WatchApiUpdate(w http.ResponseWriter, r *http.Request) {
a.respondWithError(w, ferror.MakeError(ferror.ErrorNotImplemented,
"Not implemented"))
}
func (a *API) WatchApiDelete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["watch"]
ns := a.extractQueryParamFromRequest(r, "namespace")
if len(ns) == 0 {
ns = metav1.NamespaceDefault
}
err := a.fissionClient.CoreV1().KubernetesWatchTriggers(ns).Delete(r.Context(), name, metav1.DeleteOptions{})
if err != nil {
a.respondWithError(w, err)
return
}
a.respondWithSuccess(w, []byte(""))
}
-33
View File
@@ -1,33 +0,0 @@
package controller
import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"github.com/gorilla/mux"
)
func (api *API) WorkflowApiserverProxy(w http.ResponseWriter, r *http.Request) {
u := api.workflowApiUrl
ssUrl, err := url.Parse(u)
if err != nil {
msg := fmt.Sprintf("Error parsing url %v: %v", u, err)
http.Error(w, msg, http.StatusInternalServerError)
return
}
vars := mux.Vars(r)
path := fmt.Sprintf("/%s", vars["path"])
director := func(req *http.Request) {
req.URL.Scheme = ssUrl.Scheme
req.URL.Host = ssUrl.Host
req.URL.Path = path
req.Host = ssUrl.Host
}
proxy := &httputil.ReverseProxy{
Director: director,
}
proxy.ServeHTTP(w, r)
}
-18
View File
@@ -30,7 +30,6 @@ import (
uuid "github.com/satori/go.uuid"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/controller/client"
"github.com/fission/fission/pkg/fission-cli/cmd"
"github.com/fission/fission/pkg/fission-cli/util"
storageSvcClient "github.com/fission/fission/pkg/storagesvc/client"
@@ -238,23 +237,6 @@ func WriteArchiveToFile(fileName string, reader io.Reader) error {
return nil
}
// DownloadStoragesvcURL downloads and return archive content with given storage service url
func DownloadStoragesvcURL(client client.Interface, fileUrl string) (io.ReadCloser, error) {
u, err := url.ParseRequestURI(fileUrl)
if err != nil {
return nil, err
}
// replace in-cluster storage service host with controller server url
fileDownloadUrl := strings.TrimSuffix(client.ServerURL(), "/") + "/proxy/storage/" + u.RequestURI()
reader, err := DownloadURL(fileDownloadUrl)
if err != nil {
return nil, errors.Wrapf(err, fmt.Sprintf("error downloading from storage service url: %v", fileUrl))
}
return reader, nil
}
// PrintPackageSummary prints package information and build logs.
func PrintPackageSummary(writer io.Writer, pkg *fv1.Package) {
// replace escaped line breaker character
+5 -5
View File
@@ -78,15 +78,15 @@ func (opts *DumpSubCommand) do(input cli.Input) error {
// fission component logs & spec
"fission-components-svc-spec": resources.NewKubernetesObjectDumper(k8sClient, resources.KubernetesService,
"svc in (buildermgr, controller, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"svc in (buildermgr, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"fission-components-deployment-spec": resources.NewKubernetesObjectDumper(k8sClient, resources.KubernetesDeployment,
"svc in (buildermgr, controller, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"svc in (buildermgr, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"fission-components-daemonset-spec": resources.NewKubernetesObjectDumper(k8sClient, resources.KubernetesDaemonSet,
"svc in (buildermgr, controller, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"svc in (buildermgr, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"fission-components-pod-spec": resources.NewKubernetesObjectDumper(k8sClient, resources.KubernetesPod,
"svc in (buildermgr, controller, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"svc in (buildermgr, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"fission-components-pod-log": resources.NewKubernetesPodLogDumper(k8sClient,
"svc in (buildermgr, controller, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
"svc in (buildermgr, executor, influxdb, kubewatcher, logger, mqtrigger, router, storagesvc, timer)"),
// fission builder logs & spec
"fission-builder-svc-spec": resources.NewKubernetesObjectDumper(k8sClient, resources.KubernetesService, "owner=buildermgr"),
+1 -1
View File
@@ -22,7 +22,7 @@ Its job is to:
1. Keep track of HTTP triggers and their mappings to functions
Use the controller API to get and watch this state.
Use the Kubernetes API to get and watch this state.
2. Given a function, get a reference to a routable function run service
-1
View File
@@ -43,7 +43,6 @@ manifests:
analytics: "false"
builderPodSpec.enabled: "false"
canaryDeployment.enabled: "false"
controller.enabled: "false"
debugEnv: "false"
fetcher.imageTag: ""
grafana.dashboards.enabled: "false"