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:
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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(""))
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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 ""
|
||||
}
|
||||
@@ -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, "/")
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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(""))
|
||||
}
|
||||
@@ -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(""))
|
||||
}
|
||||
@@ -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).
|
||||
`
|
||||
@@ -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(""))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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(""))
|
||||
}
|
||||
@@ -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(""))
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user